From bef24a21f8b8428bbf026e26f27045d4e7321e2b Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 8 Jun 2021 10:59:28 +0100 Subject: [PATCH 1/5] Remove Theme::new_window's draw parameter --- kas-theme/src/flat_theme.rs | 2 +- kas-theme/src/multi.rs | 4 ++-- kas-theme/src/shaded_theme.rs | 2 +- kas-theme/src/theme_dst.rs | 10 +++++----- kas-theme/src/traits.rs | 6 +++--- kas-wgpu/examples/custom-theme.rs | 4 ++-- kas-wgpu/src/window.rs | 2 +- 7 files changed, 15 insertions(+), 15 deletions(-) diff --git a/kas-theme/src/flat_theme.rs b/kas-theme/src/flat_theme.rs index 3d62f617e..83ab960fe 100644 --- a/kas-theme/src/flat_theme.rs +++ b/kas-theme/src/flat_theme.rs @@ -115,7 +115,7 @@ where } } - fn new_window(&self, _draw: &mut D::Draw, dpi_factor: f32) -> Self::Window { + fn new_window(&self, dpi_factor: f32) -> Self::Window { DimensionsWindow::new(DIMS, self.config.font_size(), dpi_factor) } diff --git a/kas-theme/src/multi.rs b/kas-theme/src/multi.rs index 67f8a6e97..3bbaddc25 100644 --- a/kas-theme/src/multi.rs +++ b/kas-theme/src/multi.rs @@ -135,8 +135,8 @@ impl Theme for MultiTheme { } } - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> Self::Window { - self.themes[self.active].new_window(draw, dpi_factor) + fn new_window(&self, dpi_factor: f32) -> Self::Window { + self.themes[self.active].new_window(dpi_factor) } fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) { diff --git a/kas-theme/src/shaded_theme.rs b/kas-theme/src/shaded_theme.rs index fed5ee531..1a49cbde8 100644 --- a/kas-theme/src/shaded_theme.rs +++ b/kas-theme/src/shaded_theme.rs @@ -104,7 +104,7 @@ where } } - fn new_window(&self, _draw: &mut D::Draw, dpi_factor: f32) -> Self::Window { + fn new_window(&self, dpi_factor: f32) -> Self::Window { DimensionsWindow::new(DIMS, self.config.font_size(), dpi_factor) } diff --git a/kas-theme/src/theme_dst.rs b/kas-theme/src/theme_dst.rs index 01b8f1b5f..f0d258e5d 100644 --- a/kas-theme/src/theme_dst.rs +++ b/kas-theme/src/theme_dst.rs @@ -54,7 +54,7 @@ pub trait ThemeDst: ThemeApi { /// Uses a [`StackDst`] to avoid requiring an associated type. /// /// See also [`Theme::new_window`]. - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> StackDst>; + fn new_window(&self, dpi_factor: f32) -> StackDst>; /// Update a window created by [`Theme::new_window`] /// @@ -117,8 +117,8 @@ where self.init(draw); } - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> StackDst> { - let window = >::new_window(self, draw, dpi_factor); + fn new_window(&self, dpi_factor: f32) -> StackDst> { + let window = >::new_window(self, dpi_factor); #[cfg(feature = "unsize")] { StackDst::new_or_boxed(window) @@ -181,8 +181,8 @@ impl<'a, D: DrawShared, T: Theme> ThemeDst for T { self.init(draw); } - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> StackDst> { - let window = >::new_window(self, draw, dpi_factor); + fn new_window(&self, dpi_factor: f32) -> StackDst> { + let window = >::new_window(self, dpi_factor); StackDst::new_or_boxed(window) } diff --git a/kas-theme/src/traits.rs b/kas-theme/src/traits.rs index 51d9075c4..a330871db 100644 --- a/kas-theme/src/traits.rs +++ b/kas-theme/src/traits.rs @@ -74,7 +74,7 @@ pub trait Theme: ThemeApi { /// ``` /// /// A reference to the draw backend is provided allowing configuration. - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> Self::Window; + fn new_window(&self, dpi_factor: f32) -> Self::Window; /// Update a window created by [`Theme::new_window`] /// @@ -161,8 +161,8 @@ impl, D: DrawShared> Theme for Box { self.deref_mut().init(draw); } - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> Self::Window { - self.deref().new_window(draw, dpi_factor) + fn new_window(&self, dpi_factor: f32) -> Self::Window { + self.deref().new_window(dpi_factor) } fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) { self.deref().update_window(window, dpi_factor); diff --git a/kas-wgpu/examples/custom-theme.rs b/kas-wgpu/examples/custom-theme.rs index 5a75ba7f6..cb22e536f 100644 --- a/kas-wgpu/examples/custom-theme.rs +++ b/kas-wgpu/examples/custom-theme.rs @@ -70,8 +70,8 @@ where self.inner.init(draw); } - fn new_window(&self, draw: &mut D::Draw, dpi_factor: f32) -> Self::Window { - Theme::::new_window(&self.inner, draw, dpi_factor) + fn new_window(&self, dpi_factor: f32) -> Self::Window { + Theme::::new_window(&self.inner, dpi_factor) } fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) { diff --git a/kas-wgpu/src/window.rs b/kas-wgpu/src/window.rs index 7b9213117..b4c5ae576 100644 --- a/kas-wgpu/src/window.rs +++ b/kas-wgpu/src/window.rs @@ -56,7 +56,7 @@ impl>> Window { // Create draw immediately (with Size::ZERO) to find ideal window size let scale_factor = shared.scale_factor as f32; let mut draw = shared.draw.new_window(&mut shared.device, Size::ZERO); - let mut theme_window = shared.theme.new_window(&mut draw, scale_factor); + let mut theme_window = shared.theme.new_window(scale_factor); let mut mgr = ManagerState::new(shared.config.clone()); let mut tkw = TkWindow::new(shared, None, &mut theme_window); From 517d2abc052785a0650853ed178e3c19808fda88 Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 8 Jun 2021 12:23:00 +0100 Subject: [PATCH 2/5] Make ShadedTheme an extension over FlatTheme --- kas-theme/src/flat_theme.rs | 4 +-- kas-theme/src/shaded_theme.rs | 62 +++++++++++++---------------------- 2 files changed, 24 insertions(+), 42 deletions(-) diff --git a/kas-theme/src/flat_theme.rs b/kas-theme/src/flat_theme.rs index 83ab960fe..1d54809ac 100644 --- a/kas-theme/src/flat_theme.rs +++ b/kas-theme/src/flat_theme.rs @@ -29,8 +29,8 @@ const BG_SHRINK_FACTOR: f32 = 1.0 - std::f32::consts::FRAC_1_SQRT_2; /// A theme with flat (unshaded) rendering #[derive(Clone, Debug)] pub struct FlatTheme { - config: Config, - cols: ColorsLinear, + pub(crate) config: Config, + pub(crate) cols: ColorsLinear, } impl FlatTheme { diff --git a/kas-theme/src/shaded_theme.rs b/kas-theme/src/shaded_theme.rs index 1a49cbde8..ce3bde02c 100644 --- a/kas-theme/src/shaded_theme.rs +++ b/kas-theme/src/shaded_theme.rs @@ -8,7 +8,9 @@ use std::f32; use std::ops::Range; -use crate::{ColorsLinear, Config, Dimensions, DimensionsParams, DimensionsWindow, Theme, Window}; +use crate::{ + ColorsLinear, Config, Dimensions, DimensionsParams, DimensionsWindow, FlatTheme, Theme, Window, +}; use kas::dir::{Direction, Directional}; use kas::draw::{ self, color::Rgba, Draw, DrawRounded, DrawShaded, DrawShared, ImageId, InputState, Pass, @@ -21,24 +23,21 @@ use kas::TkAction; /// A theme using simple shading to give apparent depth to elements #[derive(Clone, Debug)] pub struct ShadedTheme { - config: Config, - cols: ColorsLinear, + flat: FlatTheme, } impl ShadedTheme { /// Construct pub fn new() -> Self { - ShadedTheme { - config: Default::default(), - cols: ColorsLinear::default(), - } + let flat = FlatTheme::new(); + ShadedTheme { flat } } /// Set font size /// /// Units: Points per Em (standard unit of font size) pub fn with_font_size(mut self, pt_size: f32) -> Self { - self.config.set_font_size(pt_size); + self.flat.config.set_font_size(pt_size); self } @@ -46,9 +45,9 @@ impl ShadedTheme { /// /// If no scheme by this name is found the scheme is left unchanged. pub fn with_colours(mut self, scheme: &str) -> Self { - self.config.set_active_scheme(scheme); - if let Some(scheme) = self.config.get_color_scheme(scheme) { - self.cols = scheme.into(); + self.flat.config.set_active_scheme(scheme); + if let Some(scheme) = self.flat.config.get_color_scheme(scheme) { + self.flat.cols = scheme.into(); } self } @@ -87,29 +86,23 @@ where type DrawHandle<'a> = DrawHandle<'a, D>; fn config(&self) -> std::borrow::Cow { - std::borrow::Cow::Borrowed(&self.config) + >::config(&self.flat) } fn apply_config(&mut self, config: &Self::Config) -> TkAction { - let action = self.config.apply_config(config); - if let Some(scheme) = self.config.get_active_scheme() { - self.cols = scheme.into(); - } - action + >::apply_config(&mut self.flat, config) } - fn init(&mut self, _draw: &mut D) { - if let Err(e) = kas::text::fonts::fonts().select_default() { - panic!("Error loading font: {}", e); - } + fn init(&mut self, draw: &mut D) { + >::init(&mut self.flat, draw) } fn new_window(&self, dpi_factor: f32) -> Self::Window { - DimensionsWindow::new(DIMS, self.config.font_size(), dpi_factor) + DimensionsWindow::new(DIMS, self.flat.config.font_size(), dpi_factor) } fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) { - window.dims = Dimensions::new(DIMS, self.config.font_size(), dpi_factor); + window.dims = Dimensions::new(DIMS, self.flat.config.font_size(), dpi_factor); } #[cfg(not(feature = "gat"))] @@ -128,7 +121,7 @@ where shared: extend_lifetime(shared), draw: extend_lifetime(draw), window: extend_lifetime(window), - cols: std::mem::transmute::<&'a ColorsLinear, &'static ColorsLinear>(&self.cols), + cols: std::mem::transmute::<&'a ColorsLinear, &'static ColorsLinear>(&self.flat.cols), offset: Offset::ZERO, pass: Pass::new(0), } @@ -144,39 +137,28 @@ where shared, draw, window, - cols: &self.cols, + cols: &self.flat.cols, offset: Offset::ZERO, pass: Pass::new(0), } } fn clear_color(&self) -> Rgba { - self.cols.background + >::clear_color(&self.flat) } } impl ThemeApi for ShadedTheme { fn set_font_size(&mut self, pt_size: f32) -> TkAction { - self.config.set_font_size(pt_size); - TkAction::RESIZE | TkAction::THEME_UPDATE + self.flat.set_font_size(pt_size) } fn list_schemes(&self) -> Vec<&str> { - self.config - .color_schemes_iter() - .map(|(name, _)| name) - .collect() + self.flat.list_schemes() } fn set_scheme(&mut self, name: &str) -> TkAction { - if name != self.config.active_scheme() { - if let Some(scheme) = self.config.get_color_scheme(name) { - self.cols = scheme.into(); - self.config.set_active_scheme(name); - return TkAction::REDRAW; - } - } - TkAction::empty() + self.flat.set_scheme(name) } } From 600ddf8e5e3d9f7807a39ddd3d41ac3070741d5b Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Tue, 8 Jun 2021 15:20:10 +0100 Subject: [PATCH 3/5] Make fonts configurable per class (partial) --- Cargo.toml | 2 +- kas-theme/Cargo.toml | 1 + kas-theme/src/dim.rs | 82 +++++++++++++++++++++-------------- kas-theme/src/flat_theme.rs | 13 ++++-- kas-theme/src/shaded_theme.rs | 9 ++-- 5 files changed, 64 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f6588999a..e9d32a74f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,4 +89,4 @@ features = ["serde"] members = ["kas-macros", "kas-theme", "kas-wgpu"] [patch.crates-io] -kas-text = { git = "https://github.com/kas-gui/kas-text.git", rev = "c594569d5d8a4640c2b76865114453b2701d0c35" } +kas-text = { git = "https://github.com/kas-gui/kas-text.git", rev = "58f07dee97fff805f84427185e1156d50f72796a" } diff --git a/kas-theme/Cargo.toml b/kas-theme/Cargo.toml index b0407f8e8..65902a202 100644 --- a/kas-theme/Cargo.toml +++ b/kas-theme/Cargo.toml @@ -28,6 +28,7 @@ stack_dst = ["kas/stack_dst", "stack_dst_"] unsize = ["stack_dst_/unsize"] [dependencies] +linear-map = "1.2.0" log = "0.4" serde = { version = "1.0.123", features = ["derive"], optional = true } stack_dst_ = { version = "0.6", package = "stack_dst", optional = true } diff --git a/kas-theme/src/dim.rs b/kas-theme/src/dim.rs index 8fda88fed..a52879531 100644 --- a/kas-theme/src/dim.rs +++ b/kas-theme/src/dim.rs @@ -7,15 +7,17 @@ //! //! Widget size and appearance can be modified through themes. +use linear_map::LinearMap; use std::any::Any; use std::f32; use std::path::Path; +use std::rc::Rc; use kas::cast::{Cast, CastFloat, ConvFloat}; use kas::draw::{self, DrawShared, ImageId, TextClass}; use kas::geom::{Size, Vec2}; use kas::layout::{AxisInfo, FrameRules, Margins, SizeRules, Stretch}; -use kas::text::{TextApi, TextApiExt}; +use kas::text::{fonts::FontId, TextApi, TextApiExt}; /// Parameterisation of [`Dimensions`] /// @@ -99,14 +101,25 @@ impl Dimensions { /// A convenient implementation of [`crate::Window`] pub struct DimensionsWindow { pub dims: Dimensions, + pub fonts: Rc>, } impl DimensionsWindow { - pub fn new(dims: DimensionsParams, pt_size: f32, scale_factor: f32) -> Self { + pub fn new( + dims: DimensionsParams, + pt_size: f32, + scale_factor: f32, + fonts: Rc>, + ) -> Self { DimensionsWindow { dims: Dimensions::new(dims, pt_size, scale_factor), + fonts, } } + + pub fn update(&mut self, dims: DimensionsParams, pt_size: f32, scale_factor: f32) { + self.dims = Dimensions::new(dims, pt_size, scale_factor); + } } impl crate::Window for DimensionsWindow { @@ -118,12 +131,12 @@ impl crate::Window for DimensionsWindow { #[cfg(not(feature = "gat"))] unsafe fn size_handle<'a>(&'a mut self, draw: &'a mut D) -> Self::SizeHandle { // We extend lifetimes (unsafe) due to the lack of associated type generics. - let h: SizeHandle<'a, D> = SizeHandle::new(&self.dims, draw); + let h: SizeHandle<'a, D> = SizeHandle::new(self, draw); std::mem::transmute(h) } #[cfg(feature = "gat")] fn size_handle<'a>(&'a mut self, draw: &'a mut D) -> Self::SizeHandle<'a> { - SizeHandle::new(&self.dims, draw) + SizeHandle::new(self, draw) } fn as_any_mut(&mut self) -> &mut dyn Any { @@ -132,57 +145,57 @@ impl crate::Window for DimensionsWindow { } pub struct SizeHandle<'a, D: DrawShared> { - dims: &'a Dimensions, + w: &'a DimensionsWindow, draw: &'a mut D, } impl<'a, D: DrawShared> SizeHandle<'a, D> { - pub fn new(dims: &'a Dimensions, draw: &'a mut D) -> Self { - SizeHandle { dims, draw } + pub fn new(w: &'a DimensionsWindow, draw: &'a mut D) -> Self { + SizeHandle { w, draw } } } impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { fn scale_factor(&self) -> f32 { - self.dims.scale_factor + self.w.dims.scale_factor } fn pixels_from_points(&self, pt: f32) -> f32 { - self.dims.dpp * pt + self.w.dims.dpp * pt } fn pixels_from_em(&self, em: f32) -> f32 { - self.dims.dpp * self.dims.pt_size * em + self.w.dims.dpp * self.w.dims.pt_size * em } fn frame(&self, _vert: bool) -> FrameRules { - FrameRules::new_sym(self.dims.frame, 0, 0) + FrameRules::new_sym(self.w.dims.frame, 0, 0) } fn menu_frame(&self, vert: bool) -> FrameRules { - let mut size = self.dims.frame; + let mut size = self.w.dims.frame; if vert { size /= 2; } FrameRules::new_sym(size, 0, 0) } fn separator(&self) -> Size { - Size::splat(self.dims.frame) + Size::splat(self.w.dims.frame) } fn nav_frame(&self, _vert: bool) -> FrameRules { - FrameRules::new_sym(self.dims.inner_margin.into(), 0, 0) + FrameRules::new_sym(self.w.dims.inner_margin.into(), 0, 0) } fn inner_margin(&self) -> Size { - Size::splat(self.dims.inner_margin.into()) + Size::splat(self.w.dims.inner_margin.into()) } fn outer_margins(&self) -> Margins { - Margins::splat(self.dims.outer_margin) + Margins::splat(self.w.dims.outer_margin) } fn line_height(&self, _: TextClass) -> i32 { - self.dims.line_height + self.w.dims.line_height } fn text_bound( @@ -192,8 +205,11 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { axis: AxisInfo, ) -> SizeRules { let required = text.update_env(|env| { - env.set_dpp(self.dims.dpp); - env.set_pt_size(self.dims.pt_size); + if let Some(font_id) = self.w.fonts.get(&class).cloned() { + env.set_font_id(font_id); + } + env.set_dpp(self.w.dims.dpp); + env.set_pt_size(self.w.dims.pt_size); let mut bounds = kas::text::Vec2::INFINITY; if let Some(size) = axis.size_other_if_fixed(false) { @@ -209,11 +225,11 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { }); }); - let margin = self.dims.text_margin; + let margin = self.w.dims.text_margin; let margins = (margin, margin); if axis.is_horizontal() { let bound = i32::conv_ceil(required.0); - let min = self.dims.min_line_length; + let min = self.w.dims.min_line_length; let (min, ideal) = match class { TextClass::Edit => (min, 2 * min), TextClass::EditMulti => (min, 3 * min), @@ -232,9 +248,9 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { let min = match class { TextClass::Label => i32::conv_ceil(required.1), TextClass::LabelFixed | TextClass::Button | TextClass::Edit => { - self.dims.line_height + self.w.dims.line_height } - TextClass::EditMulti | TextClass::LabelScroll => self.dims.line_height * 3, + TextClass::EditMulti | TextClass::LabelScroll => self.w.dims.line_height * 3, }; let ideal = i32::conv_ceil(required.1).max(min); let stretch = match class { @@ -246,23 +262,23 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { } fn edit_marker_width(&self) -> f32 { - self.dims.font_marker_width + self.w.dims.font_marker_width } fn button_surround(&self, _vert: bool) -> FrameRules { - let inner = self.dims.inner_margin.into(); - let outer = self.dims.outer_margin; - FrameRules::new_sym(self.dims.frame, inner, outer) + let inner = self.w.dims.inner_margin.into(); + let outer = self.w.dims.outer_margin; + FrameRules::new_sym(self.w.dims.frame, inner, outer) } fn edit_surround(&self, _vert: bool) -> FrameRules { - let inner = self.dims.inner_margin.into(); + let inner = self.w.dims.inner_margin.into(); let outer = 0; - FrameRules::new_sym(self.dims.frame, inner, outer) + FrameRules::new_sym(self.w.dims.frame, inner, outer) } fn checkbox(&self) -> Size { - Size::splat(self.dims.checkbox) + Size::splat(self.w.dims.checkbox) } #[inline] @@ -271,17 +287,17 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { } fn scrollbar(&self) -> (Size, i32) { - let size = self.dims.scrollbar; + let size = self.w.dims.scrollbar; (size, 3 * size.0) } fn slider(&self) -> (Size, i32) { - let size = self.dims.slider; + let size = self.w.dims.slider; (size, 5 * size.0) } fn progress_bar(&self) -> Size { - self.dims.progress_bar + self.w.dims.progress_bar } fn load_image(&mut self, path: &Path) -> Result> { diff --git a/kas-theme/src/flat_theme.rs b/kas-theme/src/flat_theme.rs index 1d54809ac..bb987d98b 100644 --- a/kas-theme/src/flat_theme.rs +++ b/kas-theme/src/flat_theme.rs @@ -7,10 +7,12 @@ //! //! Widget size and appearance can be modified through themes. +use linear_map::LinearMap; use std::f32; use std::ops::Range; +use std::rc::Rc; -use crate::{ColorsLinear, Config, Dimensions, DimensionsParams, DimensionsWindow, Theme, Window}; +use crate::{ColorsLinear, Config, DimensionsParams, DimensionsWindow, Theme, Window}; use kas::cast::Cast; use kas::dir::{Direction, Directional}; use kas::draw::{ @@ -19,7 +21,7 @@ use kas::draw::{ }; use kas::geom::*; use kas::text::format::FormattableText; -use kas::text::{AccelString, Effect, Text, TextApi, TextDisplay}; +use kas::text::{fonts::FontId, AccelString, Effect, Text, TextApi, TextDisplay}; use kas::TkAction; // Used to ensure a rectangular background is inside a circular corner. @@ -31,6 +33,7 @@ const BG_SHRINK_FACTOR: f32 = 1.0 - std::f32::consts::FRAC_1_SQRT_2; pub struct FlatTheme { pub(crate) config: Config, pub(crate) cols: ColorsLinear, + pub(crate) fonts: Option>>, } impl FlatTheme { @@ -40,6 +43,7 @@ impl FlatTheme { FlatTheme { config: Default::default(), cols: ColorsLinear::default(), + fonts: None, } } @@ -116,11 +120,12 @@ where } fn new_window(&self, dpi_factor: f32) -> Self::Window { - DimensionsWindow::new(DIMS, self.config.font_size(), dpi_factor) + let fonts = self.fonts.as_ref().clone().unwrap().clone(); + DimensionsWindow::new(DIMS, self.config.font_size(), dpi_factor, fonts) } fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) { - window.dims = Dimensions::new(DIMS, self.config.font_size(), dpi_factor); + window.update(DIMS, self.config.font_size(), dpi_factor); } #[cfg(not(feature = "gat"))] diff --git a/kas-theme/src/shaded_theme.rs b/kas-theme/src/shaded_theme.rs index ce3bde02c..705ae5c70 100644 --- a/kas-theme/src/shaded_theme.rs +++ b/kas-theme/src/shaded_theme.rs @@ -8,9 +8,7 @@ use std::f32; use std::ops::Range; -use crate::{ - ColorsLinear, Config, Dimensions, DimensionsParams, DimensionsWindow, FlatTheme, Theme, Window, -}; +use crate::{ColorsLinear, Config, DimensionsParams, DimensionsWindow, FlatTheme, Theme, Window}; use kas::dir::{Direction, Directional}; use kas::draw::{ self, color::Rgba, Draw, DrawRounded, DrawShaded, DrawShared, ImageId, InputState, Pass, @@ -98,11 +96,12 @@ where } fn new_window(&self, dpi_factor: f32) -> Self::Window { - DimensionsWindow::new(DIMS, self.flat.config.font_size(), dpi_factor) + let fonts = self.flat.fonts.as_ref().clone().unwrap().clone(); + DimensionsWindow::new(DIMS, self.flat.config.font_size(), dpi_factor, fonts) } fn update_window(&self, window: &mut Self::Window, dpi_factor: f32) { - window.dims = Dimensions::new(DIMS, self.flat.config.font_size(), dpi_factor); + window.update(DIMS, self.flat.config.font_size(), dpi_factor); } #[cfg(not(feature = "gat"))] From c938e7802efdcb2740810acef8dad72c12f3fd8c Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 Jun 2021 09:05:02 +0100 Subject: [PATCH 4/5] Make fonts configurable; default to serif for edit boxes --- Cargo.toml | 2 +- example-config/theme.yaml | 7 +++++++ kas-theme/src/config.rs | 24 +++++++++++++++++++++++- kas-theme/src/flat_theme.rs | 11 +++++++++-- kas-wgpu/src/options.rs | 6 ++++-- src/draw/handle.rs | 1 + 6 files changed, 45 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e9d32a74f..331c8003b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -89,4 +89,4 @@ features = ["serde"] members = ["kas-macros", "kas-theme", "kas-wgpu"] [patch.crates-io] -kas-text = { git = "https://github.com/kas-gui/kas-text.git", rev = "58f07dee97fff805f84427185e1156d50f72796a" } +kas-text = { git = "https://github.com/kas-gui/kas-text.git", rev = "05b50366a0a2fe7d1e611d93acbb2d9f83c52f0a" } diff --git a/example-config/theme.yaml b/example-config/theme.yaml index 103b89510..9b4592153 100644 --- a/example-config/theme.yaml +++ b/example-config/theme.yaml @@ -43,3 +43,10 @@ font_aliases: Calibri: mode: Append list: [Carlito] +fonts: + Edit: + families: + - serif + EditMulti: + families: + - serif diff --git a/kas-theme/src/config.rs b/kas-theme/src/config.rs index 36b3ba2c3..1f0d69ab7 100644 --- a/kas-theme/src/config.rs +++ b/kas-theme/src/config.rs @@ -6,7 +6,8 @@ //! Theme configuration use crate::{ColorsLinear, ColorsSrgb, ThemeConfig}; -use kas::text::fonts::{fonts, AddMode}; +use kas::draw::TextClass; +use kas::text::fonts::{fonts, AddMode, FontSelector}; use kas::TkAction; use std::collections::BTreeMap; @@ -34,6 +35,10 @@ pub struct Config { /// Font aliases, used when searching for a font family matching the key. #[cfg_attr(feature = "config", serde(default))] font_aliases: BTreeMap, + + /// Standard fonts + #[cfg_attr(feature = "config", serde(default))] + fonts: BTreeMap>, } impl Default for Config { @@ -44,6 +49,7 @@ impl Default for Config { active_scheme: Default::default(), color_schemes: defaults::color_schemes(), font_aliases: Default::default(), + fonts: defaults::fonts(), } } } @@ -85,6 +91,12 @@ impl Config { pub fn get_active_scheme(&self) -> Option { self.color_schemes.get(&self.active_scheme).cloned() } + + /// Get an iterator over font mappings + #[inline] + pub fn iter_fonts(&self) -> impl Iterator)> { + self.fonts.iter() + } } /// Setters @@ -163,4 +175,14 @@ mod defaults { schemes.insert("dark".to_string(), ColorsLinear::dark().into()); schemes } + + pub fn fonts() -> BTreeMap> { + let mut selector = FontSelector::new(); + selector.set_families(vec!["serif".into()]); + let list = [ + (TextClass::Edit, selector.clone()), + (TextClass::EditMulti, selector), + ]; + list.iter().cloned().collect() + } } diff --git a/kas-theme/src/flat_theme.rs b/kas-theme/src/flat_theme.rs index bb987d98b..7f3cd7aea 100644 --- a/kas-theme/src/flat_theme.rs +++ b/kas-theme/src/flat_theme.rs @@ -21,7 +21,7 @@ use kas::draw::{ }; use kas::geom::*; use kas::text::format::FormattableText; -use kas::text::{fonts::FontId, AccelString, Effect, Text, TextApi, TextDisplay}; +use kas::text::{fonts, AccelString, Effect, Text, TextApi, TextDisplay}; use kas::TkAction; // Used to ensure a rectangular background is inside a circular corner. @@ -33,7 +33,7 @@ const BG_SHRINK_FACTOR: f32 = 1.0 - std::f32::consts::FRAC_1_SQRT_2; pub struct FlatTheme { pub(crate) config: Config, pub(crate) cols: ColorsLinear, - pub(crate) fonts: Option>>, + pub(crate) fonts: Option>>, } impl FlatTheme { @@ -117,6 +117,13 @@ where if let Err(e) = kas::text::fonts::fonts().select_default() { panic!("Error loading font: {}", e); } + let fonts = fonts::fonts(); + self.fonts = Some(Rc::new( + self.config + .iter_fonts() + .filter_map(|(c, s)| fonts.select_font(&s).ok().map(|id| (*c, id))) + .collect(), + )); } fn new_window(&self, dpi_factor: f32) -> Self::Window { diff --git a/kas-wgpu/src/options.rs b/kas-wgpu/src/options.rs index cf341a5e6..4286a84e2 100644 --- a/kas-wgpu/src/options.rs +++ b/kas-wgpu/src/options.rs @@ -183,12 +183,15 @@ impl Options { if !self.theme_config_path.as_os_str().is_empty() { match self.config_mode { ConfigMode::Read | ConfigMode::ReadWrite => { - let config = kas::config::Format::guess_and_read_path(&self.theme_config_path)?; + let config: T::Config = + kas::config::Format::guess_and_read_path(&self.theme_config_path)?; + config.apply_startup(); // Ignore TkAction: UI isn't built yet let _ = theme.apply_config(&config); } ConfigMode::WriteDefault => { let config = theme.config(); + config.apply_startup(); kas::config::Format::guess_and_write_path( &self.theme_config_path, config.as_ref(), @@ -196,7 +199,6 @@ impl Options { } } } - theme.config().apply_startup(); Ok(()) } diff --git a/src/draw/handle.rs b/src/draw/handle.rs index 0f00cf44f..5f07e5537 100644 --- a/src/draw/handle.rs +++ b/src/draw/handle.rs @@ -69,6 +69,7 @@ impl std::ops::BitOr for InputState { /// /// Themes choose font, font size, colour, and alignment based on this. #[derive(Copy, Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TextClass { /// Label text is drawn over the background colour Label, From c6ec5ec41131cd60e17083ee22e641f6fc17b34c Mon Sep 17 00:00:00 2001 From: Diggory Hardy Date: Wed, 9 Jun 2021 09:18:54 +0100 Subject: [PATCH 5/5] Add TextClass::MenuLabel --- example-config/theme.yaml | 4 ++++ kas-theme/src/colors.rs | 2 +- kas-theme/src/dim.rs | 4 ++-- src/draw/handle.rs | 4 ++-- src/widget/menu/menu_entry.rs | 10 ++++++++-- src/widget/menu/submenu.rs | 9 +++++++-- 6 files changed, 24 insertions(+), 9 deletions(-) diff --git a/example-config/theme.yaml b/example-config/theme.yaml index 9b4592153..f1075e918 100644 --- a/example-config/theme.yaml +++ b/example-config/theme.yaml @@ -50,3 +50,7 @@ fonts: EditMulti: families: - serif + MenuLabel: + families: + - sans-serif + weight: 600 diff --git a/kas-theme/src/colors.rs b/kas-theme/src/colors.rs index 1ba7967db..7195e8e94 100644 --- a/kas-theme/src/colors.rs +++ b/kas-theme/src/colors.rs @@ -253,7 +253,7 @@ impl ColorsLinear { /// Get text colour from class pub fn text_class(&self, class: TextClass) -> Rgba { match class { - TextClass::Label | TextClass::LabelFixed | TextClass::LabelScroll => self.label_text, + TextClass::Label | TextClass::MenuLabel | TextClass::LabelScroll => self.label_text, TextClass::Button => self.button_text, TextClass::Edit | TextClass::EditMulti => self.text, } diff --git a/kas-theme/src/dim.rs b/kas-theme/src/dim.rs index a52879531..7930cc9bb 100644 --- a/kas-theme/src/dim.rs +++ b/kas-theme/src/dim.rs @@ -239,7 +239,7 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { // cause problems (e.g. edit boxes greedily consuming too much // space). This is a hard layout problem; for now don't do this. let stretch = match class { - TextClass::LabelFixed => Stretch::None, + TextClass::MenuLabel => Stretch::None, TextClass::Button => Stretch::Filler, _ => Stretch::Low, }; @@ -247,7 +247,7 @@ impl<'a, D: DrawShared> draw::SizeHandle for SizeHandle<'a, D> { } else { let min = match class { TextClass::Label => i32::conv_ceil(required.1), - TextClass::LabelFixed | TextClass::Button | TextClass::Edit => { + TextClass::MenuLabel | TextClass::Button | TextClass::Edit => { self.w.dims.line_height } TextClass::EditMulti | TextClass::LabelScroll => self.w.dims.line_height * 3, diff --git a/src/draw/handle.rs b/src/draw/handle.rs index 5f07e5537..f06ebdda7 100644 --- a/src/draw/handle.rs +++ b/src/draw/handle.rs @@ -73,8 +73,6 @@ impl std::ops::BitOr for InputState { pub enum TextClass { /// Label text is drawn over the background colour Label, - /// Single-line label with fixed size (does not stretch to fill space) - LabelFixed, /// Scrollable label (same as label except that min height is limited) LabelScroll, /// Button text is drawn over a button @@ -83,6 +81,8 @@ pub enum TextClass { Edit, /// Class of text drawn in a multi-line edit box EditMulti, + /// Menu label (single line, does not stretch) + MenuLabel, } impl TextClass { diff --git a/src/widget/menu/menu_entry.rs b/src/widget/menu/menu_entry.rs index 3b8fe7e8d..a6cfc3219 100644 --- a/src/widget/menu/menu_entry.rs +++ b/src/widget/menu/menu_entry.rs @@ -41,7 +41,7 @@ impl WidgetConfig for MenuEntry { impl Layout for MenuEntry { fn size_rules(&mut self, size_handle: &mut dyn SizeHandle, axis: AxisInfo) -> SizeRules { let frame_rules = size_handle.menu_frame(axis.is_vertical()); - let text_rules = size_handle.text_bound(&mut self.label, TextClass::LabelFixed, axis); + let text_rules = size_handle.text_bound(&mut self.label, TextClass::MenuLabel, axis); let (rules, offset, size) = frame_rules.surround(text_rules); self.label_off.set_component(axis, offset); self.frame_size.set_component(axis, size); @@ -60,7 +60,12 @@ impl Layout for MenuEntry { fn draw(&self, draw_handle: &mut dyn DrawHandle, mgr: &ManagerState, disabled: bool) { draw_handle.menu_entry(self.core.rect, self.input_state(mgr, disabled)); let pos = self.core.rect.pos + self.label_off; - draw_handle.text_accel(pos, &self.label, mgr.show_accel_labels(), TextClass::Label); + draw_handle.text_accel( + pos, + &self.label, + mgr.show_accel_labels(), + TextClass::MenuLabel, + ); } } @@ -128,6 +133,7 @@ pub struct MenuToggle { layout_data: ::Data, #[widget] checkbox: CheckBoxBare, + // TODO: label should use TextClass::MenuLabel #[widget] label: AccelLabel, } diff --git a/src/widget/menu/submenu.rs b/src/widget/menu/submenu.rs index 91941b027..fc9ebde6e 100644 --- a/src/widget/menu/submenu.rs +++ b/src/widget/menu/submenu.rs @@ -108,7 +108,7 @@ impl WidgetConfig for SubMenu { impl kas::Layout for SubMenu { fn size_rules(&mut self, size_handle: &mut dyn SizeHandle, axis: AxisInfo) -> SizeRules { let frame_rules = size_handle.menu_frame(axis.is_vertical()); - let text_rules = size_handle.text_bound(&mut self.label, TextClass::LabelFixed, axis); + let text_rules = size_handle.text_bound(&mut self.label, TextClass::MenuLabel, axis); let (rules, offset, size) = frame_rules.surround(text_rules); self.label_off.set_component(axis, offset); self.frame_size.set_component(axis, size); @@ -134,7 +134,12 @@ impl kas::Layout for SubMenu { state.depress = state.depress || self.popup_id.is_some(); draw_handle.menu_entry(self.core.rect, state); let pos = self.core.rect.pos + self.label_off; - draw_handle.text_accel(pos, &self.label, mgr.show_accel_labels(), TextClass::Label); + draw_handle.text_accel( + pos, + &self.label, + mgr.show_accel_labels(), + TextClass::MenuLabel, + ); } }