diff --git a/crates/egui/src/lib.rs b/crates/egui/src/lib.rs index 2201afefb39..7d4d6de3bc8 100644 --- a/crates/egui/src/lib.rs +++ b/crates/egui/src/lib.rs @@ -352,7 +352,7 @@ pub mod text { pub use crate::text_edit::CCursorRange; pub use epaint::text::{ cursor::CCursor, FontData, FontDefinitions, FontFamily, Fonts, Galley, LayoutJob, - LayoutSection, TextFormat, TAB_SIZE, + LayoutSection, TextFormat, TextWrapping, TAB_SIZE, }; } diff --git a/crates/egui_demo_lib/src/demo/demo_app_windows.rs b/crates/egui_demo_lib/src/demo/demo_app_windows.rs index 354bb44e6d7..02c88357c93 100644 --- a/crates/egui_demo_lib/src/demo/demo_app_windows.rs +++ b/crates/egui_demo_lib/src/demo/demo_app_windows.rs @@ -35,7 +35,8 @@ impl Default for Demos { Box::::default(), Box::::default(), Box::::default(), - Box::::default(), + Box::::default(), + Box::::default(), Box::::default(), Box::::default(), Box::::default(), diff --git a/crates/egui_demo_lib/src/demo/misc_demo_window.rs b/crates/egui_demo_lib/src/demo/misc_demo_window.rs index 3bbc0d1699c..195b79e223a 100644 --- a/crates/egui_demo_lib/src/demo/misc_demo_window.rs +++ b/crates/egui_demo_lib/src/demo/misc_demo_window.rs @@ -1,5 +1,5 @@ use super::*; -use egui::{epaint::text::TextWrapping, *}; +use egui::*; /// Showcase some ui code #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] @@ -7,8 +7,6 @@ use egui::{epaint::text::TextWrapping, *}; pub struct MiscDemoWindow { num_columns: usize, - text_break: TextBreakDemo, - widgets: Widgets, colors: ColorWidgets, custom_collapsing_header: CustomCollapsingHeader, @@ -24,8 +22,6 @@ impl Default for MiscDemoWindow { MiscDemoWindow { num_columns: 2, - text_break: Default::default(), - widgets: Default::default(), colors: Default::default(), custom_collapsing_header: Default::default(), @@ -72,8 +68,6 @@ impl View for MiscDemoWindow { .default_open(false) .show(ui, |ui| { text_layout_demo(ui); - ui.separator(); - self.text_break.ui(ui); ui.vertical_centered(|ui| { ui.add(crate::egui_github_link_file_line!()); }); @@ -644,106 +638,3 @@ fn text_layout_demo(ui: &mut Ui) { ui.label(job); } - -#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] -#[cfg_attr(feature = "serde", serde(default))] -struct TextBreakDemo { - break_anywhere: bool, - max_rows: usize, - overflow_character: Option, - extra_letter_spacing_pixels: i32, - line_height_pixels: u32, -} - -impl Default for TextBreakDemo { - fn default() -> Self { - Self { - max_rows: 3, - break_anywhere: true, - overflow_character: Some('…'), - extra_letter_spacing_pixels: 0, - line_height_pixels: 0, - } - } -} - -impl TextBreakDemo { - pub fn ui(&mut self, ui: &mut Ui) { - let Self { - break_anywhere, - max_rows, - overflow_character, - extra_letter_spacing_pixels, - line_height_pixels, - } = self; - - use egui::text::LayoutJob; - - let pixels_per_point = ui.ctx().pixels_per_point(); - let points_per_pixel = 1.0 / pixels_per_point; - - ui.horizontal(|ui| { - ui.add(DragValue::new(max_rows)); - ui.label("Max rows"); - }); - - ui.horizontal(|ui| { - ui.label("Line-break:"); - ui.radio_value(break_anywhere, false, "word boundaries"); - ui.radio_value(break_anywhere, true, "anywhere"); - }); - - ui.horizontal(|ui| { - ui.selectable_value(overflow_character, None, "None"); - ui.selectable_value(overflow_character, Some('…'), "…"); - ui.selectable_value(overflow_character, Some('—'), "—"); - ui.selectable_value(overflow_character, Some('-'), " - "); - ui.label("Overflow character"); - }); - - ui.horizontal(|ui| { - ui.label("Extra letter spacing in pixels (NOT points):"); - ui.add(egui::DragValue::new(extra_letter_spacing_pixels)); - }); - - ui.horizontal(|ui| { - ui.label("Line height in pixels (NOT points):"); - if ui - .selectable_label(*line_height_pixels == 0, "Default") - .clicked() - { - *line_height_pixels = 0; - } - if ui - .selectable_label(*line_height_pixels != 0, "Custom") - .clicked() - { - *line_height_pixels = (pixels_per_point * 20.0).round() as _; - } - if *line_height_pixels != 0 { - ui.add(egui::DragValue::new(line_height_pixels)); - } - }); - - ui.add_space(8.0); - - let mut job = LayoutJob::single_section( - crate::LOREM_IPSUM_LONG.to_owned(), - TextFormat { - extra_letter_spacing: points_per_pixel * *extra_letter_spacing_pixels as f32, - line_height: (*line_height_pixels != 0) - .then_some(points_per_pixel * *line_height_pixels as f32), - background: ui.visuals().extreme_bg_color.gamma_multiply(0.5), - ..Default::default() - }, - ); - job.wrap = TextWrapping { - max_rows: *max_rows, - break_anywhere: *break_anywhere, - overflow_character: *overflow_character, - ..Default::default() - }; - - ui.label(job); // `Label` overrides some of the wrapping settings, e.g. wrap width - } -} diff --git a/crates/egui_demo_lib/src/demo/mod.rs b/crates/egui_demo_lib/src/demo/mod.rs index dddf215d012..220fbbcd11e 100644 --- a/crates/egui_demo_lib/src/demo/mod.rs +++ b/crates/egui_demo_lib/src/demo/mod.rs @@ -26,6 +26,7 @@ pub mod strip_demo; pub mod table_demo; pub mod tests; pub mod text_edit; +pub mod text_layout; pub mod toggle_switch; pub mod widget_gallery; pub mod window_options; diff --git a/crates/egui_demo_lib/src/demo/text_edit.rs b/crates/egui_demo_lib/src/demo/text_edit.rs index 6ad3f2420af..bd34f9750c8 100644 --- a/crates/egui_demo_lib/src/demo/text_edit.rs +++ b/crates/egui_demo_lib/src/demo/text_edit.rs @@ -2,11 +2,11 @@ #[derive(PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "serde", serde(default))] -pub struct TextEdit { +pub struct TextEditDemo { pub text: String, } -impl Default for TextEdit { +impl Default for TextEditDemo { fn default() -> Self { Self { text: "Edit this text".to_owned(), @@ -14,7 +14,7 @@ impl Default for TextEdit { } } -impl super::Demo for TextEdit { +impl super::Demo for TextEditDemo { fn name(&self) -> &'static str { "🖹 TextEdit" } @@ -30,7 +30,7 @@ impl super::Demo for TextEdit { } } -impl super::View for TextEdit { +impl super::View for TextEditDemo { fn ui(&mut self, ui: &mut egui::Ui) { let Self { text } = self; diff --git a/crates/egui_demo_lib/src/demo/text_layout.rs b/crates/egui_demo_lib/src/demo/text_layout.rs new file mode 100644 index 00000000000..01a5c7787a3 --- /dev/null +++ b/crates/egui_demo_lib/src/demo/text_layout.rs @@ -0,0 +1,135 @@ +/// Showcase text layout +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +#[cfg_attr(feature = "serde", serde(default))] +pub struct TextLayoutDemo { + break_anywhere: bool, + max_rows: usize, + overflow_character: Option, + extra_letter_spacing_pixels: i32, + line_height_pixels: u32, +} + +impl Default for TextLayoutDemo { + fn default() -> Self { + Self { + max_rows: 3, + break_anywhere: true, + overflow_character: Some('…'), + extra_letter_spacing_pixels: 0, + line_height_pixels: 0, + } + } +} + +impl super::Demo for TextLayoutDemo { + fn name(&self) -> &'static str { + "🖹 Text Layout" + } + + fn show(&mut self, ctx: &egui::Context, open: &mut bool) { + egui::Window::new(self.name()) + .open(open) + .resizable(true) + .show(ctx, |ui| { + use super::View as _; + self.ui(ui); + }); + } +} + +impl super::View for TextLayoutDemo { + fn ui(&mut self, ui: &mut egui::Ui) { + let Self { + break_anywhere, + max_rows, + overflow_character, + extra_letter_spacing_pixels, + line_height_pixels, + } = self; + + use egui::text::LayoutJob; + + let pixels_per_point = ui.ctx().pixels_per_point(); + let points_per_pixel = 1.0 / pixels_per_point; + + ui.vertical_centered(|ui| { + ui.add(crate::egui_github_link_file_line!()); + }); + + ui.add_space(12.0); + + egui::Grid::new("TextLayoutDemo") + .num_columns(2) + .show(ui, |ui| { + ui.label("Max rows:"); + ui.add(egui::DragValue::new(max_rows)); + ui.end_row(); + + ui.label("Line-break:"); + ui.horizontal(|ui| { + ui.radio_value(break_anywhere, false, "word boundaries"); + ui.radio_value(break_anywhere, true, "anywhere"); + }); + ui.end_row(); + + ui.label("Overflow character:"); + ui.horizontal(|ui| { + ui.selectable_value(overflow_character, None, "None"); + ui.selectable_value(overflow_character, Some('…'), "…"); + ui.selectable_value(overflow_character, Some('—'), "—"); + ui.selectable_value(overflow_character, Some('-'), " - "); + }); + ui.end_row(); + + ui.label("Extra letter spacing:"); + ui.add(egui::DragValue::new(extra_letter_spacing_pixels).suffix(" pixels")); + ui.end_row(); + + ui.label("Line height:"); + ui.horizontal(|ui| { + if ui + .selectable_label(*line_height_pixels == 0, "Default") + .clicked() + { + *line_height_pixels = 0; + } + if ui + .selectable_label(*line_height_pixels != 0, "Custom") + .clicked() + { + *line_height_pixels = (pixels_per_point * 20.0).round() as _; + } + if *line_height_pixels != 0 { + ui.add(egui::DragValue::new(line_height_pixels).suffix(" pixels")); + } + }); + ui.end_row(); + }); + + ui.add_space(12.0); + + egui::ScrollArea::vertical().show(ui, |ui| { + let extra_letter_spacing = points_per_pixel * *extra_letter_spacing_pixels as f32; + let line_height = + (*line_height_pixels != 0).then_some(points_per_pixel * *line_height_pixels as f32); + + let mut job = LayoutJob::single_section( + crate::LOREM_IPSUM_LONG.to_owned(), + egui::TextFormat { + extra_letter_spacing, + line_height, + ..Default::default() + }, + ); + job.wrap = egui::text::TextWrapping { + max_rows: *max_rows, + break_anywhere: *break_anywhere, + overflow_character: *overflow_character, + ..Default::default() + }; + + // NOTE: `Label` overrides some of the wrapping settings, e.g. wrap width + ui.label(job); + }); + } +}