druid_widget_nursery/
widget_ext.rs

1use druid::widget::prelude::*;
2use druid::widget::{ControllerHost, LabelText};
3use druid::{Point, Selector, WidgetExt as _, WindowHandle};
4
5use crate::on_cmd::OnCmd;
6use crate::stack_tooltip::{PlainOrRich, StackTooltip, ADVISE_TOOLTIP_SHOW, CANCEL_TOOLTIP_SHOW};
7use crate::tooltip::TooltipState;
8use crate::{OnChange, OnMonitor, TooltipController};
9
10pub trait WidgetExt<T: Data>: Widget<T> + Sized + 'static {
11    fn on_command<CT: 'static>(
12        self,
13        selector: Selector<CT>,
14        handler: impl Fn(&mut EventCtx, &CT, &mut T) + 'static,
15    ) -> ControllerHost<Self, OnCmd<CT, T>> {
16        self.controller(OnCmd::new(selector, handler))
17    }
18
19    /// Calls the function when data changes **in a child widget**
20    ///
21    /// `&T` is the old data and `&mut T` is the new data
22    fn on_change(
23        self,
24        f: impl Fn(&mut EventCtx, &T, &mut T, &Env) + 'static,
25    ) -> ControllerHost<Self, OnChange<T>> {
26        self.controller(OnChange::new(f))
27    }
28
29    /// Open a tooltip when the mouse is hovered over this widget.
30    fn tooltip<LT: Into<LabelText<T>>>(
31        self,
32        text: LT,
33    ) -> ControllerHost<Self, TooltipController<T>> {
34        self.controller(TooltipController {
35            text: text.into(),
36            state: TooltipState::Off,
37        })
38    }
39
40    /// A convenience method for ensuring that this widget is fully visible on the same monitor as
41    /// some other window.
42    fn on_monitor(self, parent: &WindowHandle) -> OnMonitor<Self> {
43        OnMonitor {
44            inner: self,
45            parent: parent.clone(),
46        }
47    }
48
49    /// A convenience method to cancel the display of a tooltip from a parent/ancestor widget.
50    fn cancel_stack_tooltip(self) -> ControllerHost<Self, OnCmd<Point, T>> {
51        self.controller(OnCmd::new(ADVISE_TOOLTIP_SHOW, move |ctx, point, _| {
52            let window_rect = ctx.size().to_rect().with_origin(ctx.window_origin());
53            if window_rect.contains(*point) {
54                ctx.submit_notification(CANCEL_TOOLTIP_SHOW)
55            }
56        }))
57    }
58
59    /// Open a stack based tooltip when the mouse is hovered over this widget
60    fn stack_tooltip(self, label: impl Into<PlainOrRich>) -> StackTooltip<T> {
61        StackTooltip::new(self, label)
62    }
63}
64
65impl<T: Data, W: Widget<T> + 'static> WidgetExt<T> for W {}