kas_core/theme/traits.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//! Theme traits
7
8use super::{ColorsLinear, ThemeDraw, ThemeSize};
9use crate::autoimpl;
10use crate::config::{Config, WindowConfig};
11use crate::draw::{DrawIface, DrawSharedImpl, color};
12use crate::event::EventState;
13use std::any::Any;
14use std::cell::RefCell;
15
16#[allow(unused)] use crate::event::EventCx;
17
18/// A *theme* provides widget sizing and drawing implementations.
19///
20/// The theme is generic over some `DrawIface`.
21///
22/// Objects of this type are copied within each window's data structure. For
23/// large resources (e.g. fonts and icons) consider using external storage.
24#[autoimpl(for<T: trait + ?Sized> Box<T>)]
25pub trait Theme<DS: DrawSharedImpl> {
26 /// The associated [`Window`] implementation.
27 type Window: Window;
28
29 /// The associated [`ThemeDraw`] implementation.
30 type Draw<'a>: ThemeDraw
31 where
32 DS: 'a,
33 Self: 'a;
34
35 /// Theme initialisation
36 ///
37 /// The toolkit must call this method before [`Theme::new_window`]
38 /// to allow initialisation specific to the `DrawIface`.
39 fn init(&mut self, config: &RefCell<Config>);
40
41 /// Construct per-window storage
42 ///
43 /// Updates theme from configuration and constructs a scaled per-window size
44 /// cache.
45 ///
46 /// On "standard" monitors, the `dpi_factor` is 1. High-DPI screens may
47 /// have a factor of 2 or higher. The factor may not be an integer; e.g.
48 /// `9/8 = 1.125` works well with many 1440p screens. It is recommended to
49 /// round dimensions to the nearest integer, and cache the result:
50 /// ```notest
51 /// self.margin = i32::conv_nearest(MARGIN * factor);
52 /// ```
53 ///
54 /// A reference to the draw backend is provided allowing configuration.
55 fn new_window(&mut self, config: &WindowConfig) -> Self::Window;
56
57 /// Update a window created by [`Theme::new_window`]
58 ///
59 /// This is called when the DPI factor changes or theme config or dimensions change.
60 ///
61 /// Returns `true` when a resize is required based on changes to the scale factor or font size.
62 fn update_window(&mut self, window: &mut Self::Window, config: &WindowConfig) -> bool;
63
64 /// Prepare to draw and construct a [`ThemeDraw`] object
65 ///
66 /// This is called once per window per frame and should do any necessary
67 /// preparation such as loading fonts and textures which are loaded on
68 /// demand.
69 ///
70 /// Drawing via this [`ThemeDraw`] object is restricted to the specified `rect`.
71 ///
72 /// The `window` is guaranteed to be one created by a call to
73 /// [`Theme::new_window`] on `self`.
74 fn draw<'a>(
75 &'a self,
76 draw: DrawIface<'a, DS>,
77 ev: &'a mut EventState,
78 window: &'a mut Self::Window,
79 ) -> Self::Draw<'a>;
80
81 /// Construct a draw object from parts
82 ///
83 /// This method allows a "derived" theme to construct a draw object for the
84 /// inherited theme.
85 fn draw_upcast<'a>(
86 draw: DrawIface<'a, DS>,
87 ev: &'a mut EventState,
88 w: &'a mut Self::Window,
89 cols: &'a ColorsLinear,
90 ) -> Self::Draw<'a>;
91
92 /// The window/scene clear color
93 ///
94 /// This is not used when the window is transparent.
95 fn clear_color(&self) -> color::Rgba;
96}
97
98/// Per-window storage for the theme
99///
100/// Constructed via [`Theme::new_window`].
101///
102/// The main reason for this separation is to allow proper handling of
103/// multi-window applications across screens with differing DPIs.
104#[autoimpl(for<T: trait + ?Sized> Box<T>)]
105pub trait Window: 'static {
106 /// Construct a [`ThemeSize`] object
107 fn size(&self) -> &dyn ThemeSize;
108
109 fn as_any_mut(&mut self) -> &mut dyn Any;
110}