refactor fonts: put TextStyle in Galley instead of in Shape::Text

This commit is contained in:
Emil Ernerfeldt 2021-03-29 21:24:09 +02:00
parent ade41403b5
commit d4e5133da2
14 changed files with 61 additions and 50 deletions

View file

@ -262,12 +262,7 @@ impl CollapsingHeader {
paint_icon(ui, openness, &icon_response); paint_icon(ui, openness, &icon_response);
} }
ui.painter().galley( ui.painter().galley(text_pos, galley, text_color);
text_pos,
galley,
label.text_style_or_default(ui.style()),
text_color,
);
Prepared { Prepared {
id, id,

View file

@ -179,8 +179,9 @@ fn combo_box(
let full_minimum_width = ui.spacing().slider_width; let full_minimum_width = ui.spacing().slider_width;
let icon_size = Vec2::splat(ui.spacing().icon_width); let icon_size = Vec2::splat(ui.spacing().icon_width);
let text_style = TextStyle::Button; let galley = ui
let galley = ui.fonts().layout_no_wrap(text_style, selected.into()); .fonts()
.layout_no_wrap(TextStyle::Button, selected.into());
let width = galley.size.x + ui.spacing().item_spacing.x + icon_size.x; let width = galley.size.x + ui.spacing().item_spacing.x + icon_size.x;
let width = width.at_least(full_minimum_width); let width = width.at_least(full_minimum_width);
@ -197,7 +198,7 @@ fn combo_box(
let text_rect = Align2::LEFT_CENTER.align_size_within_rect(galley.size, rect); let text_rect = Align2::LEFT_CENTER.align_size_within_rect(galley.size, rect);
ui.painter() ui.painter()
.galley(text_rect.min, galley, text_style, visuals.text_color()); .galley(text_rect.min, galley, visuals.text_color());
}); });
if button_response.clicked() { if button_response.clicked() {

View file

@ -172,10 +172,11 @@ impl Painter {
} }
pub fn error(&self, pos: Pos2, text: impl std::fmt::Display) -> Rect { pub fn error(&self, pos: Pos2, text: impl std::fmt::Display) -> Rect {
let text_style = TextStyle::Monospace; let galley = self.fonts().layout_multiline(
let galley = TextStyle::Monospace,
self.fonts() format!("🔥 {}", text),
.layout_multiline(text_style, format!("🔥 {}", text), f32::INFINITY); f32::INFINITY,
);
let rect = Align2::LEFT_TOP.anchor_rect(Rect::from_min_size(pos, galley.size)); let rect = Align2::LEFT_TOP.anchor_rect(Rect::from_min_size(pos, galley.size));
let frame_rect = rect.expand(2.0); let frame_rect = rect.expand(2.0);
self.add(Shape::Rect { self.add(Shape::Rect {
@ -184,7 +185,7 @@ impl Painter {
fill: Color32::from_black_alpha(240), fill: Color32::from_black_alpha(240),
stroke: Stroke::new(1.0, Color32::RED), stroke: Stroke::new(1.0, Color32::RED),
}); });
self.galley(rect.min, galley, text_style, Color32::RED); self.galley(rect.min, galley, Color32::RED);
frame_rect frame_rect
} }
} }
@ -296,27 +297,25 @@ impl Painter {
.fonts() .fonts()
.layout_multiline(text_style, text.into(), f32::INFINITY); .layout_multiline(text_style, text.into(), f32::INFINITY);
let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size)); let rect = anchor.anchor_rect(Rect::from_min_size(pos, galley.size));
self.galley(rect.min, galley, text_style, text_color); self.galley(rect.min, galley, text_color);
rect rect
} }
/// Paint text that has already been layed out in a `Galley`. /// Paint text that has already been layed out in a `Galley`.
pub fn galley(&self, pos: Pos2, galley: Galley, text_style: TextStyle, color: Color32) { pub fn galley(&self, pos: Pos2, galley: Galley, color: Color32) {
self.galley_with_italics(pos, galley, text_style, color, false) self.galley_with_italics(pos, galley, color, false)
} }
pub fn galley_with_italics( pub fn galley_with_italics(
&self, &self,
pos: Pos2, pos: Pos2,
galley: Galley, galley: Galley,
text_style: TextStyle,
color: Color32, color: Color32,
fake_italics: bool, fake_italics: bool,
) { ) {
self.add(Shape::Text { self.add(Shape::Text {
pos, pos,
galley, galley,
text_style,
color, color,
fake_italics, fake_italics,
}); });

View file

@ -141,8 +141,7 @@ impl Button {
let text_color = text_color let text_color = text_color
.or(ui.visuals().override_text_color) .or(ui.visuals().override_text_color)
.unwrap_or_else(|| visuals.text_color()); .unwrap_or_else(|| visuals.text_color());
ui.painter() ui.painter().galley(text_cursor, galley, text_color);
.galley(text_cursor, galley, text_style, text_color);
} }
response response
@ -264,8 +263,7 @@ impl<'a> Widget for Checkbox<'a> {
let text_color = text_color let text_color = text_color
.or(ui.visuals().override_text_color) .or(ui.visuals().override_text_color)
.unwrap_or_else(|| visuals.text_color()); .unwrap_or_else(|| visuals.text_color());
ui.painter() ui.painter().galley(text_cursor, galley, text_color);
.galley(text_cursor, galley, text_style, text_color);
response response
} }
} }
@ -373,7 +371,7 @@ impl Widget for RadioButton {
let text_color = text_color let text_color = text_color
.or(ui.visuals().override_text_color) .or(ui.visuals().override_text_color)
.unwrap_or_else(|| visuals.text_color()); .unwrap_or_else(|| visuals.text_color());
painter.galley(text_cursor, galley, text_style, text_color); painter.galley(text_cursor, galley, text_color);
response response
} }
} }

View file

@ -163,7 +163,7 @@ impl Label {
pub fn font_height(&self, fonts: &epaint::text::Fonts, style: &Style) -> f32 { pub fn font_height(&self, fonts: &epaint::text::Fonts, style: &Style) -> f32 {
let text_style = self.text_style_or_default(style); let text_style = self.text_style_or_default(style);
fonts[text_style].row_height() fonts.row_height(text_style)
} }
// TODO: this should return a LabelLayout which has a paint method. // TODO: this should return a LabelLayout which has a paint method.
@ -234,9 +234,8 @@ impl Label {
} }
} }
let text_style = self.text_style_or_default(ui.style());
ui.painter() ui.painter()
.galley_with_italics(pos, galley, text_style, text_color, italics); .galley_with_italics(pos, galley, text_color, italics);
ui.painter().extend(lines); ui.painter().extend(lines);
} }

View file

@ -661,7 +661,6 @@ impl Prepared {
shapes.push(Shape::Text { shapes.push(Shape::Text {
pos: text_pos, pos: text_pos,
galley, galley,
text_style,
color: ui.visuals().text_color(), color: ui.visuals().text_color(),
fake_italics: false, fake_italics: false,
}); });

View file

@ -78,8 +78,7 @@ impl Widget for SelectableLabel {
.visuals .visuals
.override_text_color .override_text_color
.unwrap_or_else(|| visuals.text_color()); .unwrap_or_else(|| visuals.text_color());
ui.painter() ui.painter().galley(text_cursor, galley, text_color);
.galley(text_cursor, galley, text_style, text_color);
response response
} }
} }

View file

@ -513,8 +513,7 @@ impl<'t> TextEdit<'t> {
.or(ui.visuals().override_text_color) .or(ui.visuals().override_text_color)
// .unwrap_or_else(|| ui.style().interact(&response).text_color()); // too bright // .unwrap_or_else(|| ui.style().interact(&response).text_color()); // too bright
.unwrap_or_else(|| ui.visuals().widgets.inactive.text_color()); .unwrap_or_else(|| ui.visuals().widgets.inactive.text_color());
ui.painter() ui.painter().galley(response.rect.min, galley, text_color);
.galley(response.rect.min, galley, text_style, text_color);
if text.is_empty() && !hint_text.is_empty() { if text.is_empty() && !hint_text.is_empty() {
let galley = if multiline { let galley = if multiline {
@ -525,7 +524,7 @@ impl<'t> TextEdit<'t> {
}; };
let hint_text_color = ui.visuals().weak_text_color(); let hint_text_color = ui.visuals().weak_text_color();
ui.painter() ui.painter()
.galley(response.rect.min, galley, text_style, hint_text_color); .galley(response.rect.min, galley, hint_text_color);
} }
ui.memory().text_edit.insert(id, state); ui.memory().text_edit.insert(id, state);

View file

@ -79,7 +79,6 @@ pub fn criterion_benchmark(c: &mut Criterion) {
&fonts, &fonts,
egui::Pos2::ZERO, egui::Pos2::ZERO,
&galley, &galley,
text_style,
egui::Color32::WHITE, egui::Color32::WHITE,
fake_italics, fake_italics,
&mut mesh, &mut mesh,

View file

@ -40,13 +40,13 @@ pub enum Shape {
stroke: Stroke, stroke: Stroke,
}, },
Text { Text {
/// Top left corner of the first character. /// Top left corner of the first character..
pos: Pos2, pos: Pos2,
/// The layed out text /// The layed out text.
galley: Galley, galley: Galley,
text_style: TextStyle, // TODO: Font? /// Text color (foreground).
color: Color32, color: Color32,
/// If true, tilt the letters for an ugly italics effect /// If true, tilt the letters for a hacky italics effect.
fake_italics: bool, fake_italics: bool,
}, },
Mesh(Mesh), Mesh(Mesh),
@ -137,7 +137,6 @@ impl Shape {
Self::Text { Self::Text {
pos: rect.min, pos: rect.min,
galley, galley,
text_style,
color, color,
fake_italics: false, fake_italics: false,
} }

View file

@ -566,7 +566,6 @@ impl Tessellator {
Shape::Text { Shape::Text {
pos, pos,
galley, galley,
text_style,
color, color,
fake_italics, fake_italics,
} => { } => {
@ -581,7 +580,7 @@ impl Tessellator {
out, out,
); );
} }
self.tessellate_text(fonts, pos, &galley, text_style, color, fake_italics, out); self.tessellate_text(fonts, pos, &galley, color, fake_italics, out);
} }
} }
} }
@ -622,7 +621,6 @@ impl Tessellator {
fonts: &Fonts, fonts: &Fonts,
pos: Pos2, pos: Pos2,
galley: &super::Galley, galley: &super::Galley,
text_style: super::TextStyle,
color: Color32, color: Color32,
fake_italics: bool, fake_italics: bool,
out: &mut Mesh, out: &mut Mesh,
@ -641,7 +639,7 @@ impl Tessellator {
let clip_rect = self.clip_rect.expand(2.0); // Some fudge to handle letters that are slightly larger than expected. let clip_rect = self.clip_rect.expand(2.0); // Some fudge to handle letters that are slightly larger than expected.
let font = &fonts[text_style]; let font = &fonts[galley.text_style];
let mut chars = galley.text.chars(); let mut chars = galley.text.chars();
for line in &galley.rows { for line in &galley.rows {
let line_min_y = pos.y + line.y_min; let line_min_y = pos.y + line.y_min;

View file

@ -7,7 +7,10 @@ use {
use crate::{ use crate::{
mutex::{Mutex, RwLock}, mutex::{Mutex, RwLock},
text::galley::{Galley, Row}, text::{
galley::{Galley, Row},
TextStyle,
},
TextureAtlas, TextureAtlas,
}; };
use emath::{vec2, Vec2}; use emath::{vec2, Vec2};
@ -153,8 +156,8 @@ type FontIndex = usize;
// TODO: rename? // TODO: rename?
/// Wrapper over multiple `FontImpl` (e.g. a primary + fallbacks for emojis) /// Wrapper over multiple `FontImpl` (e.g. a primary + fallbacks for emojis)
#[derive(Default)]
pub struct Font { pub struct Font {
text_style: TextStyle,
fonts: Vec<Arc<FontImpl>>, fonts: Vec<Arc<FontImpl>>,
replacement_glyph: (FontIndex, GlyphInfo), replacement_glyph: (FontIndex, GlyphInfo),
pixels_per_point: f32, pixels_per_point: f32,
@ -163,15 +166,23 @@ pub struct Font {
} }
impl Font { impl Font {
pub fn new(fonts: Vec<Arc<FontImpl>>) -> Self { pub fn new(text_style: TextStyle, fonts: Vec<Arc<FontImpl>>) -> Self {
if fonts.is_empty() { if fonts.is_empty() {
return Default::default(); return Self {
text_style,
fonts,
replacement_glyph: Default::default(),
pixels_per_point: 0.0,
row_height: 0.0,
glyph_info_cache: Default::default(),
};
} }
let pixels_per_point = fonts[0].pixels_per_point(); let pixels_per_point = fonts[0].pixels_per_point();
let row_height = fonts[0].row_height(); let row_height = fonts[0].row_height();
let mut slf = Self { let mut slf = Self {
text_style,
fonts, fonts,
replacement_glyph: Default::default(), replacement_glyph: Default::default(),
pixels_per_point, pixels_per_point,
@ -204,6 +215,11 @@ impl Font {
slf slf
} }
#[inline(always)]
pub fn text_style(&self) -> TextStyle {
self.text_style
}
#[inline] #[inline]
pub fn round_to_pixel(&self, point: f32) -> f32 { pub fn round_to_pixel(&self, point: f32) -> f32 {
(point * self.pixels_per_point).round() / self.pixels_per_point (point * self.pixels_per_point).round() / self.pixels_per_point
@ -301,6 +317,7 @@ impl Font {
let width = row.max_x(); let width = row.max_x();
let size = vec2(width, self.row_height()); let size = vec2(width, self.row_height());
let galley = Galley { let galley = Galley {
text_style: self.text_style,
text, text,
rows: vec![row], rows: vec![row],
size, size,
@ -391,7 +408,13 @@ impl Font {
} }
let size = vec2(widest_row, rows.last().unwrap().y_max); let size = vec2(widest_row, rows.last().unwrap().y_max);
let galley = Galley { text, rows, size }; let text_style = self.text_style;
let galley = Galley {
text_style,
text,
rows,
size,
};
galley.sanity_check(); galley.sanity_check();
galley galley
} }

View file

@ -221,7 +221,7 @@ impl Fonts {
.map(|font_name| font_impl_cache.font_impl(font_name, scale_in_points)) .map(|font_name| font_impl_cache.font_impl(font_name, scale_in_points))
.collect(); .collect();
(text_style, Font::new(fonts)) (text_style, Font::new(text_style, fonts))
}) })
.collect(); .collect();

View file

@ -23,8 +23,11 @@ use super::cursor::*;
use emath::{pos2, NumExt, Rect, Vec2}; use emath::{pos2, NumExt, Rect, Vec2};
/// A collection of text locked into place. /// A collection of text locked into place.
#[derive(Clone, Debug, Default, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Galley { pub struct Galley {
/// The [`crate::TextStyle`] (font) used.
pub text_style: crate::TextStyle,
/// The full text, including any an all `\n`. /// The full text, including any an all `\n`.
pub text: String, pub text: String,