Add new repaint logic

This commit is contained in:
daa84
2017-09-07 17:48:10 +03:00
parent 6963c7ab95
commit 7f05e11e84
7 changed files with 152 additions and 282 deletions

View File

@@ -51,7 +51,7 @@ impl Line {
self.dirty_line = true;
}
pub fn clear_draw_cache(&mut self) {
pub fn clear_glyphs(&mut self) {
for i in 0..self.item_line.len() {
self.item_line[i] = None;
self.cell_to_item[i] = -1;
@@ -176,6 +176,15 @@ impl Line {
}
}
pub fn get_item(&self, cell_idx: usize) -> Option<&Item> {
let item_idx = self.cell_to_item(cell_idx);
if item_idx >= 0 {
self.item_line[item_idx as usize].as_ref()
} else {
None
}
}
#[inline]
pub fn cell_to_item(&self, cell_idx: usize) -> i32 {
self.cell_to_item[cell_idx]

View File

@@ -6,7 +6,7 @@ mod model_rect;
pub use self::cell::{Cell, Attrs};
pub use self::line::StyledLine;
pub use self::item::Item;
pub use self::model_rect::{ModelRect, ModelRectVec, ClipRowIterator};
pub use self::model_rect::{ModelRect, ModelRectVec};
use self::line::Line;
@@ -50,33 +50,6 @@ impl UiModel {
&mut self.model
}
pub fn limit_to_model(&self, clip: &mut ModelRect) {
clip.left = if clip.left >= self.columns {
self.columns - 1
} else {
clip.left
};
clip.right = if clip.right >= self.columns {
self.columns - 1
} else {
clip.right
};
clip.top = if clip.top >= self.rows {
self.rows - 1
} else {
clip.top
};
clip.bot = if clip.bot >= self.rows {
self.rows - 1
} else {
clip.bot
};
}
pub fn clip_model<'a>(&'a self, clip: &'a ModelRect) -> ClipRowIterator<'a> {
ClipRowIterator::new(self, clip)
}
pub fn cur_point(&self) -> ModelRect {
ModelRect::point(self.cur_col, self.cur_row)
}
@@ -186,9 +159,9 @@ impl UiModel {
}
}
pub fn clear_draw_cache(&mut self) {
pub fn clear_glyphs(&mut self) {
for row in &mut self.model.iter_mut() {
row.clear_draw_cache();
row.clear_glyphs();
}
}
}
@@ -257,34 +230,6 @@ mod tests {
assert_eq!(2, list.list.len());
}
#[test]
fn test_iterator_border() {
let model = UiModel::new(10, 20);
let rect = ModelRect::new(0, 9, 0, 19);
assert_eq!(10, model.clip_model(&rect).count());
let (_, first_line) = model.clip_model(&rect).nth(0).unwrap();
assert_eq!(20, first_line.iter().count());
let (idx, _) = first_line.iter().nth(19).unwrap();
assert_eq!(19, idx);
}
#[test]
fn test_iterator() {
let model = UiModel::new(10, 20);
let rect = ModelRect::new(1, 2, 1, 2);
assert_eq!(2, model.clip_model(&rect).count());
let (idx, first_line) = model.clip_model(&rect).nth(0).unwrap();
assert_eq!(1, idx);
assert_eq!(2, first_line.iter().count());
let (idx, _) = first_line.iter().nth(0).unwrap();
assert_eq!(1, idx);
}
#[test]
fn test_from_area() {
let rect = ModelRect::from_area(10.0, 5.0, 3.0, 3.0, 9.0, 17.0);

View File

@@ -1,6 +1,6 @@
use std::slice::Iter;
use super::{Line, UiModel, Cell};
use super::UiModel;
use super::item::Item;
use render::CellMetrics;
#[derive(Clone, Debug)]
@@ -16,11 +16,13 @@ impl ModelRectVec {
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 ||
rect.bot == neighbor.bot + 1) && neighbor.in_horizontal(rect) {
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) {
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);
@@ -73,32 +75,21 @@ impl ModelRect {
#[inline]
fn in_horizontal(&self, other: &ModelRect) -> bool {
other.left >= self.left && other.left <= self.right ||
other.right >= self.left && other.right >= 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
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
self.right >= other.right
}
pub fn extend(&mut self, top: usize, bot: usize, left: usize, right: usize) {
if self.top > 0 {
self.top -= top;
}
if self.left > 0 {
self.left -= left;
}
self.bot += bot;
self.right += right;
}
/// Extend rect to left and right to make change Item rerendered
/// 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;
@@ -120,6 +111,73 @@ impl ModelRect {
}
}
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
@@ -147,20 +205,29 @@ impl ModelRect {
debug_assert!(self.left <= self.right);
}
pub fn to_area(&self, line_height: f64, char_width: f64) -> (i32, i32, i32, i32) {
(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 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 {
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;
@@ -177,86 +244,3 @@ impl AsRef<ModelRect> for ModelRect {
self
}
}
pub struct ClipRowIterator<'a> {
rect: &'a ModelRect,
pos: usize,
iter: Iter<'a, Line>,
}
impl<'a> ClipRowIterator<'a> {
pub fn new(model: &'a UiModel, rect: &'a ModelRect) -> ClipRowIterator<'a> {
ClipRowIterator {
rect: rect,
pos: 0,
iter: model.model()[rect.top..rect.bot + 1].iter(),
}
}
}
impl<'a> Iterator for ClipRowIterator<'a> {
type Item = (usize, ClipLine<'a>);
fn next(&mut self) -> Option<(usize, ClipLine<'a>)> {
self.pos += 1;
self.iter
.next()
.map(|line| (self.rect.top + self.pos - 1, ClipLine::new(line, self.rect)))
}
}
pub struct ClipLine<'a> {
rect: &'a ModelRect,
line: &'a Line,
}
impl<'a> ClipLine<'a> {
pub fn new(model: &'a Line, rect: &'a ModelRect) -> ClipLine<'a> {
ClipLine {
line: model,
rect: rect,
}
}
#[inline]
pub fn is_double_width(&self, col_idx: usize) -> bool {
self.get(col_idx + 1)
.map(|c| c.attrs.double_width)
.unwrap_or(false)
}
pub fn get(&self, idx: usize) -> Option<&Cell> {
self.line.line.get(idx)
}
pub fn iter(&self) -> ClipColIterator<'a> {
ClipColIterator::new(self.line, self.rect)
}
}
pub struct ClipColIterator<'a> {
rect: &'a ModelRect,
pos: usize,
iter: Iter<'a, Cell>,
}
impl<'a> ClipColIterator<'a> {
pub fn new(model: &'a Line, rect: &'a ModelRect) -> ClipColIterator<'a> {
ClipColIterator {
rect: rect,
pos: 0,
iter: model.line[rect.left..rect.right + 1].iter(),
}
}
}
impl<'a> Iterator for ClipColIterator<'a> {
type Item = (usize, &'a Cell);
fn next(&mut self) -> Option<(usize, &'a Cell)> {
self.pos += 1;
self.iter
.next()
.map(|line| (self.rect.left + self.pos - 1, line))
}
}