diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 4c12910ac3ee..8076310f3949 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -1893,8 +1893,7 @@ def getXPM(self,iconname,size=16): return str(a) def togglesnap(self): - if hasattr(FreeCADGui,"Snapper"): - FreeCADGui.Snapper.toggle() + FreeCADGui.doCommand('FreeCADGui.runCommand("Draft_Snap_Lock")') def togglenearsnap(self): if hasattr(FreeCADGui,"Snapper"): diff --git a/src/Mod/Draft/draftguitools/gui_snapper.py b/src/Mod/Draft/draftguitools/gui_snapper.py index 37a4a9e211ed..542acf76d876 100644 --- a/src/Mod/Draft/draftguitools/gui_snapper.py +++ b/src/Mod/Draft/draftguitools/gui_snapper.py @@ -39,19 +39,19 @@ from pivy import coin from PySide import QtCore, QtGui -import FreeCAD -import FreeCADGui +import FreeCAD as App +import FreeCADGui as Gui import Draft import DraftVecUtils from FreeCAD import Vector import draftguitools.gui_trackers as trackers +from draftutils.init_tools import get_draft_snap_commands from draftutils.messages import _msg, _wrn __title__ = "FreeCAD Draft Snap tools" __author__ = "Yorik van Havre" __url__ = "https://www.freecadweb.org" - class Snapper: """Classes to manage snapping in Draft and Arch. @@ -117,6 +117,27 @@ def __init__(self): self.callbackMove = None self.snapObjectIndex = 0 + # snap keys, it's important tha they are in this order for + # saving in preferences and for properly restore the toolbar + self.snaps = ['Lock', # 0 + 'Near', # 1 former "passive" snap + 'Extension', # 2 + 'Parallel', # 3 + 'Grid', # 4 + "Endpoint", # 5 + 'Midpoint', # 6 + 'Perpendicular', # 7 + 'Angle', # 8 + 'Center', # 9 + 'Ortho', # 10 + 'Intersection', # 11 + 'Special', # 12 + 'Dimensions', # 13 + 'WorkingPlane' # 14 + ] + + self.init_active_snaps() + # the snapmarker has "dot","circle" and "square" available styles if self.snapStyle: self.mk = coll.OrderedDict([('passive', 'empty'), @@ -159,6 +180,19 @@ def __init__(self): ('intersection', ':/icons/Snap_Intersection.svg'), ('special', ':/icons/Snap_Special.svg')]) + def init_active_snaps(self): + """ + set self.active_snaps according to user prefs + """ + self.active_snaps = [] + param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + snap_modes = param.GetString("snapModes") + i = 0 + for snap in snap_modes: + if bool(int(snap)): + self.active_snaps.append(self.snaps[i]) + i += 1 + def cstr(self, lastpoint, constrain, point): """Return constraints if needed.""" if constrain or self.mask: @@ -197,8 +231,8 @@ def snap(self, screenpos, if not hasattr(self, "toolbar"): self.makeSnapToolBar() - mw = FreeCADGui.getMainWindow() - bt = mw.findChild(QtGui.QToolBar, "Draft Snap") + mw = Gui.getMainWindow() + bt = mw.findChild(QtGui.QToolBar,"Draft Snap") if not bt: mw.addToolBar(self.toolbar) else: @@ -310,7 +344,7 @@ def snapToObject(self, lastpoint, active, constrain, subname = self.snapInfo['SubName'] obj = parent.getSubObject(subname, retType=1) else: - obj = FreeCAD.ActiveDocument.getObject(self.snapInfo['Object']) + obj = App.ActiveDocument.getObject(self.snapInfo['Object']) parent = obj subname = self.snapInfo['Component'] if not obj: @@ -434,9 +468,9 @@ def snapToObject(self, lastpoint, active, constrain, # calculating the nearest snap point shortest = 1000000000000000000 - origin = Vector(self.snapInfo['x'], - self.snapInfo['y'], - self.snapInfo['z']) + origin = App.Vector(self.snapInfo['x'], + self.snapInfo['y'], + self.snapInfo['z']) winner = None fp = point for snap in snaps: @@ -454,7 +488,7 @@ def snapToObject(self, lastpoint, active, constrain, if self.radius: dv = point.sub(winner[2]) if (dv.Length > self.radius): - if (not oldActive) and self.isEnabled("passive"): + if (not oldActive) and self.isEnabled("Near"): winner = self.snapToVertex(self.snapInfo) # setting the cursors @@ -482,8 +516,8 @@ def snapToObject(self, lastpoint, active, constrain, def toWP(self, point): """Project the given point on the working plane, if needed.""" if self.isEnabled("WorkingPlane"): - if hasattr(FreeCAD, "DraftWorkingPlane"): - return FreeCAD.DraftWorkingPlane.projectPoint(point) + if hasattr(App, "DraftWorkingPlane"): + return App.DraftWorkingPlane.projectPoint(point) return point def getApparentPoint(self, x, y): @@ -491,14 +525,14 @@ def getApparentPoint(self, x, y): view = Draft.get3DView() pt = view.getPoint(x, y) if self.mask != "z": - if hasattr(FreeCAD, "DraftWorkingPlane"): + if hasattr(App,"DraftWorkingPlane"): if view.getCameraType() == "Perspective": camera = view.getCameraNode() p = camera.getField("position").getValue() - dv = pt.sub(Vector(p[0], p[1], p[2])) + dv = pt.sub(App.Vector(p[0], p[1], p[2])) else: dv = view.getViewDirection() - return FreeCAD.DraftWorkingPlane.projectPoint(pt, dv) + return App.DraftWorkingPlane.projectPoint(pt, dv) return pt def snapToDim(self, obj): @@ -526,7 +560,7 @@ def snapToExtensions(self, point, last, constrain, eline): self.extLine.on() self.setCursor(tsnap[1]) return tsnap[2], eline - if self.isEnabled("extension"): + if self.isEnabled("Extension"): tsnap = self.snapToExtOrtho(last, constrain, eline) if tsnap: if (tsnap[0].sub(point)).Length < self.radius: @@ -553,10 +587,10 @@ def snapToExtensions(self, point, last, constrain, eline): self.setCursor(tsnap[1]) return tsnap[2], eline - for o in (self.lastObj[1], self.lastObj[0]): - if o and (self.isEnabled('extension') - or self.isEnabled('parallel')): - ob = FreeCAD.ActiveDocument.getObject(o) + for o in [self.lastObj[1], self.lastObj[0]]: + if o and (self.isEnabled('Extension') + or self.isEnabled('Parallel')): + ob = App.ActiveDocument.getObject(o) if ob: if ob.isDerivedFrom("Part::Feature"): edges = ob.Shape.Edges @@ -572,7 +606,7 @@ def snapToExtensions(self, point, last, constrain, eline): np = self.getPerpendicular(e,point) if not DraftGeomUtils.isPtOnEdge(np,e): if (np.sub(point)).Length < self.radius: - if self.isEnabled('extension'): + if self.isEnabled('Extension'): if np != e.Vertexes[0].Point: p0 = e.Vertexes[0].Point if self.tracker and not self.selectMode: @@ -603,7 +637,7 @@ def snapToExtensions(self, point, last, constrain, eline): self.lastExtensions[0] = ne return np,ne else: - if self.isEnabled('parallel'): + if self.isEnabled('Parallel'): if last: ve = DraftGeomUtils.vec(e) if not DraftVecUtils.isNull(ve): @@ -620,7 +654,7 @@ def snapToExtensions(self, point, last, constrain, eline): def snapToCrossExtensions(self, point): """Snap to the intersection of the last 2 extension lines.""" - if self.isEnabled('extension'): + if self.isEnabled('Extension'): if len(self.lastExtensions) == 2: np = DraftGeomUtils.findIntersection(self.lastExtensions[0], self.lastExtensions[1], True, True) if np: @@ -648,19 +682,19 @@ def snapToCrossExtensions(self, point): return p return None - def snapToPolar(self, point, last): + def snapToPolar(self,point,last): """Snap to polar lines from the given point.""" - if self.isEnabled('ortho') and (not self.mask): + if self.isEnabled('Ortho') and (not self.mask): if last: vecs = [] - if hasattr(FreeCAD, "DraftWorkingPlane"): - ax = [FreeCAD.DraftWorkingPlane.u, - FreeCAD.DraftWorkingPlane.v, - FreeCAD.DraftWorkingPlane.axis] + if hasattr(App,"DraftWorkingPlane"): + ax = [App.DraftWorkingPlane.u, + App.DraftWorkingPlane.v, + App.DraftWorkingPlane.axis] else: - ax = [FreeCAD.Vector(1, 0, 0), - FreeCAD.Vector(0, 1, 0), - FreeCAD.Vector(0, 0, 1)] + ax = [App.Vector(1, 0, 0), + App.Vector(0, 1, 0), + App.Vector(0, 0, 1)] for a in self.polarAngles: if a == 90: vecs.extend([ax[0], ax[0].negative()]) @@ -691,7 +725,7 @@ def snapToGrid(self, point): """Return a grid snap point if available.""" if self.grid: if self.grid.Visible: - if self.isEnabled("grid"): + if self.isEnabled("Grid"): np = self.grid.getClosestNode(point) if np: dv = point.sub(np) @@ -707,7 +741,7 @@ def snapToGrid(self, point): def snapToEndpoints(self, shape): """Return a list of endpoints snap locations.""" snaps = [] - if self.isEnabled("endpoint"): + if self.isEnabled("Endpoint"): if hasattr(shape, "Vertexes"): for v in shape.Vertexes: snaps.append([v.Point, 'endpoint', self.toWP(v.Point)]) @@ -725,7 +759,7 @@ def snapToEndpoints(self, shape): def snapToMidpoint(self, shape): """Return a list of midpoints snap locations.""" snaps = [] - if self.isEnabled("midpoint"): + if self.isEnabled("Midpoint"): if isinstance(shape, Part.Edge): mp = DraftGeomUtils.findMidpoint(shape) if mp: @@ -735,7 +769,7 @@ def snapToMidpoint(self, shape): def snapToPerpendicular(self, shape, last): """Return a list of perpendicular snap locations.""" snaps = [] - if self.isEnabled("perpendicular"): + if self.isEnabled("Perpendicular"): if last: if isinstance(shape, Part.Edge): if DraftGeomUtils.geomType(shape) == "Line": @@ -758,7 +792,7 @@ def snapToPerpendicular(self, shape, last): def snapToOrtho(self, shape, last, constrain): """Return a list of ortho snap locations.""" snaps = [] - if self.isEnabled("ortho"): + if self.isEnabled("Ortho"): if constrain: if isinstance(shape, Part.Edge): if last: @@ -774,7 +808,7 @@ def snapToOrtho(self, shape, last, constrain): def snapToExtOrtho(self, last, constrain, eline): """Return an ortho X extension snap location.""" - if self.isEnabled("extension") and self.isEnabled("ortho"): + if self.isEnabled("Extension") and self.isEnabled("Ortho"): if constrain and last and self.constraintAxis and self.extLine: tmpEdge1 = Part.LineSegment(last, last.add(self.constraintAxis)).toShape() tmpEdge2 = Part.LineSegment(self.extLine.p1(), self.extLine.p2()).toShape() @@ -800,15 +834,15 @@ def snapToHold(self, point): """ if not self.holdPoints: return None - if hasattr(FreeCAD, "DraftWorkingPlane"): - u = FreeCAD.DraftWorkingPlane.u - v = FreeCAD.DraftWorkingPlane.v + if hasattr(App, "DraftWorkingPlane"): + u = App.DraftWorkingPlane.u + v = App.DraftWorkingPlane.v else: - u = FreeCAD.Vector(1, 0, 0) - v = FreeCAD.Vector(0, 1, 0) + u = App.Vector(1, 0, 0) + v = App.Vector(0, 1, 0) if len(self.holdPoints) > 1: # first try mid points - if self.isEnabled("midpoint"): + if self.isEnabled("Midpoint"): l = list(self.holdPoints) for p1, p2 in itertools.combinations(l, 2): p3 = p1.add((p2.sub(p1)).multiply(0.5)) @@ -845,7 +879,7 @@ def snapToHold(self, point): def snapToExtPerpendicular(self, last): """Return a perpendicular X extension snap location.""" - if self.isEnabled("extension") and self.isEnabled("perpendicular"): + if self.isEnabled("Extension") and self.isEnabled("Perpendicular"): if last and self.extLine: if self.extLine.p1() != self.extLine.p2(): tmpEdge = Part.LineSegment(self.extLine.p1(), self.extLine.p2()).toShape() @@ -856,7 +890,7 @@ def snapToExtPerpendicular(self, last): def snapToElines(self, e1, e2): """Return a snap at the infinite intersection of the given edges.""" snaps = [] - if self.isEnabled("intersection") and self.isEnabled("extension"): + if self.isEnabled("Intersection") and self.isEnabled("Extension"): if e1 and e2: # get the intersection points pts = DraftGeomUtils.findIntersection(e1, e2, True, True) @@ -868,7 +902,7 @@ def snapToElines(self, e1, e2): def snapToAngles(self, shape): """Return a list of angle snap locations.""" snaps = [] - if self.isEnabled("angle"): + if self.isEnabled("Angle"): rad = shape.Curve.Radius pos = shape.Curve.Center for i in (0, 30, 45, 60, 90, @@ -885,7 +919,7 @@ def snapToAngles(self, shape): def snapToCenter(self, shape): """Return a list of center snap locations.""" snaps = [] - if self.isEnabled("center"): + if self.isEnabled("Center"): pos = shape.Curve.Center c = self.toWP(pos) if hasattr(shape.Curve, "Radius"): @@ -906,7 +940,7 @@ def snapToCenter(self, shape): def snapToFace(self, shape): """Return a face center snap location.""" snaps = [] - if self.isEnabled("center"): + if self.isEnabled("Center"): pos = shape.CenterOfMass c = self.toWP(pos) snaps.append([pos, 'center', c]) @@ -915,10 +949,10 @@ def snapToFace(self, shape): def snapToIntersection(self, shape): """Return a list of intersection snap locations.""" snaps = [] - if self.isEnabled("intersection"): + if self.isEnabled("Intersection"): # get the stored objects to calculate intersections if self.lastObj[0]: - obj = FreeCAD.ActiveDocument.getObject(self.lastObj[0]) + obj = App.ActiveDocument.getObject(self.lastObj[0]) if obj: if obj.isDerivedFrom("Part::Feature") or (Draft.getType(obj) == "Axis"): if (not self.maxEdges) or (len(obj.Shape.Edges) <= self.maxEdges): @@ -947,7 +981,7 @@ def snapToIntersection(self, shape): def snapToPolygon(self, obj): """Return a list of polygon center snap locations.""" snaps = [] - if self.isEnabled("center"): + if self.isEnabled("Center"): c = obj.Placement.Base for edge in obj.Shape.Edges: p1 = edge.Vertexes[0].Point @@ -958,29 +992,16 @@ def snapToPolygon(self, obj): snaps.append([v2, 'center', self.toWP(c)]) return snaps - def snapToVertex(self, info, active=False): - """Return a vertex snap location.""" - p = Vector(info['x'], info['y'], info['z']) - if active: - if self.isEnabled("passive"): - return [p, 'endpoint', self.toWP(p)] - else: - return [] - elif self.isEnabled("passive"): - return [p, 'passive', p] - else: - return [] def snapToSpecials(self, obj, lastpoint=None, eline=None): """Return special snap locations, if any.""" snaps = [] - if self.isEnabled("special"): + if self.isEnabled("Special"): if (Draft.getType(obj) == "Wall"): # special snapping for wall: snap to its base shape if it is linear if obj.Base: if not obj.Base.Shape.Solids: - for v in obj.Base.Shape.Vertexes: snaps.append([v.Point, 'special', self.toWP(v.Point)]) elif (Draft.getType(obj) == "Structure"): @@ -1040,13 +1061,13 @@ def setArchDims(self, p1, p2): def setCursor(self, mode=None): """Set or reset the cursor to the given mode or resets.""" if self.selectMode: - mw = FreeCADGui.getMainWindow() + mw = Gui.getMainWindow() for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget): if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget": w.unsetCursor() self.cursorMode = None elif not mode: - mw = FreeCADGui.getMainWindow() + mw = Gui.getMainWindow() for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget): if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget": w.unsetCursor() @@ -1064,7 +1085,7 @@ def setCursor(self, mode=None): qp.drawPixmap(QtCore.QPoint(16, 8), tp) qp.end() cur = QtGui.QCursor(newicon, 8, 8) - mw = FreeCADGui.getMainWindow() + mw = Gui.getMainWindow() for w in mw.findChild(QtGui.QMdiArea).findChildren(QtGui.QWidget): if w.metaObject().className() == "SIM::Coin3D::Quarter::QuarterWidget": w.setCursor(cur) @@ -1121,7 +1142,7 @@ def setAngle(self, delta=None): """Keep the current angle.""" if delta: self.mask = delta - elif isinstance(self.mask, FreeCAD.Vector): + elif isinstance(self.mask, App.Vector): self.mask = None elif self.trackLine: if self.trackLine.Visible: @@ -1138,15 +1159,15 @@ def constrain(self, point, basepoint=None, axis=None): used as basepoint. """ # without the Draft module fully loaded, no axes system!" - if not hasattr(FreeCAD, "DraftWorkingPlane"): + if not hasattr(App, "DraftWorkingPlane"): return point - point = Vector(point) + point = App.Vector(point) # setup trackers if needed if not self.constrainLine: if self.snapStyle: - self.constrainLine = trackers.lineTracker(scolor=FreeCADGui.draftToolBar.getDefaultColor("snap")) + self.constrainLine = trackers.lineTracker(scolor=Gui.draftToolBar.getDefaultColor("snap")) else: self.constrainLine = trackers.lineTracker(dotted=True) @@ -1162,23 +1183,23 @@ def constrain(self, point, basepoint=None, axis=None): if self.mask: self.affinity = self.mask if not self.affinity: - self.affinity = FreeCAD.DraftWorkingPlane.getClosestAxis(delta) - if isinstance(axis, FreeCAD.Vector): + self.affinity = App.DraftWorkingPlane.getClosestAxis(delta) + if isinstance(axis, App.Vector): self.constraintAxis = axis elif axis == "x": - self.constraintAxis = FreeCAD.DraftWorkingPlane.u + self.constraintAxis = App.DraftWorkingPlane.u elif axis == "y": - self.constraintAxis = FreeCAD.DraftWorkingPlane.v + self.constraintAxis = App.DraftWorkingPlane.v elif axis == "z": - self.constraintAxis = FreeCAD.DraftWorkingPlane.axis + self.constraintAxis = App.DraftWorkingPlane.axis else: if self.affinity == "x": - self.constraintAxis = FreeCAD.DraftWorkingPlane.u + self.constraintAxis = App.DraftWorkingPlane.u elif self.affinity == "y": - self.constraintAxis = FreeCAD.DraftWorkingPlane.v + self.constraintAxis = App.DraftWorkingPlane.v elif self.affinity == "z": - self.constraintAxis = FreeCAD.DraftWorkingPlane.axis - elif isinstance(self.affinity, FreeCAD.Vector): + self.constraintAxis = App.DraftWorkingPlane.axis + elif isinstance(self.affinity, App.Vector): self.constraintAxis = self.affinity else: self.constraintAxis = None @@ -1229,7 +1250,7 @@ def cb(point): if point: print "got a 3D point: ",point - FreeCADGui.Snapper.getPoint(callback=cb) + Gui.Snapper.getPoint(callback=cb) If the callback function accepts more than one argument, it will also receive the last snapped object. Finally, a qt widget @@ -1243,7 +1264,7 @@ def cb(point): self.pt = None self.lastSnappedObject = None self.holdPoints = [] - self.ui = FreeCADGui.draftToolBar + self.ui = Gui.draftToolBar self.view = Draft.get3DView() # remove any previous leftover callbacks @@ -1259,20 +1280,20 @@ def move(event_cb): mousepos = event.getPosition() ctrl = event.wasCtrlDown() shift = event.wasShiftDown() - self.pt = FreeCADGui.Snapper.snap(mousepos, lastpoint=last, - active=ctrl, constrain=shift) - if hasattr(FreeCAD, "DraftWorkingPlane"): + self.pt = Gui.Snapper.snap(mousepos, lastpoint=last, + active=ctrl, constrain=shift) + if hasattr(App, "DraftWorkingPlane"): self.ui.displayPoint(self.pt, last, - plane=FreeCAD.DraftWorkingPlane, - mask=FreeCADGui.Snapper.affinity) + plane = App.DraftWorkingPlane, + mask = App.Snapper.affinity) if movecallback: movecallback(self.pt, self.snapInfo) def getcoords(point, relative=False): """Get the global coordinates from a point.""" self.pt = point - if relative and last and hasattr(FreeCAD, "DraftWorkingPlane"): - v = FreeCAD.DraftWorkingPlane.getGlobalCoords(point) + if relative and last and hasattr(App, "DraftWorkingPlane"): + v = App.DraftWorkingPlane.getGlobalCoords(point) self.pt = last.add(v) accept() @@ -1289,8 +1310,8 @@ def accept(): self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) self.callbackClick = None self.callbackMove = None - obj = FreeCADGui.Snapper.lastSnappedObject - FreeCADGui.Snapper.off() + obj = Gui.Snapper.lastSnappedObject + Gui.Snapper.off() self.ui.offUi() if callback: if len(inspect.getargspec(callback).args) > 1: @@ -1306,7 +1327,7 @@ def cancel(): self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(), self.callbackMove) self.callbackClick = None self.callbackMove = None - FreeCADGui.Snapper.off() + Gui.Snapper.off() self.ui.offUi() if callback: if len(inspect.getargspec(callback).args) > 1: @@ -1332,121 +1353,90 @@ def cancel(): def makeSnapToolBar(self): """Build the Snap toolbar.""" - mw = FreeCADGui.getMainWindow() + mw = Gui.getMainWindow() self.toolbar = QtGui.QToolBar(mw) mw.addToolBar(QtCore.Qt.TopToolBarArea, self.toolbar) self.toolbar.setObjectName("Draft Snap") self.toolbar.setWindowTitle(QtCore.QCoreApplication.translate("Workbench", "Draft Snap")) - self.toolbarButtons = [] - - # grid button - self.gridbutton = QtGui.QAction(mw) - self.gridbutton.setIcon(QtGui.QIcon.fromTheme("Draft_Grid", QtGui.QIcon(":/icons/Draft_Grid.svg"))) - self.gridbutton.setText(QtCore.QCoreApplication.translate("Draft_ToggleGrid", "Grid")) - self.gridbutton.setToolTip(QtCore.QCoreApplication.translate("Draft_ToggleGrid", "Toggles the Draft grid On/Off")) - self.gridbutton.setObjectName("GridButton") - self.gridbutton.setWhatsThis("Draft_ToggleGrid") - QtCore.QObject.connect(self.gridbutton, QtCore.SIGNAL("triggered()"), self.toggleGrid) - self.toolbar.addAction(self.gridbutton) - - # master button - self.masterbutton = QtGui.QAction(mw) - self.masterbutton.setIcon(QtGui.QIcon.fromTheme("Snap_Lock", QtGui.QIcon(":/icons/Snap_Lock.svg"))) - self.masterbutton.setText(QtCore.QCoreApplication.translate("Draft_Snap_Lock", "Lock")) - self.masterbutton.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_Lock", "Toggle On/Off")) - self.masterbutton.setObjectName("SnapButtonMain") - self.masterbutton.setWhatsThis("Draft_ToggleSnap") - self.masterbutton.setCheckable(True) - self.masterbutton.setChecked(True) - QtCore.QObject.connect(self.masterbutton, - QtCore.SIGNAL("toggled(bool)"), self.toggle) - self.toolbar.addAction(self.masterbutton) - for c,i in self.cursors.items(): - if i: - b = QtGui.QAction(mw) - b.setIcon(QtGui.QIcon.fromTheme(i.replace(':/icons/', '').replace('.svg', ''), QtGui.QIcon(i))) - if c == "passive": - b.setText(QtCore.QCoreApplication.translate("Draft_Snap_Near", "Nearest")) - b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_Near", "Nearest")) - else: - b.setText(QtCore.QCoreApplication.translate("Draft_Snap_"+c.capitalize(), c.capitalize())) - b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_"+c.capitalize(), c.capitalize())) - b.setObjectName("SnapButton" + c) - b.setWhatsThis("Draft_" + c.capitalize()) - b.setCheckable(True) - b.setChecked(True) - self.toolbar.addAction(b) - self.toolbarButtons.append(b) - QtCore.QObject.connect(b, QtCore.SIGNAL("toggled(bool)"), - self.saveSnapModes) - - # adding non-snap button - for n in ("Dimensions", "WorkingPlane"): - b = QtGui.QAction(mw) - b.setIcon(QtGui.QIcon.fromTheme("Snap_" + n, QtGui.QIcon(":/icons/Snap_"+n+".svg"))) - b.setText(QtCore.QCoreApplication.translate("Draft_Snap_" + n,n)) - b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap_" + n,n)) - b.setObjectName("SnapButton" + n) - b.setWhatsThis("Draft_" + n) + + snap_gui_commands = get_draft_snap_commands() + self.init_draft_snap_buttons(snap_gui_commands, self.toolbar, "_Button") + self.restore_snap_buttons_state(self.toolbar,"_Button") + + if not Draft.getParam("showSnapBar",True): + self.toolbar.hide() + + def init_draft_snap_buttons(self, commands, context, button_suffix): + """ + Init Draft Snap toolbar buttons. + + Parameters: + commands Snap command list, + use: get_draft_snap_commands(): + context The toolbar or action group the buttons have + to be added to + button_suffix The suffix that have to be applied to the command name + to define the button name + """ + for gc in commands: + # setup toolbar buttons + command = 'Gui.runCommand("' + gc + '")' + b = QtGui.QAction(context) + b.setIcon(QtGui.QIcon(':/icons/' + gc[6:] + '.svg')) + b.setText(QtCore.QCoreApplication.translate("Draft_Snap", "Snap " + gc[11:])) + b.setToolTip(QtCore.QCoreApplication.translate("Draft_Snap", "Snap " + gc[11:])) + b.setObjectName(gc + button_suffix) + b.setWhatsThis("Draft_"+gc[11:].capitalize()) b.setCheckable(True) b.setChecked(True) - self.toolbar.addAction(b) - QtCore.QObject.connect(b, QtCore.SIGNAL("toggled(bool)"), - self.saveSnapModes) - self.toolbarButtons.append(b) + context.addAction(b) + QtCore.QObject.connect(b, + QtCore.SIGNAL("triggered()"), + lambda f=Gui.doCommand, + arg=command:f(arg)) + + for b in context.actions(): + if len(b.statusTip()) == 0: + b.setStatusTip(b.toolTip()) + def restore_snap_buttons_state(self, toolbar, button_suffix): + """ + Restore toolbar button's checked state according to + "snapModes" saved in preferences + """ # set status tip where needed - for b in self.toolbar.actions(): + param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + snap_modes = param.GetString("snapModes") + + for b in toolbar.actions(): if len(b.statusTip()) == 0: b.setStatusTip(b.toolTip()) - # restoring states - t = Draft.getParam("snapModes", "111111111101111") - if t: - c = 0 - for b in [self.masterbutton] + self.toolbarButtons: - if len(t) > c: - state = bool(int(t[c])) - b.setChecked(state) + # restore toolbar buttons state + if snap_modes: + for a in toolbar.findChildren(QtGui.QAction): + snap = a.objectName()[11:].replace(button_suffix,"") + if snap in Gui.Snapper.snaps: + i = Gui.Snapper.snaps.index(snap) + state = bool(int(snap_modes[i])) + a.setChecked(state) if state: - b.setToolTip(b.toolTip() + " (ON)") + a.setToolTip(a.toolTip()+" (ON)") else: - b.setToolTip(b.toolTip() + " (OFF)") - c += 1 - if not Draft.getParam("showSnapBar", True): - self.toolbar.hide() + a.setToolTip(a.toolTip()+" (OFF)") + + def get_snap_toolbar(self): + """retuns snap toolbar object""" + mw = Gui.getMainWindow() + if mw: + toolbar = mw.findChild(QtGui.QToolBar,"Draft Snap") + if toolbar: + return toolbar + return None def toggleGrid(self): - """Run Draft_ToggleGrid.""" - FreeCADGui.runCommand("Draft_ToggleGrid") - - def saveSnapModes(self): - """Save the snap modes for next sessions.""" - t = '' - for b in [self.masterbutton] + self.toolbarButtons: - t += str(int(b.isChecked())) - if b.isChecked(): - b.setToolTip(b.toolTip().replace("OFF", "ON")) - else: - b.setToolTip(b.toolTip().replace("ON", "OFF")) - Draft.setParam("snapModes", t) - - def toggle(self, checked=None): - """Toggle the snap mode.""" - if hasattr(self, "toolbarButtons"): - if checked is None: - self.masterbutton.toggle() - elif checked: - if hasattr(self, "savedButtonStates"): - for i in range(len(self.toolbarButtons)): - self.toolbarButtons[i].setEnabled(True) - self.toolbarButtons[i].setChecked(self.savedButtonStates[i]) - else: - self.savedButtonStates = [] - for i in range(len(self.toolbarButtons)): - self.savedButtonStates.append(self.toolbarButtons[i].isChecked()) - self.toolbarButtons[i].setEnabled(False) - self.saveSnapModes() + "toggle FreeCAD Draft Grid" + Gui.runCommand("Draft_ToggleGrid") def showradius(self): """Show the snap radius indicator.""" @@ -1456,32 +1446,66 @@ def showradius(self): self.radiusTracker.update(self.radius) self.radiusTracker.on() - def isEnabled(self, but): - """Return true if the given button is turned on.""" - for b in self.toolbarButtons: - if str(b.objectName()) == "SnapButton" + but: - return (b.isEnabled() and b.isChecked()) - return False + def isEnabled(self, snap): + "Returns true if the given snap is on" + if "Lock" in self.active_snaps and snap in self.active_snaps: + return True + else: + return False + + def toggle_snap(self, snap, set_to = None): + "Sets the given snap on/off according to the given parameter" + if set_to: # set mode + if set_to is True: + if not snap in self.active_snaps: + self.active_snaps.append(snap) + status = True + elif set_to is False: + if snap in self.active_snaps: + self.active_snaps.remove(snap) + status = False + else: # toggle mode, default + if not snap in self.active_snaps: + self.active_snaps.append(snap) + status = True + elif snap in self.active_snaps: + self.active_snaps.remove(snap) + status = False + self.save_snap_state() + return status + + def save_snap_state(self): + """ + save snap state to user preferences to be restored in next session + """ + param = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + snap_modes = "" + for snap in self.snaps: + if snap in self.active_snaps: + snap_modes += "1" + else: + snap_modes += "0" + param.SetString("snapModes",snap_modes) def show(self): """Show the toolbar and the grid.""" if not hasattr(self, "toolbar"): self.makeSnapToolBar() - mw = FreeCADGui.getMainWindow() - bt = mw.findChild(QtGui.QToolBar, "Draft Snap") + bt = self.get_snap_toolbar() if not bt: + mw = FreeCADGui.getMainWindow() mw.addToolBar(self.toolbar) self.toolbar.setParent(mw) self.toolbar.show() self.toolbar.toggleViewAction().setVisible(True) - if FreeCADGui.ActiveDocument: + if Gui.ActiveDocument: self.setTrackers() - if not FreeCAD.ActiveDocument.Objects: - if FreeCADGui.ActiveDocument.ActiveView: - if FreeCADGui.ActiveDocument.ActiveView.getCameraType() == 'Orthographic': - c = FreeCADGui.ActiveDocument.ActiveView.getCameraNode() + if not App.ActiveDocument.Objects: + if Gui.ActiveDocument.ActiveView: + if Gui.ActiveDocument.ActiveView.getCameraType() == 'Orthographic': + c = Gui.ActiveDocument.ActiveView.getCameraNode() if c.orientation.getValue().getValue() == (0.0, 0.0, 0.0, 1.0): - p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") + p = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft") h = p.GetInt("defaultCameraHeight",0) if h: c.height.setValue(h) @@ -1523,7 +1547,7 @@ def setTrackers(self): self.tracker = trackers.snapTracker() self.trackLine = trackers.lineTracker() if self.snapStyle: - c = FreeCADGui.draftToolBar.getDefaultColor("snap") + c = Gui.draftToolBar.getDefaultColor("snap") self.extLine = trackers.lineTracker(scolor=c) self.extLine2 = trackers.lineTracker(scolor=c) else: diff --git a/src/Mod/Draft/draftguitools/gui_snaps.py b/src/Mod/Draft/draftguitools/gui_snaps.py index 36ca85ffa0d7..75eb99933558 100644 --- a/src/Mod/Draft/draftguitools/gui_snaps.py +++ b/src/Mod/Draft/draftguitools/gui_snaps.py @@ -28,12 +28,23 @@ # \brief Provide the Draft_Snap commands used by the snapping mechanism # in Draft. -from PySide.QtCore import QT_TRANSLATE_NOOP - +import draftguitools.gui_base as gui_base import FreeCADGui as Gui import draftguitools.gui_base as gui_base from draftutils.translate import _tr +from PySide.QtCore import QT_TRANSLATE_NOOP +from draftutils.translate import _tr + + +class Draft_Snap_Lock(gui_base.GuiCommandSimplest): + """GuiCommand for the Draft_Snap_Lock tool. + + Activate or deactivate all snap methods at once. + """ + + def __init__(self): + super().__init__(name=_tr("Main toggle snap")) class Draft_Snap_Lock(gui_base.GuiCommandSimplest): """GuiCommand for the Draft_Snap_Lock tool. @@ -63,6 +74,11 @@ def Activated(self): if hasattr(Gui.Snapper, "masterbutton"): Gui.Snapper.masterbutton.toggle() + if hasattr(Gui, "Snapper"): + if hasattr(Gui.Snapper, "masterbutton"): + Gui.Snapper.masterbutton.toggle() + +Gui.addCommand('Draft_Snap_Lock', Draft_Snap_Lock()) Gui.addCommand('Draft_Snap_Lock', Draft_Snap_Lock()) diff --git a/src/Mod/Draft/draftutils/init_tools.py b/src/Mod/Draft/draftutils/init_tools.py index 49b85cbcf6f2..7335ae2ccdea 100644 --- a/src/Mod/Draft/draftutils/init_tools.py +++ b/src/Mod/Draft/draftutils/init_tools.py @@ -115,15 +115,15 @@ def get_draft_utility_commands(): def get_draft_snap_commands(): """Return the snapping commands list.""" - return ['Draft_Snap_Lock', 'Draft_Snap_Midpoint', - 'Draft_Snap_Perpendicular', - 'Draft_Snap_Grid', 'Draft_Snap_Intersection', - 'Draft_Snap_Parallel', - 'Draft_Snap_Endpoint', 'Draft_Snap_Angle', - 'Draft_Snap_Center', - 'Draft_Snap_Extension', 'Draft_Snap_Near', - 'Draft_Snap_Ortho', 'Draft_Snap_Special', - 'Draft_Snap_Dimensions', 'Draft_Snap_WorkingPlane'] + return ['Draft_Snap_Lock', + 'Draft_Snap_Endpoint', 'Draft_Snap_Midpoint', + 'Draft_Snap_Center', 'Draft_Snap_Angle', + 'Draft_Snap_Intersection', 'Draft_Snap_Perpendicular', + 'Draft_Snap_Extension', 'Draft_Snap_Parallel', + 'Draft_Snap_Special', 'Draft_Snap_Near', + 'Draft_Snap_Ortho', 'Draft_Snap_Grid', + 'Draft_Snap_WorkingPlane', 'Draft_Snap_Dimensions', + ] def init_draft_toolbars(workbench):