From d90074045fce5bab3d4ab7e4745f14607ae9bc49 Mon Sep 17 00:00:00 2001 From: Michael Aaron Murphy Date: Sat, 5 Oct 2024 00:03:02 +0200 Subject: [PATCH] feat(appearance): add font configuration settings --- Cargo.lock | 118 +++--- Cargo.toml | 3 + cosmic-settings/Cargo.toml | 2 + .../pages/desktop/appearance/font_config.rs | 368 ++++++++++++++++++ .../{appearance.rs => appearance/mod.rs} | 95 +++-- .../src/pages/desktop/wallpaper/mod.rs | 2 +- .../src/pages/display/arrangement.rs | 2 +- i18n/en/cosmic_settings.ftl | 28 ++ 8 files changed, 525 insertions(+), 93 deletions(-) create mode 100644 cosmic-settings/src/pages/desktop/appearance/font_config.rs rename cosmic-settings/src/pages/desktop/{appearance.rs => appearance/mod.rs} (97%) diff --git a/Cargo.lock b/Cargo.lock index 9af2ce5..a576a23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1001,9 +1001,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.23" +version = "1.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bbb537bb4a30b90362caddba8f360c0a56bc13d3a5570028e7197204cb54a17" +checksum = "812acba72f0a070b003d3697490d2b55b837230ae7c6c6497f05cc2ddbb8d938" dependencies = [ "jobserver", "libc", @@ -1092,9 +1092,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3" +checksum = "7be5744db7978a28d9df86a214130d106a89ce49644cbc4e3f0c22c3fba30615" dependencies = [ "clap_builder", "clap_derive", @@ -1102,9 +1102,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.18" +version = "4.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b" +checksum = "a5fbc17d3ef8278f55b282b2a2e75ae6f6c7d4bb70ed3d0382375104bfafdb4b" dependencies = [ "anstream", "anstyle", @@ -1447,7 +1447,7 @@ dependencies = [ [[package]] name = "cosmic-comp-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-comp#afdb65677857946b403043f04ca083810639e4e5" +source = "git+https://github.com/pop-os/cosmic-comp#a96394f7a6fd1d96289e319650e3f17b873cbfb0" dependencies = [ "cosmic-config", "input", @@ -1457,7 +1457,7 @@ dependencies = [ [[package]] name = "cosmic-config" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "atomicwrites", "cosmic-config-derive", @@ -1479,7 +1479,7 @@ dependencies = [ [[package]] name = "cosmic-config-derive" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "quote", "syn 1.0.109", @@ -1535,7 +1535,7 @@ source = "git+https://github.com/pop-os/cosmic-randr#71fabbb382fa8cf750f50fb77c4 dependencies = [ "cosmic-protocols", "futures-lite 2.3.0", - "indexmap 2.5.0", + "indexmap 2.6.0", "tachyonix", "thiserror", "tokio", @@ -1584,6 +1584,7 @@ dependencies = [ "dirs", "downcast-rs", "eyre", + "fontdb", "freedesktop-desktop-entry", "futures", "hostname-validator", @@ -1592,7 +1593,7 @@ dependencies = [ "i18n-embed-fl", "icu", "image 0.25.2", - "indexmap 2.5.0", + "indexmap 2.6.0", "itertools 0.13.0", "itoa", "libcosmic", @@ -1615,6 +1616,7 @@ dependencies = [ "udev", "upower_dbus", "url", + "ustr", "xkb-data", "zbus 4.4.0", ] @@ -1732,7 +1734,7 @@ dependencies = [ [[package]] name = "cosmic-theme" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "almost", "cosmic-config", @@ -2916,6 +2918,12 @@ dependencies = [ "allocator-api2", ] +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" + [[package]] name = "hassle-rs" version = "0.11.0" @@ -3077,7 +3085,7 @@ dependencies = [ [[package]] name = "iced" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "dnd", "iced_accessibility", @@ -3096,7 +3104,7 @@ dependencies = [ [[package]] name = "iced_accessibility" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "accesskit", "accesskit_unix", @@ -3105,7 +3113,7 @@ dependencies = [ [[package]] name = "iced_core" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "bitflags 2.6.0", "dnd", @@ -3127,7 +3135,7 @@ dependencies = [ [[package]] name = "iced_futures" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "futures", "iced_core", @@ -3140,7 +3148,7 @@ dependencies = [ [[package]] name = "iced_graphics" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "bitflags 2.6.0", "bytemuck", @@ -3164,7 +3172,7 @@ dependencies = [ [[package]] name = "iced_renderer" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "iced_graphics", "iced_tiny_skia", @@ -3176,7 +3184,7 @@ dependencies = [ [[package]] name = "iced_runtime" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "dnd", "iced_accessibility", @@ -3190,7 +3198,7 @@ dependencies = [ [[package]] name = "iced_sctk" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "enum-repr", "float-cmp", @@ -3216,7 +3224,7 @@ dependencies = [ [[package]] name = "iced_style" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "iced_core", "once_cell", @@ -3226,7 +3234,7 @@ dependencies = [ [[package]] name = "iced_tiny_skia" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "bytemuck", "cosmic-text", @@ -3243,7 +3251,7 @@ dependencies = [ [[package]] name = "iced_wgpu" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "as-raw-xcb-connection", "bitflags 2.6.0", @@ -3272,7 +3280,7 @@ dependencies = [ [[package]] name = "iced_widget" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "dnd", "iced_renderer", @@ -3289,7 +3297,7 @@ dependencies = [ [[package]] name = "iced_winit" version = "0.12.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "dnd", "iced_graphics", @@ -3807,12 +3815,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -4101,7 +4109,7 @@ checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" [[package]] name = "libcosmic" version = "0.1.0" -source = "git+https://github.com/pop-os/libcosmic#228eb4d70d581be88bacb1e261106a58603d847b" +source = "git+https://github.com/pop-os/libcosmic#173a9557c2f03bc5fda132e884c11bf8661256ff" dependencies = [ "apply", "ashpd 0.9.1", @@ -4136,6 +4144,7 @@ dependencies = [ "tracing", "unicode-segmentation", "url", + "ustr", "zbus 4.4.0", ] @@ -4167,7 +4176,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4579,7 +4588,7 @@ dependencies = [ "bitflags 2.6.0", "codespan-reporting", "hexf-parse", - "indexmap 2.5.0", + "indexmap 2.6.0", "log", "num-traits", "rustc-hash", @@ -4842,7 +4851,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.79", @@ -6030,7 +6039,7 @@ version = "1.0.128" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "itoa", "memchr", "ryu", @@ -6059,15 +6068,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "9720086b3357bcb44fce40117d769a4d068c70ecfa190850a980a71755f66fcc" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -6077,9 +6086,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "5f1abbfe725f27678f4663bcacb75a83e829fd464c25d78dd038a3a29e307cec" dependencies = [ "darling 0.20.10", "proc-macro2", @@ -6560,9 +6569,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "temp-dir" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f227968ec00f0e5322f9b8173c7a0cbcff6181a0a5b28e9892491c286277231" +checksum = "bc1ee6eef34f12f765cb94725905c6312b6610ab2b0940889cfe58dae7bc3c72" [[package]] name = "tempfile" @@ -6821,7 +6830,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "toml_datetime", "winnow 0.5.40", ] @@ -6832,7 +6841,7 @@ version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_spanned", "toml_datetime", @@ -6987,9 +6996,9 @@ dependencies = [ [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-bidi-mirroring" @@ -7038,9 +7047,9 @@ dependencies = [ [[package]] name = "unicode-properties" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ea75f83c0137a9b98608359a5f1af8144876eb67bcb1ce837368e906a9f524" +checksum = "e70f2a8b45122e719eb623c01822704c4e0907e7e426a05927e1a1cfff5b75d0" [[package]] name = "unicode-script" @@ -7100,6 +7109,19 @@ version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "daf8dba3b7eb870caf1ddeed7bc9d2a049f3cfdfae7cb521b087cc33ae4c49da" +[[package]] +name = "ustr" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e904a2279a4a36d2356425bb20be271029cc650c335bc82af8bfae30085a3d0" +dependencies = [ + "ahash 0.8.11", + "byteorder", + "lazy_static", + "parking_lot 0.12.3", + "serde", +] + [[package]] name = "usvg" version = "0.37.0" @@ -7534,7 +7556,7 @@ dependencies = [ "bitflags 2.6.0", "cfg_aliases 0.1.1", "codespan-reporting", - "indexmap 2.5.0", + "indexmap 2.6.0", "log", "naga", "once_cell", @@ -7630,7 +7652,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index ad13278..52621fa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,6 +55,9 @@ cosmic-protocols = { git = "https://github.com/pop-os/cosmic-protocols//", rev = # For development and testing purposes # [patch.'https://github.com/pop-os/libcosmic'] +# libcosmic = { git = "https://github.com/pop-os/libcosmic//", branch = "fontconfig" } +# cosmic-config = { git = "https://github.com/pop-os/libcosmic//", branch = "fontconfig" } +# cosmic-theme = { git = "https://github.com/pop-os/libcosmic//", branch = "fontconfig" } # libcosmic = { path = "../libcosmic" } # cosmic-config = { path = "../libcosmic/cosmic-config" } # cosmic-theme = { path = "../libcosmic/cosmic-theme" } diff --git a/cosmic-settings/Cargo.toml b/cosmic-settings/Cargo.toml index cc6be68..3af60d5 100644 --- a/cosmic-settings/Cargo.toml +++ b/cosmic-settings/Cargo.toml @@ -60,6 +60,8 @@ bluez-zbus = { git = "https://github.com/pop-os/dbus-settings-bindings" } url = "2.5.2" xkb-data = "0.2.1" zbus = { version = "4.4.0", features = ["tokio"] } +ustr = "1.0.0" +fontdb = "0.16.2" [dependencies.cosmic-settings-subscriptions] git = "https://github.com/pop-os/cosmic-settings-subscriptions" diff --git a/cosmic-settings/src/pages/desktop/appearance/font_config.rs b/cosmic-settings/src/pages/desktop/appearance/font_config.rs new file mode 100644 index 0000000..dc1be53 --- /dev/null +++ b/cosmic-settings/src/pages/desktop/appearance/font_config.rs @@ -0,0 +1,368 @@ +use cosmic::{ + config::{CosmicTk, FontConfig}, + widget::{self, settings}, + Apply, Command, Element, +}; +use cosmic_config::ConfigSet; +use cosmic_settings_page::Section; +use ustr::Ustr; + +const INTERFACE_FONT: &str = "interface_font"; +const MONOSPACE_FONT: &str = "monospace_font"; + +pub fn section() -> Section { + crate::slab!(descriptions { + font_family_txt = fl!("font-family"); + font_weight_txt = fl!("font-weight"); + font_stretch_txt = fl!("font-stretch"); + font_style_txt = fl!("font-style"); + interface_font_txt = fl!("interface-font"); + monospace_font_txt = fl!("monospace-font"); + }); + + Section::default() + .title(fl!("font-config")) + .descriptions(descriptions) + .view::(move |_binder, page, section| { + let descriptions = §ion.descriptions; + + let interface_font_family = settings::item::builder(&descriptions[font_family_txt]) + .control(widget::dropdown( + &page.font_config.interface_font_families, + page.font_config.interface_font_family, + |id| super::Message::FontConfig(Message::InterfaceFontFamily(id)), + )); + + let interface_font_weight = settings::item::builder(&descriptions[font_weight_txt]) + .control(widget::dropdown( + &page.font_config.font_weights, + page.font_config.interface_font_weight, + |id| super::Message::FontConfig(Message::InterfaceFontWeight(id)), + )); + + let interface_font_stretch = settings::item::builder(&descriptions[font_stretch_txt]) + .control(widget::dropdown( + &page.font_config.font_stretches, + page.font_config.interface_font_stretch, + |id| super::Message::FontConfig(Message::InterfaceFontStretch(id)), + )); + + let interface_font_style = settings::item::builder(&descriptions[font_style_txt]) + .control(widget::dropdown( + &page.font_config.font_styles, + page.font_config.interface_font_style, + |id| super::Message::FontConfig(Message::InterfaceFontStyle(id)), + )); + + let monospace_font_family = settings::item::builder(&descriptions[font_family_txt]) + .control(widget::dropdown( + &page.font_config.monospace_font_families, + page.font_config.monospace_font_family, + |id| super::Message::FontConfig(Message::MonospaceFontFamily(id)), + )); + + let monospace_font_weight = settings::item::builder(&descriptions[font_weight_txt]) + .control(widget::dropdown( + &page.font_config.font_weights, + page.font_config.monospace_font_weight, + |id| super::Message::FontConfig(Message::MonospaceFontWeight(id)), + )); + + let interface_font = settings::section() + .title(&descriptions[interface_font_txt]) + .add(interface_font_family) + .add(interface_font_weight) + .add(interface_font_stretch) + .add(interface_font_style); + + let monospace_font = settings::section() + .title(&descriptions[monospace_font_txt]) + .add(monospace_font_family) + .add(monospace_font_weight); + + widget::column::with_capacity(2) + .push(interface_font) + .push(monospace_font) + .spacing(8) + .apply(Element::from) + .map(crate::pages::Message::Appearance) + }) +} + +#[derive(Debug, Clone)] +pub enum Message { + InterfaceFontFamily(usize), + InterfaceFontStretch(usize), + InterfaceFontStyle(usize), + InterfaceFontWeight(usize), + LoadedFonts(Vec, Vec), + MonospaceFontFamily(usize), + MonospaceFontWeight(usize), +} + +#[derive(Debug, Default)] +pub struct Model { + pub font_weights: Vec, + pub font_stretches: Vec, + pub font_styles: Vec, + pub interface_font_families: Vec, + pub interface_font_family: Option, + pub interface_font_weight: Option, + pub interface_font_stretch: Option, + pub interface_font_style: Option, + pub monospace_font_families: Vec, + pub monospace_font_family: Option, + pub monospace_font_weight: Option, +} + +impl Model { + pub fn new() -> Model { + Model { + font_weights: vec![ + fl!("font-weight", "thin"), + fl!("font-weight", "extra-light"), + fl!("font-weight", "light"), + fl!("font-weight", "normal"), + fl!("font-weight", "medium"), + fl!("font-weight", "semibold"), + fl!("font-weight", "bold"), + fl!("font-weight", "extra-bold"), + fl!("font-weight", "black"), + ], + + font_stretches: vec![ + fl!("font-stretch", "condensed"), + fl!("font-stretch", "normal"), + fl!("font-stretch", "expanded"), + ], + + font_styles: vec![ + fl!("font-style", "normal"), + fl!("font-style", "italic"), + fl!("font-style", "oblique"), + ], + + interface_font_families: Vec::new(), + interface_font_family: None, + interface_font_stretch: None, + interface_font_style: None, + interface_font_weight: None, + monospace_font_families: Vec::new(), + monospace_font_family: None, + monospace_font_weight: None, + } + } + + pub fn update(&mut self, message: Message) -> Command { + match message { + Message::InterfaceFontFamily(id) => { + if let Some(family) = self.interface_font_families.get(id) { + update_config( + INTERFACE_FONT, + FontConfig { + family: Ustr::from(family), + ..cosmic::config::interface_font() + }, + ); + + self.interface_font_family = Some(id); + } + } + + Message::InterfaceFontStretch(id) => { + update_config( + INTERFACE_FONT, + FontConfig { + stretch: font_stretch_by_id(id), + ..cosmic::config::interface_font() + }, + ); + + self.interface_font_stretch = Some(id); + } + + Message::InterfaceFontStyle(id) => { + update_config( + INTERFACE_FONT, + FontConfig { + style: font_style_by_id(id), + ..cosmic::config::interface_font() + }, + ); + + self.interface_font_style = Some(id); + } + + Message::InterfaceFontWeight(id) => { + update_config( + INTERFACE_FONT, + FontConfig { + weight: font_weight_by_id(id), + ..cosmic::config::interface_font() + }, + ); + + self.interface_font_weight = Some(id); + } + + Message::LoadedFonts(interface, mono) => { + self.interface_font_families = interface; + self.monospace_font_families = mono; + + let interface_font = cosmic::config::interface_font(); + let monospace_font = cosmic::config::monospace_font(); + + self.interface_font_stretch = font_stretch_to_pos(interface_font.stretch); + self.interface_font_style = font_style_to_pos(interface_font.style); + self.interface_font_weight = font_weight_to_pos(interface_font.weight); + self.interface_font_family = + font_family_to_pos(&self.interface_font_families, &interface_font.family); + + self.monospace_font_weight = font_weight_to_pos(monospace_font.weight); + self.monospace_font_family = + font_family_to_pos(&self.monospace_font_families, &monospace_font.family); + } + + Message::MonospaceFontFamily(id) => { + if let Some(family) = self.monospace_font_families.get(id) { + update_config( + MONOSPACE_FONT, + FontConfig { + family: Ustr::from(family), + ..cosmic::config::monospace_font() + }, + ); + + self.monospace_font_family = Some(id); + } + } + + Message::MonospaceFontWeight(id) => { + update_config( + MONOSPACE_FONT, + FontConfig { + weight: font_weight_by_id(id), + ..cosmic::config::monospace_font() + }, + ); + + self.monospace_font_weight = Some(id); + } + } + + Command::none() + } +} + +fn font_family_to_pos(families: &[String], family: &str) -> Option { + families.iter().position(|f| f.as_str() == family) +} + +fn font_weight_by_id(id: usize) -> cosmic::iced::font::Weight { + match id { + 0 => cosmic::iced::font::Weight::Thin, + 1 => cosmic::iced::font::Weight::ExtraLight, + 2 => cosmic::iced::font::Weight::Light, + 3 => cosmic::iced::font::Weight::Normal, + 4 => cosmic::iced::font::Weight::Medium, + 5 => cosmic::iced::font::Weight::Semibold, + 6 => cosmic::iced::font::Weight::Bold, + 7 => cosmic::iced::font::Weight::ExtraBold, + 8 => cosmic::iced::font::Weight::Black, + _ => cosmic::iced::font::Weight::Normal, + } +} +fn font_weight_to_pos(weight: cosmic::iced::font::Weight) -> Option { + match weight { + cosmic::iced::font::Weight::Thin => Some(0), + cosmic::iced::font::Weight::Light => Some(1), + cosmic::iced::font::Weight::ExtraLight => Some(2), + cosmic::iced::font::Weight::Normal => Some(3), + cosmic::iced::font::Weight::Medium => Some(4), + cosmic::iced::font::Weight::Semibold => Some(5), + cosmic::iced::font::Weight::Bold => Some(6), + cosmic::iced::font::Weight::ExtraBold => Some(7), + cosmic::iced::font::Weight::Black => Some(8), + } +} + +fn font_stretch_by_id(id: usize) -> cosmic::iced::font::Stretch { + match id { + 0 => cosmic::iced::font::Stretch::Condensed, + 1 => cosmic::iced::font::Stretch::Normal, + 2 => cosmic::iced::font::Stretch::Expanded, + _ => cosmic::iced::font::Stretch::Normal, + } +} + +fn font_stretch_to_pos(stretch: cosmic::iced::font::Stretch) -> Option { + match stretch { + cosmic::iced::font::Stretch::Condensed => Some(0), + cosmic::iced::font::Stretch::Normal => Some(1), + cosmic::iced::font::Stretch::Expanded => Some(2), + _ => None, + } +} + +fn font_style_by_id(id: usize) -> cosmic::iced::font::Style { + match id { + 0 => cosmic::iced::font::Style::Normal, + 1 => cosmic::iced::font::Style::Italic, + 2 => cosmic::iced::font::Style::Oblique, + _ => cosmic::iced::font::Style::Normal, + } +} + +fn font_style_to_pos(style: cosmic::iced::font::Style) -> Option { + match style { + cosmic::iced::font::Style::Normal => Some(0), + cosmic::iced::font::Style::Italic => Some(1), + cosmic::iced::font::Style::Oblique => Some(2), + } +} + +fn update_config(variant: &str, font: FontConfig) { + if let Ok(config) = CosmicTk::config() { + _ = config.set(variant, font); + } +} + +pub fn load_font_families() -> (Vec, Vec) { + let mut font_system = cosmic::iced::advanced::graphics::text::font_system() + .write() + .unwrap(); + + let (mut interface, mut mono) = font_system.raw().db().faces().fold( + (Vec::new(), Vec::new()), + |(mut interface, mut mono), face| { + if face.stretch != fontdb::Stretch::Normal + || face.weight != fontdb::Weight::NORMAL + || face.style != fontdb::Style::Normal + { + return (interface, mono); + } + + let font_name = match face.families.first() { + Some(name) => &name.0, + None => return (interface, mono), + }; + + if face.monospaced { + if mono.last().map_or(true, |name| name != font_name) { + mono.push(font_name.clone()); + } + } else if interface.last().map_or(true, |name| name != font_name) { + interface.push(font_name.clone()); + } + + (interface, mono) + }, + ); + + interface.sort_unstable(); + interface.dedup(); + mono.sort_unstable(); + mono.dedup(); + + (interface, mono) +} diff --git a/cosmic-settings/src/pages/desktop/appearance.rs b/cosmic-settings/src/pages/desktop/appearance/mod.rs similarity index 97% rename from cosmic-settings/src/pages/desktop/appearance.rs rename to cosmic-settings/src/pages/desktop/appearance/mod.rs index beb885e..95db7e6 100644 --- a/cosmic-settings/src/pages/desktop/appearance.rs +++ b/cosmic-settings/src/pages/desktop/appearance/mod.rs @@ -1,6 +1,8 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only +pub mod font_config; + use std::borrow::Cow; use std::collections::BTreeMap; use std::path::PathBuf; @@ -85,12 +87,13 @@ pub struct Page { interface_text: ColorPickerModel, control_component: ColorPickerModel, roundness: Roundness, - density: Density, icon_theme_active: Option, icon_themes: IconThemes, icon_handles: IconHandles, + font_config: font_config::Model, + theme: Theme, theme_mode: ThemeMode, theme_mode_config: Option, @@ -99,7 +102,6 @@ pub struct Page { auto_switch_descs: [Cow<'static, str>; 4], - tk: CosmicTk, tk_config: Option, day_time: bool, @@ -132,17 +134,15 @@ impl Option, ThemeBuilder, Option, - CosmicTk, )> for Page { fn from( - (theme_mode_config, theme_mode, theme_builder_config, theme_builder, tk_config, tk): ( + (theme_mode_config, theme_mode, theme_builder_config, theme_builder, tk_config): ( Option, ThemeMode, Option, ThemeBuilder, Option, - CosmicTk, ), ) -> Self { let theme = if theme_mode.is_dark { @@ -150,6 +150,7 @@ impl } else { Theme::light_default() }; + let custom_accent = theme_builder.accent.filter(|c| { let c = Srgba::new(c.red, c.green, c.blue, 1.0); c != theme.palette.accent_blue @@ -171,7 +172,6 @@ impl }, context_view: None, roundness: theme_builder.corner_radii.into(), - density: tk.interface_density.into(), custom_accent: ColorPickerModel::new( &*HEX, &*RGB, @@ -209,6 +209,7 @@ impl theme_builder.window_hint.map(Color::from), ), no_custom_window_hint: theme_builder.window_hint.is_none(), + font_config: font_config::Model::new(), icon_theme_active: None, icon_themes: Vec::new(), icon_handles: Vec::new(), @@ -218,7 +219,6 @@ impl theme_mode, theme_builder, tk_config, - tk, day_time: true, auto_switch_descs: [ fl!("auto-switch", "sunrise").into(), @@ -258,25 +258,14 @@ impl From<(Option, ThemeMode)> for Page { ); let tk_config = CosmicTk::config().ok(); - let tk = match tk_config.as_ref().map(CosmicTk::get_entry) { - Some(Ok(c)) => c, - Some(Err((errs, c))) => { - for err in errs { - tracing::error!(?err, "Error loading CosmicTk"); - } - c - } - None => CosmicTk::default(), - }; - ( + + Self::from(( theme_mode_config, theme_mode, theme_builder_config, theme_builder, tk_config, - tk, - ) - .into() + )) } } @@ -296,6 +285,7 @@ pub enum Message { ExportError, ExportFile(Arc), ExportSuccess, + FontConfig(font_config::Message), GapSize(spin_button::Message), IconTheme(usize), ImportError, @@ -386,7 +376,10 @@ impl Page { settings::section().add( settings::item::builder(fl!("enable-export")) .description(fl!("enable-export", "desc")) - .toggler(self.tk.apply_theme_global, Message::ApplyThemeGlobal) + .toggler( + cosmic::config::apply_theme_global(), + Message::ApplyThemeGlobal + ) ), // Icon theme previews cosmic::widget::column::with_children(vec![ @@ -473,8 +466,7 @@ impl Page { self.icon_theme_active = Some(id); if let Some(ref config) = self.tk_config { - let _ = self.tk.write_entry(config); - _ = self.tk.set_icon_theme(config, theme.id.clone()); + _ = config.set::("icon-theme", theme.id); } tokio::spawn(set_gnome_icon_theme(theme.name)); @@ -681,20 +673,19 @@ impl Page { }); } - Message::Density(d) => { + Message::Density(density) => { needs_sync = true; - self.density = d; if let Some(config) = self.tk_config.as_mut() { - let _density = self.tk.set_interface_density(config, d); - let _header = self.tk.set_header_size(config, d); + _ = config.set("interface_density", density); + _ = config.set("header_size", density); } let Some(config) = self.theme_builder_config.as_ref() else { return Command::none(); }; - let spacing = self.density.into(); + let spacing = density.into(); if self .theme_builder @@ -705,19 +696,19 @@ impl Page { } tokio::task::spawn(async move { - Self::update_panel_spacing(d); + Self::update_panel_spacing(density); }); } Message::Entered((icon_themes, icon_handles)) => { - *self = Self::default(); + let active_icon_theme = cosmic::config::icon_theme(); // Set the icon themes, and define the active icon theme. self.icon_themes = icon_themes; self.icon_theme_active = self .icon_themes .iter() - .position(|theme| &theme.id == &self.tk.icon_theme); + .position(|theme| &theme.id == &active_icon_theme); self.icon_handles = icon_handles; } @@ -979,8 +970,8 @@ impl Page { } Message::ApplyThemeGlobal(enabled) => { - if let Some(tk_config) = self.tk_config.as_ref() { - _ = self.tk.set_apply_theme_global(tk_config, enabled); + if let Some(config) = self.tk_config.as_ref() { + _ = config.set("apply_theme_global", enabled); } else { tracing::error!("Failed to apply theme to GNOME config because the CosmicTK config does not exist."); } @@ -997,6 +988,10 @@ impl Page { self.day_time = day_time; return Command::none(); } + + Message::FontConfig(message) => { + return self.font_config.update(message); + } } // If the theme builder changed, write a new theme to disk on a background thread. @@ -1078,6 +1073,7 @@ impl Page { } fn reload_theme_mode(&mut self) { + let font_config = std::mem::take(&mut self.font_config); let icon_themes = std::mem::take(&mut self.icon_themes); let icon_handles = std::mem::take(&mut self.icon_handles); let icon_theme_active = self.icon_theme_active.take(); @@ -1088,6 +1084,7 @@ impl Page { self.icon_themes = icon_themes; self.icon_handles = icon_handles; self.icon_theme_active = icon_theme_active; + self.font_config = font_config; } fn update_color_picker( @@ -1304,6 +1301,7 @@ impl page::Page for Page { sections.insert(mode_and_colors()), sections.insert(style()), sections.insert(interface_density()), + sections.insert(font_config::section()), sections.insert(window_management()), sections.insert(experimental()), sections.insert(reset_button()), @@ -1335,7 +1333,16 @@ impl page::Page for Page { _: page::Entity, _sender: tokio::sync::mpsc::Sender, ) -> Command { - command::future(fetch_icon_themes()).map(crate::pages::Message::Appearance) + command::batch(vec![ + // Load icon themes + command::future(fetch_icon_themes()).map(crate::pages::Message::Appearance), + // Load font families + command::future(async move { + let (mono, interface) = font_config::load_font_families(); + Message::FontConfig(font_config::Message::LoadedFonts(mono, interface)) + }) + .map(crate::pages::Message::Appearance), + ]) } fn on_leave(&mut self) -> Command { @@ -1768,11 +1775,11 @@ pub fn style() -> Section { } pub fn interface_density() -> Section { - let mut descriptions = Slab::new(); - - let comfortable = descriptions.insert(fl!("interface-density", "comfortable")); - let compact = descriptions.insert(fl!("interface-density", "compact")); - let spacious = descriptions.insert(fl!("interface-density", "spacious")); + crate::slab!(descriptions { + comfortable = fl!("interface-density", "comfortable"); + compact = fl!("interface-density", "compact"); + spacious = fl!("interface-density", "spacious"); + }); Section::default() .title(fl!("interface-density")) @@ -1780,12 +1787,14 @@ pub fn interface_density() -> Section { .view::(move |_binder, page, section| { let descriptions = §ion.descriptions; + let density = cosmic::config::interface_density(); + settings::section() .title(§ion.title) .add(settings::item_row(vec![radio( text::body(&descriptions[compact]), Density::Compact, - Some(page.density), + Some(density), Message::Density, ) .width(Length::Fill) @@ -1793,7 +1802,7 @@ pub fn interface_density() -> Section { .add(settings::item_row(vec![radio( text::body(&descriptions[comfortable]), Density::Standard, - Some(page.density), + Some(density), Message::Density, ) .width(Length::Fill) @@ -1801,7 +1810,7 @@ pub fn interface_density() -> Section { .add(settings::item_row(vec![radio( text::body(&descriptions[spacious]), Density::Spacious, - Some(page.density), + Some(density), Message::Density, ) .width(Length::Fill) diff --git a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs index a6f87d1..e2f385e 100644 --- a/cosmic-settings/src/pages/desktop/wallpaper/mod.rs +++ b/cosmic-settings/src/pages/desktop/wallpaper/mod.rs @@ -1191,7 +1191,7 @@ pub fn settings() -> Section { if page.wallpaper_service_config.same_on_all { let element = text(fl!("all-displays")) - .font(cosmic::font::FONT_SEMIBOLD) + .font(cosmic::font::semibold()) .horizontal_alignment(alignment::Horizontal::Center) .vertical_alignment(alignment::Vertical::Center) .width(Length::Fill) diff --git a/cosmic-settings/src/pages/display/arrangement.rs b/cosmic-settings/src/pages/display/arrangement.rs index 99778a7..bc50a70 100644 --- a/cosmic-settings/src/pages/display/arrangement.rs +++ b/cosmic-settings/src/pages/display/arrangement.rs @@ -353,7 +353,7 @@ impl<'a, Message: Clone> Widget for Arrangemen content: itoa::Buffer::new().format(id), size: core::Pixels(24.0), line_height: core::text::LineHeight::Relative(1.2), - font: cosmic::font::FONT_BOLD, + font: cosmic::font::bold(), bounds: id_bounds.size(), horizontal_alignment: alignment::Horizontal::Center, vertical_alignment: alignment::Vertical::Center, diff --git a/i18n/en/cosmic_settings.ftl b/i18n/en/cosmic_settings.ftl index 637e619..1f5a322 100644 --- a/i18n/en/cosmic_settings.ftl +++ b/i18n/en/cosmic_settings.ftl @@ -205,6 +205,34 @@ window-management-appearance = Window Management .active-hint = Active window hint size .gaps = Gaps around tiled windows +### Appearance: Font + +font-config = Font Configuration +interface-font = Interface Font +monospace-font = Monospace Font +font-family = Family + +font-weight = Weight + .thin = Thin + .extra-light = Extra Light + .light = Light + .normal = Normal + .medium = Medium + .semibold = Semi Bold + .bold = Bold + .extra-bold = Extra Bold + .black = Black + +font-style = Style + .normal = Normal + .italic = Italic + .oblique = Oblique + +font-stretch = Stretch + .condensed = Condensed + .normal = Normal + .expanded = Expanded + ## Desktop: Notifications notifications = Notifications