Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support both mouse and touch input in GUIs in a single binary #14146

Merged
merged 7 commits into from
Dec 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
49 changes: 19 additions & 30 deletions src/gui/guiFormSpecMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand All @@ -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();
Expand Down Expand Up @@ -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;
grorp marked this conversation as resolved.
Show resolved Hide resolved
#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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -4147,7 +4142,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
return handled;
}

return GUIModalMenu::preprocessEvent(event);
return false;
}

void GUIFormSpecMenu::tryClose()
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand All @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
21 changes: 8 additions & 13 deletions src/gui/guiHyperText.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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) {
Expand Down
6 changes: 3 additions & 3 deletions src/gui/guiInventoryList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
76 changes: 45 additions & 31 deletions src/gui/modalMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
*/

#include <cstdlib>
#include <IEventReceiver.h>
#include "client/renderingengine.h"
#include "modalMenu.h"
#include "gettext.h"
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
{
Expand All @@ -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__
Expand Down Expand Up @@ -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<GUIModalMenu> 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<s32>(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;
Expand All @@ -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) {
grorp marked this conversation as resolved.
Show resolved Hide resolved
// 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<s32>(x, y));
Environment->getRootGUIElement()->getElementFromPoint(m_pointer);
if (!isChild(hovered, this)) {
if (DoubleClickDetection(event)) {
return true;
}
}
}

return false;
}

Expand Down