Skip to content

Commit

Permalink
Context::add_font (emilk#5228)
Browse files Browse the repository at this point in the history
make it easier to add fonts. 

For example if I want to add a custom FontFamily or if the user wants to
add a Chinese fallback
* [x] I have followed the instructions in the PR template

---------

Co-authored-by: Emil Ernerfeldt <[email protected]>
  • Loading branch information
2 people authored and hacknus committed Oct 30, 2024
1 parent 3cdfd1b commit 37bb1d8
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 5 deletions.
58 changes: 57 additions & 1 deletion crates/egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use epaint::{
pos2,
stats::PaintStats,
tessellator,
text::Fonts,
text::{FontInsert, FontPriority, Fonts},
util::OrderedFloat,
vec2, ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect,
TessellationOptions, TextureAtlas, TextureId, Vec2,
Expand Down Expand Up @@ -582,6 +582,28 @@ impl ContextImpl {
log::trace!("Loading new font definitions");
}

if !self.memory.add_fonts.is_empty() {
let fonts = self.memory.add_fonts.drain(..);
for font in fonts {
self.fonts.clear(); // recreate all the fonts
for family in font.families {
let fam = self
.font_definitions
.families
.entry(family.family)
.or_default();
match family.priority {
FontPriority::Highest => fam.insert(0, font.name.clone()),
FontPriority::Lowest => fam.push(font.name.clone()),
}
}
self.font_definitions.font_data.insert(font.name, font.data);
}

#[cfg(feature = "log")]
log::trace!("Adding new fonts");
}

let mut is_new = false;

let fonts = self
Expand Down Expand Up @@ -1727,6 +1749,7 @@ impl Context {
/// but you can call this to install additional fonts that support e.g. korean characters.
///
/// The new fonts will become active at the start of the next pass.
/// This will overwrite the existing fonts.
pub fn set_fonts(&self, font_definitions: FontDefinitions) {
crate::profile_function!();

Expand All @@ -1748,6 +1771,39 @@ impl Context {
}
}

/// Tell `egui` which fonts to use.
///
/// The default `egui` fonts only support latin and cyrillic alphabets,
/// but you can call this to install additional fonts that support e.g. korean characters.
///
/// The new font will become active at the start of the next pass.
/// This will keep the existing fonts.
pub fn add_font(&self, new_font: FontInsert) {
crate::profile_function!();

let pixels_per_point = self.pixels_per_point();

let mut update_fonts = true;

self.read(|ctx| {
if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) {
if current_fonts
.lock()
.fonts
.definitions()
.font_data
.contains_key(&new_font.name)
{
update_fonts = false; // no need to update
}
}
});

if update_fonts {
self.memory_mut(|mem| mem.add_fonts.push(new_font));
}
}

/// Does the OS use dark or light mode?
/// This is used when the theme preference is set to [`crate::ThemePreference::System`].
pub fn system_theme(&self) -> Option<Theme> {
Expand Down
5 changes: 5 additions & 0 deletions crates/egui/src/memory/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ pub struct Memory {
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) new_font_definitions: Option<epaint::text::FontDefinitions>,

/// add new font that will be applied at the start of the next frame
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) add_fonts: Vec<epaint::text::FontInsert>,

// Current active viewport
#[cfg_attr(feature = "persistence", serde(skip))]
pub(crate) viewport_id: ViewportId,
Expand Down Expand Up @@ -119,6 +123,7 @@ impl Default for Memory {
layer_transforms: Default::default(),
popup: Default::default(),
everything_is_visible: Default::default(),
add_fonts: Default::default(),
};
slf.interactions.entry(slf.viewport_id).or_default();
slf.areas.entry(slf.viewport_id).or_default();
Expand Down
44 changes: 44 additions & 0 deletions crates/epaint/src/text/fonts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,50 @@ pub struct FontDefinitions {
pub families: BTreeMap<FontFamily, Vec<String>>,
}

#[derive(Debug, Clone)]
pub struct FontInsert {
/// Font name
pub name: String,

/// A `.ttf` or `.otf` file and a font face index.
pub data: FontData,

/// Sets the font family and priority
pub families: Vec<InsertFontFamily>,
}

#[derive(Debug, Clone)]
pub struct InsertFontFamily {
/// Font family
pub family: FontFamily,

/// Fallback or Primary font
pub priority: FontPriority,
}

#[derive(Debug, Clone)]
pub enum FontPriority {
/// Prefer this font before all existing ones.
///
/// If a desired glyph exists in this font, it will be used.
Highest,

/// Use this font as a fallback, after all existing ones.
///
/// This font will only be used if the glyph is not found in any of the previously installed fonts.
Lowest,
}

impl FontInsert {
pub fn new(name: &str, data: FontData, families: Vec<InsertFontFamily>) -> Self {
Self {
name: name.to_owned(),
data,
families,
}
}
}

impl Default for FontDefinitions {
/// Specifies the default fonts if the feature `default_fonts` is enabled,
/// otherwise this is the same as [`Self::empty`].
Expand Down
5 changes: 4 additions & 1 deletion crates/epaint/src/text/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ mod text_layout_types;
pub const TAB_SIZE: usize = 4;

pub use {
fonts::{FontData, FontDefinitions, FontFamily, FontId, FontTweak, Fonts, FontsImpl},
fonts::{
FontData, FontDefinitions, FontFamily, FontId, FontInsert, FontPriority, FontTweak, Fonts,
FontsImpl, InsertFontFamily,
},
text_layout::layout,
text_layout_types::*,
};
Expand Down
31 changes: 28 additions & 3 deletions examples/custom_font/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] // hide console window on Windows in release
#![allow(rustdoc::missing_crate_level_docs)] // it's an example

use eframe::egui;
use eframe::{
egui,
epaint::text::{FontInsert, InsertFontFamily},
};

fn main() -> eframe::Result {
env_logger::init(); // Log to stderr (if you run with `RUST_LOG=debug`).
Expand All @@ -16,7 +19,28 @@ fn main() -> eframe::Result {
)
}

fn setup_custom_fonts(ctx: &egui::Context) {
// Demonstrates how to add a font to the existing ones
fn add_font(ctx: &egui::Context) {
ctx.add_font(FontInsert::new(
"my_font",
egui::FontData::from_static(include_bytes!(
"../../../crates/epaint_default_fonts/fonts/Hack-Regular.ttf"
)),
vec![
InsertFontFamily {
family: egui::FontFamily::Proportional,
priority: egui::epaint::text::FontPriority::Highest,
},
InsertFontFamily {
family: egui::FontFamily::Monospace,
priority: egui::epaint::text::FontPriority::Lowest,
},
],
));
}

// Demonstrates how to replace all fonts.
fn replace_fonts(ctx: &egui::Context) {
// Start with the default fonts (we will be adding to them rather than replacing them).
let mut fonts = egui::FontDefinitions::default();

Expand Down Expand Up @@ -53,7 +77,8 @@ struct MyApp {

impl MyApp {
fn new(cc: &eframe::CreationContext<'_>) -> Self {
setup_custom_fonts(&cc.egui_ctx);
replace_fonts(&cc.egui_ctx);
add_font(&cc.egui_ctx);
Self {
text: "Edit this text field if you want".to_owned(),
}
Expand Down

0 comments on commit 37bb1d8

Please sign in to comment.