From 3b3ed05dc86c165b13f244aa9bfbfbf9386b0576 Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Sun, 4 Feb 2024 15:16:49 +0100 Subject: [PATCH] Draft: fix wrong selection after commands Fixes #10469 The code of the `end_all_events()` function is by Chris Hennes (chennes). See https://forum.freecadweb.org/viewtopic.php?p=656362#p656362. --- src/Mod/Draft/Draft.py | 3 ++- src/Mod/Draft/draftguitools/gui_arcs.py | 8 ++++-- .../Draft/draftguitools/gui_base_original.py | 7 +++++ src/Mod/Draft/draftguitools/gui_ellipses.py | 1 + src/Mod/Draft/draftguitools/gui_labels.py | 2 +- src/Mod/Draft/draftguitools/gui_lines.py | 1 + src/Mod/Draft/draftguitools/gui_move.py | 11 +++----- src/Mod/Draft/draftguitools/gui_points.py | 6 +++++ src/Mod/Draft/draftguitools/gui_polygons.py | 1 + src/Mod/Draft/draftguitools/gui_rectangles.py | 10 +++---- src/Mod/Draft/draftguitools/gui_rotate.py | 4 +-- src/Mod/Draft/draftguitools/gui_snapper.py | 27 ++++++++++++++----- src/Mod/Draft/draftutils/gui_utils.py | 19 +++++++++++++ 13 files changed, 73 insertions(+), 27 deletions(-) diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index d54960f138..050ca872e8 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -117,7 +117,8 @@ from draftutils.gui_utils import (get3DView, select, loadTexture, load_texture, - get_bbox) + get_bbox, + end_all_events) from draftutils.gui_utils import (dim_symbol, dimSymbol, diff --git a/src/Mod/Draft/draftguitools/gui_arcs.py b/src/Mod/Draft/draftguitools/gui_arcs.py index 73b0450e24..bcc33a90a1 100644 --- a/src/Mod/Draft/draftguitools/gui_arcs.py +++ b/src/Mod/Draft/draftguitools/gui_arcs.py @@ -313,6 +313,7 @@ class Arc(gui_base_original.Creator): 'pl.Base = ' + _base, 'circle.Placement = pl', 'Draft.autogroup(circle)', + 'Draft.select(circle)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Circle (Part)"), _cmd_list) @@ -361,6 +362,7 @@ class Arc(gui_base_original.Creator): 'pl.Base = ' + _base, 'circle.Placement = pl', 'Draft.autogroup(circle)', + 'Draft.select(circle)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Arc (Part)"), _cmd_list) @@ -556,8 +558,10 @@ class Arc_3Points(gui_base.GuiCommandBase): _cmd += ", FreeCAD." + str(self.points[2]) _cmd += "], primitive=" + str(params.get_param("UsePartPrimitives")) + ")" _cmd_list = ["circle = " + _cmd, - "Draft.autogroup(circle)", - "FreeCAD.ActiveDocument.recompute()"] + "Draft.autogroup(circle)"] + if params.get_param("UsePartPrimitives"): + _cmd_list.append("Draft.select(circle)") + _cmd_list.append("FreeCAD.ActiveDocument.recompute()") self.commit(translate("draft", "Create Arc by 3 points"), _cmd_list) self.finish(cont=None) diff --git a/src/Mod/Draft/draftguitools/gui_base_original.py b/src/Mod/Draft/draftguitools/gui_base_original.py index 18c81ebf95..5f73a41213 100644 --- a/src/Mod/Draft/draftguitools/gui_base_original.py +++ b/src/Mod/Draft/draftguitools/gui_base_original.py @@ -33,6 +33,9 @@ of the DraftToolBar, the Snapper, and the working plane. ## \addtogroup draftguitools # @{ + +from PySide import QtCore + import FreeCAD as App import FreeCADGui as Gui import DraftVecUtils @@ -170,6 +173,10 @@ class DraftTool: if self.call: try: self.view.removeEventCallback("SoEvent", self.call) + # Next line fixes https://github.com/FreeCAD/FreeCAD/issues/10469: + QtCore.QCoreApplication.processEvents() + # It seems to work in most cases. If it does not, use this instead: + # gui_utils.end_all_events() except RuntimeError: # the view has been deleted already pass diff --git a/src/Mod/Draft/draftguitools/gui_ellipses.py b/src/Mod/Draft/draftguitools/gui_ellipses.py index 3d16663204..ec78f7f468 100644 --- a/src/Mod/Draft/draftguitools/gui_ellipses.py +++ b/src/Mod/Draft/draftguitools/gui_ellipses.py @@ -123,6 +123,7 @@ class Ellipse(gui_base_original.Creator): 'pl.Base = ' + DraftVecUtils.toString(center), 'ellipse.Placement = pl', 'Draft.autogroup(ellipse)', + 'Draft.select(ellipse)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Ellipse"), _cmd_list) diff --git a/src/Mod/Draft/draftguitools/gui_labels.py b/src/Mod/Draft/draftguitools/gui_labels.py index 71059a6a04..7dcd236d70 100644 --- a/src/Mod/Draft/draftguitools/gui_labels.py +++ b/src/Mod/Draft/draftguitools/gui_labels.py @@ -87,9 +87,9 @@ class Label(gui_base_original.Creator): def finish(self, cont=False): """Finish the command.""" + super().finish() if self.ghost: self.ghost.finalize() - super().finish() def create(self): """Create the actual object.""" diff --git a/src/Mod/Draft/draftguitools/gui_lines.py b/src/Mod/Draft/draftguitools/gui_lines.py index 755a77095c..b69d4abdb3 100644 --- a/src/Mod/Draft/draftguitools/gui_lines.py +++ b/src/Mod/Draft/draftguitools/gui_lines.py @@ -156,6 +156,7 @@ class Line(gui_base_original.Creator): 'line.Y2 = ' + str(p2.y), 'line.Z2 = ' + str(p2.z), 'Draft.autogroup(line)', + 'Draft.select(line)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Line"), _cmd_list) diff --git a/src/Mod/Draft/draftguitools/gui_move.py b/src/Mod/Draft/draftguitools/gui_move.py index a55e700e24..9eca54ca15 100644 --- a/src/Mod/Draft/draftguitools/gui_move.py +++ b/src/Mod/Draft/draftguitools/gui_move.py @@ -52,9 +52,6 @@ True if Draft_rc.__name__ else False class Move(gui_base_original.Modifier): """Gui Command for the Move tool.""" - def __init__(self): - super(Move, self).__init__() - def GetResources(self): """Set icon, menu and tooltip.""" @@ -65,9 +62,9 @@ class Move(gui_base_original.Modifier): def Activated(self): """Execute when the command is called.""" - super(Move, self).Activated(name="Move", - is_subtool=isinstance(App.activeDraftCommand, - SubelementHighlight)) + super().Activated(name="Move", + is_subtool=isinstance(App.activeDraftCommand, + SubelementHighlight)) if not self.ui: return self.ghosts = [] @@ -111,11 +108,11 @@ class Move(gui_base_original.Modifier): Restart (continue) the command if `True`, or if `None` and `ui.continueMode` is `True`. """ + super().finish() for ghost in self.ghosts: ghost.finalize() if cont or (cont is None and self.ui and self.ui.continueMode): todo.ToDo.delayAfter(self.Activated, []) - super(Move, self).finish() def action(self, arg): """Handle the 3D scene events. diff --git a/src/Mod/Draft/draftguitools/gui_points.py b/src/Mod/Draft/draftguitools/gui_points.py index 1347042e57..c7b748f1de 100644 --- a/src/Mod/Draft/draftguitools/gui_points.py +++ b/src/Mod/Draft/draftguitools/gui_points.py @@ -117,6 +117,7 @@ class Point(gui_base_original.Creator): 'point.Y = ' + str(self.point[1]), 'point.Z = ' + str(self.point[2]), 'Draft.autogroup(point)', + 'Draft.select(point)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Point"), _cmd_list) else: @@ -146,6 +147,11 @@ class Point(gui_base_original.Creator): self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) + if self.callbackClick or self.callbackMove: + # Next line fixes https://github.com/FreeCAD/FreeCAD/issues/10469: + gui_utils.end_all_events() + self.callbackClick = None + self.callbackMove = None super().finish() if cont or (cont is None and self.ui and self.ui.continueMode): self.Activated() diff --git a/src/Mod/Draft/draftguitools/gui_polygons.py b/src/Mod/Draft/draftguitools/gui_polygons.py index bf0fc11d8c..536984de01 100644 --- a/src/Mod/Draft/draftguitools/gui_polygons.py +++ b/src/Mod/Draft/draftguitools/gui_polygons.py @@ -227,6 +227,7 @@ class Polygon(gui_base_original.Creator): 'pol.Circumradius = ' + str(self.rad), 'pol.Placement = pl', 'Draft.autogroup(pol)', + 'Draft.select(pol)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Polygon (Part)"), _cmd_list) diff --git a/src/Mod/Draft/draftguitools/gui_rectangles.py b/src/Mod/Draft/draftguitools/gui_rectangles.py index 6685506645..d52bf45d2b 100644 --- a/src/Mod/Draft/draftguitools/gui_rectangles.py +++ b/src/Mod/Draft/draftguitools/gui_rectangles.py @@ -61,9 +61,6 @@ class Rectangle(gui_base_original.Creator): self.refpoint = None self.ui.pointUi(title=translate("draft", "Rectangle"), icon="Draft_Rectangle") self.ui.extUi() - if params.get_param("UsePartPrimitives"): - self.fillstate = self.ui.hasFill.isChecked() - self.ui.hasFill.setChecked(True) self.call = self.view.addEventCallback("SoEvent", self.action) self.rect = trackers.rectangleTracker() _toolmsg(translate("draft", "Pick first point")) @@ -77,11 +74,11 @@ class Rectangle(gui_base_original.Creator): Restart (continue) the command if `True`, or if `None` and `ui.continueMode` is `True`. """ + if self.ui and hasattr(self, "fillstate"): + self.ui.hasFill.setChecked(self.fillstate) + del self.fillstate super().finish() if self.ui: - if hasattr(self, "fillstate"): - self.ui.hasFill.setChecked(self.fillstate) - del self.fillstate self.rect.off() self.rect.finalize() if cont or (cont is None and self.ui and self.ui.continueMode): @@ -124,6 +121,7 @@ class Rectangle(gui_base_original.Creator): 'pl.Base = ' + DraftVecUtils.toString(base), 'plane.Placement = pl', 'Draft.autogroup(plane)', + 'Draft.select(plane)', 'FreeCAD.ActiveDocument.recompute()'] self.commit(translate("draft", "Create Plane"), _cmd_list) diff --git a/src/Mod/Draft/draftguitools/gui_rotate.py b/src/Mod/Draft/draftguitools/gui_rotate.py index 130d1a5f93..5ba46b13fa 100644 --- a/src/Mod/Draft/draftguitools/gui_rotate.py +++ b/src/Mod/Draft/draftguitools/gui_rotate.py @@ -262,15 +262,13 @@ class Rotate(gui_base_original.Modifier): Restart (continue) the command if `True`, or if `None` and `ui.continueMode` is `True`. """ + super().finish() if self.arctrack: self.arctrack.finalize() for ghost in self.ghosts: ghost.finalize() if cont or (cont is None and self.ui and self.ui.continueMode): todo.ToDo.delayAfter(self.Activated, []) - super().finish() - if self.doc: - self.doc.recompute() def rotate(self, is_copy=False): """Perform the rotation of the subelements or the entire object.""" diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index 96cfbb3dfa..fe1d533266 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -50,6 +50,7 @@ import Draft import DraftVecUtils import DraftGeomUtils from draftguitools import gui_trackers as trackers +from draftutils import gui_utils from draftutils import params from draftutils.init_tools import get_draft_snap_commands from draftutils.messages import _wrn @@ -1218,25 +1219,28 @@ class Snapper: self.dim1.off() if self.dim2: self.dim2.off() - if self.grid: - if self.grid.show_always is False: - self.grid.off() if self.holdTracker: self.holdTracker.clear() self.holdTracker.off() self.unconstrain() self.radius = 0 self.setCursor() - if params.get_param("SnapBarShowOnlyDuringCommands"): - toolbar = self.get_snap_toolbar() - if toolbar: - toolbar.hide() self.mask = None self.selectMode = False self.running = False self.holdPoints = [] self.lastObj = [] + if hasattr(App, "activeDraftCommand") and App.activeDraftCommand: + return + if self.grid: + if self.grid.show_always is False: + self.grid.off() + if params.get_param("SnapBarShowOnlyDuringCommands"): + toolbar = self.get_snap_toolbar() + if toolbar: + toolbar.hide() + def setSelectMode(self, mode): """Set the snapper into select mode (hides snapping temporarily).""" @@ -1384,6 +1388,9 @@ class Snapper: self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) + if self.callbackClick or self.callbackMove: + # Next line fixes https://github.com/FreeCAD/FreeCAD/issues/10469: + gui_utils.end_all_events() self.callbackClick = None self.callbackMove = None @@ -1424,6 +1431,9 @@ class Snapper: self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) + if self.callbackClick or self.callbackMove: + # Next line fixes https://github.com/FreeCAD/FreeCAD/issues/10469: + gui_utils.end_all_events() self.callbackClick = None self.callbackMove = None Gui.Snapper.off() @@ -1443,6 +1453,9 @@ class Snapper: self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(), self.callbackClick) if self.callbackMove: self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) + if self.callbackClick or self.callbackMove: + # Next line fixes https://github.com/FreeCAD/FreeCAD/issues/10469: + gui_utils.end_all_events() self.callbackClick = None self.callbackMove = None Gui.Snapper.off() diff --git a/src/Mod/Draft/draftutils/gui_utils.py b/src/Mod/Draft/draftutils/gui_utils.py index 2a4a8a0e77..57c21b66f4 100644 --- a/src/Mod/Draft/draftutils/gui_utils.py +++ b/src/Mod/Draft/draftutils/gui_utils.py @@ -48,6 +48,7 @@ from draftutils.translate import translate if App.GuiUp: import FreeCADGui as Gui from pivy import coin + from PySide import QtCore from PySide import QtGui # from PySide import QtSvg # for load_texture @@ -856,4 +857,22 @@ def get_bbox(obj, debug=False): return App.BoundBox(xmin, ymin, zmin, xmax, ymax, zmax) + +# Code by Chris Hennes (chennes). +# See https://forum.freecadweb.org/viewtopic.php?p=656362#p656362. +# Used to fix https://github.com/FreeCAD/FreeCAD/issues/10469. +def end_all_events(): + class DelayEnder: + def __init__(self): + self.delay_is_done = False + def stop(self): + self.delay_is_done = True + ender = DelayEnder() + timer = QtCore.QTimer() + timer.timeout.connect(ender.stop) + timer.setSingleShot(True) + timer.start(100) # 100ms (50ms is too short) timer guarantees the loop below runs at least that long + while not ender.delay_is_done: + QtCore.QCoreApplication.processEvents(QtCore.QEventLoop.AllEvents) + ## @}