raui_core/widget/component/containers/
tooltip_box.rs

1use crate::{
2    PropsData, make_widget, pre_hooks,
3    props::Props,
4    unpack_named_slots,
5    widget::{
6        component::{
7            containers::{
8                anchor_box::{AnchorProps, PivotBoxProps, pivot_box, use_anchor_box},
9                content_box::content_box,
10                portal_box::{portal_box, use_portals_container_relative_layout},
11            },
12            interactive::navigation::{NavSignal, use_nav_container_active, use_nav_item_active},
13        },
14        context::WidgetContext,
15        node::WidgetNode,
16        unit::area::AreaBoxNode,
17    },
18};
19use serde::{Deserialize, Serialize};
20
21#[derive(PropsData, Debug, Default, Copy, Clone, Serialize, Deserialize)]
22#[props_data(crate::props::PropsData)]
23#[prefab(crate::Prefab)]
24pub struct TooltipState {
25    #[serde(default)]
26    pub show: bool,
27}
28
29#[pre_hooks(use_nav_container_active, use_nav_item_active, use_anchor_box)]
30pub fn use_tooltip_box(context: &mut WidgetContext) {
31    context.life_cycle.change(|context| {
32        for msg in context.messenger.messages {
33            if let Some(msg) = msg.as_any().downcast_ref() {
34                match msg {
35                    NavSignal::Select(_) => {
36                        let _ = context.state.write_with(TooltipState { show: true });
37                    }
38                    NavSignal::Unselect => {
39                        let _ = context.state.write_with(TooltipState { show: false });
40                    }
41                    _ => {}
42                }
43            }
44        }
45    });
46}
47
48#[pre_hooks(use_tooltip_box)]
49pub fn tooltip_box(mut context: WidgetContext) -> WidgetNode {
50    let WidgetContext {
51        id,
52        idref,
53        key,
54        props,
55        state,
56        named_slots,
57        ..
58    } = context;
59    unpack_named_slots!(named_slots => {content, tooltip});
60
61    let TooltipState { show } = state.read_cloned_or_default();
62    let anchor_state = state.read_cloned_or_default::<AnchorProps>();
63    let pivot_props =
64        Props::new(anchor_state).with(props.read_cloned_or_default::<PivotBoxProps>());
65
66    let tooltip = if show {
67        make_widget!(pivot_box)
68            .key("pivot")
69            .merge_props(pivot_props)
70            .named_slot(
71                "content",
72                make_widget!(portal_box)
73                    .key("portal")
74                    .named_slot("content", tooltip),
75            )
76            .into()
77    } else {
78        WidgetNode::default()
79    };
80
81    let content = make_widget!(content_box)
82        .key(key)
83        .maybe_idref(idref.cloned())
84        .merge_props(props.clone())
85        .listed_slot(content)
86        .listed_slot(tooltip)
87        .into();
88
89    AreaBoxNode {
90        id: id.to_owned(),
91        slot: Box::new(content),
92    }
93    .into()
94}
95
96#[pre_hooks(use_portals_container_relative_layout)]
97pub fn portals_tooltip_box(mut context: WidgetContext) -> WidgetNode {
98    tooltip_box(context)
99}