From 8d854391df39ebf10ad611edbc432889fc1d1d78 Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Sat, 2 Oct 2021 21:43:17 +0200 Subject: [PATCH] TextEdit can now show immutable text --- CHANGELOG.md | 1 + egui/src/widgets/text_edit.rs | 59 ++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2251e5de..0238a659 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ NOTE: [`eframe`](eframe/CHANGELOG.md), [`egui_web`](egui_web/CHANGELOG.md), [`eg * `Fonts::layout_job*`: New text layout engine allowing mixing fonts, colors and styles, with underlining and strikethrough. * Add feature `"serialize"` separatedly from `"persistence"`. * Add `egui::widgets::global_dark_light_mode_buttons` to easily add buttons for switching the egui theme. +* `TextEdit` can now be used to show text which can be selectedd and copied, but not edited. ### Changed 🔧 * Label text will now be centered, right-aligned and/or justified based on the layout. diff --git a/egui/src/widgets/text_edit.rs b/egui/src/widgets/text_edit.rs index 32f3f76c..025eff02 100644 --- a/egui/src/widgets/text_edit.rs +++ b/egui/src/widgets/text_edit.rs @@ -119,6 +119,9 @@ impl CCursorPair { /// /// Most likely you will use a `String` which implements `TextBuffer`. pub trait TextBuffer: AsRef + Into { + /// Can this text be edited? + fn is_mutable(&self) -> bool; + /// Inserts text `text` into this buffer at character index `ch_idx`. /// /// # Notes @@ -162,6 +165,10 @@ pub trait TextBuffer: AsRef + Into { } impl TextBuffer for String { + fn is_mutable(&self) -> bool { + true + } + fn insert_text(&mut self, text: &str, ch_idx: usize) -> usize { // Get the byte index from the character index let byte_idx = self::byte_index_from_char_index(self, ch_idx); @@ -196,6 +203,19 @@ impl TextBuffer for String { } } +/// Immutable view of a &str! +impl<'a> TextBuffer for &'a str { + fn is_mutable(&self) -> bool { + false + } + + fn insert_text(&mut self, _text: &str, _ch_idx: usize) -> usize { + 0 + } + + fn delete_char_range(&mut self, _ch_range: Range) {} +} + /// A text region that the user can edit the contents of. /// /// See also [`Ui::text_edit_singleline`] and [`Ui::text_edit_multiline`]. @@ -222,6 +242,16 @@ impl TextBuffer for String { /// ui.add_sized(ui.available_size(), egui::TextEdit::multiline(&mut my_string)); /// ``` /// +/// +/// You can also use [`TextEdit`] to show text that can be selected, but not edited. +/// To do so, pass in a `&mut` reference to a `&str`, for instance: +/// +/// ``` +/// fn selectable_text(ui: &mut egui::Ui, mut text: &str) { +/// ui.add(egui::TextEdit::multiline(&mut text)); +/// } +/// ``` +/// #[must_use = "You should put this widget in an ui with `ui.add(widget);`"] pub struct TextEdit<'t, S: TextBuffer = String> { text: &'t mut S, @@ -405,6 +435,7 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> { impl<'t, S: TextBuffer> Widget for TextEdit<'t, S> { fn ui(self, ui: &mut Ui) -> Response { + let is_mutable = self.text.is_mutable(); let frame = self.frame; let enabled = self.enabled; let where_to_put_background = ui.painter().add(Shape::Noop); @@ -426,19 +457,31 @@ impl<'t, S: TextBuffer> Widget for TextEdit<'t, S> { if frame { let visuals = ui.style().interact(&response); let frame_rect = frame_rect.expand(visuals.expansion); - let shape = if response.has_focus() { - epaint::RectShape { - rect: frame_rect, - corner_radius: visuals.corner_radius, - // fill: ui.visuals().selection.bg_fill, - fill: ui.visuals().extreme_bg_color, - stroke: ui.visuals().selection.stroke, + let shape = if is_mutable { + if response.has_focus() { + epaint::RectShape { + rect: frame_rect, + corner_radius: visuals.corner_radius, + // fill: ui.visuals().selection.bg_fill, + fill: ui.visuals().extreme_bg_color, + stroke: ui.visuals().selection.stroke, + } + } else { + epaint::RectShape { + rect: frame_rect, + corner_radius: visuals.corner_radius, + fill: ui.visuals().extreme_bg_color, + stroke: visuals.bg_stroke, // TODO: we want to show something here, or a text-edit field doesn't "pop". + } } } else { + let visuals = &ui.style().visuals.widgets.inactive; epaint::RectShape { rect: frame_rect, corner_radius: visuals.corner_radius, - fill: ui.visuals().extreme_bg_color, + // fill: ui.visuals().extreme_bg_color, + // fill: visuals.bg_fill, + fill: Color32::TRANSPARENT, stroke: visuals.bg_stroke, // TODO: we want to show something here, or a text-edit field doesn't "pop". } };