From ce61fac68bf596d29c2c9f7b77d80ed93e425d8d Mon Sep 17 00:00:00 2001 From: Markus Lampert Date: Sat, 9 Sep 2017 20:08:04 -0700 Subject: [PATCH] Added buttons to use Z level of current selection for start or final depth. --- .../Gui/Resources/panels/PageDepthsEdit.ui | 111 ++++++++++++------ .../Gui/Resources/panels/PageHeightsEdit.ui | 37 ++++-- src/Mod/Path/PathScripts/PathOpGui.py | 87 ++++++++++++-- 3 files changed, 174 insertions(+), 61 deletions(-) diff --git a/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui index 65bb550ab9..fc838f466f 100644 --- a/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PageDepthsEdit.ui @@ -6,70 +6,105 @@ 0 0 - 394 - 219 + 270 + 235 Form - + - - - <html><head/><body><p>Start Depth of the operation. The highest point in Z-axis the operation needs to process.</p></body></html> - - - - Start Depth - + <html><head/><body><p>The depth of the operation which corresponds to the lowest value in Z-axis the operation needs to process.</p></body></html> - - - - Final Depth - - - - - - - <html><head/><body><p>The depth in Z-axis the operation moves downwards between layers.</p><p><br/></p><p>This value depends on the tool being used, the material to be cut, available cooling and many other factors. Please consult the tool manufacturers data sheets for the proper value.</p></body></html> - - - - - - - Step Down - - - + + + <html><head/><body><p>Depth of the final cut of the operation. Can be used to produce a cleaner finish.</p></body></html> + + + + Finish Depth - - - - <html><head/><body><p>Depth of the final cut of the operation. Can be used to produce a cleaner finish.</p></body></html> + + + + Step Down + + + + Final Depth + + + + + + + <html><head/><body><p>The depth in Z-axis the operation moves downwards between layers.</p><p><br/></p><p>This value depends on the tool being used, the material to be cut, available cooling and many other factors. Please consult the tool manufacturers data sheets for the proper value.</p></body></html> + + + + + + + <html><head/><body><p>Start Depth of the operation. The highest point in Z-axis the operation needs to process.</p></body></html> + + + + + + + ... + + + + :/icons/button_left.svg:/icons/button_left.svg + + + + + + + ... + + + + :/icons/button_left.svg:/icons/button_left.svg + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -85,6 +120,8 @@ finishDepth stepDown - + + + diff --git a/src/Mod/Path/Gui/Resources/panels/PageHeightsEdit.ui b/src/Mod/Path/Gui/Resources/panels/PageHeightsEdit.ui index 26f474de89..1cae0b407f 100644 --- a/src/Mod/Path/Gui/Resources/panels/PageHeightsEdit.ui +++ b/src/Mod/Path/Gui/Resources/panels/PageHeightsEdit.ui @@ -6,22 +6,29 @@ 0 0 - 400 - 447 + 282 + 242 Form - - + + + + + <html><head/><body><p>The height where lateral movement of the toolbit is not obstructed by any fixtures or the part / stock material itself.</p></body></html> + + + + <html><head/><body><p>The height above which it is safe to move the tool bit with rapid movements. Below this height all lateral and downward movements are performed with feed rate speeds.</p></body></html> - + Safe Height @@ -29,19 +36,25 @@ - - - <html><head/><body><p>The height where lateral movement of the toolbit is not obstructed by any fixtures or the part / stock material itself.</p></body></html> - - - - Clearance Height + + + + Qt::Vertical + + + + 20 + 40 + + + + diff --git a/src/Mod/Path/PathScripts/PathOpGui.py b/src/Mod/Path/PathScripts/PathOpGui.py index 8bad9fc562..1bd12e46d6 100644 --- a/src/Mod/Path/PathScripts/PathOpGui.py +++ b/src/Mod/Path/PathScripts/PathOpGui.py @@ -24,13 +24,15 @@ import FreeCAD import FreeCADGui +import PathScripts.PathGeom as PathGeom import PathScripts.PathGetPoint as PathGetPoint import PathScripts.PathLog as PathLog import PathScripts.PathSelection as PathSelection import PathScripts.PathOp as PathOp +import PathScripts.PathUtils as PathUtils import importlib -from PathScripts import PathUtils +from PathScripts.PathGeom import PathGeom from PySide import QtCore, QtGui __title__ = "Path Operation UI base classes" @@ -106,6 +108,10 @@ class ViewProvider(object): '''clearTaskPanel() ... internal callback function when editing has finished.''' self.panel = None + def unsetEdit(self, arg1, arg2): + if self.panel: + self.panel.reject(False) + def __getstate__(self): '''__getstate__() ... callback before receiver is saved to a file. Returns a dictionary with the receiver's resources as strings.''' @@ -244,6 +250,10 @@ class TaskPanelPage(object): In such a scenario the first property assignment will cause all changes in the UI of the other fields to be overwritten by setFields(obj). You have been warned.''' pass + def updateSelection(self, obj, sel): + '''updateSelection(obj, sel) ... overwrite to customize UI depending on current selection. + Can safely be overwritten by subclasses.''' + pass # helpers def selectInComboBox(self, name, combo): @@ -557,6 +567,7 @@ class TaskPanelDepthsPage(TaskPanelPage): self.form.stepDown.setText(FreeCAD.Units.Quantity(obj.StepDown.Value, FreeCAD.Units.Length).UserString) if PathOp.FeatureFinishDepth & self.features: self.form.finishDepth.setText(FreeCAD.Units.Quantity(obj.FinishDepth.Value, FreeCAD.Units.Length).UserString) + self.updateSelection(obj, FreeCADGui.Selection.getSelectionEx()) def getSignalsForUpdate(self, obj): signals = [] signals.append(self.form.startDepth.editingFinished) @@ -566,10 +577,40 @@ class TaskPanelDepthsPage(TaskPanelPage): if PathOp.FeatureFinishDepth & self.features: signals.append(self.form.finishDepth.editingFinished) return signals + def registerSignalHandlers(self, obj): + self.form.startDepthSet.clicked.connect(lambda: self.depthSet(obj, self.form.startDepth)) + self.form.finalDepthSet.clicked.connect(lambda: self.depthSet(obj, self.form.finalDepth)) def pageUpdateData(self, obj, prop): if prop in ['StartDepth', 'FinalDepth', 'StepDown', 'FinishDepth']: self.setFields(obj) + def depthSet(self, obj, widget): + z = self.selectionZLevel(FreeCADGui.Selection.getSelectionEx()) + if z is not None: + PathLog.info("depthSet(%.2f)" % z) + widget.setText(FreeCAD.Units.Quantity(z, FreeCAD.Units.Length).UserString) + self.getFields(obj) + else: + PathLog.info("depthSet(-)") + def selectionZLevel(self, sel): + if len(sel) == 1 and len(sel[0].SubObjects) == 1: + sub = sel[0].SubObjects[0] + if 'Vertex' == sub.ShapeType: + return sub.Z + if 'Edge' == sub.ShapeType and PathGeom.isRoughly(sub.Vertexes[0].Z, sub.Vertexes[1].Z): + return sub.Vertexes[0].Z + if 'Face' == sub.ShapeType and PathGeom.isRoughly(sub.BoundBox.ZLength, 0): + return sub.BoundBox.ZMax + return None + + def updateSelection(self, obj, sel): + if self.selectionZLevel(sel) is not None: + self.form.startDepthSet.setEnabled(True) + self.form.finalDepthSet.setEnabled(True) + else: + self.form.startDepthSet.setEnabled(False) + self.form.finalDepthSet.setEnabled(False) + class TaskPanel(object): ''' Generic TaskPanel implementation handling the standard Path operation layout. @@ -658,30 +699,36 @@ class TaskPanel(object): for page in self.featurePages: page.setClean() - def accept(self): + def accept(self, resetEdit=True): '''accept() ... callback invoked when user presses the task panel OK button.''' - FreeCAD.ActiveDocument.commitTransaction() - self.cleanup() + self.preCleanup() if self.isDirty: self.panelGetFields() - FreeCAD.ActiveDocument.recompute() + FreeCAD.ActiveDocument.commitTransaction() + self.cleanup(resetEdit) - def reject(self): + def reject(self, resetEdit=True): '''reject() ... callback invoked when user presses the task panel Cancel button.''' + self.preCleanup() FreeCAD.ActiveDocument.abortTransaction() - self.cleanup() if self.deleteOnReject: FreeCAD.ActiveDocument.openTransaction(translate("Path", "Uncreate AreaOp Operation")) FreeCAD.ActiveDocument.removeObject(self.obj.Name) FreeCAD.ActiveDocument.commitTransaction() - FreeCAD.ActiveDocument.recompute() + self.cleanup(resetEdit) + return True - def cleanup(self): + def preCleanup(self): + FreeCADGui.Selection.removeObserver(self) + FreeCADGui.Selection.removeObserver(self.s) + + def cleanup(self, resetEdit): '''cleanup() ... implements common cleanup tasks.''' self.obj.ViewObject.Proxy.clearTaskPanel() FreeCADGui.Control.closeDialog() - FreeCADGui.ActiveDocument.resetEdit() - FreeCADGui.Selection.removeObserver(self.s) + if resetEdit: + FreeCADGui.ActiveDocument.resetEdit() + FreeCAD.ActiveDocument.recompute() def clicked(self, button): '''clicked(button) ... callback invoked when the user presses any of the task panel buttons.''' @@ -710,8 +757,8 @@ class TaskPanel(object): def open(self): '''open() ... callback invoked when the task panel is opened.''' self.s = SelObserver(self.selectionFactory) - # install the function mode resident FreeCADGui.Selection.addObserver(self.s) + FreeCADGui.Selection.addObserver(self) def getStandardButtons(self): '''getStandardButtons() ... returns the Buttons for the task panel.''' @@ -741,6 +788,22 @@ class TaskPanel(object): def needsFullSpace(self): return True + def updateSelection(self): + sel = FreeCADGui.Selection.getSelectionEx() + for page in self.featurePages: + page.updateSelection(self.obj, sel) + + # SelectionObserver interface + def addSelection(self, doc, obj, sub, pnt): + self.updateSelection() + def removeSelection(self, doc, obj, sub): + self.updateSelection() + def setSelection(self, doc): + self.updateSelection() + def clearSelection(self, doc): + self.updateSelection() + + class SelObserver: '''Implementation of the selection observer used by the task panel. Its specific behaviour is determined by the factory function.'''