# SPDX-License-Identifier: LGPL-2.1-or-later # *************************************************************************** # * Copyright (c) 2019 sliptonic * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** from PySide import QtGui from PySide.QtCore import QT_TRANSLATE_NOOP import FreeCAD import FreeCADGui import Path import Path.Dressup.Boundary as PathDressupPathBoundary import Path.Dressup.Utils as PathDressup import PathGui if False: Path.Log.setLevel(Path.Log.Level.DEBUG, Path.Log.thisModule()) Path.Log.trackModule(Path.Log.thisModule()) else: Path.Log.setLevel(Path.Log.Level.INFO, Path.Log.thisModule()) translate = FreeCAD.Qt.translate class TaskPanel(object): def __init__(self, obj, viewProvider): self.obj = obj self.viewProvider = viewProvider self.form = FreeCADGui.PySideUic.loadUi(":/panels/DressupPathBoundary.ui") if obj.Stock: self.visibilityBoundary = obj.Stock.ViewObject.Visibility obj.Stock.ViewObject.Visibility = True else: self.visibilityBoundary = False self.buttonBox = None self.isDirty = False self.stockFromBase = None self.stockFromExisting = None self.stockCreateBox = None self.stockCreateCylinder = None self.stockEdit = None def getStandardButtons(self): return ( QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Cancel ) def modifyStandardButtons(self, buttonBox): self.buttonBox = buttonBox def setDirty(self): self.isDirty = True self.buttonBox.button(QtGui.QDialogButtonBox.Apply).setEnabled(True) def setClean(self): self.isDirty = False self.buttonBox.button(QtGui.QDialogButtonBox.Apply).setEnabled(False) def clicked(self, button): # callback for standard buttons if button == QtGui.QDialogButtonBox.Apply: self.updateDressup() FreeCAD.ActiveDocument.recompute() def abort(self): FreeCAD.ActiveDocument.abortTransaction() self.cleanup(False) def reject(self): FreeCAD.ActiveDocument.abortTransaction() self.cleanup(True) def accept(self): if self.isDirty: self.updateDressup() FreeCAD.ActiveDocument.commitTransaction() self.cleanup(True) def cleanup(self, gui): self.viewProvider.clearTaskPanel() if gui: FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() FreeCAD.ActiveDocument.recompute() if self.obj.Stock: self.obj.Stock.ViewObject.Visibility = self.visibilityBoundary def updateDressup(self): if self.obj.Inside != self.form.stockInside.isChecked(): self.obj.Inside = self.form.stockInside.isChecked() self.stockEdit.getFields(self.obj) self.setClean() def updateStockEditor(self, index, force=False): import Path.Main.Gui.Job as PathJobGui import Path.Main.Stock as PathStock def setupFromBaseEdit(): Path.Log.track(index, force) if force or not self.stockFromBase: self.stockFromBase = PathJobGui.StockFromBaseBoundBoxEdit( self.obj, self.form, force ) self.stockEdit = self.stockFromBase def setupCreateBoxEdit(): Path.Log.track(index, force) if force or not self.stockCreateBox: self.stockCreateBox = PathJobGui.StockCreateBoxEdit(self.obj, self.form, force) self.stockEdit = self.stockCreateBox def setupCreateCylinderEdit(): Path.Log.track(index, force) if force or not self.stockCreateCylinder: self.stockCreateCylinder = PathJobGui.StockCreateCylinderEdit( self.obj, self.form, force ) self.stockEdit = self.stockCreateCylinder def setupFromExisting(): Path.Log.track(index, force) if force or not self.stockFromExisting: self.stockFromExisting = PathJobGui.StockFromExistingEdit( self.obj, self.form, force ) if self.stockFromExisting.candidates(self.obj): self.stockEdit = self.stockFromExisting return True return False if index == -1: if self.obj.Stock is None or PathJobGui.StockFromBaseBoundBoxEdit.IsStock(self.obj): setupFromBaseEdit() elif PathJobGui.StockCreateBoxEdit.IsStock(self.obj): setupCreateBoxEdit() elif PathJobGui.StockCreateCylinderEdit.IsStock(self.obj): setupCreateCylinderEdit() elif PathJobGui.StockFromExistingEdit.IsStock(self.obj): setupFromExisting() else: Path.Log.error( translate("PathJob", "Unsupported stock object %s") % self.obj.Stock.Label ) else: if index == PathJobGui.StockFromBaseBoundBoxEdit.Index: setupFromBaseEdit() elif index == PathJobGui.StockCreateBoxEdit.Index: setupCreateBoxEdit() elif index == PathJobGui.StockCreateCylinderEdit.Index: setupCreateCylinderEdit() elif index == PathJobGui.StockFromExistingEdit.Index: if not setupFromExisting(): setupFromBaseEdit() index = -1 else: Path.Log.error( translate("PathJob", "Unsupported stock type %s (%d)") % (self.form.stock.currentText(), index) ) self.stockEdit.activate(self.obj, index == -1) def setupUi(self): self.updateStockEditor(-1, False) self.form.stockInside.setChecked(self.obj.Inside) self.form.stock.currentIndexChanged.connect(self.updateStockEditor) if hasattr(self.form.stockInside, "checkStateChanged"): # Qt version >= 6.7.0 self.form.stockInside.checkStateChanged.connect(self.setDirty) else: # Qt version < 6.7.0 self.form.stockInside.stateChanged.connect(self.setDirty) self.form.stockExtXneg.textChanged.connect(self.setDirty) self.form.stockExtXpos.textChanged.connect(self.setDirty) self.form.stockExtYneg.textChanged.connect(self.setDirty) self.form.stockExtYpos.textChanged.connect(self.setDirty) self.form.stockExtZneg.textChanged.connect(self.setDirty) self.form.stockExtZpos.textChanged.connect(self.setDirty) self.form.stockBoxLength.textChanged.connect(self.setDirty) self.form.stockBoxWidth.textChanged.connect(self.setDirty) self.form.stockBoxHeight.textChanged.connect(self.setDirty) self.form.stockCylinderRadius.textChanged.connect(self.setDirty) self.form.stockCylinderHeight.textChanged.connect(self.setDirty) class DressupPathBoundaryViewProvider(object): def __init__(self, vobj): self.attach(vobj) def dumps(self): return None def loads(self, state): return None def attach(self, vobj): self.vobj = vobj self.obj = vobj.Object self.panel = None def claimChildren(self): return [self.obj.Base, self.obj.Stock] def onDelete(self, vobj, args=None): if vobj.Object and vobj.Object.Proxy: vobj.Object.Proxy.onDelete(vobj.Object, args) return True def setEdit(self, vobj, mode=0): panel = TaskPanel(vobj.Object, self) self.setupTaskPanel(panel) return True def unsetEdit(self, vobj, mode=0): if self.panel: self.panel.abort() def setupTaskPanel(self, panel): self.panel = panel FreeCADGui.Control.closeDialog() FreeCADGui.Control.showDialog(panel) panel.setupUi() def clearTaskPanel(self): self.panel = None def getIcon(self): if getattr(PathDressup.baseOp(self.obj), "Active", True): return ":/icons/CAM_Dressup.svg" else: return ":/icons/CAM_OpActive.svg" def Create(base, name="DressupPathBoundary"): FreeCAD.ActiveDocument.openTransaction("Create a Boundary dressup") obj = PathDressupPathBoundary.Create(base, name) obj.ViewObject.Proxy = DressupPathBoundaryViewProvider(obj.ViewObject) obj.Base.ViewObject.Visibility = False obj.Stock.ViewObject.Visibility = False FreeCAD.ActiveDocument.commitTransaction() obj.ViewObject.Document.setEdit(obj.ViewObject, 0) return obj class CommandPathDressupPathBoundary: def GetResources(self): return { "Pixmap": "CAM_Dressup", "MenuText": QT_TRANSLATE_NOOP("CAM_DressupPathBoundary", "Boundary"), "ToolTip": QT_TRANSLATE_NOOP( "CAM_DressupPathBoundary", "Creates a boundary dress-up from a selected toolpath", ), } def IsActive(self): if FreeCAD.ActiveDocument is not None: for o in FreeCAD.ActiveDocument.Objects: if o.Name[:3] == "Job": return True return False def Activated(self): # check that the selection contains exactly what we want selection = FreeCADGui.Selection.getSelection() if len(selection) != 1: Path.Log.error( translate("CAM_DressupPathBoundary", "Please select one toolpath object") + "\n" ) return baseObject = selection[0] # everything ok! FreeCAD.ActiveDocument.openTransaction("Create Path Boundary Dress-up") FreeCADGui.addModule("Path.Dressup.Gui.Boundary") FreeCADGui.doCommand( "Path.Dressup.Gui.Boundary.Create(App.ActiveDocument.%s)" % baseObject.Name ) # FreeCAD.ActiveDocument.commitTransaction() # Final `commitTransaction()` called via TaskPanel.accept() FreeCAD.ActiveDocument.recompute() if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand("CAM_DressupPathBoundary", CommandPathDressupPathBoundary()) Path.Log.notice("Loading PathDressupPathBoundaryGui... done\n")