mirror of
https://github.com/emilk/egui.git
synced 2026-08-29 21:00:03 -04:00
Merge branch 'master' into cache_galley_lines
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Arc;
|
||||
|
||||
use emath::{vec2, Vec2};
|
||||
use emath::{vec2, GuiRounding, Vec2};
|
||||
|
||||
use crate::{
|
||||
mutex::{Mutex, RwLock},
|
||||
@@ -96,22 +96,18 @@ impl FontImpl {
|
||||
|
||||
use ab_glyph::{Font, ScaleFont};
|
||||
let scaled = ab_glyph_font.as_scaled(scale_in_pixels);
|
||||
let ascent = scaled.ascent() / pixels_per_point;
|
||||
let descent = scaled.descent() / pixels_per_point;
|
||||
let line_gap = scaled.line_gap() / pixels_per_point;
|
||||
let ascent = (scaled.ascent() / pixels_per_point).round_ui();
|
||||
let descent = (scaled.descent() / pixels_per_point).round_ui();
|
||||
let line_gap = (scaled.line_gap() / pixels_per_point).round_ui();
|
||||
|
||||
// Tweak the scale as the user desired
|
||||
let scale_in_pixels = scale_in_pixels * tweak.scale;
|
||||
let scale_in_points = scale_in_pixels / pixels_per_point;
|
||||
|
||||
let baseline_offset = {
|
||||
let scale_in_points = scale_in_pixels / pixels_per_point;
|
||||
scale_in_points * tweak.baseline_offset_factor
|
||||
};
|
||||
let baseline_offset = (scale_in_points * tweak.baseline_offset_factor).round_ui();
|
||||
|
||||
let y_offset_points = {
|
||||
let scale_in_points = scale_in_pixels / pixels_per_point;
|
||||
scale_in_points * tweak.y_offset_factor
|
||||
} + tweak.y_offset;
|
||||
let y_offset_points =
|
||||
((scale_in_points * tweak.y_offset_factor) + tweak.y_offset).round_ui();
|
||||
|
||||
// Center scaled glyphs properly:
|
||||
let height = ascent + descent;
|
||||
@@ -247,6 +243,8 @@ impl FontImpl {
|
||||
}
|
||||
|
||||
/// Height of one row of text in points.
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
#[inline(always)]
|
||||
pub fn row_height(&self) -> f32 {
|
||||
self.height_in_points
|
||||
@@ -418,7 +416,9 @@ impl Font {
|
||||
(point * self.pixels_per_point).round() / self.pixels_per_point
|
||||
}
|
||||
|
||||
/// Height of one row of text. In points
|
||||
/// Height of one row of text. In points.
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
#[inline(always)]
|
||||
pub fn row_height(&self) -> f32 {
|
||||
self.row_height
|
||||
|
||||
@@ -519,7 +519,9 @@ impl Fonts {
|
||||
self.lock().fonts.has_glyphs(font_id, s)
|
||||
}
|
||||
|
||||
/// Height of one row of text in points
|
||||
/// Height of one row of text in points.
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
#[inline]
|
||||
pub fn row_height(&self, font_id: &FontId) -> f32 {
|
||||
self.lock().fonts.row_height(font_id)
|
||||
@@ -706,6 +708,8 @@ impl FontsImpl {
|
||||
}
|
||||
|
||||
/// Height of one row of text in points.
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
fn row_height(&mut self, font_id: &FontId) -> f32 {
|
||||
self.font(font_id).row_height()
|
||||
}
|
||||
@@ -817,7 +821,7 @@ impl GalleyCache {
|
||||
halign: job.halign,
|
||||
justify: job.justify,
|
||||
first_row_min_height,
|
||||
round_output_size_to_nearest_ui_point: job.round_output_size_to_nearest_ui_point,
|
||||
round_output_to_gui: job.round_output_to_gui,
|
||||
};
|
||||
first_row_min_height = 0.0;
|
||||
|
||||
@@ -910,11 +914,8 @@ impl GalleyCache {
|
||||
merged_galley.elided |= galley.elided;
|
||||
}
|
||||
|
||||
if merged_galley.job.round_output_size_to_nearest_ui_point {
|
||||
super::round_output_size_to_nearest_ui_point(
|
||||
&mut merged_galley.rect,
|
||||
&merged_galley.job,
|
||||
);
|
||||
if merged_galley.job.round_output_to_gui {
|
||||
super::round_output_to_gui(&mut merged_galley.rect, &merged_galley.job);
|
||||
}
|
||||
|
||||
merged_galley
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use emath::{pos2, vec2, Align, NumExt, Pos2, Rect, Vec2};
|
||||
use emath::{pos2, vec2, Align, GuiRounding as _, NumExt, Pos2, Rect, Vec2};
|
||||
|
||||
use crate::{stroke::PathStroke, text::font::Font, Color32, Mesh, Stroke, Vertex};
|
||||
|
||||
@@ -643,7 +643,7 @@ fn galley_from_rows(
|
||||
min_x = min_x.min(placed_row.rect().min.x);
|
||||
max_x = max_x.max(placed_row.rect().max.x);
|
||||
cursor_y += max_row_height;
|
||||
cursor_y = point_scale.round_to_pixel(cursor_y);
|
||||
cursor_y = point_scale.round_to_pixel(cursor_y); // TODO(emilk): it would be better to do the calculations in pixels instead.
|
||||
}
|
||||
|
||||
let format_summary = format_summary(&job);
|
||||
@@ -662,8 +662,13 @@ fn galley_from_rows(
|
||||
|
||||
let mut rect = Rect::from_min_max(pos2(min_x, 0.0), pos2(max_x, cursor_y));
|
||||
|
||||
if job.round_output_size_to_nearest_ui_point {
|
||||
round_output_size_to_nearest_ui_point(&mut rect, &job);
|
||||
if job.round_output_to_gui {
|
||||
for placed_row in &mut rows {
|
||||
placed_row.pos = placed_row.pos.round_ui();
|
||||
let row = Arc::get_mut(&mut placed_row.row).unwrap();
|
||||
row.size = row.size.round_ui();
|
||||
}
|
||||
round_output_to_gui(&mut rect, &job);
|
||||
}
|
||||
|
||||
Galley {
|
||||
@@ -678,20 +683,21 @@ fn galley_from_rows(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn round_output_size_to_nearest_ui_point(rect: &mut Rect, job: &LayoutJob) {
|
||||
pub(crate) fn round_output_to_gui(rect: &mut Rect, job: &LayoutJob) {
|
||||
let did_exceed_wrap_width_by_a_lot = rect.width() > job.wrap.max_width + 1.0;
|
||||
|
||||
// We round the size to whole ui points here (not pixels!) so that the egui layout code
|
||||
// can have the advantage of working in integer units, avoiding rounding errors.
|
||||
rect.min = rect.min.round();
|
||||
rect.max = rect.max.round();
|
||||
*rect = rect.round_ui();
|
||||
|
||||
if did_exceed_wrap_width_by_a_lot {
|
||||
// If the user picked a too aggressive wrap width (e.g. more narrow than any individual glyph),
|
||||
// we should let the user know by reporting that our width is wider than the wrap width.
|
||||
} else {
|
||||
// Make sure we don't report being wider than the wrap width the user picked:
|
||||
rect.max.x = rect.max.x.at_most(rect.min.x + job.wrap.max_width).floor();
|
||||
rect.max.x = rect
|
||||
.max
|
||||
.x
|
||||
.at_most(rect.min.x + job.wrap.max_width)
|
||||
.floor_ui();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1151,6 +1157,7 @@ mod tests {
|
||||
LayoutJob::single_section("# DNA\nMore text".into(), TextFormat::default());
|
||||
layout_job.wrap.max_width = f32::INFINITY;
|
||||
layout_job.wrap.max_rows = 1;
|
||||
layout_job.round_output_to_gui = false;
|
||||
let galley = layout(&mut fonts, layout_job.into());
|
||||
assert!(galley.elided);
|
||||
assert_eq!(
|
||||
|
||||
@@ -78,9 +78,8 @@ pub struct LayoutJob {
|
||||
/// Justify text so that word-wrapped rows fill the whole [`TextWrapping::max_width`].
|
||||
pub justify: bool,
|
||||
|
||||
/// Rounding to the closest ui point (not pixel!) allows the rest of the
|
||||
/// layout code to run on perfect integers, avoiding rounding errors.
|
||||
pub round_output_size_to_nearest_ui_point: bool,
|
||||
/// Round output sizes using [`emath::GuiRounding`], to avoid rounding errors in layout code.
|
||||
pub round_output_to_gui: bool,
|
||||
}
|
||||
|
||||
impl Default for LayoutJob {
|
||||
@@ -94,7 +93,7 @@ impl Default for LayoutJob {
|
||||
break_on_newline: true,
|
||||
halign: Align::LEFT,
|
||||
justify: false,
|
||||
round_output_size_to_nearest_ui_point: true,
|
||||
round_output_to_gui: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,6 +167,8 @@ impl LayoutJob {
|
||||
}
|
||||
|
||||
/// The height of the tallest font used in the job.
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
pub fn font_height(&self, fonts: &crate::Fonts) -> f32 {
|
||||
let mut max_height = 0.0_f32;
|
||||
for section in &self.sections {
|
||||
@@ -178,7 +179,7 @@ impl LayoutJob {
|
||||
|
||||
/// The wrap with, with a small margin in some cases.
|
||||
pub fn effective_wrap_width(&self) -> f32 {
|
||||
if self.round_output_size_to_nearest_ui_point {
|
||||
if self.round_output_to_gui {
|
||||
// On a previous pass we may have rounded down by at most 0.5 and reported that as a width.
|
||||
// egui may then set that width as the max width for subsequent frames, and it is important
|
||||
// that we then don't wrap earlier.
|
||||
@@ -200,7 +201,7 @@ impl std::hash::Hash for LayoutJob {
|
||||
break_on_newline,
|
||||
halign,
|
||||
justify,
|
||||
round_output_size_to_nearest_ui_point,
|
||||
round_output_to_gui,
|
||||
} = self;
|
||||
|
||||
text.hash(state);
|
||||
@@ -210,7 +211,7 @@ impl std::hash::Hash for LayoutJob {
|
||||
break_on_newline.hash(state);
|
||||
halign.hash(state);
|
||||
justify.hash(state);
|
||||
round_output_size_to_nearest_ui_point.hash(state);
|
||||
round_output_to_gui.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user