diff --git a/package.xml b/package.xml index 4f29cd2..20d371b 100644 --- a/package.xml +++ b/package.xml @@ -3,7 +3,7 @@ ZTools - Extended PartDesign workbench with velocity-focused tools, advanced datum creation, and Catppuccin Mocha theme. + Velocity-focused CAD tools injected into PartDesign, Assembly, and Spreadsheet contexts, plus Catppuccin Mocha theme. 0.1.0 diff --git a/ztools/InitGui.py b/ztools/InitGui.py index 78e114e..47700d1 100644 --- a/ztools/InitGui.py +++ b/ztools/InitGui.py @@ -1,356 +1,109 @@ -# ztools Workbench for FreeCAD 1.0+ -# Extended PartDesign replacement with velocity-focused tools +# ztools Command Provider for Kindred Create +# Injects ZTools commands into context toolbars via EditingContextResolver. +# No longer a standalone workbench — commands appear in the appropriate +# editing context (PartDesign body/feature, Assembly, Spreadsheet). import FreeCAD as App import FreeCADGui as Gui -class ZToolsWorkbench(Gui.Workbench): - """Extended PartDesign workbench with velocity-focused tools.""" +def _ensure_workbenches_loaded(): + """Activate dependent workbenches so their commands are registered.""" + wb_list = Gui.listWorkbenches() + for wb_name in ( + "PartDesignWorkbench", + "SketcherWorkbench", + "AssemblyWorkbench", + "SpreadsheetWorkbench", + ): + if wb_name in wb_list: + try: + Gui.activateWorkbench(wb_name) + except Exception as e: + App.Console.PrintWarning(f"ztools: could not init {wb_name}: {e}\n") - MenuText = "ztools" - ToolTip = "Extended PartDesign replacement for faster CAD workflows" - # Catppuccin Mocha themed icon - Icon = """ - /* XPM */ - static char * ztools_xpm[] = { - "16 16 5 1", - " c None", - ". c #313244", - "+ c #cba6f7", - "@ c #94e2d5", - "# c #45475a", - " ", - " ############ ", - " #..........# ", - " #.++++++++.# ", - " #.+......+.# ", - " #.....+++..# ", - " #....++....# ", - " #...++.....# ", - " #..++......# ", - " #.++.......# ", - " #.++++++++@# ", - " #..........# ", - " ############ ", - " ", - " ", - " "}; - """ +def _register(): + """Import ZTools commands and inject them into context toolbars.""" + _ensure_workbenches_loaded() - def Initialize(self): - """Called on workbench first activation.""" - # Load PartDesign and Sketcher workbenches to register their commands - # We need to actually activate them briefly to ensure commands are registered - # Activate dependent workbenches so their commands are registered. - # Use activateWorkbench() instead of calling Initialize() directly, - # since direct calls skip the C++ __Workbench__ injection step. - # Wrap each individually so one failure doesn't block the rest. - wb_list = Gui.listWorkbenches() - current_wb = Gui.activeWorkbench() - for wb_name in ( - "PartDesignWorkbench", - "SketcherWorkbench", - "AssemblyWorkbench", - "SpreadsheetWorkbench", - ): - if wb_name in wb_list: - try: - Gui.activateWorkbench(wb_name) - except Exception as e: - App.Console.PrintWarning(f"Could not initialize {wb_name}: {e}\n") - # Restore ztools as the active workbench - try: - Gui.activateWorkbench("ZToolsWorkbench") - except Exception: - pass + # Import all ZTools command modules (registers Gui commands) + from ztools.commands import ( # noqa: F401 + assembly_pattern_commands, + datum_commands, + pattern_commands, + pocket_commands, + spreadsheet_commands, + ) - # Command imports moved to module scope (after Gui.addWorkbench) so they - # are available before Initialize() runs. See end of file. + # Apply Catppuccin Mocha Spreadsheet colors + try: + from ztools.resources.theme import apply_spreadsheet_colors - # ===================================================================== - # PartDesign Structure Tools - # ===================================================================== - self.structure_tools = [ - "PartDesign_Body", - "PartDesign_NewSketch", - ] + apply_spreadsheet_colors() + except Exception as e: + App.Console.PrintWarning(f"ztools: could not apply spreadsheet colors: {e}\n") - # ===================================================================== - # PartDesign Reference Geometry (Datums) - # ===================================================================== - self.partdesign_datum_tools = [ - "PartDesign_Plane", - "PartDesign_Line", - "PartDesign_Point", - "PartDesign_CoordinateSystem", - "PartDesign_ShapeBinder", - "PartDesign_SubShapeBinder", - "PartDesign_Clone", - ] + # Register WorkbenchManipulator for injecting into native workbench toolbars + Gui.addWorkbenchManipulator(_ZToolsManipulator()) - # ===================================================================== - # PartDesign Additive Features - # ===================================================================== - self.additive_tools = [ - "PartDesign_Pad", - "PartDesign_Revolution", - "PartDesign_AdditiveLoft", - "PartDesign_AdditivePipe", - "PartDesign_AdditiveHelix", - ] - - # ===================================================================== - # PartDesign Additive Primitives (compound command with dropdown) - # ===================================================================== - self.additive_primitives = [ - "PartDesign_CompPrimitiveAdditive", - ] - - # ===================================================================== - # PartDesign Subtractive Features - # ===================================================================== - self.subtractive_tools = [ - "PartDesign_Pocket", - "PartDesign_Hole", - "PartDesign_Groove", - "PartDesign_SubtractiveLoft", - "PartDesign_SubtractivePipe", - "PartDesign_SubtractiveHelix", - ] - - # ===================================================================== - # PartDesign Subtractive Primitives (compound command with dropdown) - # ===================================================================== - self.subtractive_primitives = [ - "PartDesign_CompPrimitiveSubtractive", - ] - - # ===================================================================== - # PartDesign Transformation Features (Patterns) - # ===================================================================== - self.transformation_tools = [ - "PartDesign_Mirrored", - "PartDesign_LinearPattern", - "PartDesign_PolarPattern", - "PartDesign_MultiTransform", - ] - - # ===================================================================== - # PartDesign Dress-Up Features - # ===================================================================== - self.dressup_tools = [ - "PartDesign_Fillet", - "PartDesign_Chamfer", - "PartDesign_Draft", - "PartDesign_Thickness", - ] - - # ===================================================================== - # PartDesign Boolean Operations - # ===================================================================== - self.boolean_tools = [ - "PartDesign_Boolean", - ] - - # ===================================================================== - # Sketcher Tools (commonly used with PartDesign) - # ===================================================================== - self.sketcher_tools = [ - "Sketcher_NewSketch", - "Sketcher_EditSketch", - "Sketcher_MapSketch", - "Sketcher_ValidateSketch", - ] - - # ===================================================================== - # ZTools Custom Tools - # ===================================================================== - self.ztools_datum_tools = [ - "ZTools_DatumCreator", - "ZTools_DatumManager", - ] - - self.ztools_pattern_tools = [ - "ZTools_RotatedLinearPattern", - ] - - self.ztools_pocket_tools = [ - "ZTools_EnhancedPocket", - ] - - # ===================================================================== - # Assembly Workbench Tools (FreeCAD 1.0+) - # ===================================================================== - self.assembly_structure_tools = [ - "Assembly_CreateAssembly", - "Assembly_InsertLink", - "Assembly_InsertNewPart", - ] - - self.assembly_joint_tools = [ - "Assembly_CreateJointFixed", - "Assembly_CreateJointRevolute", - "Assembly_CreateJointCylindrical", - "Assembly_CreateJointSlider", - "Assembly_CreateJointBall", - "Assembly_CreateJointDistance", - "Assembly_CreateJointParallel", - "Assembly_CreateJointPerpendicular", - "Assembly_CreateJointAngle", - "Assembly_CreateJointRackPinion", - "Assembly_CreateJointScrew", - "Assembly_CreateJointGears", - "Assembly_CreateJointBelt", - ] - - self.assembly_management_tools = [ - "Assembly_ToggleGrounded", - "Assembly_SolveAssembly", - "Assembly_CreateView", - "Assembly_CreateBom", - "Assembly_ExportASMT", - ] - - # ===================================================================== - # ZTools Assembly Pattern Tools - # ===================================================================== - self.ztools_assembly_tools = [ - "ZTools_AssemblyLinearPattern", - "ZTools_AssemblyPolarPattern", - ] - - # ===================================================================== - # Spreadsheet Workbench Tools - # ===================================================================== - self.spreadsheet_tools = [ - "Spreadsheet_CreateSheet", - "Spreadsheet_Import", - "Spreadsheet_Export", - "Spreadsheet_SetAlias", - "Spreadsheet_MergeCells", - "Spreadsheet_SplitCell", - ] - - # ===================================================================== - # ZTools Spreadsheet Formatting Tools - # ===================================================================== - self.ztools_spreadsheet_tools = [ - "ZTools_SpreadsheetStyleBold", - "ZTools_SpreadsheetStyleItalic", - "ZTools_SpreadsheetStyleUnderline", - "ZTools_SpreadsheetAlignLeft", - "ZTools_SpreadsheetAlignCenter", - "ZTools_SpreadsheetAlignRight", - "ZTools_SpreadsheetBgColor", - "ZTools_SpreadsheetTextColor", - "ZTools_SpreadsheetQuickAlias", - ] - - # ===================================================================== - # Append Toolbars - # ===================================================================== - self.appendToolbar("Structure", self.structure_tools) - self.appendToolbar("Sketcher", self.sketcher_tools) - self.appendToolbar("Datums", self.partdesign_datum_tools) - self.appendToolbar("Additive", self.additive_tools + self.additive_primitives) - self.appendToolbar( - "Subtractive", self.subtractive_tools + self.subtractive_primitives + # Inject ZTools commands into editing context toolbars. + # These calls append commands to the named toolbar within the given context, + # so when the EditingContextResolver activates a context the injected + # commands appear alongside the native ones. + try: + Gui.injectEditingCommands( + "partdesign.body", + "Part Design Helper Features", + ["ZTools_DatumCreator", "ZTools_DatumManager"], ) - self.appendToolbar("Transformations", self.transformation_tools) - self.appendToolbar("Dress-Up", self.dressup_tools) - self.appendToolbar("Boolean", self.boolean_tools) - self.appendToolbar("Assembly", self.assembly_structure_tools) - self.appendToolbar("Assembly Joints", self.assembly_joint_tools) - self.appendToolbar("Assembly Management", self.assembly_management_tools) - self.appendToolbar("ztools Datums", self.ztools_datum_tools) - self.appendToolbar("ztools Patterns", self.ztools_pattern_tools) - self.appendToolbar("ztools Features", self.ztools_pocket_tools) - self.appendToolbar("ztools Assembly", self.ztools_assembly_tools) - self.appendToolbar("Spreadsheet", self.spreadsheet_tools) - self.appendToolbar("ztools Spreadsheet", self.ztools_spreadsheet_tools) - - # ===================================================================== - # Append Menus - # ===================================================================== - self.appendMenu("Structure", self.structure_tools) - self.appendMenu("Sketch", self.sketcher_tools) - self.appendMenu(["PartDesign", "Datums"], self.partdesign_datum_tools) - self.appendMenu( - ["PartDesign", "Additive"], self.additive_tools + self.additive_primitives + Gui.injectEditingCommands( + "partdesign.feature", + "Part Design Modeling Features", + ["ZTools_EnhancedPocket"], ) - self.appendMenu( - ["PartDesign", "Subtractive"], - self.subtractive_tools + self.subtractive_primitives, + Gui.injectEditingCommands( + "partdesign.feature", + "Part Design Transformation Features", + ["ZTools_RotatedLinearPattern"], ) - self.appendMenu(["PartDesign", "Transformations"], self.transformation_tools) - self.appendMenu(["PartDesign", "Dress-Up"], self.dressup_tools) - self.appendMenu(["PartDesign", "Boolean"], self.boolean_tools) - self.appendMenu(["Assembly", "Structure"], self.assembly_structure_tools) - self.appendMenu(["Assembly", "Joints"], self.assembly_joint_tools) - self.appendMenu(["Assembly", "Management"], self.assembly_management_tools) - self.appendMenu(["Spreadsheet", "Edit"], self.spreadsheet_tools) - self.appendMenu(["Spreadsheet", "Format"], self.ztools_spreadsheet_tools) - self.appendMenu( - "ztools", - self.ztools_datum_tools - + self.ztools_pattern_tools - + self.ztools_pocket_tools - + self.ztools_assembly_tools - + self.ztools_spreadsheet_tools, + Gui.injectEditingCommands( + "assembly.edit", + "Assembly Management", + ["ZTools_AssemblyLinearPattern", "ZTools_AssemblyPolarPattern"], ) + Gui.injectEditingCommands( + "spreadsheet", + "Spreadsheet", + [ + "ZTools_SpreadsheetStyleBold", + "ZTools_SpreadsheetStyleItalic", + "ZTools_SpreadsheetStyleUnderline", + "ZTools_SpreadsheetAlignLeft", + "ZTools_SpreadsheetAlignCenter", + "ZTools_SpreadsheetAlignRight", + "ZTools_SpreadsheetBgColor", + "ZTools_SpreadsheetTextColor", + "ZTools_SpreadsheetQuickAlias", + ], + ) + except Exception as e: + App.Console.PrintWarning(f"ztools: could not inject context commands: {e}\n") - App.Console.PrintMessage("ztools workbench initialized\n") - - def Activated(self): - """Called when workbench is activated.""" - # Apply Catppuccin Mocha colors to Spreadsheet preferences - try: - from ztools.resources.theme import apply_spreadsheet_colors - - apply_spreadsheet_colors() - except Exception as e: - App.Console.PrintWarning(f"Could not apply spreadsheet colors: {e}\n") - - App.Console.PrintMessage("ztools workbench activated\n") - - def Deactivated(self): - """Called when workbench is deactivated.""" - pass - - def GetClassName(self): - return "Gui::PythonWorkbench" - - -Gui.addWorkbench(ZToolsWorkbench()) + App.Console.PrintMessage("ztools commands registered\n") # --------------------------------------------------------------------------- -# Eager command registration -# --------------------------------------------------------------------------- -# Import command modules at module scope so Gui.addCommand() calls run before -# any workbench activates. This ensures the PartDesign manipulator can -# reference them regardless of workbench activation order (#52). - -from ztools.commands import ( - assembly_pattern_commands, - datum_commands, - pattern_commands, - pocket_commands, - spreadsheet_commands, -) - -# --------------------------------------------------------------------------- -# WorkbenchManipulator: inject ZTools commands into PartDesign workbench +# WorkbenchManipulator: inject ZTools commands into native workbench toolbars # --------------------------------------------------------------------------- -class _ZToolsPartDesignManipulator: - """Adds ZTools commands to PartDesign toolbars and menus.""" +class _ZToolsManipulator: + """Adds ZTools commands to PartDesign, Assembly, and Spreadsheet toolbars.""" def modifyToolBars(self): return [ + # PartDesign {"append": "ZTools_DatumCreator", "toolBar": "Part Design Helper Features"}, {"append": "ZTools_DatumManager", "toolBar": "Part Design Helper Features"}, { @@ -361,15 +114,47 @@ class _ZToolsPartDesignManipulator: "append": "ZTools_RotatedLinearPattern", "toolBar": "Part Design Transformation Features", }, + # Assembly + {"append": "ZTools_AssemblyLinearPattern", "toolBar": "Assembly"}, + {"append": "ZTools_AssemblyPolarPattern", "toolBar": "Assembly"}, + # Spreadsheet + {"append": "ZTools_SpreadsheetStyleBold", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetStyleItalic", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetStyleUnderline", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetAlignLeft", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetAlignCenter", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetAlignRight", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetBgColor", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetTextColor", "toolBar": "Spreadsheet"}, + {"append": "ZTools_SpreadsheetQuickAlias", "toolBar": "Spreadsheet"}, ] def modifyMenuBar(self): return [ - {"append": "ZTools_DatumCreator", "menuItem": "PartDesign_Body"}, - {"append": "ZTools_DatumManager", "menuItem": "PartDesign_Body"}, - {"append": "ZTools_EnhancedPocket", "menuItem": "PartDesign_Body"}, - {"append": "ZTools_RotatedLinearPattern", "menuItem": "PartDesign_Body"}, + { + "insert": "ZTools_DatumCreator", + "menuItem": "PartDesign_Boolean", + "after": "", + }, + { + "insert": "ZTools_DatumManager", + "menuItem": "ZTools_DatumCreator", + "after": "", + }, + { + "insert": "ZTools_EnhancedPocket", + "menuItem": "ZTools_DatumManager", + "after": "", + }, + { + "insert": "ZTools_RotatedLinearPattern", + "menuItem": "ZTools_EnhancedPocket", + "after": "", + }, ] -Gui.addWorkbenchManipulator(_ZToolsPartDesignManipulator()) +# Deferred registration — wait for dependent workbenches to finish loading +from PySide.QtCore import QTimer # noqa: E402 + +QTimer.singleShot(2000, _register)