refactor fonts: do all text layout via the Fonts struct
This commit is contained in:
parent
46425f1e38
commit
ade41403b5
12 changed files with 112 additions and 52 deletions
|
@ -180,8 +180,7 @@ fn combo_box(
|
||||||
let icon_size = Vec2::splat(ui.spacing().icon_width);
|
let icon_size = Vec2::splat(ui.spacing().icon_width);
|
||||||
|
|
||||||
let text_style = TextStyle::Button;
|
let text_style = TextStyle::Button;
|
||||||
let font = &ui.fonts()[text_style];
|
let galley = ui.fonts().layout_no_wrap(text_style, selected.into());
|
||||||
let galley = font.layout_no_wrap(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);
|
||||||
|
|
|
@ -173,8 +173,9 @@ 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 text_style = TextStyle::Monospace;
|
||||||
let font = &self.fonts()[text_style];
|
let galley =
|
||||||
let galley = font.layout_multiline(format!("🔥 {}", text), f32::INFINITY);
|
self.fonts()
|
||||||
|
.layout_multiline(text_style, format!("🔥 {}", text), 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 {
|
||||||
|
@ -291,8 +292,9 @@ impl Painter {
|
||||||
text_style: TextStyle,
|
text_style: TextStyle,
|
||||||
text_color: Color32,
|
text_color: Color32,
|
||||||
) -> Rect {
|
) -> Rect {
|
||||||
let font = &self.fonts()[text_style];
|
let galley = self
|
||||||
let galley = font.layout_multiline(text.into(), f32::INFINITY);
|
.fonts()
|
||||||
|
.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_style, text_color);
|
||||||
rect
|
rect
|
||||||
|
|
|
@ -1245,9 +1245,8 @@ impl Ui {
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
self.wrap(|ui| {
|
self.wrap(|ui| {
|
||||||
let font = &ui.fonts()[text_style];
|
let row_height = ui.fonts().row_height(text_style);
|
||||||
let row_height = font.row_height();
|
let space_width = ui.fonts().glyph_width(text_style, ' ');
|
||||||
let space_width = font.glyph_width(' ');
|
|
||||||
let spacing = ui.spacing_mut();
|
let spacing = ui.spacing_mut();
|
||||||
spacing.interact_size.y = row_height;
|
spacing.interact_size.y = row_height;
|
||||||
spacing.item_spacing.x = space_width;
|
spacing.item_spacing.x = space_width;
|
||||||
|
@ -1290,9 +1289,8 @@ impl Ui {
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> InnerResponse<R> {
|
) -> InnerResponse<R> {
|
||||||
self.wrap(|ui| {
|
self.wrap(|ui| {
|
||||||
let font = &ui.fonts()[text_style];
|
let row_height = ui.fonts().row_height(text_style);
|
||||||
let row_height = font.row_height();
|
let space_width = ui.fonts().glyph_width(text_style, ' ');
|
||||||
let space_width = font.glyph_width(' ');
|
|
||||||
let spacing = ui.spacing_mut();
|
let spacing = ui.spacing_mut();
|
||||||
spacing.interact_size.y = row_height;
|
spacing.interact_size.y = row_height;
|
||||||
spacing.item_spacing.x = space_width;
|
spacing.item_spacing.x = space_width;
|
||||||
|
|
|
@ -106,11 +106,11 @@ impl Button {
|
||||||
}
|
}
|
||||||
let total_extra = button_padding + button_padding;
|
let total_extra = button_padding + button_padding;
|
||||||
|
|
||||||
let font = &ui.fonts()[text_style];
|
|
||||||
let galley = if ui.wrap_text() {
|
let galley = if ui.wrap_text() {
|
||||||
font.layout_multiline(text, ui.available_width() - total_extra.x)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, text, ui.available_width() - total_extra.x)
|
||||||
} else {
|
} else {
|
||||||
font.layout_no_wrap(text)
|
ui.fonts().layout_no_wrap(text_style, text)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut desired_size = galley.size + 2.0 * button_padding;
|
let mut desired_size = galley.size + 2.0 * button_padding;
|
||||||
|
@ -210,19 +210,18 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
text_color,
|
text_color,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let text_style = TextStyle::Button;
|
|
||||||
let font = &ui.fonts()[text_style];
|
|
||||||
|
|
||||||
let spacing = &ui.spacing();
|
let spacing = &ui.spacing();
|
||||||
let icon_width = spacing.icon_width;
|
let icon_width = spacing.icon_width;
|
||||||
let icon_spacing = ui.spacing().icon_spacing;
|
let icon_spacing = ui.spacing().icon_spacing;
|
||||||
let button_padding = spacing.button_padding;
|
let button_padding = spacing.button_padding;
|
||||||
let total_extra = button_padding + vec2(icon_width + icon_spacing, 0.0) + button_padding;
|
let total_extra = button_padding + vec2(icon_width + icon_spacing, 0.0) + button_padding;
|
||||||
|
|
||||||
|
let text_style = TextStyle::Button;
|
||||||
let galley = if ui.wrap_text() {
|
let galley = if ui.wrap_text() {
|
||||||
font.layout_multiline(text, ui.available_width() - total_extra.x)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, text, ui.available_width() - total_extra.x)
|
||||||
} else {
|
} else {
|
||||||
font.layout_no_wrap(text)
|
ui.fonts().layout_no_wrap(text_style, text)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut desired_size = total_extra + galley.size;
|
let mut desired_size = total_extra + galley.size;
|
||||||
|
@ -322,18 +321,17 @@ impl Widget for RadioButton {
|
||||||
text_color,
|
text_color,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let text_style = TextStyle::Button;
|
|
||||||
let font = &ui.fonts()[text_style];
|
|
||||||
|
|
||||||
let icon_width = ui.spacing().icon_width;
|
let icon_width = ui.spacing().icon_width;
|
||||||
let icon_spacing = ui.spacing().icon_spacing;
|
let icon_spacing = ui.spacing().icon_spacing;
|
||||||
let button_padding = ui.spacing().button_padding;
|
let button_padding = ui.spacing().button_padding;
|
||||||
let total_extra = button_padding + vec2(icon_width + icon_spacing, 0.0) + button_padding;
|
let total_extra = button_padding + vec2(icon_width + icon_spacing, 0.0) + button_padding;
|
||||||
|
|
||||||
|
let text_style = TextStyle::Button;
|
||||||
let galley = if ui.wrap_text() {
|
let galley = if ui.wrap_text() {
|
||||||
font.layout_multiline(text, ui.available_width() - total_extra.x)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, text, ui.available_width() - total_extra.x)
|
||||||
} else {
|
} else {
|
||||||
font.layout_no_wrap(text)
|
ui.fonts().layout_no_wrap(text_style, text)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut desired_size = total_extra + galley.size;
|
let mut desired_size = total_extra + galley.size;
|
||||||
|
|
|
@ -150,13 +150,14 @@ impl Label {
|
||||||
|
|
||||||
pub fn layout_width(&self, ui: &Ui, max_width: f32) -> Galley {
|
pub fn layout_width(&self, ui: &Ui, max_width: f32) -> Galley {
|
||||||
let text_style = self.text_style_or_default(ui.style());
|
let text_style = self.text_style_or_default(ui.style());
|
||||||
let font = &ui.fonts()[text_style];
|
|
||||||
let wrap_width = if self.should_wrap(ui) {
|
let wrap_width = if self.should_wrap(ui) {
|
||||||
max_width
|
max_width
|
||||||
} else {
|
} else {
|
||||||
f32::INFINITY
|
f32::INFINITY
|
||||||
};
|
};
|
||||||
let galley = font.layout_multiline(self.text.clone(), wrap_width); // TODO: avoid clone
|
let galley = ui
|
||||||
|
.fonts()
|
||||||
|
.layout_multiline(text_style, self.text.clone(), wrap_width); // TODO: avoid clone
|
||||||
self.valign_galley(ui, text_style, galley)
|
self.valign_galley(ui, text_style, galley)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,7 +264,7 @@ impl Label {
|
||||||
-2.0
|
-2.0
|
||||||
} else {
|
} else {
|
||||||
let normal_text_heigth = ui.fonts()[TextStyle::Body].row_height();
|
let normal_text_heigth = ui.fonts()[TextStyle::Body].row_height();
|
||||||
let font_height = ui.fonts()[text_style].row_height();
|
let font_height = ui.fonts().row_height(text_style);
|
||||||
(normal_text_heigth - font_height) / 2.0 - 1.0 // center
|
(normal_text_heigth - font_height) / 2.0 - 1.0 // center
|
||||||
|
|
||||||
// normal_text_heigth - font_height // align bottom
|
// normal_text_heigth - font_height // align bottom
|
||||||
|
@ -293,8 +294,8 @@ impl Widget for Label {
|
||||||
let first_row_indentation = max_width - ui.available_size_before_wrap().x;
|
let first_row_indentation = max_width - ui.available_size_before_wrap().x;
|
||||||
|
|
||||||
let text_style = self.text_style_or_default(ui.style());
|
let text_style = self.text_style_or_default(ui.style());
|
||||||
let font = &ui.fonts()[text_style];
|
let mut galley = ui.fonts().layout_multiline_with_indentation_and_max_width(
|
||||||
let mut galley = font.layout_multiline_with_indentation_and_max_width(
|
text_style,
|
||||||
self.text.clone(),
|
self.text.clone(),
|
||||||
first_row_indentation,
|
first_row_indentation,
|
||||||
max_width,
|
max_width,
|
||||||
|
|
|
@ -649,8 +649,7 @@ impl Prepared {
|
||||||
|
|
||||||
let text = emath::round_to_decimals(value_main, 5).to_string(); // hack
|
let text = emath::round_to_decimals(value_main, 5).to_string(); // hack
|
||||||
|
|
||||||
let font = &ui.fonts()[text_style];
|
let galley = ui.fonts().layout_multiline(text_style, text, f32::INFINITY);
|
||||||
let galley = font.layout_multiline(text, f32::INFINITY);
|
|
||||||
|
|
||||||
let mut text_pos = pos_in_gui + vec2(1.0, -galley.size.y);
|
let mut text_pos = pos_in_gui + vec2(1.0, -galley.size.y);
|
||||||
|
|
||||||
|
|
|
@ -40,16 +40,15 @@ impl Widget for SelectableLabel {
|
||||||
fn ui(self, ui: &mut Ui) -> Response {
|
fn ui(self, ui: &mut Ui) -> Response {
|
||||||
let Self { selected, text } = self;
|
let Self { selected, text } = self;
|
||||||
|
|
||||||
let text_style = TextStyle::Button;
|
|
||||||
let font = &ui.fonts()[text_style];
|
|
||||||
|
|
||||||
let button_padding = ui.spacing().button_padding;
|
let button_padding = ui.spacing().button_padding;
|
||||||
let total_extra = button_padding + button_padding;
|
let total_extra = button_padding + button_padding;
|
||||||
|
|
||||||
|
let text_style = TextStyle::Button;
|
||||||
let galley = if ui.wrap_text() {
|
let galley = if ui.wrap_text() {
|
||||||
font.layout_multiline(text, ui.available_width() - total_extra.x)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, text, ui.available_width() - total_extra.x)
|
||||||
} else {
|
} else {
|
||||||
font.layout_no_wrap(text)
|
ui.fonts().layout_no_wrap(text_style, text)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut desired_size = total_extra + galley.size;
|
let mut desired_size = total_extra + galley.size;
|
||||||
|
|
|
@ -441,8 +441,10 @@ impl<'a> Slider<'a> {
|
||||||
impl<'a> Widget for Slider<'a> {
|
impl<'a> Widget for Slider<'a> {
|
||||||
fn ui(mut self, ui: &mut Ui) -> Response {
|
fn ui(mut self, ui: &mut Ui) -> Response {
|
||||||
let text_style = TextStyle::Button;
|
let text_style = TextStyle::Button;
|
||||||
let font = &ui.fonts()[text_style];
|
let height = ui
|
||||||
let height = font.row_height().at_least(ui.spacing().interact_size.y);
|
.fonts()
|
||||||
|
.row_height(text_style)
|
||||||
|
.at_least(ui.spacing().interact_size.y);
|
||||||
|
|
||||||
let old_value = self.get_value();
|
let old_value = self.get_value();
|
||||||
|
|
||||||
|
|
|
@ -300,13 +300,13 @@ impl<'t> TextEdit<'t> {
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
let text_style = text_style.unwrap_or_else(|| ui.style().body_text_style);
|
let text_style = text_style.unwrap_or_else(|| ui.style().body_text_style);
|
||||||
let font = &ui.fonts()[text_style];
|
let line_spacing = ui.fonts().row_height(text_style);
|
||||||
let line_spacing = font.row_height();
|
|
||||||
let available_width = ui.available_width();
|
let available_width = ui.available_width();
|
||||||
let mut galley = if multiline {
|
let mut galley = if multiline {
|
||||||
font.layout_multiline(text.clone(), available_width)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, text.clone(), available_width)
|
||||||
} else {
|
} else {
|
||||||
font.layout_single_line(text.clone())
|
ui.fonts().layout_single_line(text_style, text.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width);
|
let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width);
|
||||||
|
@ -481,11 +481,11 @@ impl<'t> TextEdit<'t> {
|
||||||
response.mark_changed();
|
response.mark_changed();
|
||||||
|
|
||||||
// Layout again to avoid frame delay, and to keep `text` and `galley` in sync.
|
// Layout again to avoid frame delay, and to keep `text` and `galley` in sync.
|
||||||
let font = &ui.fonts()[text_style];
|
|
||||||
galley = if multiline {
|
galley = if multiline {
|
||||||
font.layout_multiline(text.clone(), available_width)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, text.clone(), available_width)
|
||||||
} else {
|
} else {
|
||||||
font.layout_single_line(text.clone())
|
ui.fonts().layout_single_line(text_style, text.clone())
|
||||||
};
|
};
|
||||||
|
|
||||||
// Set cursorp using new galley:
|
// Set cursorp using new galley:
|
||||||
|
@ -517,11 +517,11 @@ impl<'t> TextEdit<'t> {
|
||||||
.galley(response.rect.min, galley, text_style, 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 font = &ui.fonts()[text_style];
|
|
||||||
let galley = if multiline {
|
let galley = if multiline {
|
||||||
font.layout_multiline(hint_text, available_width)
|
ui.fonts()
|
||||||
|
.layout_multiline(text_style, hint_text, available_width)
|
||||||
} else {
|
} else {
|
||||||
font.layout_single_line(hint_text)
|
ui.fonts().layout_single_line(text_style, hint_text)
|
||||||
};
|
};
|
||||||
let hint_text_color = ui.visuals().weak_text_color();
|
let hint_text_color = ui.visuals().weak_text_color();
|
||||||
ui.painter()
|
ui.painter()
|
||||||
|
|
|
@ -132,8 +132,7 @@ impl Shape {
|
||||||
text_style: TextStyle,
|
text_style: TextStyle,
|
||||||
color: Color32,
|
color: Color32,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let font = &fonts[text_style];
|
let galley = fonts.layout_multiline(text_style, text.into(), f32::INFINITY);
|
||||||
let galley = font.layout_multiline(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::Text {
|
Self::Text {
|
||||||
pos: rect.min,
|
pos: rect.min,
|
||||||
|
|
|
@ -222,6 +222,7 @@ impl Font {
|
||||||
.and_then(|gi| gi.1.uv_rect)
|
.and_then(|gi| gi.1.uv_rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Width of this character in points.
|
||||||
pub fn glyph_width(&self, c: char) -> f32 {
|
pub fn glyph_width(&self, c: char) -> f32 {
|
||||||
self.glyph_info(c).1.advance_width
|
self.glyph_info(c).1.advance_width
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,10 @@ use std::{
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
mutex::Mutex,
|
mutex::Mutex,
|
||||||
text::font::{Font, FontImpl},
|
text::{
|
||||||
|
font::{Font, FontImpl},
|
||||||
|
Galley,
|
||||||
|
},
|
||||||
Texture, TextureAtlas,
|
Texture, TextureAtlas,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,6 +262,65 @@ impl Fonts {
|
||||||
|
|
||||||
buffered_texture.clone()
|
buffered_texture.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Width of this character in points.
|
||||||
|
pub fn glyph_width(&self, text_style: TextStyle, c: char) -> f32 {
|
||||||
|
self.fonts[&text_style].glyph_width(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Height of one row of text. In points
|
||||||
|
pub fn row_height(&self, text_style: TextStyle) -> f32 {
|
||||||
|
self.fonts[&text_style].row_height()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always returns at least one row.
|
||||||
|
/// Will line break at `\n`.
|
||||||
|
pub fn layout_no_wrap(&self, text_style: TextStyle, text: String) -> Galley {
|
||||||
|
self.layout_multiline(text_style, text, f32::INFINITY)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Typeset the given text onto one row.
|
||||||
|
/// Any `\n` will show up as the replacement character.
|
||||||
|
/// Always returns exactly one `Row` in the `Galley`.
|
||||||
|
///
|
||||||
|
/// Most often you probably want `\n` to produce a new row,
|
||||||
|
/// and so [`Self::layout_no_wrap`] may be a better choice.
|
||||||
|
pub fn layout_single_line(&self, text_style: TextStyle, text: String) -> Galley {
|
||||||
|
self.fonts[&text_style].layout_single_line(text)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Always returns at least one row.
|
||||||
|
/// Will wrap text at the given width.
|
||||||
|
pub fn layout_multiline(
|
||||||
|
&self,
|
||||||
|
text_style: TextStyle,
|
||||||
|
text: String,
|
||||||
|
max_width_in_points: f32,
|
||||||
|
) -> Galley {
|
||||||
|
self.layout_multiline_with_indentation_and_max_width(
|
||||||
|
text_style,
|
||||||
|
text,
|
||||||
|
0.0,
|
||||||
|
max_width_in_points,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// * `first_row_indentation`: extra space before the very first character (in points).
|
||||||
|
/// * `max_width_in_points`: wrapping width.
|
||||||
|
/// Always returns at least one row.
|
||||||
|
pub fn layout_multiline_with_indentation_and_max_width(
|
||||||
|
&self,
|
||||||
|
text_style: TextStyle,
|
||||||
|
text: String,
|
||||||
|
first_row_indentation: f32,
|
||||||
|
max_width_in_points: f32,
|
||||||
|
) -> Galley {
|
||||||
|
self.fonts[&text_style].layout_multiline_with_indentation_and_max_width(
|
||||||
|
text,
|
||||||
|
first_row_indentation,
|
||||||
|
max_width_in_points,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::ops::Index<TextStyle> for Fonts {
|
impl std::ops::Index<TextStyle> for Fonts {
|
||||||
|
|
Loading…
Reference in a new issue