Clip Iterator

This commit is contained in:
daa84 2017-03-20 18:18:08 +03:00
parent c2a6ec88c7
commit 778cbd0af2
3 changed files with 132 additions and 23 deletions

View File

@ -233,3 +233,24 @@ impl RepaintMode {
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_mode() {
let mode = RepaintMode::Area(ModelRect::point(1, 1));
mode.join(&RepaintMode::Nothing);
match mode {
RepaintMode::Area(ref rect) => {
assert_eq!(1, rect.top);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.left);
assert_eq!(1, rect.right);
}
_ => panic!("mode is worng")
}
}
}

View File

@ -14,7 +14,7 @@ use gtk::DrawingArea;
use neovim_lib::{Neovim, NeovimApi, Value, Integer};
use settings;
use ui_model::{UiModel, Cell, Attrs, Color, COLOR_BLACK, COLOR_WHITE, COLOR_RED};
use ui_model::{UiModel, Cell, Attrs, Color, ModelRect, COLOR_BLACK, COLOR_WHITE, COLOR_RED};
use nvim::{RedrawEvents, GuiApi, RepaintMode};
use input::{convert_key, keyval_to_input_string};
use ui::{UI, Ui, SET};
@ -276,17 +276,24 @@ fn draw(shell: &Shell, ctx: &cairo::Context) {
let line_height = shell.line_height.unwrap();
let char_width = shell.char_width.unwrap();
let clip = ctx.clip_extents();
let model_clip = ModelRect::from_area(line_height, char_width,
clip.0, clip.1, clip.2, clip.3);
let line_x = model_clip.left as f64 * char_width;
let mut line_y: f64 = model_clip.top as f64 * line_height;
let (row, col) = shell.model.get_cursor();
let mut buf = String::with_capacity(4);
let mut line_y: f64 = 0.0;
let layout = pc::create_layout(ctx);
let mut desc = shell.create_pango_font();
for (line_idx, line) in shell.model.model().iter().enumerate() {
ctx.move_to(0.0, line_y);
// FIXME: col_idx is wrong
for (line_idx, line) in shell.model.clip_model(&model_clip) {
ctx.move_to(line_x, line_y);
// first draw background
// here we join same bg color for given line
@ -319,7 +326,7 @@ fn draw(shell: &Shell, ctx: &cairo::Context) {
line_height,
from_bg.take().unwrap());
ctx.move_to(0.0, line_y);
ctx.move_to(line_x, line_y);
for (col_idx, cell) in line.iter().enumerate() {
let double_width = line.get(col_idx + 1).map(|c| c.attrs.double_width).unwrap_or(false);
@ -508,12 +515,13 @@ impl RedrawEvents for Shell {
match mode {
&RepaintMode::All => self.drawing_area.queue_draw(),
&RepaintMode::Area(ref rect) => {
if let Some(line_height) = self.line_height {
if let Some(char_width) = self.char_width {
match (&self.line_height, &self.char_width) {
(&Some(line_height), &Some(char_width)) => {
let (x, y, width, height) =
rect.to_area(line_height as i32, char_width as i32);
rect.to_area(line_height, char_width);
self.drawing_area.queue_draw_area(x, y, width, height);
}
_ => self.drawing_area.queue_draw(),
}
}
&RepaintMode::Nothing => (),

View File

@ -1,3 +1,4 @@
use std::slice::Iter;
#[derive(Clone, PartialEq)]
pub struct Color(pub f64, pub f64, pub f64);
@ -120,6 +121,10 @@ impl UiModel {
&self.model
}
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_row, self.cur_col)
}
@ -218,10 +223,10 @@ impl UiModel {
#[derive(Clone)]
pub struct ModelRect {
top: usize,
bot: usize,
left: usize,
right: usize,
pub top: usize,
pub bot: usize,
pub left: usize,
pub right: usize,
}
impl ModelRect {
@ -267,30 +272,105 @@ impl ModelRect {
};
}
pub fn to_area(&self, line_height: i32, char_width: i32) -> (i32, i32, i32, i32) {
(self.left as i32 * char_width,
self.top as i32 * line_height,
(self.right - self.left + 1) as i32 * char_width,
(self.bot - self.top + 1) as i32 * line_height)
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 from_area(line_height: i32, char_width: i32, x1: f64, y1: f64, x2: f64, y2: f64) -> ModelRect {
let left = (x1 / char_width as f64) as usize;
let right = (x2 / char_width as f64) as usize;
let top = (y1 / line_height as f64) as usize;
let bot = (y2 / line_height as f64) as usize;
pub fn from_area(line_height: f64, char_width: f64, x1: f64, y1: f64, x2: f64, y2: f64) -> ModelRect {
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)
}
}
pub struct ClipRowIterator<'a> {
rect: &'a ModelRect,
pos: usize,
iter: Iter<'a, Vec<Cell>>,
}
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, ClipColIterator<'a>);
fn next(&mut self) -> Option<(usize, ClipColIterator<'a>)> {
self.pos += 1;
self.iter.next().map(|line| {
(self.rect.top + self.pos, ClipColIterator::new(line, self.rect))
})
}
}
pub struct ClipColIterator<'a> {
rect: &'a ModelRect,
len: usize,
line: &'a Vec<Cell>,
pos: usize,
iter: Iter<'a, Cell>,
}
impl <'a> ClipColIterator<'a> {
pub fn new(model: &'a Vec<Cell>, rect: &'a ModelRect) -> ClipColIterator<'a> {
ClipColIterator {
len: rect.right - rect.left + 1,
line: model,
rect: rect,
pos: 0,
iter: model[rect.left..rect.right + 1].iter(),
}
}
pub fn len(&self) -> usize {
self.len
}
pub fn get(&self, idx: usize) -> Option<&Cell> {
self.line.get(idx)
}
}
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, line)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[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());
assert_eq!(2, model.clip_model(&rect).nth(0).unwrap().count());
}
#[test]
fn test_from_area() {
let rect = ModelRect::from_area(10, 5, 3.0, 3.0, 9.0, 17.0);
let rect = ModelRect::from_area(10.0, 5.0, 3.0, 3.0, 9.0, 17.0);
assert_eq!(0, rect.top);
assert_eq!(0, rect.left);