"""Dock panel registration helper. Routes through the ``kcsdk`` C++ module (IPanelProvider / DockWindowManager) when available, falling back to direct PySide QDockWidget creation 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 _AREA_MAP = { "left": 1, # Qt.LeftDockWidgetArea / DockArea.Left "right": 2, # Qt.RightDockWidgetArea / DockArea.Right "top": 4, # Qt.TopDockWidgetArea / DockArea.Top "bottom": 8, # Qt.BottomDockWidgetArea / DockArea.Bottom } _DOCK_AREA_MAP = None # lazily populated from kcsdk def _get_dock_area(area_str): """Convert area string to kcsdk.DockArea enum value.""" global _DOCK_AREA_MAP if _DOCK_AREA_MAP is None: _DOCK_AREA_MAP = { "left": _kcsdk.DockArea.Left, "right": _kcsdk.DockArea.Right, "top": _kcsdk.DockArea.Top, "bottom": _kcsdk.DockArea.Bottom, } return _DOCK_AREA_MAP.get(area_str) def register_dock_panel(object_name, title, widget_factory, area="right", delay_ms=0): """Register a dock panel, optionally deferred. Parameters ---------- object_name : str Qt object name for duplicate prevention. title : str Dock widget title bar text. widget_factory : callable Zero-argument callable returning a ``QWidget``. Called only when the panel is actually created (after *delay_ms*). area : str, optional Dock area: ``"left"``, ``"right"``, ``"top"``, or ``"bottom"``. Default ``"right"``. delay_ms : int, optional Milliseconds to wait before creating the panel. Default 0 (immediate, but still posted to the event loop). """ if not isinstance(object_name, str): raise TypeError(f"object_name must be str, got {type(object_name).__name__}") if not callable(widget_factory): raise TypeError("widget_factory must be callable") if area not in _AREA_MAP: raise ValueError(f"area must be one of {list(_AREA_MAP)}, got {area!r}") if _kcsdk is not None: _register_via_kcsdk(object_name, title, widget_factory, area, delay_ms) else: _register_via_pyside(object_name, title, widget_factory, area, delay_ms) def _register_via_kcsdk(object_name, title, widget_factory, area, delay_ms): """Register using the C++ SDK panel provider system.""" dock_area = _get_dock_area(area) class _AnonymousProvider(_kcsdk.IPanelProvider): def id(self): return object_name def title(self): return title def create_widget(self): return widget_factory() def preferred_area(self): return dock_area try: _kcsdk.register_panel(_AnonymousProvider()) def _create(): try: _kcsdk.create_panel(object_name) except Exception as e: FreeCAD.Console.PrintLog( f"kindred_sdk: Panel '{object_name}' creation failed: {e}\n" ) from PySide.QtCore import QTimer QTimer.singleShot(max(0, delay_ms), _create) except Exception as e: FreeCAD.Console.PrintLog( f"kindred_sdk: kcsdk panel registration failed for '{object_name}', " f"falling back: {e}\n" ) _register_via_pyside(object_name, title, widget_factory, area, delay_ms) def _register_via_pyside(object_name, title, widget_factory, area, delay_ms): """Legacy fallback: create dock widget directly via PySide.""" qt_area = _AREA_MAP[area] def _create(): try: import FreeCADGui from PySide import QtCore, QtWidgets mw = FreeCADGui.getMainWindow() if mw is None: return if mw.findChild(QtWidgets.QDockWidget, object_name): return widget = widget_factory() panel = QtWidgets.QDockWidget(title, mw) panel.setObjectName(object_name) panel.setWidget(widget) mw.addDockWidget(QtCore.Qt.DockWidgetArea(qt_area), panel) except Exception as e: FreeCAD.Console.PrintLog( f"kindred_sdk: Dock panel '{object_name}' skipped: {e}\n" ) try: from PySide.QtCore import QTimer QTimer.singleShot(max(0, delay_ms), _create) except Exception as e: FreeCAD.Console.PrintLog( f"kindred_sdk: Could not schedule dock panel '{object_name}': {e}\n" )