cosmic/widget/text_input/
cursor.rs1use iced_core::text::Affinity;
7
8use super::value::Value;
9
10#[derive(Debug, Copy, Clone, PartialEq, Eq)]
12pub struct Cursor {
13 state: State,
14 affinity: Affinity,
15}
16
17#[derive(Debug, Copy, Clone, PartialEq, Eq)]
19pub enum State {
20 Index(usize),
22
23 Selection {
25 start: usize,
27 end: usize,
29 },
30}
31
32impl Default for Cursor {
33 #[inline]
34 fn default() -> Self {
35 Self {
36 state: State::Index(0),
37 affinity: Affinity::Before,
38 }
39 }
40}
41
42impl Cursor {
43 #[must_use]
45 #[inline(never)]
46 pub fn state(&self, value: &Value) -> State {
47 match self.state {
48 State::Index(index) => State::Index(index.min(value.len())),
49 State::Selection { start, end } => {
50 let start = start.min(value.len());
51 let end = end.min(value.len());
52
53 if start == end {
54 State::Index(start)
55 } else {
56 State::Selection { start, end }
57 }
58 }
59 }
60 }
61
62 #[must_use]
66 #[inline]
67 pub fn selection(&self, value: &Value) -> Option<(usize, usize)> {
68 match self.state(value) {
69 State::Selection { start, end } => Some((start.min(end), start.max(end))),
70 State::Index(_) => None,
71 }
72 }
73
74 #[inline]
75 pub(crate) fn move_to(&mut self, position: usize) {
76 self.state = State::Index(position);
77 }
78
79 #[inline]
80 pub(crate) fn move_right(&mut self, value: &Value) {
81 self.move_right_by_amount(value, 1);
82 }
83
84 #[inline]
85 pub(crate) fn move_right_by_words(&mut self, value: &Value) {
86 self.move_to(value.next_end_of_word(self.right(value)));
87 }
88
89 #[inline]
90 pub(crate) fn move_right_by_amount(&mut self, value: &Value, amount: usize) {
91 match self.state(value) {
92 State::Index(index) => self.move_to(index.saturating_add(amount).min(value.len())),
93 State::Selection { start, end } => self.move_to(end.max(start)),
94 }
95 }
96
97 #[inline]
98 pub(crate) fn move_left(&mut self, value: &Value) {
99 match self.state(value) {
100 State::Index(index) if index > 0 => self.move_to(index - 1),
101 State::Selection { start, end } => self.move_to(start.min(end)),
102 State::Index(_) => self.move_to(0),
103 }
104 }
105
106 #[inline]
107 pub(crate) fn move_left_by_words(&mut self, value: &Value) {
108 self.move_to(value.previous_start_of_word(self.left(value)));
109 }
110
111 #[inline]
112 pub(crate) fn select_range(&mut self, start: usize, end: usize) {
113 self.state = if start == end {
114 State::Index(start)
115 } else {
116 State::Selection { start, end }
117 };
118 }
119
120 #[inline]
121 pub(crate) fn select_left(&mut self, value: &Value) {
122 match self.state(value) {
123 State::Index(index) if index > 0 => self.select_range(index, index - 1),
124 State::Selection { start, end } if end > 0 => self.select_range(start, end - 1),
125 _ => {}
126 }
127 }
128
129 #[inline]
130 pub(crate) fn select_right(&mut self, value: &Value) {
131 match self.state(value) {
132 State::Index(index) if index < value.len() => self.select_range(index, index + 1),
133 State::Selection { start, end } if end < value.len() => {
134 self.select_range(start, end + 1);
135 }
136 _ => {}
137 }
138 }
139
140 #[inline]
141 pub(crate) fn select_left_by_words(&mut self, value: &Value) {
142 match self.state(value) {
143 State::Index(index) => self.select_range(index, value.previous_start_of_word(index)),
144 State::Selection { start, end } => {
145 self.select_range(start, value.previous_start_of_word(end));
146 }
147 }
148 }
149
150 #[inline]
151 pub(crate) fn select_right_by_words(&mut self, value: &Value) {
152 match self.state(value) {
153 State::Index(index) => self.select_range(index, value.next_end_of_word(index)),
154 State::Selection { start, end } => {
155 self.select_range(start, value.next_end_of_word(end));
156 }
157 }
158 }
159
160 #[inline]
161 pub(crate) fn select_all(&mut self, value: &Value) {
162 self.select_range(0, value.len());
163 }
164
165 #[inline]
166 pub(crate) fn start(&self, value: &Value) -> usize {
167 let start = match self.state {
168 State::Index(index) => index,
169 State::Selection { start, .. } => start,
170 };
171
172 start.min(value.len())
173 }
174
175 #[inline]
176 pub(crate) fn end(&self, value: &Value) -> usize {
177 let end = match self.state {
178 State::Index(index) => index,
179 State::Selection { end, .. } => end,
180 };
181
182 end.min(value.len())
183 }
184
185 #[inline]
186 fn left(&self, value: &Value) -> usize {
187 match self.state(value) {
188 State::Index(index) => index,
189 State::Selection { start, end } => start.min(end),
190 }
191 }
192
193 #[inline]
194 fn right(&self, value: &Value) -> usize {
195 match self.state(value) {
196 State::Index(index) => index,
197 State::Selection { start, end } => start.max(end),
198 }
199 }
200
201 #[must_use]
203 pub fn affinity(&self) -> Affinity {
204 self.affinity
205 }
206
207 pub fn set_affinity(&mut self, affinity: Affinity) {
209 self.affinity = affinity;
210 }
211
212 pub fn move_visual(&mut self, forward: bool, by_words: bool, rtl: bool, value: &Value) {
216 match (forward ^ rtl, by_words) {
217 (true, false) => self.move_right(value),
218 (true, true) => self.move_right_by_words(value),
219 (false, false) => self.move_left(value),
220 (false, true) => self.move_left_by_words(value),
221 }
222 }
223
224 pub fn select_visual(&mut self, forward: bool, by_words: bool, rtl: bool, value: &Value) {
226 match (forward ^ rtl, by_words) {
227 (true, false) => self.select_right(value),
228 (true, true) => self.select_right_by_words(value),
229 (false, false) => self.select_left(value),
230 (false, true) => self.select_left_by_words(value),
231 }
232 }
233}