use super::UiModel; use super::item::Item; use render::CellMetrics; #[derive(Clone, Debug)] pub struct ModelRectVec { pub list: Vec, } impl ModelRectVec { pub fn new(first: ModelRect) -> ModelRectVec { ModelRectVec { list: vec![first] } } fn find_neighbor(&self, neighbor: &ModelRect) -> Option { for (i, rect) in self.list.iter().enumerate() { if (neighbor.top > 0 && rect.top == neighbor.top - 1 || rect.bot == neighbor.bot + 1) && neighbor.in_horizontal(rect) { return Some(i); } else if (neighbor.left > 0 && rect.left == neighbor.left - 1 || rect.right == neighbor.right + 1) && neighbor.in_vertical(rect) { return Some(i); } else if rect.in_horizontal(neighbor) && rect.in_vertical(neighbor) { return Some(i); } else if rect.contains(neighbor) { return Some(i); } } None } pub fn join(&mut self, other: &ModelRect) { match self.find_neighbor(other) { Some(i) => self.list[i].join(other), None => self.list.push(other.clone()), } } } #[derive(Clone, PartialEq, Debug)] pub struct ModelRect { pub top: usize, pub bot: usize, pub left: usize, pub right: usize, } impl ModelRect { pub fn new(top: usize, bot: usize, left: usize, right: usize) -> ModelRect { debug_assert!(top <= bot); debug_assert!(left <= right); ModelRect { top: top, bot: bot, left: left, right: right, } } pub fn point(x: usize, y: usize) -> ModelRect { ModelRect { top: y, bot: y, left: x, right: x, } } #[inline] fn in_horizontal(&self, other: &ModelRect) -> bool { other.left >= self.left && other.left <= self.right || other.right >= self.left && other.right >= self.right } #[inline] fn in_vertical(&self, other: &ModelRect) -> bool { other.top >= self.top && other.top <= self.bot || other.bot >= self.top && other.bot <= self.bot } fn contains(&self, other: &ModelRect) -> bool { self.top <= other.top && self.bot >= other.bot && self.left <= other.left && self.right >= other.right } /// Extend rect to left and right to make changed Item rerendered pub fn extend_by_items(&mut self, model: &UiModel) { let mut left = self.left; let mut right = self.right; for i in self.top..self.bot + 1 { let line = &model.model[i]; let item_idx = line.cell_to_item(self.left); if item_idx >= 0 { let item_idx = item_idx as usize; if item_idx < left { left = item_idx; } } let len_since_right = line.item_len_from_idx(self.right) - 1; if right < self.right + len_since_right { right = self.right + len_since_right; } } } pub fn to_area_extend_ink( &self, model: &UiModel, cell_metrics: &CellMetrics, ) -> (i32, i32, i32, i32) { let (x, x2) = self.extend_left_right_area(model, cell_metrics); let (y, y2) = self.extend_top_bottom_area(model, cell_metrics); (x, y, x2 - x, y2 - y) } fn extend_left_right_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) { let mut x = self.left as i32 * cell_metrics.char_width as i32; let mut x2 = (self.right + 1) as i32 * cell_metrics.char_width as i32; for row in self.top..self.bot + 1 { // left let line = &model.model[row]; if let Some(&Item { ink_rect: Some(ink_rect), .. }) = line.get_item(self.left) { if x > ink_rect.x { x = ink_rect.x; } } // right let line = &model.model[row]; if let Some(&Item { ink_rect: Some(ink_rect), .. }) = line.get_item(self.right) { let ink_x = ink_rect.x + ink_rect.width; if x2 > ink_x { x2 = ink_x; } } } (x, x2) } fn extend_top_bottom_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) { let mut y = self.top as i32 * cell_metrics.line_height as i32; let mut y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32; for col in self.left..self.right + 1 { // top let line = &model.model[self.top]; if let Some(&Item { ink_rect: Some(ink_rect), .. }) = line.get_item(col) { if y > ink_rect.y { y = ink_rect.y; } } // bottom let line = &model.model[self.bot]; if let Some(&Item { ink_rect: Some(ink_rect), .. }) = line.get_item(col) { let ink_y = ink_rect.y + ink_rect.height; if y2 < ink_y { y2 = ink_y; } } } (y, y2) } pub fn join(&mut self, rect: &ModelRect) { self.top = if self.top < rect.top { self.top } else { rect.top }; self.left = if self.left < rect.left { self.left } else { rect.left }; self.bot = if self.bot > rect.bot { self.bot } else { rect.bot }; self.right = if self.right > rect.right { self.right } else { rect.right }; debug_assert!(self.top <= self.bot); debug_assert!(self.left <= self.right); } pub fn to_area(&self, cell_metrics: &CellMetrics) -> (i32, i32, i32, i32) { let &CellMetrics { char_width, line_height, .. } = cell_metrics; ( self.left as i32 * char_width as i32, self.top as i32 * line_height as i32, (self.right - self.left + 1) as i32 * char_width as i32, (self.bot - self.top + 1) as i32 * line_height as i32, ) } pub fn from_area( line_height: f64, char_width: f64, x1: f64, y1: f64, x2: f64, y2: f64, ) -> ModelRect { let x2 = if x2 > 0.0 { x2 - 1.0 } else { x2 }; let y2 = if y2 > 0.0 { y2 - 1.0 } else { y2 }; let left = (x1 / char_width) as usize; let right = (x2 / char_width) as usize; let top = (y1 / line_height) as usize; let bot = (y2 / line_height) as usize; ModelRect::new(top, bot, left, right) } } impl AsRef for ModelRect { fn as_ref(&self) -> &ModelRect { self } }