kas_widgets/adapt/
with_label.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Wrapper adding a label
7
8use crate::AccessLabel;
9use kas::prelude::*;
10
11#[impl_self]
12mod WithLabel {
13    /// A wrapper widget with a label
14    ///
15    /// The label supports access keys; on usage the inner widget will receive
16    /// event `Event::Command(Command::Activate)`.
17    ///
18    /// Mouse/touch input on the label sends events to the inner widget.
19    #[derive(Clone, Default)]
20    #[widget]
21    #[layout(list![self.inner, self.label].with_direction(self.dir))]
22    pub struct WithLabel<W: Widget, D: Directional = Direction> {
23        core: widget_core!(),
24        dir: D,
25        #[widget]
26        inner: W,
27        #[widget(&())]
28        label: AccessLabel,
29    }
30
31    impl Self {
32        /// Construct a wrapper around `inner` placing a `label` in the given `direction`
33        pub fn new<T: Into<AccessString>>(inner: W, label: T) -> Self
34        where
35            D: Default,
36        {
37            Self::new_dir(inner, D::default(), label)
38        }
39    }
40    impl<W: Widget> WithLabel<W, kas::dir::Left> {
41        /// Construct from `inner` widget and `label`
42        pub fn left<T: Into<AccessString>>(inner: W, label: T) -> Self {
43            Self::new(inner, label)
44        }
45    }
46    impl<W: Widget> WithLabel<W, kas::dir::Right> {
47        /// Construct from `inner` widget and `label`
48        pub fn right<T: Into<AccessString>>(inner: W, label: T) -> Self {
49            Self::new(inner, label)
50        }
51    }
52
53    impl Self {
54        /// Construct a wrapper around `inner` placing a `label` in the given `direction`
55        #[inline]
56        pub fn new_dir<T: Into<AccessString>>(inner: W, direction: D, label: T) -> Self {
57            WithLabel {
58                core: Default::default(),
59                dir: direction,
60                inner,
61                label: AccessLabel::new(label.into()),
62            }
63        }
64
65        /// Get the direction
66        #[inline]
67        pub fn label_direction(&self) -> Direction {
68            self.dir.as_direction()
69        }
70
71        /// Take inner
72        #[inline]
73        pub fn take_inner(self) -> W {
74            self.inner
75        }
76
77        /// Get whether line-wrapping is enabled
78        #[inline]
79        pub fn label_wrap(&self) -> bool {
80            self.label.wrap()
81        }
82
83        /// Enable/disable line wrapping
84        ///
85        /// By default this is enabled.
86        #[inline]
87        pub fn set_label_wrap(&mut self, wrap: bool) {
88            self.label.set_wrap(wrap);
89        }
90
91        /// Enable/disable line wrapping (inline)
92        #[inline]
93        pub fn with_label_wrap(mut self, wrap: bool) -> Self {
94            self.label.set_wrap(wrap);
95            self
96        }
97
98        /// Set label text
99        ///
100        /// Note: this must not be called before fonts have been initialised
101        /// (usually done by the theme when the main loop starts).
102        pub fn set_label_text<T: Into<AccessString>>(&mut self, cx: &mut EventState, text: T) {
103            self.label.set_text(cx, text.into());
104        }
105    }
106
107    impl Tile for Self {
108        fn role_child_properties(&self, cx: &mut dyn RoleCx, index: usize) {
109            if index == widget_index!(self.inner) {
110                cx.set_label(self.label.id());
111            }
112        }
113
114        fn nav_next(&self, _: bool, from: Option<usize>) -> Option<usize> {
115            from.xor(Some(widget_index!(self.inner)))
116        }
117
118        fn probe(&self, _: Coord) -> Id {
119            self.inner.id()
120        }
121    }
122
123    impl Events for Self {
124        type Data = W::Data;
125
126        fn configure_recurse(&mut self, cx: &mut ConfigCx, data: &Self::Data) {
127            let id = self.make_child_id(widget_index!(self.inner));
128            if id.is_valid() {
129                cx.configure(self.inner.as_node(data), id);
130            }
131
132            let id = self.make_child_id(widget_index!(self.label));
133            if id.is_valid() {
134                cx.configure(self.label.as_node(&()), id);
135                self.label.set_target(self.inner.id());
136            }
137        }
138    }
139}
140
141#[impl_self]
142mod WithHiddenLabel {
143    /// A wrapper widget with a hidden label
144    ///
145    /// This label is not normally visible but may be read by accessibility
146    /// tools and tooltips.
147    #[derive(Clone, Default)]
148    #[derive_widget]
149    pub struct WithHiddenLabel<W: Widget> {
150        #[widget]
151        inner: W,
152        label: String,
153    }
154
155    impl Self {
156        /// Wrap `inner`, adding a hidden `label`
157        #[inline]
158        pub fn new<T: ToString>(inner: W, label: T) -> Self {
159            WithHiddenLabel {
160                inner,
161                label: label.to_string(),
162            }
163        }
164
165        /// Take inner
166        #[inline]
167        pub fn take_inner(self) -> W {
168            self.inner
169        }
170
171        /// Set the label
172        pub fn set_label<T: ToString>(&mut self, text: T) {
173            self.label = text.to_string();
174        }
175    }
176
177    impl Tile for Self {
178        fn tooltip(&self) -> Option<&str> {
179            Some(&self.label)
180        }
181
182        fn role(&self, cx: &mut dyn RoleCx) -> Role<'_> {
183            cx.set_label(&self.label);
184            self.inner.role(cx)
185        }
186    }
187}