Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions docs/references/app/events.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
icon: lucide/code
---

# scenex.app.events

:::scenex.app.events
File renamed without changes.
23 changes: 0 additions & 23 deletions src/scenex/adaptors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,29 +35,6 @@
**vispy** (OpenGL-based):
- Mature, widely-supported OpenGL renderer

Usage
-----
Adaptors are NOT intended for manual instantiation; they are instead created
automatically by `scenex.show()`::

>>> import scenex as snx
>>> import numpy as np

>>> # Create model
>>> my_array = np.random.rand(100, 100).astype(np.float32)
>>> scene = snx.Scene(children=[snx.Image(data=my_array)])

>>> # This creates adaptors automatically
>>> snx.show(scene)
Canvas(...)
>>> snx.run()

To select a particular backend, use `scenex.use()`::

>>> snx.use("pygfx") # doctest: +SKIP
>>> snx.show(scene)
Canvas(...)

See Also
--------
scenex.model : Declarative model classes
Expand Down
15 changes: 9 additions & 6 deletions src/scenex/adaptors/_auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,16 +100,19 @@ def use(backend: KnownBackend | None = None) -> None:
Examples
--------
Use pygfx backend explicitly:
>>> import scenex as snx
>>> snx.use("pygfx") # doctest: +SKIP
>>> canvas = snx.show(snx.View())

>>> import scenex as snx
>>> snx.use("pygfx") # doctest: +SKIP
>>> canvas = snx.show(snx.View())

Use vispy backend:
>>> snx.use("vispy") # doctest: +SKIP
>>> canvas = snx.show(snx.Scene())

>>> snx.use("vispy") # doctest: +SKIP
>>> canvas = snx.show(snx.Scene())

Reset to auto-detection:
>>> snx.use(None)

>>> snx.use(None)

Notes
-----
Expand Down
30 changes: 15 additions & 15 deletions src/scenex/app/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,28 @@
**WxPython**
**Jupyter**

Usage
-----
The app is typically created automatically by `scenex.show()` and/or `scenex.run()`::
Examples
--------
The app is typically created automatically by `scenex.show()` and/or `scenex.run()`:

>>> import scenex as snx
>>> import numpy as np
>>> import scenex as snx
>>> import numpy as np

>>> # Create a scenex scene
>>> my_array = np.random.rand(100, 100).astype(np.float32)
>>> my_scene = snx.Scene(children=[snx.Image(data=my_array)])
>>> # Create a scenex scene
>>> my_array = np.random.rand(100, 100).astype(np.float32)
>>> my_scene = snx.Scene(children=[snx.Image(data=my_array)])

>>> # Showing the scene creates the app if needed
>>> snx.show(my_scene)
Canvas(...)
>>> snx.run() # Starts the event loop
>>> # Showing the scene creates the app if needed
>>> snx.show(my_scene)
Canvas(...)
>>> snx.run() # Starts the event loop

But it CAN be useful to access the app instance directly. For example, it can be useful
to ask the app to process any pending events::
to ask the app to process any pending events:

>>> from scenex.app import app
>>> from scenex.app import app

>>> app().process_events()
>>> app().process_events()

Notes
-----
Expand Down
36 changes: 21 additions & 15 deletions src/scenex/app/_auto.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,14 @@ class CursorType(Enum):
Examples
--------
Set a crosshair cursor during drawing mode:
>>> import scenex as snx
>>> canvas = snx.Canvas()
>>> snx.set_cursor(canvas, CursorType.CROSS) # doctest: +SKIP

>>> import scenex as snx
>>> canvas = snx.Canvas()
>>> snx.set_cursor(canvas, CursorType.CROSS) # doctest: +SKIP

Restore default cursor after operation:
>>> snx.set_cursor(canvas, CursorType.DEFAULT) # doctest: +SKIP

>>> snx.set_cursor(canvas, CursorType.DEFAULT) # doctest: +SKIP

See Also
--------
Expand Down Expand Up @@ -451,12 +453,13 @@ def ensure_main_thread(func: Callable[P, T]) -> Callable[P, Future[T]]:
Examples
--------
Ensure a GUI operation runs on the main thread:
>>> @ensure_main_thread
... def update_widget(value: int) -> None:
... # Update some GUI widget with the given value
... pass
>>> future = update_widget(42) # Returns immediately with Future
>>> result = future.result() # Block until completion if needed

>>> @ensure_main_thread
... def update_widget(value: int) -> None:
... # Update some GUI widget with the given value
... pass
>>> future = update_widget(42) # Returns immediately with Future
>>> result = future.result() # Block until completion if needed

See Also
--------
Expand Down Expand Up @@ -499,12 +502,14 @@ def determine_app() -> GuiFrontend:
Examples
--------
Let the function auto-detect the backend:
>>> backend = determine_app()

>>> backend = determine_app()

Force a specific backend via environment variable:
>>> import os
>>> os.environ["SCENEX_APP_BACKEND"] = "qt" # doctest: +SKIP
>>> backend = determine_app() # Will use Qt

>>> import os
>>> os.environ["SCENEX_APP_BACKEND"] = "qt" # doctest: +SKIP
>>> backend = determine_app() # Will use Qt

See Also
--------
Expand Down Expand Up @@ -562,7 +567,8 @@ def app() -> App:
Examples
--------
Get the app and run the event loop:
>>> app().run()

>>> app().run()

See Also
--------
Expand Down
64 changes: 34 additions & 30 deletions src/scenex/app/events/_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,26 @@ class MouseButton(IntFlag):
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

>>> 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

>>> 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

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

NONE = 0
Expand Down Expand Up @@ -99,23 +102,24 @@ class Ray(NamedTuple):
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)]

>>> 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
--------
Expand Down
26 changes: 13 additions & 13 deletions src/scenex/imgui/_controls.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,19 +90,19 @@ def add_imgui_controls(view: View) -> None:

Examples
--------
Basic usage with an image::

>>> import scenex as snx
>>> import numpy as np
>>> from scenex.imgui import add_imgui_controls

>>> my_array = np.random.rand(100, 100).astype(np.float32)
>>> image = snx.Image(data=my_array)
>>> view = snx.View(scene=snx.Scene(children=[image]))
>>> snx.show(view)
Canvas(...)
>>> add_imgui_controls(view)
>>> snx.run()
Basic usage with an image:

>>> import scenex as snx
>>> import numpy as np
>>> from scenex.imgui import add_imgui_controls

>>> my_array = np.random.rand(100, 100).astype(np.float32)
>>> image = snx.Image(data=my_array)
>>> view = snx.View(scene=snx.Scene(children=[image]))
>>> snx.show(view)
Canvas(...)
>>> add_imgui_controls(view)
>>> snx.run()

The control panel will show sections for:
- View properties (camera, layout, etc.)
Expand Down
24 changes: 12 additions & 12 deletions src/scenex/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,23 +49,23 @@

Examples
--------
Build a simple scene::
Build a simple scene:

>>> from scenex.model import Scene, Image, Points
>>> import numpy as np
>>> from scenex.model import Scene, Image, Points
>>> import numpy as np

>>> scene = Scene(
... children=[
... Image(data=np.random.rand(100, 100)),
... Points(vertices=np.random.rand(50, 2) * 100),
... ]
... )
>>> scene = Scene(
... children=[
... Image(data=np.random.rand(100, 100)),
... Points(vertices=np.random.rand(50, 2) * 100),
... ]
... )

Create a view with interactive camera::
Create a view with interactive camera:

>>> from scenex.model import View, Camera, PanZoom
>>> from scenex.model import View, Camera, PanZoom

>>> view = View(scene=scene, camera=Camera(controller=PanZoom(), interactive=True))
>>> view = View(scene=scene, camera=Camera(controller=PanZoom(), interactive=True))

Notes
-----
Expand Down
9 changes: 6 additions & 3 deletions src/scenex/model/_canvas.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,16 @@ class Canvas(EventedBase):
Examples
--------
Create a simple canvas with default settings:
>>> canvas = Canvas()

>>> canvas = Canvas()

Create a canvas with custom size and title:
>>> canvas = Canvas(width=800, height=600, title="My Visualization")

>>> canvas = Canvas(width=800, height=600, title="My Visualization")

Create a canvas with multiple views side-by-side:
>>> canvas = Canvas(width=800, height=400, views=[View(), View()])

>>> canvas = Canvas(width=800, height=400, views=[View(), View()])
"""

width: int = Field(default=600, description="The width of the canvas in pixels")
Expand Down
23 changes: 12 additions & 11 deletions src/scenex/model/_color.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,10 @@ class UniformColor(ColorModel):
Examples
--------
Uniform coloring:
>>> from cmap import Color
>>> from scenex import UniformColor
>>> model = UniformColor(color=Color("red"))

>>> from cmap import Color
>>> from scenex import UniformColor
>>> model = UniformColor(color=Color("red"))
"""

color: Color = Field(default_factory=lambda: Color("white"))
Expand All @@ -54,9 +55,10 @@ class FaceColors(ColorModel):
Examples
--------
Per-face coloring:
>>> from cmap import Color
>>> from scenex import FaceColors
>>> model = FaceColors(color=[Color("red"), Color("blue"), Color("green")])

>>> from cmap import Color
>>> from scenex import FaceColors
>>> model = FaceColors(color=[Color("red"), Color("blue"), Color("green")])
"""

color: Sequence[Color]
Expand All @@ -72,11 +74,10 @@ class VertexColors(ColorModel):
Examples
--------
Per-vertex coloring:
>>> from cmap import Color
>>> from scenex import VertexColors
>>> model = VertexColors(
... color=[Color("yellow"), Color("purple"), Color("cyan")]
... )

>>> from cmap import Color
>>> from scenex import VertexColors
>>> model = VertexColors(color=[Color("yellow"), Color("purple"), Color("cyan")])
"""

color: Sequence[Color]
Loading
Loading