Skip to content

Commit

Permalink
Choose your own font and size (emilk#1154)
Browse files Browse the repository at this point in the history
* Refactor text layout: don't need &Fonts in all functions
* Replace indexing in Fonts with member function
* Wrap Fonts in a Mutex
* Remove mutex for Font::glyph_info_cache
* Remove RwLock around Font::characters
* Put FontsImpl and GalleyCache behind the same Mutex
* Round font sizes to whole pixels before deduplicating them
* Make TextStyle !Copy
* Implement user-named TextStyle:s
* round font size earlier
* Cache fonts based on family and size
* Move TextStyle into egui and Style
* Remove body_text_style
* Query graphics about max texture size and use that as font atlas size
* Recreate texture atlas when it is getting full
  • Loading branch information
emilk authored Jan 24, 2022
1 parent bb407e9 commit fa43d16
Show file tree
Hide file tree
Showing 67 changed files with 1,195 additions and 604 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
## Unreleased

### Added ⭐
* Much improved font selection ([#1154](https://github.com/emilk/egui/pull/1154)):
* You can now select any font size and family using `RichText::size` amd `RichText::family` and the new `FontId`.
* Easily change text styles with `Style::text_styles`.
* Added `Ui::text_style_height`.
* Added `TextStyle::resolve`.
* `Context::load_texture` to convert an image into a texture which can be displayed using e.g. `ui.image(texture, size)` ([#1110](https://github.com/emilk/egui/pull/1110)).
* Added `Ui::add_visible` and `Ui::add_visible_ui`.
* Added `CollapsingHeader::icon` to override the default open/close icon using a custom function. ([1147](https://github.com/emilk/egui/pull/1147))
Expand All @@ -23,6 +28,10 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* For integrations:
* `FontImage` has been replaced by `TexturesDelta` (found in `Output`), describing what textures were loaded and freed each frame ([#1110](https://github.com/emilk/egui/pull/1110)).
* The painter must support partial texture updates ([#1149](https://github.com/emilk/egui/pull/1149)).
* Added `RawInput::max_texture_side` which should be filled in with e.g. `GL_MAX_TEXTURE_SIZE` ([#1154](https://github.com/emilk/egui/pull/1154)).
* Replaced `Style::body_text_style` with more generic `Style::text_styles` ([#1154](https://github.com/emilk/egui/pull/1154)).
* `TextStyle` is no longer `Copy` ([#1154](https://github.com/emilk/egui/pull/1154)).
* Replaced `TextEdit::text_style` with `TextEdit::font` ([#1154](https://github.com/emilk/egui/pull/1154)).

### Fixed 🐛
* Context menu now respects the theme ([#1043](https://github.com/emilk/egui/pull/1043))
Expand Down Expand Up @@ -533,6 +542,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui_w
* Optimization: coarse culling in the tessellator
* CHANGED: switch argument order of `ui.checkbox` and `ui.radio`


## 0.1.4 - 2020-09-08

This is when I started the CHANGELOG.md, after almost two years of development. Better late than never.
Expand Down
2 changes: 1 addition & 1 deletion eframe/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ NOTE: [`egui_web`](../egui_web/CHANGELOG.md), [`egui-winit`](../egui-winit/CHANG
* The default web painter is now `egui_glow` (instead of WebGL) ([#1020](https://github.com/emilk/egui/pull/1020)).
* Fix horizontal scrolling direction on Linux.
* Added `App::on_exit_event` ([#1038](https://github.com/emilk/egui/pull/1038))
* Shift-scroll will now result in horizontal scrolling on all platforms ((#1136)[https://github.com/emilk/egui/pull/1136]).
* Shift-scroll will now result in horizontal scrolling on all platforms ([#1136](https://github.com/emilk/egui/pull/1136)).


## 0.16.0 - 2021-12-29
Expand Down
4 changes: 2 additions & 2 deletions eframe/examples/custom_font.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ impl epi::App for MyApp {

// Put my font first (highest priority) for proportional text:
fonts
.fonts_for_family
.families
.entry(egui::FontFamily::Proportional)
.or_default()
.insert(0, "my_font".to_owned());

// Put my font as last fallback for monospace:
fonts
.fonts_for_family
.families
.entry(egui::FontFamily::Monospace)
.or_default()
.push("my_font".to_owned());
Expand Down
2 changes: 1 addition & 1 deletion eframe/examples/file_dialog.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ impl MyApp {
screen_rect.center(),
Align2::CENTER_CENTER,
text,
TextStyle::Heading,
TextStyle::Heading.resolve(&ctx.style()),
Color32::WHITE,
);
}
Expand Down
5 changes: 3 additions & 2 deletions egui-winit/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ All notable changes to the `egui-winit` integration will be noted in this file.


## Unreleased
* Fix horizontal scrolling direction on Linux.
* Fixed horizontal scrolling direction on Linux.
* Replaced `std::time::Instant` with `instant::Instant` for WebAssembly compatability ([#1023](https://github.com/emilk/egui/pull/1023))
* Shift-scroll will now result in horizontal scrolling on all platforms ((#1136)[https://github.com/emilk/egui/pull/1136]).
* Shift-scroll will now result in horizontal scrolling on all platforms ([#1136](https://github.com/emilk/egui/pull/1136)).
* Require knowledge about max texture side (e.g. `GL_MAX_TEXTURE_SIZE`)) ([#1154](https://github.com/emilk/egui/pull/1154)).


## 0.16.0 - 2021-12-29
Expand Down
3 changes: 2 additions & 1 deletion egui-winit/src/epi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ pub struct EpiIntegration {
impl EpiIntegration {
pub fn new(
integration_name: &'static str,
max_texture_side: usize,
window: &winit::window::Window,
repaint_signal: std::sync::Arc<dyn epi::backend::RepaintSignal>,
persistence: crate::epi::Persistence,
Expand All @@ -223,7 +224,7 @@ impl EpiIntegration {
frame,
persistence,
egui_ctx,
egui_winit: crate::State::new(window),
egui_winit: crate::State::new(max_texture_side, window),
app,
quit: false,
};
Expand Down
15 changes: 10 additions & 5 deletions egui-winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,17 +129,22 @@ pub struct State {
}

impl State {
/// Initialize with the native `pixels_per_point` (dpi scaling).
pub fn new(window: &winit::window::Window) -> Self {
Self::from_pixels_per_point(native_pixels_per_point(window))
/// Initialize with:
/// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE`
/// * the native `pixels_per_point` (dpi scaling).
pub fn new(max_texture_side: usize, window: &winit::window::Window) -> Self {
Self::from_pixels_per_point(max_texture_side, native_pixels_per_point(window))
}

/// Initialize with a given dpi scaling.
pub fn from_pixels_per_point(pixels_per_point: f32) -> Self {
/// Initialize with:
/// * `max_texture_side`: e.g. `GL_MAX_TEXTURE_SIZE`
/// * the given `pixels_per_point` (dpi scaling).
pub fn from_pixels_per_point(max_texture_side: usize, pixels_per_point: f32) -> Self {
Self {
start_time: instant::Instant::now(),
egui_input: egui::RawInput {
pixels_per_point: Some(pixels_per_point),
max_texture_side,
..Default::default()
},
pointer_pos_in_points: None,
Expand Down
2 changes: 1 addition & 1 deletion egui/src/containers/collapsing_header.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::hash::Hash;

use crate::*;
use epaint::{Shape, TextStyle};
use epaint::Shape;

#[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
Expand Down
2 changes: 1 addition & 1 deletion egui/src/containers/scroll_area.rs
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ impl ScrollArea {
/// ```
/// # egui::__run_test_ui(|ui| {
/// let text_style = egui::TextStyle::Body;
/// let row_height = ui.fonts()[text_style].row_height();
/// let row_height = ui.text_style_height(&text_style);
/// // let row_height = ui.spacing().interact_size.y; // if you are adding buttons instead of labels.
/// let total_rows = 10_000;
/// egui::ScrollArea::vertical().show_rows(ui, row_height, total_rows, |ui, row_range| {
Expand Down
5 changes: 3 additions & 2 deletions egui/src/containers/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ impl<'open> Window<'open> {
.and_then(|window_interaction| {
// Calculate roughly how much larger the window size is compared to the inner rect
let title_bar_height = if with_title_bar {
title.font_height(ctx) + title_content_spacing
let style = ctx.style();
title.font_height(&ctx.fonts(), &style) + title_content_spacing
} else {
0.0
};
Expand Down Expand Up @@ -764,7 +765,7 @@ fn show_title_bar(
) -> TitleBar {
let inner_response = ui.horizontal(|ui| {
let height = title
.font_height(ui.ctx())
.font_height(&ui.fonts(), ui.style())
.max(ui.spacing().interact_size.y);
ui.set_min_height(height);

Expand Down
63 changes: 28 additions & 35 deletions egui/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ impl ContextImpl {
self.input = input.begin_frame(new_raw_input);
self.frame_state.begin_frame(&self.input);

self.update_fonts_mut(self.input.pixels_per_point());
self.update_fonts_mut();

// Ensure we register the background area so panels and background ui can catch clicks:
let screen_rect = self.input.screen_rect();
Expand All @@ -77,27 +77,21 @@ impl ContextImpl {
}

/// Load fonts unless already loaded.
fn update_fonts_mut(&mut self, pixels_per_point: f32) {
let new_font_definitions = self.memory.new_font_definitions.take();
fn update_fonts_mut(&mut self) {
let pixels_per_point = self.input.pixels_per_point();
let max_texture_side = self.input.raw.max_texture_side;

let pixels_per_point_changed = match &self.fonts {
None => true,
Some(current_fonts) => {
(current_fonts.pixels_per_point() - pixels_per_point).abs() > 1e-3
}
};

if self.fonts.is_none() || new_font_definitions.is_some() || pixels_per_point_changed {
self.fonts = Some(Fonts::new(
pixels_per_point,
new_font_definitions.unwrap_or_else(|| {
self.fonts
.as_ref()
.map(|font| font.definitions().clone())
.unwrap_or_default()
}),
));
if let Some(font_definitions) = self.memory.new_font_definitions.take() {
let fonts = Fonts::new(pixels_per_point, max_texture_side, font_definitions);
self.fonts = Some(fonts);
}

let fonts = self.fonts.get_or_insert_with(|| {
let font_definitions = FontDefinitions::default();
Fonts::new(pixels_per_point, max_texture_side, font_definitions)
});

fonts.begin_frame(pixels_per_point, max_texture_side);
}
}

Expand Down Expand Up @@ -521,7 +515,7 @@ impl Context {
pub fn set_fonts(&self, font_definitions: FontDefinitions) {
if let Some(current_fonts) = &*self.fonts_mut() {
// NOTE: this comparison is expensive since it checks TTF data for equality
if current_fonts.definitions() == &font_definitions {
if current_fonts.lock().fonts.definitions() == &font_definitions {
return; // no change - save us from reloading font textures
}
}
Expand Down Expand Up @@ -700,8 +694,6 @@ impl Context {
self.request_repaint();
}

self.fonts().end_frame();

{
let ctx_impl = &mut *self.write();
ctx_impl
Expand Down Expand Up @@ -953,16 +945,6 @@ impl Context {
self.style_ui(ui);
});

CollapsingHeader::new("🔠 Fonts")
.default_open(false)
.show(ui, |ui| {
let mut font_definitions = self.fonts().definitions().clone();
font_definitions.ui(ui);
let font_image_size = self.fonts().font_image_size();
crate::introspection::font_texture_ui(ui, font_image_size);
self.set_fonts(font_definitions);
});

CollapsingHeader::new("✒ Painting")
.default_open(true)
.show(ui, |ui| {
Expand Down Expand Up @@ -1039,6 +1021,13 @@ impl Context {
.show(ui, |ui| {
self.texture_ui(ui);
});

CollapsingHeader::new("🔠 Font texture")
.default_open(false)
.show(ui, |ui| {
let font_image_size = self.fonts().font_image_size();
crate::introspection::font_texture_ui(ui, font_image_size);
});
}

/// Show stats about the allocated textures.
Expand Down Expand Up @@ -1080,8 +1069,12 @@ impl Context {
size *= (max_preview_size.x / size.x).min(1.0);
size *= (max_preview_size.y / size.y).min(1.0);
ui.image(texture_id, size).on_hover_ui(|ui| {
// show full size on hover
ui.image(texture_id, Vec2::new(w as f32, h as f32));
// show larger on hover
let max_size = 0.5 * ui.ctx().input().screen_rect().size();
let mut size = Vec2::new(w as f32, h as f32);
size *= max_size.x / size.x.max(max_size.x);
size *= max_size.y / size.y.max(max_size.y);
ui.image(texture_id, size);
});

ui.label(format!("{} x {}", w, h));
Expand Down
13 changes: 13 additions & 0 deletions egui/src/data/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ pub struct RawInput {
/// Set this the first frame, whenever it changes, or just on every frame.
pub pixels_per_point: Option<f32>,

/// Maximum size of one side of the font texture.
///
/// Ask your graphics drivers about this. This corresponds to `GL_MAX_TEXTURE_SIZE`.
///
/// The default is a very small (but very portable) 2048.
pub max_texture_side: usize,

/// Monotonically increasing time, in seconds. Relative to whatever. Used for animations.
/// If `None` is provided, egui will assume a time delta of `predicted_dt` (default 1/60 seconds).
pub time: Option<f64>,
Expand Down Expand Up @@ -62,6 +69,7 @@ impl Default for RawInput {
Self {
screen_rect: None,
pixels_per_point: None,
max_texture_side: 2048,
time: None,
predicted_dt: 1.0 / 60.0,
modifiers: Modifiers::default(),
Expand All @@ -81,6 +89,7 @@ impl RawInput {
RawInput {
screen_rect: self.screen_rect.take(),
pixels_per_point: self.pixels_per_point.take(),
max_texture_side: self.max_texture_side,
time: self.time.take(),
predicted_dt: self.predicted_dt,
modifiers: self.modifiers,
Expand All @@ -95,6 +104,7 @@ impl RawInput {
let Self {
screen_rect,
pixels_per_point,
max_texture_side,
time,
predicted_dt,
modifiers,
Expand All @@ -105,6 +115,7 @@ impl RawInput {

self.screen_rect = screen_rect.or(self.screen_rect);
self.pixels_per_point = pixels_per_point.or(self.pixels_per_point);
self.max_texture_side = max_texture_side; // use latest
self.time = time; // use latest time
self.predicted_dt = predicted_dt; // use latest dt
self.modifiers = modifiers; // use latest
Expand Down Expand Up @@ -357,6 +368,7 @@ impl RawInput {
let Self {
screen_rect,
pixels_per_point,
max_texture_side,
time,
predicted_dt,
modifiers,
Expand All @@ -370,6 +382,7 @@ impl RawInput {
.on_hover_text(
"Also called HDPI factor.\nNumber of physical pixels per each logical pixel.",
);
ui.label(format!("max_texture_side: {}", max_texture_side));
if let Some(time) = time {
ui.label(format!("time: {:.3} s", time));
} else {
Expand Down
7 changes: 6 additions & 1 deletion egui/src/input_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -700,7 +700,12 @@ impl InputState {
events,
} = self;

ui.style_mut().body_text_style = epaint::TextStyle::Monospace;
ui.style_mut()
.text_styles
.get_mut(&crate::TextStyle::Body)
.unwrap()
.family = crate::FontFamily::Monospace;

ui.collapsing("Raw Input", |ui| raw.ui(ui));

crate::containers::CollapsingHeader::new("🖱 Pointer")
Expand Down
Loading

0 comments on commit fa43d16

Please sign in to comment.