Created
May 24, 2021 14:44
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! 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