Skip to main content

Element

Struct Element 

Source
pub struct Element<W: Widget> { /* private fields */ }
Expand description

A node under construction: its widget, its style, its pending bindings and its children.

Build one with a widget constructor such as panel, chain the builder methods, and hand it to a parent with Element::child or to show.

A builder takes either a plain value, which is written into the style immediately, or a closure, which becomes a binding that is read at mount and again whenever a signal it reads changes.

Implementations§

Source§

impl<W: Widget> Element<W>

Source

pub fn new(widget: W) -> Element<W>

Creates an element for widget with the default style.

use smudge_core::element::Element;
use smudge_core::widget::Panel;

let element = Element::new(Panel);
Source

pub fn child(self, child: impl IntoElement) -> Self

Appends child after the children the element already has.

When Element::style_children set a style for the children, it is applied to this one.

Source

pub fn children( self, children: impl IntoIterator<Item = impl IntoElement>, ) -> Self

Appends every child of children, in order.

When Element::style_children set a style for the children, it is applied to each one.

Source

pub fn style_children(self, style: impl Fn(&mut Style) + 'static) -> Self

Applies style to every direct child of this element: to the children added so far, at once, and to every child added afterwards as it is added.

The children of a child keep their own style, and a child that mounts later through show mounts under a slot, so it is styled only through that slot. A binding on the same field of a child applies when the child mounts, after this style, so the binding wins.

This is how a container decides how its children sit: a stack applies the absolute position that makes children overlap, for example.

use smudge_core::element::Element;
use smudge_core::widget::Panel;

let layers = Element::new(Panel).style_children(|style| {
    style.paint.corner_radius = 4.0.into();
});
Source

pub fn width(self, width: impl Into<Value<Length>>) -> Self

Sets the width. This takes part in layout.

Source

pub fn height(self, height: impl Into<Value<Length>>) -> Self

Sets the height. This takes part in layout.

Source

pub fn size(self, size: impl Into<Value<Size>>) -> Self

Sets the width and the height, in logical pixels. This takes part in layout.

Source

pub fn min_width(self, width: impl Into<Value<Length>>) -> Self

Sets the lower bound of the width. This takes part in layout.

Source

pub fn min_height(self, height: impl Into<Value<Length>>) -> Self

Sets the lower bound of the height. This takes part in layout.

Source

pub fn max_width(self, width: impl Into<Value<Length>>) -> Self

Sets the upper bound of the width. This takes part in layout.

Source

pub fn max_height(self, height: impl Into<Value<Length>>) -> Self

Sets the upper bound of the height. This takes part in layout.

Source

pub fn padding(self, padding: impl Into<Value<Length>>) -> Self

Sets the same padding on all four sides. This takes part in layout.

Source

pub fn padding_xy(self, padding: impl Into<Value<Size>>) -> Self

Sets the horizontal padding from width and the vertical padding from height. This takes part in layout.

Source

pub fn margin(self, margin: impl Into<Value<Length>>) -> Self

Sets the same margin on all four sides. This takes part in layout.

Source

pub fn gap(self, gap: impl Into<Value<Size>>) -> Self

Sets the space between adjacent children. This takes part in layout.

Source

pub fn direction(self, direction: impl Into<Value<Direction>>) -> Self

Sets the main axis of the children’s flex layout. This takes part in layout.

Source

pub fn row(self) -> Self

Lays the children out left to right. This takes part in layout.

Source

pub fn column(self) -> Self

Lays the children out top to bottom. This takes part in layout.

Source

pub fn wrap(self, wrap: impl Into<Value<bool>>) -> Self

Lets children that do not fit move to a new line instead of shrinking. This takes part in layout.

Source

pub fn grow(self, grow: impl Into<Value<f32>>) -> Self

Sets the share of the leftover space on the main axis this node takes. This takes part in layout.

Source

pub fn shrink(self, shrink: impl Into<Value<f32>>) -> Self

Sets how readily this node gives up space when its siblings overflow. This takes part in layout.

Source

pub fn basis(self, basis: impl Into<Value<Length>>) -> Self

Sets the main axis size the node starts from before growing or shrinking. This takes part in layout.

Source

pub fn align_items(self, align: impl Into<Value<Align>>) -> Self

Sets how the children line up across the main axis. This takes part in layout.

Source

pub fn justify_content(self, justify: impl Into<Value<Justify>>) -> Self

Sets how the children are spread along the main axis. This takes part in layout.

Source

pub fn absolute(self) -> Self

Takes the node out of normal flow, so its insets place it against its containing block and its siblings are laid out as if it were not there. This takes part in layout.

Source

pub fn inset(self, inset: impl Into<Value<Edges<Length>>>) -> Self

Sets the offsets from the containing block’s edges. This takes part in layout.

Source

pub fn border(self, width: impl Into<Value<f32>>) -> Self

Sets the border width, the same on all four sides. This takes part in layout, because the border takes space away from the content. The border is painted in the color set by Element::border_color.

Source

pub fn clip(self, clip: impl Into<Value<bool>>) -> Self

Clips the children to the node’s bounds. This takes part in layout, because clipping also changes the automatic minimum size of a flex item.

Source

pub fn overflow(self, overflow: impl Into<Value<Overflow>>) -> Self

Sets what happens to children that do not fit inside the node. This takes part in layout: Overflow::Scroll makes the node a scroll container, whose automatic minimum size as a flex item is zero, and Element::clip is the shorthand for Overflow::Clip.

Source

pub fn hidden(self, hidden: impl Into<Value<bool>>) -> Self

Hides the node and its subtree, or shows them again. This takes part in layout, because a hidden node is not laid out and paints nothing.

Source

pub fn scroll_offset(self, offset: impl Into<Value<Point>>) -> Self

Translates the node’s flowing children by this offset after layout, outside the layout engine.

This is what a scroll view changes when it scrolls: every child that stays in the flow moves by minus the offset in the window, without running the layout engine again. The frame damages the areas the children moved out of and into and wraps them in an offset display item, so a child that only moved does not paint again. An absolutely positioned child is left where its insets place it, so chrome drawn over the content does not scroll away with it.

The offset can be bound to a signal, like the style builders. It is a position, not a style: it takes part in no layout comparison, and an equal offset changes nothing.

Source

pub fn pin_child(self, pin: impl Fn() -> Option<(usize, f32)> + 'static) -> Self

Keeps one flowing child at a fixed place inside the node, whatever the heights of the children before it.

While pin returns Some((index, y)), every layout pass ends with the top of the flowing child at index sitting y logical pixels below the top of the node’s content box. The children keep their order and the sizes the pass gave them, so the ones before the pinned child stack upward from it and the ones after it stack downward, edge to edge. A child that grows therefore pushes its neighbours away from the pinned child in the frame it grows, and never overlaps them.

The pin moves the children the way Element::scroll_offset does, outside the layout engine, so do not give the node a scroll offset too. None, an index past the last child, or a pinned child that is hidden or absolutely positioned leaves the children where they are. A change of the pin alone moves them without a layout pass.

use smudge_core::element::Element;
use smudge_core::style::px;
use smudge_core::widget::{Panel, panel};

// The second row stays 100 pixels down, however tall the first is.
let rows = Element::new(Panel)
    .column()
    .pin_child(|| Some((1, 100.0)))
    .child(panel().height(px(30.0)))
    .child(panel().height(px(30.0)));
Source

pub fn background(self, color: impl Into<Value<ColorValue>>) -> Self

Sets the fill painted behind the node. This repaints the node without laying it out again.

The color can be a Color or a ColorToken. A token resolves against the theme that is current when the node paints.

Source

pub fn border_color(self, color: impl Into<Value<ColorValue>>) -> Self

Sets the color of the border whose width Element::border sets. This repaints the node without laying it out again.

The color can be a Color or a ColorToken. A token resolves against the theme that is current when the node paints.

Source

pub fn text_color(self, color: impl Into<Value<ColorValue>>) -> Self

Sets the color a widget’s text paints with. This repaints the node without laying it out again.

Widgets that show text read it; widgets without text ignore it. The color can be a Color or a ColorToken. A token resolves against the theme that is current when the node paints.

Source

pub fn corner_radius(self, radius: impl Into<Value<RadiusValue>>) -> Self

Sets the corner radius of the background and the border, the same on all four corners. An image widget rounds the pixels it paints by the same radius. This repaints the node without laying it out again.

The radius can be an f32 or a RadiusToken. A token resolves against the theme that is current when the node paints.

Source

pub fn hover(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self

Applies a patch while the node is in the hovered chain, which is the node under the pointer that can respond and its ancestors.

The closure records static values into a PatchBuilder; a reactive value has no place in a patch, so the patch methods take plain values. While the pointer is over the node the patch overrides the fields it sets, and when the pointer leaves, the base style stands again. A node with a variant is a target for hover and presses even without handlers, so a styled card reacts to the pointer on its own.

A change of hover re-resolves the style: a patch that touches only paint properties repaints the node, one that touches layout properties lays it out again. Hover also follows a layout that moves nodes under a resting pointer, except that a layout never takes the hover away from a node whose hover patch changes its layout: such a patch can move the node off the pointer, and the node then stays hovered until the pointer moves, instead of flickering.

use smudge_core::geometry::Color;
use smudge_core::widget::panel;

let card = panel()
    .background(Color::rgb(50, 50, 50))
    .hover(|p| p.background(Color::rgb(70, 70, 70)));
Source

pub fn focused(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self

Applies a patch while the node holds the keyboard focus and the focus last moved by keyboard navigation.

The focus a press moved draws no focus style, so a ring follows Tab and not a mouse click. Everything else works as hover does.

use smudge_core::geometry::Color;
use smudge_core::style::px;
use smudge_core::widget::panel;

let field = panel()
    .width(px(120.0))
    .height(px(24.0))
    .focusable()
    .focused(|p| p.border(1.0).border_color(Color::rgb(0, 120, 215)));
Source

pub fn pressed(self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder) -> Self

Applies a patch while a primary press is held on the node.

Everything works as hover does; the pressed state starts when the button goes down on the node and ends when it is released.

use smudge_core::geometry::Color;
use smudge_core::widget::panel;

let button = panel()
    .background(Color::rgb(50, 50, 50))
    .pressed(|p| p.background(Color::rgb(30, 30, 30)));
Source

pub fn disabled_style( self, patch: impl FnOnce(PatchBuilder) -> PatchBuilder, ) -> Self

Applies a patch while the node is disabled.

The patch wins over every other state, so a disabled control keeps its switched-off look while it is hovered or pressed. Everything else works as hover does.

use smudge_core::geometry::Color;
use smudge_core::widget::panel;

let button = panel()
    .background(Color::rgb(50, 50, 50))
    .disabled_style(|p| p.background(Color::rgb(35, 35, 35)));
Source

pub fn on_press(self, handler: impl FnMut() + 'static) -> Self

Runs handler when the primary button is released over the node after a press that started on it.

The press is captured: between the press and the release the node keeps the pointer even when it moves away, and the handler runs only when the release happens over the node again. A press released elsewhere runs nothing.

use std::cell::Cell;
use std::rc::Rc;

use smudge_core::app::{App, AppConfig, RepaintMode};
use smudge_core::geometry::{Color, Point, Size};
use smudge_core::input::{InputEvent, PointerButton};
use smudge_core::style::px;
use smudge_core::widget::panel;

let presses = Rc::new(Cell::new(0u32));
let counted = Rc::clone(&presses);
let mut app = App::new(
    AppConfig {
        viewport: Size {
            width: 100.0,
            height: 60.0,
        },
        scale: 1.0,
        clear_color: Color::WHITE,
        repaint: RepaintMode::Damage,
    },
    move || {
        panel().width(px(40.0)).height(px(20.0)).on_press(move || {
            counted.set(counted.get() + 1);
        })
    },
);
app.frame();

let corner = Point { x: 10.0, y: 5.0 };
app.handle_event(InputEvent::PointerMoved { position: corner });
app.handle_event(InputEvent::PointerDown {
    position: corner,
    button: PointerButton::Primary,
});
app.handle_event(InputEvent::PointerUp {
    position: corner,
    button: PointerButton::Primary,
});
assert_eq!(presses.get(), 1);
Source

pub fn on_hover(self, handler: impl FnMut(bool) + 'static) -> Self

Runs handler when the node enters (true) or leaves (false) the hovered chain.

The hovered chain is the nearest enabled node under the pointer that can respond and its enabled ancestors, so a container stays hovered while the pointer is over one of its children, and a disabled node never hears it. While a press is held, hover does not change until the button is released. The handler runs inside the node’s owner, so it can write the signals the element’s bindings read.

Source

pub fn on_pointer_down(self, handler: impl FnMut(Point) + 'static) -> Self

Runs handler when the primary pointer button is pressed on the node.

The position is in logical pixels, relative to the top left of the node’s rectangle, so it does not depend on where layout or a scroll view put the node. Other buttons do not run it.

Source

pub fn on_press_outside(self, handler: impl FnMut() + 'static) -> Self

Runs handler when a primary press targets a node that is neither this node nor one of its descendants.

A press on the node itself, on a child, or on a deeper descendant does not run it, so a popup asks for presses outside itself and closes on the ones it gets. A press that reaches no node at all is outside every node.

Source

pub fn on_wheel(self, handler: impl FnMut(Point) -> Handled + 'static) -> Self

Runs handler when the wheel scrolls while the node is in the hovered chain, which is the case when the pointer is over the node or over one of its descendants.

The delta is in logical pixels, positive for scrolling right and down. The handlers run from the deepest node in the hovered chain outward, and the first that returns Handled::Yes takes the whole event, so of two nested scroll views the one under the pointer scrolls and the one around it does not. A handler that cannot use the event, such as a view already scrolled to its end in the wheel’s direction, returns Handled::No and the event bubbles to the next one. The handler runs inside the node’s owner, so it can write the signals the element’s bindings read.

Source

pub fn on_pointer_move(self, handler: impl FnMut(Point) + 'static) -> Self

Runs handler when the pointer moves while a press that started on the node is held, which is how a drag reaches the node it started on.

With no press held, the handler runs when the node is the hover target and the pointer moves, so a node can follow the pointer without being pressed. While a press is held, hover does not change, and the moves go to the captured node alone. The position is in logical pixels, relative to the top left of the node’s rectangle. The handler runs inside the node’s owner, so it can write the signals the element’s bindings read.

Source

pub fn on_pointer_up(self, handler: impl FnMut(Point) + 'static) -> Self

Runs handler when the primary button is released.

After a press on the node, the handler runs when the button comes up wherever that happens, which is how a drag ends even when the pointer is no longer over the node. With no press held, the handler runs when the release happens over the node as the hover target. The position is in logical pixels, relative to the top left of the node’s rectangle. The handler runs inside the node’s owner, so it can write the signals the element’s bindings read.

Source

pub fn on_ime_commit(self, handler: impl FnMut(&str) + 'static) -> Self

Runs handler when the input method commits text while the node or one of its descendants holds the keyboard focus.

A commit can arrive with no key event at all, because composing text with an input method ends in a commit rather than a key press, so an editor that takes text needs this handler. The commit goes to the deepest handler in the focused chain and does not bubble past it. While a focus trap is active and the focus is outside it, the commit starts at the trap instead, as a key does. The handler runs inside the node’s owner, so it can write the signals the element’s bindings read.

Source

pub fn on_ime_preedit( self, handler: impl FnMut(&str, Option<(usize, usize)>) + 'static, ) -> Self

Runs handler when the input method changes its composing text while the node or one of its descendants holds the keyboard focus.

The handler receives the composing text and the byte range of the cursor inside it, or None when the input method shows no cursor. An empty text means the composition was canceled or committed, and the preedit must go. An editor draws the composing text itself, usually underlined, and does not write it into its value until the commit arrives. Like Element::on_ime_commit, the event goes to the deepest handler in the focused chain and does not bubble past it, and the handler runs inside the node’s owner.

Source

pub fn disabled(self, disabled: impl Into<Value<bool>>) -> Self

Disables the node, which takes it out of hit testing, or enables it again.

A disabled node receives no pointer events of its own: its handlers never run, and a press over it passes to whatever enabled node is hit instead. Its children are still hit. This can be bound to a signal, like the style builders.

Source

pub fn cursor(self, cursor: impl Into<Value<Option<Cursor>>>) -> Self

Sets the cursor the pointer shows while it is over the node, or over a descendant that sets none of its own.

The window shows the cursor of the deepest enabled node under the pointer that sets one, so a nested setter wins over an ancestor’s. Setting a cursor does not make the node a target: a press over a node that sets only a cursor still lands on the nearest ancestor that responds, and so does hover. This takes a Cursor, or an Option<Cursor> where None leaves the choice to the ancestors, and it can be bound to a signal, like the style builders: a binding that returns None hands the choice back to the ancestors.

use smudge_core::geometry::Color;
use smudge_core::widget::panel;
use smudge_core::window::Cursor;

let link = panel()
    .width(smudge_core::style::px(80.0))
    .height(smudge_core::style::px(24.0))
    .background(Color::rgb(40, 40, 48))
    .cursor(Cursor::Pointer);
Source

pub fn role(self, role: Role) -> Self

Sets the role the accessibility projection reports for the node.

A widget that reports no role of its own stays out of the projection and its children attach to the nearest projected ancestor, so this builder places a plain container on the accessibility tree. The role is fixed for the node’s lifetime, and it overrides the role the widget itself reports.

Source

pub fn accessible_label(self, label: impl Into<Value<String>>) -> Self

Sets the accessible name a screen reader announces for the node.

This can be bound to a signal, like the style builders. It overrides the name the widget itself reports.

Source

pub fn focusable(self) -> Self

Makes the node able to take the keyboard focus, by a press on it or by Tab navigation.

While a node holds the focus, key events reach it before they bubble to its ancestors, which is what Element::on_key hears. Element::on_key implies this, so a key handler never needs a separate focusable call.

Source

pub fn autofocus(self) -> Self

Takes the keyboard focus on the first frame the node is laid out after it mounts.

The request resolves after the layout pass that lays the node out, so the focus is set before the frame paints and a node a show mounts takes the focus in the frame it appears in. The request runs once per mount: when the focus moves away later, the node does not ask again, and a node unmounted and mounted again by a fresh show run does. A node that is hidden, or sits under a hidden ancestor, keeps its request until it is first laid out visible, so a dialog that mounts hidden and shows later takes the focus in the frame it shows in. A request whose node is disabled when it resolves is dropped and never asked again. When several nodes show in one frame, the node painted last wins.

While a focus trap is mounted, only a node inside the trap can take the focus this way; a request for a node outside it is dropped, like any other request that cannot take the focus.

This makes the node focusable, like Element::on_key does.

use std::cell::Cell;
use std::rc::Rc;

use smudge_core::app::{App, AppConfig, RepaintMode};
use smudge_core::geometry::{Color, Size};
use smudge_core::widget::panel;

let focused = Rc::new(Cell::new(false));
let count = Rc::clone(&focused);
let mut app = App::new(
    AppConfig {
        viewport: Size {
            width: 100.0,
            height: 60.0,
        },
        scale: 1.0,
        clear_color: Color::WHITE,
        repaint: RepaintMode::Damage,
    },
    move || panel().autofocus().on_focus(move |on| count.set(on)),
);
app.frame();

assert!(focused.get(), "the node took the focus on its first frame");
Source

pub fn trap_focus(self) -> Self

Keeps Tab and Shift+Tab cycling among the focusable nodes inside the node’s subtree, for as long as the node is mounted and not hidden.

A node the user Tabs to inside the trap never lands outside it: the cycle wraps within the subtree, and a Tab pressed with nothing focused enters the trap at its first focusable node. While the trap holds no focusable node, a Tab press leaves the focus where it is. A pointer press that lands on no node that can respond, or on a node outside the trap, leaves the focus where it is, and a press on a node inside the trap moves the focus as usual: to that node when it can take the focus, and away when it cannot. This is how a modal dialog keeps the keyboard inside itself instead of wandering into the view behind it.

While the trap is active, a key that would start outside it, because the focus is outside the trap or nothing holds the focus, starts at the trap node and bubbles from there to the root, so the trap’s own key handlers hear it and a control behind it does not.

When several traps are mounted, the last one wins, and a nested trap therefore takes over from the one around it. Removing a trap, which is what unmounting a show child does, restores the trap mounted before it, and returns the focus to the node that held it when the trap became active, when that node is still mounted and can take it. A trap becomes active when it mounts visible or shows again. A trap that cannot hold the focus, because it became disabled or hidden or sits under a hidden ancestor, yields to an earlier one while it stays mounted, and a trap that hides gives the focus back the way removing it does, when the focus was inside it or nowhere. A hidden or disabled state counts once a layout pass has run, which every frame that changes the hidden state does.

Source

pub fn follow(self, signal: RwSignal<bool>) -> Self

Pins the node’s scroll offset to the end of its flowing content while signal reads true.

Every layout pass that runs while the signal reads true ends with the node’s offset at the furthest its flowing content reaches, minus the height of its content box, floored at zero. The pin uses the rectangles that pass just computed, so a frame that grows the content shows the end in view in the same frame. A signal that reads false leaves the offset where it is, and a write of true from anywhere pins the node in the next frame.

What turns the signal is the caller’s decision, not the core’s: the scroll view widget pairs this builder with its wheel handling, so a step that leaves the end releases the pin and a step back to it engages it again.

use smudge_core::element::Element;
use smudge_core::reactive::RwSignal;
use smudge_core::widget::Panel;

let following = RwSignal::new(true);
let view = Element::new(Panel).follow(following);
Source

pub fn on_key(self, handler: impl FnMut(&KeyEvent) -> Handled + 'static) -> Self

Runs handler when a key event reaches the node while the node or one of its descendants holds the keyboard focus.

The event walks up from the focused node, and the first handler that returns Handled::Yes stops it, so a handler that takes a key hides it from its ancestors. Tab moves the focus away only when no handler took the Tab key. This makes the node focusable, so a press on it or a Tab puts the focus on it.

The handler runs inside the node’s owner, so it can write the signals the element’s bindings read.

use std::cell::Cell;
use std::rc::Rc;

use smudge_core::app::{App, AppConfig, RepaintMode};
use smudge_core::geometry::{Color, Size};
use smudge_core::input::{Handled, InputEvent, Key, KeyEvent};
use smudge_core::style::px;
use smudge_core::widget::panel;

let enters = Rc::new(Cell::new(0u32));
let counted = Rc::clone(&enters);
let mut app = App::new(
    AppConfig {
        viewport: Size {
            width: 100.0,
            height: 60.0,
        },
        scale: 1.0,
        clear_color: Color::WHITE,
        repaint: RepaintMode::Damage,
    },
    move || {
        panel().child(
            panel()
                .width(px(40.0))
                .height(px(20.0))
                .on_key(move |event: &KeyEvent| {
                    if event.pressed && event.key == Key::Enter {
                        counted.set(counted.get() + 1);
                        Handled::Yes
                    } else {
                        Handled::No
                    }
                }),
        )
    },
);
app.frame();

// Tab moves the focus to the panel, which then hears the Enter key.
app.handle_event(InputEvent::Key(KeyEvent {
    key: Key::Tab,
    pressed: true,
    repeat: false,
    modifiers: Default::default(),
    text: None,
}));
app.handle_event(InputEvent::Key(KeyEvent {
    key: Key::Enter,
    pressed: true,
    repeat: false,
    modifiers: Default::default(),
    text: None,
}));
assert_eq!(enters.get(), 1);
Source

pub fn activate_on_keys(self) -> Self

Runs the handler set with Element::on_press when the node holds the keyboard focus and a fresh press of Enter or Space arrives.

This is how a button fires from the keyboard with the same handler its pointer press uses. The activation runs before any Element::on_key handler on the same node, and a key repeat fires nothing. A press handler that ran takes the key, so it does not reach an ancestor; without a press handler the key bubbles as usual.

This makes the node focusable, like Element::on_key does.

Source

pub fn on_focus(self, handler: impl FnMut(bool) + 'static) -> Self

Runs handler when the node gains (true) or loses (false) the keyboard focus.

The handler does not make the node focusable; pair it with Element::focusable for that. It runs inside the node’s owner, so it can write the signals the element’s bindings read. A node that is removed while focused clears the focus without hearing on_focus again, because its handlers are being torn down with it.

Source

pub fn bind<K: 'static, T: 'static>( self, _key: K, value: impl Into<Value<T>>, apply: fn(&mut W, T) -> Dirty, ) -> Self

Binds one property of the element’s own widget.

The first argument names the property: pass a value of a marker type, usually a unit struct, that stands for it and for nothing else. The last call for a key wins, fixed or bound, the way it does for the style builders: a later call drops the binding an earlier call with a key of the same type recorded. Bindings with different key types all stay, and they apply in the order they were made.

apply writes the value into the widget and returns how much of the node the write invalidated. A write that changes what the widget measures returns Dirty::Layout, and the node is laid out and painted again. Any other write returns Dirty::Paint and only repaints the node.

use smudge_core::element::Element;
use smudge_core::paint::PaintOp;
use smudge_core::tree::Dirty;
use smudge_core::widget::{PaintCx, Widget};

struct Dot(f32);

impl Widget for Dot {
    fn paint(&self, _cx: &PaintCx<'_>, _out: &mut Vec<PaintOp>) {}
}

/// The key of the dot's radius.
struct Radius;

let element = Element::new(Dot(0.0)).bind(Radius, 3.0, |dot, value| {
    dot.0 = value;
    Dirty::Paint
});

Trait Implementations§

Source§

impl<W: Widget> IntoElement for Element<W>

Source§

fn into_any(self) -> AnyElement

Erases the widget type of this element.

Auto Trait Implementations§

§

impl<W> !RefUnwindSafe for Element<W>

§

impl<W> !Send for Element<W>

§

impl<W> !Sync for Element<W>

§

impl<W> !UnwindSafe for Element<W>

§

impl<W> Forget for Element<W>

§

impl<W> Freeze for Element<W>
where W: Freeze,

§

impl<W> Move for Element<W>

§

impl<W> Unpin for Element<W>
where W: Unpin,

§

impl<W> UnsafeUnpin for Element<W>
where W: UnsafeUnpin,

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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.