33import abc
44import pyray as rl
55from enum import IntEnum
6+ from typing import TypeVar
67from collections .abc import Callable
78from openpilot .system .ui .lib .application import gui_app , MousePos , MAX_TOUCH_SLOTS , MouseEvent
89
@@ -14,6 +15,9 @@ class Device:
1415 device = Device ()
1516
1617
18+ W = TypeVar ('W' , bound = 'Widget' )
19+
20+
1721class DialogResult (IntEnum ):
1822 CANCEL = 0
1923 CONFIRM = 1
@@ -22,6 +26,7 @@ class DialogResult(IntEnum):
2226
2327class Widget (abc .ABC ):
2428 def __init__ (self ):
29+ self ._children : list [Widget ] = []
2530 self ._rect : rl .Rectangle = rl .Rectangle (0 , 0 , 0 , 0 )
2631 self ._parent_rect : rl .Rectangle | None = None
2732 self .__is_pressed = [False ] * MAX_TOUCH_SLOTS
@@ -197,12 +202,24 @@ def _handle_mouse_event(self, mouse_event: MouseEvent) -> None:
197202 """Optionally handle mouse events. This is called before rendering."""
198203 # Default implementation does nothing, can be overridden by subclasses
199204
205+ def _child (self , widget : W ) -> W :
206+ """Register a widget as a child. Lifecycle events (show/hide) propagate to registered children."""
207+ self ._children .append (widget )
208+ return widget
209+
200210 def show_event (self ):
201- """Optionally handle show event. Parent must manually call this"""
202- # TODO: iterate through all child objects, check for subclassing from Widget/Layout (Scroller)
211+ """Called when widget becomes visible. Propagates to registered children."""
212+ print (f"show_event: { type (self ).__name__ } " )
213+ for child in self ._children :
214+ print (f" show_event: { type (self ).__name__ } -> { type (child ).__name__ } " )
215+ child .show_event ()
203216
204217 def hide_event (self ):
205- """Optionally handle hide event. Parent must manually call this"""
218+ """Called when widget is hidden. Propagates to registered children."""
219+ print (f"hide_event: { type (self ).__name__ } " )
220+ for child in self ._children :
221+ print (f" hide_event: { type (self ).__name__ } -> { type (child ).__name__ } " )
222+ child .hide_event ()
206223
207224 def dismiss (self , callback : Callable [[], None ] | None = None ):
208225 """Immediately dismiss the widget, firing the callback after."""
0 commit comments