Merge pull request #12443 from Roy-043/Draft-fix-wrong-selection-after-commands-improved

Draft: fix wrong selection after commands (improved)
This commit is contained in:
Roy-043
2024-02-16 11:46:04 +01:00
committed by GitHub
32 changed files with 138 additions and 119 deletions

View File

@@ -240,9 +240,9 @@ def offset(obj, delta, copy=False, bind=False, sym=False, occ=False):
print("unsupported object") # TODO
newobj = obj
if copy and params.get_param("selectBaseObjects"):
gui_utils.select(newobj)
else:
gui_utils.select(obj)
else:
gui_utils.select(newobj)
if delete:
App.ActiveDocument.removeObject(delete)
return newobj

View File

@@ -96,10 +96,11 @@ class Arc(gui_base_original.Creator):
Restart (continue) the command if `True`, or if `None` and
`ui.continueMode` is `True`.
"""
super().finish()
self.end_callbacks(self.call)
if self.ui:
self.linetrack.finalize()
self.arctrack.finalize()
super().finish()
if cont or (cont is None and self.ui and self.ui.continueMode):
self.Activated()
@@ -595,8 +596,8 @@ class Arc_3Points(gui_base.GuiCommandBase):
`ui.continueMode` is `True`.
"""
App.activeDraftCommand = None
super().finish()
self.tracker.finalize()
super().finish()
if cont or (cont is None and Gui.Snapper.ui and Gui.Snapper.ui.continueMode):
self.Activated()

View File

@@ -141,6 +141,15 @@ class DraftTool:
_toolmsg("{}".format(16*"-"))
_toolmsg("GuiCommand: {}".format(self.featureName))
def end_callbacks(self, call):
try:
self.view.removeEventCallback("SoEvent", call)
gui_utils.end_all_events()
except RuntimeError:
# the view has been deleted already
pass
call = None
def finish(self, cont=False):
"""Finish the current command.
@@ -165,22 +174,11 @@ class DraftTool:
if self.ui:
self.ui.offUi()
self.ui.sourceCmd = None
if hasattr(Gui, "Snapper"):
Gui.Snapper.off()
if self.planetrack:
self.planetrack.finalize()
self.wp._restore()
if hasattr(Gui, "Snapper"):
Gui.Snapper.off()
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
self.call = None
if self.commitList:
last_cmd = self.commitList[-1][1][-1]
if last_cmd.find("recompute") >= 0:

View File

@@ -186,9 +186,9 @@ class BezCurve(gui_lines.Line):
closed: bool, optional
Close the curve if `True`.
"""
if self.ui:
if hasattr(self, "bezcurvetrack"):
self.bezcurvetrack.finalize()
self.end_callbacks(self.call)
if self.ui and hasattr(self, "bezcurvetrack"):
self.bezcurvetrack.finalize()
if self.obj:
# remove temporary object, if any
old = self.obj.Name
@@ -433,9 +433,9 @@ class CubicBezCurve(gui_lines.Line):
"""
params.set_param_view("EnableSelection", self.old_EnableSelection)
if self.ui:
if hasattr(self, "bezcurvetrack"):
self.bezcurvetrack.finalize()
self.end_callbacks(self.call)
if self.ui and hasattr(self, "bezcurvetrack"):
self.bezcurvetrack.finalize()
if self.obj:
# remove temporary object, if any
old = self.obj.Name

View File

@@ -34,11 +34,11 @@ import FreeCAD as App
import FreeCADGui as Gui
import Draft
import Draft_rc # include resources, icons, ui files
import draftutils.todo as todo
from draftguitools import gui_base
from draftutils import gui_utils
from draftutils import todo
from draftutils.messages import _log
from draftutils.translate import translate
from draftguitools import gui_base
from drafttaskpanels import task_circulararray
# The module is used to prevent complaints from code checkers (flake8)
@@ -49,7 +49,7 @@ class CircularArray(gui_base.GuiCommandBase):
"""Gui command for the CircularArray tool."""
def __init__(self):
super(CircularArray, self).__init__()
super().__init__()
self.command_name = "Circular array"
self.location = None
self.mouse_event = None
@@ -128,6 +128,7 @@ class CircularArray(gui_base.GuiCommandBase):
self.callback_move)
self.view.removeEventCallbackPivy(self.mouse_event,
self.callback_click)
gui_utils.end_all_events()
if Gui.Control.activeDialog():
Gui.Control.closeDialog()
self.finish()

View File

@@ -60,7 +60,7 @@ class Clone(gui_base_original.Modifier):
"""Gui Command for the Clone tool."""
def __init__(self):
super(Clone, self).__init__()
super().__init__()
self.moveAfterCloning = False
def GetResources(self):
@@ -73,14 +73,13 @@ class Clone(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Clone, self).Activated(name="Clone")
super().Activated(name="Clone")
if not self.ui:
return
if not Gui.Selection.getSelection():
if self.ui:
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to clone"))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to clone"))
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
@@ -114,7 +113,9 @@ class Clone(gui_base_original.Modifier):
def finish(self):
"""Terminate the operation of the tool."""
super(Clone, self).finish()
if self.call is not None:
self.end_callbacks(self.call)
super().finish()
if self.moveAfterCloning:
todo.ToDo.delay(Gui.runCommand, "Draft_Move")

View File

@@ -174,12 +174,13 @@ class Dimension(gui_base_original.Creator):
def finish(self, cont=False):
"""Terminate the operation."""
self.end_callbacks(self.call)
self.cont = None
self.dir = None
super().finish()
if self.ui:
self.dimtrack.finalize()
self.arctrack.finalize()
super().finish()
def angle_dimension_normal(self, edge1, edge2):
rot = App.Rotation(DraftGeomUtils.vec(edge1),

View File

@@ -60,19 +60,20 @@ class Downgrade(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Downgrade, self).Activated(name="Downgrade")
if self.ui:
if not Gui.Selection.getSelection():
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to upgrade"))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
else:
self.proceed()
super().Activated(name="Downgrade")
if not self.ui:
return
if not Gui.Selection.getSelection():
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to upgrade"))
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
def proceed(self):
"""Proceed with execution of the command after selection."""
if self.call is not None:
self.end_callbacks(self.call)
if Gui.Selection.getSelection():
Gui.addModule("Draft")
_cmd = 'Draft.downgrade'

View File

@@ -59,19 +59,20 @@ class Draft2Sketch(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Draft2Sketch, self).Activated(name="Convert Draft/Sketch")
super().Activated(name="Convert Draft/Sketch")
if not self.ui:
return
if not Gui.Selection.getSelection():
if self.ui:
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to convert."))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to convert."))
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
def proceed(self):
"""Proceed with the command if one object was selected."""
if self.call is not None:
self.end_callbacks(self.call)
sel = Gui.Selection.getSelection()
allSketches = True
allDraft = True

View File

@@ -79,10 +79,11 @@ class Ellipse(gui_base_original.Creator):
Restart (continue) the command if `True`, or if `None` and
`ui.continueMode` is `True`.
"""
super().finish(self)
self.end_callbacks(self.call)
if self.ui:
self.rect.off()
self.rect.finalize()
super().finish()
if cont or (cont is None and self.ui and self.ui.continueMode):
self.Activated()

View File

@@ -63,19 +63,19 @@ class Facebinder(gui_base_original.Creator):
def Activated(self):
"""Execute when the command is called."""
super().Activated(name="Facebinder")
if not self.ui:
return
if not Gui.Selection.getSelection():
if self.ui:
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select faces from existing objects"))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select faces from existing objects"))
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
def proceed(self):
"""Proceed when a valid selection has been made."""
if self.call is not None:
self.end_callbacks(self.call)
if Gui.Selection.getSelection():
App.ActiveDocument.openTransaction("Create Facebinder")
Gui.addModule("Draft")

View File

@@ -62,9 +62,7 @@ class Join(gui_base_original.Modifier):
if not Gui.Selection.getSelection():
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to join"))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
@@ -75,6 +73,8 @@ class Join(gui_base_original.Modifier):
visually share a point. This is due to the underlying `joinWires`
method not handling the points correctly.
"""
if self.call is not None:
self.end_callbacks(self.call)
if Gui.Selection.getSelection():
self.print_selection()
Gui.addModule("Draft")

View File

@@ -87,9 +87,10 @@ class Label(gui_base_original.Creator):
def finish(self, cont=False):
"""Finish the command."""
super().finish()
self.end_callbacks(self.call)
if self.ghost:
self.ghost.finalize()
super().finish()
def create(self):
"""Create the actual object."""

View File

@@ -134,6 +134,7 @@ class Line(gui_base_original.Creator):
closed: bool, optional
Close the line if `True`.
"""
self.end_callbacks(self.call)
self.removeTemporaryObject()
if len(self.node) > 1:

View File

@@ -66,7 +66,7 @@ class Mirror(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Mirror, self).Activated(name="Mirror")
super().Activated(name="Mirror")
self.ghost = None
if self.ui:
if not Gui.Selection.getSelection():
@@ -94,9 +94,10 @@ class Mirror(gui_base_original.Modifier):
def finish(self, cont=False):
"""Terminate the operation of the tool."""
self.end_callbacks(self.call)
if self.ghost:
self.ghost.finalize()
super(Mirror, self).finish()
super().finish()
def mirror(self, p1, p2, copy=False):
"""Mirror the real shapes."""

View File

@@ -108,9 +108,10 @@ class Move(gui_base_original.Modifier):
Restart (continue) the command if `True`, or if `None` and
`ui.continueMode` is `True`.
"""
super().finish()
self.end_callbacks(self.call)
for ghost in self.ghosts:
ghost.finalize()
super().finish()
if cont or (cont is None and self.ui and self.ui.continueMode):
todo.ToDo.delayAfter(self.Activated, [])

View File

@@ -264,6 +264,7 @@ class Offset(gui_base_original.Modifier):
def finish(self, cont=False):
"""Finish the offset operation."""
self.end_callbacks(self.call)
if self.running:
if self.linetrack:
self.linetrack.finalize()

View File

@@ -34,11 +34,11 @@ import FreeCAD as App
import FreeCADGui as Gui
import Draft
import Draft_rc # include resources, icons, ui files
import draftutils.todo as todo
from draftguitools import gui_base
from draftutils import gui_utils
from draftutils import todo
from draftutils.messages import _log
from draftutils.translate import translate
from draftguitools import gui_base
from drafttaskpanels import task_orthoarray
# The module is used to prevent complaints from code checkers (flake8)
@@ -49,7 +49,7 @@ class OrthoArray(gui_base.GuiCommandBase):
"""Gui command for the OrthoArray tool."""
def __init__(self):
super(OrthoArray, self).__init__()
super().__init__()
self.command_name = "Orthogonal array"
# self.location = None
self.mouse_event = None
@@ -115,6 +115,7 @@ class OrthoArray(gui_base.GuiCommandBase):
# self.callback_move)
self.view.removeEventCallbackPivy(self.mouse_event,
self.callback_click)
gui_utils.end_all_events()
if Gui.Control.activeDialog():
Gui.Control.closeDialog()
self.finish()

View File

@@ -34,11 +34,11 @@ import FreeCAD as App
import FreeCADGui as Gui
import Draft
import Draft_rc # include resources, icons, ui files
import draftutils.todo as todo
from draftguitools import gui_base
from draftutils import gui_utils
from draftutils import todo
from draftutils.messages import _log
from draftutils.translate import translate
from draftguitools import gui_base
from drafttaskpanels import task_polararray
# The module is used to prevent complaints from code checkers (flake8)
@@ -49,7 +49,7 @@ class PolarArray(gui_base.GuiCommandBase):
"""Gui command for the PolarArray tool."""
def __init__(self):
super(PolarArray, self).__init__()
super().__init__()
self.command_name = "Polar array"
self.location = None
self.mouse_event = None
@@ -128,6 +128,7 @@ class PolarArray(gui_base.GuiCommandBase):
self.callback_move)
self.view.removeEventCallbackPivy(self.mouse_event,
self.callback_click)
gui_utils.end_all_events()
if Gui.Control.activeDialog():
Gui.Control.closeDialog()
self.finish()

View File

@@ -86,10 +86,10 @@ class Polygon(gui_base_original.Creator):
Restart (continue) the command if `True`, or if `None` and
`ui.continueMode` is `True`.
"""
super().finish(self)
self.end_callbacks(self.call)
if self.ui:
self.arctrack.finalize()
self.doc.recompute()
super().finish()
if cont or (cont is None and self.ui and self.ui.continueMode):
self.Activated()

View File

@@ -74,13 +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()
self.end_callbacks(self.call)
if self.ui:
self.rect.off()
self.rect.finalize()
super().finish()
if cont or (cont is None and self.ui and self.ui.continueMode):
self.Activated()

View File

@@ -262,11 +262,12 @@ class Rotate(gui_base_original.Modifier):
Restart (continue) the command if `True`, or if `None` and
`ui.continueMode` is `True`.
"""
super().finish()
self.end_callbacks(self.call)
if self.arctrack:
self.arctrack.finalize()
for ghost in self.ghosts:
ghost.finalize()
super().finish()
if cont or (cont is None and self.ui and self.ui.continueMode):
todo.ToDo.delayAfter(self.Activated, [])

View File

@@ -420,9 +420,10 @@ class Scale(gui_base_original.Modifier):
def finish(self, cont=False):
"""Terminate the operation."""
super().finish()
self.end_callbacks(self.call)
for ghost in self.ghosts:
ghost.finalize()
super().finish()
Gui.addCommand('Draft_Scale', Scale())

View File

@@ -61,19 +61,20 @@ class Shape2DView(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Shape2DView, self).Activated(name="Project 2D view")
super().Activated(name="Project 2D view")
if not self.ui:
return
if not Gui.Selection.getSelection():
if self.ui:
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to project"))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to project"))
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
def proceed(self):
"""Proceed with the command if one object was selected."""
if self.call is not None:
self.end_callbacks(self.call)
faces = []
objs = []
vec = Gui.ActiveDocument.ActiveView.getViewDirection().negative()

View File

@@ -69,7 +69,7 @@ class ShapeString(gui_base_original.Creator):
def Activated(self):
"""Execute when the command is called."""
super(ShapeString, self).Activated(name="ShapeString")
super().Activated(name="ShapeString")
if self.ui:
self.ui.sourceCmd = self
self.task = ShapeStringTaskPanelCmd(self)
@@ -77,6 +77,10 @@ class ShapeString(gui_base_original.Creator):
_toolmsg(translate("draft", "Pick ShapeString location point"))
todo.ToDo.delay(Gui.Control.showDialog, self.task)
def finish(self):
self.end_callbacks(self.call)
super().finish()
Gui.addCommand('Draft_ShapeString', ShapeString())

View File

@@ -155,6 +155,7 @@ class BSpline(gui_lines.Line):
closed: bool, optional
Close the spline if `True`.
"""
self.end_callbacks(self.call)
if self.ui:
self.bsplinetrack.finalize()
if self.obj:

View File

@@ -90,6 +90,7 @@ class Split(gui_base_original.Modifier):
def proceed(self, info):
"""Proceed with execution of the command after click on an edge."""
self.end_callbacks(self.call)
wire = App.ActiveDocument.getObject(info["Object"])
edge_index = int(info["Component"][4:])

View File

@@ -66,7 +66,7 @@ class Stretch(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Stretch, self).Activated(name="Stretch")
super().Activated(name="Stretch")
self.rectracker = None
self.nodetracker = None
if self.ui:
@@ -255,12 +255,13 @@ class Stretch(gui_base_original.Modifier):
def finish(self, cont=False):
"""Terminate the operation of the command. and clean up."""
self.end_callbacks(self.call)
if self.rectracker:
self.rectracker.finalize()
if self.nodetracker:
for n in self.nodetracker:
n.finalize()
super(Stretch, self).finish()
super().finish()
def doStretch(self):
"""Do the actual stretching once the points are selected."""

View File

@@ -66,12 +66,13 @@ class SubelementHighlight(gui_base_original.Modifier):
if self.is_running:
return self.finish()
self.is_running = True
super(SubelementHighlight, self).Activated(name="Subelement highlight")
super().Activated(name="Subelement highlight")
self.get_selection()
def proceed(self):
"""Continue with the command."""
self.remove_view_callback()
if self.call:
self.view.removeEventCallback("SoEvent", self.call)
self.get_editable_objects_from_selection()
if not self.editable_objects:
return self.finish()
@@ -83,9 +84,9 @@ class SubelementHighlight(gui_base_original.Modifier):
Re-initialize by running __init__ again at the end.
"""
super(SubelementHighlight, self).finish()
self.remove_view_callback()
self.end_callbacks(self.call)
self.restore_editable_objects_graphics()
super().finish()
self.__init__()
def action(self, event):
@@ -111,11 +112,6 @@ class SubelementHighlight(gui_base_original.Modifier):
else:
self.proceed()
def remove_view_callback(self):
"""Remove the installed callback if it exists."""
if self.call:
self.view.removeEventCallback("SoEvent", self.call)
def get_editable_objects_from_selection(self):
"""Get editable Draft objects for the selection."""
for obj in Gui.Selection.getSelection():

View File

@@ -62,7 +62,7 @@ class Text(gui_base_original.Creator):
def Activated(self):
"""Execute when the command is called."""
super(Text, self).Activated(name="Text")
super().Activated(name="Text")
if self.ui:
self.text = ''
self.ui.sourceCmd = self
@@ -84,7 +84,8 @@ class Text(gui_base_original.Creator):
Restart (continue) the command if `True`, or if `None` and
`ui.continueMode` is `True`.
"""
super(Text, self).finish(self)
self.end_callbacks(self.call)
super().finish(self)
if cont or (cont is None and self.ui and self.ui.continueMode):
self.Activated()

View File

@@ -81,7 +81,7 @@ class Trimex(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Trimex, self).Activated(name="Trimex")
super().Activated(name="Trimex")
self.edges = []
self.placement = None
self.ghost = []
@@ -545,7 +545,7 @@ class Trimex(gui_base_original.Modifier):
def finish(self, cont=False):
"""Terminate the operation of the Trimex tool."""
super(Trimex, self).finish()
self.end_callbacks(self.call)
self.force = None
if self.ui:
if self.linetrack:
@@ -559,7 +559,8 @@ class Trimex(gui_base_original.Modifier):
self.obj.ViewObject.LineColor = self.color
if self.width:
self.obj.ViewObject.LineWidth = self.width
gui_utils.select(self.obj)
gui_utils.select(self.obj)
super().finish()
def numericRadius(self, dist):
"""Validate the entry fields in the user interface.

View File

@@ -60,19 +60,20 @@ class Upgrade(gui_base_original.Modifier):
def Activated(self):
"""Execute when the command is called."""
super(Upgrade, self).Activated(name="Upgrade")
if self.ui:
if not Gui.Selection.getSelection():
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to upgrade"))
self.call = self.view.addEventCallback(
"SoEvent",
gui_tool_utils.selectObject)
else:
self.proceed()
super().Activated(name="Upgrade")
if not self.ui:
return
if not Gui.Selection.getSelection():
self.ui.selectUi(on_close_call=self.finish)
_msg(translate("draft", "Select an object to upgrade"))
self.call = self.view.addEventCallback("SoEvent", gui_tool_utils.selectObject)
else:
self.proceed()
def proceed(self):
"""Proceed with execution of the command after selection."""
if self.call is not None:
self.end_callbacks(self.call)
if Gui.Selection.getSelection():
Gui.addModule("Draft")
_cmd = 'Draft.upgrade'