2017-09-07 14:48:10 +00:00
|
|
|
use super::UiModel;
|
|
|
|
use super::item::Item;
|
|
|
|
use render::CellMetrics;
|
2017-09-06 15:31:13 +00:00
|
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug)]
|
|
|
|
pub struct ModelRectVec {
|
|
|
|
pub list: Vec<ModelRect>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ModelRectVec {
|
2017-11-13 09:51:22 +00:00
|
|
|
pub fn empty() -> ModelRectVec {
|
|
|
|
ModelRectVec { list: vec![] }
|
|
|
|
}
|
|
|
|
|
2017-09-06 15:31:13 +00:00
|
|
|
pub fn new(first: ModelRect) -> ModelRectVec {
|
|
|
|
ModelRectVec { list: vec![first] }
|
|
|
|
}
|
|
|
|
|
|
|
|
fn find_neighbor(&self, neighbor: &ModelRect) -> Option<usize> {
|
|
|
|
for (i, rect) in self.list.iter().enumerate() {
|
|
|
|
if (neighbor.top > 0 && rect.top == neighbor.top - 1 ||
|
2017-09-07 14:48:10 +00:00
|
|
|
rect.bot == neighbor.bot + 1) && neighbor.in_horizontal(rect)
|
|
|
|
{
|
2017-09-06 15:31:13 +00:00
|
|
|
return Some(i);
|
|
|
|
} else if (neighbor.left > 0 && rect.left == neighbor.left - 1 ||
|
2017-09-07 14:48:10 +00:00
|
|
|
rect.right == neighbor.right + 1) &&
|
|
|
|
neighbor.in_vertical(rect)
|
|
|
|
{
|
2017-09-06 15:31:13 +00:00
|
|
|
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 ||
|
2017-09-07 14:48:10 +00:00
|
|
|
other.right >= self.left && other.right >= self.right
|
2017-09-06 15:31:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
fn in_vertical(&self, other: &ModelRect) -> bool {
|
|
|
|
other.top >= self.top && other.top <= self.bot ||
|
2017-09-07 14:48:10 +00:00
|
|
|
other.bot >= self.top && other.bot <= self.bot
|
2017-09-06 15:31:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn contains(&self, other: &ModelRect) -> bool {
|
|
|
|
self.top <= other.top && self.bot >= other.bot && self.left <= other.left &&
|
2017-09-07 14:48:10 +00:00
|
|
|
self.right >= other.right
|
2017-09-06 15:31:13 +00:00
|
|
|
}
|
|
|
|
|
2017-09-07 14:48:10 +00:00
|
|
|
/// Extend rect to left and right to make changed Item rerendered
|
2017-09-06 15:31:13 +00:00
|
|
|
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;
|
|
|
|
}
|
2017-09-13 09:39:02 +00:00
|
|
|
|
|
|
|
// extend also double_width chars
|
|
|
|
let cell = &line.line[self.left];
|
|
|
|
if self.left > 0 && cell.attrs.double_width {
|
|
|
|
let dw_char_idx = self.left - 1;
|
|
|
|
if dw_char_idx < left {
|
|
|
|
left = dw_char_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let dw_char_idx = self.right + 1;
|
|
|
|
if let Some(cell) = line.line.get(dw_char_idx) {
|
|
|
|
if cell.attrs.double_width {
|
|
|
|
if right < dw_char_idx {
|
|
|
|
right = dw_char_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-09-06 15:31:13 +00:00
|
|
|
}
|
2017-09-07 19:53:32 +00:00
|
|
|
|
|
|
|
self.left = left;
|
|
|
|
self.right = right;
|
2017-09-06 15:31:13 +00:00
|
|
|
}
|
|
|
|
|
2017-09-07 14:48:10 +00:00
|
|
|
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) {
|
2017-09-07 19:53:32 +00:00
|
|
|
let x = self.left as i32 * cell_metrics.char_width as i32;
|
2017-09-08 15:26:16 +00:00
|
|
|
let x2 = (self.right + 1) as i32 * cell_metrics.char_width as i32;
|
|
|
|
let mut min_x_offset = 0.0;
|
|
|
|
let mut max_x_offset = 0.0;
|
2017-09-07 14:48:10 +00:00
|
|
|
|
|
|
|
for row in self.top..self.bot + 1 {
|
|
|
|
|
|
|
|
// left
|
|
|
|
let line = &model.model[row];
|
2017-09-08 15:26:16 +00:00
|
|
|
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) =
|
|
|
|
line.item_line[self.left].as_ref()
|
|
|
|
{
|
|
|
|
if min_x_offset < overflow.left {
|
|
|
|
min_x_offset = overflow.left;
|
2017-09-07 14:48:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// right
|
|
|
|
let line = &model.model[row];
|
2017-09-08 15:26:16 +00:00
|
|
|
// check if this item ends here
|
|
|
|
if self.right < model.columns - 1 &&
|
|
|
|
line.cell_to_item(self.right) != line.cell_to_item(self.right + 1)
|
|
|
|
{
|
|
|
|
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) =
|
|
|
|
line.get_item(self.left)
|
|
|
|
{
|
|
|
|
if max_x_offset < overflow.right {
|
|
|
|
max_x_offset = overflow.right;
|
|
|
|
}
|
2017-09-07 14:48:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 15:26:16 +00:00
|
|
|
(
|
|
|
|
x - min_x_offset.ceil() as i32,
|
|
|
|
x2 + max_x_offset.ceil() as i32,
|
|
|
|
)
|
2017-09-07 14:48:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn extend_top_bottom_area(&self, model: &UiModel, cell_metrics: &CellMetrics) -> (i32, i32) {
|
2017-09-07 19:53:32 +00:00
|
|
|
let y = self.top as i32 * cell_metrics.line_height as i32;
|
2017-09-08 15:26:16 +00:00
|
|
|
let y2 = (self.bot + 1) as i32 * cell_metrics.line_height as i32;
|
|
|
|
let mut min_y_offset = 0.0;
|
|
|
|
let mut max_y_offset = 0.0;
|
2017-09-07 14:48:10 +00:00
|
|
|
|
|
|
|
for col in self.left..self.right + 1 {
|
|
|
|
|
|
|
|
// top
|
|
|
|
let line = &model.model[self.top];
|
2017-09-08 15:26:16 +00:00
|
|
|
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = line.get_item(col) {
|
|
|
|
if min_y_offset < overflow.top {
|
|
|
|
min_y_offset = overflow.top;
|
2017-09-07 14:48:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// bottom
|
|
|
|
let line = &model.model[self.bot];
|
2017-09-08 15:26:16 +00:00
|
|
|
if let Some(&Item { ink_overflow: Some(ref overflow), .. }) = line.get_item(col) {
|
|
|
|
if max_y_offset < overflow.top {
|
|
|
|
max_y_offset = overflow.top;
|
2017-09-07 14:48:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-09-08 15:26:16 +00:00
|
|
|
(
|
|
|
|
y - min_y_offset.ceil() as i32,
|
|
|
|
y2 + max_y_offset.ceil() as i32,
|
|
|
|
)
|
2017-09-07 14:48:10 +00:00
|
|
|
}
|
|
|
|
|
2017-09-06 15:31:13 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-09-07 14:48:10 +00:00
|
|
|
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,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2017-11-13 09:51:22 +00:00
|
|
|
pub fn from_area(cell_metrics: &CellMetrics, x1: f64, y1: f64, x2: f64, y2: f64) -> ModelRect {
|
2017-09-12 15:28:01 +00:00
|
|
|
let &CellMetrics {
|
|
|
|
char_width,
|
|
|
|
line_height,
|
|
|
|
..
|
|
|
|
} = cell_metrics;
|
|
|
|
|
2017-09-06 15:31:13 +00:00
|
|
|
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<ModelRect> for ModelRect {
|
|
|
|
fn as_ref(&self) -> &ModelRect {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
}
|
2017-09-11 15:00:51 +00:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_repaint_rect() {
|
|
|
|
let rect = ModelRect::point(1, 1);
|
|
|
|
let (x, y, width, height) = rect.to_area(&CellMetrics::new_hw(10.0, 5.0));
|
|
|
|
|
|
|
|
assert_eq!(5, x);
|
|
|
|
assert_eq!(10, y);
|
|
|
|
assert_eq!(5, width);
|
|
|
|
assert_eq!(10, height);
|
|
|
|
}
|
2017-09-13 14:40:43 +00:00
|
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_from_area() {
|
|
|
|
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 3.0, 3.0, 9.0, 17.0);
|
|
|
|
|
|
|
|
assert_eq!(0, rect.top);
|
|
|
|
assert_eq!(0, rect.left);
|
|
|
|
assert_eq!(1, rect.bot);
|
|
|
|
assert_eq!(1, rect.right);
|
|
|
|
|
|
|
|
|
|
|
|
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 10.0, 20.0);
|
|
|
|
|
|
|
|
assert_eq!(0, rect.top);
|
|
|
|
assert_eq!(0, rect.left);
|
|
|
|
assert_eq!(1, rect.bot);
|
|
|
|
assert_eq!(1, rect.right);
|
|
|
|
|
|
|
|
|
|
|
|
let rect = ModelRect::from_area(&CellMetrics::new_hw(10.0, 5.0), 0.0, 0.0, 11.0, 21.0);
|
|
|
|
|
|
|
|
assert_eq!(0, rect.top);
|
|
|
|
assert_eq!(0, rect.left);
|
|
|
|
assert_eq!(2, rect.bot);
|
|
|
|
assert_eq!(2, rect.right);
|
|
|
|
}
|
|
|
|
|
2017-09-11 15:00:51 +00:00
|
|
|
}
|