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.
This commit is contained in:
Roy-043
2024-02-04 15:16:49 +01:00
committed by Chris Hennes
parent 4ff2ee43d2
commit 3b3ed05dc8
13 changed files with 73 additions and 27 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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)
## @}