Expanded TextBuffer
interface to allow borrowed values. (#444)
* Expanded `TextBuffer` interface to allow borrowed values. * Removed superfluous `PartialEq` requirement on `TextBuffer`. * Removed `std::fmt::Display` requirement for `TextBuffer`. Now uses the `AsRef<str>` impl to format it where applicable. Co-authored-by: Filipe Rodrigues <filipejacintorodrigues1@gmail.com>
This commit is contained in:
parent
00575e158f
commit
7f1123a54c
1 changed files with 53 additions and 18 deletions
|
@ -5,11 +5,11 @@ use std::ops::Range;
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "persistence", serde(default))]
|
#[cfg_attr(feature = "persistence", serde(default))]
|
||||||
pub(crate) struct State<S: TextBuffer> {
|
pub(crate) struct State {
|
||||||
cursorp: Option<CursorPair>,
|
cursorp: Option<CursorPair>,
|
||||||
|
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
undoer: Undoer<(CCursorPair, S)>,
|
undoer: Undoer<(CCursorPair, String)>,
|
||||||
|
|
||||||
// If IME candidate window is shown on this text edit.
|
// If IME candidate window is shown on this text edit.
|
||||||
#[cfg_attr(feature = "persistence", serde(skip))]
|
#[cfg_attr(feature = "persistence", serde(skip))]
|
||||||
|
@ -113,9 +113,7 @@ impl CCursorPair {
|
||||||
/// an underlying buffer.
|
/// an underlying buffer.
|
||||||
///
|
///
|
||||||
/// Most likely you will use a `String` which implements `TextBuffer`.
|
/// Most likely you will use a `String` which implements `TextBuffer`.
|
||||||
pub trait TextBuffer:
|
pub trait TextBuffer: AsRef<str> + Into<String> {
|
||||||
AsRef<str> + Into<String> + PartialEq + Clone + Default + Send + Sync + 'static + std::fmt::Display
|
|
||||||
{
|
|
||||||
/// Inserts text `text` into this buffer at character index `ch_idx`.
|
/// Inserts text `text` into this buffer at character index `ch_idx`.
|
||||||
///
|
///
|
||||||
/// # Notes
|
/// # Notes
|
||||||
|
@ -131,9 +129,31 @@ pub trait TextBuffer:
|
||||||
/// `ch_range` is a *character range*, not a byte range.
|
/// `ch_range` is a *character range*, not a byte range.
|
||||||
fn delete_char_range(&mut self, ch_range: Range<usize>);
|
fn delete_char_range(&mut self, ch_range: Range<usize>);
|
||||||
|
|
||||||
|
/// Returns this buffer as a `str`.
|
||||||
|
///
|
||||||
|
/// This is an utility method, as it simply relies on the `AsRef<str>`
|
||||||
|
/// implementation.
|
||||||
fn as_str(&self) -> &str {
|
fn as_str(&self) -> &str {
|
||||||
self.as_ref()
|
self.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears all characters in this buffer
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.delete_char_range(0..self.as_ref().len());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replaces all contents of this string with `text`
|
||||||
|
fn replace(&mut self, text: &str) {
|
||||||
|
self.clear();
|
||||||
|
self.insert_text(text, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears all characters in this buffer and returns a string of the contents.
|
||||||
|
fn take(&mut self) -> String {
|
||||||
|
let s = self.as_ref().to_owned();
|
||||||
|
self.clear();
|
||||||
|
s
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TextBuffer for String {
|
impl TextBuffer for String {
|
||||||
|
@ -157,6 +177,18 @@ impl TextBuffer for String {
|
||||||
// Then drain all characters within this range
|
// Then drain all characters within this range
|
||||||
self.drain(byte_start..byte_end);
|
self.drain(byte_start..byte_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) {
|
||||||
|
self.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn replace(&mut self, text: &str) {
|
||||||
|
*self = text.to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take(&mut self) -> String {
|
||||||
|
std::mem::take(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A text region that the user can edit the contents of.
|
/// A text region that the user can edit the contents of.
|
||||||
|
@ -206,7 +238,7 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
pub fn cursor(ui: &Ui, id: Id) -> Option<CursorPair> {
|
pub fn cursor(ui: &Ui, id: Id) -> Option<CursorPair> {
|
||||||
ui.memory()
|
ui.memory()
|
||||||
.id_data
|
.id_data
|
||||||
.get::<State<S>>(&id)
|
.get::<State>(&id)
|
||||||
.and_then(|state| state.cursorp)
|
.and_then(|state| state.cursorp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -411,7 +443,7 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev_text = text.clone();
|
let prev_text = text.as_ref().to_owned();
|
||||||
let text_style = text_style
|
let text_style = text_style
|
||||||
.or(ui.style().override_text_style)
|
.or(ui.style().override_text_style)
|
||||||
.unwrap_or_else(|| ui.style().body_text_style);
|
.unwrap_or_else(|| ui.style().body_text_style);
|
||||||
|
@ -451,7 +483,7 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
auto_id // Since we are only storing the cursor a persistent Id is not super important
|
auto_id // Since we are only storing the cursor a persistent Id is not super important
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let mut state = ui.memory().id_data.get_or_default::<State<S>>(id).clone();
|
let mut state = ui.memory().id_data.get_or_default::<State>(id).clone();
|
||||||
|
|
||||||
let sense = if enabled {
|
let sense = if enabled {
|
||||||
Sense::click_and_drag()
|
Sense::click_and_drag()
|
||||||
|
@ -530,9 +562,10 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
|
|
||||||
// We feed state to the undoer both before and after handling input
|
// We feed state to the undoer both before and after handling input
|
||||||
// so that the undoer creates automatic saves even when there are no events for a while.
|
// so that the undoer creates automatic saves even when there are no events for a while.
|
||||||
state
|
state.undoer.feed_state(
|
||||||
.undoer
|
ui.input().time,
|
||||||
.feed_state(ui.input().time, &(cursorp.as_ccursorp(), text.clone()));
|
&(cursorp.as_ccursorp(), text.as_ref().to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
for event in &ui.input().events {
|
for event in &ui.input().events {
|
||||||
let did_mutate_text = match event {
|
let did_mutate_text = match event {
|
||||||
|
@ -549,7 +582,7 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
}
|
}
|
||||||
Event::Cut => {
|
Event::Cut => {
|
||||||
if cursorp.is_empty() {
|
if cursorp.is_empty() {
|
||||||
copy_if_not_password(ui, std::mem::take(text).into());
|
copy_if_not_password(ui, text.take());
|
||||||
Some(CCursorPair::default())
|
Some(CCursorPair::default())
|
||||||
} else {
|
} else {
|
||||||
copy_if_not_password(
|
copy_if_not_password(
|
||||||
|
@ -610,10 +643,11 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
modifiers,
|
modifiers,
|
||||||
} if modifiers.command && !modifiers.shift => {
|
} if modifiers.command && !modifiers.shift => {
|
||||||
// TODO: redo
|
// TODO: redo
|
||||||
if let Some((undo_ccursorp, undo_txt)) =
|
if let Some((undo_ccursorp, undo_txt)) = state
|
||||||
state.undoer.undo(&(cursorp.as_ccursorp(), text.clone()))
|
.undoer
|
||||||
|
.undo(&(cursorp.as_ccursorp(), text.as_ref().to_owned()))
|
||||||
{
|
{
|
||||||
*text = undo_txt.clone();
|
text.replace(undo_txt);
|
||||||
Some(*undo_ccursorp)
|
Some(*undo_ccursorp)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -680,9 +714,10 @@ impl<'t, S: TextBuffer> TextEdit<'t, S> {
|
||||||
state.cursorp = Some(cursorp);
|
state.cursorp = Some(cursorp);
|
||||||
text_cursor = Some(cursorp);
|
text_cursor = Some(cursorp);
|
||||||
|
|
||||||
state
|
state.undoer.feed_state(
|
||||||
.undoer
|
ui.input().time,
|
||||||
.feed_state(ui.input().time, &(cursorp.as_ccursorp(), text.clone()));
|
&(cursorp.as_ccursorp(), text.as_ref().to_owned()),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ui.memory().has_focus(id) {
|
if ui.memory().has_focus(id) {
|
||||||
|
|
Loading…
Reference in a new issue