1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-30 21:30:03 -04:00

Allow resizing fonts at runtime

This commit is contained in:
Emil Ernerfeldt
2019-01-17 11:03:39 -06:00
parent fe3542a28d
commit 88fdd127ea
9 changed files with 156 additions and 57 deletions

View File

@@ -3,10 +3,12 @@ use std::sync::Arc;
use crate::{
layout,
layout::{LayoutOptions, Region},
math::vec2,
mesher::Vertex,
style,
types::GuiInput,
types::{Color, GuiCmd, GuiInput, PaintCmd},
widgets::*,
Frame, RawInput, Texture,
FontSizes, Fonts, Frame, RawInput, Texture,
};
#[derive(Clone, Copy, Default)]
@@ -37,6 +39,12 @@ fn show_style(style: &mut style::Style, gui: &mut Region) {
gui.add(Slider::new(&mut style.line_width, 0.0, 10.0).text("line_width"));
}
fn show_font_sizes(font_sizes: &mut FontSizes, gui: &mut Region) {
for (text_style, mut size) in font_sizes {
gui.add(Slider::new(&mut size, 4.0, 40.0).text(format!("{:?}", text_style)));
}
}
/// Encapsulates input, layout and painting for ease of use.
pub struct Emigui {
pub last_input: RawInput,
@@ -103,6 +111,39 @@ impl Emigui {
show_style(&mut self.style, gui);
});
region.foldable("Fonts", |gui| {
let texture = self.texture();
gui.add(label(format!(
"Font texture size: {} x {}",
texture.width, texture.height
)));
let size = vec2(texture.width as f32, texture.height as f32);
let rect = gui.reserve_space(size, None).rect;
let top_left = Vertex {
pos: rect.min(),
uv: (0, 0),
color: Color::WHITE,
};
let bottom_right = Vertex {
pos: rect.max(),
uv: (texture.width as u16 - 1, texture.height as u16 - 1),
color: Color::WHITE,
};
let mut frame = Frame::default();
frame.add_rect(top_left, bottom_right);
gui.add_graphic(GuiCmd::PaintCommands(vec![PaintCmd::Frame(frame)]));
let old_font_sizes = self.data.fonts.sizes();
let mut new_font_sizes = old_font_sizes.clone();
show_font_sizes(&mut new_font_sizes, gui);
if *old_font_sizes != new_font_sizes {
let mut new_data = (*self.data).clone();
let fonts = Fonts::from_sizes(new_font_sizes);
new_data.fonts = Arc::new(fonts);
self.data = Arc::new(new_data);
}
});
region.foldable("Stats", |gui| {
gui.add(label(format!("num_vertices: {}", self.stats.num_vertices)));
gui.add(label(format!(

View File

@@ -1,5 +1,6 @@
use std::{
collections::BTreeMap,
collections::{hash_map::DefaultHasher, BTreeMap},
hash::{Hash, Hasher},
sync::{Arc, Mutex},
};
@@ -9,7 +10,7 @@ use crate::{
};
/// TODO: rename
#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum TextStyle {
Body,
Button,
@@ -17,14 +18,43 @@ pub enum TextStyle {
// Monospace,
}
pub type FontSizes = BTreeMap<TextStyle, f32>;
pub struct Fonts {
sizes: FontSizes,
fonts: BTreeMap<TextStyle, Font>,
texture: Texture,
}
impl Fonts {
pub fn new() -> Fonts {
let mut atlas = TextureAtlas::new(128, 8); // TODO: better default?
let mut sizes = FontSizes::new();
sizes.insert(TextStyle::Body, 20.0);
sizes.insert(TextStyle::Button, 20.0);
sizes.insert(TextStyle::Heading, 30.0);
Fonts::from_sizes(sizes)
}
pub fn from_sizes(sizes: FontSizes) -> Fonts {
let mut fonts = Fonts {
sizes: Default::default(),
fonts: Default::default(),
texture: Default::default(),
};
fonts.set_sizes(sizes);
fonts
}
pub fn sizes(&self) -> &FontSizes {
&self.sizes
}
pub fn set_sizes(&mut self, sizes: FontSizes) {
if self.sizes == sizes {
return;
}
let mut atlas = TextureAtlas::new(512, 8); // TODO: better default?
// Make one white pixel for use for various stuff:
let pos = atlas.allocate((1, 1));
@@ -32,25 +62,20 @@ impl Fonts {
let atlas = Arc::new(Mutex::new(atlas));
// TODO: figure out a way to make the wasm smaller despite including a font.
// TODO: figure out a way to make the wasm smaller despite including a font. Zip it?
// let typeface_data = include_bytes!("../fonts/ProggyClean.ttf"); // Use 13 for this. NOTHING ELSE.
// let typeface_data = include_bytes!("../fonts/DejaVuSans.ttf");
let typeface_data = include_bytes!("../fonts/Roboto-Regular.ttf");
self.sizes = sizes.clone();
self.fonts = sizes
.into_iter()
.map(|(text_style, size)| (text_style, Font::new(atlas.clone(), typeface_data, size)))
.collect();
self.texture = atlas.lock().unwrap().texture().clone();
let mut fonts = BTreeMap::new();
fonts.insert(
TextStyle::Body,
Font::new(atlas.clone(), typeface_data, 20.0),
);
fonts.insert(TextStyle::Button, fonts[&TextStyle::Body].clone());
fonts.insert(
TextStyle::Heading,
Font::new(atlas.clone(), typeface_data, 30.0),
);
let texture = atlas.lock().unwrap().clone().texture().clone();
Fonts { fonts, texture }
let mut hasher = DefaultHasher::new();
self.texture.pixels.hash(&mut hasher);
self.texture.id = hasher.finish();
}
pub fn texture(&self) -> &Texture {

View File

@@ -428,10 +428,10 @@ impl Region {
/// Temporarily split split a vertical layout into several columns.
///
/// gui.columns(2, |columns| {
/// columns[0].add(label("First column"));
/// columns[1].add(label("Second column"));
/// });
/// region.columns(2, |columns| {
/// columns[0].add(emigui::widgets::label("First column"));
/// columns[1].add(emigui::widgets::label("Second column"));
/// });
pub fn columns<F, R>(&mut self, num_columns: usize, add_contents: F) -> R
where
F: FnOnce(&mut [Region]) -> R,

View File

@@ -19,7 +19,7 @@ pub mod widgets;
pub use crate::{
emigui::Emigui,
fonts::TextStyle,
fonts::{FontSizes, Fonts, TextStyle},
layout::{Align, LayoutOptions, Region},
mesher::{Frame, Vertex},
style::Style,

View File

@@ -8,7 +8,7 @@ use crate::{
types::{Color, PaintCmd},
};
#[derive(Clone, Copy, Debug, Default)]
#[derive(Clone, Copy, Debug, Default, Serialize)]
pub struct Vertex {
/// Pixel coordinates
pub pos: Vec2,
@@ -18,7 +18,7 @@ pub struct Vertex {
pub color: Color,
}
#[derive(Clone, Debug, Default)]
#[derive(Clone, Debug, Default, Serialize)]
pub struct Frame {
/// Draw as triangles (i.e. the length is a multiple of three)
pub indices: Vec<u32>,
@@ -33,6 +33,14 @@ pub enum PathType {
use self::PathType::*;
impl Frame {
pub fn append(&mut self, frame: &Frame) {
let index_offset = self.vertices.len() as u32;
for index in &frame.indices {
self.indices.push(index_offset + index);
}
self.vertices.extend(frame.vertices.iter());
}
fn triangle(&mut self, a: u32, b: u32, c: u32) {
self.indices.push(a);
self.indices.push(b);
@@ -224,6 +232,9 @@ impl Frame {
);
}
}
PaintCmd::Frame(cmd_frame) => {
frame.append(cmd_frame);
}
PaintCmd::Line {
points,
color,

View File

@@ -53,9 +53,15 @@ impl TextureAtlas {
}
pub fn texture_mut(&mut self) -> &mut Texture {
self.texture.id += 1;
&mut self.texture
}
pub fn clear(&mut self) {
self.cursor = (0, 0);
self.row_height = 0;
}
/// Returns the coordinates of where the rect ended up.
pub fn allocate(&mut self, (w, h): (usize, usize)) -> (usize, usize) {
assert!(w <= self.texture.width);
@@ -79,7 +85,7 @@ impl TextureAtlas {
let pos = self.cursor;
self.cursor.0 += w;
self.texture.id += 1; // TODO: hash this ?
self.texture.id += 1;
(pos.0 as usize, pos.1 as usize)
}
}

View File

@@ -1,6 +1,7 @@
use crate::{
fonts::TextStyle,
math::{Rect, Vec2},
mesher::Frame,
};
// ----------------------------------------------------------------------------
@@ -152,6 +153,7 @@ pub enum PaintCmd {
outline: Option<Outline>,
radius: f32,
},
Frame(Frame),
Line {
points: Vec<Vec2>,
color: Color,