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}