mirror of
https://github.com/emilk/egui.git
synced 2026-09-03 07:10:04 -04:00
More even text kerning (#7431)
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
This commit is contained in:
@@ -60,7 +60,7 @@ pub trait AtomExt<'a> {
|
||||
{
|
||||
let font_selection = FontSelection::default();
|
||||
let font_id = font_selection.resolve(ui.style());
|
||||
let height = ui.fonts(|f| f.row_height(&font_id));
|
||||
let height = ui.fonts_mut(|f| f.row_height(&font_id));
|
||||
self.atom_max_height(height)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,7 +476,7 @@ impl Window<'_> {
|
||||
let (title_bar_height_with_margin, title_content_spacing) = if with_title_bar {
|
||||
let style = ctx.style();
|
||||
let title_bar_inner_height = ctx
|
||||
.fonts(|fonts| title.font_height(fonts, &style))
|
||||
.fonts_mut(|fonts| title.font_height(fonts, &style))
|
||||
.at_least(style.spacing.interact_size.y);
|
||||
let title_bar_inner_height = title_bar_inner_height + window_frame.inner_margin.sum().y;
|
||||
let half_height = (title_bar_inner_height / 2.0).round() as _;
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
use std::{borrow::Cow, cell::RefCell, panic::Location, sync::Arc, time::Duration};
|
||||
|
||||
use emath::{GuiRounding as _, OrderedFloat};
|
||||
use emath::GuiRounding as _;
|
||||
use epaint::{
|
||||
ClippedPrimitive, ClippedShape, Color32, ImageData, ImageDelta, Pos2, Rect, StrokeKind,
|
||||
TessellationOptions, TextureAtlas, TextureId, Vec2,
|
||||
ClippedPrimitive, ClippedShape, Color32, ImageData, Pos2, Rect, StrokeKind,
|
||||
TessellationOptions, TextureId, Vec2,
|
||||
emath::{self, TSTransform},
|
||||
mutex::RwLock,
|
||||
stats::PaintStats,
|
||||
tessellator,
|
||||
text::{FontInsert, FontPriority, Fonts},
|
||||
text::{FontInsert, FontPriority, Fonts, FontsView},
|
||||
vec2,
|
||||
};
|
||||
|
||||
@@ -406,12 +406,7 @@ impl ViewportRepaintInfo {
|
||||
|
||||
#[derive(Default)]
|
||||
struct ContextImpl {
|
||||
/// Since we could have multiple viewports across multiple monitors with
|
||||
/// different `pixels_per_point`, we need a `Fonts` instance for each unique
|
||||
/// `pixels_per_point`.
|
||||
/// This is because the `Fonts` depend on `pixels_per_point` for the font atlas
|
||||
/// as well as kerning, font sizes, etc.
|
||||
fonts: std::collections::BTreeMap<OrderedFloat<f32>, Fonts>,
|
||||
fonts: Option<Fonts>,
|
||||
font_definitions: FontDefinitions,
|
||||
|
||||
memory: Memory,
|
||||
@@ -575,12 +570,11 @@ impl ContextImpl {
|
||||
fn update_fonts_mut(&mut self) {
|
||||
profiling::function_scope!();
|
||||
let input = &self.viewport().input;
|
||||
let pixels_per_point = input.pixels_per_point();
|
||||
let max_texture_side = input.max_texture_side;
|
||||
|
||||
if let Some(font_definitions) = self.memory.new_font_definitions.take() {
|
||||
// New font definition loaded, so we need to reload all fonts.
|
||||
self.fonts.clear();
|
||||
self.fonts = None;
|
||||
self.font_definitions = font_definitions;
|
||||
#[cfg(feature = "log")]
|
||||
log::trace!("Loading new font definitions");
|
||||
@@ -589,7 +583,7 @@ impl ContextImpl {
|
||||
if !self.memory.add_fonts.is_empty() {
|
||||
let fonts = self.memory.add_fonts.drain(..);
|
||||
for font in fonts {
|
||||
self.fonts.clear(); // recreate all the fonts
|
||||
self.fonts = None; // recreate all the fonts
|
||||
for family in font.families {
|
||||
let fam = self
|
||||
.font_definitions
|
||||
@@ -614,26 +608,22 @@ impl ContextImpl {
|
||||
|
||||
let mut is_new = false;
|
||||
|
||||
let fonts = self
|
||||
.fonts
|
||||
.entry(pixels_per_point.into())
|
||||
.or_insert_with(|| {
|
||||
#[cfg(feature = "log")]
|
||||
log::trace!("Creating new Fonts for pixels_per_point={pixels_per_point}");
|
||||
let fonts = self.fonts.get_or_insert_with(|| {
|
||||
#[cfg(feature = "log")]
|
||||
log::trace!("Creating new Fonts");
|
||||
|
||||
is_new = true;
|
||||
profiling::scope!("Fonts::new");
|
||||
Fonts::new(
|
||||
pixels_per_point,
|
||||
max_texture_side,
|
||||
text_alpha_from_coverage,
|
||||
self.font_definitions.clone(),
|
||||
)
|
||||
});
|
||||
is_new = true;
|
||||
profiling::scope!("Fonts::new");
|
||||
Fonts::new(
|
||||
max_texture_side,
|
||||
text_alpha_from_coverage,
|
||||
self.font_definitions.clone(),
|
||||
)
|
||||
});
|
||||
|
||||
{
|
||||
profiling::scope!("Fonts::begin_pass");
|
||||
fonts.begin_pass(pixels_per_point, max_texture_side, text_alpha_from_coverage);
|
||||
fonts.begin_pass(max_texture_side, text_alpha_from_coverage);
|
||||
}
|
||||
|
||||
if is_new && self.memory.options.preload_font_glyphs {
|
||||
@@ -641,7 +631,10 @@ impl ContextImpl {
|
||||
// Preload the most common characters for the most common fonts.
|
||||
// This is not very important to do, but may save a few GPU operations.
|
||||
for font_id in self.memory.options.style().text_styles.values() {
|
||||
fonts.lock().fonts.font(font_id).preload_common_characters();
|
||||
fonts
|
||||
.fonts
|
||||
.font(&font_id.family)
|
||||
.preload_common_characters();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1049,13 +1042,32 @@ impl Context {
|
||||
/// Not valid until first call to [`Context::run()`].
|
||||
/// That's because since we don't know the proper `pixels_per_point` until then.
|
||||
#[inline]
|
||||
pub fn fonts<R>(&self, reader: impl FnOnce(&Fonts) -> R) -> R {
|
||||
pub fn fonts<R>(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R {
|
||||
self.write(move |ctx| {
|
||||
let pixels_per_point = ctx.pixels_per_point();
|
||||
reader(
|
||||
ctx.fonts
|
||||
.get(&pixels_per_point.into())
|
||||
.expect("No fonts available until first call to Context::run()"),
|
||||
&ctx.fonts
|
||||
.as_mut()
|
||||
.expect("No fonts available until first call to Context::run()")
|
||||
.with_pixels_per_point(pixels_per_point),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Read-write access to [`Fonts`].
|
||||
///
|
||||
/// Not valid until first call to [`Context::run()`].
|
||||
/// That's because since we don't know the proper `pixels_per_point` until then.
|
||||
#[inline]
|
||||
pub fn fonts_mut<R>(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R {
|
||||
self.write(move |ctx| {
|
||||
let pixels_per_point = ctx.pixels_per_point();
|
||||
reader(
|
||||
&mut ctx
|
||||
.fonts
|
||||
.as_mut()
|
||||
.expect("No fonts available until first call to Context::run()")
|
||||
.with_pixels_per_point(pixels_per_point),
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -1568,9 +1580,8 @@ impl Context {
|
||||
} = ModifierNames::SYMBOLS;
|
||||
|
||||
let font_id = TextStyle::Body.resolve(&self.style());
|
||||
self.fonts(|f| {
|
||||
let mut lock = f.lock();
|
||||
let font = lock.fonts.font(&font_id);
|
||||
self.fonts_mut(|f| {
|
||||
let mut font = f.fonts.font(&font_id.family);
|
||||
font.has_glyphs(alt)
|
||||
&& font.has_glyphs(ctrl)
|
||||
&& font.has_glyphs(shift)
|
||||
@@ -1920,14 +1931,12 @@ impl Context {
|
||||
pub fn set_fonts(&self, font_definitions: FontDefinitions) {
|
||||
profiling::function_scope!();
|
||||
|
||||
let pixels_per_point = self.pixels_per_point();
|
||||
|
||||
let mut update_fonts = true;
|
||||
|
||||
self.read(|ctx| {
|
||||
if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) {
|
||||
if let Some(current_fonts) = ctx.fonts.as_ref() {
|
||||
// NOTE: this comparison is expensive since it checks TTF data for equality
|
||||
if current_fonts.lock().fonts.definitions() == &font_definitions {
|
||||
if current_fonts.definitions() == &font_definitions {
|
||||
update_fonts = false; // no need to update
|
||||
}
|
||||
}
|
||||
@@ -1948,15 +1957,11 @@ impl Context {
|
||||
pub fn add_font(&self, new_font: FontInsert) {
|
||||
profiling::function_scope!();
|
||||
|
||||
let pixels_per_point = self.pixels_per_point();
|
||||
|
||||
let mut update_fonts = true;
|
||||
|
||||
self.read(|ctx| {
|
||||
if let Some(current_fonts) = ctx.fonts.get(&pixels_per_point.into()) {
|
||||
if let Some(current_fonts) = ctx.fonts.as_ref() {
|
||||
if current_fonts
|
||||
.lock()
|
||||
.fonts
|
||||
.definitions()
|
||||
.font_data
|
||||
.contains_key(&new_font.name)
|
||||
@@ -2449,30 +2454,12 @@ impl ContextImpl {
|
||||
|
||||
self.memory.end_pass(&viewport.this_pass.used_ids);
|
||||
|
||||
if let Some(fonts) = self.fonts.get(&pixels_per_point.into()) {
|
||||
if let Some(fonts) = self.fonts.as_mut() {
|
||||
let tex_mngr = &mut self.tex_manager.0.write();
|
||||
if let Some(font_image_delta) = fonts.font_image_delta() {
|
||||
// A partial font atlas update, e.g. a new glyph has been entered.
|
||||
tex_mngr.set(TextureId::default(), font_image_delta);
|
||||
}
|
||||
|
||||
if 1 < self.fonts.len() {
|
||||
// We have multiple different `pixels_per_point`,
|
||||
// e.g. because we have many viewports spread across
|
||||
// monitors with different DPI scaling.
|
||||
// All viewports share the same texture namespace and renderer,
|
||||
// so the all use `TextureId::default()` for the font texture.
|
||||
// This is a problem.
|
||||
// We solve this with a hack: we always upload the full font atlas
|
||||
// every frame, for all viewports.
|
||||
// This ensures it is up-to-date, solving
|
||||
// https://github.com/emilk/egui/issues/3664
|
||||
// at the cost of a lot of performance.
|
||||
// (This will override any smaller delta that was uploaded above.)
|
||||
profiling::scope!("full_font_atlas_update");
|
||||
let full_delta = ImageDelta::full(fonts.image(), TextureAtlas::texture_options());
|
||||
tex_mngr.set(TextureId::default(), full_delta);
|
||||
}
|
||||
}
|
||||
|
||||
// Inform the backend of all textures that have been updated (including font atlas).
|
||||
@@ -2615,24 +2602,6 @@ impl ContextImpl {
|
||||
self.memory.set_viewport_id(viewport_id);
|
||||
}
|
||||
|
||||
let active_pixels_per_point: std::collections::BTreeSet<OrderedFloat<f32>> = self
|
||||
.viewports
|
||||
.values()
|
||||
.map(|v| v.input.pixels_per_point.into())
|
||||
.collect();
|
||||
self.fonts.retain(|pixels_per_point, _| {
|
||||
if active_pixels_per_point.contains(pixels_per_point) {
|
||||
true
|
||||
} else {
|
||||
#[cfg(feature = "log")]
|
||||
log::trace!(
|
||||
"Freeing Fonts with pixels_per_point={} because it is no longer needed",
|
||||
pixels_per_point.into_inner()
|
||||
);
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
platform_output.num_completed_passes += 1;
|
||||
|
||||
FullOutput {
|
||||
@@ -2664,7 +2633,7 @@ impl Context {
|
||||
|
||||
self.write(|ctx| {
|
||||
let tessellation_options = ctx.memory.options.tessellation_options;
|
||||
let texture_atlas = if let Some(fonts) = ctx.fonts.get(&pixels_per_point.into()) {
|
||||
let texture_atlas = if let Some(fonts) = ctx.fonts.as_ref() {
|
||||
fonts.texture_atlas()
|
||||
} else {
|
||||
#[cfg(feature = "log")]
|
||||
@@ -2673,13 +2642,8 @@ impl Context {
|
||||
.iter()
|
||||
.next()
|
||||
.expect("No fonts loaded")
|
||||
.1
|
||||
.texture_atlas()
|
||||
};
|
||||
let (font_tex_size, prepared_discs) = {
|
||||
let atlas = texture_atlas.lock();
|
||||
(atlas.size(), atlas.prepared_discs())
|
||||
};
|
||||
|
||||
let paint_stats = PaintStats::from_shapes(&shapes);
|
||||
let clipped_primitives = {
|
||||
@@ -2687,8 +2651,8 @@ impl Context {
|
||||
tessellator::Tessellator::new(
|
||||
pixels_per_point,
|
||||
tessellation_options,
|
||||
font_tex_size,
|
||||
prepared_discs,
|
||||
texture_atlas.size(),
|
||||
texture_atlas.prepared_discs(),
|
||||
)
|
||||
.tessellate_shapes(shapes)
|
||||
};
|
||||
|
||||
@@ -98,7 +98,7 @@ impl State {
|
||||
{
|
||||
// Paint location to left of `pos`:
|
||||
let location_galley =
|
||||
ctx.fonts(|f| f.layout(location, font_id.clone(), color, f32::INFINITY));
|
||||
ctx.fonts_mut(|f| f.layout(location, font_id.clone(), color, f32::INFINITY));
|
||||
let location_rect =
|
||||
Align2::RIGHT_TOP.anchor_size(pos - 4.0 * Vec2::X, location_galley.size());
|
||||
painter.galley(location_rect.min, location_galley, color);
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::sync::Arc;
|
||||
use emath::GuiRounding as _;
|
||||
use epaint::{
|
||||
CircleShape, ClippedShape, CornerRadius, PathStroke, RectShape, Shape, Stroke, StrokeKind,
|
||||
text::{Fonts, Galley, LayoutJob},
|
||||
text::{FontsView, Galley, LayoutJob},
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -141,14 +141,22 @@ impl Painter {
|
||||
self.pixels_per_point
|
||||
}
|
||||
|
||||
/// Read-only access to the shared [`Fonts`].
|
||||
/// Read-only access to the shared [`FontsView`].
|
||||
///
|
||||
/// See [`Context`] documentation for how locks work.
|
||||
#[inline]
|
||||
pub fn fonts<R>(&self, reader: impl FnOnce(&Fonts) -> R) -> R {
|
||||
pub fn fonts<R>(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R {
|
||||
self.ctx.fonts(reader)
|
||||
}
|
||||
|
||||
/// Read-write access to the shared [`FontsView`].
|
||||
///
|
||||
/// See [`Context`] documentation for how locks work.
|
||||
#[inline]
|
||||
pub fn fonts_mut<R>(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R {
|
||||
self.ctx.fonts_mut(reader)
|
||||
}
|
||||
|
||||
/// Where we paint
|
||||
#[inline]
|
||||
pub fn layer_id(&self) -> LayerId {
|
||||
@@ -525,7 +533,7 @@ impl Painter {
|
||||
color: crate::Color32,
|
||||
wrap_width: f32,
|
||||
) -> Arc<Galley> {
|
||||
self.fonts(|f| f.layout(text, font_id, color, wrap_width))
|
||||
self.fonts_mut(|f| f.layout(text, font_id, color, wrap_width))
|
||||
}
|
||||
|
||||
/// Will line break at `\n`.
|
||||
@@ -539,7 +547,7 @@ impl Painter {
|
||||
font_id: FontId,
|
||||
color: crate::Color32,
|
||||
) -> Arc<Galley> {
|
||||
self.fonts(|f| f.layout(text, font_id, color, f32::INFINITY))
|
||||
self.fonts_mut(|f| f.layout(text, font_id, color, f32::INFINITY))
|
||||
}
|
||||
|
||||
/// Lay out this text layut job in a galley.
|
||||
@@ -548,7 +556,7 @@ impl Painter {
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn layout_job(&self, layout_job: LayoutJob) -> Arc<Galley> {
|
||||
self.fonts(|f| f.layout_job(layout_job))
|
||||
self.fonts_mut(|f| f.layout_job(layout_job))
|
||||
}
|
||||
|
||||
/// Paint text that has already been laid out in a [`Galley`].
|
||||
|
||||
@@ -2790,7 +2790,6 @@ impl Widget for &mut FontTweak {
|
||||
scale,
|
||||
y_offset_factor,
|
||||
y_offset,
|
||||
baseline_offset_factor,
|
||||
} = self;
|
||||
|
||||
ui.label("Scale");
|
||||
@@ -2806,10 +2805,6 @@ impl Widget for &mut FontTweak {
|
||||
ui.add(DragValue::new(y_offset).speed(-0.02));
|
||||
ui.end_row();
|
||||
|
||||
ui.label("baseline_offset_factor");
|
||||
ui.add(DragValue::new(baseline_offset_factor).speed(-0.0025));
|
||||
ui.end_row();
|
||||
|
||||
if ui.button("Reset").clicked() {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
use emath::GuiRounding as _;
|
||||
use epaint::mutex::RwLock;
|
||||
use epaint::text::FontsView;
|
||||
use std::{any::Any, hash::Hash, sync::Arc};
|
||||
|
||||
use crate::ClosableTag;
|
||||
@@ -16,9 +17,7 @@ use crate::{
|
||||
WidgetRect, WidgetText,
|
||||
containers::{CollapsingHeader, CollapsingResponse, Frame},
|
||||
ecolor::Hsva,
|
||||
emath, epaint,
|
||||
epaint::text::Fonts,
|
||||
grid,
|
||||
emath, epaint, grid,
|
||||
layout::{Direction, Layout},
|
||||
pass_state,
|
||||
placer::Placer,
|
||||
@@ -735,7 +734,7 @@ impl Ui {
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
pub fn text_style_height(&self, style: &TextStyle) -> f32 {
|
||||
self.fonts(|f| f.row_height(&style.resolve(self.style())))
|
||||
self.fonts_mut(|f| f.row_height(&style.resolve(self.style())))
|
||||
}
|
||||
|
||||
/// Screen-space rectangle for clipping what we paint in this ui.
|
||||
@@ -847,11 +846,17 @@ impl Ui {
|
||||
self.ctx().output_mut(writer)
|
||||
}
|
||||
|
||||
/// Read-only access to [`Fonts`].
|
||||
/// Read-only access to [`FontsView`].
|
||||
#[inline]
|
||||
pub fn fonts<R>(&self, reader: impl FnOnce(&Fonts) -> R) -> R {
|
||||
pub fn fonts<R>(&self, reader: impl FnOnce(&FontsView<'_>) -> R) -> R {
|
||||
self.ctx().fonts(reader)
|
||||
}
|
||||
|
||||
/// Read-write access to [`FontsView`].
|
||||
#[inline]
|
||||
pub fn fonts_mut<R>(&self, reader: impl FnOnce(&mut FontsView<'_>) -> R) -> R {
|
||||
self.ctx().fonts_mut(reader)
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@@ -307,7 +307,7 @@ impl RichText {
|
||||
/// Read the font height of the selected text style.
|
||||
///
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
pub fn font_height(&self, fonts: &epaint::Fonts, style: &Style) -> f32 {
|
||||
pub fn font_height(&self, fonts: &mut epaint::FontsView<'_>, style: &Style) -> f32 {
|
||||
let mut font_id = self.text_style.as_ref().map_or_else(
|
||||
|| FontSelection::Default.resolve(style),
|
||||
|text_style| text_style.resolve(style),
|
||||
@@ -676,7 +676,7 @@ impl WidgetText {
|
||||
}
|
||||
|
||||
/// Returns a value rounded to [`emath::GUI_ROUNDING`].
|
||||
pub(crate) fn font_height(&self, fonts: &epaint::Fonts, style: &Style) -> f32 {
|
||||
pub(crate) fn font_height(&self, fonts: &mut epaint::FontsView<'_>, style: &Style) -> f32 {
|
||||
match self {
|
||||
Self::Text(_) => fonts.row_height(&FontSelection::Default.resolve(style)),
|
||||
Self::RichText(text) => text.font_height(fonts, style),
|
||||
@@ -762,7 +762,7 @@ impl WidgetText {
|
||||
},
|
||||
);
|
||||
layout_job.wrap = text_wrapping;
|
||||
ctx.fonts(|f| f.layout_job(layout_job))
|
||||
ctx.fonts_mut(|f| f.layout_job(layout_job))
|
||||
}
|
||||
Self::RichText(text) => {
|
||||
let mut layout_job = Arc::unwrap_or_clone(text).into_layout_job(
|
||||
@@ -771,12 +771,12 @@ impl WidgetText {
|
||||
default_valign,
|
||||
);
|
||||
layout_job.wrap = text_wrapping;
|
||||
ctx.fonts(|f| f.layout_job(layout_job))
|
||||
ctx.fonts_mut(|f| f.layout_job(layout_job))
|
||||
}
|
||||
Self::LayoutJob(job) => {
|
||||
let mut job = Arc::unwrap_or_clone(job);
|
||||
job.wrap = text_wrapping;
|
||||
ctx.fonts(|f| f.layout_job(job))
|
||||
ctx.fonts_mut(|f| f.layout_job(job))
|
||||
}
|
||||
Self::Galley(galley) => galley,
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ impl Label {
|
||||
if let Some(first_section) = layout_job.sections.first_mut() {
|
||||
first_section.leading_space = first_row_indentation;
|
||||
}
|
||||
let galley = ui.fonts(|fonts| fonts.layout_job(layout_job));
|
||||
let galley = ui.fonts_mut(|fonts| fonts.layout_job(layout_job));
|
||||
|
||||
let pos = pos2(ui.max_rect().left(), ui.cursor().top());
|
||||
assert!(!galley.rows.is_empty(), "Galleys are never empty");
|
||||
@@ -252,7 +252,7 @@ impl Label {
|
||||
layout_job.justify = ui.layout().horizontal_justify();
|
||||
}
|
||||
|
||||
let galley = ui.fonts(|fonts| fonts.layout_job(layout_job));
|
||||
let galley = ui.fonts_mut(|fonts| fonts.layout_job(layout_job));
|
||||
let (rect, mut response) = ui.allocate_exact_size(galley.size(), sense);
|
||||
response.intrinsic_size = Some(galley.intrinsic_size());
|
||||
let galley_pos = match galley.job.halign {
|
||||
|
||||
@@ -266,7 +266,7 @@ impl<'t> TextEdit<'t> {
|
||||
/// let mut layouter = |ui: &egui::Ui, buf: &dyn egui::TextBuffer, wrap_width: f32| {
|
||||
/// let mut layout_job: egui::text::LayoutJob = my_memoized_highlighter(buf.as_str());
|
||||
/// layout_job.wrap.max_width = wrap_width;
|
||||
/// ui.fonts(|f| f.layout_job(layout_job))
|
||||
/// ui.fonts_mut(|f| f.layout_job(layout_job))
|
||||
/// };
|
||||
/// ui.add(egui::TextEdit::multiline(&mut my_code).layouter(&mut layouter));
|
||||
/// # });
|
||||
@@ -504,7 +504,7 @@ impl TextEdit<'_> {
|
||||
let hint_text_str = hint_text.text().to_owned();
|
||||
|
||||
let font_id = font_selection.resolve(ui.style());
|
||||
let row_height = ui.fonts(|f| f.row_height(&font_id));
|
||||
let row_height = ui.fonts_mut(|f| f.row_height(&font_id));
|
||||
const MIN_WIDTH: f32 = 24.0; // Never make a [`TextEdit`] more narrow than this.
|
||||
let available_width = (ui.available_width() - margin.sum().x).at_least(MIN_WIDTH);
|
||||
let desired_width = desired_width.unwrap_or_else(|| ui.spacing().text_edit_width);
|
||||
@@ -522,7 +522,7 @@ impl TextEdit<'_> {
|
||||
} else {
|
||||
LayoutJob::simple_singleline(text, font_id_clone.clone(), text_color)
|
||||
};
|
||||
ui.fonts(|f| f.layout_job(layout_job))
|
||||
ui.fonts_mut(|f| f.layout_job(layout_job))
|
||||
};
|
||||
|
||||
let layouter = layouter.unwrap_or(&mut default_layouter);
|
||||
|
||||
Reference in New Issue
Block a user