diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index 445c5b902..c53c65ded 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -3656,22 +3656,18 @@ void GUIFormSpecMenu::drawMenu() NULL, m_client, IT_ROT_HOVERED); } - // On touchscreens, m_pointer is set by GUIModalMenu::preprocessEvent instead. -#ifndef HAVE_TOUCHSCREENGUI - m_pointer = RenderingEngine::get_raw_device()->getCursorControl()->getPosition(); -#endif - /* Draw fields/buttons tooltips and update the mouse cursor */ gui::IGUIElement *hovered = Environment->getRootGUIElement()->getElementFromPoint(m_pointer); -#ifndef HAVE_TOUCHSCREENGUI gui::ICursorControl *cursor_control = RenderingEngine::get_raw_device()-> getCursorControl(); - gui::ECURSOR_ICON current_cursor_icon = cursor_control->getActiveIcon(); -#endif + gui::ECURSOR_ICON current_cursor_icon = gui::ECI_NORMAL; + if (cursor_control) + current_cursor_icon = cursor_control->getActiveIcon(); + bool hovered_element_found = false; if (hovered) { @@ -3715,11 +3711,10 @@ void GUIFormSpecMenu::drawMenu() m_tooltips[field.fname].bgcolor); } -#ifndef HAVE_TOUCHSCREENGUI - if (field.ftype != f_HyperText && // Handled directly in guiHyperText + if (cursor_control && + field.ftype != f_HyperText && // Handled directly in guiHyperText current_cursor_icon != field.fcursor_icon) cursor_control->setActiveIcon(field.fcursor_icon); -#endif hovered_element_found = true; @@ -3730,10 +3725,8 @@ void GUIFormSpecMenu::drawMenu() if (!hovered_element_found) { // no element is hovered -#ifndef HAVE_TOUCHSCREENGUI - if (current_cursor_icon != ECI_NORMAL) + if (cursor_control && current_cursor_icon != ECI_NORMAL) cursor_control->setActiveIcon(ECI_NORMAL); -#endif } m_tooltip_element->draw(); @@ -3764,16 +3757,13 @@ void GUIFormSpecMenu::showTooltip(const std::wstring &text, v2u32 screenSize = Environment->getVideoDriver()->getScreenSize(); int tooltip_offset_x = m_btn_height; int tooltip_offset_y = m_btn_height; -#ifdef HAVE_TOUCHSCREENGUI - tooltip_offset_x *= 3; - tooltip_offset_y = 0; - if (m_pointer.X > (s32)screenSize.X / 2) - tooltip_offset_x = -(tooltip_offset_x + tooltip_width); - // Hide tooltip after ETIE_LEFT_UP - if (m_pointer.X == 0) - return; -#endif + if (m_pointer_type == PointerType::Touch) { + tooltip_offset_x *= 3; + tooltip_offset_y = 0; + if (m_pointer.X > (s32)screenSize.X / 2) + tooltip_offset_x = -(tooltip_offset_x + tooltip_width); + } // Calculate and set the tooltip position s32 tooltip_x = m_pointer.X + tooltip_offset_x; @@ -4070,6 +4060,11 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode) bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) { + // This must be done first so that GUIModalMenu can set m_pointer_type + // correctly. + if (GUIModalMenu::preprocessEvent(event)) + return true; + // The IGUITabControl renders visually using the skin's selected // font, which we override for the duration of form drawing, // but computes tab hotspots based on how it would have rendered @@ -4147,7 +4142,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) return handled; } - return GUIModalMenu::preprocessEvent(event); + return false; } void GUIFormSpecMenu::tryClose() @@ -4326,14 +4321,12 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } } -#ifdef HAVE_TOUCHSCREENGUI // The second touch (see GUIModalMenu::preprocessEvent() function) ButtonEventType touch = BET_OTHER; if (event.EventType == EET_TOUCH_INPUT_EVENT) { if (event.TouchInput.Event == ETIE_LEFT_UP) touch = BET_RIGHT; } -#endif // Set this number to a positive value to generate a move action // from m_selected_item to s. @@ -4678,7 +4671,6 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) break; } -#ifdef HAVE_TOUCHSCREENGUI if (touch == BET_RIGHT && m_selected_item && !m_left_dragging) { if (!s.isValid()) { // Not a valid slot @@ -4698,7 +4690,6 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } } } -#endif // Update left-dragged slots if (m_left_dragging && m_left_drag_stacks.size() > 1) { @@ -5067,10 +5058,8 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event) } } -#ifdef HAVE_TOUCHSCREENGUI if (m_second_touch) return true; // Stop propagating the event -#endif return Parent ? Parent->OnEvent(event) : false; } diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp index 66771f2e2..8aba3083c 100644 --- a/src/gui/guiHyperText.cpp +++ b/src/gui/guiHyperText.cpp @@ -1052,14 +1052,10 @@ void GUIHyperText::checkHover(s32 X, s32 Y) } } -#ifndef HAVE_TOUCHSCREENGUI - if (m_drawer.m_hovertag) - RenderingEngine::get_raw_device()->getCursorControl()->setActiveIcon( - gui::ECI_HAND); - else - RenderingEngine::get_raw_device()->getCursorControl()->setActiveIcon( - gui::ECI_NORMAL); -#endif + ICursorControl *cursor_control = RenderingEngine::get_raw_device()->getCursorControl(); + + if (cursor_control) + cursor_control->setActiveIcon(m_drawer.m_hovertag ? gui::ECI_HAND : gui::ECI_NORMAL); } bool GUIHyperText::OnEvent(const SEvent &event) @@ -1075,12 +1071,11 @@ bool GUIHyperText::OnEvent(const SEvent &event) if (event.EventType == EET_GUI_EVENT && event.GUIEvent.EventType == EGET_ELEMENT_LEFT) { m_drawer.m_hovertag = nullptr; -#ifndef HAVE_TOUCHSCREENGUI - gui::ICursorControl *cursor_control = - RenderingEngine::get_raw_device()->getCursorControl(); - if (cursor_control->isVisible()) + + ICursorControl *cursor_control = RenderingEngine::get_raw_device()->getCursorControl(); + + if (cursor_control && cursor_control->isVisible()) cursor_control->setActiveIcon(gui::ECI_NORMAL); -#endif } if (event.EventType == EET_MOUSE_INPUT_EVENT) { diff --git a/src/gui/guiInventoryList.cpp b/src/gui/guiInventoryList.cpp index 6f1d28e0b..02505d436 100644 --- a/src/gui/guiInventoryList.cpp +++ b/src/gui/guiInventoryList.cpp @@ -152,10 +152,10 @@ void GUIInventoryList::draw() // Add hovering tooltip bool show_tooltip = !item.empty() && hovering && !selected_item; -#ifdef HAVE_TOUCHSCREENGUI // Make it possible to see item tooltips on touchscreens - show_tooltip |= hovering && selected && m_fs_menu->getSelectedAmount() != 0; -#endif + if (m_fs_menu->getPointerType() == PointerType::Touch) { + show_tooltip |= hovering && selected && m_fs_menu->getSelectedAmount() != 0; + } if (show_tooltip) { std::string tooltip = orig_item.getDescription(client->idef()); if (m_fs_menu->doTooltipAppendItemname()) diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp index d4322c9f7..5d4e03baf 100644 --- a/src/gui/modalMenu.cpp +++ b/src/gui/modalMenu.cpp @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc., */ #include +#include #include "client/renderingengine.h" #include "modalMenu.h" #include "gettext.h" @@ -103,7 +104,7 @@ void GUIModalMenu::quitMenu() m_menumgr->deletingMenu(this); this->remove(); #ifdef HAVE_TOUCHSCREENGUI - if (g_touchscreengui && m_touchscreen_visible) + if (g_touchscreengui) g_touchscreengui->show(); #endif } @@ -169,8 +170,6 @@ static bool isChild(gui::IGUIElement *tocheck, gui::IGUIElement *parent) return false; } -#ifdef HAVE_TOUCHSCREENGUI - bool GUIModalMenu::simulateMouseEvent( gui::IGUIElement *target, ETOUCH_INPUT_EVENT touch_event) { @@ -194,41 +193,51 @@ bool GUIModalMenu::simulateMouseEvent( default: return false; } - if (preprocessEvent(mouse_event)) - return true; - if (!target) - return false; - return target->OnEvent(mouse_event); + + bool retval; + m_simulated_mouse = true; + do { + if (preprocessEvent(mouse_event)) { + retval = true; + break; + } + if (!target) { + retval = false; + break; + } + retval = target->OnEvent(mouse_event); + } while (false); + m_simulated_mouse = false; + + return retval; } void GUIModalMenu::enter(gui::IGUIElement *hovered) { if (!hovered) return; - sanity_check(!m_hovered); - m_hovered.grab(hovered); + sanity_check(!m_touch_hovered); + m_touch_hovered.grab(hovered); SEvent gui_event{}; gui_event.EventType = EET_GUI_EVENT; - gui_event.GUIEvent.Caller = m_hovered.get(); - gui_event.GUIEvent.EventType = EGET_ELEMENT_HOVERED; + gui_event.GUIEvent.Caller = m_touch_hovered.get(); + gui_event.GUIEvent.EventType = gui::EGET_ELEMENT_HOVERED; gui_event.GUIEvent.Element = gui_event.GUIEvent.Caller; - m_hovered->OnEvent(gui_event); + m_touch_hovered->OnEvent(gui_event); } void GUIModalMenu::leave() { - if (!m_hovered) + if (!m_touch_hovered) return; SEvent gui_event{}; gui_event.EventType = EET_GUI_EVENT; - gui_event.GUIEvent.Caller = m_hovered.get(); - gui_event.GUIEvent.EventType = EGET_ELEMENT_LEFT; - m_hovered->OnEvent(gui_event); - m_hovered.reset(); + gui_event.GUIEvent.Caller = m_touch_hovered.get(); + gui_event.GUIEvent.EventType = gui::EGET_ELEMENT_LEFT; + m_touch_hovered->OnEvent(gui_event); + m_touch_hovered.reset(); } -#endif - bool GUIModalMenu::preprocessEvent(const SEvent &event) { #ifdef __ANDROID__ @@ -268,25 +277,26 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event) } #endif -#ifdef HAVE_TOUCHSCREENGUI + // Convert touch events into mouse events. if (event.EventType == EET_TOUCH_INPUT_EVENT) { irr_ptr holder; holder.grab(this); // keep this alive until return (it might be dropped downstream [?]) if (event.TouchInput.touchedCount == 1) { - if (event.TouchInput.Event == ETIE_PRESSED_DOWN || event.TouchInput.Event == ETIE_MOVED) - m_pointer = v2s32(event.TouchInput.X, event.TouchInput.Y); + m_pointer_type = PointerType::Touch; + m_pointer = v2s32(event.TouchInput.X, event.TouchInput.Y); + gui::IGUIElement *hovered = Environment->getRootGUIElement()->getElementFromPoint(core::position2d(m_pointer)); if (event.TouchInput.Event == ETIE_PRESSED_DOWN) Environment->setFocus(hovered); - if (m_hovered != hovered) { + if (m_touch_hovered != hovered) { leave(); enter(hovered); } gui::IGUIElement *focused = Environment->getFocus(); bool ret = simulateMouseEvent(focused, event.TouchInput.Event); - if (!ret && m_hovered != focused) - ret = simulateMouseEvent(m_hovered.get(), event.TouchInput.Event); + if (!ret && m_touch_hovered != focused) + ret = simulateMouseEvent(m_touch_hovered.get(), event.TouchInput.Event); if (event.TouchInput.Event == ETIE_LEFT_UP) leave(); return ret; @@ -306,20 +316,24 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event) return true; } } -#endif if (event.EventType == EET_MOUSE_INPUT_EVENT) { - s32 x = event.MouseInput.X; - s32 y = event.MouseInput.Y; + if (!m_simulated_mouse) { + // Only set the pointer type to mouse if this is a real mouse event. + m_pointer_type = PointerType::Mouse; + m_pointer = v2s32(event.MouseInput.X, event.MouseInput.Y); + m_touch_hovered.reset(); + } + gui::IGUIElement *hovered = - Environment->getRootGUIElement()->getElementFromPoint( - core::position2d(x, y)); + Environment->getRootGUIElement()->getElementFromPoint(m_pointer); if (!isChild(hovered, this)) { if (DoubleClickDetection(event)) { return true; } } } + return false; } diff --git a/src/gui/modalMenu.h b/src/gui/modalMenu.h index f811bafc9..30eda8bc9 100644 --- a/src/gui/modalMenu.h +++ b/src/gui/modalMenu.h @@ -23,6 +23,11 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "irr_ptr.h" #include "util/string.h" +enum class PointerType { + Mouse, + Touch, +}; + class GUIModalMenu; class IMenuManager @@ -58,6 +63,8 @@ public: bool hasAndroidUIInput(); #endif + PointerType getPointerType() { return m_pointer_type; }; + protected: virtual std::wstring getLabelByID(s32 id) = 0; virtual std::string getNameByID(s32 id) = 0; @@ -69,18 +76,25 @@ protected: */ bool DoubleClickDetection(const SEvent &event); + // Stores the last known pointer type. + PointerType m_pointer_type = PointerType::Mouse; + // Stores the last known pointer position. + // If the last input event was a mouse event, it's the cursor position. + // If the last input event was a touch event, it's the finger position. v2s32 m_pointer; v2s32 m_old_pointer; // Mouse position after previous mouse event + v2u32 m_screensize_old; float m_gui_scale; #ifdef __ANDROID__ std::string m_jni_field_name; #endif -#ifdef HAVE_TOUCHSCREENGUI + // This is set to true if the menu is currently processing a second-touch event. bool m_second_touch = false; - bool m_touchscreen_visible = true; -#endif + // This is set to true if the menu is currently processing a mouse event + // that was synthesized by the menu itself from a touch event. + bool m_simulated_mouse = false; private: struct clickpos @@ -102,11 +116,11 @@ private: // wants to launch other menus bool m_allow_focus_removal = false; -#ifdef HAVE_TOUCHSCREENGUI - irr_ptr m_hovered; + // Stuff related to touchscreen input + + irr_ptr m_touch_hovered; bool simulateMouseEvent(gui::IGUIElement *target, ETOUCH_INPUT_EVENT touch_event); void enter(gui::IGUIElement *element); void leave(); -#endif };