From 8d01d70038928512c297970b61ec7a30aa183b1f Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 2 Feb 2012 09:37:47 -0200 Subject: [PATCH 1/7] More improvements to the Arch module + Draft snap can now pass the object being snapped to + Handle when wall is based on a closed wire + Handle when wall is based on a self-intersecting wire --- src/Mod/Arch/ArchWall.py | 26 ++++++++++++++++---------- src/Mod/Draft/DraftGui.py | 11 ++++++----- src/Mod/Draft/DraftSnap.py | 32 ++++++++++++++++++++++---------- src/Mod/Draft/DraftTools.py | 2 +- src/Mod/Draft/draftlibs/fcgeo.py | 16 +++++++++++++--- 5 files changed, 58 insertions(+), 29 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 316ea0bba..d03a91241 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -98,17 +98,14 @@ class _CommandWall: import DraftTrackers self.points = [] self.tracker = DraftTrackers.boxTracker() - FreeCADGui.Snapper.getPoint(callback=self.getPoint) + FreeCADGui.Snapper.getPoint(callback=self.getPoint,extradlg=TaskArchWall()) - def getPoint(self,point): + def getPoint(self,point,obj): "this function is called by the snapper when it has a 3D point" - pos = FreeCADGui.ActiveDocument.ActiveView.getCursorPos() - exi = FreeCADGui.ActiveDocument.ActiveView.getObjectInfo(pos) - if exi: - exi = FreeCAD.ActiveDocument.getObject(exi['Object']) - if Draft.getType(exi) == "Wall": - if not exi in self.existing: - self.existing.append(exi) + if obj: + if Draft.getType(obj) == "Wall": + if not obj in self.existing: + self.existing.append(obj) if point == None: self.tracker.finalize() return @@ -119,6 +116,8 @@ class _CommandWall: elif len(self.points) == 2: import Part l = Part.Line(self.points[0],self.points[1]) + self.tracker.finalize() + FreeCAD.ActiveDocument.openTransaction("Wall") if not self.existing: s = FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace") s.addGeometry(l) @@ -126,7 +125,7 @@ class _CommandWall: else: w = joinWalls(self.existing) w.Base.addGeometry(l) - self.tracker.finalize() + FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() def update(self,point): @@ -182,6 +181,8 @@ class _Wall(ArchComponent.Component): dvec = fcvec.neg(dvec) w2 = fcgeo.offsetWire(wire,dvec) sh = fcgeo.bind(w1,w2) + # fixing self-intersections + sh.fix(0.1,0,1) if height: norm = Vector(normal).multiply(height) sh = sh.extrude(norm) @@ -258,4 +259,9 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent): def getIcon(self): return ":/icons/Arch_Wall_Tree.svg" +class TaskArchWall: + def __init__(self): + from PyQt4 import QtGui + self.form = QtGui.QWidget() + FreeCADGui.addCommand('Arch_Wall',_CommandWall()) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index d6e215914..8b223c2fa 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -136,7 +136,7 @@ class DraftLineEdit(QtGui.QLineEdit): QtGui.QLineEdit.keyPressEvent(self, event) class DraftTaskPanel: - def __init__(self,widget): + def __init__(self,widget,extradlg=None): self.form = widget def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Cancel) @@ -463,7 +463,7 @@ class DraftToolBar: # Interface modes #--------------------------------------------------------------------------- - def taskUi(self,title): + def taskUi(self,title,extradlg=None): if self.taskmode: self.isTaskOn = True todo.delay(FreeCADGui.Control.closeDialog,None) @@ -472,7 +472,7 @@ class DraftToolBar: self.layout = QtGui.QVBoxLayout(self.baseWidget) self.setupToolBar(task=True) self.retranslateUi(self.baseWidget) - self.panel = DraftTaskPanel(self.baseWidget) + self.panel = DraftTaskPanel(self.baseWidget,extradlg) todo.delay(FreeCADGui.Control.showDialog,self.panel) else: self.setTitle(title) @@ -510,9 +510,9 @@ class DraftToolBar: self.labelx.setText(translate("draft", "Center X")) self.continueCmd.show() - def pointUi(self,title=translate("draft","Point"),cancel=None): + def pointUi(self,title=translate("draft","Point"),cancel=None,extradlg=None): if cancel: self.cancel = cancel - self.taskUi(title) + self.taskUi(title,extradlg) self.xValue.setEnabled(True) self.yValue.setEnabled(True) self.labelx.setText(translate("draft", "X")) @@ -536,6 +536,7 @@ class DraftToolBar: def offUi(self): todo.delay(FreeCADGui.Control.closeDialog,None) + self.cancel = None if self.taskmode: self.isTaskOn = False self.baseWidget = QtGui.QWidget() diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 87b8f45f6..7742926a4 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -68,6 +68,7 @@ class Snapper: self.grid = None self.constrainLine = None self.trackLine = None + self.lastSnappedObject = None # the snapmarker has "dot","circle" and "square" available styles self.mk = {'passive':'circle', @@ -175,6 +176,8 @@ class Snapper: obj = FreeCAD.ActiveDocument.getObject(info['Object']) if not obj: return cstr(point) + + self.lastSnappedObject = obj if hasattr(obj.ViewObject,"Selectable"): if not obj.ViewObject.Selectable: @@ -531,6 +534,7 @@ class Snapper: for v in self.views: v.unsetCursor() self.views = [] + self.cursorMode = None else: if mode != self.cursorMode: if not self.views: @@ -559,11 +563,9 @@ class Snapper: self.extLine.off() if self.grid: self.grid.off() - if self.constrainLine: - self.constrainLine.off() + self.unconstrain() self.radius = 0 self.setCursor() - self.cursorMode = None def constrain(self,point,basepoint=None,axis=None): '''constrain(point,basepoint=None,axis=None: Returns a @@ -627,11 +629,12 @@ class Snapper: if self.constrainLine: self.constrainLine.off() - def getPoint(self,last=None,callback=None,movecallback=None): + def getPoint(self,last=None,callback=None,movecallback=None,extradlg=None): - """getPoint([last],[callback],[movecallback]) : 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 pass a function as callback, which will get called + """getPoint([last],[callback],[movecallback],[extradlg]) : 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 pass a function as callback, which will get called with the resulting point as argument, when a point is clicked, and optionally another callback which gets called when the mouse is moved. @@ -642,7 +645,12 @@ class Snapper: def cb(point): if point: print "got a 3D point: ",point - FreeCADGui.Snapper.getPoint(callback=cb)""" + FreeCADGui.Snapper.getPoint(callback=cb) + + If the callback function accepts more than one argument, it will also receive + the last snapped object.Finally, a task dialog can be passed as extradlg.""" + + import inspect self.pt = None self.ui = FreeCADGui.draftToolBar @@ -673,12 +681,16 @@ class Snapper: if event.getState() == coin.SoMouseButtonEvent.DOWN: self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) + obj = FreeCADGui.Snapper.lastSnappedObject FreeCADGui.Snapper.off() self.ui.offUi() if self.trackLine: self.trackLine.off() if callback: - callback(self.pt) + if len(inspect.getargspec(callback).args) > 2: + callback(self.pt,obj) + else: + callback(self.pt) self.pt = None def cancel(): @@ -692,7 +704,7 @@ class Snapper: callback(None) # adding 2 callback functions - self.ui.pointUi(cancel=cancel) + self.ui.pointUi(cancel=cancel,extradlg=extradlg) self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),click) self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) diff --git a/src/Mod/Draft/DraftTools.py b/src/Mod/Draft/DraftTools.py index 65bbd96c4..a74f4d733 100644 --- a/src/Mod/Draft/DraftTools.py +++ b/src/Mod/Draft/DraftTools.py @@ -476,7 +476,7 @@ class Line(Creator): if self.isWire: msg(translate("draft", "Pick next point, or (F)inish or (C)lose:\n")) else: - currentshape = self.obj.Shape + currentshape = self.obj.Shape.copy() last = self.node[len(self.node)-2] newseg = Part.Line(last,point).toShape() newshape=currentshape.fuse(newseg) diff --git a/src/Mod/Draft/draftlibs/fcgeo.py b/src/Mod/Draft/draftlibs/fcgeo.py index 275f9a0de..a2844af07 100755 --- a/src/Mod/Draft/draftlibs/fcgeo.py +++ b/src/Mod/Draft/draftlibs/fcgeo.py @@ -959,9 +959,19 @@ def getTangent(edge,frompoint=None): def bind(w1,w2): '''bind(wire1,wire2): binds 2 wires by their endpoints and returns a face''' - w3 = Part.Line(w1.Vertexes[0].Point,w2.Vertexes[0].Point).toShape() - w4 = Part.Line(w1.Vertexes[-1].Point,w2.Vertexes[-1].Point).toShape() - return Part.Face(Part.Wire(w1.Edges+[w3]+w2.Edges+[w4])) + if w1.isClosed() and w2.isClosed(): + d1 = w1.BoundBox.DiagonalLength + d2 = w2.BoundBox.DiagonalLength + if d1 > d2: + #w2.reverse() + return Part.Face([w1,w2]) + else: + #w1.reverse() + return Part.Face([w2,w1]) + else: + w3 = Part.Line(w1.Vertexes[0].Point,w2.Vertexes[0].Point).toShape() + w4 = Part.Line(w1.Vertexes[-1].Point,w2.Vertexes[-1].Point).toShape() + return Part.Face(Part.Wire(w1.Edges+[w3]+w2.Edges+[w4])) def cleanFaces(shape): "removes inner edges from coplanar faces" From 26602b2aa3d25d8766fc329b16f231fb667034aa Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 2 Feb 2012 17:53:26 -0200 Subject: [PATCH 2/7] Fixed numeric input in Arch Walls coordinates --- src/Mod/Arch/ArchWall.py | 2 +- src/Mod/Draft/DraftGui.py | 57 ++++++++++++++++++++++++++++++++------ src/Mod/Draft/DraftSnap.py | 37 +++++++++++++++---------- 3 files changed, 72 insertions(+), 24 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index d03a91241..780c70ca3 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -98,7 +98,7 @@ class _CommandWall: import DraftTrackers self.points = [] self.tracker = DraftTrackers.boxTracker() - FreeCADGui.Snapper.getPoint(callback=self.getPoint,extradlg=TaskArchWall()) + FreeCADGui.Snapper.getPoint(callback=self.getPoint) def getPoint(self,point,obj): "this function is called by the snapper when it has a 3D point" diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 8b223c2fa..81f654afd 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -136,7 +136,7 @@ class DraftLineEdit(QtGui.QLineEdit): QtGui.QLineEdit.keyPressEvent(self, event) class DraftTaskPanel: - def __init__(self,widget,extradlg=None): + def __init__(self,widget): self.form = widget def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Cancel) @@ -155,6 +155,7 @@ class DraftToolBar: self.tray = None self.sourceCmd = None self.cancel = None + self.pointcallback = None self.taskmode = Draft.getParam("UiMode") self.paramcolor = Draft.getParam("color")>>8 self.color = QtGui.QColor(self.paramcolor) @@ -171,7 +172,7 @@ class DraftToolBar: self.fillmode = Draft.getParam("fillmode") if self.taskmode: - # only a dummy widget, since widgets are created on demand + # add only a dummy widget, since widgets are created on demand self.baseWidget = QtGui.QWidget() else: # create the draft Toolbar @@ -250,6 +251,12 @@ class DraftToolBar: if hide: chk.hide() layout.addWidget(chk) return chk + + def _combo (self,name,layout,hide=True): + cb = QtGui.QComboBox(self.baseWidget) + cb.setObjectName(name) + if hide: cb.hide() + layout.addWidget(cb) def setupToolBar(self,task=False): "sets the draft toolbar up" @@ -311,6 +318,21 @@ class DraftToolBar: self.resetPlaneButton = self._pushbutton("none", self.layout) self.isCopy = self._checkbox("isCopy",self.layout,checked=False) + # options buttons for other workbenches + + op1 = QtGui.QHBoxLayout() + self.layout.addLayout(op1) + self.labelop1 = self._label("labelop1", op1) + self.valueop1 = self._lineedit("valueop1", op1) + op2 = QtGui.QHBoxLayout() + self.layout.addLayout(op2) + self.labelop2 = self._label("labelop2", op2) + self.valueop2 = self._lineedit("valueop2", op2) + op3 = QtGui.QHBoxLayout() + self.layout.addLayout(op3) + self.labelop3 = self._label("labelop3", op3) + self.valueop3 = self._combo("valueop3", op3) + # spacer if not self.taskmode: spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, @@ -463,7 +485,7 @@ class DraftToolBar: # Interface modes #--------------------------------------------------------------------------- - def taskUi(self,title,extradlg=None): + def taskUi(self,title,): if self.taskmode: self.isTaskOn = True todo.delay(FreeCADGui.Control.closeDialog,None) @@ -472,7 +494,7 @@ class DraftToolBar: self.layout = QtGui.QVBoxLayout(self.baseWidget) self.setupToolBar(task=True) self.retranslateUi(self.baseWidget) - self.panel = DraftTaskPanel(self.baseWidget,extradlg) + self.panel = DraftTaskPanel(self.baseWidget) todo.delay(FreeCADGui.Control.showDialog,self.panel) else: self.setTitle(title) @@ -510,9 +532,10 @@ class DraftToolBar: self.labelx.setText(translate("draft", "Center X")) self.continueCmd.show() - def pointUi(self,title=translate("draft","Point"),cancel=None,extradlg=None): + def pointUi(self,title=translate("draft","Point"),cancel=None,extra=None,getcoords=None,rel=False): if cancel: self.cancel = cancel - self.taskUi(title,extradlg) + if getcoords: self.pointcallback = getcoords + self.taskUi(title) self.xValue.setEnabled(True) self.yValue.setEnabled(True) self.labelx.setText(translate("draft", "X")) @@ -522,9 +545,14 @@ class DraftToolBar: self.xValue.show() self.yValue.show() self.zValue.show() + if rel: self.isRelative.show() + if extra: self.extraUi(extra) self.xValue.setFocus() self.xValue.selectAll() + def extraUi(self): + pass + def offsetUi(self): self.taskUi(translate("draft","Offset")) self.radiusUi() @@ -537,6 +565,8 @@ class DraftToolBar: def offUi(self): todo.delay(FreeCADGui.Control.closeDialog,None) self.cancel = None + self.sourceCmd = None + self.pointcallback = None if self.taskmode: self.isTaskOn = False self.baseWidget = QtGui.QWidget() @@ -571,7 +601,13 @@ class DraftToolBar: self.textValue.hide() self.continueCmd.hide() self.occOffset.hide() - + self.labelop1.hide() + self.valueop1.hide() + self.labelop2.hide() + self.valueop2.hide() + self.labelop3.hide() + self.valueop3.hide() + def trimUi(self,title=translate("draft","Trim")): self.taskUi(title) self.radiusUi() @@ -793,7 +829,7 @@ class DraftToolBar: def validatePoint(self): "function for checking and sending numbers entered manually" - if self.sourceCmd != None: + if self.sourceCmd or self.pointcallback: if (self.labelRadius.isVisible()): try: rad=float(self.radiusValue.text()) @@ -831,7 +867,10 @@ class DraftToolBar: numx = v.x numy = v.y numz = v.z - self.sourceCmd.numericInput(numx,numy,numz) + if self.pointcallback: + self.pointcallback(FreeCAD.Vector(numx,numy,numz),self.isRelative.isChecked()) + else: + self.sourceCmd.numericInput(numx,numy,numz) def finish(self): "finish button action" diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 7742926a4..6535312a5 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -675,23 +675,32 @@ class Snapper: if movecallback: movecallback(self.pt) + def getcoords(point,relative=False): + self.pt = point + if relative and last: + self.pt = last.add(point) + accept() + def click(event_cb): event = event_cb.getEvent() if event.getButton() == 1: if event.getState() == coin.SoMouseButtonEvent.DOWN: - self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) - self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) - obj = FreeCADGui.Snapper.lastSnappedObject - FreeCADGui.Snapper.off() - self.ui.offUi() - if self.trackLine: - self.trackLine.off() - if callback: - if len(inspect.getargspec(callback).args) > 2: - callback(self.pt,obj) - else: - callback(self.pt) - self.pt = None + accept() + + def accept(): + self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) + self.view.removeEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),self.callbackMove) + obj = FreeCADGui.Snapper.lastSnappedObject + FreeCADGui.Snapper.off() + self.ui.offUi() + if self.trackLine: + self.trackLine.off() + if callback: + if len(inspect.getargspec(callback).args) > 2: + callback(self.pt,obj) + else: + callback(self.pt) + self.pt = None def cancel(): self.view.removeEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),self.callbackClick) @@ -704,7 +713,7 @@ class Snapper: callback(None) # adding 2 callback functions - self.ui.pointUi(cancel=cancel,extradlg=extradlg) + self.ui.pointUi(cancel=cancel,getcoords=getcoords,rel=bool(last)) self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),click) self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) From 1af6a3c2b1412330c51d0124d8a5062ea1c0bff6 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Thu, 2 Feb 2012 18:01:17 -0200 Subject: [PATCH 3/7] Bugfixes in Draft Snap --- src/Mod/Arch/ArchWall.py | 2 +- src/Mod/Draft/DraftGui.py | 32 ++++++++++++++++---------------- src/Mod/Draft/DraftSnap.py | 3 ++- 3 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 780c70ca3..8bc238b09 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -100,7 +100,7 @@ class _CommandWall: self.tracker = DraftTrackers.boxTracker() FreeCADGui.Snapper.getPoint(callback=self.getPoint) - def getPoint(self,point,obj): + def getPoint(self,point=None,obj=None): "this function is called by the snapper when it has a 3D point" if obj: if Draft.getType(obj) == "Wall": diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 81f654afd..706d4d54a 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -852,24 +852,24 @@ class DraftToolBar: except ValueError: pass else: - if self.isRelative.isVisible() and self.isRelative.isChecked(): - if self.sourceCmd.node: - if self.sourceCmd.featureName == "Rectangle": - last = self.sourceCmd.node[0] - else: - last = self.sourceCmd.node[-1] - numx = last.x + numx - numy = last.y + numy - numz = last.z + numz - if FreeCAD.DraftWorkingPlane: - v = FreeCAD.Vector(numx,numy,numz) - v = FreeCAD.DraftWorkingPlane.getGlobalCoords(v) - numx = v.x - numy = v.y - numz = v.z if self.pointcallback: - self.pointcallback(FreeCAD.Vector(numx,numy,numz),self.isRelative.isChecked()) + self.pointcallback(FreeCAD.Vector(numx,numy,numz),(self.isRelative.isVisible() and self.isRelative.isChecked())) else: + if self.isRelative.isVisible() and self.isRelative.isChecked(): + if self.sourceCmd.node: + if self.sourceCmd.featureName == "Rectangle": + last = self.sourceCmd.node[0] + else: + last = self.sourceCmd.node[-1] + numx = last.x + numx + numy = last.y + numy + numz = last.z + numz + if FreeCAD.DraftWorkingPlane: + v = FreeCAD.Vector(numx,numy,numz) + v = FreeCAD.DraftWorkingPlane.getGlobalCoords(v) + numx = v.x + numy = v.y + numz = v.z self.sourceCmd.numericInput(numx,numy,numz) def finish(self): diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 6535312a5..1022043b0 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -678,7 +678,8 @@ class Snapper: def getcoords(point,relative=False): self.pt = point if relative and last: - self.pt = last.add(point) + v = FreeCAD.DraftWorkingPlane.getGlobalCoords(point) + self.pt = last.add(v) accept() def click(event_cb): From 7b88ef317e97c782bb0a6b7f540fa3b64c787de8 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 4 Feb 2012 13:17:53 -0200 Subject: [PATCH 4/7] Allowed TaskDialogPython to display several taskboxes The "form" attribute of Python TaskDialogs can now be either a PyQt widget or a list of PyQt widgets. --- src/Gui/TaskView/TaskDialogPython.cpp | 39 ++++++++++++++++----------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/Gui/TaskView/TaskDialogPython.cpp b/src/Gui/TaskView/TaskDialogPython.cpp index 9d432c4e1..fbdb964d8 100644 --- a/src/Gui/TaskView/TaskDialogPython.cpp +++ b/src/Gui/TaskView/TaskDialogPython.cpp @@ -278,21 +278,30 @@ TaskDialogPython::TaskDialogPython(const Py::Object& o) : dlg(o) } } else if (dlg.hasAttr(std::string("form"))) { - Py::Object widget(dlg.getAttr(std::string("form"))); - Py::Module mainmod(PyImport_AddModule((char*)"sip")); - Py::Callable func = mainmod.getDict().getItem("unwrapinstance"); - Py::Tuple arguments(1); - arguments[0] = widget; //PyQt pointer - Py::Object result = func.apply(arguments); - void* ptr = PyLong_AsVoidPtr(result.ptr()); - QObject* object = reinterpret_cast(ptr); - if (object) { - QWidget* form = qobject_cast(object); - if (form) { - Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( - form->windowIcon().pixmap(32), form->windowTitle(), true, 0); - taskbox->groupLayout()->addWidget(form); - Content.push_back(taskbox); + Py::Object f(dlg.getAttr(std::string("form"))); + Py::List widgets; + if (f.isList()) { + widgets = f; + } + else { + widgets.append(f); + } + for (Py::List::iterator it = widgets.begin(); it != widgets.end(); ++it) { + Py::Module mainmod(PyImport_AddModule((char*)"sip")); + Py::Callable func = mainmod.getDict().getItem("unwrapinstance"); + Py::Tuple arguments(1); + arguments[0] = *it; //PyQt pointer + Py::Object result = func.apply(arguments); + void* ptr = PyLong_AsVoidPtr(result.ptr()); + QObject* object = reinterpret_cast(ptr); + if (object) { + QWidget* form = qobject_cast(object); + if (form) { + Gui::TaskView::TaskBox* taskbox = new Gui::TaskView::TaskBox( + form->windowIcon().pixmap(32), form->windowTitle(), true, 0); + taskbox->groupLayout()->addWidget(form); + Content.push_back(taskbox); + } } } } From bce32cc2ef2134c96db5b76e972b3690b7604c86 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 4 Feb 2012 16:25:43 -0200 Subject: [PATCH 5/7] Added additional TaskBox to Arch Wall tool Additional parameters such as height and width can now be set during wall drawing --- src/Mod/Arch/ArchWall.py | 123 ++++++++++++++++++++++++++++----- src/Mod/Draft/DraftGui.py | 42 ++++------- src/Mod/Draft/DraftSnap.py | 6 +- src/Mod/Draft/DraftTrackers.py | 2 +- 4 files changed, 122 insertions(+), 51 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 8bc238b09..2d7b0313d 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -32,7 +32,8 @@ __url__ = "http://free-cad.sourceforge.net" def makeWall(baseobj=None,width=None,height=None,align="Center",name="Wall"): '''makeWall(obj,[width],[height],[align],[name]): creates a wall based on the - given object''' + given object, which can be a sketch, a draft object, a face or a solid. align + can be "Center","Left" or "Right"''' obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",name) _Wall(obj) _ViewProviderWall(obj.ViewObject) @@ -55,6 +56,8 @@ def joinWalls(walls): return None if not isinstance(walls,list): walls = [walls] + if not areSameWallTypes(walls): + return None base = walls.pop() if base.Base: if base.Base.Shape.Faces: @@ -63,9 +66,8 @@ def joinWalls(walls): sk = base.Base else: sk = Draft.makeSketch(base.Base,autoconstraints=True) - old = base.Base.name - base.Base = sk - FreeCAD.ActiveDocument.removeObject(old) + if sk: + base.Base = sk for w in walls: if w.Base: if not base.Base.Shape.Faces: @@ -74,6 +76,24 @@ def joinWalls(walls): FreeCAD.ActiveDocument.recompute() return base +def areSameWallTypes(walls): + "returns True is all the walls in the given list have same height, width, and alignment" + for att in ["Width","Height","Align"]: + value = None + for w in walls: + if not hasattr(w,att): + return False + if not value: + value = getattr(w,att) + else: + if type(value) == float: + if round(value,Draft.precision()) != round(getattr(w,att),Draft.precision()): + return False + else: + if value != getattr(w,att): + return False + return True + class _CommandWall: "the Arch Wall command definition" def GetResources(self): @@ -83,6 +103,14 @@ class _CommandWall: 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Arch_Wall","Creates a wall object from scratch or from a selected object (wire, face or solid)")} def Activated(self): + + global QtGui, QtCore + from PyQt4 import QtGui, QtCore + + self.Width = 0.1 + self.Height = 1 + self.Align = "Center" + sel = FreeCADGui.Selection.getSelection() done = False self.existing = [] @@ -98,7 +126,7 @@ class _CommandWall: import DraftTrackers self.points = [] self.tracker = DraftTrackers.boxTracker() - FreeCADGui.Snapper.getPoint(callback=self.getPoint) + FreeCADGui.Snapper.getPoint(callback=self.getPoint,extradlg=self.taskbox()) def getPoint(self,point=None,obj=None): "this function is called by the snapper when it has a 3D point" @@ -112,26 +140,92 @@ class _CommandWall: self.points.append(point) if len(self.points) == 1: self.tracker.on() - FreeCADGui.Snapper.getPoint(last=self.points[0],callback=self.getPoint,movecallback=self.update) + FreeCADGui.Snapper.getPoint(last=self.points[0],callback=self.getPoint,movecallback=self.update,extradlg=self.taskbox()) elif len(self.points) == 2: import Part l = Part.Line(self.points[0],self.points[1]) self.tracker.finalize() FreeCAD.ActiveDocument.openTransaction("Wall") if not self.existing: - s = FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace") - s.addGeometry(l) - makeWall(s) + self.addDefault(l) else: w = joinWalls(self.existing) - w.Base.addGeometry(l) + if w: + if areSameWallTypes([w,self]): + w.Base.addGeometry(l) + else: + self.addDefault(l) + else: + self.addDefault(l) FreeCAD.ActiveDocument.commitTransaction() FreeCAD.ActiveDocument.recompute() + def addDefault(self,l): + s = FreeCAD.ActiveDocument.addObject("Sketcher::SketchObject","WallTrace") + s.addGeometry(l) + makeWall(s,width=self.Width,height=self.Height,align=self.Align) + def update(self,point): "this function is called by the Snapper when the mouse is moved" - self.tracker.update([self.points[0],point]) - + b = self.points[0] + n = FreeCAD.DraftWorkingPlane.axis + bv = point.sub(b) + dv = bv.cross(n) + dv = fcvec.scaleTo(dv,self.Width/2) + if self.Align == "Center": + self.tracker.update([b,point]) + elif self.Align == "Left": + self.tracker.update([b.add(dv),point.add(dv)]) + else: + dv = fcvec.neg(dv) + self.tracker.update([b.add(dv),point.add(dv)]) + + def taskbox(self): + "sets up a taskbox widget" + w = QtGui.QWidget() + w.setWindowTitle("Wall options") + lay0 = QtGui.QVBoxLayout(w) + lay1 = QtGui.QHBoxLayout() + lay0.addLayout(lay1) + label1 = QtGui.QLabel("Width") + lay1.addWidget(label1) + value1 = QtGui.QDoubleSpinBox() + value1.setDecimals(2) + value1.setValue(self.Width) + lay1.addWidget(value1) + lay2 = QtGui.QHBoxLayout() + lay0.addLayout(lay2) + label2 = QtGui.QLabel("Height") + lay2.addWidget(label2) + value2 = QtGui.QDoubleSpinBox() + value2.setDecimals(2) + value2.setValue(self.Height) + lay2.addWidget(value2) + lay3 = QtGui.QHBoxLayout() + lay0.addLayout(lay3) + label3 = QtGui.QLabel("Alignment") + lay3.addWidget(label3) + value3 = QtGui.QComboBox() + items = ["Center","Left","Right"] + value3.addItems(items) + value3.setCurrentIndex(items.index(self.Align)) + lay3.addWidget(value3) + QtCore.QObject.connect(value1,QtCore.SIGNAL("valueChanged(double)"),self.setWidth) + QtCore.QObject.connect(value2,QtCore.SIGNAL("valueChanged(double)"),self.setHeight) + QtCore.QObject.connect(value3,QtCore.SIGNAL("currentIndexChanged(int)"),self.setAlign) + return w + + def setWidth(self,d): + self.Width = d + self.tracker.width(d) + + def setHeight(self,d): + self.Height = d + self.tracker.height(d) + + def setAlign(self,i): + self.Align = ["Center","Left","Right"][i] + class _Wall(ArchComponent.Component): "The Wall object" def __init__(self,obj): @@ -258,10 +352,5 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent): def getIcon(self): return ":/icons/Arch_Wall_Tree.svg" - -class TaskArchWall: - def __init__(self): - from PyQt4 import QtGui - self.form = QtGui.QWidget() FreeCADGui.addCommand('Arch_Wall',_CommandWall()) diff --git a/src/Mod/Draft/DraftGui.py b/src/Mod/Draft/DraftGui.py index 706d4d54a..831220e51 100644 --- a/src/Mod/Draft/DraftGui.py +++ b/src/Mod/Draft/DraftGui.py @@ -136,8 +136,14 @@ class DraftLineEdit(QtGui.QLineEdit): QtGui.QLineEdit.keyPressEvent(self, event) class DraftTaskPanel: - def __init__(self,widget): - self.form = widget + def __init__(self,widget,extra=None): + if extra: + if isinstance(extra,list): + self.form = [widget] + extra + else: + self.form = [widget,extra] + else: + self.form = widget def getStandardButtons(self): return int(QtGui.QDialogButtonBox.Cancel) def accept(self): @@ -318,21 +324,6 @@ class DraftToolBar: self.resetPlaneButton = self._pushbutton("none", self.layout) self.isCopy = self._checkbox("isCopy",self.layout,checked=False) - # options buttons for other workbenches - - op1 = QtGui.QHBoxLayout() - self.layout.addLayout(op1) - self.labelop1 = self._label("labelop1", op1) - self.valueop1 = self._lineedit("valueop1", op1) - op2 = QtGui.QHBoxLayout() - self.layout.addLayout(op2) - self.labelop2 = self._label("labelop2", op2) - self.valueop2 = self._lineedit("valueop2", op2) - op3 = QtGui.QHBoxLayout() - self.layout.addLayout(op3) - self.labelop3 = self._label("labelop3", op3) - self.valueop3 = self._combo("valueop3", op3) - # spacer if not self.taskmode: spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, @@ -485,19 +476,17 @@ class DraftToolBar: # Interface modes #--------------------------------------------------------------------------- - def taskUi(self,title,): + def taskUi(self,title,extra=None): if self.taskmode: self.isTaskOn = True todo.delay(FreeCADGui.Control.closeDialog,None) self.baseWidget = QtGui.QWidget() - self.setTitle(title) self.layout = QtGui.QVBoxLayout(self.baseWidget) self.setupToolBar(task=True) self.retranslateUi(self.baseWidget) - self.panel = DraftTaskPanel(self.baseWidget) + self.panel = DraftTaskPanel(self.baseWidget,extra) todo.delay(FreeCADGui.Control.showDialog,self.panel) - else: - self.setTitle(title) + self.setTitle(title) def selectPlaneUi(self): self.taskUi(translate("draft", "Select Plane")) @@ -535,7 +524,7 @@ class DraftToolBar: def pointUi(self,title=translate("draft","Point"),cancel=None,extra=None,getcoords=None,rel=False): if cancel: self.cancel = cancel if getcoords: self.pointcallback = getcoords - self.taskUi(title) + self.taskUi(title,extra) self.xValue.setEnabled(True) self.yValue.setEnabled(True) self.labelx.setText(translate("draft", "X")) @@ -546,7 +535,6 @@ class DraftToolBar: self.yValue.show() self.zValue.show() if rel: self.isRelative.show() - if extra: self.extraUi(extra) self.xValue.setFocus() self.xValue.selectAll() @@ -601,12 +589,6 @@ class DraftToolBar: self.textValue.hide() self.continueCmd.hide() self.occOffset.hide() - self.labelop1.hide() - self.valueop1.hide() - self.labelop2.hide() - self.valueop2.hide() - self.labelop3.hide() - self.valueop3.hide() def trimUi(self,title=translate("draft","Trim")): self.taskUi(title) diff --git a/src/Mod/Draft/DraftSnap.py b/src/Mod/Draft/DraftSnap.py index 1022043b0..bb7fa09f0 100644 --- a/src/Mod/Draft/DraftSnap.py +++ b/src/Mod/Draft/DraftSnap.py @@ -648,7 +648,7 @@ class Snapper: FreeCADGui.Snapper.getPoint(callback=cb) If the callback function accepts more than one argument, it will also receive - the last snapped object.Finally, a task dialog can be passed as extradlg.""" + the last snapped object. Finally, a pyqt dialog can be passed as extra taskbox.""" import inspect @@ -713,8 +713,8 @@ class Snapper: if callback: callback(None) - # adding 2 callback functions - self.ui.pointUi(cancel=cancel,getcoords=getcoords,rel=bool(last)) + # adding callback functions + self.ui.pointUi(cancel=cancel,getcoords=getcoords,extra=extradlg,rel=bool(last)) self.callbackClick = self.view.addEventCallbackPivy(coin.SoMouseButtonEvent.getClassTypeId(),click) self.callbackMove = self.view.addEventCallbackPivy(coin.SoLocation2Event.getClassTypeId(),move) diff --git a/src/Mod/Draft/DraftTrackers.py b/src/Mod/Draft/DraftTrackers.py index 0fc5b3986..1f954f2f7 100644 --- a/src/Mod/Draft/DraftTrackers.py +++ b/src/Mod/Draft/DraftTrackers.py @@ -680,7 +680,7 @@ class boxTracker(Tracker): else: return self.cube.width.getValue() - def heigth(self,h=None): + def height(self,h=None): if h: self.cube.depth.setValue(h) self.update() From d22d65400754c13935b37e8064359470d1821ffa Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 4 Feb 2012 16:33:27 -0200 Subject: [PATCH 6/7] Added multi-taskboxes example to TemplatePyMod TaskPanel example --- src/Mod/TemplatePyMod/TaskPanel.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Mod/TemplatePyMod/TaskPanel.py b/src/Mod/TemplatePyMod/TaskPanel.py index da05968ab..13c67bc8a 100644 --- a/src/Mod/TemplatePyMod/TaskPanel.py +++ b/src/Mod/TemplatePyMod/TaskPanel.py @@ -95,6 +95,14 @@ class TaskCalendar: def __init__(self): self.form = QtGui.QCalendarWidget() +class TaskManyTaskBoxes: + "illustrates how to add several taskboxes" + def __init__(self): + widget1 = QtGui.QCalendarWidget() + widget2 = QtGui.QWidget() + widget2.setWindowTitle("My Test Box") + text = QtGui.QLabel("testBox",widget2) + self.form = [widget1,widget2] def createTask(): Gui.Control.addTaskWatcher([TaskWatcher(), TaskLineEdit(), TaskWatcherFilter()]) From 47765a18444882414d62c7be812c1897fe3efbf7 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 4 Feb 2012 17:26:48 -0200 Subject: [PATCH 7/7] Added 2D displaymode to Arch walls --- src/Mod/Arch/ArchWall.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/Mod/Arch/ArchWall.py b/src/Mod/Arch/ArchWall.py index 2d7b0313d..c3e5ec85c 100644 --- a/src/Mod/Arch/ArchWall.py +++ b/src/Mod/Arch/ArchWall.py @@ -255,6 +255,10 @@ class _Wall(ArchComponent.Component): import Part from draftlibs import fcgeo + + flat = False + if hasattr(obj.ViewObject,"DisplayMode"): + flat = (obj.ViewObject.DisplayMode == "Flat 2D") def getbase(wire): "returns a full shape from a base wire" @@ -277,7 +281,7 @@ class _Wall(ArchComponent.Component): sh = fcgeo.bind(w1,w2) # fixing self-intersections sh.fix(0.1,0,1) - if height: + if height and (not flat): norm = Vector(normal).multiply(height) sh = sh.extrude(norm) return sh @@ -352,5 +356,19 @@ class _ViewProviderWall(ArchComponent.ViewProviderComponent): def getIcon(self): return ":/icons/Arch_Wall_Tree.svg" - + + def getDisplayModes(self,vobj): + return ["Flat 2D"] + + def setDisplayMode(self,mode): + self.Object.Proxy.createGeometry(self.Object) + if mode == "Flat 2D": + return "Flat Lines" + else: + return mode + + def attach(self,vobj): + self.Object = vobj.Object + return + FreeCADGui.addCommand('Arch_Wall',_CommandWall())