Skip to main content

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, TextClass};
9use crate::autoimpl;
10use crate::dir::Directional;
11use crate::event::EventState;
12use crate::geom::Rect;
13use crate::layout::{AlignPair, FrameRules, LogicalBuilder, Margins, SizeRules};
14use crate::text::fonts::FontSelector;
15use std::ops::{Deref, DerefMut};
16
17#[allow(unused)]
18use crate::{event::ConfigCx, layout::Stretch, theme::DrawCx};
19
20/// Size and scaling interface
21///
22/// This context provides scaled sizing information from the theme.
23///
24/// Most methods get or calculate the size of some feature. These same features
25/// may be drawn through [`DrawCx`].
26pub struct SizeCx<'a> {
27    ev: &'a mut EventState,
28    // ThemeSize is implemented by super::dimensions::Window
29    w: &'a dyn ThemeSize,
30}
31
32impl<'a> Deref for SizeCx<'a> {
33    type Target = EventState;
34    fn deref(&self) -> &EventState {
35        self.ev
36    }
37}
38impl<'a> DerefMut for SizeCx<'a> {
39    fn deref_mut(&mut self) -> &mut EventState {
40        self.ev
41    }
42}
43
44impl<'a> SizeCx<'a> {
45    /// Construct from [`EventState`] and a [`ThemeSize`]
46    #[cfg_attr(not(feature = "internal_doc"), doc(hidden))]
47    #[cfg_attr(docsrs, doc(cfg(internal_doc)))]
48    #[inline]
49    pub fn new(ev: &'a mut EventState, w: &'a dyn ThemeSize) -> Self {
50        SizeCx { ev, w }
51    }
52
53    /// Get the scale factor
54    ///
55    /// "Traditional" PC screens have a scale factor of 1; high-DPI screens
56    /// may have a factor of 2 or higher. This may be fractional and may be
57    /// adjusted to suit the device type (e.g. a phone or desktop monitor) as
58    /// well as the user's preference.
59    ///
60    /// One could use this value to calculate physical size, but be warned that
61    /// the result may be quite inaccurate on anything other than a desktop
62    /// monitor: `25.4 mm = 1 inch = (96 * scale_factor) pixels`
63    ///
64    /// To calculate screen pixel sizes from virtual pixel sizes:
65    /// ```
66    /// use kas_core::cast::*;
67    /// # let scale_factor = 1.5f32;
68    /// let size: i32 = (100.0 * scale_factor).cast_ceil();
69    /// ```
70    ///
71    /// This value may change during a program's execution (e.g. when a window
72    /// is moved to a different monitor); in this case all widgets will be
73    /// resized via [`crate::Layout::size_rules`].
74    #[inline]
75    pub fn scale_factor(&self) -> f32 {
76        self.w.scale_factor()
77    }
78
79    /// Build [`SizeRules`] from the input size in logical pixels
80    #[inline]
81    pub fn logical(&self, width: f32, height: f32) -> LogicalBuilder {
82        LogicalBuilder::new((width, height), self.scale_factor())
83    }
84
85    /// Get the configured font selector for `class`
86    #[inline]
87    pub fn font(&self, class: TextClass) -> FontSelector {
88        self.w.font(class)
89    }
90
91    /// Get the default font size for `class`
92    ///
93    /// Units are physical pixels per font Em.
94    ///
95    /// The Em is a unit of typography (variously defined as the point-size of
96    /// the font, the height of the font or the width of an upper-case `M`).
97    ///
98    /// This method returns the size of 1 Em in physical pixels, derived from
99    /// the font size in use by the theme and the screen's scale factor.
100    #[inline]
101    pub fn dpem(&self, class: TextClass) -> f32 {
102        self.w.dpem(class)
103    }
104
105    /// Get the `(min, ideal)` line length for text which wraps
106    #[inline]
107    pub fn wrapped_line_len(&self, class: TextClass, dpem: f32) -> (i32, i32) {
108        self.w.wrapped_line_len(class, dpem)
109    }
110
111    /// The smallest reasonable size for a visible (non-frame) component
112    ///
113    /// This is used as a suggestion by some heuristics.
114    #[inline]
115    pub fn min_element_size(&self) -> i32 {
116        self.w.min_element_size()
117    }
118
119    /// The minimum size of a scrollable area
120    #[inline]
121    pub fn min_scroll_size(&self, axis: impl Directional, class: Option<TextClass>) -> i32 {
122        let class = class.unwrap_or(TextClass::Standard);
123        self.w.min_scroll_size(axis.is_vertical(), class)
124    }
125
126    /// The length of the grip (draggable handle) on a scroll bar or slider
127    ///
128    /// This is the length in line with the control. The size on the opposite
129    /// axis is assumed to be equal to the feature size as reported by
130    /// [`Self::feature`].
131    #[inline]
132    pub fn grip_len(&self) -> i32 {
133        self.w.grip_len()
134    }
135
136    /// The width of a vertical scroll bar
137    ///
138    /// This value is also available through [`Self::feature`].
139    #[inline]
140    pub fn scroll_bar_width(&self) -> i32 {
141        self.w.scroll_bar_width()
142    }
143
144    /// Get margin size
145    #[inline]
146    pub fn margins(&self, style: MarginStyle) -> Margins {
147        self.w.margins(style)
148    }
149
150    /// Get margins for [`MarginStyle::Inner`]
151    #[inline]
152    pub fn inner_margins(&self) -> Margins {
153        self.w.margins(MarginStyle::Inner)
154    }
155
156    /// Get margins for [`MarginStyle::Tiny`]
157    #[inline]
158    pub fn tiny_margins(&self) -> Margins {
159        self.w.margins(MarginStyle::Tiny)
160    }
161
162    /// Get margins for [`MarginStyle::Small`]
163    #[inline]
164    pub fn small_margins(&self) -> Margins {
165        self.w.margins(MarginStyle::Small)
166    }
167
168    /// Get margins for [`MarginStyle::Large`]
169    #[inline]
170    pub fn large_margins(&self) -> Margins {
171        self.w.margins(MarginStyle::Large)
172    }
173
174    /// Get margins for [`MarginStyle::Text`]
175    #[inline]
176    pub fn text_margins(&self) -> Margins {
177        self.w.margins(MarginStyle::Text)
178    }
179
180    /// Size rules for a feature
181    #[inline]
182    pub fn feature(&self, feature: Feature, axis: impl Directional) -> SizeRules {
183        self.w.feature(feature, axis.is_vertical())
184    }
185
186    /// Size of a frame around another element
187    #[inline]
188    pub fn frame(&self, style: FrameStyle, axis: impl Directional) -> FrameRules {
189        self.w.frame(style, axis.is_vertical())
190    }
191
192    /// Align a feature's rect
193    ///
194    /// In case the input `rect` is larger than desired on either axis, it is
195    /// reduced in size and offset within the original `rect` as is preferred.
196    #[inline]
197    pub fn align_feature(&self, feature: Feature, rect: Rect, align: AlignPair) -> Rect {
198        self.w.align_feature(feature, rect, align)
199    }
200}
201
202/// Theme sizing implementation
203#[autoimpl(for<S: trait + ?Sized, R: Deref<Target = S>> R)]
204pub trait ThemeSize {
205    /// Get the scale factor
206    fn scale_factor(&self) -> f32;
207
208    /// Get the configured font selector for `class`
209    fn font(&self, class: TextClass) -> FontSelector;
210
211    /// Get the default font size for `class`
212    ///
213    /// Units are physical pixels per Em.
214    fn dpem(&self, class: TextClass) -> f32;
215
216    /// Get the `(min, ideal)` line length for text which wraps
217    fn wrapped_line_len(&self, class: TextClass, dpem: f32) -> (i32, i32);
218
219    /// The smallest reasonable size for a visible (non-frame) component
220    ///
221    /// This is used as a suggestion by some heuristics.
222    fn min_element_size(&self) -> i32;
223
224    /// The minimum size of a scrollable area
225    fn min_scroll_size(&self, axis_is_vertical: bool, class: TextClass) -> i32;
226
227    /// The length of the grip (draggable handle) on a scroll bar or slider
228    fn grip_len(&self) -> i32;
229
230    /// The width of a vertical scroll bar
231    fn scroll_bar_width(&self) -> i32;
232
233    /// Get margin size
234    fn margins(&self, style: MarginStyle) -> Margins;
235
236    /// Size rules for a feature
237    fn feature(&self, feature: Feature, axis_is_vertical: bool) -> SizeRules;
238
239    /// Align a feature's rect
240    ///
241    /// In case the input `rect` is larger than desired on either axis, it is
242    /// reduced in size and offset within the original `rect` as is preferred.
243    fn align_feature(&self, feature: Feature, rect: Rect, align: AlignPair) -> Rect;
244
245    /// Size of a frame around another element
246    fn frame(&self, style: FrameStyle, axis_is_vertical: bool) -> FrameRules;
247}