TextEdit can now show immutable text

This commit is contained in:
Emil Ernerfeldt 2021-10-02 21:43:17 +02:00
parent 8ce7fadc9f
commit 8d854391df
2 changed files with 52 additions and 8 deletions

View file

@ -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. * `Fonts::layout_job*`: New text layout engine allowing mixing fonts, colors and styles, with underlining and strikethrough.
* Add feature `"serialize"` separatedly from `"persistence"`. * Add feature `"serialize"` separatedly from `"persistence"`.
* Add `egui::widgets::global_dark_light_mode_buttons` to easily add buttons for switching the egui theme. * 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 🔧 ### Changed 🔧
* Label text will now be centered, right-aligned and/or justified based on the layout. * Label text will now be centered, right-aligned and/or justified based on the layout.

View file

@ -119,6 +119,9 @@ impl CCursorPair {
/// ///
/// Most likely you will use a `String` which implements `TextBuffer`. /// Most likely you will use a `String` which implements `TextBuffer`.
pub trait TextBuffer: AsRef<str> + Into<String> { pub trait TextBuffer: AsRef<str> + Into<String> {
/// Can this text be edited?
fn is_mutable(&self) -> bool;
/// Inserts text `text` into this buffer at character index `ch_idx`. /// Inserts text `text` into this buffer at character index `ch_idx`.
/// ///
/// # Notes /// # Notes
@ -162,6 +165,10 @@ pub trait TextBuffer: AsRef<str> + Into<String> {
} }
impl TextBuffer for String { impl TextBuffer for String {
fn is_mutable(&self) -> bool {
true
}
fn insert_text(&mut self, text: &str, ch_idx: usize) -> usize { fn insert_text(&mut self, text: &str, ch_idx: usize) -> usize {
// Get the byte index from the character index // Get the byte index from the character index
let byte_idx = self::byte_index_from_char_index(self, ch_idx); 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<usize>) {}
}
/// A text region that the user can edit the contents of. /// A text region that the user can edit the contents of.
/// ///
/// See also [`Ui::text_edit_singleline`] and [`Ui::text_edit_multiline`]. /// 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)); /// 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);`"] #[must_use = "You should put this widget in an ui with `ui.add(widget);`"]
pub struct TextEdit<'t, S: TextBuffer = String> { pub struct TextEdit<'t, S: TextBuffer = String> {
text: &'t mut S, text: &'t mut S,
@ -405,6 +435,7 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
impl<'t, S: TextBuffer> Widget for TextEdit<'t, S> { impl<'t, S: TextBuffer> Widget for TextEdit<'t, S> {
fn ui(self, ui: &mut Ui) -> Response { fn ui(self, ui: &mut Ui) -> Response {
let is_mutable = self.text.is_mutable();
let frame = self.frame; let frame = self.frame;
let enabled = self.enabled; let enabled = self.enabled;
let where_to_put_background = ui.painter().add(Shape::Noop); 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 { if frame {
let visuals = ui.style().interact(&response); let visuals = ui.style().interact(&response);
let frame_rect = frame_rect.expand(visuals.expansion); let frame_rect = frame_rect.expand(visuals.expansion);
let shape = if response.has_focus() { let shape = if is_mutable {
epaint::RectShape { if response.has_focus() {
rect: frame_rect, epaint::RectShape {
corner_radius: visuals.corner_radius, rect: frame_rect,
// fill: ui.visuals().selection.bg_fill, corner_radius: visuals.corner_radius,
fill: ui.visuals().extreme_bg_color, // fill: ui.visuals().selection.bg_fill,
stroke: ui.visuals().selection.stroke, 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 { } else {
let visuals = &ui.style().visuals.widgets.inactive;
epaint::RectShape { epaint::RectShape {
rect: frame_rect, rect: frame_rect,
corner_radius: visuals.corner_radius, 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". stroke: visuals.bg_stroke, // TODO: we want to show something here, or a text-edit field doesn't "pop".
} }
}; };