Skip to content

Commit

Permalink
Merge pull request #200 from kas-gui/work
Browse files Browse the repository at this point in the history
Make fonts configurable per text class
  • Loading branch information
dhardy authored Jun 9, 2021
2 parents ddce69f + c6ec5ec commit e0c9277
Show file tree
Hide file tree
Showing 17 changed files with 164 additions and 107 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "05b50366a0a2fe7d1e611d93acbb2d9f83c52f0a" }
11 changes: 11 additions & 0 deletions example-config/theme.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,14 @@ font_aliases:
Calibri:
mode: Append
list: [Carlito]
fonts:
Edit:
families:
- serif
EditMulti:
families:
- serif
MenuLabel:
families:
- sans-serif
weight: 600
1 change: 1 addition & 0 deletions kas-theme/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
2 changes: 1 addition & 1 deletion kas-theme/src/colors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
24 changes: 23 additions & 1 deletion kas-theme/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<String, FontAliases>,

/// Standard fonts
#[cfg_attr(feature = "config", serde(default))]
fonts: BTreeMap<TextClass, FontSelector<'static>>,
}

impl Default for Config {
Expand All @@ -44,6 +49,7 @@ impl Default for Config {
active_scheme: Default::default(),
color_schemes: defaults::color_schemes(),
font_aliases: Default::default(),
fonts: defaults::fonts(),
}
}
}
Expand Down Expand Up @@ -85,6 +91,12 @@ impl Config {
pub fn get_active_scheme(&self) -> Option<ColorsSrgb> {
self.color_schemes.get(&self.active_scheme).cloned()
}

/// Get an iterator over font mappings
#[inline]
pub fn iter_fonts(&self) -> impl Iterator<Item = (&TextClass, &FontSelector<'static>)> {
self.fonts.iter()
}
}

/// Setters
Expand Down Expand Up @@ -163,4 +175,14 @@ mod defaults {
schemes.insert("dark".to_string(), ColorsLinear::dark().into());
schemes
}

pub fn fonts() -> BTreeMap<TextClass, FontSelector<'static>> {
let mut selector = FontSelector::new();
selector.set_families(vec!["serif".into()]);
let list = [
(TextClass::Edit, selector.clone()),
(TextClass::EditMulti, selector),
];
list.iter().cloned().collect()
}
}
86 changes: 51 additions & 35 deletions kas-theme/src/dim.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`]
///
Expand Down Expand Up @@ -99,14 +101,25 @@ impl Dimensions {
/// A convenient implementation of [`crate::Window`]
pub struct DimensionsWindow {
pub dims: Dimensions,
pub fonts: Rc<LinearMap<TextClass, FontId>>,
}

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<LinearMap<TextClass, FontId>>,
) -> 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<D: DrawShared> crate::Window<D> for DimensionsWindow {
Expand All @@ -118,12 +131,12 @@ impl<D: DrawShared> crate::Window<D> 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 {
Expand All @@ -132,57 +145,57 @@ impl<D: DrawShared> crate::Window<D> 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(
Expand All @@ -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) {
Expand All @@ -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),
Expand All @@ -223,18 +239,18 @@ 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,
};
SizeRules::new(min, ideal, margins, stretch)
} else {
let min = match class {
TextClass::Label => i32::conv_ceil(required.1),
TextClass::LabelFixed | TextClass::Button | TextClass::Edit => {
self.dims.line_height
TextClass::MenuLabel | TextClass::Button | TextClass::Edit => {
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 {
Expand All @@ -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]
Expand All @@ -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<ImageId, Box<dyn std::error::Error + 'static>> {
Expand Down
26 changes: 19 additions & 7 deletions kas-theme/src/flat_theme.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand All @@ -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, AccelString, Effect, Text, TextApi, TextDisplay};
use kas::TkAction;

// Used to ensure a rectangular background is inside a circular corner.
Expand All @@ -29,8 +31,9 @@ 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,
pub(crate) fonts: Option<Rc<LinearMap<TextClass, fonts::FontId>>>,
}

impl FlatTheme {
Expand All @@ -40,6 +43,7 @@ impl FlatTheme {
FlatTheme {
config: Default::default(),
cols: ColorsLinear::default(),
fonts: None,
}
}

Expand Down Expand Up @@ -113,14 +117,22 @@ 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, _draw: &mut D::Draw, dpi_factor: f32) -> Self::Window {
DimensionsWindow::new(DIMS, self.config.font_size(), dpi_factor)
fn new_window(&self, dpi_factor: f32) -> Self::Window {
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"))]
Expand Down
Loading

0 comments on commit e0c9277

Please sign in to comment.