Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Context::add_font #5228

Merged
merged 14 commits into from
Oct 23, 2024
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,
frederik-uni marked this conversation as resolved.
Show resolved Hide resolved

/// 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) {
frederik-uni marked this conversation as resolved.
Show resolved Hide resolved
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) {
frederik-uni marked this conversation as resolved.
Show resolved Hide resolved
// 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
Loading