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)