Source code for wolfhece._builtin_plugins._template.companion

"""
Template companion plugin.

Replace every occurrence of ``MyPlugin`` / ``my_plugin`` with your own name,
then implement the methods below.

Rename this directory to match the ``name`` field in ``plugin.toml``
(removing the leading ``_`` so it is auto-discovered).

Recommended structure to keep plugin footprint minimal:
- one Python module containing both the pure business model and the UI
    companion adapter,
- one metadata file (``plugin.toml``).
"""
from dataclasses import dataclass

from wolfhece.plugins.abc import (
        AbstractCompanionModel,
    AbstractUICompanion,
    Keys,
    MenuItem,
    MultiStepSpec,
    StepSpec,
    StepTransition,
)
from wolfhece._viewer_plugin_handlers import MouseContext, KeyboardSnapshot


@dataclass
[docs] class MyPluginModel(AbstractCompanionModel): """Pure domain state: no viewer/wx/OpenGL dependencies."""
[docs] click_count: int = 0
[docs] def record_click(self) -> None: self.click_count += 1
[docs] def reset(self) -> None: self.click_count = 0
[docs] class MyPluginCompanion(AbstractUICompanion): """Minimal template — replace with your implementation."""
[docs] def create_model(self) -> MyPluginModel: return MyPluginModel()
[docs] def menu_spec(self): """Add a sub-menu entry in Companions main menu. Remove if no menu is needed.""" return ('My Plugin', [ MenuItem('Run…', self.on_run, 'Start the interactive action'), ])
[docs] def actions_spec(self): return [ MultiStepSpec( 'run', primary=True, start_message='Right-click to interact — Esc to stop', steps=[ StepSpec( hint='Right-click to interact — Esc to stop', rdown=self.step1_rdown, key=self.key, paint=self.paint, ), StepSpec( hint='Right-click again to finish — Esc to cancel', rdown=self.step2_rdown, key=self.key, paint=self.paint, ), ], finish_message='Action finished', ), ]
[docs] def start(self) -> None: """Called when the companion is activated programmatically.""" self.proxy.start_action( 'run', 'Right-click to interact — Esc to stop', )
# -- handlers ------------------------------------------------------------
[docs] def on_run(self, ctx: MouseContext) -> None: self.start()
[docs] def rdown(self, ctx: MouseContext) -> None: # TODO: replace with your business logic if isinstance(self.model, MyPluginModel): self.model.record_click() self.proxy.set_status(f'Clicks: {self.model.click_count}') self.proxy.force_redraw()
[docs] def step1_rdown(self, ctx: MouseContext) -> StepTransition: self.rdown(ctx) return StepTransition.NEXT
[docs] def step2_rdown(self, ctx: MouseContext) -> StepTransition: self.rdown(ctx) return StepTransition.FINISH
[docs] def key(self, kb: KeyboardSnapshot) -> bool | StepTransition: if kb.key_code == Keys.ESCAPE: return StepTransition.CANCEL return False
[docs] def paintdoc(self) -> None: # TODO: draw your OpenGL overlay pass