wolfhece.plugins.abc
Abstract companion base class.
This module intentionally focuses on AbstractUICompanion.
Related helpers now live in dedicated modules:
wolfhece.plugins.typesfor declarative menu/action dataclasses,wolfhece.plugins.statefor resettable state containers,wolfhece.plugins.actionsfor interactive action helpers.
For backward compatibility, their main symbols are re-exported here.
Module Contents
- class wolfhece.plugins.abc.AbstractCompanionModel[source]
Bases:
abc.ABC
Pure business model contract for companion plugins.
Keep all business state and domain transitions in a model class that does not depend on wx/viewer/OpenGL APIs. The UI companion can then compose this model and stay focused on event wiring and rendering.
This default contract is intentionally lightweight to support plugins that only need simple dataclasses. Override
reset()when your model must clear transient state.
- class wolfhece.plugins.abc.AbstractUICompanion[source]
Bases:
abc.ABC
Abstract base class for companion objects that integrate with WolfMapViewer.
Viewer access policy
Companion code should use
proxyas the primary entry point for viewer integration (actions, menus, dialogs, redraw, OpenGL helpers).During the migration period, direct viewer access is still possible via the private bridge attribute
self.proxy._viewerfor advanced cases where no dedicated helper exists yet.A companion is an object that:
Owns the transient state needed by its interactive actions.
Registers (and later cleans up) custom mouse/keyboard handlers in the viewer’s action dispatch tables.
- Optionally appends its own
wx.Menuto the viewer’s menu bar (declare it through
menu_spec()).
- Optionally appends its own
Subclasses must implement
start(). All other methods are either concrete helpers or optional overrides. In particular,menu_spec()has a no-op default — companions that interact purely via mouse/keyboard events do not need a menu.- model: AbstractCompanionModel | None[source]
- create_model() AbstractCompanionModel | None[source]
Create the companion’s optional pure business model.
Override this to keep domain logic independent from UI concerns while staying in the same plugin module (companion + model in one file).
Default implementation returns
None.
- get_namespace() str[source]
Return the namespace string used to prefix action ids.
The default is the companion’s class name lowercased. Override in a subclass to choose a different prefix:
class MyCompanion(AbstractUICompanion): def get_namespace(self) -> str: return 'myfeature'
Declare the companion’s menu as a
(title, items)pair.Override this to add a menu without writing wx code:
def menu_spec(self) -> tuple[str, list[MenuEntry]] | None: return (_('My Tool'), [ MenuItem(_('Run'), self._on_run, _('Execute the tool')), SEPARATOR, SubMenuSpec(_('Settings'), [ MenuItem(_('Configure…'), self._on_configure), ]), ])
Return
None(the default) when no top-level menu is needed.Called automatically by
build(). Do not call directly.
Return where this companion menu should be hosted.
Supported values are:
'companions_root': create a submenu under the shared viewer menu“Companions” (default).
'top_level': create a direct top-level menu entry in the viewermenubar.
Override this in companions that must remain top-level.
- actions_spec() Iterable[ActionSpec | MultiStepSpec] | None[source]
Declare interactive handlers to register with the viewer.
Override this method declaratively by returning
ActionSpecand/orMultiStepSpecrows. The proxy performs registration and handler adaptation:def actions_spec(self): return [ ActionSpec(self._pick.action_id, ldown=self._ldown, key=self._key), MultiStepSpec( 'wall', steps=[ StepSpec(hint='Pick first point', ldown=self._step1), StepSpec(hint='Pick second point', ldown=self._step2), ], ), ]
For
MultiStepSpec, handlers can returnStepTransitionvalues (or equivalent strings) to drive the runtime state machine.Return
None(or an empty iterable) when there is no action to register.Called automatically by
build(). Do not call directly.
- start() None[source]
Activate the companion’s primary interactive action.
Default behaviour is declarative and driven by
actions_spec():select the
ActionSpecmarkedprimary=True,otherwise fall back to the first declared
ActionSpec,call
ViewerProxy.start_action()with itsaction_idand optionalstart_message.
Override this method when startup needs additional business logic.
- Raises:
RuntimeError – If no actions are declared or more than one
ActionSpecis marked primary.
- stop() None[source]
Deactivate the companion’s primary interactive action.
The default implementation calls
proxy.end_action(). Override to add post-processing (e.g. printing a summary):def stop(self) -> None: self.proxy.end_action() print(f"{len(self.points)} item(s) recorded.")
- build() None[source]
Build and attach the companion’s menu to the viewer menubar.
The default implementation calls
menu_spec()to build any declared menu, thenactions_spec()to wire up interactive handlers. Override this method directly only for advanced cases that the two hooks cannot express.Preferred approach — override
menu_spec()and/oractions_spec():def menu_spec(self) -> tuple[str, list[MenuEntry]] | None: return (_('My Feature'), [ MenuItem(_('Do something'), self._on_do), SEPARATOR, SubMenuSpec(_('Tools'), [ MenuItem(_('Export'), self._on_export), ]), ]) def actions_spec(self): return [ ActionSpec(self._pick.action_id, ldown=self._ldown), ]
Advanced — full wx control (bypass both hooks):
def build(self) -> None: if self.proxy._menu is not None: return import wx self.proxy._menu = wx.Menu() ... self.proxy.register_action(...)
Implementations must be idempotent.
- destroy() None[source]
Unregister all custom actions, remove the companion’s menu, and release viewer resources.
Call this when the companion is no longer needed. The method is safe to call multiple times.
Override this method to add companion-specific teardown:
def destroy(self) -> None: # custom pre-teardown ... super().destroy()
- Raises:
RuntimeError – Never — all wx errors are caught and logged.
- _iter_action_specs() Iterable[ActionSpec][source]
Yield action specs normalized to
ActionSpec.MultiStepSpecentries are normalized to a syntheticActionSpecfor primary-action selection logic.
- _primary_action_spec() ActionSpec | None[source]
Return the action spec used by the default
start()method.Selection rules:
If one spec has
primary=True, use it.If none are marked primary, use the first declared spec.
If multiple specs are marked primary, raise
RuntimeError.