Skip to content

Instantly share code, notes, and snippets.

@arifd
Created May 24, 2021 14:44
Show Gist options
  • Save arifd/9a5bdf24f223947ba32c09d32b625f7a to your computer and use it in GitHub Desktop.
Save arifd/9a5bdf24f223947ba32c09d32b625f7a to your computer and use it in GitHub Desktop.
Druid GUI Widget that holds a child and places it at a given x,y coordinate relative to parent
//! Place a widget anywhere in x,y pixel space
use druid::widget::prelude::*;
use druid::{Data, Point, WidgetPod};
pub struct Place<T> {
children: Vec<ChildWidget<T>>,
}
struct ChildWidget<T> {
widget: WidgetPod<T, Box<dyn Widget<T>>>,
position: Point,
}
impl<T> ChildWidget<T> {
fn new(child: impl Widget<T> + 'static, position: Point) -> Self {
ChildWidget {
widget: WidgetPod::new(Box::new(child)),
position,
}
}
}
impl<T: Data> Place<T> {
pub fn new() -> Self {
Self { children: vec![] }
}
pub fn with_child(
mut self,
child: impl Widget<T> + 'static,
position: impl Into<Point>,
) -> Self {
self.add_child(child, position);
self
}
pub fn add_child(&mut self, child: impl Widget<T> + 'static, position: impl Into<Point>) {
let child = ChildWidget::new(child, position.into());
self.children.push(child);
}
}
impl<T: Data> Widget<T> for Place<T> {
fn event(&mut self, ctx: &mut EventCtx, event: &Event, data: &mut T, env: &Env) {
for child in &mut self.children {
child.widget.event(ctx, event, data, env);
}
}
fn lifecycle(&mut self, ctx: &mut LifeCycleCtx, event: &LifeCycle, data: &T, env: &Env) {
for child in &mut self.children {
child.widget.lifecycle(ctx, event, data, env);
}
}
fn update(&mut self, ctx: &mut UpdateCtx, _old_data: &T, data: &T, env: &Env) {
for child in &mut self.children {
child.widget.update(ctx, data, env);
}
}
fn layout(&mut self, ctx: &mut LayoutCtx, bc: &BoxConstraints, data: &T, env: &Env) -> Size {
bc.debug_check("Place");
// we loosen our constraints when passing to children.
let loosened_bc = bc.loosen();
// get the width and height, currently just assuming min is the same as max.
assert!(bc.min() == bc.max());
let w = bc.min().width;
let h = bc.min().height;
for child in &mut self.children {
child.widget.layout(ctx, &loosened_bc, data, env);
let new_origin_x = child.position.x * w;
let new_origin_y = child.position.y * h;
// alternatively, we can account for the size of the child
// in order to center it at the desired position
// let child_rect = child.widget.layout_rect();
// let child_w = child_rect.x1 - child_rect.x0;
// let child_h = child_rect.y1 - child_rect.y0;
// new_origin_x -= child_w / 2.;
// new_origin_y -= child_h / 2.;
let child_pos = Point::new(new_origin_x, new_origin_y);
child.widget.set_origin(ctx, data, env, child_pos);
}
// keeping this here because it exists in the custom_widget example, but don't understand it.
if bc.is_width_bounded() | bc.is_height_bounded() {
let size = Size::new(100.0, 100.0);
bc.constrain(size)
} else {
bc.max()
}
}
fn paint(&mut self, ctx: &mut PaintCtx, data: &T, env: &Env) {
for child in &mut self.children {
child.widget.paint(ctx, data, env);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment