diff options
Diffstat (limited to 'native/src/widget/text_input')
-rw-r--r-- | native/src/widget/text_input/cursor.rs | 189 | ||||
-rw-r--r-- | native/src/widget/text_input/editor.rs | 70 | ||||
-rw-r--r-- | native/src/widget/text_input/value.rs | 133 |
3 files changed, 0 insertions, 392 deletions
diff --git a/native/src/widget/text_input/cursor.rs b/native/src/widget/text_input/cursor.rs deleted file mode 100644 index 4f3b159b..00000000 --- a/native/src/widget/text_input/cursor.rs +++ /dev/null @@ -1,189 +0,0 @@ -//! Track the cursor of a text input. -use crate::widget::text_input::Value; - -/// The cursor of a text input. -#[derive(Debug, Copy, Clone)] -pub struct Cursor { - state: State, -} - -/// The state of a [`Cursor`]. -#[derive(Debug, Copy, Clone)] -pub enum State { - /// Cursor without a selection - Index(usize), - - /// Cursor selecting a range of text - Selection { - /// The start of the selection - start: usize, - /// The end of the selection - end: usize, - }, -} - -impl Default for Cursor { - fn default() -> Self { - Cursor { - state: State::Index(0), - } - } -} - -impl Cursor { - /// Returns the [`State`] of the [`Cursor`]. - pub fn state(&self, value: &Value) -> State { - match self.state { - State::Index(index) => State::Index(index.min(value.len())), - State::Selection { start, end } => { - let start = start.min(value.len()); - let end = end.min(value.len()); - - if start == end { - State::Index(start) - } else { - State::Selection { start, end } - } - } - } - } - - /// Returns the current selection of the [`Cursor`] for the given [`Value`]. - /// - /// `start` is guaranteed to be <= than `end`. - pub fn selection(&self, value: &Value) -> Option<(usize, usize)> { - match self.state(value) { - State::Selection { start, end } => { - Some((start.min(end), start.max(end))) - } - _ => None, - } - } - - pub(crate) fn move_to(&mut self, position: usize) { - self.state = State::Index(position); - } - - pub(crate) fn move_right(&mut self, value: &Value) { - self.move_right_by_amount(value, 1) - } - - pub(crate) fn move_right_by_words(&mut self, value: &Value) { - self.move_to(value.next_end_of_word(self.right(value))) - } - - pub(crate) fn move_right_by_amount( - &mut self, - value: &Value, - amount: usize, - ) { - match self.state(value) { - State::Index(index) => { - self.move_to(index.saturating_add(amount).min(value.len())) - } - State::Selection { start, end } => self.move_to(end.max(start)), - } - } - - pub(crate) fn move_left(&mut self, value: &Value) { - match self.state(value) { - State::Index(index) if index > 0 => self.move_to(index - 1), - State::Selection { start, end } => self.move_to(start.min(end)), - _ => self.move_to(0), - } - } - - pub(crate) fn move_left_by_words(&mut self, value: &Value) { - self.move_to(value.previous_start_of_word(self.left(value))); - } - - pub(crate) fn select_range(&mut self, start: usize, end: usize) { - if start == end { - self.state = State::Index(start); - } else { - self.state = State::Selection { start, end }; - } - } - - pub(crate) fn select_left(&mut self, value: &Value) { - match self.state(value) { - State::Index(index) if index > 0 => { - self.select_range(index, index - 1) - } - State::Selection { start, end } if end > 0 => { - self.select_range(start, end - 1) - } - _ => {} - } - } - - pub(crate) fn select_right(&mut self, value: &Value) { - match self.state(value) { - State::Index(index) if index < value.len() => { - self.select_range(index, index + 1) - } - State::Selection { start, end } if end < value.len() => { - self.select_range(start, end + 1) - } - _ => {} - } - } - - pub(crate) fn select_left_by_words(&mut self, value: &Value) { - match self.state(value) { - State::Index(index) => { - self.select_range(index, value.previous_start_of_word(index)) - } - State::Selection { start, end } => { - self.select_range(start, value.previous_start_of_word(end)) - } - } - } - - pub(crate) fn select_right_by_words(&mut self, value: &Value) { - match self.state(value) { - State::Index(index) => { - self.select_range(index, value.next_end_of_word(index)) - } - State::Selection { start, end } => { - self.select_range(start, value.next_end_of_word(end)) - } - } - } - - pub(crate) fn select_all(&mut self, value: &Value) { - self.select_range(0, value.len()); - } - - pub(crate) fn start(&self, value: &Value) -> usize { - let start = match self.state { - State::Index(index) => index, - State::Selection { start, .. } => start, - }; - - start.min(value.len()) - } - - pub(crate) fn end(&self, value: &Value) -> usize { - let end = match self.state { - State::Index(index) => index, - State::Selection { end, .. } => end, - }; - - end.min(value.len()) - } - - fn left(&self, value: &Value) -> usize { - match self.state(value) { - State::Index(index) => index, - State::Selection { start, end } => start.min(end), - } - } - - fn right(&self, value: &Value) -> usize { - match self.state(value) { - State::Index(index) => index, - State::Selection { start, end } => start.max(end), - } - } -} diff --git a/native/src/widget/text_input/editor.rs b/native/src/widget/text_input/editor.rs deleted file mode 100644 index d53fa8d9..00000000 --- a/native/src/widget/text_input/editor.rs +++ /dev/null @@ -1,70 +0,0 @@ -use crate::widget::text_input::{Cursor, Value}; - -pub struct Editor<'a> { - value: &'a mut Value, - cursor: &'a mut Cursor, -} - -impl<'a> Editor<'a> { - pub fn new(value: &'a mut Value, cursor: &'a mut Cursor) -> Editor<'a> { - Editor { value, cursor } - } - - pub fn contents(&self) -> String { - self.value.to_string() - } - - pub fn insert(&mut self, character: char) { - if let Some((left, right)) = self.cursor.selection(self.value) { - self.cursor.move_left(self.value); - self.value.remove_many(left, right); - } - - self.value.insert(self.cursor.end(self.value), character); - self.cursor.move_right(self.value); - } - - pub fn paste(&mut self, content: Value) { - let length = content.len(); - if let Some((left, right)) = self.cursor.selection(self.value) { - self.cursor.move_left(self.value); - self.value.remove_many(left, right); - } - - self.value.insert_many(self.cursor.end(self.value), content); - - self.cursor.move_right_by_amount(self.value, length); - } - - pub fn backspace(&mut self) { - match self.cursor.selection(self.value) { - Some((start, end)) => { - self.cursor.move_left(self.value); - self.value.remove_many(start, end); - } - None => { - let start = self.cursor.start(self.value); - - if start > 0 { - self.cursor.move_left(self.value); - self.value.remove(start - 1); - } - } - } - } - - pub fn delete(&mut self) { - match self.cursor.selection(self.value) { - Some(_) => { - self.backspace(); - } - None => { - let end = self.cursor.end(self.value); - - if end < self.value.len() { - self.value.remove(end); - } - } - } - } -} diff --git a/native/src/widget/text_input/value.rs b/native/src/widget/text_input/value.rs deleted file mode 100644 index cf4da562..00000000 --- a/native/src/widget/text_input/value.rs +++ /dev/null @@ -1,133 +0,0 @@ -use unicode_segmentation::UnicodeSegmentation; - -/// The value of a [`TextInput`]. -/// -/// [`TextInput`]: crate::widget::TextInput -// TODO: Reduce allocations, cache results (?) -#[derive(Debug, Clone)] -pub struct Value { - graphemes: Vec<String>, -} - -impl Value { - /// Creates a new [`Value`] from a string slice. - pub fn new(string: &str) -> Self { - let graphemes = UnicodeSegmentation::graphemes(string, true) - .map(String::from) - .collect(); - - Self { graphemes } - } - - /// Returns whether the [`Value`] is empty or not. - /// - /// A [`Value`] is empty when it contains no graphemes. - pub fn is_empty(&self) -> bool { - self.len() == 0 - } - - /// Returns the total amount of graphemes in the [`Value`]. - pub fn len(&self) -> usize { - self.graphemes.len() - } - - /// Returns the position of the previous start of a word from the given - /// grapheme `index`. - pub fn previous_start_of_word(&self, index: usize) -> usize { - let previous_string = - &self.graphemes[..index.min(self.graphemes.len())].concat(); - - UnicodeSegmentation::split_word_bound_indices(previous_string as &str) - .filter(|(_, word)| !word.trim_start().is_empty()) - .next_back() - .map(|(i, previous_word)| { - index - - UnicodeSegmentation::graphemes(previous_word, true) - .count() - - UnicodeSegmentation::graphemes( - &previous_string[i + previous_word.len()..] as &str, - true, - ) - .count() - }) - .unwrap_or(0) - } - - /// Returns the position of the next end of a word from the given grapheme - /// `index`. - pub fn next_end_of_word(&self, index: usize) -> usize { - let next_string = &self.graphemes[index..].concat(); - - UnicodeSegmentation::split_word_bound_indices(next_string as &str) - .find(|(_, word)| !word.trim_start().is_empty()) - .map(|(i, next_word)| { - index - + UnicodeSegmentation::graphemes(next_word, true).count() - + UnicodeSegmentation::graphemes( - &next_string[..i] as &str, - true, - ) - .count() - }) - .unwrap_or(self.len()) - } - - /// Returns a new [`Value`] containing the graphemes from `start` until the - /// given `end`. - pub fn select(&self, start: usize, end: usize) -> Self { - let graphemes = - self.graphemes[start.min(self.len())..end.min(self.len())].to_vec(); - - Self { graphemes } - } - - /// Returns a new [`Value`] containing the graphemes until the given - /// `index`. - pub fn until(&self, index: usize) -> Self { - let graphemes = self.graphemes[..index.min(self.len())].to_vec(); - - Self { graphemes } - } - - /// Converts the [`Value`] into a `String`. - pub fn to_string(&self) -> String { - self.graphemes.concat() - } - - /// Inserts a new `char` at the given grapheme `index`. - pub fn insert(&mut self, index: usize, c: char) { - self.graphemes.insert(index, c.to_string()); - - self.graphemes = - UnicodeSegmentation::graphemes(&self.to_string() as &str, true) - .map(String::from) - .collect(); - } - - /// Inserts a bunch of graphemes at the given grapheme `index`. - pub fn insert_many(&mut self, index: usize, mut value: Value) { - let _ = self - .graphemes - .splice(index..index, value.graphemes.drain(..)); - } - - /// Removes the grapheme at the given `index`. - pub fn remove(&mut self, index: usize) { - let _ = self.graphemes.remove(index); - } - - /// Removes the graphemes from `start` to `end`. - pub fn remove_many(&mut self, start: usize, end: usize) { - let _ = self.graphemes.splice(start..end, std::iter::empty()); - } - - /// Returns a new [`Value`] with all its graphemes replaced with the - /// dot ('•') character. - pub fn secure(&self) -> Self { - Self { - graphemes: std::iter::repeat(String::from("•")) - .take(self.graphemes.len()) - .collect(), - } - } -} |