Added arbitrary attributes to ToolBit - currently re-creating the existing ones.

This commit is contained in:
Markus Lampert
2019-11-01 13:42:37 -07:00
parent 54e2ff2fab
commit 5c3bff1e01
6 changed files with 313 additions and 161 deletions

View File

@@ -6,156 +6,209 @@
<rect>
<x>0</x>
<y>0</y>
<width>411</width>
<height>886</height>
<width>587</width>
<height>744</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Tool Bit</string>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QToolBox" name="toolBox">
<property name="currentIndex">
<number>0</number>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="toolName">
<property name="maxLength">
<number>50</number>
</property>
<property name="placeholderText">
<string>Display Name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="templatePath"/>
</item>
<item>
<widget class="QToolButton" name="templateSet">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="bitParams">
<property name="title">
<string>Bit Parameter</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
<widget class="QWidget" name="page">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>559</width>
<height>626</height>
</rect>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Point/Tip Angle</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="toolCuttingEdgeAngle">
<property name="text">
<string>180°</string>
</property>
<property name="unit" stdset="0">
<string>°</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Cutting Edge Height</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="toolCuttingEdgeHeight">
<property name="text">
<string>0.00</string>
</property>
<property name="unit" stdset="0">
<string>mm</string>
</property>
</widget>
</item>
</layout>
<attribute name="label">
<string>Shape</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Tool Bit</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>Name</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="toolName">
<property name="maxLength">
<number>50</number>
</property>
<property name="placeholderText">
<string>Display Name</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>Type</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLineEdit" name="templatePath"/>
</item>
<item>
<widget class="QToolButton" name="templateSet">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="bitParams">
<property name="title">
<string>Bit Parameter</string>
</property>
<layout class="QFormLayout" name="formLayout_2">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<item row="0" column="0">
<widget class="QLabel" name="label_9">
<property name="text">
<string>Point/Tip Angle</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Gui::InputField" name="toolCuttingEdgeAngle">
<property name="text">
<string>180°</string>
</property>
<property name="unit" stdset="0">
<string>°</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>Cutting Edge Height</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="Gui::InputField" name="toolCuttingEdgeHeight">
<property name="text">
<string>0.00</string>
</property>
<property name="unit" stdset="0">
<string>mm</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="image">
<property name="maximumSize">
<size>
<width>210</width>
<height>297</height>
</size>
</property>
<property name="text">
<string>Image</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>277</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="page_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>559</width>
<height>626</height>
</rect>
</property>
<attribute name="label">
<string>Attributes</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTableView" name="attrTable">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="MinimumExpanding">
<horstretch>0</horstretch>
<verstretch>2</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>300</height>
</size>
</property>
<property name="editTriggers">
<set>QAbstractItemView::AllEditTriggers</set>
</property>
<attribute name="horizontalHeaderStretchLastSection">
<bool>true</bool>
</attribute>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QWidget" name="widget_2" native="true">
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="image">
<property name="maximumSize">
<size>
<width>210</width>
<height>297</height>
</size>
</property>
<property name="text">
<string>Image</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>

View File

@@ -209,11 +209,7 @@ class SetupSheet:
for propName in op.properties():
prop = OpPropertyName(opName, propName)
if hasattr(self.obj, prop):
attr = getattr(self.obj, prop)
if hasattr(attr, 'UserString'):
settings[propName] = attr.UserString
else:
settings[propName] = attr
settings[propName] = PathUtil.getPropertyValueString(self.obj, prop)
attrs[opName] = settings
return attrs

View File

@@ -126,14 +126,23 @@ class PropertyFloat(Property):
def typeString(self):
return "Float"
def valueFromString(self, string):
return float(string)
class PropertyInteger(Property):
def typeString(self):
return "Integer"
def valueFromString(self, string):
return int(string)
class PropertyBool(Property):
def typeString(self):
return "Bool"
def valueFromString(self, string):
return bool(string)
class PropertyString(Property):
def typeString(self):
return "String"

View File

@@ -116,7 +116,8 @@ def updateConstraint(sketch, name, value):
PathLog.track(name, constraint.Type, 'unchanged')
break
PropertyGroupBit = 'Bit'
PropertyGroupBit = 'Bit'
PropertyGroupAttribute = 'Attribute'
class ToolBit(object):
@@ -128,7 +129,7 @@ class ToolBit(object):
obj.addProperty('App::PropertyFile', 'File', 'Base', translate('PathToolBit', 'The file of the tool'))
if templateFile is not None:
obj.BitTemplate = templateFile
self._setupBitFromTemplate(obj)
self._setupBitShape(obj)
self.onDocumentRestored(obj)
def __getstate__(self):
@@ -141,29 +142,35 @@ class ToolBit(object):
break
return None
def bitPropertyNames(self, obj):
def propertyNamesBit(self, obj):
return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupBit]
def propertyNamesAttribute(self, obj):
return [prop for prop in obj.PropertiesList if obj.getGroupOfProperty(prop) == PropertyGroupAttribute]
def onDocumentRestored(self, obj):
obj.setEditorMode('BitTemplate', 1)
obj.setEditorMode('BitBody', 2)
obj.setEditorMode('File', 1)
obj.setEditorMode('Shape', 2)
for prop in self.bitPropertyNames(obj):
for prop in self.propertyNamesBit(obj):
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)
def onChanged(self, obj, prop):
PathLog.track(obj.Label, prop)
if prop == 'BitTemplate' and not 'Restore' in obj.State:
self._setupBitFromTemplate(obj)
self._setupBitShape(obj)
#elif obj.getGroupOfProperty(prop) == PropertyGroupBit:
# self._updateBitShape(obj, [prop])
def _updateBitShape(self, obj, properties=None):
if not obj.BitBody is None:
if not properties:
properties = self.bitPropertyNames(obj)
properties = self.propertyNamesBit(obj)
for prop in properties:
for sketch in [o for o in obj.BitBody.Group if o.TypeId == 'Sketcher::SketchObject']:
PathLog.track(obj.Label, sketch.Label, prop)
@@ -203,7 +210,7 @@ class ToolBit(object):
PathLog.track(obj.Label)
self._removeBitBody(obj)
self._copyBitShape(obj)
for prop in self.bitPropertyNames(obj):
for prop in self.propertyNamesBit(obj):
obj.removeProperty(prop)
def loadBitBody(self, obj, force=False):
@@ -219,7 +226,7 @@ class ToolBit(object):
def unloadBitBody(self, obj):
self._removeBitBody(obj)
def _setupBitFromTemplate(self, obj, path=None):
def _setupBitShape(self, obj, path=None):
(doc, docOpened) = self._loadBitBody(obj, path)
obj.Label = doc.RootObjects[0].Label
@@ -277,15 +284,30 @@ class ToolBit(object):
attrs['name'] = obj.Label
attrs['template'] = obj.BitTemplate
params = {}
for prop in self.bitPropertyNames(obj):
params[prop] = PathUtil.getProperty(obj, prop).UserString
for name in self.propertyNamesBit(obj):
params[name] = PathUtil.getPropertyValueString(obj, name)
attrs['parameter'] = params
params = {}
for name in self.propertyNamesAttribute(obj):
params[name] = PathUtil.getPropertyValueString(obj, name)
attrs['attribute'] = params
return attrs
def Declaration(path):
with open(path, 'r') as fp:
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'))
class ToolBitFactory(object):
def CreateFromAttrs(self, attrs, name='ToolBit'):
@@ -296,6 +318,13 @@ class ToolBitFactory(object):
PathUtil.setProperty(obj, prop, params[prop])
obj.Proxy._updateBitShape(obj)
obj.Proxy.unloadBitBody(obj)
params = attrs['attribute']
proto = AttributePrototype()
for pname in params:
prop = proto.getProperty(pname)
val = prop.valueFromString(params[pname])
print("prop[%s] = %s (%s)" % (pname, params[pname], type(val)))
prop.setupProperty(obj, pname, PropertyGroupAttribute, prop.valueFromString(params[pname]))
return obj
def CreateFrom(self, path, name='ToolBit'):

View File

@@ -27,19 +27,23 @@ import FreeCADGui
import Path
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 copy
import math
import re
from PySide import QtGui
from PySide import QtCore, QtGui
PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule())
PathLog.trackModule(PathLog.thisModule())
LastPath = 'src/Mod/Path/Tools/Template'
# Qt translation handling
def translate(context, text, disambig=None):
return QtCore.QCoreApplication.translate(context, text, disambig)
class ToolBitEditor:
class ToolBitEditor(object):
'''UI and controller for editing a ToolBit.
The controller embeds the UI to the parentWidget which has to have a layout attached to it.
'''
@@ -56,6 +60,7 @@ class ToolBitEditor:
self.tool.BitTemplate = 'src/Mod/Path/Tools/Template/endmill-straight.fcstd'
self.tool.Proxy.loadBitBody(self.tool)
self.setupTool(self.tool)
self.setupAttributes(self.tool)
def setupTool(self, tool):
layout = self.form.bitParams.layout()
@@ -78,10 +83,63 @@ class ToolBitEditor:
else:
self.form.image.setPixmap(QtGui.QPixmap())
def setupAttributes(self, tool):
self.proto = PathToolBit.AttributePrototype()
self.props = sorted(self.proto.properties)
self.delegate = PathSetupSheetGui.Delegate(self.form)
self.model = QtGui.QStandardItemModel(len(self.props), 3, self.form)
self.model.setHorizontalHeaderLabels(['Set', 'Property', 'Value'])
for i, name in enumerate(self.props):
prop = self.proto.getProperty(name)
isset = hasattr(tool, name)
if isset:
prop.setValue(getattr(tool, name))
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)
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):
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):
self.refresh()
self.tool.Proxy.unloadBitBody(self.tool)
# get the attributes
for i, name in enumerate(self.props):
prop = self.proto.getProperty(name)
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.obj.removeProperty(name)
def reject(self):
self.tool.Proxy.unloadBitBody(self.tool)
pass
@@ -120,15 +178,15 @@ class ToolBitEditor:
self.form.blockSignals(False)
def selectTemplate(self):
global LastPath
path = self.tool.BitTemplate
if not path:
path = LastPath
path = PathPreferences.lastPathToolTemplate()
foo = QtGui.QFileDialog.getOpenFileName(self.form,
"Path - Tool Template",
path,
"*.fcstd")
if foo and foo[0]:
PathPreferences.setLastPathToolTemplate(os.path.dirname(foo[0]))
self.form.templatePath.setText(foo[0])
self.updateTemplate()

View File

@@ -63,6 +63,13 @@ def getProperty(obj, prop):
o, attr, name = _getProperty(obj, prop) # pylint: disable=unused-variable
return attr
def getPropertyValueString(obj, prop):
'''getPropertyValueString(obj, prop) ... answer a string represntation of an object's property's value.'''
attr = getProperty(obj, prop)
if hasattr(attr, 'UserString'):
return attr.UserString
return str(attr)
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