Skip to main content

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;
10use crate::geom::Rect;
11use crate::layout::AlignHints;
12use crate::text::format::FormattableText;
13use crate::theme::{SizeCx, 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    /// By default, this uses [`TextClass::Label`]; see [`Self::set_class`] and
26    /// [`Self::with_class`].
27    ///
28    /// Vertical alignment defaults to centred, horizontal
29    /// alignment depends on the script direction if not specified.
30    /// Line-wrapping is enabled by default.
31    ///
32    /// This type is generic over the text type.
33    #[derive(Debug)]
34    #[widget]
35    #[layout(self.text)]
36    pub struct Label<T: FormattableText + 'static = String> {
37        core: widget_core!(),
38        text: Text<T>,
39    }
40
41    impl Self {
42        /// Construct from `text`
43        #[inline]
44        pub fn new(text: T) -> Self {
45            Label {
46                core: Default::default(),
47                text: Text::new(text, TextClass::Label, true),
48            }
49        }
50
51        /// Construct from `text`, mapping to support any data type
52        #[inline]
53        pub fn new_any<A>(text: T) -> MapAny<A, Self> {
54            MapAny::new(Label::new(text))
55        }
56
57        /// Get text class
58        #[inline]
59        pub fn class(&self) -> TextClass {
60            self.text.class()
61        }
62
63        /// Set text class
64        ///
65        /// Default: [`TextClass::Label`]
66        #[inline]
67        pub fn set_class(&mut self, class: TextClass) {
68            self.text.set_class(class);
69        }
70
71        /// Set text class (inline)
72        ///
73        /// Default: [`TextClass::Label`]
74        #[inline]
75        pub fn with_class(mut self, class: TextClass) -> Self {
76            self.text.set_class(class);
77            self
78        }
79
80        /// Get whether line-wrapping is enabled
81        #[inline]
82        pub fn wrap(&self) -> bool {
83            self.text.wrap()
84        }
85
86        /// Enable/disable line wrapping
87        ///
88        /// By default this is enabled.
89        #[inline]
90        pub fn set_wrap(&mut self, wrap: bool) {
91            self.text.set_wrap(wrap);
92        }
93
94        /// Enable/disable line wrapping (inline)
95        #[inline]
96        pub fn with_wrap(mut self, wrap: bool) -> Self {
97            self.text.set_wrap(wrap);
98            self
99        }
100
101        /// Get read access to the text object
102        #[inline]
103        pub fn text(&self) -> &Text<T> {
104            &self.text
105        }
106
107        /// Set text in an existing `Label`
108        pub fn set_text(&mut self, cx: &mut ConfigCx, text: T) {
109            self.text.set_text(text);
110            self.text.reprepare_action(cx);
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 SizeCx, 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            self.text.configure(&mut cx.size_cx());
137        }
138    }
139
140    impl Label<String> {
141        /// Set text contents from a string
142        pub fn set_string(&mut self, cx: &mut ConfigCx, string: String) {
143            if self.text.set_string(string) {
144                self.text.reprepare_action(cx);
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}