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 @@
+
+ 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 4a292c5f0e..a40e5fbe51 100644
Binary files a/src/Mod/Path/Tools/Shape/endmill.fcstd and b/src/Mod/Path/Tools/Shape/endmill.fcstd differ