From c8f28695e3cd4df712a1910cf4456089a5787597 Mon Sep 17 00:00:00 2001 From: shai Date: Thu, 5 Dec 2024 16:39:13 +0200 Subject: [PATCH] Add task panel for Base Bend Shape. Add support for auto Camel-Casing properties --- Resources/panels/CreateBaseShape.ui | 190 +++++++++++++++++++++++----- SheetMetalBaseCmd.py | 187 +++++++++++++-------------- SheetMetalTools.py | 28 +++- 3 files changed, 275 insertions(+), 130 deletions(-) diff --git a/Resources/panels/CreateBaseShape.ui b/Resources/panels/CreateBaseShape.ui index 5fcf20d..aa20c78 100644 --- a/Resources/panels/CreateBaseShape.ui +++ b/Resources/panels/CreateBaseShape.ui @@ -6,10 +6,16 @@ 0 0 - 677 - 565 + 285 + 546 + + + 0 + 0 + + Generate Sheet Metal base shape @@ -17,51 +23,166 @@ - + - Sketch: + Sketch - - - Select - - - - - + - - - Extend sides and flange to close all gaps - - - Qt::RightToLeft + + + + 0 + 0 + - - Reverse Direction + + Bend Options + + + + + Bend Plane + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Radius + + + + + + + + 0 + 0 + + + + Thickness + + + + + + + + 0 + 0 + + + + + Outside + + + + + Inside + + + + + Centered + + + + + - - - Create the base shape as a new body - - - Qt::RightToLeft - - - Center on Plane + + + + 0 + 0 + - - true + + Extrude options + + + + + + 0 + 0 + + + + Length + + + + + + + + 0 + 0 + + + + + + + + Create the base shape as a new body + + + Symetric + + + + + + + Extend sides and flange to close all gaps + + + Reverse Direction + + + + @@ -79,6 +200,13 @@ + + + Gui::QuantitySpinBox + QWidget +
Gui/QuantitySpinBox.h
+
+
diff --git a/SheetMetalBaseCmd.py b/SheetMetalBaseCmd.py index 4a37b05..e23e0fb 100644 --- a/SheetMetalBaseCmd.py +++ b/SheetMetalBaseCmd.py @@ -29,7 +29,7 @@ translate = FreeCAD.Qt.translate icons_path = SheetMetalTools.icons_path panels_path = SheetMetalTools.panels_path - +smBaseDefaults = {} def modifiedWire(WireList, radius, thk, length, normal, Side, sign): # If sketch is one type, make a face by extruding & offset it to correct position @@ -110,51 +110,58 @@ def smBase( class SMBaseBend: def __init__(self, obj, sketch): '''"Add wall or Wall with radius bend"''' - _tip_ = translate("App::Property", "Bend Radius") - obj.addProperty( - "App::PropertyLength", "radius", "Parameters", _tip_ - ).radius = 1.0 - _tip_ = translate("App::Property", "Thickness of sheetmetal") - obj.addProperty( - "App::PropertyLength", "thickness", "Parameters", _tip_ - ).thickness = 1.0 _tip_ = translate("App::Property", "Bend Plane") obj.addProperty( "App::PropertyEnumeration", "BendSide", "Parameters", _tip_ ).BendSide = ["Outside", "Inside", "Middle"] - _tip_ = translate("App::Property", "Length of wall") - obj.addProperty( - "App::PropertyLength", "length", "Parameters", _tip_ - ).length = 100.0 _tip_ = translate("App::Property", "Wall Sketch object") obj.addProperty( "App::PropertyLink", "BendSketch", "Parameters", _tip_ ).BendSketch = sketch _tip_ = translate("App::Property", "Extrude Symmetric to Plane") - obj.addProperty( - "App::PropertyBool", "MidPlane", "Parameters", _tip_ - ).MidPlane = False - _tip_ = translate("App::Property", "Reverse Extrusion Direction") - obj.addProperty( - "App::PropertyBool", "Reverse", "Parameters", _tip_ - ).Reverse = False + self._addProperties(obj) obj.Proxy = self + def _addProperties(self, obj): + SheetMetalTools.smAddLengthProperty( + obj, + "Radius", + translate("App::Property", "Bend Radius"), + 1.0 + ) + SheetMetalTools.smAddLengthProperty( + obj, + "Thickness", + translate("App::Property", "Thickness of sheetmetal"), + 1.0 + ) + SheetMetalTools.smAddLengthProperty( + obj, + "Length", + translate("App::Property", "Length of wall"), + 100.0 + ) + SheetMetalTools.smAddBoolProperty( + obj, + "MidPlane", + FreeCAD.Qt.translate("App::Property", "Extrude Symmetric to Plane"), + False + ) + SheetMetalTools.smAddBoolProperty( + obj, + "Reverse", + FreeCAD.Qt.translate("App::Property", "Reverse Extrusion Direction"), + False + ) + + def execute(self, fp): '''"Print a short message when doing a recomputation, this method is mandatory"''' - if not hasattr(fp, "MidPlane"): - _tip_ = translate("App::Property", "Extrude Symmetric to Plane") - fp.addProperty( - "App::PropertyBool", "MidPlane", "Parameters", _tip_ - ).MidPlane = False - _tip_ = translate("App::Property", "Reverse Extrusion Direction") - fp.addProperty( - "App::PropertyBool", "Reverse", "Parameters", _tip_ - ).Reverse = False + self._addProperties(fp) s = smBase( - thk=fp.thickness.Value, - length=fp.length.Value, - radius=fp.radius.Value, + thk=fp.Thickness.Value, + length=fp.Length.Value, + radius=fp.Radius.Value, Side=fp.BendSide, midplane=fp.MidPlane, reverse=fp.Reverse, @@ -176,56 +183,65 @@ def execute(self, fp): # View Provider ########################################################################################################## - class SMBaseViewProvider: - "A View provider that nests children objects under the created one" - - def __init__(self, obj): - obj.Proxy = self - self.Object = obj.Object - - def attach(self, obj): - self.Object = obj.Object - return - - def updateData(self, fp, prop): - return + class SMBaseViewProvider(SheetMetalTools.SMViewProvider): + ''' Part / Part WB style ViewProvider ''' + def getIcon(self): + return os.path.join(icons_path, 'SheetMetal_AddBase.svg') + + def claimChildren(self): + objs = [] + if hasattr(self, "Object") and hasattr(self.Object, "BendSketch"): + objs.append(self.Object.BendSketch) + return objs - def getDisplayModes(self, obj): - modes = [] - return modes + def getTaskPanel(self, obj): + return SMBaseBendTaskPanel(obj) - def setDisplayMode(self, mode): - return mode - def onChanged(self, vp, prop): - return + + ########################################################################################################## + # Task Panel + ########################################################################################################## - def __getstate__(self): - # return {'ObjectName' : self.Object.Name} - return None + class SMBaseBendTaskPanel: + '''A TaskPanel for the Sheetmetal base bend command''' - def __setstate__(self, state): - self.loads(state) + def __init__(self, obj): + self.obj = obj + self.form = SheetMetalTools.taskLoadUI("CreateBaseShape.ui") + self.updateDisplay() + SheetMetalTools.taskConnectSelectionSingle( + self, self.form.pushSketch, self.form.txtSketch, obj, "BendSketch", ("Sketcher::SketchObject", []) + ) + SheetMetalTools.taskConnectSpin(self, self.form.spinRadius, "Radius") + SheetMetalTools.taskConnectSpin(self, self.form.spinThickness, "Thickness") + SheetMetalTools.taskConnectSpin(self, self.form.spinLength, "Length") + SheetMetalTools.taskConnectEnum(self, self.form.comboBendPlane, "BendSide") + SheetMetalTools.taskConnectCheck(self, self.form.checkSymetric, "MidPlane", self.midplaneChanged) + SheetMetalTools.taskConnectCheck(self, self.form.checkRevDirection, "Reverse") + + def isAllowedAlterSelection(self): + return True - # dumps and loads replace __getstate__ and __setstate__ post v. 0.21.2 - def dumps(self): - return None + def isAllowedAlterView(self): + return True + + def updateDisplay(self): + self.form.checkRevDirection.setVisible(self.obj.MidPlane is False) - def loads(self, state): - if state is not None: - import FreeCAD + def midplaneChanged(self, value): + self.updateDisplay() - doc = FreeCAD.ActiveDocument # crap - self.Object = doc.getObject(state["ObjectName"]) + def accept(self): + SheetMetalTools.taskAccept(self) + SheetMetalTools.taskSaveDefaults(self.obj, smBaseDefaults, ["Radius", "Thickness"]) + return True + + def reject(self): + SheetMetalTools.taskReject(self) - def claimChildren(self): - objs = [] - if hasattr(self, "Object") and hasattr(self.Object, "BendSketch"): - objs.append(self.Object.BendSketch) - return objs + #def retranslateUi(self, SMBendTaskPanel): - def getIcon(self): - return os.path.join(icons_path, "SheetMetal_AddBase.svg") ########################################################################################################## # Command @@ -250,27 +266,14 @@ def GetResources(self): } def Activated(self): - doc = FreeCAD.ActiveDocument - view = Gui.ActiveDocument.ActiveView - activeBody = None selobj = Gui.Selection.getSelectionEx()[0].Object - if hasattr(view, "getActiveObject"): - activeBody = view.getActiveObject("pdbody") - # if not SheetMetalTools.smIsOperationLegal(activeBody, selobj): - # return - doc.openTransaction("BaseBend") - if activeBody is None: - a = doc.addObject("Part::FeaturePython", "BaseBend") - SMBaseBend(a, selobj) - SMBaseViewProvider(a.ViewObject) - else: - # FreeCAD.Console.PrintLog("found active body: " + activeBody.Name) - a = doc.addObject("PartDesign::FeaturePython", "BaseBend") - SMBaseBend(a, selobj) - SMBaseViewProvider(a.ViewObject) - activeBody.addObject(a) - doc.recompute() - doc.commitTransaction() + newObj, activeBody = SheetMetalTools.smCreateNewObject(selobj, "BaseBend") + if newObj is None: + return + SMBaseBend(newObj, selobj) + SMBaseViewProvider(newObj.ViewObject) + SheetMetalTools.smAddNewObject( + selobj, newObj, activeBody, SMBaseBendTaskPanel) return def IsActive(self): diff --git a/SheetMetalTools.py b/SheetMetalTools.py index 84ac7de..2d8e400 100644 --- a/SheetMetalTools.py +++ b/SheetMetalTools.py @@ -158,7 +158,8 @@ def _taskToggleSingleSelMode(task, isChecked, button, textbox, obj, selProperty, smSingleSelObserver.button.toggle() if baseObject is not None: baseObject.Visibility=True - obj.Visibility=False + obj.Visibility=False + prop.Visibility=True button.activeTypes = allowedTypes button.activeObject = obj button.activeProperty = selProperty @@ -170,7 +171,8 @@ def _taskToggleSingleSelMode(task, isChecked, button, textbox, obj, selProperty, smSingleSelObserver.button = None if baseObject is not None: baseObject.Visibility=False - obj.Visibility=True + obj.Visibility=True + prop.Visibility=False task.activeSelection = {} taskPopulateSelectionSingle(textbox, prop) button.setText(button.saveText) @@ -212,7 +214,7 @@ def taskSingleSelectionChanged(button): def _taskUpdateValue(value, obj, objvar, callback): setattr(obj, objvar, value) try: # avoid intermitant changes - obj.Document.recompute() + obj.recompute() except: pass if callback is not None: @@ -220,22 +222,29 @@ def _taskUpdateValue(value, obj, objvar, callback): def _taskEditFinished(obj): obj.Document.recompute() + + def _getVarValue(obj, objvar): + if not hasattr(obj, objvar): + # Can happen if an old file is loaded and some props were renamed + obj.recompute() + return getattr(obj, objvar) def taskConnectSpin(task, formvar, objvar, callback = None): - formvar.setProperty("value", getattr(task.obj, objvar)) + formvar.setProperty("value", _getVarValue(task.obj, objvar)) Gui.ExpressionBinding(formvar).bind(task.obj, objvar) formvar.valueChanged.connect(lambda value: _taskUpdateValue(value, task.obj, objvar, callback)) formvar.editingFinished.connect(lambda: _taskEditFinished(task.obj)) def taskConnectCheck(task, formvar, objvar, callback = None): - formvar.setChecked(getattr(task.obj, objvar)) + formvar.setChecked(_getVarValue(task.obj, objvar)) if callback is not None: callback(formvar.isChecked()) formvar.toggled.connect(lambda value: _taskUpdateValue(value, task.obj, objvar, callback)) def taskConnectEnum(task, formvar, objvar, callback = None): + val = _getVarValue(task.obj, objvar) enumlist = task.obj.getEnumerationsOfProperty(objvar) - formvar.setProperty("currentIndex", enumlist.index(getattr(task.obj, objvar))) + formvar.setProperty("currentIndex", enumlist.index(val)) formvar.currentIndexChanged.connect(lambda value: _taskUpdateValue(value, task.obj, objvar, callback)) def taskAccept(task, addRemoveButton = None): @@ -380,7 +389,8 @@ def setEdit(self, vobj, mode): def unsetEdit(self, _vobj, _mode): Gui.Control.closeDialog() - self.Object.baseObject[0].ViewObject.Visibility = False + if hasattr(self.Object, "baseObject"): + self.Object.baseObject[0].ViewObject.Visibility = False self.Object.ViewObject.Visibility = True return False @@ -484,6 +494,10 @@ def smAddProperty(obj, proptype, name, proptip, defval=None, obj.addProperty(proptype, name, paramgroup, proptip) if defval is not None: setattr(obj, name, defval) + # replaced name is either given or automatically search for + # old lower case version of the same parameter + if replacedname is None and name[0].isupper(): + replacedname = name[0].lower() + name[1:] if replacedname is not None and hasattr(obj, replacedname): setattr(obj, name, getattr(obj, replacedname)) obj.removeProperty(replacedname)