TouchScreenGUI: Replace buttonbars with grid menu (#14918)

This commit is contained in:
grorp 2024-08-12 14:34:50 +01:00 committed by GitHub
parent a3838dd0e8
commit 013c6ee166
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 285 additions and 566 deletions

@ -1,194 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="512"
height="512"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="gear_icon.svg"
inkscape:export-filename="/home/stu/Desktop/icons/png/gear_icon.png"
inkscape:export-xdpi="24"
inkscape:export-ydpi="24">
<defs
id="defs2">
<marker
style="overflow:visible"
refY="0.0"
refX="0.0"
orient="auto"
id="DistanceX">
<path
id="path4687"
style="stroke:#000000; stroke-width:0.5"
d="M 3,-3 L -3,3 M 0,-5 L 0,5" />
</marker>
<pattern
y="0"
x="0"
width="8"
patternUnits="userSpaceOnUse"
id="Hatch"
height="8">
<path
id="path4690"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M8 4 l-4,4" />
<path
id="path4692"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M6 2 l-4,4" />
<path
id="path4694"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M4 0 l-4,4" />
</pattern>
<marker
style="overflow:visible"
refY="0.0"
refX="0.0"
orient="auto"
id="DistanceX-3">
<path
id="path4756"
style="stroke:#000000; stroke-width:0.5"
d="M 3,-3 L -3,3 M 0,-5 L 0,5" />
</marker>
<pattern
y="0"
x="0"
width="8"
patternUnits="userSpaceOnUse"
id="Hatch-6"
height="8">
<path
id="path4759"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M8 4 l-4,4" />
<path
id="path4761"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M6 2 l-4,4" />
<path
id="path4763"
stroke-width="0.25"
stroke="#000000"
linecap="square"
d="M4 0 l-4,4" />
</pattern>
</defs>
<sodipodi:namedview
id="base"
pagecolor="#404040"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.5"
inkscape:cx="-308.644"
inkscape:cy="171.10144"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1023"
inkscape:window-x="0"
inkscape:window-y="34"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="false"
inkscape:snap-page="true"
inkscape:snap-grids="true"
inkscape:snap-bbox="true"
inkscape:snap-bbox-midpoints="false"
inkscape:snap-object-midpoints="true"
inkscape:snap-to-guides="false"
inkscape:showpageshadow="false"
inkscape:snap-smooth-nodes="true"
inkscape:object-nodes="false">
<inkscape:grid
type="xygrid"
id="grid16"
spacingx="2.1166666"
spacingy="2.1166666"
empspacing="2"
color="#40ff40"
opacity="0.1254902"
empcolor="#40ff40"
empopacity="0.25098039" />
</sodipodi:namedview>
<metadata
id="metadata5">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-161.53332)">
<g
id="g4792"
transform="matrix(0.68725287,0,0,0.65623884,67.477909,-509.24679)"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74041259;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<g
id="g4772"
inkscape:label="OpenJsCad"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74041259;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1">
<path
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 256,80.943359 -8.28125,0.72461 -3.63477,5.410156 -5.61328,12.685547 -2.28906,9.259768 -0.35156,5.1875 0.0937,0.86133 0.70703,2.44726 0.60547,9.80664 -2.66602,5.47461 -21.5957,5.78711 -5.04492,-3.40625 -4.37696,-8.79687 -0.61132,-2.47071 -0.35157,-0.79297 -2.89648,-4.31836 -6.60938,-6.87304 -11.20507,-8.17969 -5.84961,-2.86719 -7.53516,3.51367 -6.80859,4.76954 -0.44336,6.50195 1.48047,13.79297 2.64453,9.16406 2.28906,4.66992 0.51172,0.69922 1.83398,1.76563 5.42774,8.18945 0.42773,6.07422 -15.81054,15.81445 -6.07032,-0.42773 -8.18945,-5.42969 -1.76367,-1.83399 -0.69922,-0.51171 -4.66992,-2.28907 -9.15821,-2.64843 -13.79297,-1.47852 -6.5,0.44141 -4.76757,6.8125 -3.51367,7.53515 2.86914,5.85157 8.17382,11.20703 6.87305,6.61132 4.31641,2.90039 0.79297,0.34961 2.4707,0.61133 8.79492,4.37696 3.4043,5.04687 -5.78516,21.60156 -5.47265,2.66602 -9.80469,-0.60547 -2.44727,-0.70703 -0.85937,-0.0918 -5.1875,0.35156 -9.257816,2.28907 -12.68164,5.61523 -5.408203,3.63281 -0.72461,8.28516 0.72461,8.28516 5.408203,3.63281 12.68164,5.61523 9.257816,2.28907 5.1875,0.35156 0.85937,-0.0918 2.44727,-0.70703 9.80469,-0.60547 5.47265,2.66602 5.78516,21.60156 -3.4043,5.04687 -8.79492,4.37696 -2.4707,0.61133 -0.79297,0.34961 -4.31641,2.90039 -6.87305,6.61132 -8.17382,11.20703 -2.86914,5.85157 3.51367,7.53515 4.76757,6.8125 6.5,0.44141 13.79297,-1.47852 9.15821,-2.64843 4.66992,-2.28907 0.69922,-0.50976 1.76367,-1.83594 8.18945,-5.42969 6.07032,-0.42773 15.81054,15.81445 -0.42773,6.07422 -5.42774,8.18945 -1.83398,1.76563 -0.51172,0.69922 -2.28906,4.66992 -2.64453,9.16406 -1.48047,13.79297 0.44336,6.50195 6.80859,4.76758 7.53516,3.51758 5.84961,-2.86914 11.20507,-8.17969 6.60938,-6.87304 2.89648,-4.31836 0.35157,-0.79297 0.61132,-2.47071 4.37696,-8.79687 5.04492,-3.40625 21.5957,5.78711 2.66602,5.47461 -0.60547,9.80664 -0.70703,2.44726 -0.0937,0.85938 0.35156,5.18945 2.28906,9.25977 5.61328,12.68555 3.63477,5.41015 8.28125,0.72461 8.28125,-0.72461 3.63477,-5.41015 5.61328,-12.68555 2.28906,-9.25977 0.35156,-5.18945 -0.0937,-0.85938 -0.70703,-2.44726 -0.60547,-9.80664 2.66602,-5.47461 21.5957,-5.78711 5.04492,3.40625 4.37696,8.79687 0.61132,2.47071 0.35157,0.79297 2.89648,4.31836 6.60938,6.87304 11.20507,8.17969 5.84961,2.86914 7.53516,-3.51758 6.80859,-4.76758 0.44336,-6.50195 -1.48047,-13.79297 -2.64453,-9.16406 -2.28906,-4.66992 -0.51172,-0.69922 -1.83398,-1.76563 -5.42774,-8.18945 -0.42773,-6.07422 15.81054,-15.81445 6.07032,0.42773 8.18945,5.42969 1.76367,1.83594 0.69922,0.50976 4.66992,2.28907 9.15821,2.64843 13.79297,1.47852 6.5,-0.44141 v -0.002 l 4.76757,-6.81055 3.51367,-7.53711 -2.86914,-5.85156 -8.17382,-11.20508 -6.87305,-6.61328 -4.31641,-2.89843 -0.79297,-0.34961 -2.4707,-0.61133 -8.79492,-4.37891 -3.4043,-5.04492 5.78516,-21.60352 5.47265,-2.66797 9.80469,0.60938 2.44727,0.70703 0.85937,0.0918 5.1875,-0.35156 9.25782,-2.28907 12.68164,-5.61718 5.4082,-3.63282 0.72461,-8.28515 -0.72461,-8.28321 -5.4082,-3.63476 -12.68164,-5.61524 -9.25782,-2.28711 -5.1875,-0.35351 -0.85937,0.0937 -2.44727,0.70508 -9.80469,0.60937 -5.47265,-2.66797 -5.78516,-21.59961 3.4043,-5.04882 8.79492,-4.37696 2.4707,-0.61133 0.79297,-0.35156 4.31641,-2.89844 6.87305,-6.61132 8.17382,-11.20703 2.86914,-5.85157 -3.51367,-7.53711 -4.76757,-6.81054 -6.5,-0.44336 -13.79297,1.48047 -9.15821,2.64648 -4.66992,2.28906 -0.69922,0.51172 -1.76367,1.83594 -8.18945,5.42773 -6.07032,0.42774 -15.81054,-15.81446 0.42773,-6.07226 5.42774,-8.18945 1.83398,-1.76563 0.51172,-0.69922 2.28906,-4.67187 2.64453,-9.16016 1.48047,-13.79492 -0.44336,-6.50195 -6.80859,-4.76954 -7.53516,-3.51562 -5.84961,2.87109 -11.20507,8.17578 -6.60938,6.875 -2.89648,4.31836 -0.35157,0.79102 -0.61132,2.47266 -4.37696,8.79687 -5.04492,3.4082 -21.5957,-5.79101 -2.66602,-5.47266 0.60547,-9.80664 0.70703,-2.44726 0.0937,-0.85938 -0.35156,-5.19141 -2.28906,-9.259761 -5.61328,-12.683594 -3.63477,-5.412109 z m 0,97.111331 A 77.946197,77.946197 0 0 1 333.94531,256 77.946197,77.946197 0 0 1 256,333.94531 77.946197,77.946197 0 0 1 178.05469,256 77.946197,77.946197 0 0 1 256,178.05469 Z"
transform="matrix(0.38495268,0,0,0.40318156,-98.176247,1022.1341)"
id="path4768"
inkscape:connector-curvature="0" />
</g>
<g
id="g4774"
inkscape:label="0"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-width:0.74041259;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 9.7 KiB

@ -2,23 +2,23 @@
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="256"
width="512"
height="512"
viewBox="0 0 67.73333 135.46667"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg8"
inkscape:version="0.92.1 r15371"
sodipodi:docname="rare_controls.svg"
inkscape:export-filename="/home/stu/Desktop/icons/png/rare_controls.png"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
sodipodi:docname="overflow_btn.svg"
inkscape:export-filename="../../textures/base/pack/overflow_btn.png"
inkscape:export-xdpi="24.000002"
inkscape:export-ydpi="24.000002">
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/">
<defs
id="defs2">
<filter
@ -397,22 +397,24 @@
borderopacity="1.0"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="-59.862018"
inkscape:cy="260.34663"
inkscape:zoom="0.98994949"
inkscape:cx="41.921331"
inkscape:cy="163.13964"
inkscape:document-units="mm"
inkscape:current-layer="layer2"
showgrid="true"
units="px"
inkscape:window-width="1920"
inkscape:window-height="1023"
inkscape:window-height="1011"
inkscape:window-x="0"
inkscape:window-y="34"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:pagecheckerboard="false"
inkscape:snap-grids="true"
inkscape:snap-page="true"
showguides="false">
showguides="false"
inkscape:showpageshadow="2"
inkscape:deskcolor="#d1d1d1">
<inkscape:grid
type="xygrid"
id="grid16"
@ -422,7 +424,11 @@
color="#40ff40"
opacity="0.1254902"
empcolor="#40ff40"
empopacity="0.25098039" />
empopacity="0.25098039"
originx="0"
originy="0"
units="px"
visible="true" />
</sodipodi:namedview>
<metadata
id="metadata5">
@ -432,7 +438,6 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
@ -496,26 +501,27 @@
x="264.65997"
y="124.10143"
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1" /></flowRegion><flowPara
id="flowPara4724" /></flowRoot> <rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5231-9"
width="25.4"
height="25.400003"
x="21.166666"
y="101.6" />
id="flowPara4724" /></flowRoot>
<rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5231-9-7"
width="25.4"
height="25.400003"
x="21.166666"
y="55.033333" />
<rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:5.38756;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5231-9-5"
width="25.4"
height="25.400003"
x="21.166664"
y="8.4666681" />
width="96.212502"
height="0.61243516"
x="19.62678"
y="33.575779" />
<rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:5.38755;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5231-9-5-7"
width="96.212448"
height="0.6124543"
x="19.627108"
y="67.442772" />
<rect
style="display:inline;fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:5.38755;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5231-9-5-7-5"
width="96.212448"
height="0.6124543"
x="19.627108"
y="101.30978" />
</g>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

@ -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

@ -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");

@ -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 <ISceneCollisionManager.h>
#include <iostream>
@ -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<IGUIImage>(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<IGUIImage>(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<IGUIImage>(makeJoystickButton(joystick_off_id,
m_joystick_btn_off = grab_gui_element<IGUIImage>(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<IGUIImage>(makeJoystickButton(joystick_off_id,
m_joystick_btn_off = grab_gui_element<IGUIImage>(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<IGUIImage>(makeJoystickButton(joystick_bg_id,
m_joystick_btn_bg = grab_gui_element<IGUIImage>(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<IGUIImage>(makeJoystickButton(joystick_center_id,
m_joystick_btn_center = grab_gui_element<IGUIImage>(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<IGUIImage>(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<IGUIStaticText>(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<IGUIStaticText>(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<button_info> &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<IGUIImage>(btn_gui_button);
}
IGUIImage *TouchScreenGUI::makeJoystickButton(touch_gui_button_id id,
const recti &button_rect, bool visible)
void TouchScreenGUI::addToggleButton(std::vector<button_info> &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);
}

@ -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 <IEventReceiver.h>
#include <IGUIImage.h>
@ -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<IGUIImage> m_starter;
std::vector<button_info> 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<IGUIImage> m_joystick_btn_center;
std::vector<button_info> m_buttons;
std::shared_ptr<IGUIImage> m_overflow_btn;
bool m_overflow_open = false;
std::shared_ptr<IGUIStaticText> m_overflow_bg;
std::vector<button_info> m_overflow_buttons;
std::vector<std::shared_ptr<IGUIStaticText>> m_overflow_button_titles;
std::vector<recti> 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<button_info> &buttons,
touch_gui_button_id id, const std::string &image,
const recti &rect, bool visible=true);
void addToggleButton(std::vector<button_info> &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<size_t, v2s32> m_pointer_pos;
std::vector<AutoHideButtonBar> m_buttonbars;
v2s32 getPointerPos();
void emitMouseEvent(EMOUSE_INPUT_EVENT type);
TouchInteractionMode m_last_mode = TouchInteractionMode_END;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 155 B