From cfaef5b1cfc8ec7463a2e8aec420bfc3a434f9c1 Mon Sep 17 00:00:00 2001 From: Zughy <63455151+Zughy@users.noreply.github.com> Date: Tue, 14 Jul 2020 22:37:28 +0200 Subject: [PATCH] Formspecs: volume and key settings windows can now be closed by doubleclicking/tapping (#10128) Co-authored-by: Xx_Crazyminer_xX Co-authored-by: Marco <4279489-marco_a@users.noreply.gitlab.com> --- src/gui/guiConfirmRegistration.cpp | 2 +- src/gui/guiEngine.h | 1 - src/gui/guiFormSpecMenu.cpp | 99 +----------------------------- src/gui/guiFormSpecMenu.h | 22 ------- src/gui/guiKeyChangeMenu.cpp | 2 +- src/gui/guiMainMenu.h | 1 - src/gui/guiPasswordChange.cpp | 2 +- src/gui/guiVolumeChange.cpp | 2 +- src/gui/modalMenu.cpp | 90 ++++++++++++++++++++++++++- src/gui/modalMenu.h | 28 ++++++++- 10 files changed, 119 insertions(+), 130 deletions(-) diff --git a/src/gui/guiConfirmRegistration.cpp b/src/gui/guiConfirmRegistration.cpp index 58ac427406d2..55c111df8346 100644 --- a/src/gui/guiConfirmRegistration.cpp +++ b/src/gui/guiConfirmRegistration.cpp @@ -222,7 +222,7 @@ bool GUIConfirmRegistration::OnEvent(const SEvent &event) if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) { if (!canTakeFocus(event.GUIEvent.Element)) { - dstream << "GUIConfirmRegistration: Not allowing focus change." + infostream << "GUIConfirmRegistration: Not allowing focus change." << std::endl; // Returning true disables focus change return true; diff --git a/src/gui/guiEngine.h b/src/gui/guiEngine.h index e55531bbca63..f9ad0fb0a90c 100644 --- a/src/gui/guiEngine.h +++ b/src/gui/guiEngine.h @@ -23,7 +23,6 @@ with this program; if not, write to the Free Software Foundation, Inc., /* Includes */ /******************************************************************************/ #include "irrlichttypes.h" -#include "modalMenu.h" #include "guiFormSpecMenu.h" #include "client/sound.h" #include "client/tile.h" diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index db89d2c43bfa..601c5c18ee40 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -95,29 +95,21 @@ inline u32 clamp_u8(s32 value) GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick, gui::IGUIElement *parent, s32 id, IMenuManager *menumgr, Client *client, ISimpleTextureSource *tsrc, IFormSource *fsrc, TextDest *tdst, - const std::string &formspecPrepend, - bool remap_dbl_click): - GUIModalMenu(RenderingEngine::get_gui_env(), parent, id, menumgr), + const std::string &formspecPrepend, bool remap_dbl_click): + GUIModalMenu(RenderingEngine::get_gui_env(), parent, id, menumgr, remap_dbl_click), m_invmgr(client), m_tsrc(tsrc), m_client(client), m_formspec_prepend(formspecPrepend), m_form_src(fsrc), m_text_dst(tdst), - m_joystick(joystick), - m_remap_dbl_click(remap_dbl_click) + m_joystick(joystick) { current_keys_pending.key_down = false; current_keys_pending.key_up = false; current_keys_pending.key_enter = false; current_keys_pending.key_escape = false; - m_doubleclickdetect[0].time = 0; - m_doubleclickdetect[1].time = 0; - - m_doubleclickdetect[0].pos = v2s32(0, 0); - m_doubleclickdetect[1].pos = v2s32(0, 0); - m_tooltip_show_delay = (u32)g_settings->getS32("tooltip_show_delay"); m_tooltip_append_itemname = g_settings->getBool("tooltip_append_itemname"); } @@ -3851,17 +3843,6 @@ void GUIFormSpecMenu::acceptInput(FormspecQuitMode quitmode=quit_mode_no) } } -static bool isChild(gui::IGUIElement *tocheck, gui::IGUIElement *parent) -{ - while (tocheck) { - if (tocheck == parent) { - return true; - } - tocheck = tocheck->getParent(); - } - return false; -} - bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) { // The IGUITabControl renders visually using the skin's selected @@ -3922,22 +3903,6 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) } } - if (event.EventType == EET_MOUSE_INPUT_EVENT) { - s32 x = event.MouseInput.X; - s32 y = event.MouseInput.Y; - gui::IGUIElement *hovered = - Environment->getRootGUIElement()->getElementFromPoint( - core::position2d(x, y)); - if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { - m_old_tooltip_id = -1; - } - if (!isChild(hovered, this)) { - if (DoubleClickDetection(event)) { - return true; - } - } - } - if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { /* TODO add a check like: if (event.JoystickEvent != joystick_we_listen_for) @@ -3960,64 +3925,6 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) return GUIModalMenu::preprocessEvent(event); } -/******************************************************************************/ -bool GUIFormSpecMenu::DoubleClickDetection(const SEvent event) -{ - /* The following code is for capturing double-clicks of the mouse button - * and translating the double-click into an EET_KEY_INPUT_EVENT event - * -- which closes the form -- under some circumstances. - * - * There have been many github issues reporting this as a bug even though it - * was an intended feature. For this reason, remapping the double-click as - * an ESC must be explicitly set when creating this class via the - * /p remap_dbl_click parameter of the constructor. - */ - - if (!m_remap_dbl_click) - return false; - - if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { - m_doubleclickdetect[0].pos = m_doubleclickdetect[1].pos; - m_doubleclickdetect[0].time = m_doubleclickdetect[1].time; - - m_doubleclickdetect[1].pos = m_pointer; - m_doubleclickdetect[1].time = porting::getTimeMs(); - } - else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) { - u64 delta = porting::getDeltaMs(m_doubleclickdetect[0].time, porting::getTimeMs()); - if (delta > 400) { - return false; - } - - double squaredistance = - m_doubleclickdetect[0].pos - .getDistanceFromSQ(m_doubleclickdetect[1].pos); - - if (squaredistance > (30*30)) { - return false; - } - - SEvent* translated = new SEvent(); - assert(translated != 0); - //translate doubleclick to escape - memset(translated, 0, sizeof(SEvent)); - translated->EventType = irr::EET_KEY_INPUT_EVENT; - translated->KeyInput.Key = KEY_ESCAPE; - translated->KeyInput.Control = false; - translated->KeyInput.Shift = false; - translated->KeyInput.PressedDown = true; - translated->KeyInput.Char = 0; - OnEvent(*translated); - - // no need to send the key up event as we're already deleted - // and no one else did notice this event - delete translated; - return true; - } - - return false; -} - void GUIFormSpecMenu::tryClose() { if (m_allowclose) { diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index 5a6b467aad7a..613acaa043fb 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -457,30 +457,8 @@ class GUIFormSpecMenu : public GUIModalMenu */ void legacySortElements(core::list::Iterator from); - /** - * check if event is part of a double click - * @param event event to evaluate - * @return true/false if a doubleclick was detected - */ - bool DoubleClickDetection(const SEvent event); - - struct clickpos - { - v2s32 pos; - s64 time; - }; - clickpos m_doubleclickdetect[2]; - int m_btn_height; gui::IGUIFont *m_font = nullptr; - - /* If true, remap a double-click (or double-tap) action to ESC. This is so - * that, for example, Android users can double-tap to close a formspec. - * - * This value can (currently) only be set by the class constructor - * and the default value for the setting is true. - */ - bool m_remap_dbl_click; }; class FormspecFormSource: public IFormSource diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp index da0e25c239b9..eb641d952305 100644 --- a/src/gui/guiKeyChangeMenu.cpp +++ b/src/gui/guiKeyChangeMenu.cpp @@ -360,7 +360,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event) { if (!canTakeFocus(event.GUIEvent.Element)) { - dstream << "GUIMainMenu: Not allowing focus change." + infostream << "GUIKeyChangeMenu: Not allowing focus change." << std::endl; // Returning true disables focus change return true; diff --git a/src/gui/guiMainMenu.h b/src/gui/guiMainMenu.h index 43a3b1a33e85..1dca8bf2d295 100644 --- a/src/gui/guiMainMenu.h +++ b/src/gui/guiMainMenu.h @@ -20,7 +20,6 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include "irrlichttypes_extrabloated.h" -#include "modalMenu.h" #include #include diff --git a/src/gui/guiPasswordChange.cpp b/src/gui/guiPasswordChange.cpp index 965a2d6f75a4..5311c6fefb1d 100644 --- a/src/gui/guiPasswordChange.cpp +++ b/src/gui/guiPasswordChange.cpp @@ -236,7 +236,7 @@ bool GUIPasswordChange::OnEvent(const SEvent &event) if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) { if (!canTakeFocus(event.GUIEvent.Element)) { - dstream << "GUIPasswordChange: Not allowing focus change." + infostream << "GUIPasswordChange: Not allowing focus change." << std::endl; // Returning true disables focus change return true; diff --git a/src/gui/guiVolumeChange.cpp b/src/gui/guiVolumeChange.cpp index 07b11248ca2c..f17cfa9867e0 100644 --- a/src/gui/guiVolumeChange.cpp +++ b/src/gui/guiVolumeChange.cpp @@ -171,7 +171,7 @@ bool GUIVolumeChange::OnEvent(const SEvent& event) if (event.GUIEvent.EventType == gui::EGET_ELEMENT_FOCUS_LOST && isVisible()) { if (!canTakeFocus(event.GUIEvent.Element)) { - dstream << "GUIMainMenu: Not allowing focus change." + infostream << "GUIVolumeChange: Not allowing focus change." << std::endl; // Returning true disables focus change return true; diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp index a6fe7ebaf4fc..9b1e6dd9c7c8 100644 --- a/src/gui/modalMenu.cpp +++ b/src/gui/modalMenu.cpp @@ -28,14 +28,16 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "touchscreengui.h" #endif -GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, s32 id, - IMenuManager *menumgr) : +// clang-format off +GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, + s32 id, IMenuManager *menumgr, bool remap_dbl_click) : IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, core::rect(0, 0, 100, 100)), #ifdef __ANDROID__ m_jni_field_name(""), #endif - m_menumgr(menumgr) + m_menumgr(menumgr), + m_remap_dbl_click(remap_dbl_click) { m_gui_scale = g_settings->getFloat("gui_scaling"); #ifdef __ANDROID__ @@ -45,6 +47,12 @@ GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment *env, gui::IGUIElement *parent, setVisible(true); Environment->setFocus(this); m_menumgr->createdMenu(this); + + m_doubleclickdetect[0].time = 0; + m_doubleclickdetect[1].time = 0; + + m_doubleclickdetect[0].pos = v2s32(0, 0); + m_doubleclickdetect[1].pos = v2s32(0, 0); } // clang-format on @@ -112,6 +120,69 @@ void GUIModalMenu::removeChildren() } } +// clang-format off +bool GUIModalMenu::DoubleClickDetection(const SEvent &event) +{ + /* The following code is for capturing double-clicks of the mouse button + * and translating the double-click into an EET_KEY_INPUT_EVENT event + * -- which closes the form -- under some circumstances. + * + * There have been many github issues reporting this as a bug even though it + * was an intended feature. For this reason, remapping the double-click as + * an ESC must be explicitly set when creating this class via the + * /p remap_dbl_click parameter of the constructor. + */ + + if (!m_remap_dbl_click) + return false; + + if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { + m_doubleclickdetect[0].pos = m_doubleclickdetect[1].pos; + m_doubleclickdetect[0].time = m_doubleclickdetect[1].time; + + m_doubleclickdetect[1].pos = m_pointer; + m_doubleclickdetect[1].time = porting::getTimeMs(); + } else if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP) { + u64 delta = porting::getDeltaMs( + m_doubleclickdetect[0].time, porting::getTimeMs()); + if (delta > 400) + return false; + + double squaredistance = m_doubleclickdetect[0].pos. + getDistanceFromSQ(m_doubleclickdetect[1].pos); + + if (squaredistance > (30 * 30)) { + return false; + } + + SEvent translated{}; + // translate doubleclick to escape + translated.EventType = EET_KEY_INPUT_EVENT; + translated.KeyInput.Key = KEY_ESCAPE; + translated.KeyInput.Control = false; + translated.KeyInput.Shift = false; + translated.KeyInput.PressedDown = true; + translated.KeyInput.Char = 0; + OnEvent(translated); + + return true; + } + + return false; +} +// clang-format on + +static bool isChild(gui::IGUIElement *tocheck, gui::IGUIElement *parent) +{ + while (tocheck) { + if (tocheck == parent) { + return true; + } + tocheck = tocheck->getParent(); + } + return false; +} + bool GUIModalMenu::preprocessEvent(const SEvent &event) { #ifdef __ANDROID__ @@ -245,6 +316,19 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event) } } #endif + + if (event.EventType == EET_MOUSE_INPUT_EVENT) { + s32 x = event.MouseInput.X; + s32 y = event.MouseInput.Y; + gui::IGUIElement *hovered = + Environment->getRootGUIElement()->getElementFromPoint( + core::position2d(x, y)); + if (!isChild(hovered, this)) { + if (DoubleClickDetection(event)) { + return true; + } + } + } return false; } diff --git a/src/gui/modalMenu.h b/src/gui/modalMenu.h index 5bd70bb84749..1cb687f82782 100644 --- a/src/gui/modalMenu.h +++ b/src/gui/modalMenu.h @@ -39,7 +39,7 @@ class GUIModalMenu : public gui::IGUIElement { public: GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr); + IMenuManager *menumgr, bool remap_dbl_click = true); virtual ~GUIModalMenu(); void allowFocusRemoval(bool allow); @@ -50,8 +50,8 @@ class GUIModalMenu : public gui::IGUIElement virtual void regenerateGui(v2u32 screensize) = 0; virtual void drawMenu() = 0; - virtual bool preprocessEvent(const SEvent& event); - virtual bool OnEvent(const SEvent& event) { return false; }; + virtual bool preprocessEvent(const SEvent &event); + virtual bool OnEvent(const SEvent &event) { return false; }; virtual bool pausesGame() { return false; } // Used for pause menu #ifdef __ANDROID__ virtual bool getAndroidUIInput() { return false; } @@ -62,6 +62,13 @@ class GUIModalMenu : public gui::IGUIElement virtual std::wstring getLabelByID(s32 id) = 0; virtual std::string getNameByID(s32 id) = 0; + /** + * check if event is part of a double click + * @param event event to evaluate + * @return true/false if a doubleclick was detected + */ + bool DoubleClickDetection(const SEvent &event); + v2s32 m_pointer; v2s32 m_old_pointer; // Mouse position after previous mouse event v2u32 m_screensize_old; @@ -73,8 +80,23 @@ class GUIModalMenu : public gui::IGUIElement #ifdef HAVE_TOUCHSCREENGUI bool m_touchscreen_visible = true; #endif + private: + struct clickpos + { + v2s32 pos; + s64 time; + }; + clickpos m_doubleclickdetect[2]; + IMenuManager *m_menumgr; + /* If true, remap a double-click (or double-tap) action to ESC. This is so + * that, for example, Android users can double-tap to close a formspec. + * + * This value can (currently) only be set by the class constructor + * and the default value for the setting is true. + */ + bool m_remap_dbl_click; // This might be necessary to expose to the implementation if it // wants to launch other menus bool m_allow_focus_removal = false;