mirror of
https://github.com/emilk/egui.git
synced 2026-08-31 13:50:04 -04:00
Center-align all text vertically (#5117)
* Closes https://github.com/emilk/egui/issues/4929 * Builds on top of https://github.com/emilk/egui/pull/2724 by @lictex (ptal!) * Implement `Center` and `Max` vertical text alignment properly * Change default vertical alignment of text to centering The end result is that text centers better in buttons and other places, especially when mixing in emojis. Before, mixing text of different heights (e.g. emojis and latin text) in a label or button would cause the text to jump vertically. ## Before This is `master`, with custom `FontTweak` to move fonts up and down: <img width="1714" alt="image" src="https://github.com/user-attachments/assets/a10e2927-e824-4580-baea-124c0b38a527"> <img width="102" alt="image" src="https://github.com/user-attachments/assets/cd41f415-197b-42cd-9558-d46d63c21dcb"> ## After This PR, with the default (zero) `FontTweak` <img width="102" alt="image" src="https://github.com/user-attachments/assets/15e7d896-66b1-4996-ab58-dd1850b19a63"> <img width="1714" alt="image" src="https://github.com/user-attachments/assets/54ec708c-7698-4754-b1fc-fea0fd240ec9">
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
|
||||
use std::{collections::BTreeMap, ops::RangeInclusive, sync::Arc};
|
||||
|
||||
use emath::Align;
|
||||
use epaint::{text::FontTweak, Rounding, Shadow, Stroke};
|
||||
|
||||
use crate::{
|
||||
@@ -196,6 +197,11 @@ pub struct Style {
|
||||
/// which will take precedence over this.
|
||||
pub override_font_id: Option<FontId>,
|
||||
|
||||
/// How to vertically align text.
|
||||
///
|
||||
/// Set to `None` to use align that depends on the current layout.
|
||||
pub override_text_valign: Option<Align>,
|
||||
|
||||
/// The [`FontFamily`] and size you want to use for a specific [`TextStyle`].
|
||||
///
|
||||
/// The most convenient way to look something up in this is to use [`TextStyle::resolve`].
|
||||
@@ -1201,6 +1207,7 @@ impl Default for Style {
|
||||
Self {
|
||||
override_font_id: None,
|
||||
override_text_style: None,
|
||||
override_text_valign: Some(Align::Center),
|
||||
text_styles: default_text_styles(),
|
||||
drag_value_text_style: TextStyle::Button,
|
||||
number_formatter: NumberFormatter(Arc::new(emath::format_with_decimals_in_range)),
|
||||
@@ -1501,6 +1508,7 @@ impl Style {
|
||||
let Self {
|
||||
override_font_id,
|
||||
override_text_style,
|
||||
override_text_valign,
|
||||
text_styles,
|
||||
drag_value_text_style,
|
||||
number_formatter: _, // can't change callbacks in the UI
|
||||
@@ -1534,7 +1542,7 @@ impl Style {
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Override text style");
|
||||
crate::ComboBox::from_id_salt("Override text style")
|
||||
crate::ComboBox::from_id_salt("override_text_style")
|
||||
.selected_text(match override_text_style {
|
||||
None => "None".to_owned(),
|
||||
Some(override_text_style) => override_text_style.to_string(),
|
||||
@@ -1550,6 +1558,28 @@ impl Style {
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
fn valign_name(valign: Align) -> &'static str {
|
||||
match valign {
|
||||
Align::TOP => "Top",
|
||||
Align::Center => "Center",
|
||||
Align::BOTTOM => "Bottom",
|
||||
}
|
||||
}
|
||||
|
||||
ui.label("Override text valign");
|
||||
crate::ComboBox::from_id_salt("override_text_valign")
|
||||
.selected_text(match override_text_valign {
|
||||
None => "None",
|
||||
Some(override_text_valign) => valign_name(*override_text_valign),
|
||||
})
|
||||
.show_ui(ui, |ui| {
|
||||
ui.selectable_value(override_text_valign, None, "None");
|
||||
for align in [Align::TOP, Align::Center, Align::BOTTOM] {
|
||||
ui.selectable_value(override_text_valign, Some(align), valign_name(align));
|
||||
}
|
||||
});
|
||||
ui.end_row();
|
||||
|
||||
ui.label("Text style of DragValue");
|
||||
crate::ComboBox::from_id_salt("drag_value_text_style")
|
||||
.selected_text(drag_value_text_style.to_string())
|
||||
|
||||
@@ -77,7 +77,7 @@ pub fn update_accesskit_for_text_widget(
|
||||
value.push(glyph.chr);
|
||||
character_lengths.push((value.len() - old_len) as _);
|
||||
character_positions.push(glyph.pos.x - row.rect.min.x);
|
||||
character_widths.push(glyph.size.x);
|
||||
character_widths.push(glyph.advance_width);
|
||||
}
|
||||
|
||||
if row.ends_with_newline {
|
||||
|
||||
@@ -617,6 +617,14 @@ impl Ui {
|
||||
self.wrap_mode() == TextWrapMode::Wrap
|
||||
}
|
||||
|
||||
/// How to vertically align text
|
||||
#[inline]
|
||||
pub fn text_valign(&self) -> Align {
|
||||
self.style()
|
||||
.override_text_valign
|
||||
.unwrap_or_else(|| self.layout().vertical_align())
|
||||
}
|
||||
|
||||
/// Create a painter for a sub-region of this Ui.
|
||||
///
|
||||
/// The clip-rect of the returned [`Painter`] will be the intersection
|
||||
|
||||
@@ -648,7 +648,7 @@ impl WidgetText {
|
||||
available_width: f32,
|
||||
fallback_font: impl Into<FontSelection>,
|
||||
) -> Arc<Galley> {
|
||||
let valign = ui.layout().vertical_align();
|
||||
let valign = ui.text_valign();
|
||||
let style = ui.style();
|
||||
|
||||
let wrap_mode = wrap_mode.unwrap_or_else(|| ui.wrap_mode());
|
||||
|
||||
@@ -251,9 +251,9 @@ impl Widget for Button<'_> {
|
||||
if image.is_some() && galley.is_some() {
|
||||
desired_size.x += ui.spacing().icon_spacing;
|
||||
}
|
||||
if let Some(text) = &galley {
|
||||
desired_size.x += text.size().x;
|
||||
desired_size.y = desired_size.y.max(text.size().y);
|
||||
if let Some(galley) = &galley {
|
||||
desired_size.x += galley.size().x;
|
||||
desired_size.y = desired_size.y.max(galley.size().y);
|
||||
}
|
||||
if let Some(shortcut_galley) = &shortcut_galley {
|
||||
desired_size.x += gap_before_shortcut_text + shortcut_galley.size().x;
|
||||
|
||||
@@ -162,7 +162,7 @@ impl Label {
|
||||
return (pos, galley, response);
|
||||
}
|
||||
|
||||
let valign = ui.layout().vertical_align();
|
||||
let valign = ui.text_valign();
|
||||
let mut layout_job = self
|
||||
.text
|
||||
.into_layout_job(ui.style(), FontSelection::Default, valign);
|
||||
|
||||
Reference in New Issue
Block a user