summaryrefslogtreecommitdiffstats
path: root/widget/src/text_input/cursor.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-04 05:37:11 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-04 05:37:11 +0100
commit3a0d34c0240f4421737a6a08761f99d6f8140d02 (patch)
treec9a4a6b8e9c1db1b8fcd05bc98e3f131d5ef4bd5 /widget/src/text_input/cursor.rs
parentc54409d1711e1f615c7ea4b02c082954e340632a (diff)
downloadiced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.gz
iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.tar.bz2
iced-3a0d34c0240f4421737a6a08761f99d6f8140d02.zip
Create `iced_widget` subcrate and re-organize the whole codebase
Diffstat (limited to 'widget/src/text_input/cursor.rs')
-rw-r--r--widget/src/text_input/cursor.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/widget/src/text_input/cursor.rs b/widget/src/text_input/cursor.rs
new file mode 100644
index 00000000..9680dfd7
--- /dev/null
+++ b/widget/src/text_input/cursor.rs
@@ -0,0 +1,189 @@
+//! Track the cursor of a text input.
+use crate::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),
+ }
+ }
+}