From 323c8600450a5ae3893de9ba1d04095589c5b06c Mon Sep 17 00:00:00 2001 From: stujones11 Date: Sun, 24 Jun 2018 20:50:57 +0100 Subject: [PATCH] Move touchscreen input handling to base GUIModalMenu class --- build/android/jni/Android.mk | 1 + src/game.cpp | 9 +- src/gui/CMakeLists.txt | 1 + src/gui/guiConfirmRegistration.cpp | 28 ++- src/gui/guiConfirmRegistration.h | 6 + src/gui/guiFormSpecMenu.cpp | 178 +----------------- src/gui/guiFormSpecMenu.h | 11 +- src/gui/guiKeyChangeMenu.h | 4 + src/gui/guiPasswordChange.cpp | 48 ++++- src/gui/guiPasswordChange.h | 7 + src/gui/guiPathSelectMenu.h | 4 + src/gui/guiVolumeChange.h | 4 + src/gui/modalMenu.cpp | 283 +++++++++++++++++++++++++++++ src/gui/modalMenu.h | 113 +++--------- 14 files changed, 425 insertions(+), 272 deletions(-) create mode 100644 src/gui/modalMenu.cpp diff --git a/build/android/jni/Android.mk b/build/android/jni/Android.mk index 548e56ffe..e5cf7349c 100644 --- a/build/android/jni/Android.mk +++ b/build/android/jni/Android.mk @@ -165,6 +165,7 @@ LOCAL_SRC_FILES := \ jni/src/guiscalingfilter.cpp \ jni/src/gui/guiVolumeChange.cpp \ jni/src/gui/intlGUIEditBox.cpp \ + jni/src/gui/modalMenu.cpp \ jni/src/gui/profilergraph.cpp \ jni/src/gui/touchscreengui.cpp \ jni/src/httpfetch.cpp \ diff --git a/src/game.cpp b/src/game.cpp index 34606172c..227b21db5 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1288,7 +1288,12 @@ bool Game::createClient(const std::string &playername, return false; bool could_connect, connect_aborted; - +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui) { + g_touchscreengui->init(texture_src); + g_touchscreengui->hide(); + } +#endif if (!connectToServer(playername, password, address, port, &could_connect, &connect_aborted)) return false; @@ -1414,7 +1419,7 @@ bool Game::initGui() #ifdef HAVE_TOUCHSCREENGUI if (g_touchscreengui) - g_touchscreengui->init(texture_src); + g_touchscreengui->show(); #endif diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index b52ea0349..4bc451825 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -10,6 +10,7 @@ set(gui_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/guiTable.cpp ${CMAKE_CURRENT_SOURCE_DIR}/guiVolumeChange.cpp ${CMAKE_CURRENT_SOURCE_DIR}/intlGUIEditBox.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/modalMenu.cpp ${CMAKE_CURRENT_SOURCE_DIR}/profilergraph.cpp PARENT_SCOPE ) diff --git a/src/gui/guiConfirmRegistration.cpp b/src/gui/guiConfirmRegistration.cpp index 7f5aec264..9ffd9563e 100644 --- a/src/gui/guiConfirmRegistration.cpp +++ b/src/gui/guiConfirmRegistration.cpp @@ -43,6 +43,9 @@ GUIConfirmRegistration::GUIConfirmRegistration(gui::IGUIEnvironment *env, m_client(client), m_playername(playername), m_password(password), m_address(address), m_aborted(aborted) { +#ifdef __ANDROID__ + m_touchscreen_visible = false; +#endif } GUIConfirmRegistration::~GUIConfirmRegistration() @@ -157,6 +160,9 @@ void GUIConfirmRegistration::drawMenu() driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); gui::IGUIElement::draw(); +#ifdef __ANDROID__ + getAndroidUIInput(); +#endif } void GUIConfirmRegistration::closeMenu(bool goNext) @@ -193,10 +199,14 @@ bool GUIConfirmRegistration::processInput() bool GUIConfirmRegistration::OnEvent(const SEvent &event) { if (event.EventType == EET_KEY_INPUT_EVENT) { - if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) { + // clang-format off + if ((event.KeyInput.Key == KEY_ESCAPE || + event.KeyInput.Key == KEY_CANCEL) && + event.KeyInput.PressedDown) { closeMenu(false); return true; } + // clang-format on if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) { acceptInput(); if (processInput()) @@ -239,3 +249,19 @@ bool GUIConfirmRegistration::OnEvent(const SEvent &event) return false; } + +#ifdef __ANDROID__ +bool GUIConfirmRegistration::getAndroidUIInput() +{ + if (!hasAndroidUIInput() || m_jni_field_name != "password") + return false; + + std::string text = porting::getInputDialogValue(); + gui::IGUIElement *e = getElementFromId(ID_confirmPassword); + if (e) + e->setText(utf8_to_wide(text).c_str()); + + m_jni_field_name.clear(); + return false; +} +#endif diff --git a/src/gui/guiConfirmRegistration.h b/src/gui/guiConfirmRegistration.h index e14066e0e..2f2066c21 100644 --- a/src/gui/guiConfirmRegistration.h +++ b/src/gui/guiConfirmRegistration.h @@ -50,8 +50,14 @@ public: bool processInput(); bool OnEvent(const SEvent &event); +#ifdef __ANDROID__ + bool getAndroidUIInput(); +#endif private: + std::wstring getLabelByID(s32 id) { return L""; } + std::string getNameByID(s32 id) { return "password"; } + Client *m_client = nullptr; const std::string &m_playername; const std::string &m_password; diff --git a/src/gui/guiFormSpecMenu.cpp b/src/gui/guiFormSpecMenu.cpp index ed94b82de..363128012 100644 --- a/src/gui/guiFormSpecMenu.cpp +++ b/src/gui/guiFormSpecMenu.cpp @@ -97,9 +97,6 @@ GUIFormSpecMenu::GUIFormSpecMenu(JoystickController *joystick, m_text_dst(tdst), m_joystick(joystick), m_remap_dbl_click(remap_dbl_click) -#ifdef __ANDROID__ - , m_JavaDialogFieldName("") -#endif { current_keys_pending.key_down = false; current_keys_pending.key_up = false; @@ -2265,23 +2262,11 @@ void GUIFormSpecMenu::regenerateGui(v2u32 screensize) #ifdef __ANDROID__ bool GUIFormSpecMenu::getAndroidUIInput() { - /* no dialog shown */ - if (m_JavaDialogFieldName == "") { + if (!hasAndroidUIInput()) return false; - } - /* still waiting */ - if (porting::getInputDialogState() == -1) { - return true; - } - - std::string fieldname = m_JavaDialogFieldName; - m_JavaDialogFieldName = ""; - - /* no value abort dialog processing */ - if (porting::getInputDialogState() != 0) { - return false; - } + std::string fieldname = m_jni_field_name; + m_jni_field_name.clear(); for(std::vector::iterator iter = m_fields.begin(); iter != m_fields.end(); ++iter) { @@ -2301,8 +2286,7 @@ bool GUIFormSpecMenu::getAndroidUIInput() std::string text = porting::getInputDialogValue(); - ((gui::IGUIEditBox*) tochange)-> - setText(utf8_to_wide(text).c_str()); + ((gui::IGUIEditBox *)tochange)->setText(utf8_to_wide(text).c_str()); } return false; } @@ -3043,158 +3027,6 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) } } - #ifdef __ANDROID__ - // display software keyboard when clicking edit boxes - if (event.EventType == EET_MOUSE_INPUT_EVENT - && event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { - gui::IGUIElement *hovered = - Environment->getRootGUIElement()->getElementFromPoint( - core::position2d(event.MouseInput.X, event.MouseInput.Y)); - if ((hovered) && (hovered->getType() == irr::gui::EGUIET_EDIT_BOX)) { - bool retval = hovered->OnEvent(event); - if (retval) - Environment->setFocus(hovered); - - std::string field_name = getNameByID(hovered->getID()); - /* read-only field */ - if (field_name.empty()) - return retval; - - m_JavaDialogFieldName = field_name; - std::string message = gettext("Enter "); - std::string label = wide_to_utf8(getLabelByID(hovered->getID())); - if (label.empty()) - label = "text"; - message += gettext(label) + ":"; - - /* single line text input */ - int type = 2; - - /* multi line text input */ - if (((gui::IGUIEditBox*) hovered)->isMultiLineEnabled()) - type = 1; - - /* passwords are always single line */ - if (((gui::IGUIEditBox*) hovered)->isPasswordBox()) - type = 3; - - porting::showInputDialog(gettext("ok"), "", - wide_to_utf8(((gui::IGUIEditBox*) hovered)->getText()), - type); - return retval; - } - } - - if (event.EventType == EET_TOUCH_INPUT_EVENT) - { - SEvent translated; - memset(&translated, 0, sizeof(SEvent)); - translated.EventType = EET_MOUSE_INPUT_EVENT; - gui::IGUIElement* root = Environment->getRootGUIElement(); - - if (!root) { - errorstream - << "GUIFormSpecMenu::preprocessEvent unable to get root element" - << std::endl; - return false; - } - gui::IGUIElement* hovered = root->getElementFromPoint( - core::position2d( - event.TouchInput.X, - event.TouchInput.Y)); - - translated.MouseInput.X = event.TouchInput.X; - translated.MouseInput.Y = event.TouchInput.Y; - translated.MouseInput.Control = false; - - bool dont_send_event = false; - - if (event.TouchInput.touchedCount == 1) { - switch (event.TouchInput.Event) { - case ETIE_PRESSED_DOWN: - m_pointer = v2s32(event.TouchInput.X,event.TouchInput.Y); - translated.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN; - translated.MouseInput.ButtonStates = EMBSM_LEFT; - m_down_pos = m_pointer; - break; - case ETIE_MOVED: - m_pointer = v2s32(event.TouchInput.X,event.TouchInput.Y); - translated.MouseInput.Event = EMIE_MOUSE_MOVED; - translated.MouseInput.ButtonStates = EMBSM_LEFT; - break; - case ETIE_LEFT_UP: - translated.MouseInput.Event = EMIE_LMOUSE_LEFT_UP; - translated.MouseInput.ButtonStates = 0; - hovered = root->getElementFromPoint(m_down_pos); - /* we don't have a valid pointer element use last - * known pointer pos */ - translated.MouseInput.X = m_pointer.X; - translated.MouseInput.Y = m_pointer.Y; - - /* reset down pos */ - m_down_pos = v2s32(0,0); - break; - default: - dont_send_event = true; - //this is not supposed to happen - errorstream - << "GUIFormSpecMenu::preprocessEvent unexpected usecase Event=" - << event.TouchInput.Event << std::endl; - } - } else if ( (event.TouchInput.touchedCount == 2) && - (event.TouchInput.Event == ETIE_PRESSED_DOWN) ) { - hovered = root->getElementFromPoint(m_down_pos); - - translated.MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN; - translated.MouseInput.ButtonStates = EMBSM_LEFT | EMBSM_RIGHT; - translated.MouseInput.X = m_pointer.X; - translated.MouseInput.Y = m_pointer.Y; - - if (hovered) { - hovered->OnEvent(translated); - } - - translated.MouseInput.Event = EMIE_RMOUSE_LEFT_UP; - translated.MouseInput.ButtonStates = EMBSM_LEFT; - - - if (hovered) { - hovered->OnEvent(translated); - } - dont_send_event = true; - } - /* ignore unhandled 2 touch events ... accidental moving for example */ - else if (event.TouchInput.touchedCount == 2) { - dont_send_event = true; - } - else if (event.TouchInput.touchedCount > 2) { - errorstream - << "GUIFormSpecMenu::preprocessEvent to many multitouch events " - << event.TouchInput.touchedCount << " ignoring them" << std::endl; - } - - if (dont_send_event) { - return true; - } - - /* check if translated event needs to be preprocessed again */ - if (preprocessEvent(translated)) { - return true; - } - if (hovered) { - grab(); - bool retval = hovered->OnEvent(translated); - - if (event.TouchInput.Event == ETIE_LEFT_UP) { - /* reset pointer */ - m_pointer = v2s32(0,0); - } - drop(); - return retval; - } - } - #endif - if (event.EventType == irr::EET_JOYSTICK_INPUT_EVENT) { /* TODO add a check like: if (event.JoystickEvent != joystick_we_listen_for) @@ -3214,7 +3046,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event) return handled; } - return false; + return GUIModalMenu::preprocessEvent(event); } /******************************************************************************/ diff --git a/src/gui/guiFormSpecMenu.h b/src/gui/guiFormSpecMenu.h index 926faa350..d75a108d4 100644 --- a/src/gui/guiFormSpecMenu.h +++ b/src/gui/guiFormSpecMenu.h @@ -372,6 +372,8 @@ protected: { return padding + offset + AbsoluteRect.UpperLeftCorner; } + std::wstring getLabelByID(s32 id); + std::string getNameByID(s32 id); v2s32 getElementBasePos(bool absolute, const std::vector *v_pos); @@ -411,8 +413,6 @@ protected: bool m_selected_dragging = false; ItemStack m_selected_swap; - v2s32 m_pointer; - v2s32 m_old_pointer; // Mouse position after previous mouse event gui::IGUIStaticText *m_tooltip_element = nullptr; u64 m_tooltip_show_delay; @@ -535,13 +535,6 @@ private: int m_btn_height; gui::IGUIFont *m_font = nullptr; - std::wstring getLabelByID(s32 id); - std::string getNameByID(s32 id); -#ifdef __ANDROID__ - v2s32 m_down_pos; - std::string m_JavaDialogFieldName; -#endif - /* 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. * diff --git a/src/gui/guiKeyChangeMenu.h b/src/gui/guiKeyChangeMenu.h index 7cf11d3f9..eded61e4c 100644 --- a/src/gui/guiKeyChangeMenu.h +++ b/src/gui/guiKeyChangeMenu.h @@ -58,6 +58,10 @@ public: bool pausesGame() { return true; } +protected: + std::wstring getLabelByID(s32 id) { return L""; } + std::string getNameByID(s32 id) { return ""; } + private: void init_keys(); diff --git a/src/gui/guiPasswordChange.cpp b/src/gui/guiPasswordChange.cpp index 46de2026c..14e28cd36 100644 --- a/src/gui/guiPasswordChange.cpp +++ b/src/gui/guiPasswordChange.cpp @@ -23,7 +23,8 @@ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include #include #include - +#include "keycode.h" +#include "porting.h" #include "gettext.h" const int ID_oldPassword = 256; @@ -180,6 +181,9 @@ void GUIPasswordChange::drawMenu() driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect); gui::IGUIElement::draw(); +#ifdef __ANDROID__ + getAndroidUIInput(); +#endif } void GUIPasswordChange::acceptInput() @@ -211,10 +215,14 @@ bool GUIPasswordChange::processInput() bool GUIPasswordChange::OnEvent(const SEvent &event) { if (event.EventType == EET_KEY_INPUT_EVENT) { - if (event.KeyInput.Key == KEY_ESCAPE && event.KeyInput.PressedDown) { + // clang-format off + if ((event.KeyInput.Key == KEY_ESCAPE || + event.KeyInput.Key == KEY_CANCEL) && + event.KeyInput.PressedDown) { quitMenu(); return true; } + // clang-format on if (event.KeyInput.Key == KEY_RETURN && event.KeyInput.PressedDown) { acceptInput(); if (processInput()) @@ -259,3 +267,39 @@ bool GUIPasswordChange::OnEvent(const SEvent &event) return Parent ? Parent->OnEvent(event) : false; } + +std::string GUIPasswordChange::getNameByID(s32 id) +{ + switch (id) { + case ID_oldPassword: + return "old_password"; + case ID_newPassword1: + return "new_password_1"; + case ID_newPassword2: + return "new_password_2"; + } + return ""; +} + +#ifdef __ANDROID__ +bool GUIPasswordChange::getAndroidUIInput() +{ + if (!hasAndroidUIInput()) + return false; + + gui::IGUIElement *e = nullptr; + if (m_jni_field_name == "old_password") + e = getElementFromId(ID_oldPassword); + else if (m_jni_field_name == "new_password_1") + e = getElementFromId(ID_newPassword1); + else if (m_jni_field_name == "new_password_2") + e = getElementFromId(ID_newPassword2); + + if (e) { + std::string text = porting::getInputDialogValue(); + e->setText(utf8_to_wide(text).c_str()); + } + m_jni_field_name.clear(); + return false; +} +#endif diff --git a/src/gui/guiPasswordChange.h b/src/gui/guiPasswordChange.h index 59f3513b2..58541a399 100644 --- a/src/gui/guiPasswordChange.h +++ b/src/gui/guiPasswordChange.h @@ -44,6 +44,13 @@ public: bool processInput(); bool OnEvent(const SEvent &event); +#ifdef __ANDROID__ + bool getAndroidUIInput(); +#endif + +protected: + std::wstring getLabelByID(s32 id) { return L""; } + std::string getNameByID(s32 id); private: Client *m_client; diff --git a/src/gui/guiPathSelectMenu.h b/src/gui/guiPathSelectMenu.h index f69d0acd7..11307d682 100644 --- a/src/gui/guiPathSelectMenu.h +++ b/src/gui/guiPathSelectMenu.h @@ -44,6 +44,10 @@ public: void setTextDest(TextDest *dest) { m_text_dst = dest; } +protected: + std::wstring getLabelByID(s32 id) { return L""; } + std::string getNameByID(s32 id) { return ""; } + private: void acceptInput(); diff --git a/src/gui/guiVolumeChange.h b/src/gui/guiVolumeChange.h index 7c7e19a86..f4f4e9eea 100644 --- a/src/gui/guiVolumeChange.h +++ b/src/gui/guiVolumeChange.h @@ -42,4 +42,8 @@ public: bool OnEvent(const SEvent& event); bool pausesGame() { return true; } + +protected: + std::wstring getLabelByID(s32 id) { return L""; } + std::string getNameByID(s32 id) { return ""; } }; diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp new file mode 100644 index 000000000..d8df2540c --- /dev/null +++ b/src/gui/modalMenu.cpp @@ -0,0 +1,283 @@ +/* +Minetest +Copyright (C) 2013 celeron55, Perttu Ahola +Copyright (C) 2018 stujones11, Stuart Jones + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as published by +the Free Software Foundation; either version 2.1 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#include +#include "modalMenu.h" +#include "gettext.h" +#include "porting.h" + +#ifdef HAVE_TOUCHSCREENGUI +#include "touchscreengui.h" +#endif + +// clang-format off +GUIModalMenu::GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, + IMenuManager *menumgr) : + IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, + core::rect(0, 0, 100, 100)), +#ifdef __ANDROID__ + m_jni_field_name(""), +#endif + m_menumgr(menumgr) +{ + setVisible(true); + Environment->setFocus(this); + m_menumgr->createdMenu(this); +} +// clang-format on + +GUIModalMenu::~GUIModalMenu() +{ + m_menumgr->deletingMenu(this); +} + +void GUIModalMenu::allowFocusRemoval(bool allow) +{ + m_allow_focus_removal = allow; +} + +bool GUIModalMenu::canTakeFocus(gui::IGUIElement *e) +{ + return (e && (e == this || isMyChild(e))) || m_allow_focus_removal; +} + +void GUIModalMenu::draw() +{ + if (!IsVisible) + return; + + video::IVideoDriver *driver = Environment->getVideoDriver(); + v2u32 screensize = driver->getScreenSize(); + if (screensize != m_screensize_old) { + m_screensize_old = screensize; + regenerateGui(screensize); + } + + drawMenu(); +} + +/* + This should be called when the menu wants to quit. + + WARNING: THIS DEALLOCATES THE MENU FROM MEMORY. Return + immediately if you call this from the menu itself. + + (More precisely, this decrements the reference count.) +*/ +void GUIModalMenu::quitMenu() +{ + allowFocusRemoval(true); + // This removes Environment's grab on us + Environment->removeFocus(this); + m_menumgr->deletingMenu(this); + this->remove(); +#ifdef HAVE_TOUCHSCREENGUI + if (g_touchscreengui && m_touchscreen_visible) + g_touchscreengui->show(); +#endif +} + +void GUIModalMenu::removeChildren() +{ + const core::list &children = getChildren(); + core::list children_copy; + for (gui::IGUIElement *i : children) { + children_copy.push_back(i); + } + + for (gui::IGUIElement *i : children_copy) { + i->remove(); + } +} + +bool GUIModalMenu::preprocessEvent(const SEvent &event) +{ +#ifdef __ANDROID__ + // clang-format off + // display software keyboard when clicking edit boxes + if (event.EventType == EET_MOUSE_INPUT_EVENT && + event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { + gui::IGUIElement *hovered = + Environment->getRootGUIElement()->getElementFromPoint( + core::position2d(event.MouseInput.X, event.MouseInput.Y)); + if ((hovered) && (hovered->getType() == irr::gui::EGUIET_EDIT_BOX)) { + bool retval = hovered->OnEvent(event); + if (retval) + Environment->setFocus(hovered); + + std::string field_name = getNameByID(hovered->getID()); + // read-only field + if (field_name.empty()) + return retval; + + m_jni_field_name = field_name; + std::string message = gettext("Enter "); + std::string label = wide_to_utf8(getLabelByID(hovered->getID())); + if (label.empty()) + label = "text"; + message += gettext(label) + ":"; + + // single line text input + int type = 2; + + // multi line text input + if (((gui::IGUIEditBox *)hovered)->isMultiLineEnabled()) + type = 1; + + // passwords are always single line + if (((gui::IGUIEditBox *)hovered)->isPasswordBox()) + type = 3; + + porting::showInputDialog(gettext("ok"), "", + wide_to_utf8(((gui::IGUIEditBox *)hovered)->getText()), type); + return retval; + } + } + + if (event.EventType == EET_TOUCH_INPUT_EVENT) { + SEvent translated; + memset(&translated, 0, sizeof(SEvent)); + translated.EventType = EET_MOUSE_INPUT_EVENT; + gui::IGUIElement *root = Environment->getRootGUIElement(); + + if (!root) { + errorstream << "GUIModalMenu::preprocessEvent" + << " unable to get root element" << std::endl; + return false; + } + gui::IGUIElement *hovered = root->getElementFromPoint( + core::position2d(event.TouchInput.X, event.TouchInput.Y)); + + translated.MouseInput.X = event.TouchInput.X; + translated.MouseInput.Y = event.TouchInput.Y; + translated.MouseInput.Control = false; + + bool dont_send_event = false; + + if (event.TouchInput.touchedCount == 1) { + switch (event.TouchInput.Event) { + case ETIE_PRESSED_DOWN: + m_pointer = v2s32(event.TouchInput.X, event.TouchInput.Y); + translated.MouseInput.Event = EMIE_LMOUSE_PRESSED_DOWN; + translated.MouseInput.ButtonStates = EMBSM_LEFT; + m_down_pos = m_pointer; + break; + case ETIE_MOVED: + m_pointer = v2s32(event.TouchInput.X, event.TouchInput.Y); + translated.MouseInput.Event = EMIE_MOUSE_MOVED; + translated.MouseInput.ButtonStates = EMBSM_LEFT; + break; + case ETIE_LEFT_UP: + translated.MouseInput.Event = EMIE_LMOUSE_LEFT_UP; + translated.MouseInput.ButtonStates = 0; + hovered = root->getElementFromPoint(m_down_pos); + // we don't have a valid pointer element use last + // known pointer pos + translated.MouseInput.X = m_pointer.X; + translated.MouseInput.Y = m_pointer.Y; + + // reset down pos + m_down_pos = v2s32(0, 0); + break; + default: + dont_send_event = true; + // this is not supposed to happen + errorstream << "GUIModalMenu::preprocessEvent" + << " unexpected usecase Event=" + << event.TouchInput.Event << std::endl; + } + } else if ((event.TouchInput.touchedCount == 2) && + (event.TouchInput.Event == ETIE_PRESSED_DOWN)) { + hovered = root->getElementFromPoint(m_down_pos); + + translated.MouseInput.Event = EMIE_RMOUSE_PRESSED_DOWN; + translated.MouseInput.ButtonStates = EMBSM_LEFT | EMBSM_RIGHT; + translated.MouseInput.X = m_pointer.X; + translated.MouseInput.Y = m_pointer.Y; + if (hovered) { + hovered->OnEvent(translated); + } + + translated.MouseInput.Event = EMIE_RMOUSE_LEFT_UP; + translated.MouseInput.ButtonStates = EMBSM_LEFT; + + if (hovered) { + hovered->OnEvent(translated); + } + dont_send_event = true; + } + // ignore unhandled 2 touch events ... accidental moving for example + else if (event.TouchInput.touchedCount == 2) { + dont_send_event = true; + } + else if (event.TouchInput.touchedCount > 2) { + errorstream << "GUIModalMenu::preprocessEvent" + << " to many multitouch events " + << event.TouchInput.touchedCount << " ignoring them" + << std::endl; + } + + if (dont_send_event) { + return true; + } + + // check if translated event needs to be preprocessed again + if (preprocessEvent(translated)) { + return true; + } + if (hovered) { + grab(); + bool retval = hovered->OnEvent(translated); + + if (event.TouchInput.Event == ETIE_LEFT_UP) { + // reset pointer + m_pointer = v2s32(0, 0); + } + drop(); + return retval; + } + } + // clang-format on +#endif + return false; +} + +#ifdef __ANDROID__ +bool GUIModalMenu::hasAndroidUIInput() +{ + // no dialog shown + if (m_jni_field_name.empty()) { + return false; + } + + // still waiting + if (porting::getInputDialogState() == -1) { + return true; + } + + // no value abort dialog processing + if (porting::getInputDialogState() != 0) { + m_jni_field_name.clear(); + return false; + } + + return true; +} +#endif diff --git a/src/gui/modalMenu.h b/src/gui/modalMenu.h index f41591c3f..8d32ad159 100644 --- a/src/gui/modalMenu.h +++ b/src/gui/modalMenu.h @@ -20,9 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once #include "irrlichttypes_extrabloated.h" -#ifdef HAVE_TOUCHSCREENGUI -#include "touchscreengui.h" -#endif +#include "util/string.h" class GUIModalMenu; @@ -34,101 +32,46 @@ public: virtual void deletingMenu(gui::IGUIElement *menu) = 0; }; -/* - Remember to drop() the menu after creating, so that it can - remove itself when it wants to. -*/ +// Remember to drop() the menu after creating, so that it can +// remove itself when it wants to. class GUIModalMenu : public gui::IGUIElement { public: GUIModalMenu(gui::IGUIEnvironment* env, gui::IGUIElement* parent, s32 id, - IMenuManager *menumgr): - IGUIElement(gui::EGUIET_ELEMENT, env, parent, id, - core::rect(0,0,100,100)) - { - m_menumgr = menumgr; + IMenuManager *menumgr); + virtual ~GUIModalMenu(); - setVisible(true); - Environment->setFocus(this); - m_menumgr->createdMenu(this); - } - - virtual ~GUIModalMenu() - { - m_menumgr->deletingMenu(this); - } - - void allowFocusRemoval(bool allow) - { - m_allow_focus_removal = allow; - } - - bool canTakeFocus(gui::IGUIElement *e) - { - return (e && (e == this || isMyChild(e))) || m_allow_focus_removal; - } - - void draw() - { - if(!IsVisible) - return; - - video::IVideoDriver* driver = Environment->getVideoDriver(); - v2u32 screensize = driver->getScreenSize(); - if(screensize != m_screensize_old /*|| m_force_regenerate_gui*/) - { - m_screensize_old = screensize; - regenerateGui(screensize); - //m_force_regenerate_gui = false; - } - - drawMenu(); - } - - /* - This should be called when the menu wants to quit. - - WARNING: THIS DEALLOCATES THE MENU FROM MEMORY. Return - immediately if you call this from the menu itself. - - (More precisely, this decrements the reference count.) - */ - void quitMenu() - { - allowFocusRemoval(true); - // This removes Environment's grab on us - Environment->removeFocus(this); - m_menumgr->deletingMenu(this); - this->remove(); -#ifdef HAVE_TOUCHSCREENGUI - if (g_touchscreengui) - g_touchscreengui->show(); -#endif - } - - void removeChildren() - { - const core::list &children = getChildren(); - core::list children_copy; - for (gui::IGUIElement *i : children) { - children_copy.push_back(i); - } - - for (gui::IGUIElement *i : children_copy) { - i->remove(); - } - } + void allowFocusRemoval(bool allow); + bool canTakeFocus(gui::IGUIElement *e); + void draw(); + void quitMenu(); + void removeChildren(); virtual void regenerateGui(v2u32 screensize) = 0; virtual void drawMenu() = 0; - virtual bool preprocessEvent(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 + virtual bool pausesGame() { return false; } // Used for pause menu +#ifdef __ANDROID__ + virtual bool getAndroidUIInput() { return false; } + bool hasAndroidUIInput(); +#endif protected: - //bool m_force_regenerate_gui; + virtual std::wstring getLabelByID(s32 id) = 0; + virtual std::string getNameByID(s32 id) = 0; + + v2s32 m_pointer; + v2s32 m_old_pointer; // Mouse position after previous mouse event v2u32 m_screensize_old; +#ifdef __ANDROID__ + v2s32 m_down_pos; + std::string m_jni_field_name; +#endif +#ifdef HAVE_TOUCHSCREENGUI + bool m_touchscreen_visible = true; +#endif private: IMenuManager *m_menumgr; // This might be necessary to expose to the implementation if it