Draft: Improve Draft_Edit context menus

This commit is contained in:
Roy-043
2022-09-26 10:03:50 +02:00
parent cbc5cf8ee0
commit fc14567d34
3 changed files with 102 additions and 98 deletions

View File

@@ -285,7 +285,6 @@ class DraftToolBar:
self.uiloader = FreeCADGui.UiLoader()
self.autogroup = None
self.isCenterPlane = False
self.lastMode = None
self.input_fields = {
"xValue":{"value":"x","unit":"Length"},
"yValue":{"value":"y","unit":"Length"},
@@ -1198,34 +1197,8 @@ class DraftToolBar:
self.labelx.show()
self.makeDumbTask(extra, on_close_call)
def editUi(self, mode=None):
self.lastMode=mode
self.taskUi(translate("draft", "Edit"))
self.hideXYZ()
self.numFaces.hide()
self.hasFill.hide()
# self.addButton.show()
# self.delButton.show()
# if mode == 'Wire':
# self.setEditButtons(True)
# self.setBezEditButtons(False)
# elif mode == 'Arc':
# self.addButton.hide()
# self.delButton.hide()
# self.arc3PtButton.show()
# elif mode == 'BezCurve':
# self.sharpButton.show()
# self.tangentButton.show()
# self.symmetricButton.show()
self.closeButton.show()
# self.finishButton.show()
# always start Edit with buttons unchecked
# self.addButton.setChecked(False)
# self.delButton.setChecked(False)
# self.sharpButton.setChecked(False)
# self.tangentButton.setChecked(False)
# self.symmetricButton.setChecked(False)
# self.arc3PtButton.setChecked(False)
def editUi(self):
self.makeDumbTask(on_close_call=self.finish)
def extUi(self):
if Draft.getParam("UsePartPrimitives",False):

View File

@@ -91,29 +91,13 @@ class Edit(gui_base_original.Modifier):
Task panel (Draft Toolbar)
----------
self.ui = Gui.draftToolBar
TODO: since we introduced context menu for interacting
with editTrackers, point 2 should become obsolete,
because not consistent with multi-object editing.
Draft_Edit uses taskpanel in 3 ways:
Draft_Edit uses the taskpanel in 2 ways:
1 - when waiting for user to select an object
calling self.ui.selectUi()
1 - the user can select select an object and close the operation
self.ui.editUi()
2 - when Trackers are displayed and user must click one, a
custom task panel is displayed depending on edited
object:
self.ui.editUi() -> the default one
self.ui.editUi("Wire") -> line and wire editing
self.ui.editUi("BezCurve") -> BezCurve editing
self.ui.editUi("Circle") -> circle editing
self.ui.editUi("Arc") -> arc editing
When Draft_Edit evaluate mouse click, depending if some
ui button have been pressed (.isChecked()), decide if
the action is a startEditing or AddPoint or DelPoint or
change BezCurve Continuity, ecc.
3 - when in editing, lineUi support clicking destination point
2 - when editing, lineUi support clicking destination point
by self.startEditing
self.ui.lineUi()
@@ -123,7 +107,6 @@ class Edit(gui_base_original.Modifier):
using soRayPickAction, it identifies the selected editTracker and
start editing it. Here is where "looo" code was very useful.
Editing preview
---------------
When object editing begins, self.ghost is initiated with the
@@ -234,7 +217,7 @@ class Edit(gui_base_original.Modifier):
param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
self.maxObjects = param.GetInt("DraftEditMaxObjects", 5)
self.pick_radius = param.GetInt("DraftEditPickRadius", 20)
self.alt_edit_mode = 0 # default edit mode for objects
# preview
@@ -300,7 +283,7 @@ class Edit(gui_base_original.Modifier):
self.proceed()
else:
self.ui.selectUi(on_close_call=self.finish)
App.Console.PrintMessage(translate("draft",
App.Console.PrintMessage(translate("draft",
"Select a Draft object to edit")
+ "\n")
self.register_selection_callback()
@@ -357,7 +340,7 @@ class Edit(gui_base_original.Modifier):
if self.edited_objects:
self.deformat_objects_after_editing(self.edited_objects)
super(Edit, self).finish()
if Gui.Snapper.grid:
Gui.Snapper.grid.set()
@@ -448,7 +431,7 @@ class Edit(gui_base_original.Modifier):
mouse button event handler, calls: startEditing, endEditing, addPoint, delPoint
"""
event = event_callback.getEvent()
if (event.getState() == coin.SoMouseButtonEvent.DOWN and
if (event.getState() == coin.SoMouseButtonEvent.DOWN and
event.getButton() == event.BUTTON1
):#left click
if not event.wasAltDown():
@@ -501,7 +484,7 @@ class Edit(gui_base_original.Modifier):
+ ": editing node number "
+ str(node_idx) + "\n")
self.ui.lineUi()
self.ui.lineUi(title=translate("draft", "Edit node"), icon="Draft_Edit")
self.editing = node_idx
self.trackers[obj.Name][node_idx].off()
@@ -538,7 +521,7 @@ class Edit(gui_base_original.Modifier):
self.trackers[obj.Name][nodeIndex].set(v)
self.update(obj, nodeIndex, v)
self.alt_edit_mode = 0
self.ui.editUi(self.ui.lastMode)
self.ui.editUi()
self.node = []
self.editing = None
self.showTrackers()
@@ -651,7 +634,7 @@ class Edit(gui_base_original.Modifier):
self.current_editing_object_gui_tools = self.get_obj_gui_tools(obj)
if self.current_editing_object_gui_tools:
self.ghost = self.current_editing_object_gui_tools.init_preview_object(obj)
def updateGhost(self, obj, node_idx, v):
self.ghost.on()
@@ -719,7 +702,7 @@ class Edit(gui_base_original.Modifier):
# -------------------------------------------------------------------------
# EDIT OBJECT TOOLS
# EDIT OBJECT TOOLS
#
# This section contains the code to retrieve the object points and update them
#
@@ -799,7 +782,7 @@ class Edit(gui_base_original.Modifier):
#to be used for app link support
for selobj in Gui.Selection.getSelectionEx('', 0):
for selobj in Gui.Selection.getSelectionEx('', 0):
for sub in selobj.SubElementNames:
obj = selobj.Object
obj_matrix = selobj.Object.getSubObject(sub, retType=4)
@@ -828,7 +811,7 @@ class Edit(gui_base_original.Modifier):
if obj_gui_tools:
self.objs_formats[obj.Name] = obj_gui_tools.get_object_style(obj)
obj_gui_tools.set_object_editing_style(obj)
def deformat_objects_after_editing(self, objs):
"""Restore objects style during editing mode.
@@ -902,7 +885,7 @@ class Edit(gui_base_original.Modifier):
"""Get edit node from given screen position."""
node = self.sendRay(pos)
return node
def sendRay(self, mouse_pos):
"""Send a ray through the scene and return the nearest entity."""
ray_pick = coin.SoRayPickAction(self.render_manager.getViewportRegion())
@@ -936,7 +919,7 @@ class Edit(gui_base_original.Modifier):
class GuiToolsRepository():
""" This object provide a repository to collect all the specific objects
""" This object provide a repository to collect all the specific objects
editing tools.
"""
def __init__(self):

View File

@@ -106,15 +106,29 @@ class DraftWireGuiTools(GuiTools):
def get_edit_point_context_menu(self, edit_command, obj, node_idx):
return [
("delete point", lambda: self.delete_point(obj, node_idx)),
(translate("draft", "Delete point"), lambda: self.delete_point(obj, node_idx)),
]
def get_edit_obj_context_menu(self, edit_command, obj, position):
return [
("add point", lambda: self.add_point(edit_command, obj, position)),
("reverse wire", lambda: self.reverse_wire(obj)),
(translate("draft", "Add point"), lambda: self.add_point(edit_command, obj, position)),
(self.get_open_close_menu_text(obj), lambda: self.open_close_wire(obj)),
(self.get_reverse_menu_text(obj), lambda: self.reverse_wire(obj)),
]
def get_open_close_menu_text(self, obj):
"""This function is overridden in the DraftBSplineGuiTools class.
"""
if obj.Closed:
return translate("draft", "Open wire")
else:
return translate("draft", "Close wire")
def get_reverse_menu_text(self, obj):
"""This function is overridden in the DraftBSplineGuiTools class.
"""
return translate("draft", "Reverse wire")
def init_preview_object(self, obj):
return trackers.wireTracker(obj.Shape)
@@ -133,7 +147,7 @@ class DraftWireGuiTools(GuiTools):
if not info:
return
if not 'Edge' in info["Component"]:
if not 'Edge' in info["Component"]:
return
edgeIndex = int(info["Component"][4:])
@@ -156,11 +170,10 @@ class DraftWireGuiTools(GuiTools):
obj.Points = newPoints
obj.recompute()
return
def delete_point(self, obj, node_idx):
if len(obj.Points) <= 2:
_msg = translate("draft", "Active object must have more than two points/nodes")
_msg = translate("draft", "Active object must have more than two points/nodes")
App.Console.PrintWarning(_msg + "\n")
return
@@ -170,12 +183,26 @@ class DraftWireGuiTools(GuiTools):
obj.recompute()
def open_close_wire(self, obj):
obj.Closed = not obj.Closed
obj.recompute()
def reverse_wire(self, obj):
obj.Points = reversed(obj.Points)
obj.recompute()
class DraftBSplineGuiTools(DraftWireGuiTools):
def get_open_close_menu_text(self, obj):
if obj.Closed:
return translate("draft", "Open spline")
else:
return translate("draft", "Close spline")
def get_reverse_menu_text(self, obj):
return translate("draft", "Reverse spline")
def init_preview_object(self, obj):
return trackers.bsplineTracker()
@@ -301,7 +328,7 @@ class DraftCircleGuiTools(GuiTools):
p1 = obj.Placement.multVec(self.getArcStart(obj))
p2 = obj.Placement.multVec(self.getArcMid(obj))
p3 = obj.Placement.multVec(self.getArcEnd(obj))
if node_idx == 1: # first point
p1 = v
elif node_idx == 3: # midpoint
@@ -316,7 +343,7 @@ class DraftCircleGuiTools(GuiTools):
p0 = arc.Location
obj.Placement.Base = p0
obj.Radius = arc.Radius
delta = s.Vertexes[0].Point
obj.FirstAngle = -math.degrees(DraftVecUtils.angle(p1.sub(p0)))
delta = s.Vertexes[1].Point
@@ -341,19 +368,19 @@ class DraftCircleGuiTools(GuiTools):
if obj.FirstAngle != obj.LastAngle:
if node_idx == 0: # user is over arc start point
return [
("move arc", lambda: self.handle_move_arc(edit_command, obj, node_idx)),
(translate("draft", "Move arc"), lambda: self.handle_move_arc(edit_command, obj, node_idx)),
]
elif node_idx == 1: # user is over arc start point
return [
("set first angle", lambda: self.handle_set_first_angle(edit_command, obj, node_idx)),
(translate("draft", "Set first angle"), lambda: self.handle_set_first_angle(edit_command, obj, node_idx)),
]
elif node_idx == 2: # user is over arc end point
return [
("set last angle", lambda: self.handle_set_last_angle(edit_command, obj, node_idx)),
(translate("draft", "Set last angle"), lambda: self.handle_set_last_angle(edit_command, obj, node_idx)),
]
elif node_idx == 3: # user is over arc mid point
return [
("set radius", lambda: self.handle_set_radius(edit_command, obj, node_idx)),
(translate("draft", "Set radius"), lambda: self.handle_set_radius(edit_command, obj, node_idx)),
]
def handle_move_arc(self, edit_command, obj, node_idx):
@@ -373,8 +400,12 @@ class DraftCircleGuiTools(GuiTools):
edit_command.startEditing(obj, node_idx)
def get_edit_obj_context_menu(self, edit_command, obj, position):
# Do not show the `Invert arc` option for circles:
if obj.FirstAngle == obj.LastAngle:
return
return [
("invert arc", lambda: self.arcInvert(obj)),
(translate("draft", "Invert arc"), lambda: self.arcInvert(obj)),
]
def init_preview_object(self, obj):
@@ -505,7 +536,7 @@ class DraftPolygonGuiTools(GuiTools):
if obj.DrawMode == 'inscribed':
editpoints.append(obj.Placement.inverse().multVec(obj.Shape.Vertexes[0].Point))
else:
editpoints.append(obj.Placement.inverse().multVec((obj.Shape.Vertexes[0].Point +
editpoints.append(obj.Placement.inverse().multVec((obj.Shape.Vertexes[0].Point +
obj.Shape.Vertexes[1].Point) / 2
))
return editpoints
@@ -560,7 +591,7 @@ class DraftBezCurveGuiTools(GuiTools):
pts = obj.Points
# DNC: check for coincident startpoint/endpoint to auto close the curve
tol = 0.001
if ( ( node_idx == 0 ) and ( (v - pts[-1]).Length < tol) ) or (
if ( ( node_idx == 0 ) and ( (v - pts[-1]).Length < tol) ) or (
node_idx == len(pts) - 1 ) and ( (v - pts[0]).Length < tol):
obj.Closed = True
# DNC: checks if point enter is equal to other, this could cause a OCC problem
@@ -569,7 +600,7 @@ class DraftBezCurveGuiTools(GuiTools):
"coincident points, please try again.")
App.Console.PrintMessage(_err + "\n")
return
pts = self.recomputePointsBezier(obj, pts, node_idx, v, obj.Degree, moveTrackers=False)
if obj.Closed:
@@ -584,17 +615,25 @@ class DraftBezCurveGuiTools(GuiTools):
def get_edit_point_context_menu(self, edit_command, obj, node_idx):
return [
("make sharp", lambda: self.smoothBezPoint(obj, node_idx, 'Sharp')),
("make tangent", lambda: self.smoothBezPoint(obj, node_idx, 'Tangent')),
("make symmetric", lambda: self.smoothBezPoint(obj, node_idx, 'Symmetric')),
("delete point", lambda: self.delete_point(obj, node_idx)),
(translate("draft", "Delete point"), lambda: self.delete_point(obj, node_idx)),
(translate("draft", "Make sharp"), lambda: self.smoothBezPoint(obj, node_idx, "Sharp")),
(translate("draft", "Make tangent"), lambda: self.smoothBezPoint(obj, node_idx, "Tangent")),
(translate("draft", "Make symmetric"), lambda: self.smoothBezPoint(obj, node_idx, "Symmetric")),
]
def get_edit_obj_context_menu(self, edit_command, obj, position):
return [
("add point", lambda: self.add_point(edit_command, obj, position)),
(translate("draft", "Add point"), lambda: self.add_point(edit_command, obj, position)),
(self.get_open_close_menu_text(obj), lambda: self.open_close_wire(obj)),
(translate("draft", "Reverse curve"), lambda: self.reverse_wire(obj)),
]
def get_open_close_menu_text(self, obj):
if obj.Closed:
return translate("draft", "Open curve")
else:
return translate("draft", "Close curve")
def init_preview_object(self, obj):
return trackers.bezcurveTracker()
@@ -602,18 +641,6 @@ class DraftBezCurveGuiTools(GuiTools):
plist = edit_command.globalize_vectors(obj, obj.Points)
pointList = self.recomputePointsBezier(obj,plist,node_idx,v,obj.Degree,moveTrackers=False)
edit_command.ghost.update(pointList, obj.Degree)
def delete_point(self, obj, node_idx):
if len(obj.Points) <= 2:
_msg = translate("draft", "Active object must have more than two points/nodes")
App.Console.PrintWarning(_msg + "\n")
return
pts = obj.Points
pts.pop(node_idx)
obj.Points = pts
obj.Proxy.resetcontinuity(obj)
obj.recompute()
def recomputePointsBezier(self, obj, pts, idx, v,
degree, moveTrackers=False):
@@ -677,7 +704,8 @@ class DraftBezCurveGuiTools(GuiTools):
def smoothBezPoint(self, obj, point, style='Symmetric'):
"called when changing the continuity of a knot"
"""called when changing the continuity of a knot
"""
style2cont = {'Sharp':0,'Tangent':1,'Symmetric':2}
if point is None:
return
@@ -770,7 +798,7 @@ class DraftBezCurveGuiTools(GuiTools):
info, pt = edit_command.get_specific_object_info(obj,pos)
if not info or (pt is None):
return
import Part
pts = obj.Points
@@ -806,4 +834,24 @@ class DraftBezCurveGuiTools(GuiTools):
obj.recompute()
def delete_point(self, obj, node_idx):
if len(obj.Points) <= 2:
_msg = translate("draft", "Active object must have more than two points/nodes")
App.Console.PrintWarning(_msg + "\n")
return
pts = obj.Points
pts.pop(node_idx)
obj.Points = pts
obj.Proxy.resetcontinuity(obj)
obj.recompute()
def open_close_wire(self, obj):
obj.Closed = not obj.Closed
obj.recompute()
def reverse_wire(self, obj):
obj.Points = reversed(obj.Points)
obj.recompute()
## @}