"""Editing context and overlay registration wrappers. Routes through the ``kcsdk`` C++ module when available, falling back to the legacy ``FreeCADGui`` Python bindings for backwards compatibility. """ import FreeCAD # Try to import the C++ SDK module; None if not yet built/installed. try: import kcsdk as _kcsdk except ImportError: _kcsdk = None def _gui(): """Lazy import of FreeCADGui (not available in console mode).""" import FreeCADGui return FreeCADGui def register_context(context_id, label, color, toolbars, match, priority=50): """Register an editing context. Parameters ---------- context_id : str Unique identifier (e.g. ``"myaddon.edit"``). label : str Display label template. Supports ``{name}`` placeholder. color : str Hex color for the breadcrumb (e.g. ``"#f38ba8"``). toolbars : list[str] Toolbar names to show when this context is active. match : callable Zero-argument callable returning *True* when this context is active. priority : int, optional Higher values are checked first. Default 50. """ if not isinstance(context_id, str): raise TypeError(f"context_id must be str, got {type(context_id).__name__}") if not isinstance(toolbars, list): raise TypeError(f"toolbars must be list, got {type(toolbars).__name__}") if not callable(match): raise TypeError("match must be callable") try: if _kcsdk is not None: _kcsdk.register_context(context_id, label, color, toolbars, match, priority) else: _gui().registerEditingContext( context_id, label, color, toolbars, match, priority ) except Exception as e: FreeCAD.Console.PrintWarning( f"kindred_sdk: Failed to register context '{context_id}': {e}\n" ) def unregister_context(context_id): """Remove a previously registered editing context.""" if not isinstance(context_id, str): raise TypeError(f"context_id must be str, got {type(context_id).__name__}") try: if _kcsdk is not None: _kcsdk.unregister_context(context_id) else: _gui().unregisterEditingContext(context_id) except Exception as e: FreeCAD.Console.PrintWarning( f"kindred_sdk: Failed to unregister context '{context_id}': {e}\n" ) def register_overlay(overlay_id, toolbars, match): """Register an editing overlay. Overlays add toolbars to whatever context is currently active when *match* returns True. Parameters ---------- overlay_id : str Unique overlay identifier. toolbars : list[str] Toolbar names to append. match : callable Zero-argument callable returning *True* when the overlay applies. """ if not isinstance(overlay_id, str): raise TypeError(f"overlay_id must be str, got {type(overlay_id).__name__}") if not isinstance(toolbars, list): raise TypeError(f"toolbars must be list, got {type(toolbars).__name__}") if not callable(match): raise TypeError("match must be callable") try: if _kcsdk is not None: _kcsdk.register_overlay(overlay_id, toolbars, match) else: _gui().registerEditingOverlay(overlay_id, toolbars, match) except Exception as e: FreeCAD.Console.PrintWarning( f"kindred_sdk: Failed to register overlay '{overlay_id}': {e}\n" ) def unregister_overlay(overlay_id): """Remove a previously registered editing overlay.""" if not isinstance(overlay_id, str): raise TypeError(f"overlay_id must be str, got {type(overlay_id).__name__}") try: if _kcsdk is not None: _kcsdk.unregister_overlay(overlay_id) else: _gui().unregisterEditingOverlay(overlay_id) except Exception as e: FreeCAD.Console.PrintWarning( f"kindred_sdk: Failed to unregister overlay '{overlay_id}': {e}\n" ) def inject_commands(context_id, toolbar_name, commands): """Inject commands into a context's toolbar. Parameters ---------- context_id : str Target context identifier. toolbar_name : str Toolbar within that context. commands : list[str] Command names to add. """ if not isinstance(context_id, str): raise TypeError(f"context_id must be str, got {type(context_id).__name__}") if not isinstance(toolbar_name, str): raise TypeError(f"toolbar_name must be str, got {type(toolbar_name).__name__}") if not isinstance(commands, list): raise TypeError(f"commands must be list, got {type(commands).__name__}") try: if _kcsdk is not None: _kcsdk.inject_commands(context_id, toolbar_name, commands) else: _gui().injectEditingCommands(context_id, toolbar_name, commands) except Exception as e: FreeCAD.Console.PrintWarning( f"kindred_sdk: Failed to inject commands into '{context_id}': {e}\n" ) def current_context(): """Return the current editing context as a dict. Keys: ``id``, ``label``, ``color``, ``toolbars``, ``breadcrumb``, ``breadcrumbColors``. Returns ``None`` if no context is active. """ try: if _kcsdk is not None: return _kcsdk.current_context() return _gui().currentEditingContext() except Exception as e: FreeCAD.Console.PrintWarning( f"kindred_sdk: Failed to get current context: {e}\n" ) return None def refresh_context(): """Force re-resolution and update of the editing context.""" try: if _kcsdk is not None: _kcsdk.refresh() else: _gui().refreshEditingContext() except Exception as e: FreeCAD.Console.PrintWarning(f"kindred_sdk: Failed to refresh context: {e}\n")