raui_core/widget/component/interactive/
float_view.rs

1use crate::{
2    pre_hooks, unpack_named_slots,
3    widget::{
4        component::{
5            containers::float_box::{
6                FloatBoxChange, FloatBoxChangeMessage, FloatBoxNotifyProps, FloatBoxState,
7            },
8            interactive::{
9                button::{ButtonNotifyMessage, ButtonNotifyProps, ButtonProps, use_button},
10                navigation::{
11                    NavSignal, NavTrackingNotifyMessage, NavTrackingNotifyProps, use_nav_item,
12                    use_nav_tracking_self,
13                },
14            },
15        },
16        context::WidgetContext,
17        node::WidgetNode,
18        unit::area::AreaBoxNode,
19        utils::Vec2,
20    },
21};
22
23#[pre_hooks(use_button, use_nav_tracking_self)]
24pub fn use_float_view_control(context: &mut WidgetContext) {
25    context
26        .props
27        .write(ButtonNotifyProps(context.id.to_owned().into()));
28    context
29        .props
30        .write(NavTrackingNotifyProps(context.id.to_owned().into()));
31
32    context.life_cycle.unmount(|context| {
33        context.signals.write(NavSignal::Unlock);
34    });
35
36    context.life_cycle.change(|context| {
37        let Some(notify) = context
38            .props
39            .read_cloned_or_default::<FloatBoxNotifyProps>()
40            .0
41            .read()
42        else {
43            return;
44        };
45        let button = context.state.read_cloned_or_default::<ButtonProps>();
46        let zoom = context.props.read_cloned_or_default::<FloatBoxState>().zoom;
47        let scale = if zoom > 0.0 { 1.0 / zoom } else { 1.0 };
48
49        for msg in context.messenger.messages {
50            if let Some(msg) = msg.as_any().downcast_ref::<ButtonNotifyMessage>() {
51                if msg.trigger_start() {
52                    context.signals.write(NavSignal::Lock);
53                }
54                if msg.trigger_stop() {
55                    context.signals.write(NavSignal::Unlock);
56                }
57            } else if let Some(msg) = msg.as_any().downcast_ref::<NavTrackingNotifyMessage>() {
58                if button.selected && button.trigger {
59                    let delta = msg.pointer_delta_ui_space();
60                    context.messenger.write(
61                        notify.clone(),
62                        FloatBoxChangeMessage {
63                            sender: context.id.to_owned(),
64                            change: FloatBoxChange::RelativePosition(Vec2 {
65                                x: delta.x * scale,
66                                y: delta.y * scale,
67                            }),
68                        },
69                    );
70                }
71            }
72        }
73    });
74}
75
76#[pre_hooks(use_nav_item, use_float_view_control)]
77pub fn float_view_control(mut context: WidgetContext) -> WidgetNode {
78    let WidgetContext {
79        id,
80        props,
81        state,
82        named_slots,
83        ..
84    } = context;
85    unpack_named_slots!(named_slots => content);
86
87    if let Some(p) = content.props_mut() {
88        p.merge_from(props.clone());
89        p.write(state.read_cloned_or_default::<ButtonProps>());
90    }
91
92    AreaBoxNode {
93        id: id.to_owned(),
94        slot: Box::new(content),
95    }
96    .into()
97}