Skip to content

Commit

Permalink
Merge pull request #623 from woelper/system_fonts
Browse files Browse the repository at this point in the history
System fonts
  • Loading branch information
woelper authored Jan 20, 2025
2 parents 0da6296 + 37235c1 commit eeffcb5
Show file tree
Hide file tree
Showing 8 changed files with 541 additions and 367 deletions.
592 changes: 356 additions & 236 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ sysinfo = "0.33.1"
dicom-pixeldata = { version = "0.8.0", features = ["image"] }
dicom-object = "0.8.0"
unicode-segmentation = "1.12.0"
font-kit = "0.14.2"

[features]
default = [
Expand Down
Binary file removed res/fonts/NotoNaskhArabic-Regular.ttf
Binary file not shown.
Binary file removed res/fonts/NotoSansJP-Regular.ttf
Binary file not shown.
Binary file removed res/fonts/NotoSansSC-Regular.ttf
Binary file not shown.
37 changes: 3 additions & 34 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ fn init(_app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteSt
// Set up egui style / theme
plugins.egui(|ctx| {
// FIXME: Wait for https://github.com/Nazariglez/notan/issues/315 to close, then remove

let mut fonts = FontDefinitions::default();

egui_extras::install_image_loaders(ctx);

ctx.options_mut(|o| o.zoom_with_keyboard = false);
Expand Down Expand Up @@ -349,40 +349,9 @@ fn init(_app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) -> OculanteSt
.unwrap()
.insert(0, "inter".to_owned());

fonts.font_data.insert(
"noto_jp".to_owned(),
FontData::from_static(include_bytes!("../res/fonts/NotoSansJP-Regular.ttf")),
);

fonts
.families
.get_mut(&FontFamily::Proportional)
.unwrap()
.insert(2, "noto_jp".to_owned());

let fonts = load_system_fonts(fonts);

fonts.font_data.insert(
"noto_ar".to_owned(),
FontData::from_static(include_bytes!("../res/fonts/NotoNaskhArabic-Regular.ttf")),
);

fonts
.families
.get_mut(&FontFamily::Proportional)
.unwrap()
.insert(2, "noto_ar".to_owned());

#[cfg(feature = "lang_support")]
{
fonts.font_data.insert(
"noto_sc".to_owned(),
FontData::from_static(include_bytes!("../res/fonts/NotoSansSC-Regular.ttf")),
);
fonts
.families
.get_mut(&FontFamily::Proportional)
.unwrap()
.insert(2, "noto_sc".to_owned());
}

debug!("Theme {:?}", state.persistent_settings.theme);
apply_theme(&mut state, ctx);
Expand Down
99 changes: 2 additions & 97 deletions src/ui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ mod top_bar;
pub use top_bar::*;
mod edit_ui;
pub use edit_ui::edit_ui;
mod theme;
pub use theme::*;

#[cfg(feature = "file_open")]
use crate::filebrowser::browse_for_image_path;
Expand Down Expand Up @@ -866,104 +868,7 @@ pub fn blank_icon(
) {
}

pub fn apply_theme(state: &mut OculanteState, ctx: &Context) {
let mut button_color = Color32::from_hex("#262626").unwrap_or_default();
let mut panel_color = Color32::from_gray(25);

match state.persistent_settings.theme {
ColorTheme::Light => ctx.set_visuals(Visuals::light()),
ColorTheme::Dark => ctx.set_visuals(Visuals::dark()),
ColorTheme::System => set_system_theme(ctx),
}

// Switching theme resets accent color, set it again
let mut style: egui::Style = (*ctx.style()).clone();
style.spacing.scroll = egui::style::ScrollStyle::solid();

if style.visuals.dark_mode {
// Text color for label
style.visuals.widgets.noninteractive.fg_stroke.color =
Color32::from_hex("#CCCCCC").unwrap_or_default();
// Text color for buttons
style.visuals.widgets.inactive.fg_stroke.color =
Color32::from_hex("#CCCCCC").unwrap_or_default();
style.visuals.extreme_bg_color = Color32::from_hex("#0D0D0D").unwrap_or_default();
if state.persistent_settings.background_color == [200, 200, 200] {
state.persistent_settings.background_color =
PersistentSettings::default().background_color;
}
if state.persistent_settings.accent_color == [0, 170, 255] {
state.persistent_settings.accent_color = PersistentSettings::default().accent_color;
}
} else {
style.visuals.extreme_bg_color = Color32::from_hex("#D9D9D9").unwrap_or_default();
// Text color for label
style.visuals.widgets.noninteractive.fg_stroke.color =
Color32::from_hex("#333333").unwrap_or_default();
// Text color for buttons
style.visuals.widgets.inactive.fg_stroke.color =
Color32::from_hex("#333333").unwrap_or_default();

button_color = Color32::from_gray(255);
panel_color = Color32::from_gray(230);
if state.persistent_settings.background_color
== PersistentSettings::default().background_color
{
state.persistent_settings.background_color = [200, 200, 200];
}
if state.persistent_settings.accent_color == PersistentSettings::default().accent_color {
state.persistent_settings.accent_color = [0, 170, 255];
}
style.visuals.widgets.inactive.bg_fill = Color32::WHITE;
style.visuals.widgets.hovered.bg_fill = Color32::WHITE.gamma_multiply(0.8);
}
style.interaction.tooltip_delay = 0.0;
style.spacing.icon_width = 20.;
style.spacing.window_margin = 5.0.into();
style.spacing.item_spacing = vec2(8., 6.);
style.spacing.icon_width_inner = style.spacing.icon_width / 1.5;
style.spacing.interact_size.y = BUTTON_HEIGHT_SMALL;
style.visuals.window_fill = panel_color;

// button color
style.visuals.widgets.inactive.weak_bg_fill = button_color;
// style.visuals.widgets.inactive.bg_fill = button_color;
// style.visuals.widgets.inactive.bg_fill = button_color;

// button rounding
style.visuals.widgets.inactive.rounding = Rounding::same(4.);
style.visuals.widgets.active.rounding = Rounding::same(4.);
style.visuals.widgets.hovered.rounding = Rounding::same(4.);

// No stroke on buttons
style.visuals.widgets.hovered.bg_stroke = Stroke::NONE;

style.visuals.warn_fg_color = Color32::from_rgb(255, 204, 0);

style.visuals.panel_fill = panel_color;

style.text_styles.get_mut(&TextStyle::Body).unwrap().size = 15.;
style.text_styles.get_mut(&TextStyle::Button).unwrap().size = 15.;
style.text_styles.get_mut(&TextStyle::Small).unwrap().size = 12.;
style.text_styles.get_mut(&TextStyle::Heading).unwrap().size = 18.;
// accent color
style.visuals.selection.bg_fill = Color32::from_rgb(
state.persistent_settings.accent_color[0],
state.persistent_settings.accent_color[1],
state.persistent_settings.accent_color[2],
);

let accent_color = style.visuals.selection.bg_fill.to_array();

let accent_color_luma = (accent_color[0] as f32 * 0.299
+ accent_color[1] as f32 * 0.587
+ accent_color[2] as f32 * 0.114)
.clamp(0., 255.) as u8;
let accent_color_luma = if accent_color_luma < 80 { 220 } else { 80 };
// Set text on highlighted elements
style.visuals.selection.stroke = Stroke::new(2.0, Color32::from_gray(accent_color_luma));
ctx.set_style(style);
}

fn caret_icon(ui: &mut egui::Ui, openness: f32, response: &egui::Response) {
let galley = ui.ctx().fonts(|fonts| {
Expand Down
179 changes: 179 additions & 0 deletions src/ui/theme.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
use super::*;
use crate::appstate::OculanteState;
use std::{collections::HashMap, fs::read};
use egui::{Context, FontData, FontDefinitions};
use epaint::FontFamily;
use font_kit::{
family_name::FamilyName, handle::Handle, properties::Properties, source::SystemSource
};

pub fn apply_theme(state: &mut OculanteState, ctx: &Context) {
let mut button_color = Color32::from_hex("#262626").unwrap_or_default();
let mut panel_color = Color32::from_gray(25);

match state.persistent_settings.theme {
ColorTheme::Light => ctx.set_visuals(Visuals::light()),
ColorTheme::Dark => ctx.set_visuals(Visuals::dark()),
ColorTheme::System => set_system_theme(ctx),
}

// Switching theme resets accent color, set it again
let mut style: egui::Style = (*ctx.style()).clone();
style.spacing.scroll = egui::style::ScrollStyle::solid();

if style.visuals.dark_mode {
// Text color for label
style.visuals.widgets.noninteractive.fg_stroke.color =
Color32::from_hex("#CCCCCC").unwrap_or_default();
// Text color for buttons
style.visuals.widgets.inactive.fg_stroke.color =
Color32::from_hex("#CCCCCC").unwrap_or_default();
style.visuals.extreme_bg_color = Color32::from_hex("#0D0D0D").unwrap_or_default();
if state.persistent_settings.background_color == [200, 200, 200] {
state.persistent_settings.background_color =
PersistentSettings::default().background_color;
}
if state.persistent_settings.accent_color == [0, 170, 255] {
state.persistent_settings.accent_color = PersistentSettings::default().accent_color;
}
} else {
style.visuals.extreme_bg_color = Color32::from_hex("#D9D9D9").unwrap_or_default();
// Text color for label
style.visuals.widgets.noninteractive.fg_stroke.color =
Color32::from_hex("#333333").unwrap_or_default();
// Text color for buttons
style.visuals.widgets.inactive.fg_stroke.color =
Color32::from_hex("#333333").unwrap_or_default();

button_color = Color32::from_gray(255);
panel_color = Color32::from_gray(230);
if state.persistent_settings.background_color
== PersistentSettings::default().background_color
{
state.persistent_settings.background_color = [200, 200, 200];
}
if state.persistent_settings.accent_color == PersistentSettings::default().accent_color {
state.persistent_settings.accent_color = [0, 170, 255];
}
style.visuals.widgets.inactive.bg_fill = Color32::WHITE;
style.visuals.widgets.hovered.bg_fill = Color32::WHITE.gamma_multiply(0.8);
}
style.interaction.tooltip_delay = 0.0;
style.spacing.icon_width = 20.;
style.spacing.window_margin = 5.0.into();
style.spacing.item_spacing = vec2(8., 6.);
style.spacing.icon_width_inner = style.spacing.icon_width / 1.5;
style.spacing.interact_size.y = BUTTON_HEIGHT_SMALL;
style.visuals.window_fill = panel_color;

// button color
style.visuals.widgets.inactive.weak_bg_fill = button_color;
// style.visuals.widgets.inactive.bg_fill = button_color;
// style.visuals.widgets.inactive.bg_fill = button_color;

// button rounding
style.visuals.widgets.inactive.rounding = Rounding::same(4.);
style.visuals.widgets.active.rounding = Rounding::same(4.);
style.visuals.widgets.hovered.rounding = Rounding::same(4.);

// No stroke on buttons
style.visuals.widgets.hovered.bg_stroke = Stroke::NONE;

style.visuals.warn_fg_color = Color32::from_rgb(255, 204, 0);

style.visuals.panel_fill = panel_color;

style.text_styles.get_mut(&TextStyle::Body).unwrap().size = 15.;
style.text_styles.get_mut(&TextStyle::Button).unwrap().size = 15.;
style.text_styles.get_mut(&TextStyle::Small).unwrap().size = 12.;
style.text_styles.get_mut(&TextStyle::Heading).unwrap().size = 18.;
// accent color
style.visuals.selection.bg_fill = Color32::from_rgb(
state.persistent_settings.accent_color[0],
state.persistent_settings.accent_color[1],
state.persistent_settings.accent_color[2],
);

let accent_color = style.visuals.selection.bg_fill.to_array();

let accent_color_luma = (accent_color[0] as f32 * 0.299
+ accent_color[1] as f32 * 0.587
+ accent_color[2] as f32 * 0.114)
.clamp(0., 255.) as u8;
let accent_color_luma = if accent_color_luma < 80 { 220 } else { 80 };
// Set text on highlighted elements
style.visuals.selection.stroke = Stroke::new(2.0, Color32::from_gray(accent_color_luma));
ctx.set_style(style);
}


/// Attempt to load a system font by any of the given `family_names`, returning the first match.
fn load_font_family(family_names: &[&str]) -> Option<Vec<u8>> {
let system_source = SystemSource::new();

for &name in family_names {
let font_handle = system_source
.select_best_match(&[FamilyName::Title(name.to_string())], &Properties::new());
match font_handle {
Ok(h) => {
match &h {
Handle::Memory { bytes, .. } => {
debug!("Loaded {name} from memory.");
return Some(bytes.to_vec());
}
Handle::Path { path, .. } => {
info!("Loaded {name} from path: {:?}", path);
if let Ok(data) = read(path) {
return Some(data);
}
}
}
}
Err(e) => error!("Could not load {}: {:?}", name, e),
}
}

None
}

pub fn load_system_fonts(mut fonts: FontDefinitions) -> FontDefinitions{
debug!("Attempting to load sys fonts");
let mut fontdb = HashMap::new();

fontdb.insert("chinese_simplified", vec![
"Heiti SC",
"Songti SC",
"Noto Sans CJK SC", // Good coverage for Simplified Chinese
"Noto Sans SC",
"Noto Sans CJK JP",
"Noto Sans JP",
"WenQuanYi Zen Hei",
"SimSun",
"MS Gothic",
"Noto Sans SC",
"PingFang SC",
]);

fontdb.insert("arabic", vec![
"Noto Sans Arabic",
"Amiri",
"Lateef",
"Al Tarikh",
"Segoe UI",
]);

for (region, font_names) in fontdb {
if let Some(font_data) = load_font_family(&font_names) {
info!("Inserting font {region}");
fonts
.font_data
.insert(region.to_owned(), FontData::from_owned(font_data));

fonts.families
.get_mut(&FontFamily::Proportional)
.unwrap()
.push(region.to_owned());
}
}
fonts
}

0 comments on commit eeffcb5

Please sign in to comment.