Menu-less companion - minimal example
This notebook shows the shortest possible companion:
No menu: no
menu_spec()/build()requiredNo hidden graphics helper: OpenGL drawing is explicit
Single responsibility: right click -> add a point
The whole class fits in about twenty lines.
What AbstractUICompanion does for you
API |
Role |
|---|---|
|
Registers handlers on the viewer |
|
Activates the action and shows the hint |
|
Deactivates the current action |
|
Returns a namespaced id ( |
|
Forces a redraw |
|
Unregisters all companion actions |
1 - Start wx
[1]:
import sys
%gui wx
2 - Create the viewer
[ ]:
from wolfhece.PyDraw import WolfMapViewer
viewer = WolfMapViewer(None, title="Menu-less companion", w=1200, h=800)
viewer.Show()
INFO:root:Importing wolfhece modules
INFO:root:wolfhece modules imported
INFO:root:Plugin manager init: skipping auto-discovery because no global configuration is available yet.
False
3 - The companion class
The only requirement is to implement
start() (required by AbstractUICompanion).Everything else is optional.
[ ]:
from wolfhece.plugins.abc import AbstractUICompanion
from wolfhece._viewer_plugin_handlers import MouseContext
from OpenGL.GL import glBegin, glEnd, glVertex2f, glColor4f, glLineWidth, GL_LINES
class DotCompanion(AbstractUICompanion):
"""Collect right-clicks and draw them on the map.
No menu, no boilerplate - the minimal companion.
"""
def __init__(self):
#: Collected points - readable from the notebook.
self.points: list[tuple[float, float]] = []
def start(self) -> None:
"""Register handlers and activate the action."""
self.proxy.register_action('pick', rdown=self._rdown, paint=self._paint)
self.proxy.start_action('pick', 'Right-click to add a point...')
def _rdown(self, ctx: MouseContext) -> None:
self.points.append((ctx.x_snap, ctx.y_snap))
print(f'#{len(self.points):3d} X={ctx.x_snap:.3f} Y={ctx.y_snap:.3f}')
self.proxy._viewer.Refresh()
def _paint(self) -> None:
half = (self.proxy._viewer.xmax - self.proxy._viewer.xmin) * 0.01
glLineWidth(2.0)
glColor4f(0.0, 1.0, 0.0, 1.0)
glBegin(GL_LINES)
for (x, y) in self.points:
glVertex2f(x - half, y); glVertex2f(x + half, y)
glVertex2f(x, y - half); glVertex2f(x, y + half)
glEnd()
4 - Instantiate and start
No build() to call - start directly.
[ ]:
comp = DotCompanion()
viewer.attach_companion(comp)
comp.start()
print(comp)
print('Action active - right-click on the map to add points.')
INFO:root:ACTION : Clic droit pour ajouter un point…
<DotCompanion ns='dotcompanion' menu=not built actions=[dotcompanion.pick]>
Action active — clic droit sur la carte pour ajouter des points.
5 - Inspect collected points
[5]:
print(f"{len(comp.points)} point(s) :")
for i, (x, y) in enumerate(comp.points, 1):
print(f" {i:3d}. X={x:.3f} Y={y:.3f}")
0 point(s) :
6 - Stop and clean up
[ ]:
viewer.detach_companion(comp)
print("Companion destroyed.")
print(comp)
INFO:root:ACTION : End of action
Compagnon détruit.
<DotCompanion ns='dotcompanion' menu=not built actions=[—]>
The Kernel crashed while executing code in the current cell or a previous cell.
Please review the code in the cell(s) to identify a possible cause of the failure.
Click <a href='https://aka.ms/vscodeJupyterKernelCrash'>here</a> for more info.
View Jupyter <a href='command:jupyter.viewOutput'>log</a> for further details.
Summary - full class
from wolfhece.plugins.abc import AbstractUICompanion
from wolfhece._viewer_plugin_handlers import MouseContext
from OpenGL.GL import glBegin, glEnd, glVertex2f, glColor4f, glLineWidth, GL_LINES
class DotCompanion(AbstractUICompanion):
def __init__(self):_()
self.points: list[tuple[float, float]] = []
def start(self) -> None:
self.proxy.register_action('pick', rdown=self._rdown, paint=self._paint)
self.proxy.start_action('pick', 'Right-click to add a point...')
def _rdown(self, ctx: MouseContext) -> None:
self.points.append((ctx.x_snap, ctx.y_snap))
self.proxy._viewer.Refresh()
def _paint(self) -> None:
half = (self.proxy._viewer.xmax - self.proxy._viewer.xmin) * 0.01
glLineWidth(2.0)
glColor4f(0.0, 1.0, 0.0, 1.0)
glBegin(GL_LINES)
for (x, y) in self.points:
glVertex2f(x - half, y); glVertex2f(x + half, y)
glVertex2f(x, y - half); glVertex2f(x, y + half)
glEnd()