From fc14567d3424e19e8a3a7d333e253f46214ca469 Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Mon, 26 Sep 2022 10:03:50 +0200 Subject: [PATCH] Draft: Improve Draft_Edit context menus --- src/Mod/Draft/DraftGui.py | 31 +---- src/Mod/Draft/draftguitools/gui_edit.py | 49 +++---- .../draftguitools/gui_edit_draft_objects.py | 120 ++++++++++++------ 3 files changed, 102 insertions(+), 98 deletions(-) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 4f69c91b77..4d3f542100 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -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): diff --git a/src/Mod/Draft/draftguitools/gui_edit.py b/src/Mod/Draft/draftguitools/gui_edit.py index 8438f69446..3b84fb81d5 100644 --- a/src/Mod/Draft/draftguitools/gui_edit.py +++ b/src/Mod/Draft/draftguitools/gui_edit.py @@ -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): diff --git a/src/Mod/Draft/draftguitools/gui_edit_draft_objects.py b/src/Mod/Draft/draftguitools/gui_edit_draft_objects.py index 1298265078..82a1191c00 100644 --- a/src/Mod/Draft/draftguitools/gui_edit_draft_objects.py +++ b/src/Mod/Draft/draftguitools/gui_edit_draft_objects.py @@ -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() + ## @}