1use super::item::Item;
2use super::UiModel;
3use crate::render::CellMetrics;
4
5#[derive(Clone, Debug)]
6pub struct ModelRectVec {
7 pub list: Vec<ModelRect>,
8}
9
10impl ModelRectVec {
11 pub fn empty() -> ModelRectVec {
12 ModelRectVec { list: vec![] }
13 }
14
15 pub fn new(first: ModelRect) -> ModelRectVec {
16 ModelRectVec { list: vec![first] }
17 }
18
19 fn find_neighbor(&self, neighbor: &ModelRect) -> Option<usize> {
20 for (i, rect) in self.list.iter().enumerate() {
21 if (neighbor.top > 0 && rect.top == neighbor.top - 1 || rect.bot == neighbor.bot + 1)
22 && neighbor.in_horizontal(rect)
23 {
24 return Some(i);
25 } else if (neighbor.left > 0 && rect.left == neighbor.left - 1
26 || rect.right == neighbor.right + 1)
27 && neighbor.in_vertical(rect)
28 {
29 return Some(i);
30 } else if rect.in_horizontal(neighbor) && rect.in_vertical(neighbor) {
31 return Some(i);
32 } else if rect.contains(neighbor) {
33 return Some(i);
34 }
35 }
36
37 None
38 }
39
40 pub fn join(&mut self, other: &ModelRect) {
41 match self.find_neighbor(other) {
42 Some(i) => self.list[i].join(other),
43 None => self.list.push(other.clone()),
44 }
45 }
46}
47
48#[derive(Clone, PartialEq, Debug)]
49pub struct ModelRect {
50 pub top: usize,
51 pub bot: usize,
52 pub left: usize,
53 pub right: usize,
54}
55
56impl ModelRect {
57 pub fn new(top: usize, bot: usize, left: usize, right: usize) -> ModelRect {
58 debug_assert!(top <= bot, "{} <= {}", top, bot);
59 debug_assert!(left <= right, "{} <= {}", left, right);
60
61 ModelRect {
62 top,
63 bot,
64 left,
65 right,
66 }
67 }
68
69 pub fn point(x: usize, y: usize) -> ModelRect {
70 ModelRect {
71 top: y,
72 bot: y,
73 left: x,
74 right: x,
75 }
76 }
77
78 #[inline]
79 fn in_horizontal(&self, other: &ModelRect) -> bool {
80 other.left >= self.left && other.left <= self.right
81 || other.right >= self.left && other.right >= self.right
82 }
83
84 #[inline]
85 fn in_vertical(&self, other: &ModelRect) -> bool {
86 other.top >= self.top && other.top <= self.bot
87 || other.bot >= self.top && other.bot <= self.bot
88 }
89
90 fn contains(&self, other: &ModelRect) -> bool {
91 self.top <= other.top
92 && self.bot >= other.bot
93 && self.left <= other.left
94 && self.right >= other.right
95 }
96
97 pub fn extend_by_items(&mut self, model: Option<&UiModel>) {
99 if model.is_none() {
100 return;
101 }
102 let model = model.unwrap();
103
104 let mut left = self.left;
105 let mut right = self.right;
106
107 for i in self.top..self.bot + 1 {
108 let line = &model.model[i];
109 let item_idx = line.cell_to_item(self.left);
110 if item_idx >= 0 {
111 let item_idx = item_idx as usize;
112 if item_idx < left {
113 left = item_idx;
114 }
115 }
116
117 let len_since_right = line.item_len_from_idx(self.right) - 1;
118 if right < self.right + len_since_right {
119 right = self.right + len_since_right;
120 }
121
122 let cell = &line.line[self.left];
124 if self.left > 0 && cell.double_width {
125 let dw_char_idx = self.left - 1;
126 if dw_char_idx < left {
127 left = dw_char_idx;
128 }
129 }
130
131 let dw_char_idx = self.right + 1;
132 if let Some(cell) = line.line.get(dw_char_idx) {
133 if cell.double_width {
134 if right < dw_char_idx {
135 right = dw_char_idx;
136 }
137 }
138 }
139 }
140
141 self.left = left;
142 self.right = right;
143 }
144
145 pub fn to_area_extend_ink(
146 &self,
147 model: Option<&UiModel>,
148 cell_metrics: &CellMetrics,
149 ) -> (i32, i32, i32, i32) {
150 let (x, x2) = self.extend_left_right_area(model, cell_metrics);
151 let (y, y2) = self.extend_top_bottom_area(model, cell_metrics);
152
153 (x, y, x2 - x, y2 - y)
154 }
155
156 fn extend_left_right_area(&self, model: Option<&UiModel>, cell_metrics: &CellMetrics) -> (i32, i32) {
157 let x = (self.left as f64 * cell_metrics.char_width).floor() as i32;
159 let x2 = ((self.right + 1) as f64 * cell_metrics.char_width).ceil() as i32;
160
161 if model.is_none() {
162 return (x, x2);
163 }
164 let model = model.unwrap();
165
166 let mut min_x_offset = 0.0;
167 let mut max_x_offset = 0.0;
168
169 for row in self.top..self.bot + 1 {
170 let line = &model.model[row];
172 if let Some(&Item {
173 ink_overflow: Some(ref overflow),
174 ..
175 }) = line.item_line[self.left].as_ref()
176 {
177 if min_x_offset < overflow.left {
178 min_x_offset = overflow.left;
179 }
180 }
181
182 let line = &model.model[row];
184 if self.right < model.columns - 1
186 && line.cell_to_item(self.right) != line.cell_to_item(self.right + 1)
187 {
188 if let Some(&Item {
189 ink_overflow: Some(ref overflow),
190 ..
191 }) = line.get_item(self.left)
192 {
193 if max_x_offset < overflow.right {
194 max_x_offset = overflow.right;
195 }
196 }
197 }
198 }
199
200 (
201 x - min_x_offset.ceil() as i32,
202 x2 + max_x_offset.ceil() as i32,
203 )
204 }
205
206 fn extend_top_bottom_area(&self, model: Option<&UiModel>, cell_metrics: &CellMetrics) -> (i32, i32) {
207 let y = self.top as i32 * cell_metrics.line_height as i32;
208 let y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32;
209
210 if model.is_none() {
211 return (y, y2);
212 }
213 let model = model.unwrap();
214
215 let mut min_y_offset = 0.0;
216 let mut max_y_offset = 0.0;
217
218 for col in self.left..self.right + 1 {
219 let line = &model.model[self.top];
221 if let Some(&Item {
222 ink_overflow: Some(ref overflow),
223 ..
224 }) = line.get_item(col)
225 {
226 if min_y_offset < overflow.top {
227 min_y_offset = overflow.top;
228 }
229 }
230
231 let line = &model.model[self.bot];
233 if let Some(&Item {
234 ink_overflow: Some(ref overflow),
235 ..
236 }) = line.get_item(col)
237 {
238 if max_y_offset < overflow.top {
239 max_y_offset = overflow.top;
240 }
241 }
242 }
243
244 (
245 y - min_y_offset.ceil() as i32,
246 y2 + max_y_offset.ceil() as i32,
247 )
248 }
249
250 pub fn join(&mut self, rect: &ModelRect) {
251 self.top = if self.top < rect.top {
252 self.top
253 } else {
254 rect.top
255 };
256 self.left = if self.left < rect.left {
257 self.left
258 } else {
259 rect.left
260 };
261
262 self.bot = if self.bot > rect.bot {
263 self.bot
264 } else {
265 rect.bot
266 };
267 self.right = if self.right > rect.right {
268 self.right
269 } else {
270 rect.right
271 };
272
273 debug_assert!(self.top <= self.bot);
274 debug_assert!(self.left <= self.right);
275 }
276
277 pub fn to_area(&self, cell_metrics: &CellMetrics) -> (i32, i32, i32, i32) {
278 let &CellMetrics {
279 char_width,
280 line_height,
281 ..
282 } = cell_metrics;
283
284 (
286 (self.left as f64 * char_width).floor() as i32,
287 (self.top as f64 * line_height).floor() as i32,
288 ((self.right - self.left + 1) as f64 * char_width).ceil() as i32,
289 ((self.bot - self.top + 1) as f64 * line_height).ceil() as i32,
290 )
291 }
292
293 pub fn from_area(cell_metrics: &CellMetrics, x1: f64, y1: f64, x2: f64, y2: f64) -> ModelRect {
294 let &CellMetrics {
295 char_width,
296 line_height,
297 ..
298 } = cell_metrics;
299
300 let x2 = if x2 > 0.0 { x2 - 1.0 } else { x2 };
301 let y2 = if y2 > 0.0 { y2 - 1.0 } else { y2 };
302 let left = (x1 / char_width) as usize;
303 let right = (x2 / char_width) as usize;
304 let top = (y1 / line_height) as usize;
305 let bot = (y2 / line_height) as usize;
306
307 ModelRect::new(top, bot, left, right)
308 }
309}
310
311impl AsRef<ModelRect> for ModelRect {
312 fn as_ref(&self) -> &ModelRect {
313 self
314 }
315}
316
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn test_repaint_rect() {
323 let rect = ModelRect::point(1, 1);
324 let (x, y, width, height) = rect.to_area(&CellMetrics::new_hw(10.0, 5.0));
325
326 assert_eq!(5, x);
327 assert_eq!(10, y);
328 assert_eq!(5, width);
329 assert_eq!(10, height);
330 }
331
332 #[test]
333 fn test_from_area() {
334 let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 3.0, 3.0, 9.0, 17.0);
335
336 assert_eq!(0, rect.top);
337 assert_eq!(0, rect.left);
338 assert_eq!(1, rect.bot);
339 assert_eq!(1, rect.right);
340
341 let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 10.0, 20.0);
342
343 assert_eq!(0, rect.top);
344 assert_eq!(0, rect.left);
345 assert_eq!(1, rect.bot);
346 assert_eq!(1, rect.right);
347
348 let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 11.0, 21.0);
349
350 assert_eq!(0, rect.top);
351 assert_eq!(0, rect.left);
352 assert_eq!(2, rect.bot);
353 assert_eq!(2, rect.right);
354 }
355
356}