diff --git a/src/Mod/Path/Gui/Resources/panels/PageOpPocketExtEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageOpPocketExtEdit.ui
index 5b0ff175d5..828bbb3e91 100644
--- a/src/Mod/Path/Gui/Resources/panels/PageOpPocketExtEdit.ui
+++ b/src/Mod/Path/Gui/Resources/panels/PageOpPocketExtEdit.ui
@@ -7,7 +7,7 @@
0
0
381
- 552
+ 617
@@ -50,41 +50,38 @@
-
-
-
- false
+
+
+ QAbstractItemView::NoEditTriggers
+
+
+ true
+
+
+ QAbstractItemView::MultiSelection
+
+
+ true
+
+
+ true
-
-
- Feature
-
-
-
-
- Length
-
-
-
-
- Direction
-
-
-
-
-
+
- Add
+ Enable
-
-
+
- Remove
+ Disable
diff --git a/src/Mod/Path/PathScripts/PathPocketShape.py b/src/Mod/Path/PathScripts/PathPocketShape.py
index 552cf2b047..f1dc0b5ba9 100644
--- a/src/Mod/Path/PathScripts/PathPocketShape.py
+++ b/src/Mod/Path/PathScripts/PathPocketShape.py
@@ -41,7 +41,7 @@ __author__ = "sliptonic (Brad Collette)"
__url__ = "http://www.freecadweb.org"
__doc__ = "Class and implementation of shape based Pocket operation."
-if True:
+if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
@@ -52,6 +52,7 @@ def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
def endPoints(edgeOrWire):
+ '''endPoints(edgeOrWire) ... return the first and last point of the wire or the edge, assuming the argument is not a closed wire.'''
if Part.Wire == type(edgeOrWire):
edges = edgeOrWire.Edges
pts = [e.valueAt(e.FirstParameter) for e in edgeOrWire.Edges]
@@ -65,12 +66,14 @@ def endPoints(edgeOrWire):
return [e.valueAt(edgeOrWire.FirstParameter), e.valueAt(edgeOrWire.LastParameter)]
def includesPoint(p, pts):
+ '''includesPoint(p, pts) ... answer True if the collection of pts includes the point p'''
for pt in pts:
if PathGeom.pointsCoincide(p, pt):
return True
return False
def selectOffsetWire(wire, wires, offset):
+ '''selectOffsetWire(wire, wires, offset) ... returns the Wire in wires which most likely is wire offset by offset'''
startPoint = endPoints(wire)[0] + offset;
closest = None
for w in wires:
@@ -82,11 +85,9 @@ def selectOffsetWire(wire, wires, offset):
return closest[1]
return None
-d = []
def extendWire(wire, length, direction):
- global d
- d = []
+ '''extendWire(wire, length, direction) ... return a closed Wire which extends wire by length into direction'''
off2D = wire.makeOffset2D(length)
endPts = endPoints(wire)
edges = [e for e in off2D.Edges if Part.Circle != type(e.Curve) or not includesPoint(e.Curve.Center, endPts)]
@@ -163,7 +164,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
obj.UseOutline = False
if not hasattr(obj, 'ExtensionLengthDefault'):
obj.addProperty('App::PropertyDistance', 'ExtensionLengthDefault', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'Default length of extensions.'))
- if not hasattr(obj, 'ExtensionFeatures'):
+ if not hasattr(obj, 'ExtensionFeature'):
obj.addProperty('App::PropertyLinkSubListGlobal', 'ExtensionFeature', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'List of features to extend.'))
if not hasattr(obj, 'ExtensionLength'):
obj.addProperty('App::PropertyFloatList', 'ExtensionLength', 'Extension', QtCore.QT_TRANSLATE_NOOP('PathPocketShape', 'List of extension lenght of corresponding feature.'))
@@ -297,6 +298,7 @@ class ObjectPocket(PathPocketBase.ObjectPocket):
return extensions
def setExtensions(self, obj, extensions):
+ PathLog.track(obj.Label, len(extensions))
features = {}
for ext in extensions:
subs = features.get(ext.obj, [])
diff --git a/src/Mod/Path/PathScripts/PathPocketShapeGui.py b/src/Mod/Path/PathScripts/PathPocketShapeGui.py
index 776c57d9e4..8a6e7843ed 100644
--- a/src/Mod/Path/PathScripts/PathPocketShapeGui.py
+++ b/src/Mod/Path/PathScripts/PathPocketShapeGui.py
@@ -43,7 +43,7 @@ __doc__ = "Pocket Shape operation page controller and command implementation."
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
-if True:
+if False:
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
else:
@@ -56,20 +56,23 @@ def createExtensionSoSwitch(ext):
crd = coin.SoCoordinate3()
fce = coin.SoFaceSet()
- wire = ext.getWire()
- if wire:
- polygon = []
- for p in wire.discretize(Deflection=0.01):
- polygon.append((p.x, p.y, p.z))
- crd.point.setValues(polygon)
+ if not ext is None:
+ wire = ext.getWire()
+ if wire:
+ polygon = []
+ for p in wire.discretize(Deflection=0.01):
+ polygon.append((p.x, p.y, p.z))
+ crd.point.setValues(polygon)
+ else:
+ return None
- mat.diffuseColor = (1.0, 0.0, 0.0)
- mat.transparency = 0.5
+ mat.diffuseColor = (1.0, 0.0, 0.0)
+ mat.transparency = 0.5
- sep.addChild(pos)
- sep.addChild(mat)
- sep.addChild(crd)
- sep.addChild(fce)
+ sep.addChild(pos)
+ sep.addChild(mat)
+ sep.addChild(crd)
+ sep.addChild(fce)
switch = coin.SoSwitch()
switch.addChild(sep)
@@ -78,11 +81,21 @@ def createExtensionSoSwitch(ext):
return switch
class _Extension(object):
- def __init__(self, ext):
- self.ext = ext
- self.switch = createExtensionSoSwitch(ext)
+ def __init__(self, obj, base, face, edge):
+ self.base = base
+ self.face = face
+ self.edge = edge
+ if edge is None:
+ self.ext = None
+ else:
+ self.ext = obj.Proxy.createExtension(obj, base, edge)
+ self.switch = createExtensionSoSwitch(self.ext)
self.root = self.switch
+ def isValid(self):
+ return not self.root is None
+
+Page = None
class TaskPanelExtensionPage(PathOpGui.TaskPanelPage):
DataObject = QtCore.Qt.ItemDataRole.UserRole
@@ -95,7 +108,7 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage):
}
def initPage(self, obj):
- self.setTitle("Pocket Extensions")
+ self.setTitle("Extensions")
self.extensions = obj.Proxy.getExtensions(obj)
self.defaultLength = PathGui.QuantitySpinBox(self.form.defaultLength, obj, 'ExtensionLengthDefault')
@@ -107,132 +120,166 @@ class TaskPanelExtensionPage(PathOpGui.TaskPanelPage):
self.obj.ViewObject.RootNode.addChild(self.switch)
self.switch.whichChild = coin.SO_SWITCH_ALL
+ self.model = QtGui.QStandardItemModel(self.form.extensions)
+ self.model.setHorizontalHeaderLabels(['Base', 'Extension'])
+
+ global Page
+ Page = self
+
def cleanupPage(self, obj):
self.obj.ViewObject.RootNode.removeChild(self.switch)
def getForm(self):
return FreeCADGui.PySideUic.loadUi(":/panels/PageOpPocketExtEdit.ui")
+ def forAllItemsCall(self, cb):
+ for modelRow in range(self.model.rowCount()):
+ model = self.model.item(modelRow, 0)
+ for featureRow in range(model.rowCount()):
+ feature = model.child(featureRow, 0);
+ for edgeRow in range(feature.rowCount()):
+ cb(feature.child(edgeRow, 0))
+
def getFields(self, obj):
- PathLog.track(obj.Label)
+ PathLog.track(obj.Label, self.model.rowCount(), self.model.columnCount())
self.defaultLength.updateProperty()
- exts = []
- for row in range(self.form.extensions.rowCount()):
- item = self.form.extensions.item(row, 0)
- exts.append(item.data(self.DataObject).ext)
- obj.Proxy.setExtensions(obj, exts)
+ extensions = []
+
+ def extractExtension(item):
+ ext = item.data(self.DataObject)
+ if ext and ext.edge and item.checkState() == QtCore.Qt.Checked:
+ extensions.append(ext.ext)
+
+ self.forAllItemsCall(extractExtension)
+
+ self.extensions = extensions
+ obj.Proxy.setExtensions(obj, extensions)
def setFields(self, obj):
PathLog.track(obj.Label)
self.defaultLength.updateSpinBox()
self.setExtensions(self.extensions)
+ def createItemForBaseModel(self, base, sub, edges, extensions):
+ ext = _Extension(self.obj, base, sub, None)
+ self.switch.addChild(ext.root)
+ item = QtGui.QStandardItem()
+ item.setData(sub, QtCore.Qt.EditRole)
+ item.setData(ext, self.DataObject)
+ item.setSelectable(False)
+
+ for edge in base.Shape.getElement(sub).Edges:
+ for (e, label) in edges:
+ if edge.isSame(e):
+ ext0 = _Extension(self.obj, base, sub, label)
+ if ext0.isValid():
+ self.switch.addChild(ext0.root)
+ item0 = QtGui.QStandardItem()
+ item0.setData(label, QtCore.Qt.EditRole)
+ item0.setData(ext0, self.DataObject)
+ item0.setCheckable(True)
+ for e in extensions:
+ PathLog.debug("%s.%s vs %s.%s" % (base.Label, label, e.obj.Label, e.sub))
+ if e.obj == base and e.sub == label:
+ item0.setCheckState(QtCore.Qt.Checked)
+ break
+ item.appendRow([item0])
+ break
+
+ return item
+
def setExtensions(self, extensions):
self.form.extensions.blockSignals(True)
- for row in range(self.form.extensions.rowCount()):
- self.switch.removeChild(self.form.extensions.item(row, 0).data(self.DataObject).root)
- self.form.extensions.clearContents()
- self.form.extensions.setRowCount(0)
- for row, ext in enumerate(extensions):
- PathLog.info("{}.{}".format(ext.obj.Label, ext.sub))
- self.form.extensions.insertRow(row)
+ self.forAllItemsCall(lambda item: self.switch.removeChild(item.data(self.DataObject).root))
+ self.model.clear()
- _ext = _Extension(ext)
+ for base in self.obj.Base:
+ edges = [(edge, "Edge%d" % (i + 1)) for i, edge in enumerate(base[0].Shape.Edges)]
+ baseItem = QtGui.QStandardItem()
+ baseItem.setData(base[0].Label, QtCore.Qt.EditRole)
+ baseItem.setSelectable(False)
+ for sub in sorted(base[1]):
+ baseItem.appendRow(self.createItemForBaseModel(base[0], sub, edges, extensions))
+ self.model.appendRow(baseItem)
- item0 = QtGui.QTableWidgetItem("{}.{}".format(ext.obj.Label, ext.sub))
- item0.setData(self.DataObject, _ext)
- self.form.extensions.setItem(row, 0, item0)
-
- item1 = QtGui.QTableWidgetItem("{}".format(ext.length))
- item1.setData(self.DataObject, _ext)
- item1.setFlags(item1.flags() & ~QtCore.Qt.ItemIsEnabled)
- self.form.extensions.setItem(row, 1, item1)
-
- item2 = QtGui.QTableWidgetItem("{}".format(self.Direction[ext.direction]))
- item2.setData(self.DataObject, _ext)
- item2.setFlags(item2.flags() & ~QtCore.Qt.ItemIsEnabled)
- self.form.extensions.setItem(row, 2, item2)
-
- self.switch.addChild(_ext.root)
-
- self.form.extensions.resizeColumnsToContents()
- self.form.extensions.blockSignals(False)
- self.extensions = extensions
+ self.form.extensions.setModel(self.model)
+ self.form.extensions.expandAll()
+ self.form.extensions.resizeColumnToContents(0)
def updateData(self, obj, prop):
if prop in ['ExtensionLengthDefault']:
pass
if prop in ['ExtensionFeature']:
+ pass
+ if prop in ['Base']:
self.setExtensions(obj.Proxy.getExtensions(obj))
- def updateSelection(self, obj, sel):
- if sel and sel[0].SubElementNames:
- self.form.buttonAdd.setEnabled(True)
- else:
- self.form.buttonAdd.setEnabled(False)
-
- def itemSelectionChanged(self):
- if 0 == self.form.extensions.rowCount():
+ def selectionChanged(self):
+ if 0 == self.model.rowCount():
+ PathLog.track('-')
self.form.buttonClear.setEnabled(False)
- self.form.buttonRemove.setEnabled(False)
+ self.form.buttonDisable.setEnabled(False)
+ self.form.buttonEnable.setEnabled(False)
else:
self.form.buttonClear.setEnabled(True)
- if self.form.extensions.selectedItems():
- self.form.buttonRemove.setEnabled(True)
+
+ if self.selectionModel.selectedIndexes():
+ self.form.buttonDisable.setEnabled(True)
+ self.form.buttonEnable.setEnabled(True)
else:
- self.form.buttonRemove.setEnabled(False)
+ self.form.buttonDisable.setEnabled(False)
+ self.form.buttonEnable.setEnabled(False)
FreeCADGui.Selection.clearSelection()
- print("rowCount = %s" % self.form.extensions.rowCount())
- for row in range(self.form.extensions.rowCount()):
- item = self.form.extensions.item(row, 0)
+ for row in range(self.model.rowCount()):
+ item = self.model.item(row, 0)
ext = item.data(self.DataObject)
- ext.switch.whichChild = coin.SO_SWITCH_NONE
+ if not ext is None:
+ ext.switch.whichChild = coin.SO_SWITCH_NONE
- processed = []
- for item in self.form.extensions.selectedItems():
+ for index in self.selectionModel.selectedIndexes():
+ item = self.model.itemFromIndex(index)
ext = item.data(self.DataObject)
- if not ext in processed:
- FreeCADGui.Selection.addSelection(ext.ext.obj, ext.ext.sub)
+ if not ext.face is None:
+ FreeCADGui.Selection.addSelection(ext.base, ext.face)
+ if not ext.edge is None:
+ PathLog.track(ext.base.Label, ext.edge)
ext.switch.whichChild = coin.SO_SWITCH_ALL
- processed.append(ext)
-
- def extensionsAdd(self):
- extensions = self.extensions
- for sel in FreeCADGui.Selection.getSelectionEx():
- for subname in sel.SubElementNames:
- row = self.form.extensions.rowCount()
- extensions.append(self.obj.Proxy.createExtension(self.obj, sel.Object, subname))
- self.obj.Proxy.setExtensions(self.obj, extensions)
- self.setDirty()
def extensionsClear(self):
- self.obj.Proxy.setExtensions(self.obj, [])
+ self.forAllItemsCall(lambda item: item.setCheckState(QtCore.Qt.Unchecked))
self.setDirty()
- def extensionsRemove(self):
- extensions = self.extensions
- for item in self.form.extensions.selectedItems():
- ext = item.data(self.DataObject).ext
- if ext in extensions:
- extensions.remove(ext)
- self.obj.Proxy.setExtensions(self.obj, extensions)
+ def _extensionsSetState(self, state):
+ for index in self.selectionModel.selectedIndexes():
+ item = self.model.itemFromIndex(index)
+ ext = item.data(self.DataObject)
+ if ext.edge:
+ item.setCheckState(state)
self.setDirty()
+ def extensionsDisable(self):
+ self._extensionsSetState(QtCore.Qt.Unchecked)
+
+ def extensionsEnable(self):
+ self._extensionsSetState(QtCore.Qt.Checked)
+
+
def getSignalsForUpdate(self, obj):
PathLog.track(obj.Label)
return [self.form.defaultLength.editingFinished]
def registerSignalHandlers(self, obj):
- self.form.buttonAdd.clicked.connect(self.extensionsAdd)
self.form.buttonClear.clicked.connect(self.extensionsClear)
- self.form.buttonRemove.clicked.connect(self.extensionsRemove)
+ self.form.buttonDisable.clicked.connect(self.extensionsDisable)
+ self.form.buttonEnable.clicked.connect(self.extensionsEnable)
- self.updateSelection(self.obj, FreeCADGui.Selection.getSelectionEx())
- self.form.extensions.itemSelectionChanged.connect(self.itemSelectionChanged)
- self.itemSelectionChanged()
+ self.model.itemChanged.connect(lambda x: self.setDirty())
+
+ self.selectionModel = self.form.extensions.selectionModel()
+ self.selectionModel.selectionChanged.connect(self.selectionChanged)
class TaskPanelOpPage(PathPocketBaseGui.TaskPanelOpPage):
'''Page controller class for Pocket operation'''
@@ -242,7 +289,8 @@ class TaskPanelOpPage(PathPocketBaseGui.TaskPanelOpPage):
return PathPocketBaseGui.FeaturePocket | PathPocketBaseGui.FeatureOutline
def taskPanelBaseLocationPage(self, obj, features):
- self.extensionsPanel = TaskPanelExtensionPage(obj, features)
+ if not hasattr(self, 'extensionsPanel'):
+ self.extensionsPanel = TaskPanelExtensionPage(obj, features)
return self.extensionsPanel
def pageRegisterSignalHandlers(self):
diff --git a/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py b/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py
index 8e2ffb5385..e55916bf36 100644
--- a/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py
+++ b/src/Mod/Path/PathScripts/PathSetupSheetOpPrototype.py
@@ -142,7 +142,9 @@ class OpPrototype(object):
'App::PropertyEnumeration': PropertyEnumeration,
'App::PropertyFloat': PropertyFloat,
'App::PropertyFloatConstraint': Property,
+ 'App::PropertyFloatList': Property,
'App::PropertyInteger': PropertyInteger,
+ 'App::PropertyIntegerList': PropertyInteger,
'App::PropertyLength': PropertyLength,
'App::PropertyLink': Property,
'App::PropertyLinkList': Property,