zng_wgt_text_input/
label.rs

1//! Label text.
2
3use zng_app::access::ACCESS_CLICK_EVENT;
4use zng_ext_input::{
5    focus::{FOCUS, FocusInfoBuilder},
6    mouse::MOUSE_INPUT_EVENT,
7    touch::TOUCH_INPUT_EVENT,
8};
9use zng_wgt::prelude::*;
10use zng_wgt_input::focus::FocusableMix;
11use zng_wgt_style::{Style, StyleMix, impl_style_fn, style_fn};
12
13/// Styleable and focusable read-only text widget.
14///
15/// Optionally can be the label of a [`target`](#method.target) widget, in this case the label is not focusable, it transfers focus
16/// to the target.
17///
18/// # Shorthand
19///
20/// The widget macro supports the shorthand that sets the `txt` and `target` properties.
21///
22/// ```
23/// # zng_wgt::enable_widget_macros!();
24/// # use zng_wgt::prelude::*;
25/// # use zng_wgt_text_input::label::*;
26/// #
27/// # fn main() {
28/// # let _scope = zng_app::APP.minimal();
29/// let label = Label!("txt", "target");
30/// # }
31/// ```
32#[widget($crate::label::Label {
33    ($txt:expr, $target:expr $(,)?) => {
34        txt = $txt;
35        target = $target;
36    };
37})]
38pub struct Label(FocusableMix<StyleMix<zng_wgt_text::Text>>);
39impl Label {
40    fn widget_intrinsic(&mut self) {
41        self.style_intrinsic(STYLE_FN_VAR, property_id!(self::style_fn));
42        widget_set! {
43            self;
44            style_base_fn = style_fn!(|_| DefaultStyle!());
45        }
46    }
47}
48impl_style_fn!(Label);
49
50/// Default label style.
51#[widget($crate::label::DefaultStyle)]
52pub struct DefaultStyle(Style);
53impl DefaultStyle {
54    fn widget_intrinsic(&mut self) {
55        widget_set! {
56            self;
57            replace = true;
58        }
59    }
60}
61
62/// Defines the widget the label is for.
63///
64/// When the label is pressed the widget or the first focusable child of the widget is focused.
65/// Accessibility metadata is also set so the target widget is marked as *labelled-by* this widget in the view-process.
66///
67/// If this is set focusable is disabled on the label widget.
68#[property(CONTEXT, widget_impl(Label))]
69pub fn target(child: impl UiNode, target: impl IntoVar<WidgetId>) -> impl UiNode {
70    let target = target.into_var();
71    let mut prev_target = None::<WidgetId>;
72
73    match_node(child, move |c, op| match op {
74        UiNodeOp::Init => {
75            WIDGET
76                .sub_var(&target)
77                .sub_event(&MOUSE_INPUT_EVENT)
78                .sub_event(&TOUCH_INPUT_EVENT)
79                .sub_event(&ACCESS_CLICK_EVENT);
80        }
81        UiNodeOp::Info { info } => {
82            c.info(info);
83
84            FocusInfoBuilder::new(info).focusable(false);
85
86            if let Some(mut a) = info.access() {
87                let target = target.get();
88                prev_target = Some(target);
89                a.set_labels(target);
90            }
91        }
92        UiNodeOp::Event { update } => {
93            c.event(update);
94
95            if let Some(args) = MOUSE_INPUT_EVENT.on(update) {
96                if args.is_mouse_down() {
97                    FOCUS.focus_widget_or_enter(target.get(), true, false);
98                }
99            } else if let Some(args) = TOUCH_INPUT_EVENT.on(update) {
100                if args.is_touch_start() {
101                    FOCUS.focus_widget_or_enter(target.get(), true, false);
102                }
103            } else if let Some(args) = ACCESS_CLICK_EVENT.on(update) {
104                if args.is_primary {
105                    FOCUS.focus_widget_or_enter(target.get(), true, false);
106                }
107            }
108        }
109        UiNodeOp::Update { .. } => {
110            if let Some(id) = target.get_new() {
111                if let Some(id) = prev_target.take() {
112                    UPDATES.update_info(id);
113                }
114                UPDATES.update_info(id);
115                WIDGET.update_info();
116            }
117        }
118        _ => {}
119    })
120}