1use crate::base::{CellRef, MAX_COLS, MAX_ROWS, RangeRef};
4use crate::model::Sheet;
5use serde::{Deserialize, Serialize};
6
7#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct Selection {
9 pub active: CellRef,
11 pub anchor: CellRef,
13 pub ranges: Vec<RangeRef>,
15}
16
17impl Default for Selection {
18 fn default() -> Self {
19 Selection::at(CellRef::default())
20 }
21}
22
23impl Selection {
24 pub fn at(c: CellRef) -> Selection {
25 Selection { active: c, anchor: c, ranges: vec![RangeRef::cell(c)] }
26 }
27 pub fn range(r: RangeRef) -> Selection {
28 Selection { active: r.start, anchor: r.start, ranges: vec![r] }
29 }
30 pub fn current(&self) -> RangeRef {
32 self.ranges.last().copied().unwrap_or(RangeRef::cell(self.active))
33 }
34 pub fn bounds(&self) -> RangeRef {
36 let mut it = self.ranges.iter();
37 let first = it.next().copied().unwrap_or(RangeRef::cell(self.active));
38 it.fold(first, |a, b| a.union(b))
39 }
40 pub fn contains(&self, c: CellRef) -> bool {
41 self.ranges.iter().any(|r| r.contains(c))
42 }
43 pub fn is_single_cell(&self) -> bool {
44 self.ranges.len() == 1 && self.current().is_single()
45 }
46 pub fn moving_end(&self) -> CellRef {
48 let r = self.current();
49 let row = if self.anchor.row == r.start.row { r.end.row } else { r.start.row };
50 let col = if self.anchor.col == r.start.col { r.end.col } else { r.start.col };
51 CellRef::new(row, col)
52 }
53 pub fn extend_to(&mut self, to: CellRef) {
55 let r = RangeRef::new(self.anchor, to);
56 if let Some(last) = self.ranges.last_mut() {
57 *last = r;
58 } else {
59 self.ranges.push(r);
60 }
61 }
62 pub fn a1(&self) -> String {
64 self.ranges.iter().map(|r| r.a1()).collect::<Vec<_>>().join(",")
65 }
66 pub fn expand_merges(&mut self, sheet: &Sheet) {
69 for r in self.ranges.iter_mut() {
70 if r.is_full_cols() || r.is_full_rows() {
71 continue;
72 }
73 let mut cur = *r;
74 loop {
75 let mut grown = cur;
76 for m in &sheet.merges {
77 if m.intersects(&grown) {
78 grown = grown.union(m);
79 }
80 }
81 if grown == cur {
82 break;
83 }
84 cur = grown;
85 }
86 *r = cur;
87 }
88 }
89 pub fn cycle(&mut self, forward: bool, by_row: bool) {
91 let r = self.current();
92 if r.is_single() && self.ranges.len() == 1 {
93 return;
94 }
95 let a = self.active;
96 let (mut row, mut col) = (a.row as i64, a.col as i64);
97 let step: i64 = if forward { 1 } else { -1 };
98 if by_row {
99 col += step;
100 if col > r.end.col as i64 {
101 col = r.start.col as i64;
102 row += 1;
103 } else if col < r.start.col as i64 {
104 col = r.end.col as i64;
105 row -= 1;
106 }
107 if row > r.end.row as i64 {
108 row = r.start.row as i64;
109 } else if row < r.start.row as i64 {
110 row = r.end.row as i64;
111 }
112 } else {
113 row += step;
114 if row > r.end.row as i64 {
115 row = r.start.row as i64;
116 col += 1;
117 } else if row < r.start.row as i64 {
118 row = r.end.row as i64;
119 col -= 1;
120 }
121 if col > r.end.col as i64 {
122 col = r.start.col as i64;
123 } else if col < r.start.col as i64 {
124 col = r.end.col as i64;
125 }
126 }
127 self.active = CellRef::new(row.clamp(0, MAX_ROWS as i64 - 1) as u32, col.clamp(0, MAX_COLS as i64 - 1) as u32);
128 }
129}
130
131impl Selection {
132 pub fn next_corner(&mut self) {
137 self.next_corner_by(Some);
138 }
139
140 pub fn next_corner_by(&mut self, stop: impl Fn(CellRef) -> Option<CellRef>) {
144 let r = self.current();
145 let corners = [r.start, CellRef::new(r.start.row, r.end.col), r.end, CellRef::new(r.end.row, r.start.col)];
146 let next = match corners.iter().rposition(|c| stop(*c) == Some(self.active)) {
147 Some(i) => (1..=4).filter_map(|k| corners.get((i + k) % 4)).filter_map(|c| stop(*c)).find(|c| *c != self.active),
148 None => corners.iter().find_map(|c| stop(*c)),
149 };
150 if let Some(next) = next {
151 self.active = next;
152 self.anchor = next;
153 }
154 }
155}
156
157pub fn jump(sheet: &Sheet, from: CellRef, dr: i64, dc: i64) -> CellRef {
159 if dr == 0 && dc == 0 {
160 return from;
162 }
163 let filled = |c: CellRef| sheet.value_ref(c).is_some_and(|v| !v.is_empty());
164 let Some(mut cur) = from.offset(dr, dc) else { return from };
165 let here = filled(from);
166 let next = filled(cur);
167 if here && next {
168 while let Some(n) = cur.offset(dr, dc) {
170 if !filled(n) {
171 break;
172 }
173 cur = n;
174 }
175 return cur;
176 }
177 let used = sheet.used_range();
180 loop {
181 if filled(cur) {
182 return cur;
183 }
184 let beyond = match used {
185 Some(u) => {
186 (dr > 0 && cur.row > u.end.row)
187 || (dc > 0 && cur.col > u.end.col)
188 || (dr < 0 && cur.row < u.start.row)
189 || (dc < 0 && cur.col < u.start.col)
190 }
191 None => true,
192 };
193 if beyond {
194 let r = if dr > 0 {
195 MAX_ROWS - 1
196 } else if dr < 0 {
197 0
198 } else {
199 cur.row
200 };
201 let c = if dc > 0 {
202 MAX_COLS - 1
203 } else if dc < 0 {
204 0
205 } else {
206 cur.col
207 };
208 return CellRef::new(r, c);
209 }
210 match cur.offset(dr, dc) {
211 Some(n) => cur = n,
212 None => return cur,
213 }
214 }
215}
216
217pub fn current_region(sheet: &Sheet, c: CellRef) -> RangeRef {
219 let filled = |c: CellRef| sheet.cell(c).is_some_and(crate::model::Cell::has_content) || sheet.spill.contains_key(&c);
220 let row_has = |row: u32, a: u32, b: u32| (a..=b).any(|col| filled(CellRef::new(row, col)));
222 let col_has = |col: u32, a: u32, b: u32| (a..=b).any(|row| filled(CellRef::new(row, col)));
223 let (mut r0, mut r1, mut c0, mut c1) = (c.row, c.row, c.col, c.col);
224 loop {
227 let before = (r0, r1, c0, c1);
228 let (lo_c, hi_c) = (c0.saturating_sub(1), (c1 + 1).min(MAX_COLS - 1));
229 while r0 > 0 && row_has(r0 - 1, lo_c, hi_c) {
230 r0 -= 1;
231 }
232 while r1 + 1 < MAX_ROWS && row_has(r1 + 1, lo_c, hi_c) {
233 r1 += 1;
234 }
235 let (lo_r, hi_r) = (r0.saturating_sub(1), (r1 + 1).min(MAX_ROWS - 1));
236 while c0 > 0 && col_has(c0 - 1, lo_r, hi_r) {
237 c0 -= 1;
238 }
239 while c1 + 1 < MAX_COLS && col_has(c1 + 1, lo_r, hi_r) {
240 c1 += 1;
241 }
242 if (r0, r1, c0, c1) == before {
243 break;
244 }
245 }
246 RangeRef::new(CellRef::new(r0, c0), CellRef::new(r1, c1))
247}
248
249#[cfg(test)]
250mod tests {
251 use super::*;
252 use crate::base::Value;
253
254 #[test]
255 fn jumps() {
256 let mut s = Sheet::new("S");
257 for r in 0..5 {
258 s.set_value(CellRef::new(r, 0), Value::Number(1.0));
259 }
260 s.set_value(CellRef::new(10, 0), Value::Number(1.0));
261 assert_eq!(jump(&s, CellRef::new(0, 0), 1, 0), CellRef::new(4, 0));
262 assert_eq!(jump(&s, CellRef::new(7, 0), 0, 0), CellRef::new(7, 0));
264 assert_eq!(jump(&s, CellRef::new(4, 0), 1, 0), CellRef::new(10, 0));
265 assert_eq!(jump(&s, CellRef::new(10, 0), 1, 0), CellRef::new(MAX_ROWS - 1, 0));
266 assert_eq!(jump(&s, CellRef::new(0, 0), 0, 1), CellRef::new(0, MAX_COLS - 1));
267 assert_eq!(jump(&s, CellRef::new(0, 0), -1, 0), CellRef::new(0, 0));
268 }
269
270 #[test]
271 fn regions() {
272 let mut s = Sheet::new("S");
273 for r in 2..5 {
274 for c in 1..4 {
275 s.set_value(CellRef::new(r, c), Value::Number(1.0));
276 }
277 }
278 assert_eq!(current_region(&s, CellRef::new(3, 2)).a1(), "B3:D5");
279 assert_eq!(current_region(&s, CellRef::new(5, 4)).a1(), "B3:E6");
280 assert_eq!(current_region(&s, CellRef::new(20, 20)).a1(), "U21");
281 let mut s = Sheet::new("S");
283 for r in 0..20_000 {
284 s.set_value(CellRef::new(r, 0), Value::Number(r as f64));
285 s.set_value(CellRef::new(r, 1), Value::Number(1.0));
286 }
287 assert_eq!(current_region(&s, CellRef::new(5, 0)).a1(), "A1:B20000");
288 }
289
290 #[test]
291 fn cycling() {
292 let mut sel = Selection::range(RangeRef::parse("A1:B2").unwrap());
293 sel.cycle(true, false);
294 assert_eq!(sel.active.a1(), "A2");
295 sel.cycle(true, false);
296 assert_eq!(sel.active.a1(), "B1");
297 sel.cycle(true, true);
298 assert_eq!(sel.active.a1(), "A2");
299 }
300}