Skip to content

Commit b80d63f

Browse files
committed
refactor(viewer): event and command use IntEnum and not str
1 parent 176422a commit b80d63f

12 files changed

Lines changed: 247 additions & 141 deletions

File tree

bot/control/mouse.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from panda3d.core import MouseButton, Point2, Point3
33

44
from bot.control.picker import RayPicker
5+
from bot.viewer.contracts import ViewEventType
56
from bot.math.constraints import ConstraintManager
67

78

@@ -80,7 +81,7 @@ def _finalize_drag(self, world_pos):
8081
curve.rebuild_cp_collision()
8182

8283
self.base._on_event_cb(
83-
"cp_pick_end",
84+
ViewEventType.CP_PICK_END,
8485
{
8586
"curve_tag": self.drag_curve_tag,
8687
"cp_index": self.drag_cp_index,
@@ -98,7 +99,7 @@ def _handle_hover(self, m_pos: Point2):
9899

99100
if hovered_tag != self.last_hovered_tag:
100101
self.last_hovered_tag = hovered_tag
101-
self.base._on_event_cb("hover", hovered_tag)
102+
self.base._on_event_cb(ViewEventType.HOVER, hovered_tag)
102103

103104
def _handle_cp_interaction(self, m_pos: Point2, left_down: bool):
104105
if not self.edit_mode_enabled and not self.dragging_cp:
@@ -162,7 +163,7 @@ def _start_cp_drag(self, metadata: dict, m_pos: Point2):
162163
)
163164

164165
self.base._on_event_cb(
165-
"cp_pick_start",
166+
ViewEventType.CP_PICK_START,
166167
{
167168
"curve_tag": self.drag_curve_tag,
168169
"cp_index": self.drag_cp_index,
@@ -189,7 +190,7 @@ def _update_cp_drag(self, m_pos: Point2):
189190
)
190191

191192
self.base._on_event_cb(
192-
"cp_drag",
193+
ViewEventType.CP_DRAG,
193194
{
194195
"curve_tag": self.drag_curve_tag,
195196
"cp_index": self.drag_cp_index,
@@ -225,7 +226,7 @@ def _handle_curve_click(self, m_pos: Point2, left_down: bool):
225226
metadata.get("pick_kind") == "curve"
226227
and metadata.get("curve_tag") is not None
227228
):
228-
self.base._on_event_cb("curve_selected", metadata["curve_tag"])
229+
self.base._on_event_cb(ViewEventType.CURVE_SELECTED, metadata["curve_tag"])
229230

230231
def _handle_drag(self, curr_pos: Point2):
231232
if self.dragging_cp:

bot/viewer/app.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from bot.control.camera import CameraController
1313
from bot.control.mouse import MouseHandler
1414
from bot.control.keyboard import KeyboardHandler
15-
from bot.viewer.contracts import ScenePayload
15+
from bot.viewer.contracts import ScenePayload, SceneUpdateOp, ViewerCommandType
1616

1717
_DEFAULT_SCENE = {
1818
"background_color": [0.1, 0.1, 0.12],
@@ -100,39 +100,39 @@ def __process_commands(self, task):
100100
while not self._cmd_queue.empty():
101101
try:
102102
cmd, data = self._cmd_queue.get_nowait()
103-
if cmd == "add":
103+
if cmd == SceneUpdateOp.ADD:
104104
self.__load_scene(data)
105-
elif cmd == "update":
105+
elif cmd == SceneUpdateOp.UPDATE:
106106
self.__update_scene(data)
107-
elif cmd == "delete":
107+
elif cmd == SceneUpdateOp.DELETE:
108108
self.__delete_in_scene(data)
109-
elif cmd == "reload_config":
109+
elif cmd == ViewerCommandType.RELOAD_CONFIG:
110110
self._config = data
111111
if self._scene:
112112
self._scene.apply_settings(self.__scene_cfg())
113113
if self._camera_controller:
114114
self._camera_controller.apply_settings(self.__camera_cfg())
115-
elif cmd == "highlight_curve":
115+
elif cmd == ViewerCommandType.HIGHLIGHT_CURVE:
116116
if self._scene:
117117
self._scene.set_curve_color(data["tag"], data["color"])
118-
elif cmd == "update_hud":
118+
elif cmd == ViewerCommandType.UPDATE_HUD:
119119
self.hud.setText(data["text"])
120-
elif cmd == "set_edit_mode":
120+
elif cmd == ViewerCommandType.SET_EDIT_MODE:
121121
enabled = bool(data.get("enabled", False))
122122
curve_tag = data.get("curve_tag")
123123
self.mouse_handler.set_edit_mode(enabled, curve_tag)
124124
if self._scene:
125125
self._scene.set_edit_mode(enabled)
126126
if curve_tag is not None:
127127
self._scene.set_active_curve(curve_tag)
128-
elif cmd == "set_active_curve":
128+
elif cmd == ViewerCommandType.SET_ACTIVE_CURVE:
129129
curve_tag = data.get("curve_tag")
130130
self.mouse_handler.set_edit_mode(
131131
self.mouse_handler.edit_mode_enabled, curve_tag
132132
)
133133
if self._scene:
134134
self._scene.set_active_curve(curve_tag)
135-
elif cmd == "set_axis_constraint":
135+
elif cmd == ViewerCommandType.SET_AXIS_CONSTRAINT:
136136
self.__set_axis_constraint(data.get("mask", 7))
137137
except queue.Empty:
138138
break
@@ -160,7 +160,7 @@ def __load_scene(self, payload: dict):
160160
if self._scene is not None:
161161
self._scene.clear()
162162

163-
if isinstance(payload, dict) and payload.get("op") == "add":
163+
if isinstance(payload, dict) and payload.get("op") == SceneUpdateOp.ADD:
164164
geom_data = payload_to_geom_data(payload)
165165
else:
166166
geom_data = payload
@@ -183,7 +183,7 @@ def __update_scene(self, payload: dict):
183183
self.__load_scene(payload)
184184
return
185185

186-
if isinstance(payload, dict) and payload.get("op") == "update":
186+
if isinstance(payload, dict) and payload.get("op") == SceneUpdateOp.UPDATE:
187187
self._scene.apply_patch(payload)
188188
return
189189

bot/viewer/contracts.py

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2,69 +2,79 @@
22

33
from __future__ import annotations
44

5-
from typing import Any, Literal, TypedDict, Union, NotRequired
6-
from enum import Enum
5+
from enum import IntEnum
6+
from typing import Any, Literal, NotRequired, TypedDict, Union
77

88
from bot.core.spline import BEZIER_TYP, NURBS_TYP
99

1010

11-
class SceneUpdateOp(str, Enum):
11+
class SceneUpdateOp(IntEnum):
1212
"""
1313
Category 1: Geometric Update Flow (Parent -> Child)
1414
Heavy payloads used to synchronize 3D topology and geometry.
1515
"""
16-
ADD = "add" # Initializes or fully rebuilds the scene.
17-
UPDATE = "update" # Applies a partial patch to existing geometries.
18-
DELETE = "delete" # Removes one or multiple geometries from the scene.
1916

17+
ADD = 1 # Initializes or fully rebuilds the scene.
18+
UPDATE = 2 # Applies a partial patch to existing geometries.
19+
DELETE = 3 # Removes one or multiple geometries from the scene.
2020

21-
class ViewerCommandType(str, Enum):
21+
22+
class ViewerCommandType(IntEnum):
2223
"""
2324
Category 2: Display State Commands (Parent -> Child)
2425
Orders given to the GUI by the parent process.
2526
"""
27+
2628
# FIXME Color changes on hover should be detected and applied locally by the child.
27-
HIGHLIGHT_CURVE = "highlight_curve"
29+
HIGHLIGHT_CURVE = 10
2830

2931
# Legitimate: The parent sends domain-specific data (calculated by the kernel) that the child lacks.
30-
UPDATE_HUD = "update_hud"
32+
UPDATE_HUD = 11
3133

3234
# Legitimate: The parent (script/kernel) forces the UI into edit mode programmatically.
33-
SET_EDIT_MODE = "set_edit_mode"
35+
SET_EDIT_MODE = 12
3436

3537
# Legitimate: The parent targets a specific curve programmatically.
36-
SET_ACTIVE_CURVE = "set_active_curve"
38+
SET_ACTIVE_CURVE = 13
3739

3840
# FIXME The child already has the math logic (ConstraintManager) to calculate axes locally.
39-
SET_AXIS_CONSTRAINT = "set_axis_constraint"
41+
SET_AXIS_CONSTRAINT = 14
4042

4143
# Legitimate: The parent commands the child process to terminate gracefully.
42-
EXIT = "exit"
44+
EXIT = 15
4345

46+
RELOAD_CONFIG = 16
4447

45-
class ViewEventType(str, Enum):
48+
49+
class ViewEventType(IntEnum):
4650
"""
4751
Category 3: User Interaction Events (Child -> Parent)
4852
Notifications of physical user actions occurring in the 3D window.
4953
"""
54+
5055
# FIXME If no custom user callback is set, sending this just to trigger a HIGHLIGHT_CURVE is wasteful.
51-
HOVER = "hover"
56+
HOVER = 100
5257

5358
# Legitimate: The parent needs to know which curve was clicked to update its internal state.
54-
CURVE_SELECTED = "curve_selected"
59+
CURVE_SELECTED = 101
5560

5661
# Legitimate: Notifies the parent that a control point drag operation has started.
57-
CP_PICK_START = "cp_pick_start"
62+
CP_PICK_START = 102
5863

5964
# FIXME Sending mouse position at 60 FPS clogs the IPC pipe.
6065
# The child should handle real-time visual updates locally via `preview_evaluate`.
61-
CP_DRAG = "cp_drag"
66+
CP_DRAG = 103
6267

6368
# Legitimate (Crucial): The parent receives the final position to permanently update the math kernel.
64-
CP_PICK_END = "cp_pick_end"
69+
CP_PICK_END = 104
6570

6671
# Legitimate: The parent receives an absolute 3D coordinate to instantiate a new free point.
67-
PICK = "pick"
72+
PICK = 105
73+
74+
75+
ParentCommand = SceneUpdateOp | ViewerCommandType
76+
ParentMessage = tuple[ParentCommand, Any]
77+
ChildMessage = tuple[ViewEventType, Any]
6878

6979

7080
class CurveGeometry(TypedDict):
@@ -89,7 +99,7 @@ class CurveDelta(TypedDict):
8999
class ScenePayload(TypedDict):
90100
"""Universal exchange format for incremental scene updates."""
91101

92-
op: Literal["add", "update", "delete"]
102+
op: SceneUpdateOp
93103
changed_curves: dict[str, CurveDelta]
94104
deleted_curves: NotRequired[list[str]]
95105
bounds: NotRequired[dict[str, Any]]
@@ -98,45 +108,82 @@ class ScenePayload(TypedDict):
98108

99109

100110
class EventHover(TypedDict):
101-
event_type: Literal["hover"]
111+
event_type: Literal[ViewEventType.HOVER]
102112
tag: str | None
103113

114+
104115
class EventCurveSelected(TypedDict):
105-
event_type: Literal["curve_selected"]
116+
event_type: Literal[ViewEventType.CURVE_SELECTED]
106117
curve_tag: str
107118

108-
class EventCPInteraction(TypedDict):
109-
event_type: Literal["cp_pick_start", "cp_drag", "cp_pick_end"]
119+
120+
class EventCPPickStart(TypedDict):
121+
event_type: Literal[ViewEventType.CP_PICK_START]
122+
curve_tag: str
123+
cp_index: int
124+
world_pos: list[float]
125+
126+
127+
class EventCPDrag(TypedDict):
128+
event_type: Literal[ViewEventType.CP_DRAG]
110129
curve_tag: str
111130
cp_index: int
112131
world_pos: list[float]
113132

133+
134+
class EventCPPickEnd(TypedDict):
135+
event_type: Literal[ViewEventType.CP_PICK_END]
136+
curve_tag: str
137+
cp_index: int
138+
world_pos: list[float]
139+
140+
114141
class EventPick(TypedDict):
115-
event_type: Literal["pick"]
142+
event_type: Literal[ViewEventType.PICK]
116143
world_pos: list[float]
117144

118-
ViewEvent = Union[EventHover, EventCurveSelected, EventCPInteraction, EventPick]
119145

146+
ViewEvent = Union[
147+
EventHover,
148+
EventCurveSelected,
149+
EventCPPickStart,
150+
EventCPDrag,
151+
EventCPPickEnd,
152+
EventPick,
153+
]
120154

121155

122156
class CmdHighlightCurve(TypedDict):
123-
cmd: Literal["highlight_curve"]
157+
cmd: Literal[ViewerCommandType.HIGHLIGHT_CURVE]
124158
tag: str
125159
color: list[float]
126160

161+
127162
class CmdUpdateHud(TypedDict):
128-
cmd: Literal["update_hud"]
163+
cmd: Literal[ViewerCommandType.UPDATE_HUD]
129164
text: str
130165

166+
131167
class CmdSetEditMode(TypedDict):
132-
cmd: Literal["set_edit_mode"]
168+
cmd: Literal[ViewerCommandType.SET_EDIT_MODE]
133169
enabled: bool
134170
curve_tag: str | None
135171

172+
136173
class CmdSetActiveCurve(TypedDict):
137-
cmd: Literal["set_active_curve"]
174+
cmd: Literal[ViewerCommandType.SET_ACTIVE_CURVE]
138175
curve_tag: str | None
139176

177+
178+
class CmdSetAxisConstraint(TypedDict):
179+
cmd: Literal[ViewerCommandType.SET_AXIS_CONSTRAINT]
180+
mask: int
181+
182+
140183
ViewerCommand = Union[
141-
CmdHighlightCurve, CmdUpdateHud, CmdSetEditMode, CmdSetActiveCurve
142-
]
184+
CmdHighlightCurve,
185+
CmdUpdateHud,
186+
CmdSetEditMode,
187+
CmdSetActiveCurve,
188+
CmdSetAxisConstraint,
189+
]

bot/viewer/serialize.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import numpy as np
99

10-
from bot.viewer.contracts import CurveDelta, CurveGeometry, ScenePayload
10+
from bot.viewer.contracts import CurveDelta, CurveGeometry, ScenePayload, SceneUpdateOp
1111

1212

1313
def floats_to_bytes(points: Sequence[Sequence[float]] | np.ndarray) -> bytes:
@@ -74,7 +74,7 @@ def merge_deltas(*payloads: ScenePayload) -> ScenePayload:
7474
bounds: dict[str, Any] | None = None
7575
points: bytes | None = None
7676
edges: list[tuple[int, int, str]] | None = None
77-
op: str = "add"
77+
op: SceneUpdateOp = SceneUpdateOp.ADD
7878

7979
for payload in payloads:
8080
op = payload.get("op", op)

0 commit comments

Comments
 (0)