feat: load system fonts

This commit is contained in:
2026-05-13 22:02:24 +03:00
parent 377b218592
commit d72eaabf54
5 changed files with 261 additions and 15 deletions
Generated
+82
View File
@@ -722,6 +722,15 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "core_maths"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30"
dependencies = [
"libm",
]
[[package]] [[package]]
name = "coreaudio-rs" name = "coreaudio-rs"
version = "0.14.1" version = "0.14.1"
@@ -1308,6 +1317,29 @@ dependencies = [
"bytemuck", "bytemuck",
] ]
[[package]]
name = "fontconfig-parser"
version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646"
dependencies = [
"roxmltree",
]
[[package]]
name = "fontdb"
version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905"
dependencies = [
"fontconfig-parser",
"log",
"memmap2",
"slotmap",
"tinyvec",
"ttf-parser",
]
[[package]] [[package]]
name = "foreign-types" name = "foreign-types"
version = "0.5.0" version = "0.5.0"
@@ -3027,6 +3059,7 @@ dependencies = [
"rodio", "rodio",
"serde", "serde",
"serde_json", "serde_json",
"system-fonts",
"tokio", "tokio",
] ]
@@ -3245,6 +3278,12 @@ dependencies = [
"thiserror 2.0.18", "thiserror 2.0.18",
] ]
[[package]]
name = "roxmltree"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "1.1.0" version = "1.1.0"
@@ -3803,6 +3842,15 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "sys-locale"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "system-deps" name = "system-deps"
version = "7.0.8" version = "7.0.8"
@@ -3816,6 +3864,16 @@ dependencies = [
"version-compare", "version-compare",
] ]
[[package]]
name = "system-fonts"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f369feb844d5e08bb4e938c3f88ff359261bc94c7553ddb34e174447120b64d6"
dependencies = [
"fontdb",
"sys-locale",
]
[[package]] [[package]]
name = "tap" name = "tap"
version = "1.0.1" version = "1.0.1"
@@ -3905,6 +3963,21 @@ dependencies = [
"zerovec", "zerovec",
] ]
[[package]]
name = "tinyvec"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3"
dependencies = [
"tinyvec_macros",
]
[[package]]
name = "tinyvec_macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.52.3" version = "1.52.3"
@@ -4016,6 +4089,15 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "ttf-parser"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
dependencies = [
"core_maths",
]
[[package]] [[package]]
name = "type-map" name = "type-map"
version = "0.5.1" version = "0.5.1"
+1
View File
@@ -40,6 +40,7 @@ rfd = { version = "0.17.2", default-features = false, features = [
"xdg-portal", "xdg-portal",
] } ] }
opener = { version = "0.8.4", features = ["reveal"] } opener = { version = "0.8.4", features = ["reveal"] }
system-fonts = "0.1.0"
egui = { version = "0.34.2", default-features = false, features = [ egui = { version = "0.34.2", default-features = false, features = [
"default_fonts", "default_fonts",
+117
View File
@@ -960,6 +960,19 @@
"dest": "cargo/vendor/core-graphics-types-0.1.3", "dest": "cargo/vendor/core-graphics-types-0.1.3",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/core_maths/core_maths-0.1.1.crate",
"sha256": "77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30",
"dest": "cargo/vendor/core_maths-0.1.1"
},
{
"type": "inline",
"contents": "{\"package\": \"77745e017f5edba1a9c1d854f6f3a52dac8a12dd5af5d2f54aecf61e43d80d30\", \"files\": {}}",
"dest": "cargo/vendor/core_maths-0.1.1",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
@@ -1693,6 +1706,32 @@
"dest": "cargo/vendor/font-types-0.11.3", "dest": "cargo/vendor/font-types-0.11.3",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/fontconfig-parser/fontconfig-parser-0.5.8.crate",
"sha256": "bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646",
"dest": "cargo/vendor/fontconfig-parser-0.5.8"
},
{
"type": "inline",
"contents": "{\"package\": \"bbc773e24e02d4ddd8395fd30dc147524273a83e54e0f312d986ea30de5f5646\", \"files\": {}}",
"dest": "cargo/vendor/fontconfig-parser-0.5.8",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/fontdb/fontdb-0.23.0.crate",
"sha256": "457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905",
"dest": "cargo/vendor/fontdb-0.23.0"
},
{
"type": "inline",
"contents": "{\"package\": \"457e789b3d1202543297a350643cf459f836cade38934e7a4cf6a39e7cde2905\", \"files\": {}}",
"dest": "cargo/vendor/fontdb-0.23.0",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
@@ -4181,6 +4220,19 @@
"dest": "cargo/vendor/rodio", "dest": "cargo/vendor/rodio",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/roxmltree/roxmltree-0.20.0.crate",
"sha256": "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97",
"dest": "cargo/vendor/roxmltree-0.20.0"
},
{
"type": "inline",
"contents": "{\"package\": \"6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97\", \"files\": {}}",
"dest": "cargo/vendor/roxmltree-0.20.0",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
@@ -4896,6 +4948,19 @@
"dest": "cargo/vendor/synstructure-0.13.2", "dest": "cargo/vendor/synstructure-0.13.2",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/sys-locale/sys-locale-0.3.2.crate",
"sha256": "8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4",
"dest": "cargo/vendor/sys-locale-0.3.2"
},
{
"type": "inline",
"contents": "{\"package\": \"8eab9a99a024a169fe8a903cf9d4a3b3601109bcc13bd9e3c6fff259138626c4\", \"files\": {}}",
"dest": "cargo/vendor/sys-locale-0.3.2",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
@@ -4909,6 +4974,19 @@
"dest": "cargo/vendor/system-deps-7.0.8", "dest": "cargo/vendor/system-deps-7.0.8",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/system-fonts/system-fonts-0.1.0.crate",
"sha256": "f369feb844d5e08bb4e938c3f88ff359261bc94c7553ddb34e174447120b64d6",
"dest": "cargo/vendor/system-fonts-0.1.0"
},
{
"type": "inline",
"contents": "{\"package\": \"f369feb844d5e08bb4e938c3f88ff359261bc94c7553ddb34e174447120b64d6\", \"files\": {}}",
"dest": "cargo/vendor/system-fonts-0.1.0",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
@@ -5026,6 +5104,32 @@
"dest": "cargo/vendor/tinystr-0.8.3", "dest": "cargo/vendor/tinystr-0.8.3",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/tinyvec/tinyvec-1.11.0.crate",
"sha256": "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3",
"dest": "cargo/vendor/tinyvec-1.11.0"
},
{
"type": "inline",
"contents": "{\"package\": \"3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3\", \"files\": {}}",
"dest": "cargo/vendor/tinyvec-1.11.0",
"dest-filename": ".cargo-checksum.json"
},
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/tinyvec_macros/tinyvec_macros-0.1.1.crate",
"sha256": "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20",
"dest": "cargo/vendor/tinyvec_macros-0.1.1"
},
{
"type": "inline",
"contents": "{\"package\": \"1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20\", \"files\": {}}",
"dest": "cargo/vendor/tinyvec_macros-0.1.1",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
@@ -5156,6 +5260,19 @@
"dest": "cargo/vendor/tracing-core-0.1.36", "dest": "cargo/vendor/tracing-core-0.1.36",
"dest-filename": ".cargo-checksum.json" "dest-filename": ".cargo-checksum.json"
}, },
{
"type": "archive",
"archive-type": "tar-gzip",
"url": "https://static.crates.io/crates/ttf-parser/ttf-parser-0.25.1.crate",
"sha256": "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31",
"dest": "cargo/vendor/ttf-parser-0.25.1"
},
{
"type": "inline",
"contents": "{\"package\": \"d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31\", \"files\": {}}",
"dest": "cargo/vendor/ttf-parser-0.25.1",
"dest-filename": ".cargo-checksum.json"
},
{ {
"type": "archive", "type": "archive",
"archive-type": "tar-gzip", "archive-type": "tar-gzip",
+5 -14
View File
@@ -9,10 +9,7 @@ use egui_material_icons::icons::*;
use pwsp::types::socket::Request; use pwsp::types::socket::Request;
use pwsp::types::{audio_player::TrackInfo, gui::AppState}; use pwsp::types::{audio_player::TrackInfo, gui::AppState};
use pwsp::utils::gui::{format_time_pair, make_request_async}; use pwsp::utils::gui::{format_time_pair, make_request_async};
use std::{ use std::{path::Path, time::Instant};
path::Path,
time::Instant,
};
enum TrackAction { enum TrackAction {
Pause(u32), Pause(u32),
@@ -282,8 +279,7 @@ impl SoundpadGui {
row.col(|_| {}); row.col(|_| {});
row.col(|ui| { row.col(|ui| {
ui.label( ui.label(
RichText::new("No hotkey slots configured.") RichText::new("No hotkey slots configured.").color(Color32::GRAY),
.color(Color32::GRAY),
); );
}); });
row.col(|_| {}); row.col(|_| {});
@@ -305,8 +301,7 @@ impl SoundpadGui {
.on_hover_text("Key chord conflict"); .on_hover_text("Key chord conflict");
} }
ui.add( ui.add(
Label::new(RichText::new(&slot.slot).monospace()) Label::new(RichText::new(&slot.slot).monospace()).truncate(),
.truncate(),
); );
}); });
}); });
@@ -315,9 +310,7 @@ impl SoundpadGui {
row.col(|ui| { row.col(|ui| {
let action_name = match slot.action.name.as_str() { let action_name = match slot.action.name.as_str() {
"play" => { "play" => {
if let Some(file_path_str) = if let Some(file_path_str) = slot.action.args.get("file_path") {
slot.action.args.get("file_path")
{
Path::new(file_path_str) Path::new(file_path_str)
.file_name() .file_name()
.unwrap_or_default() .unwrap_or_default()
@@ -334,9 +327,7 @@ impl SoundpadGui {
"toggle_loop" => "Toggle Loop".to_string(), "toggle_loop" => "Toggle Loop".to_string(),
other => other.to_string(), other => other.to_string(),
}; };
ui.add( ui.add(Label::new(RichText::new(action_name).monospace()).truncate());
Label::new(RichText::new(action_name).monospace()).truncate(),
);
}); });
// Column 3: Key Chord // Column 3: Key Chord
+56 -1
View File
@@ -3,7 +3,7 @@ mod input;
mod update; mod update;
use eframe::{HardwareAcceleration, NativeOptions, icon_data::from_png_bytes, run_native}; use eframe::{HardwareAcceleration, NativeOptions, icon_data::from_png_bytes, run_native};
use egui::{Context, Vec2, ViewportBuilder}; use egui::{Context, FontData, FontDefinitions, FontFamily, FontTweak, Vec2, ViewportBuilder};
use itertools::Itertools; use itertools::Itertools;
use pwsp::{ use pwsp::{
types::{ types::{
@@ -21,9 +21,11 @@ use pwsp::{
use rfd::FileDialog; use rfd::FileDialog;
use std::{ use std::{
error::Error, error::Error,
fs,
path::{Path, PathBuf}, path::{Path, PathBuf},
sync::{Arc, Mutex}, sync::{Arc, Mutex},
}; };
use system_fonts::{FontStyle, FoundFontSource, find_for_locale};
const SUPPORTED_EXTENSIONS: [&str; 13] = [ const SUPPORTED_EXTENSIONS: [&str; 13] = [
"mp3", "wav", "ogg", "flac", "mp4", "m4a", "aac", "mov", "mkv", "mka", "webm", "avi", "opus", "mp3", "wav", "ogg", "flac", "mp4", "m4a", "aac", "mov", "mkv", "mka", "webm", "avi", "opus",
@@ -196,6 +198,54 @@ impl SoundpadGui {
} }
} }
fn add_font(
font_name: &str,
font_bytes: &[u8],
fonts: &mut FontDefinitions,
) -> Result<(), Box<dyn Error>> {
let font_data = FontData::from_owned(font_bytes.to_vec()).tweak(FontTweak {
scale: 1.0,
hinting_override: Some(true),
..Default::default()
});
fonts
.font_data
.insert(font_name.to_owned(), font_data.into());
fonts
.families
.entry(FontFamily::Proportional)
.or_default()
.insert(0, font_name.to_owned());
fonts
.families
.entry(FontFamily::Monospace)
.or_default()
.insert(0, font_name.to_owned());
Ok(())
}
fn load_system_fonts(fonts: &mut FontDefinitions) -> Result<(), Box<dyn Error>> {
let (_, en_sans) = find_for_locale("en", FontStyle::Sans);
let (_, en_serif) = find_for_locale("en", FontStyle::Serif);
let (_, ja_sans) = find_for_locale("ja", FontStyle::Sans);
let system_fonts = [en_sans, en_serif, ja_sans].concat();
for font in system_fonts.iter().rev() {
let font_bytes = match &font.source {
FoundFontSource::Path(path) => fs::read(path)?,
FoundFontSource::Bytes(bytes) => bytes.to_vec(),
};
add_font(&font.key, &font_bytes, fonts)?;
}
Ok(())
}
pub async fn run() -> Result<(), Box<dyn Error>> { pub async fn run() -> Result<(), Box<dyn Error>> {
const ICON: &[u8] = include_bytes!("../../assets/icon.png"); const ICON: &[u8] = include_bytes!("../../assets/icon.png");
@@ -218,6 +268,11 @@ pub async fn run() -> Result<(), Box<dyn Error>> {
options, options,
Box::new(|cc| { Box::new(|cc| {
egui_material_icons::initialize(&cc.egui_ctx); egui_material_icons::initialize(&cc.egui_ctx);
let mut fonts = FontDefinitions::default();
load_system_fonts(&mut fonts).ok();
cc.egui_ctx.set_fonts(fonts);
Ok(Box::new(SoundpadGui::new(&cc.egui_ctx))) Ok(Box::new(SoundpadGui::new(&cc.egui_ctx)))
}), }),
) { ) {