Skip to main content

WetLayer

Struct WetLayer 

Source
pub struct WetLayer(/* private fields */);
Expand description

A surface for content being authored right now, which repaints without taking the scene’s item bands with it.

The case is ink. A stroke in flight changes on every pointer sample, and there is no way to invalidate a SceneView’s foreground alone: the render walker computes one needs_paint per node and gates that node’s paint and its post_paint with it, so asking the view to repaint re-runs the whole Under band as well. A wet layer is its own node, so request_repaint marks that node and nothing else.

The painter draws in scene coordinates — the node lives inside the view’s content transform, so a wet stroke pans and zooms with the page for free, and a scene point can be drawn at its own value.

Where it lands in the paint order, and why: above every card and every Interleaved item, under the Over band and the view’s own chrome (marquee, magnet feedback, transform frame, debug overlay). docs/teksilo-scene.md states the whole order.

let points: Rc<RefCell<Vec<Point>>> = Rc::default();
let wet = {
    let points = points.clone();
    WetLayer::new(move |canvas, _ctx| {
        for p in points.borrow().iter() {
            canvas.fill_circle(*p, 2.0, Color::BLACK);
        }
    })
};
let view = SceneView::new(Scene::new()).wet_layer(wet.clone());
// …and from a pointer handler, after pushing a point:
// wet.request_repaint(ctx);

A cloneable handle: clone it into the pointer handler that feeds it and into SceneView::wet_layer, the way a SceneModel is cloned into its views.

§More than one view

The comparison with SceneModel is meant literally. Mount the same layer in two views — an overview beside a detail pane — and both paint it, and request_repaint repaints both. A second view does not displace the first.

One thing does not carry across, and it is a property of the door rather than of this type: a repaint is requested through an EventContext, and a context belongs to one window’s tree. So request_repaint repaints the mounts in the calling context’s own window and leaves a mount in another window to that window’s own frame — an id from the other tree could not reach it anyway, because ids are per-arena slot keys and two trees mint the same ones.

That last sentence is the reason request_repaint does not simply push the ids it holds: it resolves each one in the calling tree through a typed door first, so a stale id can only ever land on one of this layer’s own nodes there — or trip an assertion. The rule and its one remaining edge (the same layer mounted in two window-less trees) are written out at request_repaint.

Implementations§

Source§

impl WetLayer

Source

pub fn new( painter: impl Fn(&mut Canvas, &SceneItemPaintContext<'_>) + 'static, ) -> Self

A wet surface painted by painter, in scene coordinates.

The closure is called on every repaint of a node this layer is mounted in, and on nothing else. It owns whatever the app is authoring — a stroke’s points, a rubber-band shape, a live measurement — typically through an Rc<RefCell<…>> shared with the pointer handler that feeds it.

Source

pub fn request_repaint(&self, ctx: &mut EventContext<'_>)

Repaint the wet surface, and only it.

No relayout, no rebuild, no accessibility re-walk — and, crucially, no repaint of the scene’s item bands: this marks nodes, one per view that mounted the layer in ctx’s own window.

A no-op until the layer has been mounted through SceneView::wet_layer and the view has built, which is the frame before any handler can run.

§Why the id goes through a typed door

A [WidgetId] is a slot key in some arena, and every tree mints the same ones. The window a mount was made in narrows the candidates — a tree belongs to exactly one window — but a headless tree has no window, so None == None is not a match, it is two unknowns comparing equal. Marking on that alone is how a repaint from one test’s tree lands on whatever unrelated widget happens to hold that slot in another’s.

So the mark is not pushed as a bare request_repaint. It goes through with_widget_mut, which resolves the id in the calling tree and hands the node over only if it downcasts to this crate’s own WetLayerNode — and the closure then checks it is a node of this layer. Both checks fail loudly (debug_assert) rather than quietly, so a cross-tree repaint is a test failure instead of a stray dirty bit.

What that buys, stated exactly:

  • An id naming a slot the calling tree does not fill, or fills with a widget that has not opted into Widget::as_any_mut — which is every ordinary widget, the default being None — reaches nothing, in both profiles. That is the case this used to get wrong: the foreign id was marked, and whatever held the slot repainted.
  • An id naming a WetLayerNode of this layer is marked, which is right: that node’s own mount is in the same list, so it wanted repainting anyway.
  • An id naming a node that has opted into as_any_mut and is not one of this layer’s trips the assertion, so in a test or a dev build it is a panic. In release the closure is skipped and the node still takes the RepaintOnly mark, which costs one repaint of something already on screen — never a mutation, never a relayout, rebuild or accessibility change.

So this does not make one layer in two window-less trees work; it makes the attempt fail where it can be seen. Drive each tree’s repaint itself, from nodes.

Source

pub fn nodes(&self) -> Vec<WetNode>

The nodes this layer paints into — one per mounted view, in mount order, each paired with the window whose tree holds it.

Exposed for a caller that wants to drive the repaint through some other door than request_repaint — a WidgetTree::mark_needs_paint in a test, say. Such a caller owns the question request_repaint answers from its context: which tree a given node belongs to, which is why this reports WetNode::window beside the id rather than the id alone. With one view (the overwhelmingly common case) that is the one tree there is.

Trait Implementations§

Source§

impl Clone for WetLayer

Source§

fn clone(&self) -> WetLayer

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for WetLayer

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

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
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

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

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self> ⓘ

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self> ⓘ

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self> ⓘ
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more