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>
impl<T, W: Widget<T>> WidgetPod<T, W>
Sourcepub fn new(inner: W) -> WidgetPod<T, W>
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?
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
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 }Sourcepub fn is_initialized(&self) -> bool
pub fn is_initialized(&self) -> bool
Returns true if the widget has received LifeCycle::WidgetAdded.
Sourcepub fn is_active(&self) -> bool
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.
Sourcepub fn has_active(&self) -> bool
pub fn has_active(&self) -> bool
Returns true if any descendant is active.
Sourcepub fn is_hot(&self) -> bool
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).
Sourcepub fn layout_requested(&self) -> bool
pub fn layout_requested(&self) -> bool
This widget or any of its children have requested layout.
Sourcepub fn set_origin(&mut self, ctx: &mut impl ChangeCtx, origin: Point)
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?
More examples
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 }Sourcepub fn layout_rect(&self) -> Rect
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?
More examples
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 }Sourcepub fn paint_rect(&self) -> Rect
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.
Sourcepub fn paint_insets(&self) -> Insets
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.
Sourcepub fn compute_parent_paint_insets(&self, parent_size: Size) -> Insets
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.
Sourcepub fn baseline_offset(&self) -> f64
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>
impl<T: Data, W: Widget<T>> WidgetPod<T, W>
Sourcepub fn paint_raw(&mut self, ctx: &mut PaintCtx<'_, '_, '_>, data: &T, env: &Env)
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.
Sourcepub fn paint(&mut self, ctx: &mut PaintCtx<'_, '_, '_>, data: &T, env: &Env)
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?
More examples
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 }Sourcepub fn paint_always(
&mut self,
ctx: &mut PaintCtx<'_, '_, '_>,
data: &T,
env: &Env,
)
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.
Sourcepub fn layout(
&mut self,
ctx: &mut LayoutCtx<'_, '_>,
bc: &BoxConstraints,
data: &T,
env: &Env,
) -> Size
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?
More examples
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 }Sourcepub fn event(
&mut self,
ctx: &mut EventCtx<'_, '_>,
event: &Event,
data: &mut T,
env: &Env,
)
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?
More examples
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 }Sourcepub fn lifecycle(
&mut self,
ctx: &mut LifeCycleCtx<'_, '_>,
event: &LifeCycle,
data: &T,
env: &Env,
)
pub fn lifecycle( &mut self, ctx: &mut LifeCycleCtx<'_, '_>, event: &LifeCycle, data: &T, env: &Env, )
Propagate a LifeCycle event.