"""
Dot Picker — example companion plugin.
Demonstrates the minimal pattern:
* right-click adds a point
* Ctrl+Z removes the last point
* Esc deactivates
This file is a simplified wrapper around
:class:`wolfhece._plugin_factory.PointPickerCompanion`.
Import the factory class directly in your own code if you only need the
behaviour without the plugin infrastructure.
"""
from dataclasses import dataclass
from wolfhece.plugins.factory import PointPickerCompanion, PointPickerModel
from wolfhece.plugins.abc import MenuItem, MultiStepSpec, StepSpec
from wolfhece._viewer_plugin_handlers import MouseContext
@dataclass
[docs]
class DotPickerModel(PointPickerModel):
"""Business state for the Dot Picker plugin.
Keeps domain operations explicit for the built-in plugin example while
reusing the base point-picker state structure.
"""
[docs]
def clear_points(self) -> None:
self.reset()
[docs]
class DotPickerCompanion(PointPickerCompanion):
"""Point-picker companion exposed as a plugin.
Adds a *"Dot Picker"* entry to the viewer's menu bar.
Inherits all interaction logic from :class:`PointPickerCompanion`.
"""
[docs]
def create_model(self) -> DotPickerModel:
return DotPickerModel()
@property
[docs]
def model_state(self) -> DotPickerModel:
return self.model # type: ignore[return-value]
[docs]
def build(self) -> None:
"""Keep explicit build override for backwards compatibility."""
super().build()
[docs]
def actions_spec(self):
return [
MultiStepSpec(
'pick',
primary=True,
start_message='Right-click: add | Left-click: select | Ctrl+Z: undo | Esc: stop',
steps=[
StepSpec(
hint='Right-click: add | Left-click: select | Ctrl+Z: undo | Esc: stop',
rdown=self._rdown,
ldown=self._ldown,
key=self._key,
paint=self._paint,
)
],
),
]
[docs]
def start(self) -> None:
"""Activate the pick action (called by the plugin manager)."""
self.proxy.start_action(
'pick',
'Right-click: add | Left-click: select | Ctrl+Z: undo | Esc: stop',
)
# -- menu handlers -------------------------------------------------------
[docs]
def _on_pick(self, ctx: MouseContext) -> None:
self.start()
[docs]
def _on_clear(self, ctx: MouseContext) -> None:
self.model_state.clear_points()
self.proxy.force_redraw()
self.proxy.set_status('Dot Picker: all points cleared.')