diff --git a/android/icons/gear_icon.svg b/android/icons/gear_icon.svg deleted file mode 100644 index b44685ade..000000000 --- a/android/icons/gear_icon.svg +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/icons/rare_controls.svg b/android/icons/overflow_btn.svg similarity index 90% rename from android/icons/rare_controls.svg rename to android/icons/overflow_btn.svg index c9991ec7a..455dcc35a 100644 --- a/android/icons/rare_controls.svg +++ b/android/icons/overflow_btn.svg @@ -2,23 +2,23 @@ + inkscape:export-ydpi="24.000002" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + showguides="false" + inkscape:showpageshadow="2" + inkscape:deskcolor="#d1d1d1"> + empopacity="0.25098039" + originx="0" + originy="0" + units="px" + visible="true" /> @@ -432,7 +438,6 @@ image/svg+xml - @@ -496,26 +501,27 @@ x="264.65997" y="124.10143" style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1" /> + id="flowPara4724" /> - + width="96.212502" + height="0.61243516" + x="19.62678" + y="33.575779" /> + + diff --git a/doc/texture_packs.md b/doc/texture_packs.md index b6f9306d9..890f5a950 100644 --- a/doc/texture_packs.md +++ b/doc/texture_packs.md @@ -151,8 +151,7 @@ are placeholders intended to be overwritten by the game. * `rangeview_btn.png` * `debug_btn.png` -* `gear_icon.png` -* `rare_controls.png` +* `overflow_btn.png` * `exit_btn.png` Texture Overrides diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp index b8c1143f2..7e6c486e0 100644 --- a/src/gui/guiKeyChangeMenu.cpp +++ b/src/gui/guiKeyChangeMenu.cpp @@ -377,6 +377,7 @@ void GUIKeyChangeMenu::add_key(int id, std::wstring button_name, const std::stri key_settings.push_back(k); } +// compare with button_titles in touchscreengui.cpp void GUIKeyChangeMenu::init_keys() { this->add_key(GUI_ID_KEY_FORWARD_BUTTON, wstrgettext("Forward"), "keymap_forward"); diff --git a/src/gui/touchscreengui.cpp b/src/gui/touchscreengui.cpp index 2504c4eb5..c428ef52e 100644 --- a/src/gui/touchscreengui.cpp +++ b/src/gui/touchscreengui.cpp @@ -31,6 +31,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "client/keycode.h" #include "client/renderingengine.h" #include "util/numeric.h" +#include "gettext.h" +#include "IGUIStaticText.h" +#include "IGUIFont.h" #include #include @@ -43,8 +46,7 @@ static const char *button_image_names[] = { "down.png", "zoom.png", "aux1_btn.png", - "gear_icon.png", - "rare_controls.png", + "overflow_btn.png", "fly_btn.png", "noclip_btn.png", @@ -65,6 +67,33 @@ static const char *button_image_names[] = { "joystick_center.png", }; +// compare with GUIKeyChangeMenu::init_keys +static const char *button_titles[] = { + N_("Jump"), + N_("Sneak"), + N_("Zoom"), + N_("Aux1"), + N_("Overflow menu"), + + N_("Toggle fly"), + N_("Toggle noclip"), + N_("Toggle fast"), + N_("Toggle debug"), + N_("Change camera"), + N_("Range select"), + N_("Toggle minimap"), + N_("Toggle chat log"), + + N_("Chat"), + N_("Inventory"), + N_("Drop"), + N_("Exit"), + + N_("Joystick"), + N_("Joystick"), + N_("Joystick"), +}; + static void load_button_texture(IGUIImage *gui_button, const std::string &path, const recti &button_rect, ISimpleTextureSource *tsrc, video::IVideoDriver *driver) { @@ -243,165 +272,6 @@ static EKEY_CODE id_to_keycode(touch_gui_button_id id) return code; } -AutoHideButtonBar::AutoHideButtonBar(IrrlichtDevice *device, ISimpleTextureSource *tsrc, - touch_gui_button_id starter_id, const std::string &starter_img, - recti starter_rect, autohide_button_bar_dir dir) : - m_driver(device->getVideoDriver()), - m_guienv(device->getGUIEnvironment()), - m_receiver(device->getEventReceiver()), - m_texturesource(tsrc) -{ - m_upper_left = starter_rect.UpperLeftCorner; - m_lower_right = starter_rect.LowerRightCorner; - - IGUIImage *starter_gui_button = m_guienv->addImage(starter_rect, nullptr, - starter_id); - load_button_texture(starter_gui_button, starter_img, starter_rect, - m_texturesource, m_driver); - - m_starter = grab_gui_element(starter_gui_button); - m_dir = dir; -} - -void AutoHideButtonBar::addButton(touch_gui_button_id id, const std::string &image) -{ - int button_size = 0; - - if (m_dir == AHBB_Dir_Top_Bottom || m_dir == AHBB_Dir_Bottom_Top) - button_size = m_lower_right.X - m_upper_left.X; - else - button_size = m_lower_right.Y - m_upper_left.Y; - - recti current_button; - - if (m_dir == AHBB_Dir_Right_Left || m_dir == AHBB_Dir_Left_Right) { - int x_start = 0; - int x_end = 0; - - if (m_dir == AHBB_Dir_Left_Right) { - x_start = m_lower_right.X + button_size * 1.25f * m_buttons.size() - + button_size * 0.25f; - x_end = x_start + button_size; - } else { - x_end = m_upper_left.X - button_size * 1.25f * m_buttons.size() - - button_size * 0.25f; - x_start = x_end - button_size; - } - - current_button = recti(x_start, m_upper_left.Y, x_end, m_lower_right.Y); - } else { - double y_start = 0; - double y_end = 0; - - if (m_dir == AHBB_Dir_Top_Bottom) { - y_start = m_lower_right.X + button_size * 1.25f * m_buttons.size() - + button_size * 0.25f; - y_end = y_start + button_size; - } else { - y_end = m_upper_left.X - button_size * 1.25f * m_buttons.size() - - button_size * 0.25f; - y_start = y_end - button_size; - } - - current_button = recti(m_upper_left.X, y_start, m_lower_right.Y, y_end); - } - - IGUIImage *btn_gui_button = m_guienv->addImage(current_button, nullptr, id); - btn_gui_button->setVisible(false); - btn_gui_button->setEnabled(false); - load_button_texture(btn_gui_button, image, current_button, m_texturesource, m_driver); - - button_info btn{}; - btn.keycode = id_to_keycode(id); - btn.gui_button = grab_gui_element(btn_gui_button); - m_buttons.push_back(btn); -} - -void AutoHideButtonBar::addToggleButton(touch_gui_button_id id, - const std::string &image_1, const std::string &image_2) -{ - addButton(id, image_1); - button_info &btn = m_buttons.back(); - btn.toggleable = button_info::FIRST_TEXTURE; - btn.toggle_textures[0] = image_1; - btn.toggle_textures[1] = image_2; -} - -bool AutoHideButtonBar::handlePress(size_t pointer_id, IGUIElement *element) -{ - if (m_active) { - return buttons_handlePress(m_buttons, pointer_id, element, m_driver, - m_receiver, m_texturesource); - } - if (m_starter.get() == element) { - activate(); - return true; - } - return false; -} - -bool AutoHideButtonBar::handleRelease(size_t pointer_id) -{ - return buttons_handleRelease(m_buttons, pointer_id, m_driver, - m_receiver, m_texturesource); -} - -void AutoHideButtonBar::step(float dtime) -{ - // Since buttons can stay pressed after the buttonbar is deactivated, - // we call the step function even if the buttonbar is inactive. - bool has_pointers = buttons_step(m_buttons, dtime, m_driver, m_receiver, - m_texturesource); - - if (m_active) { - if (!has_pointers) { - m_timeout += dtime; - if (m_timeout > BUTTONBAR_HIDE_DELAY) - deactivate(); - } else { - m_timeout = 0.0f; - } - } - -} - -void AutoHideButtonBar::updateVisibility() { - bool starter_visible = m_visible && !m_active; - bool inner_visible = m_visible && m_active; - - m_starter->setVisible(starter_visible); - m_starter->setEnabled(starter_visible); - - for (auto &button : m_buttons) { - button.gui_button->setVisible(inner_visible); - button.gui_button->setEnabled(inner_visible); - } -} - -void AutoHideButtonBar::activate() -{ - m_active = true; - m_timeout = 0.0f; - updateVisibility(); -} - -void AutoHideButtonBar::deactivate() -{ - m_active = false; - updateVisibility(); -} - -void AutoHideButtonBar::show() -{ - m_visible = true; - updateVisibility(); -} - -void AutoHideButtonBar::hide() -{ - m_visible = false; - updateVisibility(); -} TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, ISimpleTextureSource *tsrc): m_device(device), @@ -421,44 +291,44 @@ TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, ISimpleTextureSource *tsr // Initialize joystick display "button". // Joystick is placed on the bottom left of screen. if (m_fixed_joystick) { - m_joystick_btn_off = grab_gui_element(makeJoystickButton(joystick_off_id, + m_joystick_btn_off = grab_gui_element(makeButtonDirect(joystick_off_id, recti(m_button_size, m_screensize.Y - m_button_size * 4, m_button_size * 4, m_screensize.Y - m_button_size), true)); } else { - m_joystick_btn_off = grab_gui_element(makeJoystickButton(joystick_off_id, + m_joystick_btn_off = grab_gui_element(makeButtonDirect(joystick_off_id, recti(m_button_size, m_screensize.Y - m_button_size * 3, m_button_size * 3, m_screensize.Y - m_button_size), true)); } - m_joystick_btn_bg = grab_gui_element(makeJoystickButton(joystick_bg_id, + m_joystick_btn_bg = grab_gui_element(makeButtonDirect(joystick_bg_id, recti(m_button_size, m_screensize.Y - m_button_size * 4, m_button_size * 4, m_screensize.Y - m_button_size), false)); - m_joystick_btn_center = grab_gui_element(makeJoystickButton(joystick_center_id, + m_joystick_btn_center = grab_gui_element(makeButtonDirect(joystick_center_id, recti(0, 0, m_button_size, m_button_size), false)); // init jump button - addButton(jump_id, button_image_names[jump_id], + addButton(m_buttons, jump_id, button_image_names[jump_id], recti(m_screensize.X - 1.75f * m_button_size, m_screensize.Y - m_button_size, m_screensize.X - 0.25f * m_button_size, m_screensize.Y)); // init sneak button - addButton(sneak_id, button_image_names[sneak_id], + addButton(m_buttons, sneak_id, button_image_names[sneak_id], recti(m_screensize.X - 3.25f * m_button_size, m_screensize.Y - m_button_size, m_screensize.X - 1.75f * m_button_size, m_screensize.Y)); // init zoom button - addButton(zoom_id, button_image_names[zoom_id], + addButton(m_buttons, zoom_id, button_image_names[zoom_id], recti(m_screensize.X - 1.25f * m_button_size, m_screensize.Y - 4 * m_button_size, m_screensize.X - 0.25f * m_button_size, @@ -466,72 +336,112 @@ TouchScreenGUI::TouchScreenGUI(IrrlichtDevice *device, ISimpleTextureSource *tsr // init aux1 button if (!m_joystick_triggers_aux1) - addButton(aux1_id, button_image_names[aux1_id], + addButton(m_buttons, aux1_id, button_image_names[aux1_id], recti(m_screensize.X - 1.25f * m_button_size, m_screensize.Y - 2.5f * m_button_size, m_screensize.X - 0.25f * m_button_size, m_screensize.Y - 1.5f * m_button_size)); - AutoHideButtonBar &settings_bar = m_buttonbars.emplace_back(m_device, m_texturesource, - settings_starter_id, button_image_names[settings_starter_id], - recti(m_screensize.X - 1.25f * m_button_size, - m_screensize.Y - (SETTINGS_BAR_Y_OFFSET + 1.0f) * m_button_size - + 0.5f * m_button_size, - m_screensize.X - 0.25f * m_button_size, - m_screensize.Y - SETTINGS_BAR_Y_OFFSET * m_button_size - + 0.5f * m_button_size), - AHBB_Dir_Right_Left); + // init overflow button + m_overflow_btn = grab_gui_element(makeButtonDirect(overflow_id, + recti(m_screensize.X - 1.25f * m_button_size, + m_screensize.Y - 5.5f * m_button_size, + m_screensize.X - 0.25f * m_button_size, + m_screensize.Y - 4.5f * m_button_size), true)); - const static touch_gui_button_id settings_bar_buttons[] { + const static touch_gui_button_id overflow_buttons[] { + chat_id, inventory_id, drop_id, exit_id, fly_id, noclip_id, fast_id, debug_id, camera_id, range_id, minimap_id, + toggle_chat_id, }; - for (auto id : settings_bar_buttons) { - if (id_to_keycode(id) == KEY_UNKNOWN) - continue; - settings_bar.addButton(id, button_image_names[id]); + + IGUIStaticText *background = m_guienv->addStaticText(L"", + recti(v2s32(0, 0), dimension2du(m_screensize))); + background->setBackgroundColor(video::SColor(140, 0, 0, 0)); + background->setVisible(false); + m_overflow_bg = grab_gui_element(background); + + s32 cols = 4; + s32 rows = 3; + f32 screen_aspect = (f32)m_screensize.X / (f32)m_screensize.Y; + while ((s32)ARRLEN(overflow_buttons) > cols * rows) { + f32 aspect = (f32)cols / (f32)rows; + if (aspect > screen_aspect) + rows++; + else + cols++; } - // Chat is shown by default, so chat_hide_btn.png is shown first. - settings_bar.addToggleButton(toggle_chat_id, - "chat_hide_btn.png", "chat_show_btn.png"); + v2s32 size(m_button_size, m_button_size); + v2s32 spacing(m_screensize.X / (cols + 1), m_screensize.Y / (rows + 1)); + v2s32 pos(spacing); - AutoHideButtonBar &rare_controls_bar = m_buttonbars.emplace_back(m_device, m_texturesource, - rare_controls_starter_id, button_image_names[rare_controls_starter_id], - recti(0.25f * m_button_size, - m_screensize.Y - (RARE_CONTROLS_BAR_Y_OFFSET + 1.0f) * m_button_size - + 0.5f * m_button_size, - 0.75f * m_button_size, - m_screensize.Y - RARE_CONTROLS_BAR_Y_OFFSET * m_button_size - + 0.5f * m_button_size), - AHBB_Dir_Left_Right); - - const static touch_gui_button_id rare_controls_bar_buttons[] { - chat_id, inventory_id, drop_id, exit_id, - }; - for (auto id : rare_controls_bar_buttons) { + for (auto id : overflow_buttons) { if (id_to_keycode(id) == KEY_UNKNOWN) continue; - rare_controls_bar.addButton(id, button_image_names[id]); + + recti rect(pos - size / 2, dimension2du(size.X, size.Y)); + if (rect.LowerRightCorner.X > (s32)m_screensize.X) { + pos.X = spacing.X; + pos.Y += spacing.Y; + rect = recti(pos - size / 2, dimension2du(size.X, size.Y)); + } + + if (id == toggle_chat_id) + // Chat is shown by default, so chat_hide_btn.png is shown first. + addToggleButton(m_overflow_buttons, id, "chat_hide_btn.png", + "chat_show_btn.png", rect, false); + else + addButton(m_overflow_buttons, id, button_image_names[id], rect, false); + + std::wstring str = wstrgettext(button_titles[id]); + IGUIStaticText *text = m_guienv->addStaticText(str.c_str(), recti()); + IGUIFont *font = text->getActiveFont(); + dimension2du dim = font->getDimension(str.c_str()); + dim = dimension2du(dim.Width * 1.25f, dim.Height * 1.25f); // avoid clipping + text->setRelativePosition(recti(pos.X - dim.Width / 2, pos.Y + size.Y / 2, + pos.X + dim.Width / 2, pos.Y + size.Y / 2 + dim.Height)); + text->setTextAlignment(EGUIA_CENTER, EGUIA_UPPERLEFT); + text->setVisible(false); + m_overflow_button_titles.push_back(grab_gui_element(text)); + + rect.addInternalPoint(text->getRelativePosition().UpperLeftCorner); + rect.addInternalPoint(text->getRelativePosition().LowerRightCorner); + m_overflow_button_rects.push_back(rect); + + pos.X += spacing.X; } } -void TouchScreenGUI::addButton(touch_gui_button_id id, const std::string &image, const recti &rect) +void TouchScreenGUI::addButton(std::vector &buttons, touch_gui_button_id id, + const std::string &image, const recti &rect, bool visible) { IGUIImage *btn_gui_button = m_guienv->addImage(rect, nullptr, id); + btn_gui_button->setVisible(visible); load_button_texture(btn_gui_button, image, rect, m_texturesource, m_device->getVideoDriver()); - button_info &btn = m_buttons.emplace_back(); + button_info &btn = buttons.emplace_back(); btn.keycode = id_to_keycode(id); btn.gui_button = grab_gui_element(btn_gui_button); } -IGUIImage *TouchScreenGUI::makeJoystickButton(touch_gui_button_id id, - const recti &button_rect, bool visible) +void TouchScreenGUI::addToggleButton(std::vector &buttons, touch_gui_button_id id, + const std::string &image_1, const std::string &image_2, const recti &rect, bool visible) { - IGUIImage *btn_gui_button = m_guienv->addImage(button_rect, nullptr, id); + addButton(buttons, id, image_1, rect, visible); + button_info &btn = buttons.back(); + btn.toggleable = button_info::FIRST_TEXTURE; + btn.toggle_textures[0] = image_1; + btn.toggle_textures[1] = image_2; +} + +IGUIImage *TouchScreenGUI::makeButtonDirect(touch_gui_button_id id, + const recti &rect, bool visible) +{ + IGUIImage *btn_gui_button = m_guienv->addImage(rect, nullptr, id); btn_gui_button->setVisible(visible); - load_button_texture(btn_gui_button, button_image_names[id], button_rect, + load_button_texture(btn_gui_button, button_image_names[id], rect, m_texturesource, m_device->getVideoDriver()); return btn_gui_button; @@ -566,17 +476,17 @@ void TouchScreenGUI::handleReleaseEvent(size_t pointer_id) m_pointer_downpos.erase(pointer_id); m_pointer_pos.erase(pointer_id); + if (m_overflow_open) { + buttons_handleRelease(m_overflow_buttons, pointer_id, m_device->getVideoDriver(), + m_receiver, m_texturesource); + return; + } + // handle buttons if (buttons_handleRelease(m_buttons, pointer_id, m_device->getVideoDriver(), m_receiver, m_texturesource)) return; - // handle buttonbars - for (AutoHideButtonBar &bar : m_buttonbars) { - if (bar.handleRelease(pointer_id)) - return; - } - if (m_has_move_id && pointer_id == m_move_id) { // handle the point used for moving view m_has_move_id = false; @@ -584,7 +494,8 @@ void TouchScreenGUI::handleReleaseEvent(size_t pointer_id) // If m_tap_state is already set to TapState::ShortTap, we must keep // that value. Otherwise, many short taps will be ignored if you tap // very fast. - if (!m_move_has_really_moved && m_tap_state != TapState::LongTap) { + if (!m_move_has_really_moved && !m_move_prevent_short_tap && + m_tap_state != TapState::LongTap) { m_tap_state = TapState::ShortTap; } else { m_tap_state = TapState::None; @@ -635,41 +546,48 @@ void TouchScreenGUI::translateEvent(const SEvent &event) m_pointer_downpos[pointer_id] = touch_pos; m_pointer_pos[pointer_id] = touch_pos; + bool prevent_short_tap = false; + IGUIElement *element = m_guienv->getRootGUIElement()->getElementFromPoint(touch_pos); + // handle overflow menu + if (!m_overflow_open) { + if (element == m_overflow_btn.get()) { + toggleOverflowMenu(); + return; + } + } else { + for (size_t i = 0; i < m_overflow_buttons.size(); i++) { + if (m_overflow_button_rects[i].isPointInside(touch_pos)) { + element = m_overflow_buttons[i].gui_button.get(); + break; + } + } + + if (buttons_handlePress(m_overflow_buttons, pointer_id, element, + m_device->getVideoDriver(), m_receiver, m_texturesource)) + return; + + toggleOverflowMenu(); + // refresh since visibility of buttons has changed + element = m_guienv->getRootGUIElement()->getElementFromPoint(touch_pos); + // restore after releaseAll in toggleOverflowMenu + m_pointer_downpos[pointer_id] = touch_pos; + m_pointer_pos[pointer_id] = touch_pos; + // continue processing, but avoid accidentally placing a node + // when closing the overflow menu + prevent_short_tap = true; + } + // handle buttons if (buttons_handlePress(m_buttons, pointer_id, element, - m_device->getVideoDriver(), m_receiver, m_texturesource)) { - for (AutoHideButtonBar &bar : m_buttonbars) - bar.deactivate(); + m_device->getVideoDriver(), m_receiver, m_texturesource)) return; - } - - // handle buttonbars - for (AutoHideButtonBar &bar : m_buttonbars) { - if (bar.handlePress(pointer_id, element)) { - for (AutoHideButtonBar &other : m_buttonbars) - if (other != bar) - other.deactivate(); - return; - } - } // handle hotbar - if (isHotbarButton(event)) { + if (isHotbarButton(event)) // already handled in isHotbarButton() - for (AutoHideButtonBar &bar : m_buttonbars) - bar.deactivate(); return; - } - - // handle non button events - for (AutoHideButtonBar &bar : m_buttonbars) { - if (bar.isActive()) { - bar.deactivate(); - return; - } - } // Select joystick when joystick tapped (fixed joystick position) or // when left 1/3 of screen dragged (free joystick position) @@ -704,6 +622,7 @@ void TouchScreenGUI::translateEvent(const SEvent &event) // DON'T reset m_tap_state here, otherwise many short taps // will be ignored if you tap very fast. m_had_move_id = true; + m_move_prevent_short_tap = prevent_short_tap; } } } @@ -713,6 +632,9 @@ void TouchScreenGUI::translateEvent(const SEvent &event) } else { assert(event.TouchInput.Event == ETIE_MOVED); + if (m_overflow_open) + return; + if (!(m_has_joystick_id && m_fixed_joystick) && m_pointer_pos[event.TouchInput.ID] == touch_pos) return; @@ -798,10 +720,13 @@ void TouchScreenGUI::applyJoystickStatus() void TouchScreenGUI::step(float dtime) { + if (m_overflow_open) { + buttons_step(m_overflow_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); + return; + } + // simulate keyboard repeats buttons_step(m_buttons, dtime, m_device->getVideoDriver(), m_receiver, m_texturesource); - for (AutoHideButtonBar &bar : m_buttonbars) - bar.step(dtime); // joystick applyJoystickStatus(); @@ -844,42 +769,65 @@ void TouchScreenGUI::registerHotbarRect(u16 index, const recti &rect) void TouchScreenGUI::setVisible(bool visible) { + if (m_visible == visible) + return; + m_visible = visible; - for (auto &button : m_buttons) { - if (button.gui_button) - button.gui_button->setVisible(visible); - } - - if (m_joystick_btn_off) - m_joystick_btn_off->setVisible(visible); - - // clear all active buttons + // order matters if (!visible) { - while (!m_pointer_pos.empty()) - handleReleaseEvent(m_pointer_pos.begin()->first); - for (AutoHideButtonBar &bar : m_buttonbars) { - bar.deactivate(); - bar.hide(); - } - } else { - for (AutoHideButtonBar &bar : m_buttonbars) - bar.show(); + releaseAll(); + m_overflow_open = false; + } + updateVisibility(); +} + +void TouchScreenGUI::toggleOverflowMenu() +{ + releaseAll(); // must be done first + m_overflow_open = !m_overflow_open; + updateVisibility(); +} + +void TouchScreenGUI::updateVisibility() +{ + bool regular_visible = m_visible && !m_overflow_open; + for (auto &button : m_buttons) + button.gui_button->setVisible(regular_visible); + m_overflow_btn->setVisible(regular_visible); + m_joystick_btn_off->setVisible(regular_visible); + + bool overflow_visible = m_visible && m_overflow_open; + m_overflow_bg->setVisible(overflow_visible); + for (auto &button : m_overflow_buttons) + button.gui_button->setVisible(overflow_visible); + for (auto &text : m_overflow_button_titles) + text->setVisible(overflow_visible); +} + +void TouchScreenGUI::releaseAll() +{ + while (!m_pointer_pos.empty()) + handleReleaseEvent(m_pointer_pos.begin()->first); + + // Release those manually too since the change initiated by + // handleReleaseEvent will only be applied later by applyContextControls. + if (m_dig_pressed) { + emitMouseEvent(EMIE_LMOUSE_LEFT_UP); + m_dig_pressed = false; + } + if (m_place_pressed) { + emitMouseEvent(EMIE_RMOUSE_LEFT_UP); + m_place_pressed = false; } } void TouchScreenGUI::hide() { - if (!m_visible) - return; - setVisible(false); } void TouchScreenGUI::show() { - if (m_visible) - return; - setVisible(true); } diff --git a/src/gui/touchscreengui.h b/src/gui/touchscreengui.h index ca6c05e18..2da9d8151 100644 --- a/src/gui/touchscreengui.h +++ b/src/gui/touchscreengui.h @@ -20,6 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #pragma once +#include "IGUIStaticText.h" #include "irrlichttypes.h" #include #include @@ -74,8 +75,7 @@ enum touch_gui_button_id sneak_id, zoom_id, aux1_id, - settings_starter_id, - rare_controls_starter_id, + overflow_id, // usually in the "settings bar" fly_id, @@ -99,25 +99,16 @@ enum touch_gui_button_id joystick_center_id, }; -enum autohide_button_bar_dir -{ - AHBB_Dir_Top_Bottom, - AHBB_Dir_Bottom_Top, - AHBB_Dir_Left_Right, - AHBB_Dir_Right_Left -}; #define BUTTON_REPEAT_DELAY 0.5f #define BUTTON_REPEAT_INTERVAL 0.333f -#define BUTTONBAR_HIDE_DELAY 3.0f -#define SETTINGS_BAR_Y_OFFSET 5 -#define RARE_CONTROLS_BAR_Y_OFFSET 5 // Our simulated clicks last some milliseconds so that server-side mods have a // chance to detect them via l_get_player_control. // If you tap faster than this value, the simulated clicks are of course shorter. #define SIMULATED_CLICK_DURATION_MS 50 + struct button_info { float repeat_counter; @@ -136,52 +127,6 @@ struct button_info IEventReceiver *receiver, ISimpleTextureSource *tsrc); }; -class AutoHideButtonBar -{ -public: - AutoHideButtonBar(IrrlichtDevice *device, ISimpleTextureSource *tsrc, - touch_gui_button_id starter_id, const std::string &starter_image, - recti starter_rect, autohide_button_bar_dir dir); - - void addButton(touch_gui_button_id id, const std::string &image); - void addToggleButton(touch_gui_button_id id, - const std::string &image_1, const std::string &image_2); - - bool handlePress(size_t pointer_id, IGUIElement *element); - bool handleRelease(size_t pointer_id); - - void step(float dtime); - - void activate(); - void deactivate(); - bool isActive() { return m_active; } - - void show(); - void hide(); - - bool operator==(const AutoHideButtonBar &other) - { return m_starter.get() == other.m_starter.get(); } - bool operator!=(const AutoHideButtonBar &other) - { return m_starter.get() != other.m_starter.get(); } - -private: - irr::video::IVideoDriver *m_driver = nullptr; - IGUIEnvironment *m_guienv = nullptr; - IEventReceiver *m_receiver = nullptr; - ISimpleTextureSource *m_texturesource = nullptr; - std::shared_ptr m_starter; - std::vector m_buttons; - - v2s32 m_upper_left; - v2s32 m_lower_right; - - bool m_active = false; - bool m_visible = true; - float m_timeout = 0.0f; - autohide_button_bar_dir m_dir = AHBB_Dir_Right_Left; - - void updateVisibility(); -}; class TouchScreenGUI { @@ -262,6 +207,7 @@ private: // This is needed so that we don't miss if m_has_move_id is true for less // than one client step, i.e. press and release happen in the same step. bool m_had_move_id = false; + bool m_move_prevent_short_tap = false; bool m_has_joystick_id = false; size_t m_joystick_id; @@ -277,13 +223,28 @@ private: std::shared_ptr m_joystick_btn_center; std::vector m_buttons; + std::shared_ptr m_overflow_btn; + + bool m_overflow_open = false; + std::shared_ptr m_overflow_bg; + std::vector m_overflow_buttons; + std::vector> m_overflow_button_titles; + std::vector m_overflow_button_rects; + + void toggleOverflowMenu(); + void updateVisibility(); + void releaseAll(); // initialize a button - void addButton(touch_gui_button_id id, const std::string &image, - const recti &rect); + void addButton(std::vector &buttons, + touch_gui_button_id id, const std::string &image, + const recti &rect, bool visible=true); + void addToggleButton(std::vector &buttons, + touch_gui_button_id id, + const std::string &image_1, const std::string &image_2, + const recti &rect, bool visible=true); - // initialize a joystick button - IGUIImage *makeJoystickButton(touch_gui_button_id id, + IGUIImage *makeButtonDirect(touch_gui_button_id id, const recti &rect, bool visible); // handle pressing hotbar items @@ -300,8 +261,6 @@ private: // map to store the IDs and positions of currently pressed pointers std::unordered_map m_pointer_pos; - std::vector m_buttonbars; - v2s32 getPointerPos(); void emitMouseEvent(EMOUSE_INPUT_EVENT type); TouchInteractionMode m_last_mode = TouchInteractionMode_END; diff --git a/textures/base/pack/gear_icon.png b/textures/base/pack/gear_icon.png deleted file mode 100644 index 6ca451046..000000000 Binary files a/textures/base/pack/gear_icon.png and /dev/null differ diff --git a/textures/base/pack/overflow_btn.png b/textures/base/pack/overflow_btn.png new file mode 100644 index 000000000..9afaed2c7 Binary files /dev/null and b/textures/base/pack/overflow_btn.png differ diff --git a/textures/base/pack/rare_controls.png b/textures/base/pack/rare_controls.png deleted file mode 100644 index 16bf61a8f..000000000 Binary files a/textures/base/pack/rare_controls.png and /dev/null differ