diff --git a/egui/src/containers/window.rs b/egui/src/containers/window.rs
index 01545bb2b16..bad59e01c77 100644
--- a/egui/src/containers/window.rs
+++ b/egui/src/containers/window.rs
@@ -1,6 +1,6 @@
// WARNING: the code in here is horrible. It is a behemoth that needs breaking up into simpler parts.
-use crate::{widgets::*, *};
+use crate::{widget_text::WidgetTextGalley, *};
use epaint::*;
use super::*;
@@ -23,7 +23,7 @@ use super::*;
/// });
#[must_use = "You should call .show()"]
pub struct Window<'open> {
- title_label: Label,
+ title: WidgetText,
open: Option<&'open mut bool>,
area: Area,
frame: Option,
@@ -37,13 +37,14 @@ impl<'open> Window<'open> {
/// The window title is used as a unique [`Id`] and must be unique, and should not change.
/// This is true even if you disable the title bar with `.title_bar(false)`.
/// If you need a changing title, you must call `window.id(…)` with a fixed id.
- #[allow(clippy::needless_pass_by_value)]
- pub fn new(title: impl ToString) -> Self {
- let title = title.to_string();
- let area = Area::new(&title);
- let title_label = Label::new(title).text_style(TextStyle::Heading).wrap(false);
+ pub fn new(title: impl Into) -> Self {
+ let title = title
+ .into()
+ .fallback_text_style(TextStyle::Heading)
+ .wrap(false);
+ let area = Area::new(title.text());
Self {
- title_label,
+ title,
open: None,
area,
frame: None,
@@ -250,7 +251,7 @@ impl<'open> Window<'open> {
add_contents: Box R + 'c>,
) -> Option>> {
let Window {
- title_label,
+ title,
open,
area,
frame,
@@ -299,7 +300,7 @@ impl<'open> Window<'open> {
.and_then(|window_interaction| {
// Calculate roughly how much larger the window size is compared to the inner rect
let title_bar_height = if with_title_bar {
- title_label.font_height(ctx.fonts(), &ctx.style()) + title_content_spacing
+ title.font_height(ctx.fonts(), &ctx.style()) + title_content_spacing
} else {
0.0
};
@@ -336,7 +337,7 @@ impl<'open> Window<'open> {
let title_bar = if with_title_bar {
let title_bar = show_title_bar(
&mut frame.content_ui,
- title_label,
+ title,
show_close_button,
collapsing_id,
&mut collapsing,
@@ -745,22 +746,21 @@ fn paint_frame_interaction(
struct TitleBar {
id: Id,
- title_label: Label,
- title_galley: std::sync::Arc,
+ title_galley: WidgetTextGalley,
min_rect: Rect,
rect: Rect,
}
fn show_title_bar(
ui: &mut Ui,
- title_label: Label,
+ title: WidgetText,
show_close_button: bool,
collapsing_id: Id,
collapsing: &mut collapsing_header::State,
collapsible: bool,
) -> TitleBar {
let inner_response = ui.horizontal(|ui| {
- let height = title_label
+ let height = title
.font_height(ui.fonts(), ui.style())
.max(ui.spacing().interact_size.y);
ui.set_min_height(height);
@@ -782,7 +782,7 @@ fn show_title_bar(
collapsing_header::paint_icon(ui, openness, &collapse_button_response);
}
- let title_galley = title_label.layout(ui);
+ let title_galley = title.layout(ui, f32::INFINITY, TextStyle::Heading);
let minimum_width = if collapsible || show_close_button {
// If at least one button is shown we make room for both buttons (since title is centered):
@@ -795,7 +795,6 @@ fn show_title_bar(
TitleBar {
id,
- title_label,
title_galley,
min_rect,
rect: Rect::NAN, // Will be filled in later
@@ -830,20 +829,13 @@ impl TitleBar {
}
}
- // Always have inactive style for the window.
- // It is VERY annoying to e.g. change it when moving the window.
- let style = ui.visuals().widgets.inactive;
-
- self.title_label = self.title_label.text_color(style.fg_stroke.color);
-
let full_top_rect = Rect::from_x_y_ranges(self.rect.x_range(), self.min_rect.y_range());
let text_pos =
emath::align::center_size_in_rect(self.title_galley.size(), full_top_rect).left_top();
- let text_pos = text_pos - self.title_galley.rect.min.to_vec2();
+ let text_pos = text_pos - self.title_galley.galley().rect.min.to_vec2();
let text_pos = text_pos - 1.5 * Vec2::Y; // HACK: center on x-height of text (looks better)
- let text_color = ui.visuals().text_color();
- self.title_label
- .paint_galley(ui, text_pos, self.title_galley, false, text_color);
+ self.title_galley
+ .paint_with_color(ui, text_pos, ui.visuals().text_color());
if let Some(content_response) = &content_response {
// paint separator between title and content:
diff --git a/egui/src/widget_text.rs b/egui/src/widget_text.rs
index 88bda692618..4efda002091 100644
--- a/egui/src/widget_text.rs
+++ b/egui/src/widget_text.rs
@@ -35,6 +35,13 @@ impl RichText {
self
}
+ /// Set the [`TextStyle`] unless it has already been set
+ #[inline]
+ pub fn fallback_text_style(mut self, text_style: TextStyle) -> Self {
+ self.text_style.get_or_insert(text_style);
+ self
+ }
+
/// Use [`TextStyle::Heading`].
#[inline]
pub fn heading(self) -> Self {
@@ -67,12 +74,20 @@ impl RichText {
self
}
+ pub fn font_height(&self, fonts: &epaint::text::Fonts, style: &crate::Style) -> f32 {
+ let text_style = self
+ .text_style
+ .or(style.override_text_style)
+ .unwrap_or(style.body_text_style);
+ fonts.row_height(text_style)
+ }
+
pub fn layout(
self,
ui: &Ui,
wrap_width: f32,
default_text_style: TextStyle,
- ) -> WidgetTextLayout {
+ ) -> WidgetTextGalley {
let Self {
text,
text_style,
@@ -92,7 +107,7 @@ impl RichText {
if let Some(text_color) = text_color {
let galley = ui.fonts().layout(text, text_style, text_color, wrap_width);
- WidgetTextLayout {
+ WidgetTextGalley {
galley,
galley_has_color: true,
}
@@ -101,7 +116,7 @@ impl RichText {
.fonts()
.layout_delayed_color(text, text_style, wrap_width);
- WidgetTextLayout {
+ WidgetTextGalley {
galley,
galley_has_color: false,
}
@@ -142,6 +157,15 @@ impl WidgetText {
}
}
+ /// Set the [`TextStyle`] unless it has already been set
+ #[inline]
+ pub fn fallback_text_style(self, text_style: TextStyle) -> Self {
+ match self {
+ Self::RichText(text) => Self::RichText(text.fallback_text_style(text_style)),
+ Self::LayoutJob(_) | Self::Galley(_) => self,
+ }
+ }
+
/// Override text color if, and only if, this is a [`RichText`].
#[inline]
pub fn color(self, color: impl Into) -> Self {
@@ -160,22 +184,36 @@ impl WidgetText {
}
}
+ pub fn font_height(&self, fonts: &epaint::text::Fonts, style: &crate::Style) -> f32 {
+ match self {
+ Self::RichText(text) => text.font_height(fonts, style),
+ Self::LayoutJob(job) => job.font_height(fonts),
+ Self::Galley(galley) => {
+ if let Some(row) = galley.rows.first() {
+ row.height()
+ } else {
+ galley.size().y
+ }
+ }
+ }
+ }
+
pub fn layout(
self,
ui: &Ui,
wrap_width: f32,
default_text_style: TextStyle,
- ) -> WidgetTextLayout {
+ ) -> WidgetTextGalley {
match self {
Self::RichText(text) => text.layout(ui, wrap_width, default_text_style),
Self::LayoutJob(mut job) => {
job.wrap_width = wrap_width;
- WidgetTextLayout {
+ WidgetTextGalley {
galley: ui.fonts().layout_job(job),
galley_has_color: true,
}
}
- Self::Galley(galley) => WidgetTextLayout {
+ Self::Galley(galley) => WidgetTextGalley {
galley,
galley_has_color: true,
},
@@ -221,12 +259,12 @@ impl From> for WidgetText {
// ----------------------------------------------------------------------------
/// Text that has been layed out and ready to be painted.
-pub struct WidgetTextLayout {
+pub struct WidgetTextGalley {
galley: Arc,
galley_has_color: bool,
}
-impl WidgetTextLayout {
+impl WidgetTextGalley {
/// Size of the layed out text.
#[inline]
pub fn size(&self) -> crate::Vec2 {
@@ -239,6 +277,11 @@ impl WidgetTextLayout {
self.galley.text()
}
+ #[inline]
+ pub fn galley(&self) -> &Arc {
+ &self.galley
+ }
+
pub fn paint(self, ui: &Ui, text_pos: Pos2, visuals: &WidgetVisuals) {
if self.galley_has_color {
ui.painter().galley(text_pos, self.galley);
@@ -247,4 +290,9 @@ impl WidgetTextLayout {
.galley_with_color(text_pos, self.galley, visuals.text_color());
}
}
+
+ pub fn paint_with_color(self, ui: &Ui, text_pos: Pos2, text_color: Color32) {
+ ui.painter()
+ .galley_with_color(text_pos, self.galley, text_color);
+ }
}
diff --git a/epaint/src/text/text_layout_types.rs b/epaint/src/text/text_layout_types.rs
index 26ce416d1e0..c70efcfe58e 100644
--- a/epaint/src/text/text_layout_types.rs
+++ b/epaint/src/text/text_layout_types.rs
@@ -134,6 +134,15 @@ impl LayoutJob {
format,
});
}
+
+ /// The height of the tallest used font in the job.
+ pub fn font_height(&self, fonts: &crate::Fonts) -> f32 {
+ let mut max_height = 0.0_f32;
+ for section in &self.sections {
+ max_height = max_height.max(fonts.row_height(section.format.style));
+ }
+ max_height
+ }
}
impl std::hash::Hash for LayoutJob {