mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
TouchControls: Implement an option for dig/place buttons (#15845)
This commit is contained in:
parent
1f14b7cb1b
commit
ead44a27ca
15 changed files with 540 additions and 88 deletions
|
@ -102,6 +102,9 @@ grorp:
|
||||||
using the font "undefined medium" (https://undefined-medium.com/),
|
using the font "undefined medium" (https://undefined-medium.com/),
|
||||||
which is licensed under the SIL Open Font License, Version 1.1
|
which is licensed under the SIL Open Font License, Version 1.1
|
||||||
modified by DS
|
modified by DS
|
||||||
|
textures/base/pack/dig_btn.png
|
||||||
|
textures/base/pack/place_btn.png
|
||||||
|
derived by editing the text in aux1_btn.svg
|
||||||
|
|
||||||
License of Luanti source code
|
License of Luanti source code
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
148
android/icons/dig_btn.svg
Normal file
148
android/icons/dig_btn.svg
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
inkscape:export-ydpi="24.000002"
|
||||||
|
inkscape:export-xdpi="24.000002"
|
||||||
|
inkscape:export-filename="../../textures/base/pack/dig_btn.png"
|
||||||
|
sodipodi:docname="dig_btn.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 135.46666 135.46667"
|
||||||
|
height="512"
|
||||||
|
width="512"
|
||||||
|
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" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:snap-others="true"
|
||||||
|
inkscape:snap-object-midpoints="false"
|
||||||
|
inkscape:snap-to-guides="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:snap-page="true"
|
||||||
|
inkscape:snap-grids="false"
|
||||||
|
inkscape:pagecheckerboard="false"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:current-layer="layer2"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:cy="266.84627"
|
||||||
|
inkscape:cx="201.24514"
|
||||||
|
inkscape:zoom="1.4633894"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#404040"
|
||||||
|
id="base"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:deskcolor="#d1d1d1">
|
||||||
|
<inkscape:grid
|
||||||
|
empopacity="0.25098039"
|
||||||
|
empcolor="#40ff40"
|
||||||
|
opacity="0.1254902"
|
||||||
|
color="#40ff40"
|
||||||
|
empspacing="4"
|
||||||
|
spacingy="0.26458333"
|
||||||
|
spacingx="0.26458333"
|
||||||
|
id="grid16"
|
||||||
|
type="xygrid"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
units="px"
|
||||||
|
visible="true" />
|
||||||
|
</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" />
|
||||||
|
<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
|
||||||
|
style="display:inline"
|
||||||
|
inkscape:label="Layer 2"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7055"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7035"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7005"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5127"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<text
|
||||||
|
transform="scale(1.0078883,0.99217343)"
|
||||||
|
id="text4716"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
xml:space="preserve"><tspan
|
||||||
|
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
id="tspan4714"
|
||||||
|
sodipodi:role="line">LMB</tspan></text>
|
||||||
|
<flowRoot
|
||||||
|
transform="scale(0.26458333)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRoot4718"
|
||||||
|
xml:space="preserve"><flowRegion
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRegion4720"><rect
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
y="124.10143"
|
||||||
|
x="264.65997"
|
||||||
|
height="136.37059"
|
||||||
|
width="157.5838"
|
||||||
|
id="rect4722" /></flowRegion><flowPara
|
||||||
|
id="flowPara4724" /></flowRoot>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
148
android/icons/place_btn.svg
Normal file
148
android/icons/place_btn.svg
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<svg
|
||||||
|
inkscape:export-ydpi="24.000002"
|
||||||
|
inkscape:export-xdpi="24.000002"
|
||||||
|
inkscape:export-filename="../../textures/base/pack/place_btn.png"
|
||||||
|
sodipodi:docname="place_btn.svg"
|
||||||
|
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25)"
|
||||||
|
id="svg8"
|
||||||
|
version="1.1"
|
||||||
|
viewBox="0 0 135.46666 135.46667"
|
||||||
|
height="512"
|
||||||
|
width="512"
|
||||||
|
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" />
|
||||||
|
<sodipodi:namedview
|
||||||
|
inkscape:document-rotation="0"
|
||||||
|
inkscape:snap-bbox-midpoints="true"
|
||||||
|
inkscape:snap-others="true"
|
||||||
|
inkscape:snap-object-midpoints="false"
|
||||||
|
inkscape:snap-to-guides="true"
|
||||||
|
inkscape:snap-bbox="true"
|
||||||
|
showguides="true"
|
||||||
|
inkscape:snap-page="true"
|
||||||
|
inkscape:snap-grids="false"
|
||||||
|
inkscape:pagecheckerboard="false"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:window-y="32"
|
||||||
|
inkscape:window-x="0"
|
||||||
|
inkscape:window-height="1011"
|
||||||
|
inkscape:window-width="1920"
|
||||||
|
units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:current-layer="layer2"
|
||||||
|
inkscape:document-units="mm"
|
||||||
|
inkscape:cy="266.84627"
|
||||||
|
inkscape:cx="201.24514"
|
||||||
|
inkscape:zoom="1.4633894"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
borderopacity="1.0"
|
||||||
|
bordercolor="#666666"
|
||||||
|
pagecolor="#404040"
|
||||||
|
id="base"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:deskcolor="#d1d1d1">
|
||||||
|
<inkscape:grid
|
||||||
|
empopacity="0.25098039"
|
||||||
|
empcolor="#40ff40"
|
||||||
|
opacity="0.1254902"
|
||||||
|
color="#40ff40"
|
||||||
|
empspacing="4"
|
||||||
|
spacingy="0.26458333"
|
||||||
|
spacingx="0.26458333"
|
||||||
|
id="grid16"
|
||||||
|
type="xygrid"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
units="px"
|
||||||
|
visible="true" />
|
||||||
|
</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" />
|
||||||
|
<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
|
||||||
|
style="display:inline"
|
||||||
|
inkscape:label="Layer 2"
|
||||||
|
id="layer2"
|
||||||
|
inkscape:groupmode="layer">
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7055"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7035"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path7005"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<path
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path5127"
|
||||||
|
d=""
|
||||||
|
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||||
|
<text
|
||||||
|
transform="scale(1.0078883,0.99217343)"
|
||||||
|
id="text4716"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:48.4785px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
xml:space="preserve"><tspan
|
||||||
|
style="fill:#d9d9d9;fill-opacity:1;stroke:#ffffff;stroke-width:1;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||||
|
y="85.59491"
|
||||||
|
x="67.78315"
|
||||||
|
id="tspan4714"
|
||||||
|
sodipodi:role="line">RMB</tspan></text>
|
||||||
|
<flowRoot
|
||||||
|
transform="scale(0.26458333)"
|
||||||
|
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:40px;line-height:1.25;font-family:'Bitstream Vera Sans';-inkscape-font-specification:'Bitstream Vera Sans';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRoot4718"
|
||||||
|
xml:space="preserve"><flowRegion
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
id="flowRegion4720"><rect
|
||||||
|
style="fill:none;fill-opacity:1;stroke:#ffffff;stroke-opacity:1"
|
||||||
|
y="124.10143"
|
||||||
|
x="264.65997"
|
||||||
|
height="136.37059"
|
||||||
|
width="157.5838"
|
||||||
|
id="rect4722" /></flowRegion><flowPara
|
||||||
|
id="flowPara4724" /></flowRoot>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 5.6 KiB |
|
@ -259,6 +259,17 @@ local function load()
|
||||||
["true"] = fgettext_ne("Enabled"),
|
["true"] = fgettext_ne("Enabled"),
|
||||||
["false"] = fgettext_ne("Disabled"),
|
["false"] = fgettext_ne("Disabled"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get_setting_info("touch_interaction_style").option_labels = {
|
||||||
|
["tap"] = fgettext_ne("Tap"),
|
||||||
|
["tap_crosshair"] = fgettext_ne("Tap with crosshair"),
|
||||||
|
["buttons_crosshair"] = fgettext("Buttons with crosshair"),
|
||||||
|
}
|
||||||
|
|
||||||
|
get_setting_info("touch_punch_gesture").option_labels = {
|
||||||
|
["short_tap"] = fgettext_ne("Short tap"),
|
||||||
|
["long_tap"] = fgettext_ne("Long tap"),
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -359,6 +370,7 @@ local function check_requirements(name, requires)
|
||||||
local video_driver = core.get_active_driver()
|
local video_driver = core.get_active_driver()
|
||||||
local touch_support = core.irrlicht_device_supports_touch()
|
local touch_support = core.irrlicht_device_supports_touch()
|
||||||
local touch_controls = core.settings:get("touch_controls")
|
local touch_controls = core.settings:get("touch_controls")
|
||||||
|
local touch_interaction_style = core.settings:get("touch_interaction_style")
|
||||||
local special = {
|
local special = {
|
||||||
android = PLATFORM == "Android",
|
android = PLATFORM == "Android",
|
||||||
desktop = PLATFORM ~= "Android",
|
desktop = PLATFORM ~= "Android",
|
||||||
|
@ -369,6 +381,7 @@ local function check_requirements(name, requires)
|
||||||
keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)),
|
keyboard_mouse = not touch_support or (touch_controls == "auto" or not core.is_yes(touch_controls)),
|
||||||
opengl = (video_driver == "opengl" or video_driver == "opengl3"),
|
opengl = (video_driver == "opengl" or video_driver == "opengl3"),
|
||||||
gles = video_driver:sub(1, 5) == "ogles",
|
gles = video_driver:sub(1, 5) == "ogles",
|
||||||
|
touch_interaction_style_tap = touch_interaction_style ~= "buttons_crosshair",
|
||||||
}
|
}
|
||||||
|
|
||||||
for req_key, req_value in pairs(requires) do
|
for req_key, req_value in pairs(requires) do
|
||||||
|
|
|
@ -167,6 +167,36 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false
|
||||||
# Requires: touch_support
|
# Requires: touch_support
|
||||||
touch_controls (Touchscreen controls) enum auto auto,true,false
|
touch_controls (Touchscreen controls) enum auto auto,true,false
|
||||||
|
|
||||||
|
# The kind of digging/placing controls used.
|
||||||
|
#
|
||||||
|
# * Tap
|
||||||
|
# Long/short tap anywhere on the screen to interact.
|
||||||
|
# Interaction happens at finger position.
|
||||||
|
#
|
||||||
|
# * Tap with crosshair
|
||||||
|
# Long/short tap anywhere on the screen to interact.
|
||||||
|
# Interaction happens at crosshair position.
|
||||||
|
#
|
||||||
|
# * Buttons with crosshair
|
||||||
|
# Use dedicated dig/place buttons to interact.
|
||||||
|
# Interaction happens at crosshair position.
|
||||||
|
#
|
||||||
|
# Requires: touchscreen
|
||||||
|
touch_interaction_style (Interaction style) enum tap tap,tap_crosshair,buttons_crosshair
|
||||||
|
|
||||||
|
# The gesture for punching players/entities.
|
||||||
|
# This can be overridden by games and mods.
|
||||||
|
#
|
||||||
|
# * Short tap
|
||||||
|
# Easy to use and well-known from other games that shall not be named.
|
||||||
|
#
|
||||||
|
# * Long tap
|
||||||
|
# Known from the classic Luanti mobile controls.
|
||||||
|
# Combat is more or less impossible.
|
||||||
|
#
|
||||||
|
# Requires: touchscreen, touch_interaction_style_tap
|
||||||
|
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
||||||
|
|
||||||
# Touchscreen sensitivity multiplier.
|
# Touchscreen sensitivity multiplier.
|
||||||
#
|
#
|
||||||
# Requires: touchscreen
|
# Requires: touchscreen
|
||||||
|
@ -182,12 +212,6 @@ touchscreen_threshold (Movement threshold) int 20 0 100
|
||||||
# Requires: touchscreen
|
# Requires: touchscreen
|
||||||
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
|
touch_long_tap_delay (Threshold for long taps) int 400 100 1000
|
||||||
|
|
||||||
# Use crosshair to select object instead of whole screen.
|
|
||||||
# If enabled, a crosshair will be shown and will be used for selecting object.
|
|
||||||
#
|
|
||||||
# Requires: touchscreen
|
|
||||||
touch_use_crosshair (Use crosshair for touch screen) bool false
|
|
||||||
|
|
||||||
# Fixes the position of virtual joystick.
|
# Fixes the position of virtual joystick.
|
||||||
# If disabled, virtual joystick will center to first-touch's position.
|
# If disabled, virtual joystick will center to first-touch's position.
|
||||||
#
|
#
|
||||||
|
@ -200,20 +224,6 @@ fixed_virtual_joystick (Fixed virtual joystick) bool false
|
||||||
# Requires: touchscreen
|
# Requires: touchscreen
|
||||||
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
|
virtual_joystick_triggers_aux1 (Virtual joystick triggers Aux1 button) bool false
|
||||||
|
|
||||||
# The gesture for punching players/entities.
|
|
||||||
# This can be overridden by games and mods.
|
|
||||||
#
|
|
||||||
# * short_tap
|
|
||||||
# Easy to use and well-known from other games that shall not be named.
|
|
||||||
#
|
|
||||||
# * long_tap
|
|
||||||
# Known from the classic Luanti mobile controls.
|
|
||||||
# Combat is more or less impossible.
|
|
||||||
#
|
|
||||||
# Requires: touchscreen
|
|
||||||
touch_punch_gesture (Punch gesture) enum short_tap short_tap,long_tap
|
|
||||||
|
|
||||||
|
|
||||||
[Graphics and Audio]
|
[Graphics and Audio]
|
||||||
|
|
||||||
[*Graphics]
|
[*Graphics]
|
||||||
|
|
|
@ -139,21 +139,34 @@ are placeholders intended to be overwritten by the game.
|
||||||
|
|
||||||
### Android textures
|
### Android textures
|
||||||
|
|
||||||
* `drop_btn.png`
|
* `dig_btn.png`
|
||||||
* `fast_btn.png`
|
* `place_btn.png`
|
||||||
* `fly_btn.png`
|
|
||||||
* `jump_btn.png`
|
* `jump_btn.png`
|
||||||
* `noclip_btn.png`
|
* `down.png`
|
||||||
|
* `zoom.png`
|
||||||
|
* `aux1_btn.png`
|
||||||
|
* `overflow_btn.png`
|
||||||
|
|
||||||
* `camera_btn.png`
|
|
||||||
* `chat_btn.png`
|
* `chat_btn.png`
|
||||||
* `inventory_btn.png`
|
* `inventory_btn.png`
|
||||||
* `rangeview_btn.png`
|
* `drop_btn.png`
|
||||||
|
|
||||||
* `debug_btn.png`
|
|
||||||
* `overflow_btn.png`
|
|
||||||
* `exit_btn.png`
|
* `exit_btn.png`
|
||||||
|
|
||||||
|
* `fly_btn.png`
|
||||||
|
* `fast_btn.png`
|
||||||
|
* `noclip_btn.png`
|
||||||
|
* `debug_btn.png`
|
||||||
|
* `camera_btn.png`
|
||||||
|
* `rangeview_btn.png`
|
||||||
|
* `minimap_btn.png`
|
||||||
|
* `chat_hide_btn.png`
|
||||||
|
* `chat_show_btn.png`
|
||||||
|
|
||||||
|
* `joystick_off.png`
|
||||||
|
* `joystick_bg.png`
|
||||||
|
* `joystick_center.png`
|
||||||
|
|
||||||
Texture Overrides
|
Texture Overrides
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
|
|
@ -549,9 +549,9 @@ void set_default_settings()
|
||||||
settings->setDefault("touchscreen_sensitivity", "0.2");
|
settings->setDefault("touchscreen_sensitivity", "0.2");
|
||||||
settings->setDefault("touchscreen_threshold", "20");
|
settings->setDefault("touchscreen_threshold", "20");
|
||||||
settings->setDefault("touch_long_tap_delay", "400");
|
settings->setDefault("touch_long_tap_delay", "400");
|
||||||
settings->setDefault("touch_use_crosshair", "false");
|
|
||||||
settings->setDefault("fixed_virtual_joystick", "false");
|
settings->setDefault("fixed_virtual_joystick", "false");
|
||||||
settings->setDefault("virtual_joystick_triggers_aux1", "false");
|
settings->setDefault("virtual_joystick_triggers_aux1", "false");
|
||||||
|
settings->setDefault("touch_interaction_style", "tap");
|
||||||
settings->setDefault("touch_punch_gesture", "short_tap");
|
settings->setDefault("touch_punch_gesture", "short_tap");
|
||||||
settings->setDefault("clickable_chat_weblinks", "true");
|
settings->setDefault("clickable_chat_weblinks", "true");
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "client/guiscalingfilter.h"
|
#include "client/guiscalingfilter.h"
|
||||||
#include "client/renderingengine.h"
|
#include "client/renderingengine.h"
|
||||||
#include "client/texturesource.h"
|
#include "client/texturesource.h"
|
||||||
|
#include "util/enum_string.h"
|
||||||
#include "util/numeric.h"
|
#include "util/numeric.h"
|
||||||
#include "irr_gui_ptr.h"
|
#include "irr_gui_ptr.h"
|
||||||
#include "IGUIImage.h"
|
#include "IGUIImage.h"
|
||||||
|
@ -78,15 +79,18 @@ bool TouchControls::buttonsHandlePress(std::vector<button_info> &buttons, size_t
|
||||||
|
|
||||||
for (button_info &btn : buttons) {
|
for (button_info &btn : buttons) {
|
||||||
if (btn.gui_button.get() == element) {
|
if (btn.gui_button.get() == element) {
|
||||||
|
// Allow moving the camera with the same finger that holds dig/place.
|
||||||
|
bool absorb = btn.id != dig_id && btn.id != place_id;
|
||||||
|
|
||||||
assert(std::find(btn.pointer_ids.begin(), btn.pointer_ids.end(), pointer_id) == btn.pointer_ids.end());
|
assert(std::find(btn.pointer_ids.begin(), btn.pointer_ids.end(), pointer_id) == btn.pointer_ids.end());
|
||||||
btn.pointer_ids.push_back(pointer_id);
|
btn.pointer_ids.push_back(pointer_id);
|
||||||
|
|
||||||
if (btn.pointer_ids.size() > 1)
|
if (btn.pointer_ids.size() > 1)
|
||||||
return true;
|
return absorb;
|
||||||
|
|
||||||
buttonEmitAction(btn, true);
|
buttonEmitAction(btn, true);
|
||||||
btn.repeat_counter = -BUTTON_REPEAT_DELAY;
|
btn.repeat_counter = -BUTTON_REPEAT_DELAY;
|
||||||
return true;
|
return absorb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,13 +103,16 @@ bool TouchControls::buttonsHandleRelease(std::vector<button_info> &buttons, size
|
||||||
for (button_info &btn : buttons) {
|
for (button_info &btn : buttons) {
|
||||||
auto it = std::find(btn.pointer_ids.begin(), btn.pointer_ids.end(), pointer_id);
|
auto it = std::find(btn.pointer_ids.begin(), btn.pointer_ids.end(), pointer_id);
|
||||||
if (it != btn.pointer_ids.end()) {
|
if (it != btn.pointer_ids.end()) {
|
||||||
|
// Don't absorb since we didn't absorb the press event either.
|
||||||
|
bool absorb = btn.id != dig_id && btn.id != place_id;
|
||||||
|
|
||||||
btn.pointer_ids.erase(it);
|
btn.pointer_ids.erase(it);
|
||||||
|
|
||||||
if (!btn.pointer_ids.empty())
|
if (!btn.pointer_ids.empty())
|
||||||
return true;
|
return absorb;
|
||||||
|
|
||||||
buttonEmitAction(btn, false);
|
buttonEmitAction(btn, false);
|
||||||
return true;
|
return absorb;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +124,8 @@ bool TouchControls::buttonsStep(std::vector<button_info> &buttons, float dtime)
|
||||||
bool has_pointers = false;
|
bool has_pointers = false;
|
||||||
|
|
||||||
for (button_info &btn : buttons) {
|
for (button_info &btn : buttons) {
|
||||||
|
if (btn.id == dig_id || btn.id == place_id)
|
||||||
|
continue; // key repeats would cause glitches here
|
||||||
if (btn.pointer_ids.empty())
|
if (btn.pointer_ids.empty())
|
||||||
continue;
|
continue;
|
||||||
has_pointers = true;
|
has_pointers = true;
|
||||||
|
@ -205,7 +214,7 @@ static const KeyPress &id_to_keypress(touch_gui_button_id id)
|
||||||
|
|
||||||
|
|
||||||
static const char *setting_names[] = {
|
static const char *setting_names[] = {
|
||||||
"touch_use_crosshair",
|
"touch_interaction_style",
|
||||||
"touchscreen_threshold", "touch_long_tap_delay",
|
"touchscreen_threshold", "touch_long_tap_delay",
|
||||||
"fixed_virtual_joystick", "virtual_joystick_triggers_aux1",
|
"fixed_virtual_joystick", "virtual_joystick_triggers_aux1",
|
||||||
"touch_layout",
|
"touch_layout",
|
||||||
|
@ -232,14 +241,20 @@ void TouchControls::settingChangedCallback(const std::string &name, void *data)
|
||||||
|
|
||||||
void TouchControls::readSettings()
|
void TouchControls::readSettings()
|
||||||
{
|
{
|
||||||
m_use_crosshair = g_settings->getBool("touch_use_crosshair");
|
const std::string &s = g_settings->get("touch_interaction_style");
|
||||||
|
if (!string_to_enum(es_TouchInteractionStyle, m_interaction_style, s)) {
|
||||||
|
m_interaction_style = TAP;
|
||||||
|
warningstream << "Invalid touch_interaction_style value" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
m_touchscreen_threshold = g_settings->getU16("touchscreen_threshold");
|
m_touchscreen_threshold = g_settings->getU16("touchscreen_threshold");
|
||||||
m_long_tap_delay = g_settings->getU16("touch_long_tap_delay");
|
m_long_tap_delay = g_settings->getU16("touch_long_tap_delay");
|
||||||
m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick");
|
m_fixed_joystick = g_settings->getBool("fixed_virtual_joystick");
|
||||||
m_joystick_triggers_aux1 = g_settings->getBool("virtual_joystick_triggers_aux1");
|
m_joystick_triggers_aux1 = g_settings->getBool("virtual_joystick_triggers_aux1");
|
||||||
|
|
||||||
// Note that "fixed_virtual_joystick" and "virtual_joystick_triggers_aux1"
|
// Note that other settings also affect the layout:
|
||||||
// also affect the layout.
|
// - ButtonLayout::loadFromSettings: "touch_interaction_style" and "virtual_joystick_triggers_aux1"
|
||||||
|
// - applyLayout: "fixed_virtual_joystick"
|
||||||
applyLayout(ButtonLayout::loadFromSettings());
|
applyLayout(ButtonLayout::loadFromSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -305,8 +320,8 @@ void TouchControls::applyLayout(const ButtonLayout &layout)
|
||||||
overflow_buttons.erase(std::remove_if(
|
overflow_buttons.erase(std::remove_if(
|
||||||
overflow_buttons.begin(), overflow_buttons.end(),
|
overflow_buttons.begin(), overflow_buttons.end(),
|
||||||
[&](touch_gui_button_id id) {
|
[&](touch_gui_button_id id) {
|
||||||
// There's no sense in adding the overflow button to the overflow
|
// There would be no sense in adding the overflow button to the
|
||||||
// menu (also, it's impossible since it doesn't have a keycode).
|
// overflow menu.
|
||||||
return !mayAddButton(id) || id == overflow_id;
|
return !mayAddButton(id) || id == overflow_id;
|
||||||
}), overflow_buttons.end());
|
}), overflow_buttons.end());
|
||||||
|
|
||||||
|
@ -346,13 +361,10 @@ TouchControls::~TouchControls()
|
||||||
|
|
||||||
bool TouchControls::mayAddButton(touch_gui_button_id id)
|
bool TouchControls::mayAddButton(touch_gui_button_id id)
|
||||||
{
|
{
|
||||||
if (!ButtonLayout::isButtonAllowed(id))
|
assert(ButtonLayout::isButtonValid(id));
|
||||||
return false;
|
assert(ButtonLayout::isButtonAllowed(id));
|
||||||
if (id == aux1_id && m_joystick_triggers_aux1)
|
// The overflow button doesn't need a keycode to be valid.
|
||||||
return false;
|
return id == overflow_id || id_to_keypress(id);
|
||||||
if (id != overflow_id && !id_to_keypress(id))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TouchControls::addButton(std::vector<button_info> &buttons, touch_gui_button_id id,
|
void TouchControls::addButton(std::vector<button_info> &buttons, touch_gui_button_id id,
|
||||||
|
@ -363,6 +375,7 @@ void TouchControls::addButton(std::vector<button_info> &buttons, touch_gui_butto
|
||||||
loadButtonTexture(btn_gui_button, image);
|
loadButtonTexture(btn_gui_button, image);
|
||||||
|
|
||||||
button_info &btn = buttons.emplace_back();
|
button_info &btn = buttons.emplace_back();
|
||||||
|
btn.id = id;
|
||||||
btn.keypress = id_to_keypress(id);
|
btn.keypress = id_to_keypress(id);
|
||||||
btn.gui_button = grab_gui_element<IGUIImage>(btn_gui_button);
|
btn.gui_button = grab_gui_element<IGUIImage>(btn_gui_button);
|
||||||
}
|
}
|
||||||
|
@ -429,7 +442,8 @@ void TouchControls::handleReleaseEvent(size_t pointer_id)
|
||||||
// If m_tap_state is already set to TapState::ShortTap, we must keep
|
// 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
|
// that value. Otherwise, many short taps will be ignored if you tap
|
||||||
// very fast.
|
// very fast.
|
||||||
if (!m_move_has_really_moved && !m_move_prevent_short_tap &&
|
if (m_interaction_style != BUTTONS_CROSSHAIR &&
|
||||||
|
!m_move_has_really_moved && !m_move_prevent_short_tap &&
|
||||||
m_tap_state != TapState::LongTap) {
|
m_tap_state != TapState::LongTap) {
|
||||||
m_tap_state = TapState::ShortTap;
|
m_tap_state = TapState::ShortTap;
|
||||||
} else {
|
} else {
|
||||||
|
@ -655,7 +669,9 @@ void TouchControls::step(float dtime)
|
||||||
applyJoystickStatus();
|
applyJoystickStatus();
|
||||||
|
|
||||||
// if a new placed pointer isn't moved for some time start digging
|
// if a new placed pointer isn't moved for some time start digging
|
||||||
if (m_has_move_id && !m_move_has_really_moved && m_tap_state == TapState::None) {
|
if (m_interaction_style != BUTTONS_CROSSHAIR &&
|
||||||
|
m_has_move_id && !m_move_has_really_moved &&
|
||||||
|
m_tap_state == TapState::None) {
|
||||||
u64 delta = porting::getDeltaMs(m_move_downtime, porting::getTimeMs());
|
u64 delta = porting::getDeltaMs(m_move_downtime, porting::getTimeMs());
|
||||||
|
|
||||||
if (delta > m_long_tap_delay) {
|
if (delta > m_long_tap_delay) {
|
||||||
|
@ -669,7 +685,7 @@ void TouchControls::step(float dtime)
|
||||||
// shootline when a touch event occurs.
|
// shootline when a touch event occurs.
|
||||||
// Only updating when m_has_move_id means that the shootline will stay at
|
// Only updating when m_has_move_id means that the shootline will stay at
|
||||||
// it's last in-world position when the player doesn't need it.
|
// it's last in-world position when the player doesn't need it.
|
||||||
if (!m_use_crosshair && (m_has_move_id || m_had_move_id)) {
|
if (m_interaction_style == TAP && (m_has_move_id || m_had_move_id)) {
|
||||||
m_shootline = m_device
|
m_shootline = m_device
|
||||||
->getSceneManager()
|
->getSceneManager()
|
||||||
->getSceneCollisionManager()
|
->getSceneCollisionManager()
|
||||||
|
@ -757,6 +773,9 @@ void TouchControls::show()
|
||||||
|
|
||||||
void TouchControls::applyContextControls(const TouchInteractionMode &mode)
|
void TouchControls::applyContextControls(const TouchInteractionMode &mode)
|
||||||
{
|
{
|
||||||
|
if (m_interaction_style == BUTTONS_CROSSHAIR)
|
||||||
|
return;
|
||||||
|
|
||||||
// Since the pointed thing has already been determined when this function
|
// Since the pointed thing has already been determined when this function
|
||||||
// is called, we cannot use this function to update the shootline.
|
// is called, we cannot use this function to update the shootline.
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ enum class TapState
|
||||||
|
|
||||||
struct button_info
|
struct button_info
|
||||||
{
|
{
|
||||||
|
touch_gui_button_id id;
|
||||||
float repeat_counter;
|
float repeat_counter;
|
||||||
KeyPress keypress;
|
KeyPress keypress;
|
||||||
std::vector<size_t> pointer_ids;
|
std::vector<size_t> pointer_ids;
|
||||||
|
@ -94,7 +95,7 @@ public:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isShootlineAvailable() { return !m_use_crosshair; }
|
bool isShootlineAvailable() { return m_interaction_style == TAP; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a line which describes what the player is pointing at.
|
* Returns a line which describes what the player is pointing at.
|
||||||
|
@ -137,7 +138,7 @@ private:
|
||||||
s32 m_button_size;
|
s32 m_button_size;
|
||||||
|
|
||||||
// cached settings
|
// cached settings
|
||||||
bool m_use_crosshair;
|
TouchInteractionStyle m_interaction_style;
|
||||||
double m_touchscreen_threshold;
|
double m_touchscreen_threshold;
|
||||||
u16 m_long_tap_delay;
|
u16 m_long_tap_delay;
|
||||||
bool m_fixed_joystick;
|
bool m_fixed_joystick;
|
||||||
|
@ -161,7 +162,7 @@ private:
|
||||||
* The line ends on the camera's far plane.
|
* The line ends on the camera's far plane.
|
||||||
* The coordinates do not contain the camera offset.
|
* The coordinates do not contain the camera offset.
|
||||||
*
|
*
|
||||||
* Only valid if !m_use_crosshair
|
* Only used for m_interaction_style == TAP
|
||||||
*/
|
*/
|
||||||
line3d<f32> m_shootline;
|
line3d<f32> m_shootline;
|
||||||
|
|
||||||
|
@ -243,6 +244,8 @@ private:
|
||||||
// map to store the IDs and positions of currently pressed pointers
|
// map to store the IDs and positions of currently pressed pointers
|
||||||
std::unordered_map<size_t, v2s32> m_pointer_pos;
|
std::unordered_map<size_t, v2s32> m_pointer_pos;
|
||||||
|
|
||||||
|
// The following are not used if m_interaction_style == BUTTONS_CROSSHAIR
|
||||||
|
|
||||||
TouchInteractionMode m_last_mode = TouchInteractionMode_END;
|
TouchInteractionMode m_last_mode = TouchInteractionMode_END;
|
||||||
TapState m_tap_state = TapState::None;
|
TapState m_tap_state = TapState::None;
|
||||||
|
|
||||||
|
|
|
@ -371,7 +371,7 @@ bool GUITouchscreenLayout::OnEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.GUIEvent.Caller == m_gui_reset_btn.get()) {
|
if (event.GUIEvent.Caller == m_gui_reset_btn.get()) {
|
||||||
m_layout = ButtonLayout::predefined;
|
m_layout = ButtonLayout::loadDefault();
|
||||||
regenerateGui(screensize);
|
regenerateGui(screensize);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,15 @@
|
||||||
|
|
||||||
#include "IGUIFont.h"
|
#include "IGUIFont.h"
|
||||||
#include "IGUIStaticText.h"
|
#include "IGUIStaticText.h"
|
||||||
|
#include "util/enum_string.h"
|
||||||
|
|
||||||
|
const struct EnumString es_TouchInteractionStyle[] =
|
||||||
|
{
|
||||||
|
{TAP, "tap"},
|
||||||
|
{TAP_CROSSHAIR, "tap_crosshair"},
|
||||||
|
{BUTTONS_CROSSHAIR, "buttons_crosshair"},
|
||||||
|
{0, NULL},
|
||||||
|
};
|
||||||
|
|
||||||
const char *button_names[] = {
|
const char *button_names[] = {
|
||||||
"dig",
|
"dig",
|
||||||
|
@ -73,8 +82,8 @@ const char *button_titles[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *button_image_names[] = {
|
const char *button_image_names[] = {
|
||||||
"",
|
"dig_btn.png",
|
||||||
"",
|
"place_btn.png",
|
||||||
|
|
||||||
"jump_btn.png",
|
"jump_btn.png",
|
||||||
"down.png",
|
"down.png",
|
||||||
|
@ -130,11 +139,21 @@ void ButtonMeta::setPos(v2s32 pos, v2u32 screensize, s32 button_size)
|
||||||
offset.Y = (pos.Y - (position.Y * screensize.Y)) / button_size;
|
offset.Y = (pos.Y - (position.Y * screensize.Y)) / button_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ButtonLayout::isButtonValid(touch_gui_button_id id)
|
||||||
|
{
|
||||||
|
return id != joystick_off_id && id != joystick_bg_id && id != joystick_center_id &&
|
||||||
|
id < touch_gui_button_id_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *buttons_crosshair = enum_to_string(es_TouchInteractionStyle, BUTTONS_CROSSHAIR);
|
||||||
|
|
||||||
bool ButtonLayout::isButtonAllowed(touch_gui_button_id id)
|
bool ButtonLayout::isButtonAllowed(touch_gui_button_id id)
|
||||||
{
|
{
|
||||||
return id != dig_id && id != place_id &&
|
if (id == dig_id || id == place_id)
|
||||||
id != joystick_off_id && id != joystick_bg_id && id != joystick_center_id &&
|
return g_settings->get("touch_interaction_style") == buttons_crosshair;
|
||||||
id != touch_gui_button_id_END;
|
if (id == aux1_id)
|
||||||
|
return !g_settings->getBool("virtual_joystick_triggers_aux1");
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ButtonLayout::isButtonRequired(touch_gui_button_id id)
|
bool ButtonLayout::isButtonRequired(touch_gui_button_id id)
|
||||||
|
@ -149,7 +168,15 @@ s32 ButtonLayout::getButtonSize(v2u32 screensize)
|
||||||
g_settings->getFloat("hud_scaling"));
|
g_settings->getFloat("hud_scaling"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const ButtonLayout ButtonLayout::predefined {{
|
const ButtonLayout::ButtonMap ButtonLayout::default_data {
|
||||||
|
{dig_id, {
|
||||||
|
v2f(1.0f, 1.0f),
|
||||||
|
v2f(-2.0f, -2.75f),
|
||||||
|
}},
|
||||||
|
{place_id, {
|
||||||
|
v2f(1.0f, 1.0f),
|
||||||
|
v2f(-2.0f, -4.25f),
|
||||||
|
}},
|
||||||
{jump_id, {
|
{jump_id, {
|
||||||
v2f(1.0f, 1.0f),
|
v2f(1.0f, 1.0f),
|
||||||
v2f(-1.0f, -0.5f),
|
v2f(-1.0f, -0.5f),
|
||||||
|
@ -170,28 +197,40 @@ const ButtonLayout ButtonLayout::predefined {{
|
||||||
v2f(1.0f, 1.0f),
|
v2f(1.0f, 1.0f),
|
||||||
v2f(-0.75f, -5.0f),
|
v2f(-0.75f, -5.0f),
|
||||||
}},
|
}},
|
||||||
}};
|
};
|
||||||
|
|
||||||
|
ButtonLayout ButtonLayout::postProcessLoaded(const ButtonMap &data)
|
||||||
|
{
|
||||||
|
ButtonLayout layout;
|
||||||
|
for (const auto &[id, meta] : data) {
|
||||||
|
assert(isButtonValid(id));
|
||||||
|
if (isButtonAllowed(id))
|
||||||
|
layout.layout.emplace(id, meta);
|
||||||
|
else
|
||||||
|
layout.preserved_disallowed.emplace(id, meta);
|
||||||
|
}
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonLayout ButtonLayout::loadDefault()
|
||||||
|
{
|
||||||
|
return postProcessLoaded(default_data);
|
||||||
|
}
|
||||||
|
|
||||||
ButtonLayout ButtonLayout::loadFromSettings()
|
ButtonLayout ButtonLayout::loadFromSettings()
|
||||||
{
|
{
|
||||||
bool restored = false;
|
|
||||||
ButtonLayout layout;
|
|
||||||
|
|
||||||
std::string str = g_settings->get("touch_layout");
|
std::string str = g_settings->get("touch_layout");
|
||||||
if (!str.empty()) {
|
if (!str.empty()) {
|
||||||
std::istringstream iss(str);
|
std::istringstream iss(str);
|
||||||
try {
|
try {
|
||||||
layout.deserializeJson(iss);
|
ButtonMap data = deserializeJson(iss);
|
||||||
restored = true;
|
return postProcessLoaded(data);
|
||||||
} catch (const Json::Exception &e) {
|
} catch (const Json::Exception &e) {
|
||||||
warningstream << "Could not parse touchscreen layout: " << e.what() << std::endl;
|
warningstream << "Could not parse touchscreen layout: " << e.what() << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!restored)
|
return loadDefault();
|
||||||
return predefined;
|
|
||||||
|
|
||||||
return layout;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<touch_gui_button_id, irr_ptr<video::ITexture>> ButtonLayout::texture_cache;
|
std::unordered_map<touch_gui_button_id, irr_ptr<video::ITexture>> ButtonLayout::texture_cache;
|
||||||
|
@ -234,7 +273,7 @@ std::vector<touch_gui_button_id> ButtonLayout::getMissingButtons()
|
||||||
std::vector<touch_gui_button_id> missing_buttons;
|
std::vector<touch_gui_button_id> missing_buttons;
|
||||||
for (u8 i = 0; i < touch_gui_button_id_END; i++) {
|
for (u8 i = 0; i < touch_gui_button_id_END; i++) {
|
||||||
touch_gui_button_id btn = (touch_gui_button_id)i;
|
touch_gui_button_id btn = (touch_gui_button_id)i;
|
||||||
if (isButtonAllowed(btn) && layout.count(btn) == 0)
|
if (isButtonValid(btn) && isButtonAllowed(btn) && layout.count(btn) == 0)
|
||||||
missing_buttons.push_back(btn);
|
missing_buttons.push_back(btn);
|
||||||
}
|
}
|
||||||
return missing_buttons;
|
return missing_buttons;
|
||||||
|
@ -243,16 +282,19 @@ std::vector<touch_gui_button_id> ButtonLayout::getMissingButtons()
|
||||||
void ButtonLayout::serializeJson(std::ostream &os) const
|
void ButtonLayout::serializeJson(std::ostream &os) const
|
||||||
{
|
{
|
||||||
Json::Value root = Json::objectValue;
|
Json::Value root = Json::objectValue;
|
||||||
|
root["version"] = 1;
|
||||||
root["layout"] = Json::objectValue;
|
root["layout"] = Json::objectValue;
|
||||||
|
|
||||||
for (const auto &[id, meta] : layout) {
|
for (const auto &list : {layout, preserved_disallowed}) {
|
||||||
Json::Value button = Json::objectValue;
|
for (const auto &[id, meta] : list) {
|
||||||
button["position_x"] = meta.position.X;
|
Json::Value button = Json::objectValue;
|
||||||
button["position_y"] = meta.position.Y;
|
button["position_x"] = meta.position.X;
|
||||||
button["offset_x"] = meta.offset.X;
|
button["position_y"] = meta.position.Y;
|
||||||
button["offset_y"] = meta.offset.Y;
|
button["offset_x"] = meta.offset.X;
|
||||||
|
button["offset_y"] = meta.offset.Y;
|
||||||
|
|
||||||
root["layout"][button_names[id]] = button;
|
root["layout"][button_names[id]] = button;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fastWriteJson(root, os);
|
fastWriteJson(root, os);
|
||||||
|
@ -267,13 +309,19 @@ static touch_gui_button_id button_name_to_id(const std::string &name)
|
||||||
return touch_gui_button_id_END;
|
return touch_gui_button_id_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ButtonLayout::deserializeJson(std::istream &is)
|
ButtonLayout::ButtonMap ButtonLayout::deserializeJson(std::istream &is)
|
||||||
{
|
{
|
||||||
layout.clear();
|
ButtonMap data;
|
||||||
|
|
||||||
Json::Value root;
|
Json::Value root;
|
||||||
is >> root;
|
is >> root;
|
||||||
|
|
||||||
|
u8 version;
|
||||||
|
if (root["version"].isUInt())
|
||||||
|
version = root["version"].asUInt();
|
||||||
|
else
|
||||||
|
version = 0;
|
||||||
|
|
||||||
if (!root["layout"].isObject())
|
if (!root["layout"].isObject())
|
||||||
throw Json::RuntimeError("invalid type for layout");
|
throw Json::RuntimeError("invalid type for layout");
|
||||||
|
|
||||||
|
@ -281,7 +329,7 @@ void ButtonLayout::deserializeJson(std::istream &is)
|
||||||
Json::ValueIterator iter;
|
Json::ValueIterator iter;
|
||||||
for (iter = obj.begin(); iter != obj.end(); iter++) {
|
for (iter = obj.begin(); iter != obj.end(); iter++) {
|
||||||
touch_gui_button_id id = button_name_to_id(iter.name());
|
touch_gui_button_id id = button_name_to_id(iter.name());
|
||||||
if (!isButtonAllowed(id))
|
if (!isButtonValid(id))
|
||||||
throw Json::RuntimeError("invalid button name");
|
throw Json::RuntimeError("invalid button name");
|
||||||
|
|
||||||
Json::Value &value = *iter;
|
Json::Value &value = *iter;
|
||||||
|
@ -300,8 +348,20 @@ void ButtonLayout::deserializeJson(std::istream &is)
|
||||||
meta.offset.X = value["offset_x"].asFloat();
|
meta.offset.X = value["offset_x"].asFloat();
|
||||||
meta.offset.Y = value["offset_y"].asFloat();
|
meta.offset.Y = value["offset_y"].asFloat();
|
||||||
|
|
||||||
layout.emplace(id, meta);
|
data.emplace(id, meta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version < 1) {
|
||||||
|
// Version 0 did not have dig/place buttons, so add them in.
|
||||||
|
// Otherwise, the missing buttons would cause confusion if the user
|
||||||
|
// switches to "touch_interaction_style = buttons_crosshair".
|
||||||
|
// This may result in overlapping buttons (could be fixed by resolving
|
||||||
|
// collisions in postProcessLoaded).
|
||||||
|
data.emplace(dig_id, default_data.at(dig_id));
|
||||||
|
data.emplace(place_id, default_data.at(place_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void layout_button_grid(v2u32 screensize, ISimpleTextureSource *tsrc,
|
void layout_button_grid(v2u32 screensize, ISimpleTextureSource *tsrc,
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include "irr_ptr.h"
|
#include "irr_ptr.h"
|
||||||
#include "irrlichttypes_bloated.h"
|
#include "irrlichttypes_bloated.h"
|
||||||
#include "rect.h"
|
#include "rect.h"
|
||||||
|
#include "util/enum_string.h"
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
|
@ -20,9 +21,16 @@ namespace irr::video
|
||||||
class ITexture;
|
class ITexture;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum TouchInteractionStyle : u8
|
||||||
|
{
|
||||||
|
TAP,
|
||||||
|
TAP_CROSSHAIR,
|
||||||
|
BUTTONS_CROSSHAIR,
|
||||||
|
};
|
||||||
|
extern const struct EnumString es_TouchInteractionStyle[];
|
||||||
|
|
||||||
enum touch_gui_button_id : u8
|
enum touch_gui_button_id : u8
|
||||||
{
|
{
|
||||||
// these two are no actual buttons ... yet
|
|
||||||
dig_id = 0,
|
dig_id = 0,
|
||||||
place_id,
|
place_id,
|
||||||
|
|
||||||
|
@ -75,15 +83,34 @@ struct ButtonMeta {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ButtonLayout {
|
struct ButtonLayout {
|
||||||
|
using ButtonMap = std::unordered_map<touch_gui_button_id, ButtonMeta>;
|
||||||
|
|
||||||
|
static bool isButtonValid(touch_gui_button_id id);
|
||||||
static bool isButtonAllowed(touch_gui_button_id id);
|
static bool isButtonAllowed(touch_gui_button_id id);
|
||||||
static bool isButtonRequired(touch_gui_button_id id);
|
static bool isButtonRequired(touch_gui_button_id id);
|
||||||
static s32 getButtonSize(v2u32 screensize);
|
static s32 getButtonSize(v2u32 screensize);
|
||||||
|
|
||||||
|
// Returns the default layout.
|
||||||
|
// Note: Indirectly depends on settings.
|
||||||
|
static ButtonLayout loadDefault();
|
||||||
|
// Reads the layout from the "touch_layout" setting. Falls back to loadDefault
|
||||||
|
// if the setting is absent or invalid.
|
||||||
|
// Note: Indirectly depends on additional settings.
|
||||||
static ButtonLayout loadFromSettings();
|
static ButtonLayout loadFromSettings();
|
||||||
|
|
||||||
static video::ITexture *getTexture(touch_gui_button_id btn, ISimpleTextureSource *tsrc);
|
static video::ITexture *getTexture(touch_gui_button_id btn, ISimpleTextureSource *tsrc);
|
||||||
static void clearTextureCache();
|
static void clearTextureCache();
|
||||||
|
|
||||||
std::unordered_map<touch_gui_button_id, ButtonMeta> layout;
|
ButtonMap layout;
|
||||||
|
|
||||||
|
// Contains disallowed buttons that have been loaded.
|
||||||
|
// These are only preserved to be saved again later.
|
||||||
|
// This exists to prevent data loss: If you edit the layout while some button
|
||||||
|
// is temporarily disallowed, this prevents that button's custom position
|
||||||
|
// from being lost. See isButtonAllowed.
|
||||||
|
// This may result in overlapping buttons when the buttons are allowed again
|
||||||
|
// (could be fixed by resolving collisions in postProcessLoaded).
|
||||||
|
ButtonMap preserved_disallowed;
|
||||||
|
|
||||||
core::recti getRect(touch_gui_button_id btn,
|
core::recti getRect(touch_gui_button_id btn,
|
||||||
v2u32 screensize, s32 button_size, ISimpleTextureSource *tsrc);
|
v2u32 screensize, s32 button_size, ISimpleTextureSource *tsrc);
|
||||||
|
@ -91,11 +118,12 @@ struct ButtonLayout {
|
||||||
std::vector<touch_gui_button_id> getMissingButtons();
|
std::vector<touch_gui_button_id> getMissingButtons();
|
||||||
|
|
||||||
void serializeJson(std::ostream &os) const;
|
void serializeJson(std::ostream &os) const;
|
||||||
void deserializeJson(std::istream &is);
|
|
||||||
|
|
||||||
static const ButtonLayout predefined;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static const ButtonMap default_data;
|
||||||
|
static ButtonMap deserializeJson(std::istream &is);
|
||||||
|
static ButtonLayout postProcessLoaded(const ButtonMap &map);
|
||||||
|
|
||||||
static std::unordered_map<touch_gui_button_id, irr_ptr<video::ITexture>> texture_cache;
|
static std::unordered_map<touch_gui_button_id, irr_ptr<video::ITexture>> texture_cache;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -28,4 +28,11 @@ void migrate_settings()
|
||||||
}
|
}
|
||||||
g_settings->remove("disable_anticheat");
|
g_settings->remove("disable_anticheat");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert touch_use_crosshair to touch_interaction_style
|
||||||
|
if (g_settings->existsLocal("touch_use_crosshair")) {
|
||||||
|
bool value = g_settings->getBool("touch_use_crosshair");
|
||||||
|
g_settings->set("touch_interaction_style", value ? "tap_crosshair" : "tap");
|
||||||
|
g_settings->remove("touch_use_crosshair");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
textures/base/pack/dig_btn.png
Normal file
BIN
textures/base/pack/dig_btn.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
BIN
textures/base/pack/place_btn.png
Normal file
BIN
textures/base/pack/place_btn.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
Loading…
Add table
Add a link
Reference in a new issue