Draft: improve context menus

This commit is contained in:
Roy-043
2022-12-07 11:21:06 +01:00
parent e64a2ce675
commit daf6cc5012
12 changed files with 231 additions and 183 deletions

View File

@@ -31,11 +31,13 @@ the same basic behavior."""
## \addtogroup draftviewproviders
# @{
import PySide.QtCore as QtCore
import PySide.QtGui as QtGui
from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD as App
import draftutils.utils as utils
import draftutils.gui_utils as gui_utils
from draftutils.translate import translate
if App.GuiUp:
from pivy import coin
@@ -360,89 +362,114 @@ class ViewProviderDraft(object):
"""
return
def setEdit(self, vobj, mode=0):
"""Enter edit mode of the object.
Override this method to define a custom command to run when entering
the edit mode of the object in the tree view.
It must return `True` to successfully enter edit mode.
If the conditions to edit are not met, it should return `False`,
in which case the edit mode is not started.
By default it runs the `Draft_Edit` GuiCommand.
::
Gui.runCommand('Draft_Edit')
def setEdit(self, vobj, mode):
"""Enter the edit mode of the object.
Parameters
----------
vobj : the view provider of the scripted object.
This is `obj.ViewObject`.
mode : int, optional
It defaults to 0, in which case
it runs the `Draft_Edit` GuiCommand.
It indicates the type of edit in the underlying C++ code.
mode : int
0, 1, 2 or 3. See the `Std_UserEditMode` command.
Returns
-------
bool or None
It is `True` if `mode` is 0, and `Draft_Edit` ran successfully.
None if mode is not zero.
It is `False` otherwise.
`False`: NOT USED HERE.
Do not enter edit mode (unsetEdit is not called).
`True` : Handled edit mode.
Handled modes are 0 and 3, and only for certain objects.
The unsetEdit function should then also return `True`.
`None` : Unhandled edit mode.
Handling is left to Part::FeaturePython code.
The unsetEdit function should then also return `None`.
"""
if mode != 0:
# Act like this function doesn't even exist, so the command falls back to Part (e.g. in the
# case of an unrecognized context menu action)
if mode == 1 or mode == 2:
return None
elif App.GuiUp and "Draft_Edit" in Gui.listCommands(): # remove App.GuiUp guard after splitting every viewprovider
tp = utils.get_type(vobj.Object)
if tp in ("Wire", "Circle", "Ellipse", "Rectangle", "Polygon",
"BSpline", "BezCurve"): # Facebinder and ShapeString objects have their own setEdit.
if not "Draft_Edit" in Gui.listCommands():
self.wb_before_edit = Gui.activeWorkbench()
Gui.activateWorkbench("DraftWorkbench")
Gui.runCommand("Draft_Edit")
return True
else:
App.Console.PrintWarning(QT_TRANSLATE_NOOP("draft",
"Please load the Draft Workbench to enable editing this object"))
return False
def unsetEdit(self, vobj, mode=0):
if tp in ("Fillet", "Point", "Shape2DView"):
Gui.runCommand("Std_TransformManip")
return True
return None
def unsetEdit(self, vobj, mode):
"""Terminate the edit mode of the object.
Override this method to define a custom command to run when
terminating the edit mode of the object in the tree view.
It should return `True` to indicate that the method already
cleaned up everything and there is no need to call
the `usetEdit` method of the base class.
It should return `False` to indicate that cleanup
is still required, so the `unsetEdit` method of the base class
is invoked to do the rest.
By default it runs the `finish` method of the active
Draft GuiCommand, and closes the task panel.
::
App.activeDraftCommand.finish()
Gui.Control.closeDialog()
Parameters
----------
vobj : the view provider of the scripted object.
This is `obj.ViewObject`.
mode : int, optional
It defaults to 0.
It indicates the type of edit in the underlying C++ code.
Returns
-------
bool
This method always returns `False` so it passes
control to the base class to finish the edit mode.
See setEdit.
"""
if mode != 0:
return False
if App.activeDraftCommand:
App.activeDraftCommand.finish()
if App.GuiUp: # remove guard after splitting every viewprovider
if mode == 1 or mode == 2:
return None
tp = utils.get_type(vobj.Object)
if tp in ("Wire", "Circle", "Ellipse", "Rectangle", "Polygon",
"BSpline", "BezCurve"): # Facebinder and ShapeString objects have their own setEdit.
if hasattr(App, "activeDraftCommand") and App.activeDraftCommand:
App.activeDraftCommand.finish()
Gui.Control.closeDialog()
return False
if hasattr(self, "wb_before_edit"):
Gui.activateWorkbench(self.wb_before_edit.name())
delattr(self, "wb_before_edit")
return True
if tp in ("Fillet", "Point", "Shape2DView"):
return True
return None
def setupContextMenu(self, vobj, menu):
tp = utils.get_type(self.Object)
if tp in ("Wire", "Circle", "Ellipse", "Rectangle", "Polygon",
"BSpline", "BezCurve", "Facebinder", "ShapeString"):
action_edit = QtGui.QAction(translate("draft", "Edit"),
menu)
QtCore.QObject.connect(action_edit,
QtCore.SIGNAL("triggered()"),
self.edit)
menu.addAction(action_edit)
if tp == "Wire":
action_flatten = QtGui.QAction(translate("draft", "Flatten"),
menu)
QtCore.QObject.connect(action_flatten,
QtCore.SIGNAL("triggered()"),
self.flatten) # The flatten function is defined in view_wire.py.
menu.addAction(action_flatten)
# The default Part::FeaturePython context menu contains a `Set colors`
# option. This option makes no sense for objects without a face or that
# can only have a single face. In those cases we override this menu and
# have to add our own `Transform` item.
# To override the default menu this function must return `True`.
if tp in ("Wire", "Circle", "Ellipse", "Rectangle", "Polygon",
"BSpline","BezCurve", "Fillet", "Point", "Shape2DView"):
action_transform = QtGui.QAction(Gui.getIcon("Std_TransformManip.svg"),
translate("Command", "Transform"), # Context `Command` instead of `draft`.
menu)
QtCore.QObject.connect(action_transform,
QtCore.SIGNAL("triggered()"),
self.transform)
menu.addAction(action_transform)
return True
def edit(self):
Gui.ActiveDocument.setEdit(self.Object, 0)
def transform(self):
Gui.ActiveDocument.setEdit(self.Object, 1)
def getIcon(self):
"""Return the path to the icon used by the view provider.
@@ -461,16 +488,15 @@ class ViewProviderDraft(object):
str
`':/icons/Draft_Draft.svg'`
"""
if hasattr(self.Object,"Proxy") and hasattr(self.Object.Proxy,"Type"):
tp = self.Object.Proxy.Type
if tp in ('Line', 'Wire', 'Polyline'):
return ":/icons/Draft_N-Linear.svg"
elif tp in ('Rectangle', 'Polygon'):
return ":/icons/Draft_N-Polygon.svg"
elif tp in ('Circle', 'Ellipse', 'BSpline', 'BezCurve', 'Fillet'):
return ":/icons/Draft_N-Curve.svg"
elif tp in ("ShapeString"):
return ":/icons/Draft_ShapeString_tree.svg"
tp = utils.get_type(self.Object)
if tp in ("Line", "Wire", "Polyline"):
return ":/icons/Draft_N-Linear.svg"
if tp in ("Rectangle", "Polygon"):
return ":/icons/Draft_N-Polygon.svg"
if tp in ("Circle", "Ellipse", "BSpline", "BezCurve", "Fillet"):
return ":/icons/Draft_N-Curve.svg"
if tp in ("ShapeString"):
return ":/icons/Draft_ShapeString_tree.svg"
if hasattr(self.Object,"AutoUpdate") and not self.Object.AutoUpdate:
import TechDrawGui
return ":/icons/TechDraw_TreePageUnsync.svg"
@@ -513,6 +539,8 @@ class ViewProviderDraftAlt(ViewProviderDraft):
"""A view provider that doesn't absorb its base object in the tree view.
The `claimChildren` method is overridden to return an empty list.
Only used by the `Shape2DView` object.
"""
def __init__(self, vobj):
@@ -531,6 +559,8 @@ class ViewProviderDraftPart(ViewProviderDraftAlt):
"""A view provider that displays a Part icon instead of a Draft icon.
The `getIcon` method is overridden to provide `Part_3D_object.svg`.
Only used by the `Block` object.
"""
def __init__(self, vobj):
@@ -539,6 +569,12 @@ class ViewProviderDraftPart(ViewProviderDraftAlt):
def getIcon(self):
return ":/icons/Part_3D_object.svg"
def setEdit(self, vobj, mode):
return None
def unsetEdit(self, vobj, mode):
return None
# Alias for compatibility with v0.18 and earlier
_ViewProviderDraftPart = ViewProviderDraftPart

View File

@@ -39,9 +39,6 @@ class ViewProviderBezCurve(ViewProviderWire):
def __init__(self, vobj):
super(ViewProviderBezCurve, self).__init__(vobj)
def setupContextMenu(self, vobj, menu):
return
# Alias for compatibility with v0.18 and earlier
_ViewProviderBezCurve = ViewProviderBezCurve

View File

@@ -39,9 +39,6 @@ class ViewProviderBSpline(ViewProviderWire):
def __init__(self, vobj):
super(ViewProviderBSpline, self).__init__(vobj)
def setupContextMenu(self, vobj, menu):
return
# Alias for compatibility with v0.18 and earlier
_ViewProviderBSpline = ViewProviderBSpline

View File

@@ -300,10 +300,6 @@ class ViewProviderDimensionBase(ViewProviderDraftAnnotation):
"""Execute when a view property is changed."""
super(ViewProviderDimensionBase, self).onChanged(vobj, prop)
def doubleClicked(self, vobj):
"""Execute when double clicking the icon in the tree view."""
self.setEdit(vobj)
def getDisplayModes(self, vobj):
"""Return the display modes that this viewprovider supports."""
return ["2D", "3D"]

View File

@@ -42,12 +42,16 @@ Its edit mode launches the `Draft_Edit` command.
import json
from PySide.QtCore import QT_TRANSLATE_NOOP
import PySide.QtCore as QtCore
import PySide.QtGui as QtGui
import FreeCAD as App
import FreeCADGui as Gui
import draftutils.utils as utils
from draftutils.messages import _msg
from draftutils.translate import translate
if App.GuiUp:
import FreeCADGui as Gui
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
@@ -193,27 +197,55 @@ class ViewProviderDraftAnnotation(object):
"""Execute when the object is created or recomputed."""
return
def setEdit(self, vobj, mode=0):
def setEdit(self, vobj, mode):
"""Execute the code when entering the specific edit mode.
Currently only mode 0 works.
See view_base.py.
"""
if mode == 0:
Gui.runCommand("Draft_Edit")
return True
return False
if mode != 0:
return None
def unsetEdit(self, vobj, mode=0):
if utils.get_type(vobj.Object) in ("AngularDimension", "Label"):
return False # Required, else edit mode is entered.
if not "Draft_Edit" in Gui.listCommands():
self.wb_before_edit = Gui.activeWorkbench()
Gui.activateWorkbench("DraftWorkbench")
Gui.runCommand("Draft_Edit")
return True
def unsetEdit(self, vobj, mode):
"""Execute the code when leaving the specific edit mode.
Currently only mode 0 works.
It runs the finish method of the currently active command, and close
the task panel if any.
See view_base.py.
"""
if App.activeDraftCommand:
if mode != 0:
return None
if hasattr(App, "activeDraftCommand") and App.activeDraftCommand:
App.activeDraftCommand.finish()
Gui.Control.closeDialog()
return False
if hasattr(self, "wb_before_edit"):
Gui.activateWorkbench(self.wb_before_edit.name())
delattr(self, "wb_before_edit")
return True
def doubleClicked(self, vobj):
self.edit()
def setupContextMenu(self, vobj, menu):
if utils.get_type(self.Object) in ("AngularDimension", "Label"):
return
action_edit = QtGui.QAction(translate("draft", "Edit"),
menu)
QtCore.QObject.connect(action_edit,
QtCore.SIGNAL("triggered()"),
self.edit)
menu.addAction(action_edit)
def edit(self):
Gui.ActiveDocument.setEdit(self.Object, 0)
def getIcon(self):
"""Return the path to the icon used by the view provider."""

View File

@@ -39,8 +39,5 @@ class ViewProviderFillet(ViewProviderWire):
def __init__(self, vobj):
super(ViewProviderFillet, self).__init__(vobj)
def setupContextMenu(self, vobj, menu):
return
## @}

View File

@@ -49,6 +49,11 @@ class ViewProviderDraftHatch:
return None
def attach(self, vobj):
self.Object = vobj.Object
return
def setEdit(self, vobj, mode):
# EditMode 1 and 2 are handled by the Part::FeaturePython code.
# EditMode 3 (Color) does not make sense for hatches (which do not
@@ -74,16 +79,26 @@ class ViewProviderDraftHatch:
return True
def setupContextMenu(self, vobj, menu):
action1 = QtGui.QAction(Gui.getIcon("Std_TransformManip.svg"),
translate("Command", "Transform"), # Context `Command` instead of `draft`.
menu)
QtCore.QObject.connect(action1,
action_edit = QtGui.QAction(translate("draft", "Edit"),
menu)
QtCore.QObject.connect(action_edit,
QtCore.SIGNAL("triggered()"),
self.edit)
menu.addAction(action_edit)
action_transform = QtGui.QAction(Gui.getIcon("Std_TransformManip.svg"),
translate("Command", "Transform"), # Context `Command` instead of `draft`.
menu)
QtCore.QObject.connect(action_transform,
QtCore.SIGNAL("triggered()"),
self.transform)
menu.addAction(action1)
menu.addAction(action_transform)
return True # Removes `Transform` and `Set colors` from the default
# Part::FeaturePython context menu.
# Part::FeaturePython context menu. See view_base.py.
def edit(self):
Gui.ActiveDocument.setEdit(self.Object, 0)
def transform(self):
Gui.runCommand("Std_TransformManip", 0)
Gui.ActiveDocument.setEdit(self.Object, 1)

View File

@@ -284,6 +284,7 @@ class ViewProviderLabel(ViewProviderDraftAnnotation):
self.onChanged(vobj, "LineWidth")
self.onChanged(vobj, "ArrowSize")
self.onChanged(vobj, "Line")
self.Object = vobj.Object
def getDisplayModes(self, vobj):
"""Return the display modes that this viewprovider supports."""

View File

@@ -458,31 +458,31 @@ class ViewProviderLayer:
def setupContextMenu(self, vobj, menu):
"""Set up actions to perform in the context menu."""
action1 = QtGui.QAction(QtGui.QIcon(":/icons/button_right.svg"),
translate("draft", "Activate this layer"),
menu)
action1.triggered.connect(self.activate)
menu.addAction(action1)
action_activate = QtGui.QAction(QtGui.QIcon(":/icons/button_right.svg"),
translate("draft", "Activate this layer"),
menu)
action_activate.triggered.connect(self.activate)
menu.addAction(action_activate)
action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectGroup.svg"),
translate("draft", "Select layer contents"),
menu)
action2.triggered.connect(self.select_contents)
menu.addAction(action2)
action_select = QtGui.QAction(QtGui.QIcon(":/icons/Draft_SelectGroup.svg"),
translate("draft", "Select layer contents"),
menu)
action_select.triggered.connect(self.select_contents)
menu.addAction(action_select)
def activate(self):
"""Activate the selected layer, it becomes the Autogroup."""
if hasattr(self, "Object"):
Gui.Selection.clearSelection()
Gui.Selection.addSelection(self.Object)
Gui.runCommand("Draft_AutoGroup")
Gui.Selection.clearSelection()
Gui.Selection.addSelection(self.Object)
if not "Draft_AutoGroup" in Gui.listCommands():
Gui.activateWorkbench("DraftWorkbench")
Gui.runCommand("Draft_AutoGroup")
def select_contents(self):
"""Select the contents of the layer."""
if hasattr(self, "Object"):
Gui.Selection.clearSelection()
for layer_obj in self.Object.Group:
Gui.Selection.addSelection(layer_obj)
Gui.Selection.clearSelection()
for layer_obj in self.Object.Group:
Gui.Selection.addSelection(layer_obj)
class ViewProviderLayerContainer:
@@ -502,22 +502,20 @@ class ViewProviderLayerContainer:
def setupContextMenu(self, vobj, menu):
"""Set up actions to perform in the context menu."""
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Layer.svg"),
translate("draft", "Merge layer duplicates"),
menu)
action1.triggered.connect(self.merge_by_name)
menu.addAction(action1)
action2 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_NewLayer.svg"),
translate("draft", "Add new layer"),
menu)
action2.triggered.connect(self.add_layer)
menu.addAction(action2)
action_merge = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Layer.svg"),
translate("draft", "Merge layer duplicates"),
menu)
action_merge.triggered.connect(self.merge_by_name)
menu.addAction(action_merge)
action_add = QtGui.QAction(QtGui.QIcon(":/icons/Draft_NewLayer.svg"),
translate("draft", "Add new layer"),
menu)
action_add.triggered.connect(self.add_layer)
menu.addAction(action_add)
def merge_by_name(self):
"""Merge the layers that have the same base label."""
if not hasattr(self, "Object") or not hasattr(self.Object, "Group"):
return
doc = App.ActiveDocument
doc.openTransaction(translate("draft", "Merge layer duplicates"))

View File

@@ -42,11 +42,11 @@ class ViewProviderShapeString(ViewProviderDraft):
if mode != 0:
return None
self.wb_before_edit = Gui.activeWorkbench()
Gui.activateWorkbench("DraftWorkbench")
if not "Draft_Edit" in Gui.listCommands(): # Using Draft_Edit to detect if the Draft, Arch or BIM WB has been loaded.
self.wb_before_edit = Gui.activeWorkbench()
Gui.activateWorkbench("DraftWorkbench")
self.task = ShapeStringTaskPanelEdit(vobj)
Gui.Control.showDialog(self.task)
return True
def unsetEdit(self, vobj, mode):
@@ -54,6 +54,7 @@ class ViewProviderShapeString(ViewProviderDraft):
return None
self.task.finish()
Gui.activateWorkbench(self.wb_before_edit.name())
if hasattr(self, "wb_before_edit"):
Gui.activateWorkbench(self.wb_before_edit.name())
delattr(self, "wb_before_edit")
return True

View File

@@ -30,10 +30,13 @@
## \addtogroup draftviewproviders
# @{
import pivy.coin as coin
import sys
from PySide.QtCore import QT_TRANSLATE_NOOP
import FreeCAD as App
import FreeCADGui as Gui
import draftutils.utils as utils
from draftutils.translate import translate
from draftviewproviders.view_draft_annotation \
import ViewProviderDraftAnnotation
@@ -218,32 +221,18 @@ class ViewProviderText(ViewProviderDraftAnnotation):
self.text2d.spacing = vobj.LineSpacing
self.text3d.spacing = vobj.LineSpacing
def setEdit(self,vobj,mode):
import FreeCADGui
if not hasattr(FreeCADGui, "draftToolBar"):
def edit(self):
if not hasattr(Gui, "draftToolBar"):
import DraftGui
self.text = ""
FreeCADGui.draftToolBar.sourceCmd = self
FreeCADGui.draftToolBar.taskUi()
FreeCADGui.draftToolBar.textUi()
FreeCADGui.draftToolBar.textValue.setPlainText("\n".join(vobj.Object.Text))
FreeCADGui.draftToolBar.textValue.setFocus()
def unsetEdit(self,vobj=None,mode=0):
import FreeCADGui
FreeCADGui.Control.closeDialog()
return True
def doubleClicked(self,vobj):
self.setEdit(vobj,None)
Gui.draftToolBar.sourceCmd = self
Gui.draftToolBar.taskUi(title=translate("draft", "Text"), icon="Draft_Text")
Gui.draftToolBar.textUi()
Gui.draftToolBar.continueCmd.hide()
Gui.draftToolBar.textValue.setPlainText("\n".join(self.Object.Text))
Gui.draftToolBar.textValue.setFocus()
def createObject(self):
import FreeCAD
import FreeCADGui
if hasattr(self,"Object"):
txt = self.text
if not txt:
@@ -255,15 +244,13 @@ class ViewProviderText(ViewProviderDraftAnnotation):
t_list = ['"' + l + '"' for l in txt]
list_as_text = ", ".join(t_list)
string = '[' + list_as_text + ']'
FreeCADGui.doCommand("FreeCAD.ActiveDocument."+self.Object.Name+".Text = "+string)
FreeCAD.ActiveDocument.recompute()
Gui.doCommand("FreeCAD.ActiveDocument." + self.Object.Name + ".Text = " + string)
App.ActiveDocument.recompute()
self.finish()
def finish(self,args=None):
import FreeCADGui
FreeCADGui.draftToolBar.sourceCmd = None
FreeCADGui.draftToolBar.offUi()
def finish(self, cont=False):
Gui.draftToolBar.sourceCmd = None
Gui.draftToolBar.offUi()
# Alias for compatibility with v0.18 and earlier

View File

@@ -148,15 +148,6 @@ class ViewProviderWire(ViewProviderDraft):
return [self.Object.Base,self.Object.Tool]
return []
def setupContextMenu(self, vobj, menu):
action1 = QtGui.QAction(QtGui.QIcon(":/icons/Draft_Edit.svg"),
translate("draft", "Flatten"),
menu)
QtCore.QObject.connect(action1,
QtCore.SIGNAL("triggered()"),
self.flatten)
menu.addAction(action1)
def flatten(self): # Only to be used for Draft_Wires.
if not hasattr(self, "Object"):
return