Skip to main content

WidgetPod

Struct WidgetPod 

Source
pub struct WidgetPod<T, W> { /* private fields */ }
Expand description

A container for one widget in the hierarchy.

Generally, container widgets don’t contain other widgets directly, but rather contain a WidgetPod, which has additional state needed for layout and for the widget to participate in event flow.

WidgetPod will translate internal Druid events to regular events, synthesize additional events of interest, and stop propagation when it makes sense.

This struct also contains the previous data for a widget, which is essential for the update method, both to decide when the update needs to propagate, and to provide the previous data so that a widget can process a diff between the old value and the new.

Implementations§

Source§

impl<T, W: Widget<T>> WidgetPod<T, W>

Source

pub fn new(inner: W) -> WidgetPod<T, W>

Create a new widget pod.

In a widget hierarchy, each widget is wrapped in a WidgetPod so it can participate in layout and event flow. The process of adding a child widget to a container should call this method.

Examples found in repository?
examples/timer.rs (line 124)
121pub fn main() {
122    let window = WindowDesc::new(TimerWidget {
123        timer_id: TimerToken::INVALID,
124        simple_box: WidgetPod::new(SimpleBox),
125        pos: Point::ZERO,
126    })
127    .with_min_size((200., 200.))
128    .title(LocalizedString::new("timer-demo-window-title").with_placeholder("Look at it go!"));
129
130    AppLauncher::with_window(window)
131        .log_to_console()
132        .launch(0u32)
133        .expect("launch failed");
134}
More examples
Hide additional examples
examples/input_region.rs (line 80)
48    pub fn new() -> Self {
49        let info_label = Label::new(INFO_TEXT)
50            .with_line_break_mode(LineBreaking::WordWrap)
51            .padding(20.0)
52            .background(Color::rgba(0.2, 0.2, 0.2, 1.0));
53        let toggle_input_region = Button::new("Toggle Input Region")
54            .on_click(|ctx, data: &mut bool, _: &Env| {
55                *data = !*data;
56                tracing::debug!("Setting input region toggle to: {}", *data);
57                ctx.request_layout();
58            })
59            .lens(AppState::limit_input_region);
60        let toggle_titlebar = Button::new("Toggle TitleBar")
61            .on_click(|ctx, data: &mut bool, _: &Env| {
62                *data = !*data;
63                tracing::debug!("Setting titlebar visibility to: {}", *data);
64                ctx.window().show_titlebar(*data);
65                ctx.request_layout();
66            })
67            .lens(AppState::show_titlebar);
68        let toggle_always_on_top = Button::new("Toggle Always On Top")
69            .on_click(|ctx, data: &mut bool, _: &Env| {
70                *data = !*data;
71                tracing::debug!("Setting always on top to: {}", *data);
72                ctx.window().set_always_on_top(*data);
73            })
74            .lens(AppState::always_on_top);
75        let controls_flex = Flex::row()
76            .with_child(toggle_input_region)
77            .with_child(toggle_titlebar)
78            .with_child(toggle_always_on_top);
79        Self {
80            info_label: WidgetPod::new(info_label),
81            controls: WidgetPod::new(controls_flex),
82        }
83    }
Source

pub fn is_initialized(&self) -> bool

Returns true if the widget has received LifeCycle::WidgetAdded.

Source

pub fn has_focus(&self) -> bool

Returns true if widget or any descendent is focused

Source

pub fn is_active(&self) -> bool

The “active” (aka pressed) status of a widget.

Active status generally corresponds to a mouse button down. Widgets with behavior similar to a button will call set_active on mouse down and then up.

The active status can only be set manually. Druid doesn’t automatically set it to false on mouse release or anything like that.

There is no special handling of the active status for multi-pointer devices.

When a widget is active, it gets mouse events even when the mouse is dragged away.

Source

pub fn has_active(&self) -> bool

Returns true if any descendant is active.

Source

pub fn is_hot(&self) -> bool

The “hot” (aka hover) status of a widget.

A widget is “hot” when the mouse is hovered over it. Some Widgets (eg buttons) will change their appearance when hot as a visual indication that they will respond to mouse interaction.

The hot status is automatically computed from the widget’s layout rect. In a container hierarchy, all widgets with layout rects containing the mouse position have hot status. The hot status cannot be set manually.

There is no special handling of the hot status for multi-pointer devices.

Note: a widget can be hot while another is active (for example, when clicking a button and dragging the cursor to another widget).

Source

pub fn id(&self) -> WidgetId

Get the identity of the widget.

Source

pub fn layout_requested(&self) -> bool

This widget or any of its children have requested layout.

Source

pub fn set_origin(&mut self, ctx: &mut impl ChangeCtx, origin: Point)

Set the origin of this widget, in the parent’s coordinate space.

A container widget should call the Widget::layout method on its children in its own Widget::layout implementation, and then call set_origin to position those children.

The changed origin won’t be fully in effect until LifeCycle::ViewContextChanged has finished propagating. Specifically methods that depend on the widget’s origin in relation to the window will return stale results during the period after calling set_origin but before LifeCycle::ViewContextChanged has finished propagating.

The widget container can also call set_origin from other context, but calling set_origin after the widget received LifeCycle::ViewContextChanged and before the next event results in an inconsistent state of the widget tree.

The child will receive the LifeCycle::Size event informing them of the final Size.

Examples found in repository?
examples/timer.rs (line 79)
77    fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &u32, env: &Env) -> Size {
78        self.simple_box.layout(ctx, &bc.loosen(), data, env);
79        self.simple_box.set_origin(ctx, self.pos);
80        bc.constrain((500.0, 500.0))
81    }
More examples
Hide additional examples
examples/input_region.rs (line 137)
120    fn layout(
121        &mut self,
122        ctx: &mut druid::LayoutCtx,
123        bc: &druid::BoxConstraints,
124        data: &AppState,
125        env: &druid::Env,
126    ) -> druid::Size {
127        let mut interactable_area = Region::EMPTY;
128        let smaller_bc = BoxConstraints::new(
129            Size::new(0.0, 0.0),
130            Size::new(bc.max().width - 100.0, bc.max().height - 100.0),
131        );
132        let full_bc = BoxConstraints::new(Size::new(0.0, 0.0), bc.max());
133        let _label_size = self.info_label.layout(ctx, &smaller_bc, data, env);
134        let controls_size = self.controls.layout(ctx, &full_bc, data, env);
135
136        let text_origin_point = Point::new(50.0, 50.0 + controls_size.height);
137        self.info_label.set_origin(ctx, text_origin_point);
138        let controls_origin_point = Point::new(EXAMPLE_BORDER_SIZE, EXAMPLE_BORDER_SIZE);
139        self.controls.set_origin(ctx, controls_origin_point);
140
141        // Add side rects to clarify the dimensions of the window.
142        let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, bc.max().height);
143        let right_rect = Rect::new(
144            bc.max().width - EXAMPLE_BORDER_SIZE,
145            0.0,
146            bc.max().width,
147            bc.max().height,
148        );
149        let bottom_rect = Rect::new(
150            0.0,
151            bc.max().height - EXAMPLE_BORDER_SIZE,
152            bc.max().width,
153            bc.max().height,
154        );
155        interactable_area.add_rect(left_rect);
156        interactable_area.add_rect(right_rect);
157        interactable_area.add_rect(bottom_rect);
158        interactable_area.add_rect(self.info_label.layout_rect());
159        interactable_area.add_rect(self.controls.layout_rect());
160
161        if data.limit_input_region {
162            ctx.window().set_input_region(Some(interactable_area));
163        } else {
164            ctx.window().set_input_region(None);
165        }
166
167        bc.max()
168    }
Source

pub fn layout_rect(&self) -> Rect

Returns the layout Rect.

This will be a Rect with a Size determined by the child’s layout method, and the origin that was set by set_origin.

Examples found in repository?
examples/timer.rs (line 38)
37    fn adjust_box_pos(&mut self, container_size: Size) {
38        let box_size = self.simple_box.layout_rect().size();
39        self.pos.x += 2.;
40        if self.pos.x + box_size.width > container_size.width {
41            self.pos.x = 0.;
42            self.pos.y += box_size.height;
43            if self.pos.y + box_size.height > container_size.height {
44                self.pos.y = 0.;
45            }
46        }
47    }
More examples
Hide additional examples
examples/input_region.rs (line 158)
120    fn layout(
121        &mut self,
122        ctx: &mut druid::LayoutCtx,
123        bc: &druid::BoxConstraints,
124        data: &AppState,
125        env: &druid::Env,
126    ) -> druid::Size {
127        let mut interactable_area = Region::EMPTY;
128        let smaller_bc = BoxConstraints::new(
129            Size::new(0.0, 0.0),
130            Size::new(bc.max().width - 100.0, bc.max().height - 100.0),
131        );
132        let full_bc = BoxConstraints::new(Size::new(0.0, 0.0), bc.max());
133        let _label_size = self.info_label.layout(ctx, &smaller_bc, data, env);
134        let controls_size = self.controls.layout(ctx, &full_bc, data, env);
135
136        let text_origin_point = Point::new(50.0, 50.0 + controls_size.height);
137        self.info_label.set_origin(ctx, text_origin_point);
138        let controls_origin_point = Point::new(EXAMPLE_BORDER_SIZE, EXAMPLE_BORDER_SIZE);
139        self.controls.set_origin(ctx, controls_origin_point);
140
141        // Add side rects to clarify the dimensions of the window.
142        let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, bc.max().height);
143        let right_rect = Rect::new(
144            bc.max().width - EXAMPLE_BORDER_SIZE,
145            0.0,
146            bc.max().width,
147            bc.max().height,
148        );
149        let bottom_rect = Rect::new(
150            0.0,
151            bc.max().height - EXAMPLE_BORDER_SIZE,
152            bc.max().width,
153            bc.max().height,
154        );
155        interactable_area.add_rect(left_rect);
156        interactable_area.add_rect(right_rect);
157        interactable_area.add_rect(bottom_rect);
158        interactable_area.add_rect(self.info_label.layout_rect());
159        interactable_area.add_rect(self.controls.layout_rect());
160
161        if data.limit_input_region {
162            ctx.window().set_input_region(Some(interactable_area));
163        } else {
164            ctx.window().set_input_region(None);
165        }
166
167        bc.max()
168    }
Source

pub fn paint_rect(&self) -> Rect

Get the widget’s paint Rect.

This is the Rect that widget has indicated it needs to paint in. This is the same as the layout_rect with the paint_insets applied; in the general case it is the same as the layout_rect.

Source

pub fn paint_insets(&self) -> Insets

Return the paint Insets for this widget.

If these Insets are nonzero, they describe the area beyond a widget’s layout rect where it needs to paint.

These are generally zero; exceptions are widgets that do things like paint a drop shadow.

A widget can set its insets by calling set_paint_insets during its layout method.

Source

pub fn compute_parent_paint_insets(&self, parent_size: Size) -> Insets

Given a parents layout size, determine the appropriate paint Insets for the parent.

This is a convenience method to be used from the layout method of a Widget that manages a child; it allows the parent to correctly propagate a child’s desired paint rect, if it extends beyond the bounds of the parent’s layout rect.

Source

pub fn baseline_offset(&self) -> f64

The distance from the bottom of this widget to the baseline.

Source§

impl<T: Data, W: Widget<T>> WidgetPod<T, W>

Source

pub fn paint_raw(&mut self, ctx: &mut PaintCtx<'_, '_, '_>, data: &T, env: &Env)

Paint a child widget.

Generally called by container widgets as part of their Widget::paint method.

Note that this method does not apply the offset of the layout rect. If that is desired, use paint instead.

Source

pub fn paint(&mut self, ctx: &mut PaintCtx<'_, '_, '_>, data: &T, env: &Env)

Paint the widget, translating it by the origin of its layout rectangle.

This will recursively paint widgets, stopping if a widget’s layout rect is outside of the currently visible region.

Examples found in repository?
examples/timer.rs (line 84)
83    fn paint(&mut self, ctx: &mut PaintCtx, data: &u32, env: &Env) {
84        self.simple_box.paint(ctx, data, env);
85    }
More examples
Hide additional examples
examples/input_region.rs (line 189)
170    fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &AppState, env: &druid::Env) {
171        let window_area = ctx.size();
172        let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, window_area.height);
173        let right_rect = Rect::new(
174            window_area.width - EXAMPLE_BORDER_SIZE,
175            0.0,
176            window_area.width,
177            window_area.height,
178        );
179        let bottom_rect = Rect::new(
180            0.0,
181            window_area.height - EXAMPLE_BORDER_SIZE,
182            window_area.width,
183            window_area.height,
184        );
185
186        ctx.fill(left_rect, &Color::rgba(1.0, 0., 0., 0.7));
187        ctx.fill(right_rect, &Color::rgba(1.0, 0., 0., 0.7));
188        ctx.fill(bottom_rect, &Color::rgba(1.0, 0., 0., 0.7));
189        self.info_label.paint(ctx, data, env);
190        self.controls.paint(ctx, data, env);
191    }
Source

pub fn paint_always( &mut self, ctx: &mut PaintCtx<'_, '_, '_>, data: &T, env: &Env, )

Paint the widget, even if its layout rect is outside of the currently visible region.

Source

pub fn layout( &mut self, ctx: &mut LayoutCtx<'_, '_>, bc: &BoxConstraints, data: &T, env: &Env, ) -> Size

Compute layout of a widget.

Generally called by container widgets as part of their layout method.

Examples found in repository?
examples/timer.rs (line 78)
77    fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &u32, env: &Env) -> Size {
78        self.simple_box.layout(ctx, &bc.loosen(), data, env);
79        self.simple_box.set_origin(ctx, self.pos);
80        bc.constrain((500.0, 500.0))
81    }
More examples
Hide additional examples
examples/input_region.rs (line 133)
120    fn layout(
121        &mut self,
122        ctx: &mut druid::LayoutCtx,
123        bc: &druid::BoxConstraints,
124        data: &AppState,
125        env: &druid::Env,
126    ) -> druid::Size {
127        let mut interactable_area = Region::EMPTY;
128        let smaller_bc = BoxConstraints::new(
129            Size::new(0.0, 0.0),
130            Size::new(bc.max().width - 100.0, bc.max().height - 100.0),
131        );
132        let full_bc = BoxConstraints::new(Size::new(0.0, 0.0), bc.max());
133        let _label_size = self.info_label.layout(ctx, &smaller_bc, data, env);
134        let controls_size = self.controls.layout(ctx, &full_bc, data, env);
135
136        let text_origin_point = Point::new(50.0, 50.0 + controls_size.height);
137        self.info_label.set_origin(ctx, text_origin_point);
138        let controls_origin_point = Point::new(EXAMPLE_BORDER_SIZE, EXAMPLE_BORDER_SIZE);
139        self.controls.set_origin(ctx, controls_origin_point);
140
141        // Add side rects to clarify the dimensions of the window.
142        let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, bc.max().height);
143        let right_rect = Rect::new(
144            bc.max().width - EXAMPLE_BORDER_SIZE,
145            0.0,
146            bc.max().width,
147            bc.max().height,
148        );
149        let bottom_rect = Rect::new(
150            0.0,
151            bc.max().height - EXAMPLE_BORDER_SIZE,
152            bc.max().width,
153            bc.max().height,
154        );
155        interactable_area.add_rect(left_rect);
156        interactable_area.add_rect(right_rect);
157        interactable_area.add_rect(bottom_rect);
158        interactable_area.add_rect(self.info_label.layout_rect());
159        interactable_area.add_rect(self.controls.layout_rect());
160
161        if data.limit_input_region {
162            ctx.window().set_input_region(Some(interactable_area));
163        } else {
164            ctx.window().set_input_region(None);
165        }
166
167        bc.max()
168    }
Source

pub fn event( &mut self, ctx: &mut EventCtx<'_, '_>, event: &Event, data: &mut T, env: &Env, )

Propagate an event.

Generally the event method of a container widget will call this method on all its children. Here is where a great deal of the event flow logic resides, particularly whether to continue propagating the event.

Examples found in repository?
examples/input_region.rs (line 94)
87    fn event(
88        &mut self,
89        ctx: &mut druid::EventCtx,
90        event: &druid::Event,
91        data: &mut AppState,
92        env: &druid::Env,
93    ) {
94        self.info_label.event(ctx, event, data, env);
95        self.controls.event(ctx, event, data, env);
96    }
More examples
Hide additional examples
examples/timer.rs (line 66)
51    fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut u32, env: &Env) {
52        match event {
53            Event::WindowConnected => {
54                // Start the timer when the application launches
55                self.timer_id = ctx.request_timer(TIMER_INTERVAL);
56            }
57            Event::Timer(id) => {
58                if *id == self.timer_id {
59                    self.adjust_box_pos(ctx.size());
60                    ctx.request_layout();
61                    self.timer_id = ctx.request_timer(TIMER_INTERVAL);
62                }
63            }
64            _ => (),
65        }
66        self.simple_box.event(ctx, event, data, env);
67    }
Source

pub fn lifecycle( &mut self, ctx: &mut LifeCycleCtx<'_, '_>, event: &LifeCycle, data: &T, env: &Env, )

Propagate a LifeCycle event.

Examples found in repository?
examples/timer.rs (line 70)
69    fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &u32, env: &Env) {
70        self.simple_box.lifecycle(ctx, event, data, env);
71    }
More examples
Hide additional examples
examples/input_region.rs (line 105)
98    fn lifecycle(
99        &mut self,
100        ctx: &mut druid::LifeCycleCtx,
101        event: &druid::LifeCycle,
102        data: &AppState,
103        env: &druid::Env,
104    ) {
105        self.info_label.lifecycle(ctx, event, data, env);
106        self.controls.lifecycle(ctx, event, data, env);
107    }
Source

pub fn update(&mut self, ctx: &mut UpdateCtx<'_, '_>, data: &T, env: &Env)

Propagate a data update.

Generally called by container widgets as part of their update method.

Examples found in repository?
examples/timer.rs (line 74)
73    fn update(&mut self, ctx: &mut UpdateCtx, _old_data: &u32, data: &u32, env: &Env) {
74        self.simple_box.update(ctx, data, env);
75    }
More examples
Hide additional examples
examples/input_region.rs (line 116)
109    fn update(
110        &mut self,
111        ctx: &mut druid::UpdateCtx,
112        _old_data: &AppState,
113        data: &AppState,
114        env: &druid::Env,
115    ) {
116        self.info_label.update(ctx, data, env);
117        self.controls.update(ctx, data, env);
118    }
Source§

impl<T, W: Widget<T> + 'static> WidgetPod<T, W>

Source

pub fn boxed(self) -> WidgetPod<T, Box<dyn Widget<T>>>

Box the contained widget.

Convert a WidgetPod containing a widget of a specific concrete type into a dynamically boxed widget.

Source§

impl<T, W> WidgetPod<T, W>

Source

pub fn widget(&self) -> &W

Return a reference to the inner widget.

Source

pub fn widget_mut(&mut self) -> &mut W

Return a mutable reference to the inner widget.

Auto Trait Implementations§

§

impl<T, W> !Freeze for WidgetPod<T, W>

§

impl<T, W> !RefUnwindSafe for WidgetPod<T, W>

§

impl<T, W> !Send for WidgetPod<T, W>

§

impl<T, W> !Sync for WidgetPod<T, W>

§

impl<T, W> Unpin for WidgetPod<T, W>
where W: Unpin, T: Unpin,

§

impl<T, W> UnsafeUnpin for WidgetPod<T, W>
where W: UnsafeUnpin, T: UnsafeUnpin,

§

impl<T, W> !UnwindSafe for WidgetPod<T, W>

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> Instrument for T

Source§

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

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

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> RoundFrom<T> for T

Source§

fn round_from(x: T) -> T

Performs the conversion.
Source§

impl<T, U> RoundInto<U> for T
where U: RoundFrom<T>,

Source§

fn round_into(self) -> U

Performs the conversion.
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.
Source§

impl<T> WithSubscriber for T

Source§

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

fn with_current_subscriber(self) -> WithDispatch<Self>

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