Commit Graph

14 Commits

Author SHA1 Message Date
forbes
74b0073327 feat(editing-context): hierarchical context system with stack, guards, and breadcrumb injection (#385, #386, #387)
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Replaces the flat context model with a tree-structured hierarchy:

- ContextDefinition gains parentId field for declaring parent-child
  relationships between contexts
- Resolver builds a context stack by walking parentId links from
  leaf to root, verifying each ancestor matches current state
- Breadcrumb is now auto-built from the stack — each level
  contributes its expanded label and color, replacing all hardcoded
  special cases
- EditingContext gains stack field (QStringList, root to leaf)

Transition guards (#386):
- addTransitionGuard() / removeTransitionGuard() on resolver
- Guards run synchronously before applyContext(); first rejection
  cancels the transition and emits contextTransitionBlocked signal
- Full SDK/pybind11/Python bindings

Breadcrumb injection (#387):
- injectBreadcrumb() / removeBreadcrumbInjection() on resolver
- Addons can append segments to any context's breadcrumb display
- Active only when the target context is in the current stack
- Full SDK/pybind11/Python bindings

Built-in parent assignments:
- partdesign.body → partdesign.workbench
- partdesign.feature → partdesign.body
- partdesign.in_assembly → assembly.edit
- sketcher.edit → partdesign.body
- assembly.idle → assembly.workbench
- assembly.edit → assembly.idle
- Workbench-level and root contexts have no parent

SDK surface:
- Types.h: parentId on ContextDef, stack on ContextSnapshot
- SDKRegistry: guard/injection delegation, snapshotFromGui helper
- kcsdk_py: parent_id param, context_stack(), guard/injection bindings
- kindred_sdk: context_stack(), add/remove_transition_guard(),
  inject/remove_breadcrumb_injection(), parent_id on register_context()

Closes #385, closes #386, closes #387
2026-03-04 14:23:45 -06:00
forbes
2127d2c904 feat(sdk): addon load timing diagnostics — addon_diagnostics() (#390)
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Add kindred_sdk.addon_diagnostics() returning per-addon load state,
timing, and error info as a list of dicts. Reads name, state,
load_time_ms, and error from AddonManifest via AddonRegistry.

Add _print_load_summary() to addon_loader.py that prints a formatted
summary table to the console after each load phase (Init.py and
InitGui.py), replacing interleaved individual log lines with a
consolidated view.

Closes #390
2026-03-04 13:50:37 -06:00
forbes
85ae0effc9 feat(sdk): addon asset path resolution — addon_resource() (#389)
Some checks failed
Build and Test / build (pull_request) Has been cancelled
Add kindred_sdk.addon_resource(name, relative_path) that resolves
bundled asset paths relative to an addon's root directory. Looks up
the addon manifest from AddonRegistry for the install root, joins
the relative path, and validates existence on disk.

Raises LookupError if the addon is not registered, FileNotFoundError
if the resolved path does not exist.

Closes #389
2026-03-04 13:46:25 -06:00
forbes
519d5b4436 feat(sdk): add context introspection — available_contexts and context_history (#383)
All checks were successful
Build and Test / build (pull_request) Successful in 25m9s
C++ layer:
- EditingContextResolver::registeredContexts() returns static metadata
  (id, labelTemplate, color, priority) for all registered contexts
- SDKRegistry::registeredContexts() wraps with Qt-to-std conversion
- kcsdk.available_contexts() pybind11 binding returns list of dicts

Python layer:
- kindred_sdk.available_contexts() wraps kcsdk binding
- kindred_sdk.context_history(limit=10) returns recent transitions
  from a 50-entry ring buffer tracked in lifecycle.py, with timestamps

Closes #383
2026-03-04 13:42:34 -06:00
forbes
d2ec22f5ff feat(sdk): add context lifecycle callbacks (#381)
All checks were successful
Build and Test / build (pull_request) Successful in 29m7s
Expose EditingContextResolver::contextChanged to Python addons via
two-layer design:

C++ layer:
- SDKRegistry::onContextChanged() stores callbacks and lazily connects
  to the Qt signal on first registration
- pybind11 binding kcsdk.on_context_changed() wraps Python callables
  with GIL-safe invocation

Python layer:
- kindred_sdk.on_context_enter(context_id, callback) subscribes to
  context activation ("*" wildcard supported)
- kindred_sdk.on_context_exit(context_id, callback) subscribes to
  context deactivation
- Internal tracking of previous context derives enter/exit transitions
- Emits context.enter / context.exit on the SDK event bus

Closes #381
2026-03-04 10:01:00 -06:00
forbes
54b926a925 feat(sdk): add event bus for inter-addon communication (#382)
All checks were successful
Build and Test / build (pull_request) Successful in 28m56s
New module kindred_sdk/events.py provides lightweight publish-subscribe
so addons can signal each other without direct imports.

New public API:
- sdk.on(event, handler) — subscribe to a named event
- sdk.off(event, handler) — unsubscribe
- sdk.emit(event, data) — publish event with dict payload

Pure Python, synchronous dispatch, snapshot-safe iteration.
Handlers that raise are logged and skipped without breaking the chain.
2026-03-04 09:47:43 -06:00
forbes
8c5d259e79 feat(sdk): add addon registry wrappers to kindred_sdk (#384)
All checks were successful
Build and Test / build (pull_request) Successful in 29m35s
New module kindred_sdk/registry.py wraps FreeCAD.KindredAddons so
addons use a stable SDK import instead of reaching into FreeCAD
internals directly.

New public API:
- sdk.is_addon_loaded(name) — boolean check
- sdk.addon_version(name) — version string or None
- sdk.loaded_addons() — list of loaded addon names in load order
2026-03-04 09:36:17 -06:00
forbes
79f69e2856 feat(sdk): remove fallbacks, add deprecation warnings, bump v1.0.0 (#357)
All checks were successful
Build and Test / build (pull_request) Successful in 28m54s
- Bump SDK_VERSION to 1.0.0 in version.py and package.xml
- Remove <pure_python> tag from package.xml (kcsdk is C++)
- Remove all FreeCADGui.* fallback paths in context.py, dock.py,
  toolbar.py, menu.py; require kcsdk module
- Remove query fallbacks in origin.py (keep register/unregister
  which still need FreeCADGui.addOrigin/removeOrigin)
- Add deprecation warnings to 11 superseded FreeCADGui methods
  in ApplicationPy.cpp (not addOrigin/removeOrigin)
- All 39 Tier 1 tests pass
2026-03-01 14:42:00 -06:00
forbes
a6a6cefc16 feat(sdk): add status bar widget wrapper and origin query bindings (#356)
register_status_widget(): pure Python wrapper that adds a live widget
to the main window status bar with context menu discoverability.

Origin query bindings (kcsdk.list_origins, active_origin, get_origin,
set_active_origin): thin C++ forwarding to OriginManager with Python
wrappers using kcsdk-first routing.

IOriginProvider and IStatusBarProvider C++ interfaces dropped — existing
FileOrigin stack is already complete, and status bar widgets don't need
C++ lifecycle management.
2026-03-01 14:42:00 -06:00
forbes
747c458e23 feat(sdk): add IMenuProvider interface and register_command wrapper (#355)
IMenuProvider: declarative menu placement with optional context awareness.
C++ interface with pybind11 bindings + GIL-safe holder. SDKMenuManipulator
(shared WorkbenchManipulator) injects menu items on workbench switch,
filtered by editing context when context_ids() is non-empty.

register_command(): thin Python wrapper around FreeCADGui.addCommand()
that standardizes the calling convention within the SDK contract.

Python wrappers (kindred_sdk.register_menu, kindred_sdk.register_command)
use kcsdk-first routing with FreeCADGui fallback.
2026-03-01 14:42:00 -06:00
forbes
4eb643a26f feat(sdk): add IToolbarProvider interface to kcsdk (#354) 2026-03-01 14:42:00 -06:00
forbes
64644eb623 feat(sdk): add panel provider and theme engine to kcsdk (#352, #353)
- IPanelProvider: abstract interface for dock panels with PySide widget bridging
- PyIPanelProvider/PyProviderHolder: pybind11 trampoline + GIL-safe holder
- WidgetBridge: PySide QWidget → C++ QWidget* conversion via Shiboken
- SDKRegistry: panel registration, creation, and lifecycle management
- ThemeEngine: C++ singleton with minimal YAML parser, palette cache,
  getColor/allTokens/formatQss matching Python Palette API
- kcsdk bindings: DockArea, PanelPersistence enums, panel functions,
  theme_color, theme_tokens, format_qss, load_palette
- dock.py: kcsdk delegation with FreeCADGui fallback
- theme.py: kcsdk delegation with Python YAML fallback
2026-03-01 14:42:00 -06:00
forbes
60c0489d73 feat(sdk): migrate editing context API to kcsdk (#351)
Add context/overlay registration, injection, query, and refresh to the
KCSDK C++ library and kcsdk pybind11 module.

New files:
- src/Gui/SDK/Types.h — ContextDef, OverlayDef, ContextSnapshot structs
  (plain C++, no Qt in public API)

Modified:
- src/Gui/SDK/SDKRegistry.h/.cpp — register_context/overlay, unregister,
  inject_commands, current_context, refresh (delegates to
  EditingContextResolver with std↔Qt conversion)
- src/Gui/SDK/CMakeLists.txt — add Types.h, link FreeCADGui
- src/Gui/SDK/bindings/kcsdk_py.cpp — bind all context functions with
  GIL-safe match callable wrapping and dict-based snapshot return
- mods/sdk/kindred_sdk/context.py — try kcsdk first, fall back to
  FreeCADGui for backwards compatibility
2026-03-01 14:42:00 -06:00
e667aceead feat(addon-system): create kindred-addon-sdk package (#249)
Some checks failed
Build and Test / build (pull_request) Failing after 1m40s
Add mods/sdk/ with the kindred_sdk Python package providing a stable
API layer for addon integration with Kindred Create platform features.

Modules:
- context: editing context/overlay registration wrappers
- theme: YAML-driven palette system (Catppuccin Mocha)
- origin: FileOrigin registration helpers
- dock: deferred dock panel registration
- compat: version detection utilities

The SDK loads at priority 0 (before all other addons) via the existing
manifest-driven loader. Theme colors are defined in a single YAML
palette file instead of hardcoded Python dicts, enabling future theme
support and eliminating color duplication across addons.

Closes #249
2026-02-17 08:36:27 -06:00