Skip to main content

kas_widgets/
access_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//! Label with access key
7
8#[allow(unused)] use super::Label;
9use kas::prelude::*;
10use kas::theme::{Text, TextClass};
11
12#[impl_self]
13mod AccessLabel {
14    /// A label supporting an access key
15    ///
16    /// An `AccessLabel` is a variant of [`Label`] supporting an access key,
17    /// for example "&Edit" binds an action to <kbd>Alt+E</kbd> since by default
18    /// <kbd>Alt</kbd> must be held to use access keys.
19    /// The access key is parsed from the input `text` (see [`AccessString`])
20    /// and underlined when <kbd>Alt</kbd> is held.
21    ///
22    /// Vertical alignment defaults to centred, horizontal
23    /// alignment depends on the script direction if not specified.
24    /// Line-wrapping is enabled by default.
25    ///
26    /// ### Action bindings
27    ///
28    /// This widget attempts to bind itself to its access key unless
29    /// [a different target is set](Self::set_target). If the binding succeeds
30    /// and the access key is used, the target will receive navigation focus
31    /// (if supported; otherwise the first supporting ancestor is focussed) and
32    /// `Event::Command(Command::Activate)` (likewise, an ancestor may handle
33    /// the event). This `AccessLabel` does not support focus and will not
34    /// handle the [`Command::Activate`] event.
35    #[derive(Debug)]
36    #[widget]
37    #[layout(self.text)]
38    pub struct AccessLabel {
39        core: widget_core!(),
40        target: Id,
41        text: Text<AccessString>,
42    }
43
44    impl Self {
45        /// Construct from `text`
46        #[inline]
47        pub fn new(text: impl Into<AccessString>) -> Self {
48            AccessLabel {
49                core: Default::default(),
50                target: Default::default(),
51                text: Text::new(text.into(), TextClass::Label, true),
52            }
53        }
54
55        /// Set the access key target
56        ///
57        /// This method should normally be called from [`Events::post_configure`].
58        #[inline]
59        pub fn set_target(&mut self, target: Id) {
60            self.target = target;
61        }
62
63        /// Get text class
64        #[inline]
65        pub fn class(&self) -> TextClass {
66            self.text.class()
67        }
68
69        /// Set text class
70        ///
71        /// Default: `TextClass::Label`
72        #[inline]
73        pub fn set_class(&mut self, class: TextClass) {
74            self.text.set_class(class);
75        }
76
77        /// Set text class (inline)
78        ///
79        /// Default: `TextClass::Label`
80        #[inline]
81        pub fn with_class(mut self, class: TextClass) -> Self {
82            self.text.set_class(class);
83            self
84        }
85
86        /// Get whether line-wrapping is enabled
87        #[inline]
88        pub fn wrap(&self) -> bool {
89            self.text.wrap()
90        }
91
92        /// Enable/disable line wrapping
93        ///
94        /// By default this is enabled.
95        #[inline]
96        pub fn set_wrap(&mut self, wrap: bool) {
97            self.text.set_wrap(wrap);
98        }
99
100        /// Enable/disable line wrapping (inline)
101        #[inline]
102        pub fn with_wrap(mut self, wrap: bool) -> Self {
103            self.text.set_wrap(wrap);
104            self
105        }
106
107        /// Get text contents
108        pub fn as_str(&self) -> &str {
109            self.text.as_str()
110        }
111
112        /// Get read access to the text object
113        #[inline]
114        pub fn text(&self) -> &Text<AccessString> {
115            &self.text
116        }
117
118        /// Set text in an existing `Label`
119        pub fn set_text(&mut self, cx: &mut ConfigCx, text: AccessString) {
120            self.text.set_text(text);
121            self.text.reprepare_action(cx);
122        }
123    }
124
125    impl Layout for Self {
126        fn set_rect(&mut self, cx: &mut SizeCx, rect: Rect, hints: AlignHints) {
127            self.text
128                .set_rect(cx, rect, hints.combine(AlignHints::VERT_CENTER));
129        }
130
131        fn draw(&self, mut draw: DrawCx) {
132            let rect = self.text.rect();
133            if let Some((key, effects)) = self.text.text().key()
134                && draw.access_key(&self.target, key)
135            {
136                // Stop on first successful binding and draw
137                draw.text_with_effects(rect.pos, rect, &self.text, &[], effects);
138            } else {
139                draw.text(rect, &self.text);
140            }
141        }
142    }
143
144    impl Tile for Self {
145        fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
146            if let Some((key, _)) = self.text.text().key() {
147                Role::AccessLabel(self.text.as_str(), key.clone())
148            } else {
149                Role::Label(self.text.as_str())
150            }
151        }
152    }
153
154    impl Events for Self {
155        type Data = ();
156
157        fn configure(&mut self, cx: &mut ConfigCx) {
158            self.target = self.id();
159            self.text.configure(&mut cx.size_cx());
160        }
161    }
162}