zng_wgt_input/
misc.rs
1use std::sync::{
2 Arc,
3 atomic::{AtomicBool, Ordering},
4};
5
6use zng_ext_input::mouse::{ClickMode, MOUSE_HOVERED_EVENT, WidgetInfoBuilderMouseExt as _};
7use zng_ext_window::WINDOW_Ext as _;
8use zng_wgt::prelude::*;
9
10pub use zng_view_api::window::CursorIcon;
11
12pub use zng_ext_window::{CursorImg, CursorSource};
13
14context_local! {
15 static CHILD_SETS_CURSOR: AtomicBool = AtomicBool::new(false);
16}
17
18#[property(CONTEXT, default(CursorIcon::Default))]
23pub fn cursor(child: impl UiNode, cursor: impl IntoVar<CursorSource>) -> impl UiNode {
24 let cursor = cursor.into_var();
25 let mut binding = None;
26 let mut child_sets_ctx = None::<Arc<AtomicBool>>;
27
28 match_node(child, move |c, op| {
29 let mut unbind_restore = false;
30 match op {
31 UiNodeOp::Init => {
32 WIDGET.sub_event(&MOUSE_HOVERED_EVENT);
33 }
34 UiNodeOp::Deinit => {
35 unbind_restore = true;
36 child_sets_ctx = None;
37 }
38 UiNodeOp::Event { update } => {
39 if let Some(args) = MOUSE_HOVERED_EVENT.on(update) {
40 let mut bind = false;
41 if args.is_over() {
42 if child_sets_ctx.is_none() {
43 child_sets_ctx = Some(Arc::new(AtomicBool::new(false)));
44 }
45
46 CHILD_SETS_CURSOR.with_context(&mut child_sets_ctx, || c.event(update));
48
49 if !child_sets_ctx.as_ref().unwrap().swap(false, Ordering::Relaxed) {
50 bind = true;
52 }
53
54 CHILD_SETS_CURSOR.get().store(true, Ordering::Relaxed);
56 }
57
58 if bind {
59 if binding.is_none() {
60 binding = Some(cursor.set_bind(&WINDOW.vars().cursor()));
62 }
63 } else {
64 unbind_restore = true;
65 }
66 }
67 }
68 _ => {}
69 }
70
71 if unbind_restore && binding.is_some() {
73 binding = None;
74 let value = cursor.get();
75 WINDOW.vars().cursor().modify(move |c| {
76 if c.as_ref() == &value {
77 *c.to_mut() = CursorIcon::Default.into();
78 }
79 });
80 }
81 })
82}
83
84#[property(CONTEXT, default(None))]
91pub fn click_mode(child: impl UiNode, mode: impl IntoVar<Option<ClickMode>>) -> impl UiNode {
92 let mode = mode.into_var();
93
94 match_node(child, move |_, op| match op {
95 UiNodeOp::Init => {
96 WIDGET.sub_var_info(&mode);
97 }
98 UiNodeOp::Info { info } => {
99 info.set_click_mode(mode.get());
100 }
101 _ => {}
102 })
103}