diff --git a/README.md b/README.md index c32184a..1598b63 100644 --- a/README.md +++ b/README.md @@ -248,9 +248,14 @@ You can specify alternative configuration locations through: 1. Use the following config keys to configure centerpiece. These are all config keys including their respective defaults. ```yml + scale: 1.0 color: text: "#ffffff" background: "#000000" + font: + # To list the available fonts on your system, use `fc-list : family | sed 's/,.*$//' | sort | uniq` + family: monospace # 'monospace' | 'serif' | 'sans_serif' | 'cursive' | 'fantasy' | 'your-font-name' + size: 14 plugin: applications: enable: true @@ -302,10 +307,16 @@ You can specify alternative configuration locations through: programs.centerpiece = { enable = true; config = { + scale = 1.0; color = { text = "#ffffff"; background = "#000000"; }; + font = { + # To list the available fonts on your system, use `fc-list : family | sed 's/,.*$//' | sort | uniq` + family = "monospace"; # 'monospace' | 'serif' | 'sans_serif' | 'cursive' | 'fantasy' | 'your-font-name' + size = 14; + }; plugin = { applications = { enable = true; diff --git a/client/assets/FiraCode/FiraCodeNerdFont-Bold.ttf b/client/assets/FiraCode/FiraCodeNerdFont-Bold.ttf deleted file mode 100644 index b98890e..0000000 Binary files a/client/assets/FiraCode/FiraCodeNerdFont-Bold.ttf and /dev/null differ diff --git a/client/assets/FiraCode/FiraCodeNerdFont-Light.ttf b/client/assets/FiraCode/FiraCodeNerdFont-Light.ttf deleted file mode 100644 index 5add06d..0000000 Binary files a/client/assets/FiraCode/FiraCodeNerdFont-Light.ttf and /dev/null differ diff --git a/client/assets/FiraCode/FiraCodeNerdFont-Medium.ttf b/client/assets/FiraCode/FiraCodeNerdFont-Medium.ttf deleted file mode 100644 index f8a8546..0000000 Binary files a/client/assets/FiraCode/FiraCodeNerdFont-Medium.ttf and /dev/null differ diff --git a/client/assets/FiraCode/FiraCodeNerdFont-Regular.ttf b/client/assets/FiraCode/FiraCodeNerdFont-Regular.ttf deleted file mode 100644 index ef65b36..0000000 Binary files a/client/assets/FiraCode/FiraCodeNerdFont-Regular.ttf and /dev/null differ diff --git a/client/assets/FiraCode/LICENSE b/client/assets/FiraCode/LICENSE deleted file mode 100644 index 805e0b3..0000000 --- a/client/assets/FiraCode/LICENSE +++ /dev/null @@ -1,93 +0,0 @@ -Copyright (c) 2014, The Fira Code Project Authors (https://github.com/tonsky/FiraCode) - -This Font Software is licensed under the SIL Open Font License, Version 1.1. -This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL - - ------------------------------------------------------------ -SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 ------------------------------------------------------------ - -PREAMBLE -The goals of the Open Font License (OFL) are to stimulate worldwide -development of collaborative font projects, to support the font creation -efforts of academic and linguistic communities, and to provide a free and -open framework in which fonts may be shared and improved in partnership -with others. - -The OFL allows the licensed fonts to be used, studied, modified and -redistributed freely as long as they are not sold by themselves. The -fonts, including any derivative works, can be bundled, embedded, -redistributed and/or sold with any software provided that any reserved -names are not used by derivative works. The fonts and derivatives, -however, cannot be released under any other type of license. The -requirement for fonts to remain under this license does not apply -to any document created using the fonts or their derivatives. - -DEFINITIONS -"Font Software" refers to the set of files released by the Copyright -Holder(s) under this license and clearly marked as such. This may -include source files, build scripts and documentation. - -"Reserved Font Name" refers to any names specified as such after the -copyright statement(s). - -"Original Version" refers to the collection of Font Software components as -distributed by the Copyright Holder(s). - -"Modified Version" refers to any derivative made by adding to, deleting, -or substituting -- in part or in whole -- any of the components of the -Original Version, by changing formats or by porting the Font Software to a -new environment. - -"Author" refers to any designer, engineer, programmer, technical -writer or other person who contributed to the Font Software. - -PERMISSION & CONDITIONS -Permission is hereby granted, free of charge, to any person obtaining -a copy of the Font Software, to use, study, copy, merge, embed, modify, -redistribute, and sell modified and unmodified copies of the Font -Software, subject to the following conditions: - -1) Neither the Font Software nor any of its individual components, -in Original or Modified Versions, may be sold by itself. - -2) Original or Modified Versions of the Font Software may be bundled, -redistributed and/or sold with any software, provided that each copy -contains the above copyright notice and this license. These can be -included either as stand-alone text files, human-readable headers or -in the appropriate machine-readable metadata fields within text or -binary files as long as those fields can be easily viewed by the user. - -3) No Modified Version of the Font Software may use the Reserved Font -Name(s) unless explicit written permission is granted by the corresponding -Copyright Holder. This restriction only applies to the primary font name as -presented to the users. - -4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font -Software shall not be used to promote, endorse or advertise any -Modified Version, except to acknowledge the contribution(s) of the -Copyright Holder(s) and the Author(s) or with their explicit written -permission. - -5) The Font Software, modified or unmodified, in part or in whole, -must be distributed entirely under this license, and must not be -distributed under any other license. The requirement for fonts to -remain under this license does not apply to any document created -using the Font Software. - -TERMINATION -This license becomes null and void if any of the above conditions are -not met. - -DISCLAIMER -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE -COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL -DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM -OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/client/assets/SymbolsNerdFont.ttf b/client/assets/SymbolsNerdFont.ttf new file mode 100644 index 0000000..4ab98de Binary files /dev/null and b/client/assets/SymbolsNerdFont.ttf differ diff --git a/client/src/component/divider.rs b/client/src/component/divider.rs index ab54ac6..5816aa6 100644 --- a/client/src/component/divider.rs +++ b/client/src/component/divider.rs @@ -1,14 +1,14 @@ pub fn view() -> iced::Element<'static, crate::Message> { iced::widget::column![iced::widget::horizontal_rule(1)] .padding(iced::Padding { - top: 1. * crate::REM, + top: 1. * crate::rem(), right: 0., - bottom: 0.5 * crate::REM, + bottom: 0.5 * crate::rem(), left: 0., }) // We're fixing the height here to unify it // with the height of entries for a smooth // scrolling experience - .height(crate::ENTRY_HEIGHT) + .height(crate::entry_height()) .into() } diff --git a/client/src/component/entry.rs b/client/src/component/entry.rs index 722752d..d29b3ba 100644 --- a/client/src/component/entry.rs +++ b/client/src/component/entry.rs @@ -3,7 +3,7 @@ pub fn view(entry: &crate::model::Entry, active: bool) -> iced::Element<'static, iced::widget::container( iced::widget::row![ iced::widget::text(clipped_title(entry.title.clone())) - .size(1. * crate::REM) + .size(1. * crate::rem()) .width(iced::Length::Fill) .shaping(iced::widget::text::Shaping::Advanced), iced::widget::text(if active { @@ -11,9 +11,9 @@ pub fn view(entry: &crate::model::Entry, active: bool) -> iced::Element<'static, } else { "".to_string() }) - .size(1. * crate::REM) + .size(1. * crate::rem()) ] - .padding(0.5 * crate::REM), + .padding(0.5 * crate::rem()), ) .style(move |theme: &iced::Theme| { if !active { @@ -25,7 +25,7 @@ pub fn view(entry: &crate::model::Entry, active: bool) -> iced::Element<'static, border: iced::Border { color: palette.background.base.text, width: 1., - radius: iced::border::Radius::from(0.1 * crate::REM), + radius: iced::border::Radius::from(0.1 * crate::rem()), }, ..Default::default() } @@ -34,8 +34,8 @@ pub fn view(entry: &crate::model::Entry, active: bool) -> iced::Element<'static, // We're fixing the height here to unify it // with the height of plugin headers for a smooth // scrolling experience - .height(crate::ENTRY_HEIGHT) - .padding([0., 0.75 * crate::REM]) + .height(crate::entry_height()) + .padding([0., 0.75 * crate::rem()]) .into() } diff --git a/client/src/component/plugin_header.rs b/client/src/component/plugin_header.rs index 2de16e8..fe89c12 100644 --- a/client/src/component/plugin_header.rs +++ b/client/src/component/plugin_header.rs @@ -1,20 +1,21 @@ +use crate::settings; + pub fn view(plugin: &crate::model::Plugin) -> iced::Element<'static, crate::Message> { + let mut font = settings().default_font.clone(); + font.weight = iced::font::Weight::Light; + iced::widget::row![iced::widget::text(plugin.title.clone()) - .font(iced::Font { - family: iced::font::Family::Name("FiraCode Nerd Font"), - weight: iced::font::Weight::Light, - ..Default::default() - }) - .size(0.75 * crate::REM)] + .font(font) + .size(0.75 * crate::rem())] // We're fixing the height here to unify it // with the height of entries for a smooth // scrolling experience - .height(crate::ENTRY_HEIGHT) + .height(crate::entry_height()) .padding(iced::Padding { - top: 0.8 * crate::REM, - right: 1.25 * crate::REM, - bottom: 0.5 * crate::REM, - left: 1.25 * crate::REM, + top: 0.8 * crate::rem(), + right: 1.25 * crate::rem(), + bottom: 0.5 * crate::rem(), + left: 1.25 * crate::rem(), }) .into() } diff --git a/client/src/component/query_input.rs b/client/src/component/query_input.rs index 5dd5bab..434070c 100644 --- a/client/src/component/query_input.rs +++ b/client/src/component/query_input.rs @@ -7,12 +7,12 @@ pub fn view(query: &str, add_horizontal_rule: bool) -> iced::Element<'static, cr .icon(iced::widget::text_input::Icon { font: crate::settings().default_font, code_point: '󰍉', - size: Some(iced::Pixels(1.3 * crate::REM)), - spacing: crate::REM, + size: Some(iced::Pixels(1.3 * crate::rem())), + spacing: crate::rem(), side: iced::widget::text_input::Side::Left, }) - .size(1. * crate::REM) - .padding([1.0 * crate::REM, 1.2 * crate::REM]) + .size(1. * crate::rem()) + .padding([1.0 * crate::rem(), 1.2 * crate::rem()]) .style(style),] .padding(iced::Padding::default().bottom(1.)); diff --git a/client/src/main.rs b/client/src/main.rs index afd144e..5d45adb 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -172,11 +172,11 @@ fn view(centerpice: &Centerpiece) -> iced::Element { iced::widget::container::Style { background: Some(iced::Background::Color(palette.background.base.color)), - border: iced::Border::default().rounded(0.25 * crate::REM), + border: iced::Border::default().rounded(0.25 * crate::rem()), ..Default::default() } }) - .padding(iced::padding::bottom(0.75 * crate::REM)) + .padding(iced::padding::bottom(0.75 * crate::rem())) .into() } @@ -317,17 +317,22 @@ fn style(_centerpiece: &Centerpiece, _theme: &iced::Theme) -> iced_layershell::A } fn settings() -> iced_layershell::build_pattern::MainSettings { + let settings = settings::Settings::get_or_init(); + + let width = (650.0 * settings.scale).round() as u32; + let height = (380.0 * settings.scale).round() as u32; + iced_layershell::build_pattern::MainSettings { id: Some(APP_ID.into()), default_font: iced::Font { - family: iced::font::Family::Name("FiraCode Nerd Font"), + family: settings.font.family, weight: iced::font::Weight::Normal, stretch: iced::font::Stretch::Normal, style: iced::font::Style::default(), }, - default_text_size: iced::Pixels(crate::REM), + default_text_size: iced::Pixels(settings.font.size), layer_settings: iced_layershell::settings::LayerShellSettings { - size: Some((650, 380)), + size: Some((width, height)), layer: iced_layershell::reexport::Layer::Top, anchor: iced_layershell::reexport::Anchor::Top, keyboard_interactivity: iced_layershell::reexport::KeyboardInteractivity::Exclusive, @@ -353,14 +358,9 @@ impl Centerpiece { plugins: vec![], }, iced::Task::batch(vec![ - iced::font::load( - include_bytes!("../assets/FiraCode/FiraCodeNerdFont-Regular.ttf").as_slice(), - ) - .map(Message::FontLoaded), - iced::font::load( - include_bytes!("../assets/FiraCode/FiraCodeNerdFont-Light.ttf").as_slice(), - ) - .map(Message::FontLoaded), + // Load the symbols only nerd font to ensure they're always available + iced::font::load(include_bytes!("../assets/SymbolsNerdFont.ttf").as_slice()) + .map(Message::FontLoaded), iced::Task::perform(async {}, move |()| Message::Loaded), ]), ) @@ -518,5 +518,11 @@ impl Centerpiece { } } -pub const REM: f32 = 14.0; -pub const ENTRY_HEIGHT: f32 = 2.3 * crate::REM; +pub fn rem() -> f32 { + let settings = settings::Settings::get_or_init(); + (settings.scale as f32) * settings.font.size +} + +pub fn entry_height() -> f32 { + 2.3 * rem() +} diff --git a/home-manager-module.nix b/home-manager-module.nix index 52f6ad1..66c29a6 100644 --- a/home-manager-module.nix +++ b/home-manager-module.nix @@ -14,6 +14,12 @@ in enable = lib.mkEnableOption (lib.mdDoc "Centerpiece"); config = { + scale = lib.mkOption { + default = 1.; + type = lib.types.float; + description = lib.mdDoc "Scale factor"; + }; + color = { text = lib.mkOption { default = "#ffffff"; @@ -28,6 +34,19 @@ in }; }; + font = { + family = lib.mkOption { + default = "monospace"; + type = lib.types.str; + description = lib.mdDoc "To list the available fonts on your system, use `fc-list : family | sed 's/,.*$//' | sort | uniq`. May be the name of a font or one of: 'monospace' | 'serif' | 'sans_serif' | 'cursive' | 'fantasy'"; + }; + size = lib.mkOption { + default = 14; + type = lib.types.int; + description = lib.mdDoc "Font size"; + }; + }; + plugin = { applications = { enable = lib.mkOption { diff --git a/settings/src/lib.rs b/settings/src/lib.rs index 9d4003a..3d4b2d8 100644 --- a/settings/src/lib.rs +++ b/settings/src/lib.rs @@ -181,6 +181,55 @@ impl Default for ColorSettings { } } +fn default_font_family() -> iced::font::Family { + iced::font::Family::Monospace +} + +fn default_font_size() -> f32 { + 14.0 +} + +#[derive(Debug, Deserialize)] +pub struct FontSettings { + #[serde( + default = "default_font_family", + deserialize_with = "deserialize_font_family" + )] + pub family: iced::font::Family, + #[serde(default = "default_font_size")] + pub size: f32, +} + +fn deserialize_font_family<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let s = String::deserialize(deserializer)?; + + match s.to_lowercase().as_str() { + "monospace" => Ok(iced::font::Family::Monospace), + "serif" => Ok(iced::font::Family::Serif), + "sans_serif" | "sans-serif" => Ok(iced::font::Family::SansSerif), + "cursive" => Ok(iced::font::Family::Cursive), + "fantasy" => Ok(iced::font::Family::Fantasy), + _ => { + // Convert String to &'static str by leaking it + // This is appropriate since we only generate one settings struct + let static_str = Box::leak(s.into_boxed_str()); + Ok(iced::font::Family::Name(static_str)) + } + } +} + +impl Default for FontSettings { + fn default() -> Self { + Self { + family: default_font_family(), + size: default_font_size(), + } + } +} + fn default_commands() -> Vec> { vec![ vec![ @@ -333,12 +382,20 @@ pub struct PluginSettings { pub wifi: WifiPluginSettings, } +fn default_scale() -> f64 { + 1. +} + #[derive(Debug, Default, Deserialize)] pub struct Settings { + #[serde(default = "default_scale")] + pub scale: f64, #[serde(default)] pub plugin: PluginSettings, #[serde(default)] pub color: ColorSettings, + #[serde(default)] + pub font: FontSettings, } impl Settings { @@ -372,7 +429,9 @@ impl Settings { #[allow(deprecated)] if settings.color.surface != *"deprecated" { - log::warn!("color.surface has been replaced by automatic shading of the background color in cernterpiece version 1.2.0. Please remove this field from your configuration.") + log::warn!( + "color.surface has been replaced by automatic shading of the background color in cernterpiece version 1.2.0. Please remove this field from your configuration." + ) } settings