From 14687898be9bd3d4e989821be668c9102865463d Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Wed, 30 Dec 2020 21:58:37 -0800 Subject: [PATCH] Simplified tool bit editor using property-bags --- .../Gui/Resources/panels/ToolBitEditor.ui | 341 ++++++++---------- src/Mod/Path/PathScripts/PathToolBit.py | 138 ++----- src/Mod/Path/PathScripts/PathToolBitEdit.py | 93 +---- src/Mod/Path/PathScripts/PathUtil.py | 5 + src/Mod/Path/Tools/Shape/endmill.fcstd | Bin 11428 -> 11485 bytes 5 files changed, 194 insertions(+), 383 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui b/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui index 7642c14185..5ed0208067 100644 --- a/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui +++ b/src/Mod/Path/Gui/Resources/panels/ToolBitEditor.ui @@ -13,202 +13,168 @@ Tool Bit Attributes - - - + + + - + 0 0 - - 0 + + Tool Bit - - - Shape - - - - - - Tool Bit + + + + + Name + + + + + + + <html><head/><body><p>Display name of the Tool Bit (initial value taken from the shape file).</p></body></html> + + + 50 + + + Display Name + + + + + + + Shape File + + + + + + + + 0 + 0 + + + + + 0 - - - - - Name - - - - - - - <html><head/><body><p>Display name of the Tool Bit (initial value taken from the shape file).</p></body></html> - - - 50 - - - Display Name - - - - - - - Shape File - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - <html><head/><body><p>The file which defines the type and shape of the Tool Bit.</p></body></html> - - - - - - - <html><head/><body><p>Change file defining type and shape of Tool Bit.</p></body></html> - - - ... - - - - - - - - - - - - - Geometry + + 0 - - - QFormLayout::AllNonFixedFieldsGrow - - - - - Point/Tip Angle - - - - - - - 0 ° - - - ° - - - - - - - Cutting Edge Height - - - - - - - 0 mm - - - mm - - - - - - - - - - - 210 - 297 - + + 0 - - Image + + 0 - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - - 20 - 277 - - - - - - - - - Attributes - - - - - - - 0 - 2 - - - - - 0 - 300 - - - - QAbstractItemView::AllEditTriggers - - - true - - - - - + + + + <html><head/><body><p>The file which defines the type and shape of the Tool Bit.</p></body></html> + + + path + + + + + + + <html><head/><body><p>Change file defining type and shape of Tool Bit.</p></body></html> + + + ... + + + + + + + + + + + Parameter + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Point/Tip Angle + + + + + + + 0 ° + + + ° + + + + + + + Cutting Edge Height + + + + + + + 0 mm + + + mm + + + + + + + + + + + 210 + 297 + + + + Image + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + + 20 + 277 + + + + @@ -218,6 +184,13 @@
Gui/InputField.h
+ + toolName + toolCuttingEdgeAngle + toolCuttingEdgeHeight + shapePath + shapeSet + diff --git a/src/Mod/Path/PathScripts/PathToolBit.py b/src/Mod/Path/PathScripts/PathToolBit.py index fdee7aeb50..0445feabab 100644 --- a/src/Mod/Path/PathScripts/PathToolBit.py +++ b/src/Mod/Path/PathScripts/PathToolBit.py @@ -43,7 +43,9 @@ __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" __doc__ = "Class to deal with and represent a tool bit." -_DebugFindTool = True +PropertyGroupShape = 'Shape' + +_DebugFindTool = False PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule() @@ -52,15 +54,6 @@ PathLog.trackModule() def translate(context, text, disambig=None): return PySide.QtCore.QCoreApplication.translate(context, text, disambig) - -ParameterTypeConstraint = { - 'Angle': 'App::PropertyAngle', - 'Distance': 'App::PropertyLength', - 'DistanceX': 'App::PropertyLength', - 'DistanceY': 'App::PropertyLength', - 'Radius': 'App::PropertyLength'} - - def _findTool(path, typ, dbg=_DebugFindTool): PathLog.track(path) if os.path.exists(path): # absolute reference @@ -136,50 +129,16 @@ def findRelativePathTool(path): def findRelativePathLibrary(path): return _findRelativePath(path, 'Library') - -def updateConstraint(sketch, name, value): - for i, constraint in enumerate(sketch.Constraints): - if constraint.Name.split(';')[0] == name: - constr = None - if constraint.Type in ['DistanceX', 'DistanceY', 'Distance', 'Radius', 'Angle']: - constr = Sketcher.Constraint(constraint.Type, constraint.First, constraint.FirstPos, constraint.Second, constraint.SecondPos, value) - else: - print(constraint.Name, constraint.Type) - - if constr is not None: - if not PathGeom.isRoughly(constraint.Value, value.Value): - PathLog.track(name, constraint.Type, - 'update', i, "(%.2f -> %.2f)" - % (constraint.Value, value.Value)) - sketch.delConstraint(i) - sketch.recompute() - n = sketch.addConstraint(constr) - sketch.renameConstraint(n, constraint.Name) - else: - PathLog.track(name, constraint.Type, 'unchanged') - break - - -PropertyGroupBit = 'Bit' -PropertyGroupAttribute = 'Attribute' - - class ToolBit(object): def __init__(self, obj, shapeFile): PathLog.track(obj.Label, shapeFile) self.obj = obj - obj.addProperty('App::PropertyFile', 'BitShape', 'Base', - translate('PathToolBit', 'Shape for bit shape')) - obj.addProperty('App::PropertyLink', 'BitBody', 'Base', - translate('PathToolBit', - 'The parametrized body representing the tool bit')) - obj.addProperty('App::PropertyFile', 'File', 'Base', - translate('PathToolBit', 'The file of the tool')) - obj.addProperty('App::PropertyString', 'ShapeName', 'Base', - translate('PathToolBit', 'The name of the shape file')) - obj.addProperty('App::PropertyStringList', 'BitPropertyNames', 'Base', - translate('PathToolBit', 'List of all properties inherited from the bit')) + obj.addProperty('App::PropertyFile', 'BitShape', 'Base', translate('PathToolBit', 'Shape for bit shape')) + obj.addProperty('App::PropertyLink', 'BitBody', 'Base', translate('PathToolBit', 'The parametrized body representing the tool bit')) + obj.addProperty('App::PropertyFile', 'File', 'Base', translate('PathToolBit', 'The file of the tool')) + obj.addProperty('App::PropertyString', 'ShapeName', 'Base', translate('PathToolBit', 'The name of the shape file')) + obj.addProperty('App::PropertyStringList', 'BitPropertyNames', 'Base', translate('PathToolBit', 'List of all properties inherited from the bit')) if shapeFile is None: obj.BitShape = 'endmill.fcstd' @@ -200,9 +159,6 @@ class ToolBit(object): break return None - def propertyNamesAttribute(self, obj): - return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupAttribute] - def onDocumentRestored(self, obj): # when files are shared it is essential to be able to change/set the shape file, # otherwise the file is hard to use @@ -213,17 +169,19 @@ class ToolBit(object): obj.setEditorMode('BitPropertyNames', 2) for prop in obj.BitPropertyNames: - obj.setEditorMode(prop, 1) - # I currently don't see why these need to be read-only - # for prop in self.propertyNamesAttribute(obj): - # obj.setEditorMode(prop, 1) + if obj.getGroupOfProperty(prop) == PropertyGroupShape: + # properties in the Shape group can only be modified while the actual + # shape is loaded, so we have to disable direct property editing + obj.setEditorMode(prop, 1) + else: + # all other custom properties can and should be edited directly in the + # property editor widget, not much value in re-implementing that + obj.setEditorMode(prop, 0) def onChanged(self, obj, prop): PathLog.track(obj.Label, prop) if prop == 'BitShape' and 'Restore' not in obj.State: self._setupBitShape(obj) - # elif obj.getGroupOfProperty(prop) == PropertyGroupBit: - # self._updateBitShape(obj, [prop]) def onDelete(self, obj, arg2=None): PathLog.track(obj.Label) @@ -335,6 +293,20 @@ class ToolBit(object): obj.BitBody = bitBody self._copyBitShape(obj) + def toolShapeProperties(self, obj): + '''toolShapeProperties(obj) ... return all properties defining the geometry''' + return sorted([prop for prop in obj.BitPropertyNames if obj.getGroupOfProperty(prop) == PropertyGroupShape]) + + def toolGroupsAndProperties(self, obj, includeShape=True): + '''toolGroupsAndProperties(obj) ... returns a dictionary of group names with a list of property names.''' + category = {} + for prop in obj.BitPropertyNames: + group = obj.getGroupOfProperty(prop) + properties = category.get(group, []) + properties.append(prop) + category[group] = properties + return category + def getBitThumbnail(self, obj): if obj.BitShape: path = findShape(obj.BitShape) @@ -359,8 +331,7 @@ class ToolBit(object): obj.File = path return True except (OSError, IOError) as e: - PathLog.error("Could not save tool {} to {} ({})".format( - obj.Label, path, e)) + PathLog.error("Could not save tool {} to {} ({})".format(obj.Label, path, e)) raise def templateAttrs(self, obj): @@ -376,12 +347,6 @@ class ToolBit(object): params[name] = PathUtil.getPropertyValueString(obj, name) attrs['parameter'] = params params = {} - for name in self.propertyNamesAttribute(obj): - if name == "UserAttributes": - for key, value in obj.UserAttributes.items(): - params[key] = value - else: - params[name] = PathUtil.getPropertyValueString(obj, name) attrs['attribute'] = params return attrs @@ -392,32 +357,6 @@ def Declaration(path): return json.load(fp) -class AttributePrototype(PathSetupSheetOpPrototype.OpPrototype): - - def __init__(self): - PathSetupSheetOpPrototype.OpPrototype.__init__(self, 'ToolBitAttribute') - self.addProperty('App::PropertyEnumeration', 'Material', - PropertyGroupAttribute, - translate('PathToolBit', 'Tool bit material')) - self.Material = ['Carbide', 'CastAlloy', 'Ceramics', 'Diamond', - 'HighCarbonToolSteel', 'HighSpeedSteel', 'Sialon'] - self.addProperty('App::PropertyDistance', 'LengthOffset', - PropertyGroupAttribute, translate('PathToolBit', - 'Length offset in Z direction')) - self.addProperty('App::PropertyInteger', 'Flutes', - PropertyGroupAttribute, translate('PathToolBit', - 'The number of flutes')) - self.addProperty('App::PropertyDistance', 'ChipLoad', - PropertyGroupAttribute, translate('PathToolBit', - 'Chipload as per manufacturer')) - self.addProperty('App::PropertyMap', 'UserAttributes', - PropertyGroupAttribute, translate('PathToolBit', - 'User Defined Values')) - self.addProperty('App::PropertyBool', 'SpindlePower', - PropertyGroupAttribute, translate('PathToolBit', - 'Whether Spindle Power should be allowed')) - - class ToolBitFactory(object): def CreateFromAttrs(self, attrs, name='ToolBit'): @@ -429,21 +368,6 @@ class ToolBitFactory(object): PathUtil.setProperty(obj, prop, params[prop]) obj.Proxy._updateBitShape(obj) obj.Proxy.unloadBitBody(obj) - params = attrs['attribute'] - proto = AttributePrototype() - uservals = {} - for pname in params: - try: - prop = proto.getProperty(pname) - prop.setupProperty(obj, pname, PropertyGroupAttribute, prop.valueFromString(params[pname])) - except Exception: - prop = proto.getProperty("UserAttributes") - uservals.update({pname: params[pname]}) - - if len(uservals.items()) > 0: - prop.setupProperty(obj, "UserAttributes", - PropertyGroupAttribute, uservals) - return obj def CreateFrom(self, path, name='ToolBit'): diff --git a/src/Mod/Path/PathScripts/PathToolBitEdit.py b/src/Mod/Path/PathScripts/PathToolBitEdit.py index b2cc823d76..5ced9249aa 100644 --- a/src/Mod/Path/PathScripts/PathToolBitEdit.py +++ b/src/Mod/Path/PathScripts/PathToolBitEdit.py @@ -24,7 +24,6 @@ import FreeCADGui import PathScripts.PathGui as PathGui import PathScripts.PathLog as PathLog import PathScripts.PathPreferences as PathPreferences -import PathScripts.PathSetupSheetGui as PathSetupSheetGui import PathScripts.PathToolBit as PathToolBit import os import re @@ -70,7 +69,6 @@ class ToolBitEditor(object): self.widgets = [] self.setupTool(self.tool) - self.setupAttributes(self.tool) def setupTool(self, tool): PathLog.track() @@ -88,7 +86,7 @@ class ToolBitEditor(object): # for all properties either assign them to existing labels and editors # or create additional ones for them if not enough have already been # created. - for nr, name in enumerate(tool.BitPropertyNames): + for nr, name in enumerate(tool.Proxy.toolShapeProperties(tool)): if nr < len(self.widgets): PathLog.debug("re-use row: {} [{}]".format(nr, name)) label, qsb, editor = self.widgets[nr] @@ -122,100 +120,11 @@ class ToolBitEditor(object): else: self.form.image.setPixmap(QtGui.QPixmap()) - def setupAttributes(self, tool): - PathLog.track() - self.proto = PathToolBit.AttributePrototype() - self.props = sorted(self.proto.properties) - self.delegate = PathSetupSheetGui.Delegate(self.form) - self.model = QtGui.QStandardItemModel(len(self.props)-1, 3, self.form) - self.model.setHorizontalHeaderLabels(['Set', 'Property', 'Value']) - - for i, name in enumerate(self.props): - PathLog.debug("propname: %s " % name) - - prop = self.proto.getProperty(name) - isset = hasattr(tool, name) - - if isset: - prop.setValue(getattr(tool, name)) - - if name == "UserAttributes": - continue - - else: - - self.model.setData(self.model.index(i, 0), isset, - QtCore.Qt.EditRole) - self.model.setData(self.model.index(i, 1), name, - QtCore.Qt.EditRole) - self.model.setData(self.model.index(i, 2), prop, - PathSetupSheetGui.Delegate.PropertyRole) - self.model.setData(self.model.index(i, 2), - prop.displayString(), - QtCore.Qt.DisplayRole) - - self.model.item(i, 0).setCheckable(True) - self.model.item(i, 0).setText('') - self.model.item(i, 1).setEditable(False) - self.model.item(i, 1).setToolTip(prop.info) - self.model.item(i, 2).setToolTip(prop.info) - - if isset: - self.model.item(i, 0).setCheckState(QtCore.Qt.Checked) - else: - self.model.item(i, 0).setCheckState(QtCore.Qt.Unchecked) - self.model.item(i, 1).setEnabled(False) - self.model.item(i, 2).setEnabled(False) - - if hasattr(tool, "UserAttributes"): - for key, value in tool.UserAttributes.items(): - PathLog.debug(key, value) - c1 = QtGui.QStandardItem() - c1.setCheckable(False) - c1.setEditable(False) - c1.setCheckState(QtCore.Qt.CheckState.Checked) - - c1.setText('') - c2 = QtGui.QStandardItem(key) - c2.setEditable(False) - c3 = QtGui.QStandardItem(value) - c3.setEditable(False) - - self.model.appendRow([c1, c2, c3]) - - self.form.attrTable.setModel(self.model) - self.form.attrTable.setItemDelegateForColumn(2, self.delegate) - self.form.attrTable.resizeColumnsToContents() - self.form.attrTable.verticalHeader().hide() - - self.model.dataChanged.connect(self.updateData) - - def updateData(self, topLeft, bottomRight): - PathLog.track() - if 0 == topLeft.column(): - isset = self.model.item(topLeft.row(), - 0).checkState() == QtCore.Qt.Checked - self.model.item(topLeft.row(), 1).setEnabled(isset) - self.model.item(topLeft.row(), 2).setEnabled(isset) - def accept(self): PathLog.track() self.refresh() self.tool.Proxy.unloadBitBody(self.tool) - # get the attributes - for i, name in enumerate(self.props): - PathLog.debug('in accept: {}'.format(name)) - prop = self.proto.getProperty(name) - if self.model.item(i, 0) is not None: - enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked - if enabled and not prop.getValue() is None: - prop.setupProperty(self.tool, name, - PathToolBit.PropertyGroupAttribute, - prop.getValue()) - elif hasattr(self.tool, name): - self.tool.removeProperty(name) - def reject(self): PathLog.track() self.tool.Proxy.unloadBitBody(self.tool) diff --git a/src/Mod/Path/PathScripts/PathUtil.py b/src/Mod/Path/PathScripts/PathUtil.py index 40e59a78af..7c423af22f 100644 --- a/src/Mod/Path/PathScripts/PathUtil.py +++ b/src/Mod/Path/PathScripts/PathUtil.py @@ -71,6 +71,11 @@ def getPropertyValueString(obj, prop): def setProperty(obj, prop, value): '''setProperty(obj, prop, value) ... set the property value of obj's property defined by its canonical name.''' o, attr, name = _getProperty(obj, prop) # pylint: disable=unused-variable + if attr and type(value) == str: + if type(attr) == int: + value = int(value, 0) + elif type(attr) == bool: + value = value.lower() in ['true', '1', 'yes', 'ok'] if o and name: setattr(o, name, value) diff --git a/src/Mod/Path/Tools/Shape/endmill.fcstd b/src/Mod/Path/Tools/Shape/endmill.fcstd index 4a292c5f0e241d84d362a906ef1ec7a46ef6781f..a40e5fbe5168b3cbda5f37d5ff67a630bc9b9f33 100644 GIT binary patch delta 10275 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