iced_widget/text_input/
cursor.rs

1//! Track the cursor of a text input.
2use crate::text_input::Value;
3
4/// The cursor of a text input.
5#[derive(Debug, Copy, Clone, PartialEq, Eq)]
6pub struct Cursor {
7    state: State,
8}
9
10/// The state of a [`Cursor`].
11#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub enum State {
13    /// Cursor without a selection
14    Index(usize),
15
16    /// Cursor selecting a range of text
17    Selection {
18        /// The start of the selection
19        start: usize,
20        /// The end of the selection
21        end: usize,
22    },
23}
24
25impl Default for Cursor {
26    fn default() -> Self {
27        Cursor {
28            state: State::Index(0),
29        }
30    }
31}
32
33impl Cursor {
34    /// Returns the [`State`] of the [`Cursor`].
35    pub fn state(&self, value: &Value) -> State {
36        match self.state {
37            State::Index(index) => State::Index(index.min(value.len())),
38            State::Selection { start, end } => {
39                let start = start.min(value.len());
40                let end = end.min(value.len());
41
42                if start == end {
43                    State::Index(start)
44                } else {
45                    State::Selection { start, end }
46                }
47            }
48        }
49    }
50
51    /// Returns the current selection of the [`Cursor`] for the given [`Value`].
52    ///
53    /// `start` is guaranteed to be <= than `end`.
54    pub fn selection(&self, value: &Value) -> Option<(usize, usize)> {
55        match self.state(value) {
56            State::Selection { start, end } => {
57                Some((start.min(end), start.max(end)))
58            }
59            State::Index(_) => None,
60        }
61    }
62
63    pub(crate) fn move_to(&mut self, position: usize) {
64        self.state = State::Index(position);
65    }
66
67    pub(crate) fn move_right(&mut self, value: &Value) {
68        self.move_right_by_amount(value, 1);
69    }
70
71    pub(crate) fn move_right_by_words(&mut self, value: &Value) {
72        self.move_to(value.next_end_of_word(self.right(value)));
73    }
74
75    pub(crate) fn move_right_by_amount(
76        &mut self,
77        value: &Value,
78        amount: usize,
79    ) {
80        match self.state(value) {
81            State::Index(index) => {
82                self.move_to(index.saturating_add(amount).min(value.len()));
83            }
84            State::Selection { start, end } => self.move_to(end.max(start)),
85        }
86    }
87
88    pub(crate) fn move_left(&mut self, value: &Value) {
89        match self.state(value) {
90            State::Index(index) if index > 0 => self.move_to(index - 1),
91            State::Selection { start, end } => self.move_to(start.min(end)),
92            State::Index(_) => self.move_to(0),
93        }
94    }
95
96    pub(crate) fn move_left_by_words(&mut self, value: &Value) {
97        self.move_to(value.previous_start_of_word(self.left(value)));
98    }
99
100    pub(crate) fn select_range(&mut self, start: usize, end: usize) {
101        if start == end {
102            self.state = State::Index(start);
103        } else {
104            self.state = State::Selection { start, end };
105        }
106    }
107
108    pub(crate) fn select_left(&mut self, value: &Value) {
109        match self.state(value) {
110            State::Index(index) if index > 0 => {
111                self.select_range(index, index - 1);
112            }
113            State::Selection { start, end } if end > 0 => {
114                self.select_range(start, end - 1);
115            }
116            _ => {}
117        }
118    }
119
120    pub(crate) fn select_right(&mut self, value: &Value) {
121        match self.state(value) {
122            State::Index(index) if index < value.len() => {
123                self.select_range(index, index + 1);
124            }
125            State::Selection { start, end } if end < value.len() => {
126                self.select_range(start, end + 1);
127            }
128            _ => {}
129        }
130    }
131
132    pub(crate) fn select_left_by_words(&mut self, value: &Value) {
133        match self.state(value) {
134            State::Index(index) => {
135                self.select_range(index, value.previous_start_of_word(index));
136            }
137            State::Selection { start, end } => {
138                self.select_range(start, value.previous_start_of_word(end));
139            }
140        }
141    }
142
143    pub(crate) fn select_right_by_words(&mut self, value: &Value) {
144        match self.state(value) {
145            State::Index(index) => {
146                self.select_range(index, value.next_end_of_word(index));
147            }
148            State::Selection { start, end } => {
149                self.select_range(start, value.next_end_of_word(end));
150            }
151        }
152    }
153
154    pub(crate) fn select_all(&mut self, value: &Value) {
155        self.select_range(0, value.len());
156    }
157
158    pub(crate) fn start(&self, value: &Value) -> usize {
159        let start = match self.state {
160            State::Index(index) => index,
161            State::Selection { start, .. } => start,
162        };
163
164        start.min(value.len())
165    }
166
167    pub(crate) fn end(&self, value: &Value) -> usize {
168        let end = match self.state {
169            State::Index(index) => index,
170            State::Selection { end, .. } => end,
171        };
172
173        end.min(value.len())
174    }
175
176    fn left(&self, value: &Value) -> usize {
177        match self.state(value) {
178            State::Index(index) => index,
179            State::Selection { start, end } => start.min(end),
180        }
181    }
182
183    fn right(&self, value: &Value) -> usize {
184        match self.state(value) {
185            State::Index(index) => index,
186            State::Selection { start, end } => start.max(end),
187        }
188    }
189}