# -*- coding: utf-8 -*- # *************************************************************************** # * 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 * # * * # *************************************************************************** import FreeCAD import FreeCADGui import PathGui as PGui # ensure Path/Gui/Resources are loaded import PathScripts import PathScripts.PathGui as PathGui import PathScripts.PathLog as PathLog import PathScripts.PathToolBitGui as PathToolBitGui import PathScripts.PathToolEdit as PathToolEdit import PathScripts.PathUtil as PathUtil from PySide import QtCore, QtGui # lazily loaded modules from lazy_loader.lazy_loader import LazyLoader Part = LazyLoader('Part', globals(), 'Part') # Qt translation handling def translate(context, text, disambig=None): return QtCore.QCoreApplication.translate(context, text, disambig) class ViewProvider: def __init__(self, vobj): vobj.Proxy = self self.vobj = vobj def attach(self, vobj): mode = 2 vobj.setEditorMode('LineWidth', mode) vobj.setEditorMode('MarkerColor', mode) vobj.setEditorMode('NormalColor', mode) vobj.setEditorMode('DisplayMode', mode) vobj.setEditorMode('BoundingBox', mode) vobj.setEditorMode('Selectable', mode) vobj.setEditorMode('ShapeColor', mode) vobj.setEditorMode('Transparency', mode) vobj.setEditorMode('Visibility', mode) self.vobj = vobj def __getstate__(self): return None def __setstate__(self, state): return None def getIcon(self): return ":/icons/Path_ToolController.svg" def onChanged(self, vobj, prop): # pylint: disable=unused-argument mode = 2 vobj.setEditorMode('LineWidth', mode) vobj.setEditorMode('MarkerColor', mode) vobj.setEditorMode('NormalColor', mode) vobj.setEditorMode('DisplayMode', mode) vobj.setEditorMode('BoundingBox', mode) vobj.setEditorMode('Selectable', mode) def onDelete(self, vobj, args=None): # pylint: disable=unused-argument PathUtil.clearExpressionEngine(vobj.Object) self.vobj.Object.Proxy.onDelete(vobj.Object, args) return True def updateData(self, vobj, prop): # this is executed when a property of the APP OBJECT changes # pylint: disable=unused-argument pass def setEdit(self, vobj=None, mode=0): if 0 == mode: if vobj is None: vobj = self.vobj FreeCADGui.Control.closeDialog() taskd = TaskPanel(vobj.Object) FreeCADGui.Control.showDialog(taskd) taskd.setupUi() FreeCAD.ActiveDocument.recompute() return True return False def unsetEdit(self, vobj, mode): # this is executed when the user cancels or terminates edit mode # pylint: disable=unused-argument return False def setupContextMenu(self, vobj, menu): # pylint: disable=unused-argument PathLog.track() for action in menu.actions(): menu.removeAction(action) action = QtGui.QAction(translate('Path', 'Edit'), menu) action.triggered.connect(self.setEdit) menu.addAction(action) def claimChildren(self): obj = self.vobj.Object if obj and obj.Proxy and not obj.Proxy.usesLegacyTool(obj): return [obj.Tool] return [] def Create(name='Default Tool', tool=None, toolNumber=1): PathLog.track(tool, toolNumber) obj = PathScripts.PathToolController.Create(name, tool, toolNumber) ViewProvider(obj.ViewObject) if not obj.Proxy.usesLegacyTool(obj): # ToolBits are visible by default, which is typically not what the user wants if tool and tool.ViewObject and tool.ViewObject.Visibility: tool.ViewObject.Visibility = False return obj class CommandPathToolController(object): # pylint: disable=no-init def GetResources(self): return {'Pixmap': 'Path_LengthOffset', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Path_ToolController", "Add Tool Controller to the Job"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Path_ToolController", "Add Tool Controller")} def selectedJob(self): if FreeCAD.ActiveDocument: sel = FreeCADGui.Selection.getSelectionEx() if sel and sel[0].Object.Name[:3] == 'Job': return sel[0].Object jobs = [o for o in FreeCAD.ActiveDocument.Objects if o.Name[:3] == 'Job'] if 1 == len(jobs): return jobs[0] return None def IsActive(self): return self.selectedJob() is not None def Activated(self): PathLog.track() job = self.selectedJob() if job: tool = PathToolBitGui.ToolBitSelector().getTool() if tool: toolNr = None for tc in job.Tools.Group: if tc.Tool == tool: toolNr = tc.ToolNumber break if not toolNr: toolNr = max([tc.ToolNumber for tc in job.Tools.Group]) + 1 tc = Create("TC: {}".format(tool.Label), tool, toolNr) job.Proxy.addToolController(tc) FreeCAD.ActiveDocument.recompute() class ToolControllerEditor(object): def __init__(self, obj, asDialog): self.form = FreeCADGui.PySideUic.loadUi(":/panels/DlgToolControllerEdit.ui") if not asDialog: self.form.buttonBox.hide() self.obj = obj self.vertFeed = PathGui.QuantitySpinBox(self.form.vertFeed, obj, 'VertFeed') self.horizFeed = PathGui.QuantitySpinBox(self.form.horizFeed, obj, 'HorizFeed') self.vertRapid = PathGui.QuantitySpinBox(self.form.vertRapid, obj, 'VertRapid') self.horizRapid = PathGui.QuantitySpinBox(self.form.horizRapid, obj, 'HorizRapid') if obj.Proxy.usesLegacyTool(obj): self.editor = PathToolEdit.ToolEditor(obj.Tool, self.form.toolEditor) else: self.editor = None self.form.toolBox.widget(1).hide() self.form.toolBox.removeItem(1) def updateUi(self): tc = self.obj self.form.tcName.setText(tc.Label) self.form.tcNumber.setValue(tc.ToolNumber) self.horizFeed.updateSpinBox() self.horizRapid.updateSpinBox() self.vertFeed.updateSpinBox() self.vertRapid.updateSpinBox() self.form.spindleSpeed.setValue(tc.SpindleSpeed) index = self.form.spindleDirection.findText(tc.SpindleDir, QtCore.Qt.MatchFixedString) if index >= 0: self.form.spindleDirection.setCurrentIndex(index) if self.editor: self.editor.updateUI() def updateToolController(self): tc = self.obj try: tc.Label = self.form.tcName.text() tc.ToolNumber = self.form.tcNumber.value() self.horizFeed.updateProperty() self.vertFeed.updateProperty() self.horizRapid.updateProperty() self.vertRapid.updateProperty() tc.SpindleSpeed = self.form.spindleSpeed.value() tc.SpindleDir = self.form.spindleDirection.currentText() if self.editor: self.editor.updateTool() tc.Tool = self.editor.tool except Exception as e: PathLog.error(translate("PathToolController", "Error updating TC: %s") % e) def refresh(self): self.form.blockSignals(True) self.updateToolController() self.updateUi() self.form.blockSignals(False) def setupUi(self): if self.editor: self.editor.setupUI() self.form.tcName.editingFinished.connect(self.refresh) self.form.horizFeed.editingFinished.connect(self.refresh) self.form.vertFeed.editingFinished.connect(self.refresh) self.form.horizRapid.editingFinished.connect(self.refresh) self.form.vertRapid.editingFinished.connect(self.refresh) self.form.spindleSpeed.editingFinished.connect(self.refresh) self.form.spindleDirection.currentIndexChanged.connect(self.refresh) class TaskPanel: def __init__(self, obj): self.editor = ToolControllerEditor(obj, False) self.form = self.editor.form self.updating = False self.toolrep = None self.obj = obj def accept(self): self.getFields() FreeCADGui.ActiveDocument.resetEdit() FreeCADGui.Control.closeDialog() if self.toolrep: FreeCAD.ActiveDocument.removeObject(self.toolrep.Name) FreeCAD.ActiveDocument.recompute() def reject(self): FreeCADGui.Control.closeDialog() if self.toolrep: FreeCAD.ActiveDocument.removeObject(self.toolrep.Name) FreeCAD.ActiveDocument.recompute() def getFields(self): self.editor.updateToolController() self.obj.Proxy.execute(self.obj) def setFields(self): self.editor.updateUi() if self.toolrep: tool = self.obj.Tool radius = float(tool.Diameter) / 2 length = tool.CuttingEdgeHeight t = Part.makeCylinder(radius, length) self.toolrep.Shape = t def edit(self, item, column): # pylint: disable=unused-argument if not self.updating: self.resetObject() def resetObject(self, remove=None): # pylint: disable=unused-argument "transfers the values from the widget to the object" FreeCAD.ActiveDocument.recompute() def setupUi(self): if self.editor.editor: t = Part.makeCylinder(1, 1) self.toolrep = FreeCAD.ActiveDocument.addObject("Part::Feature", "tool") self.toolrep.Shape = t self.setFields() self.editor.setupUi() class DlgToolControllerEdit: def __init__(self, obj): self.editor = ToolControllerEditor(obj, True) self.editor.updateUi() self.editor.setupUi() self.obj = obj def exec_(self): restoreTC = self.obj.Proxy.templateAttrs(self.obj) rc = False if not self.editor.form.exec_(): PathLog.info("revert") self.obj.Proxy.setFromTemplate(self.obj, restoreTC) rc = True return rc if FreeCAD.GuiUp: # register the FreeCAD command FreeCADGui.addCommand('Path_ToolController', CommandPathToolController()) FreeCAD.Console.PrintLog("Loading PathToolControllerGui... done\n")