From a1722273b5b7d83628bc45e7c388d996c37f1779 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 11 Feb 2026 09:03:18 +0100 Subject: [PATCH 1/2] Change event propagation order The active tool is now the first to received and possibly catch the event. It does seem quite logical to have it before the selection tool because the active tool is the one that should be actually interacting with the user, and the selection is somehow a fallback behavior. This change is required to allow painting on a model and using the shift key without having the selection to catch this event and change the selection. --- UM/Controller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/UM/Controller.py b/UM/Controller.py index 77291966a..8a493fe3a 100644 --- a/UM/Controller.py +++ b/UM/Controller.py @@ -428,17 +428,17 @@ def getScene(self) -> Scene: def event(self, event: Event): """Process an event - The event is first passed to the selection tool, then the active tool and finally the camera tool. + The event is first passed to the active tool, then the selection tool and finally the camera tool. If none of these events handle it (when they return something that does not evaluate to true) a context menu signal is emitted. :param event: event to be handle. """ - if self._selection_tool and self._selection_tool.event(event): + if self._active_tool and self._active_tool.event(event): return - if self._active_tool and self._active_tool.event(event): + if self._selection_tool and self._selection_tool.event(event): return if self._camera_tool and self._camera_tool.event(event): From d4008c9058f61f0dff7323eedc56c8e27612e860 Mon Sep 17 00:00:00 2001 From: Erwan MATHIEU Date: Wed, 11 Feb 2026 18:38:41 +0100 Subject: [PATCH 2/2] Refine core tools behavior This change is required due to the behavior change in the events propagations to the tools. It also allows multi-selected-objects interactions, e.g. dragging multiple selected objects on the build plate. --- plugins/Tools/MirrorTool/MirrorTool.py | 4 ++++ plugins/Tools/RotateTool/RotateTool.py | 4 ++++ plugins/Tools/ScaleTool/ScaleTool.py | 4 ++++ plugins/Tools/TranslateTool/TranslateTool.py | 4 ++++ 4 files changed, 16 insertions(+) diff --git a/plugins/Tools/MirrorTool/MirrorTool.py b/plugins/Tools/MirrorTool/MirrorTool.py index 975d79430..481f08dcc 100644 --- a/plugins/Tools/MirrorTool/MirrorTool.py +++ b/plugins/Tools/MirrorTool/MirrorTool.py @@ -41,6 +41,10 @@ def event(self, event): if not id: return False + node = self.getController().getScene().findObject(id) + if node and not Selection.isSelected(node): + return False + if self._handle.isAxis(id): self.setLockedAxis(id) self._operation_started = True diff --git a/plugins/Tools/RotateTool/RotateTool.py b/plugins/Tools/RotateTool/RotateTool.py index 2b3f39156..d52ad70a5 100644 --- a/plugins/Tools/RotateTool/RotateTool.py +++ b/plugins/Tools/RotateTool/RotateTool.py @@ -102,6 +102,10 @@ def event(self, event): if not id: return False + node = self.getController().getScene().findObject(id) + if node and not Selection.isSelected(node): + return False + if id in self._handle.getExtraWidgetsColorMap(): self._active_widget = self._handle.ExtraWidgets(id) self._widget_click_start = time.monotonic() diff --git a/plugins/Tools/ScaleTool/ScaleTool.py b/plugins/Tools/ScaleTool/ScaleTool.py index af8786c7d..61e96352a 100644 --- a/plugins/Tools/ScaleTool/ScaleTool.py +++ b/plugins/Tools/ScaleTool/ScaleTool.py @@ -104,6 +104,10 @@ def event(self, event): if not id: return False + node = self.getController().getScene().findObject(id) + if node and not Selection.isSelected(node): + return False + if self._handle.isAxis(id): self.setLockedAxis(id) self._saved_handle_position = self._handle.getWorldPosition() diff --git a/plugins/Tools/TranslateTool/TranslateTool.py b/plugins/Tools/TranslateTool/TranslateTool.py index ba0a9c400..9f6b35684 100644 --- a/plugins/Tools/TranslateTool/TranslateTool.py +++ b/plugins/Tools/TranslateTool/TranslateTool.py @@ -261,6 +261,10 @@ def event(self, event: Event) -> bool: if not id: return False + node = self.getController().getScene().findObject(id) + if node and not Selection.isSelected(node): + return False + if id in self._enabled_axis: self.setLockedAxis(id) elif self._handle.isAxis(id):