raui_core/widget/component/containers/
tooltip_box.rs

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