kas_core/theme/size.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//! "Handle" types used by themes
7
8use super::{Feature, FrameStyle, MarginStyle, SizableText, Text, TextClass};
9use crate::autoimpl;
10use crate::dir::Directional;
11use crate::geom::Rect;
12use crate::layout::{AlignPair, AxisInfo, FrameRules, Margins, SizeRules};
13use crate::text::format::FormattableText;
14use std::ops::Deref;
15
16#[allow(unused)]
17use crate::{event::ConfigCx, layout::Stretch, theme::DrawCx};
18
19/// Size and scale interface
20///
21/// This interface is provided to widgets in [`crate::Layout::size_rules`].
22/// It may also be accessed through [`crate::event::EventCx::size_cx`],
23/// [`DrawCx::size_cx`].
24///
25/// Most methods get or calculate the size of some feature. These same features
26/// may be drawn through [`DrawCx`].
27pub struct SizeCx<'a>(&'a dyn ThemeSize);
28
29impl<'a> SizeCx<'a> {
30 /// Construct from a [`ThemeSize`]
31 #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
32 #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
33 pub fn new(h: &'a dyn ThemeSize) -> Self {
34 SizeCx(h)
35 }
36
37 /// Reborrow with a new lifetime
38 ///
39 /// Rust allows references like `&T` or `&mut T` to be "reborrowed" through
40 /// coercion: essentially, the pointer is copied under a new, shorter, lifetime.
41 /// Until rfcs#1403 lands, reborrows on user types require a method call.
42 ///
43 /// Calling this method is zero-cost.
44 #[inline(always)]
45 pub fn re<'b>(&'b self) -> SizeCx<'b>
46 where
47 'a: 'b,
48 {
49 SizeCx(self.0)
50 }
51
52 /// Get the scale factor
53 ///
54 /// "Traditional" PC screens have a scale factor of 1; high-DPI screens
55 /// may have a factor of 2 or higher. This may be fractional and may be
56 /// adjusted to suit the device type (e.g. a phone or desktop monitor) as
57 /// well as the user's preference.
58 ///
59 /// One could use this value to calculate physical size, but be warned that
60 /// the result may be quite inaccurate on anything other than a desktop
61 /// monitor: `25.4 mm = 1 inch = (96 * scale_factor) pixels`
62 ///
63 /// To calculate screen pixel sizes from virtual pixel sizes:
64 /// ```
65 /// use kas_core::cast::*;
66 /// # let scale_factor = 1.5f32;
67 /// let size: i32 = (100.0 * scale_factor).cast_ceil();
68 /// ```
69 ///
70 /// This value may change during a program's execution (e.g. when a window
71 /// is moved to a different monitor); in this case all widgets will be
72 /// resized via [`crate::Layout::size_rules`].
73 pub fn scale_factor(&self) -> f32 {
74 self.0.scale_factor()
75 }
76
77 /// The Em size of the standard font in pixels
78 ///
79 /// The Em is a unit of typography (variously defined as the point-size of
80 /// the font, the height of the font or the width of an upper-case `M`).
81 ///
82 /// This method returns the size of 1 Em in physical pixels, derived from
83 /// the font size in use by the theme and the screen's scale factor.
84 pub fn dpem(&self) -> f32 {
85 self.0.dpem()
86 }
87
88 /// The smallest reasonable size for a visible (non-frame) component
89 ///
90 /// This is used as a suggestion by some heuristics.
91 pub fn min_element_size(&self) -> i32 {
92 self.0.min_element_size()
93 }
94
95 /// The minimum size of a scrollable area
96 pub fn min_scroll_size(&self, axis: impl Directional) -> i32 {
97 self.0.min_scroll_size(axis.is_vertical())
98 }
99
100 /// The length of the grip (draggable handle) on a scroll bar or slider
101 ///
102 /// This is the length in line with the control. The size on the opposite
103 /// axis is assumed to be equal to the feature size as reported by
104 /// [`Self::feature`].
105 pub fn grip_len(&self) -> i32 {
106 self.0.grip_len()
107 }
108
109 /// The width of a vertical scroll bar
110 ///
111 /// This value is also available through [`Self::feature`].
112 pub fn scroll_bar_width(&self) -> i32 {
113 self.0.scroll_bar_width()
114 }
115
116 /// Get margin size
117 pub fn margins(&self, style: MarginStyle) -> Margins {
118 self.0.margins(style)
119 }
120
121 /// Get margins for [`MarginStyle::Inner`]
122 pub fn inner_margins(&self) -> Margins {
123 self.0.margins(MarginStyle::Inner)
124 }
125
126 /// Get margins for [`MarginStyle::Tiny`]
127 pub fn tiny_margins(&self) -> Margins {
128 self.0.margins(MarginStyle::Tiny)
129 }
130
131 /// Get margins for [`MarginStyle::Small`]
132 pub fn small_margins(&self) -> Margins {
133 self.0.margins(MarginStyle::Small)
134 }
135
136 /// Get margins for [`MarginStyle::Large`]
137 pub fn large_margins(&self) -> Margins {
138 self.0.margins(MarginStyle::Large)
139 }
140
141 /// Get margins for [`MarginStyle::Text`]
142 pub fn text_margins(&self) -> Margins {
143 self.0.margins(MarginStyle::Text)
144 }
145
146 /// Size rules for a feature
147 pub fn feature(&self, feature: Feature, axis: impl Directional) -> SizeRules {
148 self.0.feature(feature, axis.is_vertical())
149 }
150
151 /// Size of a frame around another element
152 pub fn frame(&self, style: FrameStyle, axis: impl Directional) -> FrameRules {
153 self.0.frame(style, axis.is_vertical())
154 }
155
156 /// Get [`SizeRules`] for a text element
157 ///
158 /// The [`TextClass`] is used to select a font and controls whether line
159 /// wrapping is enabled.
160 ///
161 /// Horizontal size without wrapping is simply the size the text.
162 /// Horizontal size with wrapping is bounded to some width dependant on the
163 /// theme, and may have non-zero [`Stretch`] depending on the size.
164 ///
165 /// Vertical size is the size of the text with or without wrapping, but with
166 /// the minimum at least the height of one line of text.
167 ///
168 /// Widgets with editable text contents or internal scrolling enabled may
169 /// wish to adjust the result.
170 ///
171 /// Note: this method partially prepares the `text` object. It is not
172 /// required to call this method but it is required to call
173 /// [`ConfigCx::text_configure`] before text display for correct results.
174 pub fn text_rules<T: FormattableText>(&self, text: &mut Text<T>, axis: AxisInfo) -> SizeRules {
175 let class = text.class();
176 self.0.text_rules(text, class, axis)
177 }
178}
179
180/// Theme sizing implementation
181#[autoimpl(for<S: trait + ?Sized, R: Deref<Target = S>> R)]
182pub trait ThemeSize {
183 /// Get the scale factor
184 fn scale_factor(&self) -> f32;
185
186 /// Get the Em size of the standard font in pixels
187 fn dpem(&self) -> f32;
188
189 /// The smallest reasonable size for a visible (non-frame) component
190 ///
191 /// This is used as a suggestion by some heuristics.
192 fn min_element_size(&self) -> i32;
193
194 /// The minimum size of a scrollable area
195 fn min_scroll_size(&self, axis_is_vertical: bool) -> i32;
196
197 /// The length of the grip (draggable handle) on a scroll bar or slider
198 fn grip_len(&self) -> i32;
199
200 /// The width of a vertical scroll bar
201 fn scroll_bar_width(&self) -> i32;
202
203 /// Get margin size
204 fn margins(&self, style: MarginStyle) -> Margins;
205
206 /// Size rules for a feature
207 fn feature(&self, feature: Feature, axis_is_vertical: bool) -> SizeRules;
208
209 /// Align a feature's rect
210 ///
211 /// In case the input `rect` is larger than desired on either axis, it is
212 /// reduced in size and offset within the original `rect` as is preferred.
213 fn align_feature(&self, feature: Feature, rect: Rect, align: AlignPair) -> Rect;
214
215 /// Size of a frame around another element
216 fn frame(&self, style: FrameStyle, axis_is_vertical: bool) -> FrameRules;
217
218 /// Configure a text object, setting font properties
219 fn text_configure(&self, text: &mut dyn SizableText, class: TextClass);
220
221 /// Get [`SizeRules`] for a text element
222 fn text_rules(&self, text: &mut dyn SizableText, class: TextClass, axis: AxisInfo)
223 -> SizeRules;
224}