Skip to content

Added an experimental touch-screen mode#1194

Draft
Max-RM wants to merge 6 commits intoAmulet-Team:0.10from
Max-RM:0.10
Draft

Added an experimental touch-screen mode#1194
Max-RM wants to merge 6 commits intoAmulet-Team:0.10from
Max-RM:0.10

Conversation

@Max-RM
Copy link
Contributor

@Max-RM Max-RM commented Aug 27, 2025

An experimental touch-screen mode has been added for touchscreen devices, such as x86 Windows tablets, tablets from the Microsoft Surface line, other touchscreen devices and phones with unofficially installed Windows ARM (Renegade Project) which was my case.
image_2025-08-26_18-40-55

The sensitivity of the camera can now take fractional, not just integer values, as it is necessary for touch control mode (recommended to use 0.2), in Options > Controls... A new switch "Enable touchscreen mode (experimental)" has been added, which enables touch control mode, which is disabled by default.
When turned on, it adds 6 buttons to control the camera's position in space (forward, backward, left, right, up, down), they work as switches, after pressing it will be active and turned off after pressing it again, you can also simulate diagonal movement by activating, for example, the forward and right buttons.
When the touch mode is activated up, two new buttons appear: "Touch Controls" and "Camera/Selector". The "Touch Controls" button can turn on and off 6 buttons for controlling the camera's position in space, this is necessary, since when using standard operations and third-party plug-ins, these buttons can overlap part of the interface, while this button allows you to temporarily disable them.
The Camera / Selector button is needed to switch the rotation modes of the camera's view direction (camera) and the selection mode (Selector), since there are big problems using the right and left mouse clicks on the touchscreen, this button helps to switch between modes so that it is easy.
While using the "Camera" mode, any interaction with the selection areas is blocked. When the "Selector" mode is turned on, to select the area correctly, you first need to long tap the desired block, then stretch from this block to another desired point, then if you need to stretch the area in one direction, you can not just poke along the edge of the selection area and stretch this, but first you need to long tap on the desired face, and as soon as it turns blue, you can stretch it in the right direction. If a mistake was made during the selection, you can simply cancel the action via the button at the top.

This is the most complete implementation of touch-screen control that could be done without having to use a mouse through an adapter.

Comment on lines +264 to +330
def set_touch_controls_enabled(self, enabled: bool):
"""Show or hide on-screen movement buttons.
Does not affect visibility of toolbar controls; that is controlled by touchscreen mode.
"""
self._touch_controls_enabled = bool(enabled)

# Show/hide touch buttons (only if touchscreen mode is enabled)
if hasattr(self, "_touch_buttons"):
for btn in self._touch_buttons.values():
btn.Show(self._touchscreen_mode and self._touch_controls_enabled)

# When touch controls are enabled, default to selection mode (mouse mode enabled)
# When touch controls are disabled, default to camera rotation mode (mouse mode disabled)
if (
not hasattr(self, "_mouse_selection_mode_initialized")
or not self._mouse_selection_mode_initialized
):
self._mouse_selection_mode = not self._touch_controls_enabled
self._mouse_selection_mode_initialized = True
# Apply the initial mouse mode setting
self.set_mouse_selection_mode(self._mouse_selection_mode)

# Ensure touch controls are positioned correctly and on top
if enabled and self._touchscreen_mode:
self._position_touch_overlay()

self.Layout()

# Update the toggle in the top toolbar (FilePanel)
if hasattr(self, "_file_panel"):
self._file_panel.update_touch_toggles()

def set_touchscreen_mode(self, enabled: bool):
"""Enable/disable touchscreen mode (global).
Controls whether the toolbar Touch Controls/Selector button is visible and
whether on-screen movement buttons can be shown at all.
"""
self._touchscreen_mode = bool(enabled)
# If disabling touchscreen mode, also hide on-screen buttons
if not self._touchscreen_mode:
self._touch_controls_enabled = False
# Apply visibility to on-screen buttons
if hasattr(self, "_touch_buttons"):
for btn in self._touch_buttons.values():
btn.Show(self._touchscreen_mode and self._touch_controls_enabled)
# Update toolbar controls visibility/state
if hasattr(self, "_file_panel"):
self._file_panel.update_touch_toggles()
self.Layout()

def set_mouse_selection_mode(self, selection_mode: bool):
"""Set mouse mode: True for selection mode, False for camera rotation mode."""
self._mouse_selection_mode = bool(selection_mode)
# Update camera behavior based on mode
if hasattr(self, "camera") and hasattr(self.camera, "rotating"):
if not selection_mode:
# Camera rotation mode - enable mouse rotation
self.camera.rotating = True
self.SetCursor(wx.Cursor(wx.CURSOR_BLANK))
else:
# Selection mode - disable mouse rotation
self.camera.rotating = False
self.SetCursor(wx.NullCursor)

# Update the toggle in the top toolbar (FilePanel)
if hasattr(self, "_file_panel"):
self._file_panel.update_touch_toggles()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These would be better as properties.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@property
def touch_controls_enabled(self) -> bool:
    return self._touch_controls_enabled

@touch_controls_enabled.setter
def touch_controls_enabled(self, enabled: bool) -> None:
    # your setter method goes here

You can then access it as canvas.touch_controls_enabled and set it as canvas.touch_controls_enabled = True

@gentlegiantJGC
Copy link
Member

All of the hasattr checks are redundant

@gentlegiantJGC
Copy link
Member

There are still lots of hasattr checks. Please remove them.
_mouse_selection_mode, _touch_controls_enabled, ... should be replaced with the public property you just added

Comment on lines +156 to +159
hasattr(self.canvas, "_mouse_selection_mode")
and not self.canvas._mouse_selection_mode
and hasattr(self.canvas, "_touch_controls_enabled")
and self.canvas._touch_controls_enabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +270 to +273
hasattr(self.canvas, "_mouse_selection_mode")
and not self.canvas._mouse_selection_mode
and hasattr(self.canvas, "_touch_controls_enabled")
and self.canvas._touch_controls_enabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +78 to +81
if (
not hasattr(self.canvas, "_touch_controls_enabled")
or not self.canvas._touch_controls_enabled
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +92 to +95
if (
not hasattr(self.canvas, "_touch_controls_enabled")
or not self.canvas._touch_controls_enabled
):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +116 to +120
self._camera_moved_with_touch
and hasattr(self.canvas, "_touch_controls_enabled")
and self.canvas._touch_controls_enabled
and hasattr(self.canvas, "set_mouse_selection_mode")
and self._saved_mouse_selection_mode is not None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +141 to +144
hasattr(self.canvas, "_touch_controls_enabled")
and self.canvas._touch_controls_enabled
and hasattr(self.canvas, "_mouse_selection_mode")
and any((forward, up, right))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +72 to +75
hasattr(self.canvas, "_mouse_selection_mode")
and not self.canvas._mouse_selection_mode
and hasattr(self.canvas, "_touch_controls_enabled")
and self.canvas._touch_controls_enabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +94 to +97
hasattr(self.canvas, "_mouse_selection_mode")
and not self.canvas._mouse_selection_mode
and hasattr(self.canvas, "_touch_controls_enabled")
and self.canvas._touch_controls_enabled
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

Comment on lines +205 to +212
if hasattr(self, "_file_panel"):
self._file_panel.update_touch_toggles()

# Initialize touch buttons
if hasattr(self, "_touch_buttons"):
self._position_touch_overlay()
for btn in self._touch_buttons.values():
btn.Show(self._touch_controls_enabled)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

improve

@gentlegiantJGC
Copy link
Member

This is a non-exhaustive list of places you are still doing hasattr checks.
The private variable accessed on the canvas should be replaced with the property.

If I see hasattr used or _touch_controls_enabled, _touchscreen_mode or _mouse_selection_mode used outside of the property I will ask you to change it.

@gentlegiantJGC gentlegiantJGC marked this pull request as draft August 28, 2025 12:47
@gentlegiantJGC
Copy link
Member

Click ready for review and @ me when you think it is ready

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants