Struct PaintContext

Source
pub struct PaintContext<'a> {
    pub layers: Vec<Layer>,
    pub overlay_layers: Vec<Layer>,
    pub clip_stack: ClipStack,
    pub origin: Offset,
    pub clip: ClipStackSnapshot,
    pub text_system: Option<&'a mut TextSystem>,
    /* private fields */
}
Expand description

Accumulates draw commands, clips, overlays, effects, and paint-time services.

Coordinates are window-space logical pixels unless a widget contract says otherwise. A fresh context contains one empty base layer, an empty clip stack, zero origin and frame time, default interaction state, and no text system. It is single-threaded because it exclusively borrows TextSystem.

§Examples

use ailloli_ui_runtime::scene::PaintCtx;
let ctx = PaintCtx::new();
assert_eq!(ctx.layers.len(), 1);
assert!(ctx.overlay_layers.is_empty() && ctx.text_system.is_none());

Fields§

§layers: Vec<Layer>

Draw commands grouped by clip layer (scissor / shader / stencil downstream).

§overlay_layers: Vec<Layer>

Top-level overlay layers appended after all base content.

§clip_stack: ClipStack

Mutable active clip entries, ordered outermost to innermost.

§origin: Offset

Caller-managed paint translation in logical pixels.

§clip: ClipStackSnapshot

Snapshot corresponding to the active clip stack.

§text_system: Option<&'a mut TextSystem>

Optional shared shaping engine and prepared-layout cache.

Implementations§

Source§

impl<'a> PaintContext<'a>

Provides the operations defined for PaintContext<'a>.

Source

pub fn new() -> Self

Creates an empty paint accumulator with one base layer.

§Examples
use ailloli_ui_runtime::scene::{LayerKind, PaintCtx};
let ctx = PaintCtx::new();
assert_eq!(ctx.layers[0].kind, LayerKind::Base);
assert!(ctx.clip.is_empty());
Source

pub fn with_text_system(text_system: &'a mut TextSystem) -> Self

Creates a fresh context borrowing a text system.

Input interaction stays at its default and frame time stays zero.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
use ailloli_ui_text::TextSystem;
let mut text = TextSystem::new();
let ctx = PaintCtx::with_text_system(&mut text);
assert!(ctx.text_system.is_some());
Source

pub fn with_text_system_and_input( text_system: &'a mut TextSystem, input: InputSnapshot, frame_time_ms: u128, ) -> Self

Creates a text-enabled context with an input snapshot and frame timestamp.

frame_time_ms is an opaque monotonic host timestamp in milliseconds; it is stored verbatim and is not compared with wall-clock time.

§Examples
use ailloli_ui_runtime::input::InputSnapshot;
use ailloli_ui_runtime::scene::PaintCtx;
use ailloli_ui_text::TextSystem;
let mut text = TextSystem::new();
let ctx = PaintCtx::with_text_system_and_input(
    &mut text, InputSnapshot::default(), 250,
);
assert_eq!(ctx.frame_time_ms(), 250);
Source

pub fn text_engine_mut(&mut self) -> Option<&mut ParleyEngine>

Borrows the underlying Parley engine, or returns None without text services.

Mutations through the engine bypass TextSystem cache accounting; prefer the higher-level text-system APIs unless direct shaping is required.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
let mut ctx = PaintCtx::new();
assert!(ctx.text_engine_mut().is_none());
Source

pub fn push(&mut self, cmd: DrawCmd)

Appends a command to the current base or innermost isolated layer.

If public mutation removed all base layers, this method first recreates one with the current clip snapshot. Commands preserve call order.

§Panics

May panic if caller mutation leaves an active isolated-layer index that no longer exists in layers.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, PaintCtx};
let mut ctx = PaintCtx::new();
ctx.push(DrawCmd::Rect(DrawRect { rect: Rect::new(0.0, 0.0, 4.0, 4.0), color: Color::WHITE }));
assert_eq!(ctx.layers[0].cmds.len(), 1);
Source

pub fn push_overlay(&mut self, cmd: DrawCmd)

Pushes a command into the current top-level overlay target.

Outside an explicit overlay clip, consecutive calls share one unclipped overlay layer. Self::into_scene places all overlay layers after base layers regardless of when this method was called.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, PaintCtx};
let mut ctx = PaintCtx::new();
ctx.push_overlay(DrawCmd::Rect(DrawRect { rect: Rect::new(0.0, 0.0, 4.0, 4.0), color: Color::WHITE }));
assert_eq!(ctx.overlay_layers[0].cmds.len(), 1);
Source

pub fn with_overlay_clip(&mut self, clip: Rect, f: impl FnOnce(&mut Self))

Pushes overlay commands into a layer clipped by a window-space rect.

Overlay clips are top-level and intentionally do not inherit parent widget clips. Nested overlay scopes target the innermost layer. On normal return, an unscoped overlay command starts a fresh layer after the clipped scope, preserving procedural order.

§Panics

A panic in f propagates without popping the overlay target, so callers that catch unwinding must discard the context rather than continue it.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, PaintCtx};
let mut ctx = PaintCtx::new();
let clip = Rect::new(10.0, 10.0, 20.0, 20.0);
ctx.with_overlay_clip(clip, |ctx| ctx.push_overlay(DrawCmd::Rect(DrawRect {
    rect: clip, color: Color::WHITE,
})));
assert_eq!(ctx.overlay_layers[0].clip.scissor_rect(), Some(clip));
Source

pub fn with_clip(&mut self, clip: Rect, f: impl FnOnce(&mut Self))

Runs f with an additional nested rectangular clip and base layer.

The full ancestor stack is retained. A new base pass is started both on entry and normal exit; empty passes are removed by Self::into_scene.

§Panics

A panic in f propagates before the clip is popped, so a caught unwind leaves this context unbalanced.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, PaintCtx};
let mut ctx = PaintCtx::new();
let clip = Rect::new(0.0, 0.0, 10.0, 10.0);
ctx.with_clip(clip, |ctx| ctx.push(DrawCmd::Rect(DrawRect { rect: clip, color: Color::WHITE })));
let scene = ctx.into_scene();
assert_eq!(scene.layers[0].clip.scissor_rect(), Some(clip));
Source

pub fn with_clip_isolated(&mut self, clip: Rect, f: impl FnOnce(&mut Self))

Pushes a single rectangular clip for a new layer without inheriting the stack.

Intersects clip with the current parent scissor when present. Useful for widget-local viewports that need a “fresh” clip stack (e.g. embedded surfaces, off-screen viewports) so they don’t re-apply expensive ancestor masks (round mask, stencil) on every contained draw. Most widgets should prefer Self::with_clip which keeps the full ancestor stack.

This is implemented as an isolated offscreen layer with no effects. If the requested rectangle does not intersect a parent scissor, the current compatibility behavior falls back to the requested rectangle rather than representing an empty clip.

§Panics

A panic in f propagates before the saved stack and snapshot are restored; a caught unwind leaves the context unsuitable for reuse.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, PaintCtx};
let mut ctx = PaintCtx::new();
let clip = Rect::new(2.0, 3.0, 8.0, 9.0);
ctx.with_clip_isolated(clip, |ctx| ctx.push(DrawCmd::Rect(DrawRect { rect: clip, color: Color::WHITE })));
assert!(ctx.into_scene().layers[0].isolated);
Source

pub fn with_isolated_effects( &mut self, clip: Rect, effects: IsolatedEffects, f: impl FnOnce(&mut Self), )

Runs f in a fresh clipped offscreen layer with post-effects.

The requested logical-pixel clip is intersected with the parent’s coarse scissor when they overlap; disjoint rectangles currently fall back to the requested clip. Nested depth starts at zero and is cast to u8, so more than 256 nested scopes wrap the stored diagnostic depth.

§Panics

A panic in f prevents stack restoration. Public mutation of layers inside f can also invalidate the recorded isolated index.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, IsolatedEffects, PaintCtx};
let mut ctx = PaintCtx::new();
let clip = Rect::new(0.0, 0.0, 20.0, 20.0);
ctx.with_isolated_effects(clip, IsolatedEffects { opacity: 0.5, ..Default::default() },
    |ctx| ctx.push(DrawCmd::Rect(DrawRect { rect: clip, color: Color::WHITE })));
assert_eq!(ctx.into_scene().layers[0].effects.opacity, 0.5);
Source

pub fn with_clip_shape( &mut self, clip: ClipShape, is_window_root: bool, f: impl FnOnce(&mut Self), )

Runs f with one additional clip shape and base-layer pass.

is_window_root is preserved on the clip entry for downstream surface handling. The active clip snapshot and stack are restored on normal return, and a new pass is opened after the scope.

§Panics

A panic in f propagates without restoring the clip stack.

§Examples
use ailloli_ui_core::{ClipShape, Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, PaintCtx};
let mut ctx = PaintCtx::new();
let rect = Rect::new(0.0, 0.0, 20.0, 10.0);
ctx.with_clip_shape(ClipShape::Rect(rect), true, |ctx| {
    ctx.push(DrawCmd::Rect(DrawRect { rect, color: Color::WHITE }));
});
assert!(ctx.into_scene().layers[0].clip.entries()[0].is_window_root);
Source

pub fn current_clip(&self) -> ClipStackSnapshot

Clones the active clip snapshot.

The returned snapshot remains unchanged after later scope transitions.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert!(PaintCtx::new().current_clip().is_empty());
Source

pub fn current_clip_bbox(&self) -> Option<Rect>

Returns the coarse axis-aligned intersection of active clip bounds.

None means no active clip or a disjoint stack.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert_eq!(PaintCtx::new().current_clip_bbox(), None);
Source

pub fn set_current_interaction( &mut self, interaction: InputInteraction, ) -> InputInteraction

Replaces paint-time interaction flags and returns the previous value.

This does not invalidate any element; the paint traversal uses it to scope a widget’s focused, hovered, and pressed state.

§Examples
use ailloli_ui_runtime::input::InputInteraction;
use ailloli_ui_runtime::scene::PaintCtx;
let mut ctx = PaintCtx::new();
let previous = ctx.set_current_interaction(InputInteraction { hovered: true, ..Default::default() });
assert!(!previous.hovered && ctx.is_hovered());
Source

pub fn interaction(&self) -> InputInteraction

Returns all current paint-time interaction flags by value.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert_eq!(PaintCtx::new().interaction(), Default::default());
Source

pub fn is_focused(&self) -> bool

Returns whether the currently painted widget owns keyboard focus.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert!(!PaintCtx::new().is_focused());
Source

pub fn has_focus_within(&self) -> bool

Whether this element or a descendant owns keyboard focus.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert!(!PaintCtx::new().has_focus_within());
Source

pub fn is_hovered(&self) -> bool

Returns whether the pointer currently hovers the painted widget.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert!(!PaintCtx::new().is_hovered());
Source

pub fn is_pressed(&self) -> bool

Returns whether the painted widget owns an active pointer press.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert!(!PaintCtx::new().is_pressed());
Source

pub fn frame_time_ms(&self) -> u128

Returns the opaque host frame timestamp in milliseconds.

A context created without explicit input uses zero. This is not elapsed time and arithmetic is the caller’s responsibility.

§Examples
use ailloli_ui_runtime::scene::PaintCtx;
assert_eq!(PaintCtx::new().frame_time_ms(), 0);
Source

pub fn into_scene(self) -> Scene

Consumes the context and returns non-empty layers in final paint order.

Empty base and overlay layers are removed. Remaining base layers come first with kind normalized to LayerKind::Base, followed by every overlay layer normalized to LayerKind::Overlay. Command order within each layer is unchanged.

§Examples
use ailloli_ui_core::{Color, Rect};
use ailloli_ui_runtime::scene::{DrawCmd, DrawRect, LayerKind, PaintCtx};
let mut ctx = PaintCtx::new();
ctx.push_overlay(DrawCmd::Rect(DrawRect { rect: Rect::new(0.0, 0.0, 1.0, 1.0), color: Color::WHITE }));
let scene = ctx.into_scene();
assert_eq!(scene.layers.len(), 1);
assert_eq!(scene.layers[0].kind, LayerKind::Overlay);

Trait Implementations§

Source§

impl<'a> Default for PaintContext<'a>

Implements the Default contract for PaintContext<'a>.

Source§

fn default() -> Self

Constructs the documented default value.

Source§

impl<'a> Painter for PaintContext<'a>

Implements the Painter contract for PaintContext<'a>.

Source§

fn push(&mut self, cmd: DrawCmd)

Implements the push helper used by this module.

Source§

fn push_clipped(&mut self, cmd: DrawCmd, clip: Option<Rect>)

Implements the push_clipped helper used by this module.

Auto Trait Implementations§

§

impl<'a> Freeze for PaintContext<'a>

§

impl<'a> !RefUnwindSafe for PaintContext<'a>

§

impl<'a> Send for PaintContext<'a>

§

impl<'a> Sync for PaintContext<'a>

§

impl<'a> Unpin for PaintContext<'a>

§

impl<'a> !UnwindSafe for PaintContext<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> ErasedDestructor for T
where T: 'static,