diff --git a/src/Mod/Draft/draftguitools/gui_lines.py b/src/Mod/Draft/draftguitools/gui_lines.py index d297d34ac8..eba740fb45 100644 --- a/src/Mod/Draft/draftguitools/gui_lines.py +++ b/src/Mod/Draft/draftguitools/gui_lines.py @@ -122,9 +122,13 @@ class Line(gui_base_original.Creator): if not self.isWire and len(self.node) == 2: self.finish(False, cont=True) if len(self.node) > 2: + # The wire is closed if (self.point - self.node[0]).Length < utils.tolerance(): self.undolast() - self.finish(True, cont=True) + if len(self.node) > 2: + self.finish(True, cont=True) + else: + self.finish(False, cont=True) def finish(self, closed=False, cont=False): """Terminate the operation and close the polyline if asked. diff --git a/src/Mod/Path/Gui/Resources/panels/PathEdit.ui b/src/Mod/Path/Gui/Resources/panels/PathEdit.ui index d71044c96f..44d768ff13 100644 --- a/src/Mod/Path/Gui/Resources/panels/PathEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PathEdit.ui @@ -31,8 +31,8 @@ 0 0 - 549 - 628 + 146 + 378 @@ -112,8 +112,8 @@ 0 0 - 98 - 28 + 96 + 26 @@ -281,7 +281,7 @@ G54 - Checked + Unchecked @@ -431,8 +431,8 @@ 0 0 - 536 - 1291 + 545 + 896 @@ -1002,8 +1002,8 @@ 0 0 - 419 - 548 + 213 + 321 @@ -1096,7 +1096,7 @@ - + <html><head/><body><p>ClearanceHeightOffset - can be used by expressions to set the default ClearanceHeight for new operations.</p><p><br/></p><p>Default: &quot;3 mm&quot;</p></body></html> @@ -1123,7 +1123,7 @@ - + <html><head/><body><p>SafeHeightOffset can be for expressions to set the SafeHeight for new operations.</p><p><br/></p><p>Default: &quot;5 mm&quot;</p></body></html> @@ -1185,8 +1185,8 @@ 0 0 - 549 - 628 + 317 + 173 @@ -1285,8 +1285,8 @@ 0 0 - 208 - 160 + 138 + 112 @@ -1310,7 +1310,7 @@ - + 0 @@ -1330,7 +1330,7 @@ - + 0 diff --git a/src/Mod/Path/PathScripts/PathJob.py b/src/Mod/Path/PathScripts/PathJob.py index a6c027b722..8ddf574c13 100644 --- a/src/Mod/Path/PathScripts/PathJob.py +++ b/src/Mod/Path/PathScripts/PathJob.py @@ -56,6 +56,9 @@ class JobTemplate: PostProcessor = 'Post' PostProcessorArgs = 'PostArgs' PostProcessorOutputFile = 'Output' + Fixtures = 'Fixtures' + OrderOutputBy = 'OrderOutputBy' + SplitOutput = 'SplitOutput' SetupSheet = 'SetupSheet' Stock = 'Stock' # TCs are grouped under Tools in a job, the template refers to them directly though @@ -121,7 +124,6 @@ class ObjectJob: obj.addProperty("App::PropertyLink", "Stock", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Solid object to be used as stock.")) obj.addProperty("App::PropertyLink", "Operations", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Compound path of all operations in the order they are processed.")) - #obj.addProperty("App::PropertyLinkList", "ToolController", "Base", QtCore.QT_TRANSLATE_NOOP("PathJob", "Collection of tool controllers available for this job.")) obj.addProperty("App::PropertyBool", "SplitOutput", "Output", QtCore.QT_TRANSLATE_NOOP("PathJob", "Split output into multiple gcode files")) obj.addProperty("App::PropertyEnumeration", "OrderOutputBy", "WCS", QtCore.QT_TRANSLATE_NOOP("PathJob", "If multiple WCS, order the output this way")) @@ -350,6 +352,15 @@ class ObjectJob: if attrs.get(JobTemplate.Stock): obj.Stock = PathStock.CreateFromTemplate(obj, attrs.get(JobTemplate.Stock)) + if attrs.get(JobTemplate.Fixtures): + obj.Fixtures = [x for y in attrs.get(JobTemplate.Fixtures) for x in y] + + if attrs.get(JobTemplate.OrderOutputBy): + obj.OrderOutputBy = attrs.get(JobTemplate.OrderOutputBy) + + if attrs.get(JobTemplate.SplitOutput): + obj.SplitOutput = attrs.get(JobTemplate.SplitOutput) + PathLog.debug("setting tool controllers (%d)" % len(tcs)) obj.Tools.Group = tcs else: @@ -364,6 +375,9 @@ class ObjectJob: if obj.PostProcessor: attrs[JobTemplate.PostProcessor] = obj.PostProcessor attrs[JobTemplate.PostProcessorArgs] = obj.PostProcessorArgs + attrs[JobTemplate.Fixtures] = [{f: True} for f in obj.Fixtures] + attrs[JobTemplate.OrderOutputBy] = obj.OrderOutputBy + attrs[JobTemplate.SplitOutput] = obj.SplitOutput if obj.PostProcessorOutputFile: attrs[JobTemplate.PostProcessorOutputFile] = obj.PostProcessorOutputFile attrs[JobTemplate.GeometryTolerance] = str(obj.GeometryTolerance.Value) diff --git a/src/Mod/Path/PathScripts/PathSetupSheet.py b/src/Mod/Path/PathScripts/PathSetupSheet.py index 87203d6a95..9cdfb0596c 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheet.py +++ b/src/Mod/Path/PathScripts/PathSetupSheet.py @@ -34,7 +34,7 @@ __doc__ = "A container for all default values and job specific configuration val _RegisteredOps = {} -PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) +PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) # PathLog.trackModule(PathLog.thisModule()) @@ -55,11 +55,15 @@ class Template: StartDepthExpression = 'StartDepthExpression' FinalDepthExpression = 'FinalDepthExpression' StepDownExpression = 'StepDownExpression' + Fixtures = 'Fixtures' + OrderOutputBy = 'OrderOutputBy' + SplitOutput = 'SplitOutput' All = [HorizRapid, VertRapid, CoolantMode, SafeHeightOffset, SafeHeightExpression, ClearanceHeightOffset, ClearanceHeightExpression, StartDepthExpression, FinalDepthExpression, StepDownExpression] def _traverseTemplateAttributes(attrs, codec): + PathLog.debug(attrs) coded = {} for key, value in PathUtil.keyValueIter(attrs): if type(value) == dict: diff --git a/src/Mod/Path/PathScripts/PathSetupSheetGui.py b/src/Mod/Path/PathScripts/PathSetupSheetGui.py index 7b06816ed7..d2ceb3956b 100644 --- a/src/Mod/Path/PathScripts/PathSetupSheetGui.py +++ b/src/Mod/Path/PathScripts/PathSetupSheetGui.py @@ -26,7 +26,6 @@ import PathScripts.PathGui as PathGui import PathScripts.PathIconViewProvider as PathIconViewProvider import PathScripts.PathLog as PathLog import PathScripts.PathSetupSheet as PathSetupSheet -# import PathScripts.PathSetupSheetOpPrototype as PathSetupSheetOpPrototype import PathScripts.PathSetupSheetOpPrototypeGui as PathSetupSheetOpPrototypeGui import PathScripts.PathUtil as PathUtil @@ -37,18 +36,22 @@ __author__ = "sliptonic (Brad Collette)" __url__ = "https://www.freecadweb.org" __doc__ = "Task panel editor for a SetupSheet" + # Qt translation handling def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) + LOGLEVEL = False + if LOGLEVEL: PathLog.setLevel(PathLog.Level.DEBUG, PathLog.thisModule()) PathLog.trackModule(PathLog.thisModule()) else: PathLog.setLevel(PathLog.Level.INFO, PathLog.thisModule()) + class ViewProvider: '''ViewProvider for a SetupSheet. It's sole job is to provide an icon and invoke the TaskPanel on edit.''' @@ -100,14 +103,11 @@ class ViewProvider: def doubleClicked(self, vobj): self.setEdit(vobj) + class Delegate(QtGui.QStyledItemDelegate): PropertyRole = QtCore.Qt.UserRole + 1 EditorRole = QtCore.Qt.UserRole + 2 - - #def paint(self, painter, option, index): - # #PathLog.track(index.column(), type(option)) - def createEditor(self, parent, option, index): # pylint: disable=unused-argument if index.data(self.EditorRole) is None: @@ -130,6 +130,7 @@ class Delegate(QtGui.QStyledItemDelegate): # pylint: disable=unused-argument widget.setGeometry(option.rect) + class OpTaskPanel: '''Editor for an operation's property default values. The implementation is a simplified generic property editor with basically 3 fields @@ -168,16 +169,16 @@ class OpTaskPanel: self.model = QtGui.QStandardItemModel(len(self.props), 3, self.form) self.model.setHorizontalHeaderLabels(['Set', 'Property', 'Value']) - for i,name in enumerate(self.props): + for i, name in enumerate(self.props): prop = self.prototype.getProperty(name) isset = hasattr(self.obj, self.propertyName(name)) if isset: prop.setValue(getattr(self.obj, self.propertyName(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, Delegate.PropertyRole) - self.model.setData(self.model.index(i, 2), prop.displayString(), QtCore.Qt.DisplayRole) + self.model.setData(self.model.index(i, 1), name, QtCore.Qt.EditRole) + self.model.setData(self.model.index(i, 2), prop, 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('') @@ -206,7 +207,7 @@ class OpTaskPanel: def accept(self): propertiesCreatedRemoved = False - for i,name in enumerate(self.props): + for i, name in enumerate(self.props): prop = self.prototype.getProperty(name) propName = self.propertyName(name) enabled = self.model.item(i, 0).checkState() == QtCore.Qt.Checked @@ -229,7 +230,7 @@ class OpsDefaultEditor: def __init__(self, obj, form): self.form = form self.obj = obj - self.ops = sorted([OpTaskPanel(self.obj, name, op) for name, op in PathUtil.keyValueIter(PathSetupSheet._RegisteredOps)], key = lambda op: op.name) # pylint: disable=protected-access + self.ops = sorted([OpTaskPanel(self.obj, name, op) for name, op in PathUtil.keyValueIter(PathSetupSheet._RegisteredOps)], key=lambda op: op.name) if form: parent = form.tabOpDefaults for op in self.ops: @@ -245,10 +246,6 @@ class OpsDefaultEditor: def accept(self): if any([op.accept() for op in self.ops]): PathLog.track() - #sel = FreeCADGui.Selection.getSelection() - #FreeCADGui.Selection.clearSelection() - #for o in sel: - # FreeCADGui.Selection.addSelection(o) def getFields(self): pass @@ -264,7 +261,7 @@ class OpsDefaultEditor: self.currentOp = self.form.opDefaultOp.itemData(current) self.currentOp.form.show() - def updateModel(self, recomp = True): + def updateModel(self, recomp=True): PathLog.track() self.getFields() self.updateUI() @@ -281,6 +278,7 @@ class OpsDefaultEditor: if self.form: self.form.opDefaultOp.currentIndexChanged.connect(self.updateUI) + class GlobalEditor(object): '''Editor for the global properties which affect almost every operation.''' @@ -293,7 +291,6 @@ class GlobalEditor(object): self.safeHeightOffs = None self.rapidHorizontal = None self.rapidVertical = None - #self.coolantMode = None def reject(self): pass @@ -308,16 +305,15 @@ class GlobalEditor(object): if val != value: PathUtil.setProperty(self.obj, name, value) - updateExpression('StartDepthExpression', self.form.setupStartDepthExpr) - updateExpression('FinalDepthExpression', self.form.setupFinalDepthExpr) - updateExpression('StepDownExpression', self.form.setupStepDownExpr) - updateExpression('ClearanceHeightExpression', self.form.setupClearanceHeightExpr) - updateExpression('SafeHeightExpression', self.form.setupSafeHeightExpr) + updateExpression('StartDepthExpression', self.form.setupStartDepthExpr) + updateExpression('FinalDepthExpression', self.form.setupFinalDepthExpr) + updateExpression('StepDownExpression', self.form.setupStepDownExpr) + updateExpression('ClearanceHeightExpression', self.form.setupClearanceHeightExpr) + updateExpression('SafeHeightExpression', self.form.setupSafeHeightExpr) self.clearanceHeightOffs.updateProperty() self.safeHeightOffs.updateProperty() self.rapidVertical.updateProperty() self.rapidHorizontal.updateProperty() - #self.coolantMode.updateProperty() self.obj.CoolantMode = self.form.setupCoolantMode.currentText() def selectInComboBox(self, name, combo): @@ -330,18 +326,18 @@ class GlobalEditor(object): def updateUI(self): PathLog.track() - self.form.setupStartDepthExpr.setText( self.obj.StartDepthExpression) - self.form.setupFinalDepthExpr.setText( self.obj.FinalDepthExpression) - self.form.setupStepDownExpr.setText( self.obj.StepDownExpression) - self.form.setupClearanceHeightExpr.setText( self.obj.ClearanceHeightExpression) - self.form.setupSafeHeightExpr.setText( self.obj.SafeHeightExpression) + self.form.setupStartDepthExpr.setText(self.obj.StartDepthExpression) + self.form.setupFinalDepthExpr.setText(self.obj.FinalDepthExpression) + self.form.setupStepDownExpr.setText(self.obj.StepDownExpression) + self.form.setupClearanceHeightExpr.setText(self.obj.ClearanceHeightExpression) + self.form.setupSafeHeightExpr.setText(self.obj.SafeHeightExpression) self.clearanceHeightOffs.updateSpinBox() self.safeHeightOffs.updateSpinBox() self.rapidVertical.updateSpinBox() self.rapidHorizontal.updateSpinBox() self.selectInComboBox(self.obj.CoolantMode, self.form.setupCoolantMode) - def updateModel(self, recomp = True): + def updateModel(self, recomp=True): PathLog.track() self.getFields() self.updateUI() @@ -359,6 +355,7 @@ class GlobalEditor(object): self.form.setupCoolantMode.addItems(self.obj.CoolantModes) self.setFields() + class TaskPanel: '''TaskPanel for the SetupSheet - if it is being edited directly.''' @@ -387,8 +384,6 @@ class TaskPanel: FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() - #FreeCADGui.Selection.removeObserver(self.s) - #FreeCAD.ActiveDocument.recompute() def getFields(self): self.globalEditor.getFields() @@ -411,11 +406,13 @@ class TaskPanel: self.globalEditor.setupUi() self.opsEditor.setupUi() -def Create(name = 'SetupSheet'): - '''Create(name = 'SetupSheet') ... creates a new setup sheet''' + +def Create(name='SetupSheet'): + '''Create(name='SetupSheet') ... creates a new setup sheet''' FreeCAD.ActiveDocument.openTransaction(translate("Path_Job", "Create Job")) ssheet = PathSetupSheet.Create(name) PathIconViewProvider.Attach(ssheet, name) return ssheet + PathIconViewProvider.RegisterViewProvider('SetupSheet', ViewProvider)