From 58a8f743befadcb5c637cc6e873b0b4c21c9228b Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Wed, 20 May 2020 21:22:42 +0200 Subject: [PATCH] Optimize and clean up text output --- emigui/src/context.rs | 11 ++++++---- emigui/src/paint/font.rs | 18 +++++++-------- emigui/src/ui.rs | 12 +++++----- emigui/src/widgets.rs | 39 ++++++++++++++++++++++----------- emigui/src/widgets/slider.rs | 3 +-- emigui/src/widgets/text_edit.rs | 8 +++---- 6 files changed, 52 insertions(+), 39 deletions(-) diff --git a/emigui/src/context.rs b/emigui/src/context.rs index 21f94af09..29897615d 100644 --- a/emigui/src/context.rs +++ b/emigui/src/context.rs @@ -377,7 +377,8 @@ impl Context { // --------------------------------------------------------------------- - pub fn show_error(&self, pos: Pos2, text: &str) { + pub fn show_error(&self, pos: Pos2, text: impl Into) { + let text = text.into(); let align = (Align::Min, Align::Min); let layer = Layer::debug(); let text_style = TextStyle::Monospace; @@ -396,7 +397,8 @@ impl Context { self.add_galley(layer, rect.min, galley, text_style, Some(color::RED)); } - pub fn debug_text(&self, pos: Pos2, text: &str) { + pub fn debug_text(&self, pos: Pos2, text: impl Into) { + let text = text.into(); let layer = Layer::debug(); let align = (Align::Min, Align::Min); self.floating_text( @@ -409,7 +411,8 @@ impl Context { ); } - pub fn debug_rect(&self, rect: Rect, text: &str) { + pub fn debug_rect(&self, rect: Rect, text: impl Into) { + let text = text.into(); let layer = Layer::debug(); self.add_paint_cmd( layer, @@ -431,7 +434,7 @@ impl Context { &self, layer: Layer, pos: Pos2, - text: &str, + text: String, text_style: TextStyle, align: (Align, Align), text_color: Option, diff --git a/emigui/src/paint/font.rs b/emigui/src/paint/font.rs index 539ebf85c..65fad93a3 100644 --- a/emigui/src/paint/font.rs +++ b/emigui/src/paint/font.rs @@ -306,8 +306,8 @@ impl Font { /// Typeset the given text onto one line. /// Assumes there are no \n in the text. /// Always returns exactly one frament. - pub fn layout_single_line(&self, text: &str) -> Galley { - let x_offsets = self.layout_single_line_fragment(text); + pub fn layout_single_line(&self, text: String) -> Galley { + let x_offsets = self.layout_single_line_fragment(&text); let line = Line { x_offsets, y_min: 0.0, @@ -317,7 +317,7 @@ impl Font { let width = line.max_x(); let size = vec2(width, self.height()); let galley = Galley { - text: text.to_owned(), + text, lines: vec![line], size, }; @@ -325,7 +325,7 @@ impl Font { galley } - pub fn layout_multiline(&self, text: &str, max_width_in_points: f32) -> Galley { + pub fn layout_multiline(&self, text: String, max_width_in_points: f32) -> Galley { let line_spacing = self.line_spacing(); let mut cursor_y = 0.0; let mut lines = Vec::new(); @@ -372,11 +372,7 @@ impl Font { } let size = vec2(widest_line, lines.last().unwrap().y_max); - let galley = Galley { - text: text.to_owned(), - lines, - size, - }; + let galley = Galley { text, lines, size }; galley.sanity_check(); galley } @@ -387,7 +383,9 @@ impl Font { fn layout_single_line_fragment(&self, text: &str) -> Vec { let scale_in_pixels = Scale::uniform(self.scale_in_pixels); - let mut x_offsets = vec![0.0]; + let mut x_offsets = Vec::with_capacity(text.chars().count() + 1); + x_offsets.push(0.0); + let mut cursor_x_in_points = 0.0f32; let mut last_glyph_id = None; diff --git a/emigui/src/ui.rs b/emigui/src/ui.rs index 21e50c2fd..79f4e5425 100644 --- a/emigui/src/ui.rs +++ b/emigui/src/ui.rs @@ -434,16 +434,16 @@ impl Ui { } /// Paint some debug text at current cursor - pub fn debug_text(&self, text: &str) { + pub fn debug_text(&self, text: impl Into) { self.debug_text_at(self.cursor, text); } // TODO: AsRef - pub fn debug_text_at(&self, pos: Pos2, text: &str) { + pub fn debug_text_at(&self, pos: Pos2, text: impl Into) { self.ctx.debug_text(pos, text); } - pub fn debug_rect(&mut self, rect: Rect, text: &str) { + pub fn debug_rect(&mut self, rect: Rect, text: impl Into) { self.add_paint_cmd(PaintCmd::Rect { corner_radius: 0.0, fill_color: None, @@ -452,7 +452,7 @@ impl Ui { }); let align = (Align::Min, Align::Min); let text_style = TextStyle::Monospace; - self.floating_text(rect.min, text, text_style, align, Some(color::RED)); + self.floating_text(rect.min, text.into(), text_style, align, Some(color::RED)); } /// Show some text anywhere in the ui. @@ -462,13 +462,13 @@ impl Ui { pub fn floating_text( &mut self, pos: Pos2, - text: &str, + text: impl Into, text_style: TextStyle, align: (Align, Align), text_color: Option, ) -> Rect { let font = &self.fonts()[text_style]; - let galley = font.layout_multiline(text, f32::INFINITY); + let galley = font.layout_multiline(text.into(), f32::INFINITY); let rect = align_rect(Rect::from_min_size(pos, galley.size), align); self.add_galley(rect.min, galley, text_style, text_color); rect diff --git a/emigui/src/widgets.rs b/emigui/src/widgets.rs index 90d4f8640..728d08e56 100644 --- a/emigui/src/widgets.rs +++ b/emigui/src/widgets.rs @@ -66,9 +66,9 @@ impl Label { pub fn layout(&self, max_width: f32, ui: &Ui) -> font::Galley { let font = &ui.fonts()[self.text_style]; if self.multiline { - font.layout_multiline(&self.text, max_width) + font.layout_multiline(self.text.clone(), max_width) // TODO: avoid clone } else { - font.layout_single_line(&self.text) + font.layout_single_line(self.text.clone()) // TODO: avoid clone } } @@ -143,17 +143,19 @@ impl Hyperlink { impl Widget for Hyperlink { fn ui(self, ui: &mut Ui) -> GuiResponse { + let Hyperlink { url, text } = self; + let color = color::LIGHT_BLUE; let text_style = TextStyle::Body; - let id = ui.make_child_id(&self.url); + let id = ui.make_child_id(&url); let font = &ui.fonts()[text_style]; - let galley = font.layout_multiline(&self.text, ui.available().width()); + let galley = font.layout_multiline(text, ui.available().width()); let interact = ui.reserve_space(galley.size, Some(id)); if interact.hovered { ui.ctx().output().cursor_icon = CursorIcon::PointingHand; } if interact.clicked { - ui.ctx().output().open_url = Some(self.url); + ui.ctx().output().open_url = Some(url); } if interact.hovered { @@ -225,7 +227,7 @@ impl Widget for Button { let id = ui.make_position_id(); let font = &ui.fonts()[text_style]; - let galley = font.layout_multiline(&text, ui.available().width()); + let galley = font.layout_multiline(text, ui.available().width()); let padding = ui.style().button_padding; let mut size = galley.size + 2.0 * padding; size.y = size.y.max(ui.style().clickable_diameter); @@ -271,10 +273,16 @@ impl<'a> Checkbox<'a> { impl<'a> Widget for Checkbox<'a> { fn ui(self, ui: &mut Ui) -> GuiResponse { + let Checkbox { + checked, + text, + text_color, + } = self; + let id = ui.make_position_id(); let text_style = TextStyle::Button; let font = &ui.fonts()[text_style]; - let galley = font.layout_single_line(&self.text); + let galley = font.layout_single_line(text); let interact = ui.reserve_space( ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0) @@ -285,7 +293,7 @@ impl<'a> Widget for Checkbox<'a> { let text_cursor = interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0); if interact.clicked { - *self.checked = !*self.checked; + *checked = !*checked; } let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect); ui.add_paint_cmd(PaintCmd::Rect { @@ -297,7 +305,7 @@ impl<'a> Widget for Checkbox<'a> { let stroke_color = ui.style().interact(&interact).stroke_color; - if *self.checked { + if *checked { ui.add_paint_cmd(PaintCmd::LinePath { points: vec![ pos2(small_icon_rect.left(), small_icon_rect.center().y), @@ -309,7 +317,7 @@ impl<'a> Widget for Checkbox<'a> { }); } - let text_color = self.text_color.unwrap_or(stroke_color); + let text_color = text_color.unwrap_or(stroke_color); ui.add_galley(text_cursor, galley, text_style, Some(text_color)); ui.response(interact) } @@ -345,10 +353,15 @@ pub fn radio(checked: bool, text: impl Into) -> RadioButton { impl Widget for RadioButton { fn ui(self, ui: &mut Ui) -> GuiResponse { + let RadioButton { + checked, + text, + text_color, + } = self; let id = ui.make_position_id(); let text_style = TextStyle::Button; let font = &ui.fonts()[text_style]; - let galley = font.layout_multiline(&self.text, ui.available().width()); + let galley = font.layout_multiline(text, ui.available().width()); let interact = ui.reserve_space( ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0) @@ -371,7 +384,7 @@ impl Widget for RadioButton { radius: big_icon_rect.width() / 2.0, }); - if self.checked { + if checked { ui.add_paint_cmd(PaintCmd::Circle { center: small_icon_rect.center(), fill_color: Some(stroke_color), @@ -380,7 +393,7 @@ impl Widget for RadioButton { }); } - let text_color = self.text_color.unwrap_or(stroke_color); + let text_color = text_color.unwrap_or(stroke_color); ui.add_galley(text_cursor, galley, text_style, Some(text_color)); ui.response(interact) } diff --git a/emigui/src/widgets/slider.rs b/emigui/src/widgets/slider.rs index 831573645..b4bd3f183 100644 --- a/emigui/src/widgets/slider.rs +++ b/emigui/src/widgets/slider.rs @@ -116,8 +116,7 @@ impl<'a> Widget for Slider<'a> { let slider_sans_text = Slider { text: None, ..self }; if text_on_top { - // let galley = font.layout_multiline(&full_text, ui.available().width()); - let galley = font.layout_single_line(&full_text); + let galley = font.layout_single_line(full_text); let pos = ui.reserve_space(galley.size, None).rect.min; ui.add_galley(pos, galley, text_style, text_color); slider_sans_text.ui(ui) diff --git a/emigui/src/widgets/text_edit.rs b/emigui/src/widgets/text_edit.rs index ad4bb826a..7463ad449 100644 --- a/emigui/src/widgets/text_edit.rs +++ b/emigui/src/widgets/text_edit.rs @@ -66,9 +66,9 @@ impl<'t> Widget for TextEdit<'t> { let line_spacing = font.line_spacing(); let available_width = ui.available().width(); let mut galley = if multiline { - font.layout_multiline(text.as_str(), available_width) + font.layout_multiline(text.clone(), available_width) } else { - font.layout_single_line(text.as_str()) + font.layout_single_line(text.clone()) }; let desired_size = galley.size.max(vec2(available_width, line_spacing)); let interact = ui.reserve_space(desired_size, Some(id)); @@ -108,9 +108,9 @@ impl<'t> Widget for TextEdit<'t> { // layout again to avoid frame delay: let font = &ui.fonts()[text_style]; galley = if multiline { - font.layout_multiline(text.as_str(), available_width) + font.layout_multiline(text.clone(), available_width) } else { - font.layout_single_line(text.as_str()) + font.layout_single_line(text.clone()) }; // dbg!(&galley);