From 225ec5633eebf82af26aafbe5aea513cb9814a94 Mon Sep 17 00:00:00 2001 From: riChar Date: Mon, 25 Mar 2024 10:01:12 +0800 Subject: [PATCH 1/3] configurable font for text annotations --- README.md | 4 ++++ src/command_line.rs | 4 ++++ src/configuration.rs | 13 +++++++++++++ src/femtovg_area/imp.rs | 21 +++++++++++++++++---- 4 files changed, 38 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b785e8e..38e51e3 100644 --- a/README.md +++ b/README.md @@ -78,6 +78,8 @@ output-filename = "/tmp/test-%Y-%m-%d_%H:%M:%S.png" save-after-copy = false # Hide toolbars by default default-hide-toolbars = false +# Path of font to use for text annotations +font = "/usr/share/fonts/TTF/Roboto-Regular.ttf" # custom colours for the colour palette [color-palette] @@ -118,6 +120,8 @@ Options: After copying the screenshot, save it to a file as well -d, --default-hide-toolbars Hide toolbars by default + --font + Path of font to use for text annotations -h, --help Print help -V, --version diff --git a/src/command_line.rs b/src/command_line.rs index 9774bb5..b1fa542 100644 --- a/src/command_line.rs +++ b/src/command_line.rs @@ -43,6 +43,10 @@ pub struct CommandLine { /// Hide toolbars by default #[arg(short, long)] pub default_hide_toolbars: bool, + + /// Path of font to use for text annotations + #[arg(long)] + pub font: Option, } #[derive(Debug, Clone, Copy, Default, ValueEnum)] diff --git a/src/configuration.rs b/src/configuration.rs index 4d60c04..9c33708 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -38,6 +38,7 @@ pub struct Configuration { save_after_copy: bool, color_palette: ColorPalette, default_hide_toolbars: bool, + font: Option, } pub struct ColorPalette { @@ -146,6 +147,9 @@ impl Configuration { if let Some(v) = general.default_hide_toolbars { self.default_hide_toolbars = v; } + if let Some(v) = general.font { + self.font = Some(v); + } } fn merge(&mut self, file: Option, command_line: CommandLine) { // input_filename is required and needs to be overwritten @@ -186,6 +190,9 @@ impl Configuration { if command_line.save_after_copy { self.save_after_copy = command_line.save_after_copy; } + if let Some(v) = command_line.font { + self.font = Some(v); + } } pub fn early_exit(&self) -> bool { @@ -227,6 +234,10 @@ impl Configuration { pub fn default_hide_toolbars(&self) -> bool { self.default_hide_toolbars } + + pub fn font(&self) -> Option<&String> { + self.font.as_ref() + } } impl Default for Configuration { @@ -242,6 +253,7 @@ impl Default for Configuration { save_after_copy: false, color_palette: ColorPalette::default(), default_hide_toolbars: false, + font: None, } } } @@ -277,6 +289,7 @@ struct ConfiguationFileGeneral { output_filename: Option, save_after_copy: Option, default_hide_toolbars: Option, + font: Option, } #[derive(Deserialize)] diff --git a/src/femtovg_area/imp.rs b/src/femtovg_area/imp.rs index 7d7b0c1..4813bb9 100644 --- a/src/femtovg_area/imp.rs +++ b/src/femtovg_area/imp.rs @@ -21,6 +21,7 @@ use crate::{ math::Vec2D, sketch_board::{Action, SketchBoardInput}, tools::{CropTool, Drawable, Tool}, + APP_CONFIG, }; #[derive(Default)] @@ -162,14 +163,26 @@ impl FemtoVGArea { self.canvas.borrow_mut().replace(c); } - self.font.borrow_mut().replace( + let font = APP_CONFIG.read().font().and_then(|f| { self.canvas .borrow_mut() .as_mut() .unwrap() // this unwrap is safe because it gets placed above - .add_font_mem(&resource!("src/assets/Roboto-Regular.ttf")) - .expect("Cannot add font"), - ); + .add_font(f) + .ok() + }); + if let Some(font) = font { + self.font.borrow_mut().replace(font); + } else { + self.font.borrow_mut().replace( + self.canvas + .borrow_mut() + .as_mut() + .unwrap() // this unwrap is safe because it gets placed above + .add_font_mem(&resource!("src/assets/Roboto-Regular.ttf")) + .expect("Cannot add font"), + ); + } } fn setup_canvas(&self) -> Result> { From 6a81200906021364980f18b3030a7cc70803d7e7 Mon Sep 17 00:00:00 2001 From: riChar Date: Tue, 26 Mar 2024 10:37:11 +0800 Subject: [PATCH 2/3] use fontconfig to find font path --- Cargo.lock | 41 +++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + README.md | 13 +++++++++---- config.toml | 3 +++ flake.nix | 1 + src/command_line.rs | 8 ++++++-- src/configuration.rs | 31 ++++++++++++++++++++++--------- src/femtovg_area/imp.rs | 25 +++++++++++++++++-------- 8 files changed, 100 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index db3c76e..a7307a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,6 +305,25 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "cstr" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68523903c8ae5aacfa32a0d9ae60cadeb764e1da14ee0d26b1f3089f13a54636" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + [[package]] name = "epoxy" version = "0.1.0" @@ -383,6 +402,15 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "fontconfig" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b79b619a4ae048ea79e927376b1d10294979bda195b0c052fc958be96c62d9" +dependencies = [ + "yeslogic-fontconfig-sys", +] + [[package]] name = "fragile" version = "2.0.0" @@ -1352,6 +1380,7 @@ dependencies = [ "clap_complete_nushell", "epoxy", "femtovg", + "fontconfig", "gdk-pixbuf", "glib", "glib-macros", @@ -2024,6 +2053,18 @@ dependencies = [ "bitflags 1.3.2", ] +[[package]] +name = "yeslogic-fontconfig-sys" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffb6b23999a8b1a997bf47c7bb4d19ad4029c3327bb3386ebe0a5ff584b33c7a" +dependencies = [ + "cstr", + "dlib", + "once_cell", + "pkg-config", +] + [[package]] name = "zvariant" version = "3.15.2" diff --git a/Cargo.toml b/Cargo.toml index 6ff1fe6..85292fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,6 +45,7 @@ glow = "0.13.1" glib-macros = "0.19.2" glib = "0.19.2" resource = "0.5.0" # font emedding +fontconfig = "0.8.0" # font loading [dependencies.relm4-icons] version = "0.8.2" diff --git a/README.md b/README.md index 38e51e3..fed9b2f 100644 --- a/README.md +++ b/README.md @@ -78,8 +78,9 @@ output-filename = "/tmp/test-%Y-%m-%d_%H:%M:%S.png" save-after-copy = false # Hide toolbars by default default-hide-toolbars = false -# Path of font to use for text annotations -font = "/usr/share/fonts/TTF/Roboto-Regular.ttf" +# Font to use for text annotations +font-family = "Roboto" +font-style = "Bold" # custom colours for the colour palette [color-palette] @@ -120,8 +121,10 @@ Options: After copying the screenshot, save it to a file as well -d, --default-hide-toolbars Hide toolbars by default - --font - Path of font to use for text annotations + --font-family + Font family to use for text annotations + --font-style + Font style to use for text annotations -h, --help Print help -V, --version @@ -161,6 +164,7 @@ Satty is based on GTK-4 and Adwaita. - libgtk-4-1 - libadwaita-1-0 - libepoxy +- fontconfig ### Arch Linux & Gentoo @@ -169,6 +173,7 @@ Satty is based on GTK-4 and Adwaita. - gtk4 - gdk-pixbuf2 - libepoxy +- fontconfig ## License diff --git a/config.toml b/config.toml index 4c2f992..8e67d7c 100644 --- a/config.toml +++ b/config.toml @@ -15,6 +15,9 @@ output-filename = "/tmp/test-%Y-%m-%d_%H:%M:%S.png" save-after-copy = false # Hide toolbars by default dafault-hide-toolbars = false +# Font to use for text annotations +font-family = "Roboto" +font-style = "Regular" # custom colours for the colour palette [color-palette] diff --git a/flake.nix b/flake.nix index 29726ff..488f650 100644 --- a/flake.nix +++ b/flake.nix @@ -26,6 +26,7 @@ gtk4 wrapGAppsHook4 # this is needed for relm4-icons to properly load after gtk::init() libadwaita + fontconfig (rust-bin.stable.latest.default.override { diff --git a/src/command_line.rs b/src/command_line.rs index b1fa542..cb24751 100644 --- a/src/command_line.rs +++ b/src/command_line.rs @@ -44,9 +44,13 @@ pub struct CommandLine { #[arg(short, long)] pub default_hide_toolbars: bool, - /// Path of font to use for text annotations + /// Font family to use for text annotations #[arg(long)] - pub font: Option, + pub font_family: Option, + + /// Font style to use for text annotations + #[arg(long)] + pub font_style: Option, } #[derive(Debug, Clone, Copy, Default, ValueEnum)] diff --git a/src/configuration.rs b/src/configuration.rs index 9c33708..9f6df3e 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -38,7 +38,8 @@ pub struct Configuration { save_after_copy: bool, color_palette: ColorPalette, default_hide_toolbars: bool, - font: Option, + font_family: Option, + font_style: Option, } pub struct ColorPalette { @@ -147,8 +148,11 @@ impl Configuration { if let Some(v) = general.default_hide_toolbars { self.default_hide_toolbars = v; } - if let Some(v) = general.font { - self.font = Some(v); + if let Some(v) = general.font_family { + self.font_family = Some(v); + } + if let Some(v) = general.font_style { + self.font_style = Some(v); } } fn merge(&mut self, file: Option, command_line: CommandLine) { @@ -190,8 +194,11 @@ impl Configuration { if command_line.save_after_copy { self.save_after_copy = command_line.save_after_copy; } - if let Some(v) = command_line.font { - self.font = Some(v); + if let Some(v) = command_line.font_family { + self.font_family = Some(v); + } + if let Some(v) = command_line.font_style { + self.font_style = Some(v); } } @@ -235,8 +242,12 @@ impl Configuration { self.default_hide_toolbars } - pub fn font(&self) -> Option<&String> { - self.font.as_ref() + pub fn font_family(&self) -> Option<&String> { + self.font_family.as_ref() + } + + pub fn font_style(&self) -> Option<&String> { + self.font_style.as_ref() } } @@ -253,7 +264,8 @@ impl Default for Configuration { save_after_copy: false, color_palette: ColorPalette::default(), default_hide_toolbars: false, - font: None, + font_family: None, + font_style: None, } } } @@ -289,7 +301,8 @@ struct ConfiguationFileGeneral { output_filename: Option, save_after_copy: Option, default_hide_toolbars: Option, - font: Option, + font_family: Option, + font_style: Option, } #[derive(Deserialize)] diff --git a/src/femtovg_area/imp.rs b/src/femtovg_area/imp.rs index 4813bb9..b6d6538 100644 --- a/src/femtovg_area/imp.rs +++ b/src/femtovg_area/imp.rs @@ -12,6 +12,7 @@ use femtovg::{ rgb::{RGB, RGBA, RGBA8}, Canvas, FontId, ImageFlags, ImageId, ImageSource, Paint, Path, PixelFormat, Transform2D, }; +use fontconfig::Fontconfig; use gdk_pixbuf::Pixbuf; use gtk::{glib, prelude::*, subclass::prelude::*}; use relm4::{gtk, Sender}; @@ -163,14 +164,22 @@ impl FemtoVGArea { self.canvas.borrow_mut().replace(c); } - let font = APP_CONFIG.read().font().and_then(|f| { - self.canvas - .borrow_mut() - .as_mut() - .unwrap() // this unwrap is safe because it gets placed above - .add_font(f) - .ok() - }); + let app_config = APP_CONFIG.read(); + let font = app_config + .font_family() + .and_then(|font_family| { + Fontconfig::new().and_then(|fc| { + fc.find(font_family, app_config.font_style().map(String::as_str)) + }) + }) + .and_then(|f| { + self.canvas + .borrow_mut() + .as_mut() + .unwrap() // this unwrap is safe because it gets placed above + .add_font(f.path) + .ok() + }); if let Some(font) = font { self.font.borrow_mut().replace(font); } else { From 69921606def7523a8c4def41ce9116da8f674a29 Mon Sep 17 00:00:00 2001 From: riChar Date: Wed, 27 Mar 2024 18:32:21 +0800 Subject: [PATCH 3/3] font config in toml object form & log when missing font --- README.md | 5 ++-- config.toml | 7 ++--- src/configuration.rs | 60 +++++++++++++++++++++++++++-------------- src/femtovg_area/imp.rs | 28 +++++++++++-------- 4 files changed, 64 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index fed9b2f..cdb26a6 100644 --- a/README.md +++ b/README.md @@ -79,8 +79,9 @@ save-after-copy = false # Hide toolbars by default default-hide-toolbars = false # Font to use for text annotations -font-family = "Roboto" -font-style = "Bold" +[font] +family = "Roboto" +style = "Bold" # custom colours for the colour palette [color-palette] diff --git a/config.toml b/config.toml index 8e67d7c..67515d9 100644 --- a/config.toml +++ b/config.toml @@ -14,10 +14,11 @@ output-filename = "/tmp/test-%Y-%m-%d_%H:%M:%S.png" # After copying the screenshot, save it to a file as well save-after-copy = false # Hide toolbars by default -dafault-hide-toolbars = false +default-hide-toolbars = false # Font to use for text annotations -font-family = "Roboto" -font-style = "Regular" +[font] +family = "Roboto" +style = "Regular" # custom colours for the colour palette [color-palette] diff --git a/src/configuration.rs b/src/configuration.rs index 9f6df3e..acbd546 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -38,8 +38,30 @@ pub struct Configuration { save_after_copy: bool, color_palette: ColorPalette, default_hide_toolbars: bool, - font_family: Option, - font_style: Option, + font: FontConfiguration, +} + +#[derive(Default)] +pub struct FontConfiguration { + family: Option, + style: Option, +} + +impl FontConfiguration { + pub fn family(&self) -> Option<&str> { + self.family.as_deref() + } + pub fn style(&self) -> Option<&str> { + self.style.as_deref() + } + fn merge(&mut self, file_font: FontFile) { + if let Some(v) = file_font.family { + self.family = Some(v); + } + if let Some(v) = file_font.style { + self.style = Some(v); + } + } } pub struct ColorPalette { @@ -148,12 +170,6 @@ impl Configuration { if let Some(v) = general.default_hide_toolbars { self.default_hide_toolbars = v; } - if let Some(v) = general.font_family { - self.font_family = Some(v); - } - if let Some(v) = general.font_style { - self.font_style = Some(v); - } } fn merge(&mut self, file: Option, command_line: CommandLine) { // input_filename is required and needs to be overwritten @@ -167,6 +183,9 @@ impl Configuration { if let Some(v) = file.color_palette { self.color_palette.merge(v); } + if let Some(v) = file.font { + self.font.merge(v); + } } // overwrite with all specified values from command line @@ -195,10 +214,10 @@ impl Configuration { self.save_after_copy = command_line.save_after_copy; } if let Some(v) = command_line.font_family { - self.font_family = Some(v); + self.font.family = Some(v); } if let Some(v) = command_line.font_style { - self.font_style = Some(v); + self.font.style = Some(v); } } @@ -242,12 +261,8 @@ impl Configuration { self.default_hide_toolbars } - pub fn font_family(&self) -> Option<&String> { - self.font_family.as_ref() - } - - pub fn font_style(&self) -> Option<&String> { - self.font_style.as_ref() + pub fn font(&self) -> &FontConfiguration { + &self.font } } @@ -264,8 +279,7 @@ impl Default for Configuration { save_after_copy: false, color_palette: ColorPalette::default(), default_hide_toolbars: false, - font_family: None, - font_style: None, + font: FontConfiguration::default(), } } } @@ -288,6 +302,14 @@ impl Default for ColorPalette { struct ConfigurationFile { general: Option, color_palette: Option, + font: Option, +} + +#[derive(Deserialize)] +#[serde(rename_all = "kebab-case", deny_unknown_fields)] +struct FontFile { + family: Option, + style: Option, } #[derive(Deserialize)] @@ -301,8 +323,6 @@ struct ConfiguationFileGeneral { output_filename: Option, save_after_copy: Option, default_hide_toolbars: Option, - font_family: Option, - font_style: Option, } #[derive(Deserialize)] diff --git a/src/femtovg_area/imp.rs b/src/femtovg_area/imp.rs index b6d6538..7ca45d6 100644 --- a/src/femtovg_area/imp.rs +++ b/src/femtovg_area/imp.rs @@ -1,4 +1,4 @@ -use anyhow::Result; +use anyhow::{anyhow, Error, Result}; use glow::HasContext; use std::{ cell::{RefCell, RefMut}, @@ -166,19 +166,25 @@ impl FemtoVGArea { let app_config = APP_CONFIG.read(); let font = app_config - .font_family() - .and_then(|font_family| { - Fontconfig::new().and_then(|fc| { - fc.find(font_family, app_config.font_style().map(String::as_str)) - }) - }) - .and_then(|f| { - self.canvas + .font() + .family() + .map(|font| { + let font = Fontconfig::new() + .ok_or_else(|| anyhow!("Error while initializing fontconfig"))? + .find(font, app_config.font().style()) + .ok_or_else(|| anyhow!("Can not find font"))?; + let font_id = self + .canvas .borrow_mut() .as_mut() .unwrap() // this unwrap is safe because it gets placed above - .add_font(f.path) - .ok() + .add_font(font.path)?; + Ok(font_id) + }) + .transpose() + .unwrap_or_else(|e: Error| { + println!("Error while loading font. Using default font: {e}"); + None }); if let Some(font) = font { self.font.borrow_mut().replace(font);