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}