Skip to content

scenex.app.events#

scenex.app.events #

Event system for handling user input and interaction.

This module provides a unified event abstraction for user interactions across different GUI frameworks and rendering backends. Events represent user actions (e.g. mouse clicks, movement, scrolling) and system events (e.g. window resize), allowing event filters, camera controllers, etc. to respond to input in a framework-agnostic way.

Event Types

Keyboard Events: - KeyPressEvent: Key pressed - KeyReleaseEvent: Key released

Mouse Events: - MousePressEvent: Mouse button pressed - MouseReleaseEvent: Mouse button released - MouseMoveEvent: Mouse cursor moved - MouseDoublePressEvent: Mouse button double-pressed - MouseEnterEvent: Mouse entered a view - MouseLeaveEvent: Mouse left a view - WheelEvent: Mouse wheel scrolled

System Events: - ResizeEvent: Canvas window resized

Event Flow

Events are dispatched by the canvas to views and their camera controllers::

Canvas → View (filter_event) → Camera Controller (handle_event)

The flow works as follows: 1. Canvas determines which view contains the cursor position 2. Canvas calls the view's filter_event() method with the event 3. If the view's camera is interactive, the camera controller's handle_event() is called 4. Handlers return True to stop propagation or False to continue

Key Concepts

Ray: 3D ray in world space representing the mouse position - Used for 3D picking and intersection tests - Computed from 2D canvas position via camera unprojection

MouseButton: Enumeration of mouse buttons (LEFT, RIGHT, MIDDLE, etc.)

Examples:

Set a custom event filter on a view::

from scenex.model import View
from scenex.app.events import MousePressEvent


def on_click(event):
    if isinstance(event, MousePressEvent):
        print(f"Clicked at {event.canvas_pos}")
        return True  # Event handled
    return False


view = View(scene=my_scene, camera=my_camera)
view.set_event_filter(on_click)
See Also

scenex.model.Camera : Camera with interactive interaction strategies scenex.model.View : View with event filter support

Classes:

Event dataclass #

Event()

Base class for all user interaction and system events.

Event is the root of the event hierarchy in scenex. All specific event types (mouse, keyboard, resize) inherit from this base class, enabling polymorphic event handling and extensibility for custom event types.

The inheritance-based design allows: - Type checking with isinstance() to discriminate event types - Extensibility for adding new event types downstream - Structured event filtering based on event class hierarchy

See Also

MouseEvent : Base class for mouse-related events ResizeEvent : Window resize event

EventFilter #

Bases: ABC


              flowchart TD
              scenex.app.events.EventFilter[EventFilter]

              

              click scenex.app.events.EventFilter href "" "scenex.app.events.EventFilter"
            

Base class for event filter handles.

EventFilter instances are returned when installing event filters on views or canvases. They provide a mechanism to uninstall the filter when it's no longer needed, ensuring proper cleanup and preventing memory leaks.

Methods:

uninstall abstractmethod #

uninstall() -> None

Remove this event filter.

Uninstalls the event filter, ensuring that the filter function will no longer be called for future events. After calling uninstall(), this EventFilter instance should not be used further.

Source code in src/scenex/app/events/_events.py
402
403
404
405
406
407
408
409
410
@abstractmethod
def uninstall(self) -> None:
    """Remove this event filter.

    Uninstalls the event filter, ensuring that the filter function will no
    longer be called for future events. After calling uninstall(), this
    EventFilter instance should not be used further.
    """
    ...

KeyEvent dataclass #

KeyEvent(key: KeyBinding)

Bases: Event


              flowchart TD
              scenex.app.events.KeyEvent[KeyEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.Event --> scenex.app.events.KeyEvent
                


              click scenex.app.events.KeyEvent href "" "scenex.app.events.KeyEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Base class for keyboard events.

Attributes:

  • key (KeyBinding) –

    The key (or chord) that was pressed or released. Use KeyBinding.from_str("Ctrl+A") to construct from a string, or access key.part0 for the first (usually only) key and its modifier state (ctrl, shift, alt, meta).

See Also

KeyPressEvent : Key press KeyReleaseEvent : Key release

KeyPressEvent dataclass #

KeyPressEvent(key: KeyBinding)

Bases: KeyEvent


              flowchart TD
              scenex.app.events.KeyPressEvent[KeyPressEvent]
              scenex.app.events._events.KeyEvent[KeyEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.KeyEvent --> scenex.app.events.KeyPressEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.KeyEvent
                



              click scenex.app.events.KeyPressEvent href "" "scenex.app.events.KeyPressEvent"
              click scenex.app.events._events.KeyEvent href "" "scenex.app.events._events.KeyEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Keyboard key press.

See Also

KeyReleaseEvent : Key release

KeyReleaseEvent dataclass #

KeyReleaseEvent(key: KeyBinding)

Bases: KeyEvent


              flowchart TD
              scenex.app.events.KeyReleaseEvent[KeyReleaseEvent]
              scenex.app.events._events.KeyEvent[KeyEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.KeyEvent --> scenex.app.events.KeyReleaseEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.KeyEvent
                



              click scenex.app.events.KeyReleaseEvent href "" "scenex.app.events.KeyReleaseEvent"
              click scenex.app.events._events.KeyEvent href "" "scenex.app.events._events.KeyEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Keyboard key release.

See Also

KeyPressEvent : Key press

MouseButton #

Bases: IntFlag


              flowchart TD
              scenex.app.events.MouseButton[MouseButton]

              

              click scenex.app.events.MouseButton href "" "scenex.app.events.MouseButton"
            

Enumeration of mouse button states as bit flags.

MouseButton uses IntFlag to allow bitwise operations, enabling representation of multiple simultaneous button presses.

Examples:

Check if left button is pressed:

>>> event = MousePressEvent(
...     pos=(100, 150),
...     buttons=MouseButton.LEFT | MouseButton.RIGHT,
... )
>>> if event.buttons & MouseButton.LEFT:
...     print("Left button is down")
Left button is down

Check for specific button combination:

>>> if event.buttons == (MouseButton.LEFT | MouseButton.RIGHT):
...     print("Both left and right buttons pressed")
Both left and right buttons pressed

Check if any button is pressed:

>>> if event.buttons != MouseButton.NONE:
...     print("Some button is pressed")
Some button is pressed

MouseDoublePressEvent dataclass #

MouseDoublePressEvent(pos: tuple[float, float], buttons: MouseButton)

Bases: MouseEvent


              flowchart TD
              scenex.app.events.MouseDoublePressEvent[MouseDoublePressEvent]
              scenex.app.events._events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.MouseEvent --> scenex.app.events.MouseDoublePressEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.MouseEvent
                



              click scenex.app.events.MouseDoublePressEvent href "" "scenex.app.events.MouseDoublePressEvent"
              click scenex.app.events._events.MouseEvent href "" "scenex.app.events._events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse button double-click.

Fired when a mouse button is double-clicked (pressed twice in rapid succession). The timing threshold for double-click detection is system-dependent.

See Also

MousePressEvent : Single mouse button press

MouseEnterEvent dataclass #

MouseEnterEvent(pos: tuple[float, float], buttons: MouseButton)

Bases: MouseEvent


              flowchart TD
              scenex.app.events.MouseEnterEvent[MouseEnterEvent]
              scenex.app.events._events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.MouseEvent --> scenex.app.events.MouseEnterEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.MouseEvent
                



              click scenex.app.events.MouseEnterEvent href "" "scenex.app.events.MouseEnterEvent"
              click scenex.app.events._events.MouseEvent href "" "scenex.app.events._events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse cursor entering the view area.

Fired when the mouse cursor enters the bounds of a view from outside. Includes the entry position and button states.

See Also

MouseLeaveEvent : Mouse cursor leaving the view

MouseEvent dataclass #

MouseEvent(pos: tuple[float, float], buttons: MouseButton)

Bases: Event


              flowchart TD
              scenex.app.events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.Event --> scenex.app.events.MouseEvent
                


              click scenex.app.events.MouseEvent href "" "scenex.app.events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Base class for all mouse-related interaction events.

MouseEvent provides common fields for all mouse interactions, including the 2D position and the state of mouse buttons. Specific mouse event types (move, press, release, etc.) inherit from this base.

To obtain the 3D world ray for a mouse event, use View.to_ray().

Attributes:

  • pos (tuple[float, float]) –

    The (x, y) position of the mouse cursor in pixel coordinates, with origin at the top-left corner.

  • buttons (MouseButton) –

    Bit flags indicating which mouse buttons are currently pressed. Use bitwise operations to test button states (e.g., buttons & MouseButton.LEFT).

See Also

MouseMoveEvent : Mouse cursor movement MousePressEvent : Mouse button press MouseReleaseEvent : Mouse button release WheelEvent : Mouse wheel scroll

MouseLeaveEvent dataclass #

MouseLeaveEvent()

Bases: Event


              flowchart TD
              scenex.app.events.MouseLeaveEvent[MouseLeaveEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.Event --> scenex.app.events.MouseLeaveEvent
                


              click scenex.app.events.MouseLeaveEvent href "" "scenex.app.events.MouseLeaveEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse cursor leaving the view area.

Fired when the mouse cursor exits the bounds of a view. This is distinct from other mouse events in that it does not include position or button information, as the cursor is no longer over the view.

Note that this does not inherit from MouseEvent, as no position or buttons are available when the cursor has left the view.

See Also

MouseEnterEvent : Mouse cursor entering the view

MouseMoveEvent dataclass #

MouseMoveEvent(pos: tuple[float, float], buttons: MouseButton)

Bases: MouseEvent


              flowchart TD
              scenex.app.events.MouseMoveEvent[MouseMoveEvent]
              scenex.app.events._events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.MouseEvent --> scenex.app.events.MouseMoveEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.MouseEvent
                



              click scenex.app.events.MouseMoveEvent href "" "scenex.app.events.MouseMoveEvent"
              click scenex.app.events._events.MouseEvent href "" "scenex.app.events._events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse cursor movement within the view.

Fired when the mouse cursor moves within the view bounds. Includes the current position, world ray, and button states. This event fires continuously during cursor movement.

MousePressEvent dataclass #

MousePressEvent(pos: tuple[float, float], buttons: MouseButton)

Bases: MouseEvent


              flowchart TD
              scenex.app.events.MousePressEvent[MousePressEvent]
              scenex.app.events._events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.MouseEvent --> scenex.app.events.MousePressEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.MouseEvent
                



              click scenex.app.events.MousePressEvent href "" "scenex.app.events.MousePressEvent"
              click scenex.app.events._events.MouseEvent href "" "scenex.app.events._events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse button press.

Fired when a mouse button is pressed down. The buttons field indicates which button(s) are now pressed. For detecting which button was newly pressed, compare with previous button states.

See Also

MouseReleaseEvent : Mouse button release MouseDoublePressEvent : Double-click detection

MouseReleaseEvent dataclass #

MouseReleaseEvent(pos: tuple[float, float], buttons: MouseButton)

Bases: MouseEvent


              flowchart TD
              scenex.app.events.MouseReleaseEvent[MouseReleaseEvent]
              scenex.app.events._events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.MouseEvent --> scenex.app.events.MouseReleaseEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.MouseEvent
                



              click scenex.app.events.MouseReleaseEvent href "" "scenex.app.events.MouseReleaseEvent"
              click scenex.app.events._events.MouseEvent href "" "scenex.app.events._events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse button release.

Fired when a mouse button is released. The buttons field reflects the state after the release (i.e., the released button is no longer set in the flags).

See Also

MousePressEvent : Mouse button press

Ray #

Bases: NamedTuple


              flowchart TD
              scenex.app.events.Ray[Ray]

              

              click scenex.app.events.Ray href "" "scenex.app.events.Ray"
            

A 3D ray in world space representing a mouse position.

A Ray represents the path of the mouse cursor projected into 3D world space, starting from the camera and passing through the cursor position on the view. Rays are the fundamental mechanism for 3D picking and intersection testing, allowing determination of which scene objects are under the mouse cursor.

The ray is defined by an origin point (typically the camera position) and a normalized direction vector, and can be used to test intersections with scene geometry.

Attributes:

  • origin (tuple[float, float, float]) –

    The starting point of the ray in world coordinates, typically the camera position for perspective projections or a point on the view plane for orthographic projections.

  • direction (tuple[float, float, float]) –

    The normalized direction vector of the ray in world coordinates. For perspective views, this points from the camera through the cursor. For orthographic views, this is parallel to the camera's view direction.

  • source (View) –

    The view that generated this ray, providing context for which camera and scene the ray originated from.

Examples:

Find all intersections with a scene:

>>> import numpy as np
>>> import scenex as snx
>>> view = snx.View(
...     scene=snx.Scene(
...         children=[
...             snx.Image(data=np.random.rand(100, 100)),
...             snx.Points(
...                 vertices=np.asarray([[0, 0, 0], [1, 1, 0]]),
...                 size=5,
...                 edge_width=0,
...             ),
...         ]
...     )
... )
>>> ray = Ray(origin=(1, 1, 10), direction=(0, 0, -1), source=view)
>>> ray.intersections(view.scene)
[(Points(...), 7.5), (Image(...), 10.0)]
See Also

View.to_ray : Method to compute a Ray from a canvas position Node.passes_through : Node method for computing ray intersections

Methods:

  • intersections

    Find all nodes intersected by this ray in the scene graph.

  • point_at_distance

    Compute the 3D point at a given distance along the ray.

intersections #

intersections(graph: Node) -> list[Intersection]

Find all nodes intersected by this ray in the scene graph.

Recursively tests the ray against the given node and all its descendants, returning all intersections sorted by distance from the ray origin. Only visible nodes are tested.

Parameters:

  • graph #

    (Node) –

    The root node to test. Typically a Scene, but can be any node with children.

Returns:

  • list[Intersection]

    List of (node, distance) tuples for all intersections, sorted by increasing distance from the ray origin. The distance is the parameter t where intersection occurs at origin + t * direction.

Source code in src/scenex/app/events/_events.py
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
def intersections(self, graph: Node) -> list[Intersection]:
    """Find all nodes intersected by this ray in the scene graph.

    Recursively tests the ray against the given node and all its descendants,
    returning all intersections sorted by distance from the ray origin. Only
    visible nodes are tested.

    Parameters
    ----------
    graph : Node
        The root node to test. Typically a Scene, but can be any node with
        children.

    Returns
    -------
    list[Intersection]
        List of (node, distance) tuples for all intersections, sorted by
        increasing distance from the ray origin. The distance is the parameter
        t where intersection occurs at origin + t * direction.
    """
    through: list[Intersection] = []
    if graph.visible:
        # ...check the node itself...
        if (d := graph.passes_through(self)) is not None:
            through.append((graph, d))
        # ...then check its children...
        for child in graph.children:
            through.extend(self.intersections(child))
    return sorted(through, key=lambda inter: inter[1])

point_at_distance #

point_at_distance(distance: float) -> tuple[float, float, float]

Compute the 3D point at a given distance along the ray.

Parameters:

  • distance #

    (float) –

    The distance along the ray from the origin. Positive values extend in the direction of the ray, negative values extend backward from the origin.

Returns:

  • tuple[float, float, float]

    The (x, y, z) coordinates of the point at the specified distance along the ray.

Source code in src/scenex/app/events/_events.py
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
def point_at_distance(self, distance: float) -> tuple[float, float, float]:
    """Compute the 3D point at a given distance along the ray.

    Parameters
    ----------
    distance : float
        The distance along the ray from the origin. Positive values extend
        in the direction of the ray, negative values extend backward from
        the origin.

    Returns
    -------
    tuple[float, float, float]
        The (x, y, z) coordinates of the point at the specified distance
        along the ray.
    """
    x = self.origin[0] + self.direction[0] * distance
    y = self.origin[1] + self.direction[1] * distance
    z = self.origin[2] + self.direction[2] * distance
    return (x, y, z)

ResizeEvent dataclass #

ResizeEvent(width: int, height: int)

Bases: Event


              flowchart TD
              scenex.app.events.ResizeEvent[ResizeEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.Event --> scenex.app.events.ResizeEvent
                


              click scenex.app.events.ResizeEvent href "" "scenex.app.events.ResizeEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Window resize event.

Fired when a window changes dimensions, whether from user interaction (dragging window edges), programmatic resizing, or window manager actions. This event allows views and other components to adapt to new window dimensions.

Attributes:

  • width (int) –

    The new width of the window in pixels.

  • height (int) –

    The new height of the window in pixels.

WheelEvent dataclass #

WheelEvent(pos: tuple[float, float], buttons: MouseButton, angle_delta: tuple[float, float])

Bases: MouseEvent


              flowchart TD
              scenex.app.events.WheelEvent[WheelEvent]
              scenex.app.events._events.MouseEvent[MouseEvent]
              scenex.app.events._events.Event[Event]

                              scenex.app.events._events.MouseEvent --> scenex.app.events.WheelEvent
                                scenex.app.events._events.Event --> scenex.app.events._events.MouseEvent
                



              click scenex.app.events.WheelEvent href "" "scenex.app.events.WheelEvent"
              click scenex.app.events._events.MouseEvent href "" "scenex.app.events._events.MouseEvent"
              click scenex.app.events._events.Event href "" "scenex.app.events._events.Event"
            

Mouse wheel scroll event.

Fired when the mouse wheel (or trackpad scroll) is used. Includes the scroll delta in both horizontal and vertical directions. The magnitude and units of angle_delta are platform-dependent but typically represent degrees or steps.

Attributes:

  • angle_delta (tuple[float, float]) –

    The (horizontal, vertical) scroll delta. Positive vertical values typically represent scrolling up/away from the user, negative values down/toward the user. Horizontal scrolling (if supported) uses the first component.