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