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?
121 122 123 124 125 126 127 128 129 130 131 132 133 134
pub fn main() {
let window = WindowDesc::new(TimerWidget {
timer_id: TimerToken::INVALID,
simple_box: WidgetPod::new(SimpleBox),
pos: Point::ZERO,
})
.with_min_size((200., 200.))
.title(LocalizedString::new("timer-demo-window-title").with_placeholder("Look at it go!"));
AppLauncher::with_window(window)
.log_to_console()
.launch(0u32)
.expect("launch failed");
}
More examples
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
pub fn new() -> Self {
let info_label = Label::new(INFO_TEXT)
.with_line_break_mode(LineBreaking::WordWrap)
.padding(20.0)
.background(Color::rgba(0.2, 0.2, 0.2, 1.0));
let toggle_input_region = Button::new("Toggle Input Region")
.on_click(|ctx, data: &mut bool, _: &Env| {
*data = !*data;
tracing::debug!("Setting input region toggle to: {}", *data);
ctx.request_layout();
})
.lens(AppState::limit_input_region);
let toggle_titlebar = Button::new("Toggle TitleBar")
.on_click(|ctx, data: &mut bool, _: &Env| {
*data = !*data;
tracing::debug!("Setting titlebar visibility to: {}", *data);
ctx.window().show_titlebar(*data);
ctx.request_layout();
})
.lens(AppState::show_titlebar);
let toggle_always_on_top = Button::new("Toggle Always On Top")
.on_click(|ctx, data: &mut bool, _: &Env| {
*data = !*data;
tracing::debug!("Setting always on top to: {}", *data);
ctx.window().set_always_on_top(*data);
})
.lens(AppState::always_on_top);
let controls_flex = Flex::row()
.with_child(toggle_input_region)
.with_child(toggle_titlebar)
.with_child(toggle_always_on_top);
Self {
info_label: WidgetPod::new(info_label),
controls: WidgetPod::new(controls_flex),
}
}
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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
fn layout(
&mut self,
ctx: &mut druid::LayoutCtx,
bc: &druid::BoxConstraints,
data: &AppState,
env: &druid::Env,
) -> druid::Size {
let mut interactable_area = Region::EMPTY;
let smaller_bc = BoxConstraints::new(
Size::new(0.0, 0.0),
Size::new(bc.max().width - 100.0, bc.max().height - 100.0),
);
let full_bc = BoxConstraints::new(Size::new(0.0, 0.0), bc.max());
let _label_size = self.info_label.layout(ctx, &smaller_bc, data, env);
let controls_size = self.controls.layout(ctx, &full_bc, data, env);
let text_origin_point = Point::new(50.0, 50.0 + controls_size.height);
self.info_label.set_origin(ctx, text_origin_point);
let controls_origin_point = Point::new(EXAMPLE_BORDER_SIZE, EXAMPLE_BORDER_SIZE);
self.controls.set_origin(ctx, controls_origin_point);
// Add side rects to clarify the dimensions of the window.
let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, bc.max().height);
let right_rect = Rect::new(
bc.max().width - EXAMPLE_BORDER_SIZE,
0.0,
bc.max().width,
bc.max().height,
);
let bottom_rect = Rect::new(
0.0,
bc.max().height - EXAMPLE_BORDER_SIZE,
bc.max().width,
bc.max().height,
);
interactable_area.add_rect(left_rect);
interactable_area.add_rect(right_rect);
interactable_area.add_rect(bottom_rect);
interactable_area.add_rect(self.info_label.layout_rect());
interactable_area.add_rect(self.controls.layout_rect());
if data.limit_input_region {
ctx.window().set_input_region(Some(interactable_area));
} else {
ctx.window().set_input_region(None);
}
bc.max()
}
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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
fn layout(
&mut self,
ctx: &mut druid::LayoutCtx,
bc: &druid::BoxConstraints,
data: &AppState,
env: &druid::Env,
) -> druid::Size {
let mut interactable_area = Region::EMPTY;
let smaller_bc = BoxConstraints::new(
Size::new(0.0, 0.0),
Size::new(bc.max().width - 100.0, bc.max().height - 100.0),
);
let full_bc = BoxConstraints::new(Size::new(0.0, 0.0), bc.max());
let _label_size = self.info_label.layout(ctx, &smaller_bc, data, env);
let controls_size = self.controls.layout(ctx, &full_bc, data, env);
let text_origin_point = Point::new(50.0, 50.0 + controls_size.height);
self.info_label.set_origin(ctx, text_origin_point);
let controls_origin_point = Point::new(EXAMPLE_BORDER_SIZE, EXAMPLE_BORDER_SIZE);
self.controls.set_origin(ctx, controls_origin_point);
// Add side rects to clarify the dimensions of the window.
let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, bc.max().height);
let right_rect = Rect::new(
bc.max().width - EXAMPLE_BORDER_SIZE,
0.0,
bc.max().width,
bc.max().height,
);
let bottom_rect = Rect::new(
0.0,
bc.max().height - EXAMPLE_BORDER_SIZE,
bc.max().width,
bc.max().height,
);
interactable_area.add_rect(left_rect);
interactable_area.add_rect(right_rect);
interactable_area.add_rect(bottom_rect);
interactable_area.add_rect(self.info_label.layout_rect());
interactable_area.add_rect(self.controls.layout_rect());
if data.limit_input_region {
ctx.window().set_input_region(Some(interactable_area));
} else {
ctx.window().set_input_region(None);
}
bc.max()
}
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 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &AppState, env: &druid::Env) {
let window_area = ctx.size();
let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, window_area.height);
let right_rect = Rect::new(
window_area.width - EXAMPLE_BORDER_SIZE,
0.0,
window_area.width,
window_area.height,
);
let bottom_rect = Rect::new(
0.0,
window_area.height - EXAMPLE_BORDER_SIZE,
window_area.width,
window_area.height,
);
ctx.fill(left_rect, &Color::rgba(1.0, 0., 0., 0.7));
ctx.fill(right_rect, &Color::rgba(1.0, 0., 0., 0.7));
ctx.fill(bottom_rect, &Color::rgba(1.0, 0., 0., 0.7));
self.info_label.paint(ctx, data, env);
self.controls.paint(ctx, data, env);
}
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 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
fn layout(
&mut self,
ctx: &mut druid::LayoutCtx,
bc: &druid::BoxConstraints,
data: &AppState,
env: &druid::Env,
) -> druid::Size {
let mut interactable_area = Region::EMPTY;
let smaller_bc = BoxConstraints::new(
Size::new(0.0, 0.0),
Size::new(bc.max().width - 100.0, bc.max().height - 100.0),
);
let full_bc = BoxConstraints::new(Size::new(0.0, 0.0), bc.max());
let _label_size = self.info_label.layout(ctx, &smaller_bc, data, env);
let controls_size = self.controls.layout(ctx, &full_bc, data, env);
let text_origin_point = Point::new(50.0, 50.0 + controls_size.height);
self.info_label.set_origin(ctx, text_origin_point);
let controls_origin_point = Point::new(EXAMPLE_BORDER_SIZE, EXAMPLE_BORDER_SIZE);
self.controls.set_origin(ctx, controls_origin_point);
// Add side rects to clarify the dimensions of the window.
let left_rect = Rect::new(0.0, 0.0, EXAMPLE_BORDER_SIZE, bc.max().height);
let right_rect = Rect::new(
bc.max().width - EXAMPLE_BORDER_SIZE,
0.0,
bc.max().width,
bc.max().height,
);
let bottom_rect = Rect::new(
0.0,
bc.max().height - EXAMPLE_BORDER_SIZE,
bc.max().width,
bc.max().height,
);
interactable_area.add_rect(left_rect);
interactable_area.add_rect(right_rect);
interactable_area.add_rect(bottom_rect);
interactable_area.add_rect(self.info_label.layout_rect());
interactable_area.add_rect(self.controls.layout_rect());
if data.limit_input_region {
ctx.window().set_input_region(Some(interactable_area));
} else {
ctx.window().set_input_region(None);
}
bc.max()
}
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut u32, env: &Env) {
match event {
Event::WindowConnected => {
// Start the timer when the application launches
self.timer_id = ctx.request_timer(TIMER_INTERVAL);
}
Event::Timer(id) => {
if *id == self.timer_id {
self.adjust_box_pos(ctx.size());
ctx.request_layout();
self.timer_id = ctx.request_timer(TIMER_INTERVAL);
}
}
_ => (),
}
self.simple_box.event(ctx, event, data, env);
}
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.