diff --git a/src/Mod/Arch/ArchWindow.py b/src/Mod/Arch/ArchWindow.py index 1ae3abdb99..91bc796c74 100644 --- a/src/Mod/Arch/ArchWindow.py +++ b/src/Mod/Arch/ArchWindow.py @@ -51,7 +51,7 @@ class _CommandWindow: def GetResources(self): return {'Pixmap' : 'Arch_Window', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Window"), - 'Accel': "W, I", + 'Accel': "W, N", 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Window","Creates a window object from scratch or from a selected object (wire, rectangle or sketch)")} def Activated(self): diff --git a/src/Mod/Draft/Draft.py b/src/Mod/Draft/Draft.py index 3627f3338e..0816e14289 100644 --- a/src/Mod/Draft/Draft.py +++ b/src/Mod/Draft/Draft.py @@ -1931,6 +1931,10 @@ class _Wire: "The base object is the wire is formed from 2 objects") obj.addProperty("App::PropertyLink","Tool","Base", "The tool object is the wire is formed from 2 objects") + obj.addProperty("App::PropertyVector","Start","Base", + "The start point of this line") + obj.addProperty("App::PropertyVector","End","Base", + "The end point of this line") obj.Proxy = self obj.Closed = False self.Type = "Wire" @@ -1941,6 +1945,26 @@ class _Wire: def onChanged(self, fp, prop): if prop in ["Points","Closed","Base","Tool"]: self.createGeometry(fp) + if prop == "Points": + if fp.Start != fp.Points[0]: + fp.Start = fp.Points[0] + if fp.End != fp.Points[-1]: + fp.End = fp.Points[-1] + if len(fp.Points) > 2: + fp.setEditorMode('Start',2) + fp.setEditorMode('End',2) + elif prop == "Start": + pts = fp.Points + if pts: + if pts[0] != fp.Start: + pts[0] = fp.Start + fp.Points = pts + elif prop == "End": + pts = fp.Points + if len(pts) > 1: + if pts[-1] != fp.End: + pts[-1] = fp.End + fp.Points = pts def createGeometry(self,fp): plm = fp.Placement diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index fc4e6f1948..114d0078e3 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -533,11 +533,10 @@ class DraftToolBar: self.radiusValue.selectAll() def offUi(self): + todo.delay(FreeCADGui.Control.closeDialog,None) if self.taskmode: self.isTaskOn = False - todo.delay(FreeCADGui.Control.closeDialog,None) self.baseWidget = QtGui.QWidget() - # print "UI turned off" else: self.setTitle(translate("draft", "None")) self.labelx.setText(translate("draft", "X")) @@ -637,6 +636,7 @@ class DraftToolBar: if not self.taskmode: self.labelx.setText(translate("draft", "Pick Object")) self.labelx.show() + self.makeDumbTask() def editUi(self): self.taskUi(translate("draft", "Edit")) @@ -701,6 +701,15 @@ class DraftToolBar: else: self.layout.setDirection(QtGui.QBoxLayout.LeftToRight) + def makeDumbTask(self): + "create a dumb taskdialog to prevent deleting the temp object" + class TaskPanel: + def __init__(self): + pass + def getStandardButtons(self): + return 0 + panel = TaskPanel() + FreeCADGui.Control.showDialog(panel) #--------------------------------------------------------------------------- # Processing functions diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index cbcdb68429..f2f0b3d256 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -38,7 +38,17 @@ class Snapper: and arch module to manage object snapping. It is responsible for finding snap points and displaying snap markers. Usually You only need to invoke it's snap() function, all the rest is taken - care of.""" + care of. + + 3 functions are useful for the scriptwriter: snap(), constrain() + or getPoint() which is an all-in-one combo. + + The indivudual snapToXXX() functions return a snap definition in + the form [real_point,marker_type,visual_point], and are not + meant to be used directly, they are all called when necessary by + the general snap() function. + + """ def __init__(self): self.lastObj = [None,None] @@ -57,6 +67,7 @@ class Snapper: self.extLine = None self.grid = None self.constrainLine = None + self.trackLine = None # the snapmarker has "dot","circle" and "square" available styles self.mk = {'passive':'circle', @@ -98,6 +109,8 @@ class Snapper: self.unconstrain() return point + snaps = [] + # type conversion if needed if isinstance(screenpos,list): screenpos = tuple(screenpos) @@ -141,7 +154,7 @@ class Snapper: info = FreeCADGui.ActiveDocument.ActiveView.getObjectInfo((screenpos[0],screenpos[1])) # checking if parallel to one of the edges of the last objects - point = self.snapToExtensions(point,lastpoint) + point = self.snapToExtensions(point,lastpoint,constrain) if not info: @@ -152,7 +165,6 @@ class Snapper: else: # we have an object to snap to - snaps = [] obj = FreeCAD.ActiveDocument.getObject(info['Object']) if not obj: @@ -213,6 +225,9 @@ class Snapper: self.lastObj[0] = self.lastObj[1] self.lastObj[1] = obj.Name + if not snaps: + return point + # calculating the nearest snap point shortest = 1000000000000000000 origin = Vector(info['x'],info['y'],info['z']) @@ -241,8 +256,22 @@ class Snapper: # return the final point return cstr(winner[2]) - def snapToExtensions(self,point,last): + def snapToExtensions(self,point,last,constrain): "returns a point snapped to extension or parallel line to last object, if any" + + tsnap = self.snapToExtOrtho(last,constrain) + if tsnap: + if (tsnap[0].sub(point)).Length < self.radius: + if self.tracker: + self.tracker.setCoords(tsnap[2]) + self.tracker.setMarker(self.mk[tsnap[1]]) + self.tracker.on() + if self.extLine: + self.extLine.p2(tsnap[2]) + self.extLine.on() + self.setCursor(tsnap[1]) + return tsnap[2] + for o in [self.lastObj[1],self.lastObj[0]]: if o: ob = FreeCAD.ActiveDocument.getObject(o) @@ -333,24 +362,30 @@ class Snapper: def snapToOrtho(self,shape,last,constrain): "returns a list of ortho snap locations" snaps = [] - if constrain != None: + if constrain: if isinstance(shape,Part.Edge): if last: if isinstance(shape.Curve,Part.Line): - p1 = shape.Vertexes[0].Point - p2 = shape.Vertexes[-1].Point - if (constrain == 0): - if ((last.y > p1.y) and (last.y < p2.y) or (last.y > p2.y) and (last.y < p1.y)): - pc = (last.y-p1.y)/(p2.y-p1.y) - cp = (Vector(p1.x+pc*(p2.x-p1.x),p1.y+pc*(p2.y-p1.y),p1.z+pc*(p2.z-p1.z))) - snaps.append([cp,'ortho',cp]) - elif (constrain == 1): - if ((last.x > p1.x) and (last.x < p2.x) or (last.x > p2.x) and (last.x < p1.x)): - pc = (last.x-p1.x)/(p2.x-p1.x) - cp = (Vector(p1.x+pc*(p2.x-p1.x),p1.y+pc*(p2.y-p1.y),p1.z+pc*(p2.z-p1.z))) - snaps.append([cp,'ortho',cp]) + if self.constraintAxis: + tmpEdge = Part.Line(last,last.add(self.constraintAxis)).toShape() + # get the intersection points + pt = fcgeo.findIntersection(tmpEdge,shape,True,True) + if pt: + for p in pt: + snaps.append([p,'ortho',p]) return snaps + def snapToExtOrtho(self,last,constrain): + "returns an ortho X extension snap location" + if constrain and last and self.constraintAxis and self.extLine: + tmpEdge1 = Part.Line(last,last.add(self.constraintAxis)).toShape() + tmpEdge2 = Part.Line(self.extLine.p1(),self.extLine.p2()).toShape() + # get the intersection points + pt = fcgeo.findIntersection(tmpEdge1,tmpEdge2,True,True) + if pt: + return [pt[0],'ortho',pt[0]] + return None + def snapToAngles(self,shape): "returns a list of angle snap locations" snaps = [] @@ -511,316 +546,54 @@ class Snapper: self.affinity = None if self.constrainLine: self.constrainLine.off() - -# deprecated ################################################################## -# last snapped objects, for quick intersection calculation -lastObj = [0,0] + def getPoint(self,last=None,callback=None): + """getPoint([last],[callback]) : gets a 3D point from the screen. You can provide an existing point, + in that case additional snap options and a tracker are available. You can also passa function as + callback, which will get called with the resulting point as argument, when a point is clicked: + + def cb(point): + print "got a 3D point: ",point + FreeCADGui.Snapper.getPoint(callback=cb) + """ + self.pt = None + self.ui = FreeCADGui.draftToolBar + self.view = FreeCADGui.ActiveDocument.ActiveView + + # setting a track line if we got an existing point + if last: + if not self.trackLine: + self.trackLine = DraftTrackers.lineTracker() + self.trackLine.p1(last) + self.trackLine.on() + + def move(event_cb): + event = event_cb.getEvent() + mousepos = event.getPosition() + ctrl = event.wasCtrlDown() + shift = event.wasShiftDown() + self.pt = FreeCADGui.Snapper.snap(mousepos,lastpoint=last,active=ctrl,constrain=shift) + self.ui.displayPoint(self.pt,last,plane=FreeCAD.DraftWorkingPlane,mask=FreeCADGui.Snapper.affinity) + if self.trackLine: + self.trackLine.p2(self.pt) -def snapPoint(target,point,cursor,ctrl=False): - ''' - Snap function used by the Draft tools - - Currently has two modes: passive and active. Pressing CTRL while - clicking puts you in active mode: - - - In passive mode (an open circle appears), your point is - snapped to the nearest point on any underlying geometry. - - - In active mode (ctrl pressed, a filled circle appears), your point - can currently be snapped to the following points: - - Nodes and midpoints of all Part shapes - - Nodes and midpoints of lines/wires - - Centers and quadrant points of circles - - Endpoints of arcs - - Intersection between line, wires segments, arcs and circles - - When constrained (SHIFT pressed), Intersections between - constraining axis and lines/wires - ''' - - def getConstrainedPoint(edge,last,constrain): - "check for constrained snappoint" - p1 = edge.Vertexes[0].Point - p2 = edge.Vertexes[-1].Point - ar = [] - if (constrain == 0): - if ((last.y > p1.y) and (last.y < p2.y) or (last.y > p2.y) and (last.y < p1.y)): - pc = (last.y-p1.y)/(p2.y-p1.y) - cp = (Vector(p1.x+pc*(p2.x-p1.x),p1.y+pc*(p2.y-p1.y),p1.z+pc*(p2.z-p1.z))) - ar.append([cp,1,cp]) # constrainpoint - if (constrain == 1): - if ((last.x > p1.x) and (last.x < p2.x) or (last.x > p2.x) and (last.x < p1.x)): - pc = (last.x-p1.x)/(p2.x-p1.x) - cp = (Vector(p1.x+pc*(p2.x-p1.x),p1.y+pc*(p2.y-p1.y),p1.z+pc*(p2.z-p1.z))) - ar.append([cp,1,cp]) # constrainpoint - return ar - - def getPassivePoint(info): - "returns a passive snap point" - cur = Vector(info['x'],info['y'],info['z']) - return [cur,2,cur] - - def getScreenDist(dist,cursor): - "returns a 3D distance from a screen pixels distance" - p1 = FreeCADGui.ActiveDocument.ActiveView.getPoint(cursor) - p2 = FreeCADGui.ActiveDocument.ActiveView.getPoint((cursor[0]+dist,cursor[1])) - return (p2.sub(p1)).Length - - def getGridSnap(target,point): - "returns a grid snap point if available" - if target.grid: - return target.grid.getClosestNode(point) - return None - - def getPerpendicular(edge,last): - "returns a point on an edge, perpendicular to the given point" - dv = last.sub(edge.Vertexes[0].Point) - nv = fcvec.project(dv,fcgeo.vec(edge)) - np = (edge.Vertexes[0].Point).add(nv) - return np - - # checking if alwaySnap setting is on - extractrl = False - if Draft.getParam("alwaysSnap"): - extractrl = ctrl - ctrl = True - - # setting Radius - radius = getScreenDist(Draft.getParam("snapRange"),cursor) - - # checking if parallel to one of the edges of the last objects - target.snap.off() - target.extsnap.off() - if (len(target.node) > 0): - for o in [lastObj[1],lastObj[0]]: - if o: - ob = target.doc.getObject(o) - if ob: - if ob.isDerivedFrom("Part::Feature"): - edges = ob.Shape.Edges - if len(edges)<10: - for e in edges: - if isinstance(e.Curve,Part.Line): - last = target.node[len(target.node)-1] - de = Part.Line(last,last.add(fcgeo.vec(e))).toShape() - np = getPerpendicular(e,point) - if (np.sub(point)).Length < radius: - target.snap.coords.point.setValue((np.x,np.y,np.z)) - target.snap.setMarker("circle") - target.snap.on() - target.extsnap.p1(e.Vertexes[0].Point) - target.extsnap.p2(np) - target.extsnap.on() - point = np - else: - last = target.node[len(target.node)-1] - de = Part.Line(last,last.add(fcgeo.vec(e))).toShape() - np = getPerpendicular(de,point) - if (np.sub(point)).Length < radius: - target.snap.coords.point.setValue((np.x,np.y,np.z)) - target.snap.setMarker("circle") - target.snap.on() - point = np - - # check if we snapped to something - snapped=target.view.getObjectInfo((cursor[0],cursor[1])) - - if (snapped == None): - # nothing has been snapped, check fro grid snap - gpt = getGridSnap(target,point) - if gpt: - if radius != 0: - dv = point.sub(gpt) - if dv.Length <= radius: - target.snap.coords.point.setValue((gpt.x,gpt.y,gpt.z)) - target.snap.setMarker("point") - target.snap.on() - return gpt - return point - else: - # we have something to snap - obj = target.doc.getObject(snapped['Object']) - if hasattr(obj.ViewObject,"Selectable"): - if not obj.ViewObject.Selectable: - return point - if not ctrl: - # are we in passive snap? - snapArray = [getPassivePoint(snapped)] - else: - snapArray = [] - comp = snapped['Component'] - if obj.isDerivedFrom("Part::Feature"): - if "Edge" in comp: - # get the stored objects to calculate intersections - intedges = [] - if lastObj[0]: - lo = target.doc.getObject(lastObj[0]) - if lo: - if lo.isDerivedFrom("Part::Feature"): - intedges = lo.Shape.Edges - - nr = int(comp[4:])-1 - edge = obj.Shape.Edges[nr] - for v in edge.Vertexes: - snapArray.append([v.Point,0,v.Point]) - if isinstance(edge.Curve,Part.Line): - # the edge is a line - midpoint = fcgeo.findMidpoint(edge) - snapArray.append([midpoint,1,midpoint]) - if (len(target.node) > 0): - last = target.node[len(target.node)-1] - snapArray.extend(getConstrainedPoint(edge,last,target.constrain)) - np = getPerpendicular(edge,last) - snapArray.append([np,1,np]) - - elif isinstance (edge.Curve,Part.Circle): - # the edge is an arc - rad = edge.Curve.Radius - pos = edge.Curve.Center - for i in [0,30,45,60,90,120,135,150,180,210,225,240,270,300,315,330]: - ang = math.radians(i) - cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) - snapArray.append([cur,1,cur]) - for i in [15,37.5,52.5,75,105,127.5,142.5,165,195,217.5,232.5,255,285,307.5,322.5,345]: - ang = math.radians(i) - cur = Vector(math.sin(ang)*rad+pos.x,math.cos(ang)*rad+pos.y,pos.z) - snapArray.append([cur,0,pos]) - - for e in intedges: - # get the intersection points - pt = fcgeo.findIntersection(e,edge) - if pt: - for p in pt: - snapArray.append([p,3,p]) - elif "Vertex" in comp: - # directly snapped to a vertex - p = Vector(snapped['x'],snapped['y'],snapped['z']) - snapArray.append([p,0,p]) - elif comp == '': - # workaround for the new view provider - p = Vector(snapped['x'],snapped['y'],snapped['z']) - snapArray.append([p,2,p]) - else: - snapArray = [getPassivePoint(snapped)] - elif Draft.getType(obj) == "Dimension": - for pt in [obj.Start,obj.End,obj.Dimline]: - snapArray.append([pt,0,pt]) - elif Draft.getType(obj) == "Mesh": - for v in obj.Mesh.Points: - snapArray.append([v.Vector,0,v.Vector]) - if not lastObj[0]: - lastObj[0] = obj.Name - lastObj[1] = obj.Name - if (lastObj[1] != obj.Name): - lastObj[0] = lastObj[1] - lastObj[1] = obj.Name - - # calculating shortest distance - shortest = 1000000000000000000 - spt = Vector(snapped['x'],snapped['y'],snapped['z']) - newpoint = [Vector(0,0,0),0,Vector(0,0,0)] - for pt in snapArray: - if pt[0] == None: print "snapPoint: debug 'i[0]' is 'None'" - di = pt[0].sub(spt) - if di.Length < shortest: - shortest = di.Length - newpoint = pt - if radius != 0: - dv = point.sub(newpoint[2]) - if (not extractrl) and (dv.Length > radius): - newpoint = getPassivePoint(snapped) - target.snap.coords.point.setValue((newpoint[2].x,newpoint[2].y,newpoint[2].z)) - if (newpoint[1] == 1): - target.snap.setMarker("square") - elif (newpoint[1] == 0): - target.snap.setMarker("point") - elif (newpoint[1] == 3): - target.snap.setMarker("square") - else: - target.snap.setMarker("circle") - target.snap.on() - return newpoint[2] - -def constrainPoint (target,pt,mobile=False,sym=False): - ''' - Constrain function used by the Draft tools - On commands that need to enter several points (currently only line/wire), - you can constrain the next point to be picked to the last drawn point by - pressing SHIFT. The vertical or horizontal constraining depends on the - position of your mouse in relation to last point at the moment you press - SHIFT. if mobile=True, mobile behaviour applies. If sym=True, x alway = y - ''' - point = Vector(pt) - if len(target.node) > 0: - last = target.node[-1] - dvec = point.sub(last) - affinity = FreeCAD.DraftWorkingPlane.getClosestAxis(dvec) - if ((target.constrain == None) or mobile): - if affinity == "x": - dv = fcvec.project(dvec,FreeCAD.DraftWorkingPlane.u) - point = last.add(dv) - if sym: - l = dv.Length - if dv.getAngle(FreeCAD.DraftWorkingPlane.u) > 1: - l = -l - point = last.add(FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(l,l,l))) - target.constrain = 0 #x direction - target.ui.xValue.setEnabled(True) - target.ui.yValue.setEnabled(False) - target.ui.zValue.setEnabled(False) - target.ui.xValue.setFocus() - elif affinity == "y": - dv = fcvec.project(dvec,FreeCAD.DraftWorkingPlane.v) - point = last.add(dv) - if sym: - l = dv.Length - if dv.getAngle(FreeCAD.DraftWorkingPlane.v) > 1: - l = -l - point = last.add(FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(l,l,l))) - target.constrain = 1 #y direction - target.ui.xValue.setEnabled(False) - target.ui.yValue.setEnabled(True) - target.ui.zValue.setEnabled(False) - target.ui.yValue.setFocus() - elif affinity == "z": - dv = fcvec.project(dvec,FreeCAD.DraftWorkingPlane.axis) - point = last.add(dv) - if sym: - l = dv.Length - if dv.getAngle(FreeCAD.DraftWorkingPlane.axis) > 1: - l = -l - point = last.add(FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(l,l,l))) - target.constrain = 2 #z direction - target.ui.xValue.setEnabled(False) - target.ui.yValue.setEnabled(False) - target.ui.zValue.setEnabled(True) - target.ui.zValue.setFocus() - else: target.constrain = 3 - elif (target.constrain == 0): - dv = fcvec.project(dvec,FreeCAD.DraftWorkingPlane.u) - point = last.add(dv) - if sym: - l = dv.Length - if dv.getAngle(FreeCAD.DraftWorkingPlane.u) > 1: - l = -l - point = last.add(FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(l,l,l))) - elif (target.constrain == 1): - dv = fcvec.project(dvec,FreeCAD.DraftWorkingPlane.v) - point = last.add(dv) - if sym: - l = dv.Length - if dv.getAngle(FreeCAD.DraftWorkingPlane.u) > 1: - l = -l - point = last.add(FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(l,l,l))) - elif (target.constrain == 2): - dv = fcvec.project(dvec,FreeCAD.DraftWorkingPlane.axis) - point = last.add(dv) - if sym: - l = dv.Length - if dv.getAngle(FreeCAD.DraftWorkingPlane.u) > 1: - l = -l - point = last.add(FreeCAD.DraftWorkingPlane.getGlobalCoords(Vector(l,l,l))) - return point + def click(event_cb): + event = event_cb.getEvent() + if event.getState() == coin.SoMouseButtonEvent.DOWN: + self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) + self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) + FreeCADGui.Snapper.off() + self.ui.offUi() + if self.trackLine: + self.trackLine.off() + if callback: + callback(self.pt) + self.pt = None + # adding 2 callback functions + self.ui.pointUi() + self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),click) + self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) + if not hasattr(FreeCADGui,"Snapper"): FreeCADGui.Snapper = Snapper() diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index ac1610bf49..e9b55d6e1a 100755 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -389,24 +389,11 @@ class Line(Creator): self.obj=self.doc.addObject("Part::Feature",self.featureName) # self.obj.ViewObject.Selectable = False Draft.formatObject(self.obj) - if not Draft.getParam("UiMode"): self.makeDumbTask() self.call = self.view.addEventCallback("SoEvent",self.action) msg(translate("draft", "Pick first point:\n")) - def makeDumbTask(self): - "create a dumb taskdialog to prevent deleting the temp object" - class TaskPanel: - def __init__(self): - pass - def getStandardButtons(self): - return 0 - panel = TaskPanel() - FreeCADGui.Control.showDialog(panel) - def finish(self,closed=False,cont=False): "terminates the operation and closes the poly if asked" - if not Draft.getParam("UiMode"): - FreeCADGui.Control.closeDialog() if self.obj: old = self.obj.Name todo.delay(self.doc.removeObject,old) @@ -1627,6 +1614,12 @@ class Modifier: def __init__(self): self.commitList = [] + + def IsActive(self): + if Draft.getSelection(): + return True + else: + return False def Activated(self,name="None"): if FreeCAD.activeDraftCommand: @@ -1655,12 +1648,6 @@ class Modifier: self.snap = snapTracker() self.extsnap = lineTracker(dotted=True) self.planetrack = PlaneTracker() - - def IsActive(self): - if FreeCADGui.ActiveDocument: - return True - else: - return False def finish(self): self.node = [] diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index da064ffd92..29494d6fb4 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -503,7 +503,10 @@ class wireTracker(Tracker): def update(self,wire): if wire: - self.line.numVertices.setValue(len(wire.Vertexes)) + if self.closed: + self.line.numVertices.setValue(len(wire.Vertexes)+1) + else: + self.line.numVertices.setValue(len(wire.Vertexes)) for i in range(len(wire.Vertexes)): p=wire.Vertexes[i].Point self.coords.point.set1Value(i,[p.x,p.y,p.z]) diff --git a/src/Mod/Drawing/App/FeaturePage.cpp b/src/Mod/Drawing/App/FeaturePage.cpp index e5f33ba65a..684fe28cf8 100644 --- a/src/Mod/Drawing/App/FeaturePage.cpp +++ b/src/Mod/Drawing/App/FeaturePage.cpp @@ -56,6 +56,7 @@ FeaturePage::FeaturePage(void) ADD_PROPERTY_TYPE(PageResult ,(0),group,App::Prop_Output,"Resulting SVG document of that page"); ADD_PROPERTY_TYPE(Template ,(""),group,App::Prop_None ,"Template for the page"); + ADD_PROPERTY_TYPE(EditableTexts,(""),group,App::Prop_None,"Substitution values for the editable strings in the template"); } FeaturePage::~FeaturePage() @@ -74,6 +75,11 @@ void FeaturePage::onChanged(const App::Property* prop) return; } } + if (prop == &Template) { + if (!this->isRestoring()) { + EditableTexts.setValues(getEditableTextsFromTemplate()); + } + } App::DocumentObjectGroup::onChanged(prop); } @@ -103,7 +109,8 @@ App::DocumentObjectExecReturn *FeaturePage::execute(void) // make a temp file for FileIncluded Property string tempName = PageResult.getExchangeTempFile(); - ofstream ofile(tempName.c_str()); + ostringstream ofile; + string tempendl = "--endOfLine--"; while (!file.eof()) { @@ -111,7 +118,7 @@ App::DocumentObjectExecReturn *FeaturePage::execute(void) // check if the marker in the template is found if(line.find("") == string::npos) // if not - write through - ofile << line << endl; + ofile << line << tempendl; else { // get through the children and collect all the views @@ -120,14 +127,42 @@ App::DocumentObjectExecReturn *FeaturePage::execute(void) if ((*It)->getTypeId().isDerivedFrom(Drawing::FeatureView::getClassTypeId())) { Drawing::FeatureView *View = dynamic_cast(*It); ofile << View->ViewResult.getValue(); - ofile << endl << endl << endl; + ofile << tempendl << tempendl << tempendl; } } } } file.close(); - ofile.close(); + + // checking for freecad editable texts + string outfragment(ofile.str()); + if (EditableTexts.getSize() > 0) { + boost::regex e1 ("(.*?)"); + string::const_iterator begin, end; + begin = outfragment.begin(); + end = outfragment.end(); + boost::match_results what; + int count = 0; + + while (boost::regex_search(begin, end, what, e1)) { + if (count < EditableTexts.getSize()) { + // change values of editable texts + boost::regex e2 ("((.*?)()"); + outfragment = boost::regex_replace(outfragment, e2, "$1>"+EditableTexts.getValues()[count]+"$3"); + } + count ++; + begin = what[0].second; + } + } + + // restoring linebreaks and saving the file + boost::regex e3 ("--endOfLine--"); + string fmt = "\\n"; + outfragment = boost::regex_replace(outfragment, e3, fmt); + ofstream outfinal(tempName.c_str()); + outfinal << outfragment; + outfinal.close(); PageResult.setValue(tempName.c_str()); @@ -140,3 +175,39 @@ App::DocumentObjectExecReturn *FeaturePage::execute(void) //} return App::DocumentObject::StdReturn; } + +std::vector FeaturePage::getEditableTextsFromTemplate(void) const { + //getting editable texts from "freecad:editable" attributes in SVG template + + std::vector eds; + + if (Template.getValue() != "") { + Base::FileInfo tfi(Template.getValue()); + if (!tfi.isReadable()) { + // if there is a old absolute template file set use a redirect + tfi.setFile(App::Application::getResourceDir() + "Mod/Drawing/Templates/" + tfi.fileName()); + // try the redirect + if (!tfi.isReadable()) { + return eds; + } + } + string tline, tfrag; + ifstream tfile (tfi.filePath().c_str()); + while (!tfile.eof()) { + getline (tfile,tline); + tfrag += tline; + tfrag += "--endOfLine--"; + } + tfile.close(); + boost::regex e ("(.*?)"); + string::const_iterator tbegin, tend; + tbegin = tfrag.begin(); + tend = tfrag.end(); + boost::match_results twhat; + while (boost::regex_search(tbegin, tend, twhat, e)) { + eds.push_back(twhat[2]); + tbegin = twhat[0].second; + } + } + return eds; +} diff --git a/src/Mod/Drawing/App/FeaturePage.h b/src/Mod/Drawing/App/FeaturePage.h index e430c9e29f..8f03c76d4d 100644 --- a/src/Mod/Drawing/App/FeaturePage.h +++ b/src/Mod/Drawing/App/FeaturePage.h @@ -47,7 +47,7 @@ public: App::PropertyFileIncluded PageResult; App::PropertyFile Template; - + App::PropertyStringList EditableTexts; /** @name methods overide Feature */ //@{ @@ -59,6 +59,7 @@ public: virtual const char* getViewProviderName(void) const { return "DrawingGui::ViewProviderDrawingPage"; } + virtual std::vector getEditableTextsFromTemplate(void) const; protected: void onChanged(const App::Property* prop); @@ -68,5 +69,4 @@ protected: } //namespace Drawing - #endif diff --git a/src/Mod/Drawing/Templates/A3_Landscape.svg b/src/Mod/Drawing/Templates/A3_Landscape.svg index 050070bc6f..4e2cdb854e 100644 --- a/src/Mod/Drawing/Templates/A3_Landscape.svg +++ b/src/Mod/Drawing/Templates/A3_Landscape.svg @@ -1,7 +1,7 @@ + inkscape:output_extension="org.inkscape.output.svg.inkscape"> @@ -512,9 +511,60 @@ id="radialGradient3412" xlink:href="#defitem12" inkscape:collect="always" /> + + + + + + + + + + + + inkscape:zoom="1.7101889" + inkscape:cx="254.10366" + inkscape:cy="146.94782" + inkscape:window-x="0" + inkscape:window-y="20" + inkscape:current-layer="svg2" + showgrid="false" + inkscape:window-maximized="1" /> + + inkscape:label="Layer 1" + id="layer1" + transform="matrix(0.21138442,0,0,0.21138442,371.09182,256.75666)"> - + transform="matrix(0.8506406,0,0,0.8506406,187.82699,-0.1960013)" + id="g3813"> + style="fill:url(#radialGradient3817);fill-opacity:1;fill-rule:evenodd;stroke:#370700;stroke-width:1.91000152;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + d="m -216.13659,7.270763 0,55.5 12.375,0 0,-21.71875 8.75,0 0,-8.5625 -8.75,0 0,-9.241879 21.55514,0 0,-15.945621 -33.93014,-0.03125 z" + id="rect3663" + sodipodi:nodetypes="ccccccccccc" + inkscape:connector-curvature="0" /> - - - - - - - - - - - - - - - - - + style="fill:url(#radialGradient3661);fill-opacity:1;fill-rule:evenodd;stroke:#000137;stroke-width:1.91000152;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" + d="m -161.05088,23.811562 -7.19826,4.129889 -3.17869,-1.103092 -3.03274,-7.750723 -4.77066,0.250699 -2.17602,8.014733 -3.04547,1.45841 -7.59591,-3.322815 -3.20831,3.565187 4.1299,7.198257 -1.12858,3.169376 -7.75073,3.032741 0.27618,4.779962 8.01474,2.176021 1.45841,3.045461 -3.34829,7.586615 3.56518,3.208306 7.19825,-4.129891 3.19487,1.137883 3.00726,7.741419 4.80544,-0.266883 2.15054,-8.024034 3.04547,-1.458412 7.61208,3.357607 3.20831,-3.565187 -4.12989,-7.198256 1.11239,-3.204168 7.74142,-3.00726 -0.24138,-4.796137 -8.02404,-2.150536 -1.45842,-3.045461 3.33212,-7.621406 -3.56517,-3.208305 z m -10.7808,11.804259 1.47765,0.857357 1.28022,1.160735 1.02494,1.385223 0.73729,1.540127 0.43349,1.660242 0.0718,1.701463 -0.24575,1.701021 -0.56084,1.61483 -0.89215,1.493834 -1.12594,1.264037 -1.38523,1.024933 -1.54013,0.737291 -1.66023,0.433483 -1.71077,0.09731 -1.70103,-0.245733 -1.61482,-0.560852 -1.49383,-0.892149 -1.25475,-1.151431 -1.03422,-1.359735 -0.73731,-1.540126 -0.42417,-1.685727 -0.0973,-1.710769 0.24573,-1.701025 0.56086,-1.614826 0.88284,-1.468351 1.13526,-1.28952 1.38522,-1.024934 1.54012,-0.737294 1.68572,-0.424174 1.70147,-0.07182 1.70102,0.245731 1.61483,0.560854 z" + id="path3659" + inkscape:connector-curvature="0" /> - Free - Free - CAD - CAD - - + + AUTHOR NAME + CREATION DATE + SUPERVISOR NAME + CHECK DATE + SCALE + WEIGHT + NUMBER + SHEET + TITLE + SUBTITLE +