kas_core/widgets/
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 widgets
7
8use super::adapt::MapAny;
9use crate::event::{ConfigCx, EventState};
10use crate::geom::Rect;
11use crate::layout::AlignHints;
12use crate::text::format::FormattableText;
13use crate::theme::{Text, TextClass};
14use crate::{Events, Layout, Role, RoleCx, Tile};
15use kas_macros::impl_self;
16use std::fmt::Debug;
17
18#[impl_self]
19mod Label {
20    /// A text label
21    ///
22    /// `Label` text is set at construction time. It may also be set by
23    /// [`Self::set_text`] or [`Self::set_string`].
24    ///
25    /// Vertical alignment defaults to centred, horizontal
26    /// alignment depends on the script direction if not specified.
27    /// Line-wrapping is enabled by default.
28    ///
29    /// This type is generic over the text type.
30    #[derive(Clone, Debug, Default)]
31    #[widget]
32    #[layout(self.text)]
33    pub struct Label<T: FormattableText + 'static> {
34        core: widget_core!(),
35        text: Text<T>,
36    }
37
38    impl Self {
39        /// Construct from `text`
40        #[inline]
41        pub fn new(text: T) -> Self {
42            Label {
43                core: Default::default(),
44                text: Text::new(text, TextClass::Label(true)),
45            }
46        }
47
48        /// Construct from `text`, mapping to support any data type
49        #[inline]
50        pub fn new_any<A>(text: T) -> MapAny<A, Self> {
51            MapAny::new(Label::new(text))
52        }
53
54        /// Get text class
55        #[inline]
56        pub fn class(&self) -> TextClass {
57            self.text.class()
58        }
59
60        /// Set text class
61        ///
62        /// Default: `TextClass::Label(true)`
63        #[inline]
64        pub fn set_class(&mut self, class: TextClass) {
65            self.text.set_class(class);
66        }
67
68        /// Set text class (inline)
69        ///
70        /// Default: `TextClass::Label(true)`
71        #[inline]
72        pub fn with_class(mut self, class: TextClass) -> Self {
73            self.text.set_class(class);
74            self
75        }
76
77        /// Get whether line-wrapping is enabled
78        #[inline]
79        pub fn wrap(&self) -> bool {
80            self.class().multi_line()
81        }
82
83        /// Enable/disable line wrapping
84        ///
85        /// This is equivalent to `label.set_class(TextClass::Label(wrap))`.
86        ///
87        /// By default this is enabled.
88        #[inline]
89        pub fn set_wrap(&mut self, wrap: bool) {
90            self.text.set_class(TextClass::Label(wrap));
91        }
92
93        /// Enable/disable line wrapping (inline)
94        #[inline]
95        pub fn with_wrap(mut self, wrap: bool) -> Self {
96            self.text.set_class(TextClass::Label(wrap));
97            self
98        }
99
100        /// Get read access to the text object
101        #[inline]
102        pub fn text(&self) -> &Text<T> {
103            &self.text
104        }
105
106        /// Set text in an existing `Label`
107        pub fn set_text(&mut self, cx: &mut EventState, text: T) {
108            self.text.set_text(text);
109            let act = self.text.reprepare_action();
110            cx.action(self, act);
111        }
112
113        /// Get text contents
114        pub fn as_str(&self) -> &str {
115            self.text.as_str()
116        }
117    }
118
119    impl Layout for Self {
120        fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
121            self.text
122                .set_rect(cx, rect, hints.combine(AlignHints::VERT_CENTER));
123        }
124    }
125
126    impl Tile for Self {
127        fn role(&self, _: &mut dyn RoleCx) -> Role<'_> {
128            Role::Label(self.text.as_str())
129        }
130    }
131
132    impl Events for Self {
133        type Data = ();
134
135        fn configure(&mut self, cx: &mut ConfigCx) {
136            cx.text_configure(&mut self.text);
137        }
138    }
139
140    impl Label<String> {
141        /// Set text contents from a string
142        pub fn set_string(&mut self, cx: &mut EventState, string: String) {
143            if self.text.set_string(string) {
144                cx.action(self.id(), self.text.reprepare_action());
145            }
146        }
147    }
148}
149
150/* TODO(specialization): can we support this? min_specialization is not enough.
151impl<U, T: From<U> + FormattableText + 'static> From<U> for Label<T> {
152    default fn from(text: U) -> Self {
153        let text = T::from(text);
154        Label::new(text)
155    }
156}*/
157
158impl<T: FormattableText + 'static> From<T> for Label<T> {
159    fn from(text: T) -> Self {
160        Label::new(text)
161    }
162}
163
164impl<'a> From<&'a str> for Label<String> {
165    fn from(text: &'a str) -> Self {
166        Label::new(text.to_string())
167    }
168}