Invalidate rect passed to draw

This commit is contained in:
daa 2017-03-18 12:45:05 +03:00
parent 51dcd7f4e8
commit 89e6600325
3 changed files with 162 additions and 51 deletions

View File

@ -7,35 +7,35 @@ use shell::Shell;
use glib;
pub trait RedrawEvents {
fn on_cursor_goto(&mut self, row: u64, col: u64);
fn on_cursor_goto(&mut self, row: u64, col: u64) -> RepaintMode;
fn on_put(&mut self, text: &str);
fn on_put(&mut self, text: &str) -> RepaintMode;
fn on_clear(&mut self);
fn on_clear(&mut self) -> RepaintMode;
fn on_resize(&mut self, columns: u64, rows: u64);
fn on_resize(&mut self, columns: u64, rows: u64) -> RepaintMode;
fn on_redraw(&self, mode: &RepaintMode);
fn on_highlight_set(&mut self, attrs: &Vec<(Value, Value)>);
fn on_highlight_set(&mut self, attrs: &Vec<(Value, Value)>) -> RepaintMode;
fn on_eol_clear(&mut self);
fn on_eol_clear(&mut self) -> RepaintMode;
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64);
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) -> RepaintMode;
fn on_scroll(&mut self, count: i64);
fn on_scroll(&mut self, count: i64) -> RepaintMode;
fn on_update_bg(&mut self, bg: i64);
fn on_update_bg(&mut self, bg: i64) -> RepaintMode;
fn on_update_fg(&mut self, fg: i64);
fn on_update_fg(&mut self, fg: i64) -> RepaintMode;
fn on_update_sp(&mut self, sp: i64);
fn on_update_sp(&mut self, sp: i64) -> RepaintMode;
fn on_mode_change(&mut self, mode: &str);
fn on_mode_change(&mut self, mode: &str) -> RepaintMode;
fn on_mouse_on(&mut self);
fn on_mouse_on(&mut self) -> RepaintMode;
fn on_mouse_off(&mut self);
fn on_mouse_off(&mut self) -> RepaintMode;
}
pub trait GuiApi {
@ -96,6 +96,8 @@ fn nvim_cb(method: &str, params: Vec<Value>) {
match method {
"redraw" => {
safe_call(move |ui| {
let mut repaint_mode = RepaintMode::Nothing;
for ev in &params {
if let &Value::Array(ref ev_args) = ev {
if let Value::String(ref ev_name) = ev_args[0] {
@ -104,7 +106,8 @@ fn nvim_cb(method: &str, params: Vec<Value>) {
&Value::Array(ref ar) => ar.clone(),
_ => vec![],
};
call(ui, ev_name, &args)?;
let call_reapint_mode = call(ui, ev_name, &args)?;
repaint_mode = repaint_mode.join(&call_reapint_mode);
}
} else {
println!("Unsupported event {:?}", ev_args);
@ -114,7 +117,7 @@ fn nvim_cb(method: &str, params: Vec<Value>) {
}
}
ui.on_redraw(&RepaintMode::All);
ui.on_redraw(&repaint_mode);
Ok(())
});
}
@ -148,8 +151,8 @@ fn call_gui_event(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Re
Ok(())
}
fn call(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<(), String> {
match method {
fn call(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<RepaintMode, String> {
Ok(match method {
"cursor_goto" => ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1])),
"put" => ui.on_put(try_str!(args[0])),
"clear" => ui.on_clear(),
@ -160,6 +163,7 @@ fn call(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<(), S
} else {
panic!("Supports only map value as argument");
}
RepaintMode::Nothing
}
"eol_clear" => ui.on_eol_clear(),
"set_scroll_region" => {
@ -167,6 +171,7 @@ fn call(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<(), S
try_uint!(args[1]),
try_uint!(args[2]),
try_uint!(args[3]));
RepaintMode::Nothing
}
"scroll" => ui.on_scroll(try_int!(args[0])),
"update_bg" => ui.on_update_bg(try_int!(args[0])),
@ -175,10 +180,11 @@ fn call(ui: &mut Shell, method: &str, args: &Vec<Value>) -> result::Result<(), S
"mode_change" => ui.on_mode_change(try_str!(args[0])),
"mouse_on" => ui.on_mouse_on(),
"mouse_off" => ui.on_mouse_off(),
_ => println!("Event {}({:?})", method, args),
};
Ok(())
_ => {
println!("Event {}({:?})", method, args);
RepaintMode::Nothing
},
})
}
fn safe_call<F>(cb: F)
@ -205,8 +211,25 @@ impl<T> ErrorReport for result::Result<T, CallError> {
}
}
#[derive(Clone)]
pub enum RepaintMode {
Nothing,
All,
Area(ModelRect),
}
impl RepaintMode {
pub fn join(&self, mode: &RepaintMode) -> RepaintMode {
match (self, mode) {
(&RepaintMode::Nothing, m) => m.clone(),
(m, &RepaintMode::Nothing) => m.clone(),
(&RepaintMode::All, _) => RepaintMode::All,
(_, &RepaintMode::All) => RepaintMode::All,
(&RepaintMode::Area(ref mr1), &RepaintMode::Area(ref mr2)) => {
let mut area = mr1.clone();
area.join(mr2);
RepaintMode::Area(area)
}
}
}
}

View File

@ -459,24 +459,26 @@ fn gtk_configure_event(_: &DrawingArea, ev: &EventConfigure) -> bool {
}
impl RedrawEvents for Shell {
fn on_cursor_goto(&mut self, row: u64, col: u64) {
self.model.set_cursor(row, col);
fn on_cursor_goto(&mut self, row: u64, col: u64) -> RepaintMode {
RepaintMode::Area(self.model.set_cursor(row, col))
}
fn on_put(&mut self, text: &str) {
self.model.put(text, self.cur_attrs.as_ref());
fn on_put(&mut self, text: &str) -> RepaintMode {
RepaintMode::Area(self.model.put(text, self.cur_attrs.as_ref()))
}
fn on_clear(&mut self) {
fn on_clear(&mut self) -> RepaintMode {
self.model.clear();
RepaintMode::All
}
fn on_eol_clear(&mut self) {
self.model.eol_clear();
fn on_eol_clear(&mut self) -> RepaintMode {
RepaintMode::Area(self.model.eol_clear())
}
fn on_resize(&mut self, columns: u64, rows: u64) {
fn on_resize(&mut self, columns: u64, rows: u64) -> RepaintMode {
self.model = UiModel::new(rows, columns);
RepaintMode::All
}
fn on_redraw(&self, mode: &RepaintMode) {
@ -492,18 +494,20 @@ impl RedrawEvents for Shell {
}
});
},
&RepaintMode::Nothing => (),
}
}
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) {
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) -> RepaintMode {
self.model.set_scroll_region(top, bot, left, right);
RepaintMode::Nothing
}
fn on_scroll(&mut self, count: i64) {
self.model.scroll(count as usize);
fn on_scroll(&mut self, count: i64) -> RepaintMode {
RepaintMode::Area(self.model.scroll(count as usize))
}
fn on_highlight_set(&mut self, attrs: &Vec<(Value, Value)>) {
fn on_highlight_set(&mut self, attrs: &Vec<(Value, Value)>) -> RepaintMode {
let mut model_attrs = Attrs::new();
for &(ref key_val, ref val) in attrs {
@ -537,46 +541,54 @@ impl RedrawEvents for Shell {
}
self.cur_attrs = Some(model_attrs);
RepaintMode::Nothing
}
fn on_update_bg(&mut self, bg: i64) {
fn on_update_bg(&mut self, bg: i64) -> RepaintMode {
if bg >= 0 {
self.bg_color = split_color(bg as u64);
} else {
self.bg_color = COLOR_BLACK;
}
RepaintMode::Nothing
}
fn on_update_fg(&mut self, fg: i64) {
fn on_update_fg(&mut self, fg: i64) -> RepaintMode {
if fg >= 0 {
self.fg_color = split_color(fg as u64);
} else {
self.fg_color = COLOR_WHITE;
}
RepaintMode::Nothing
}
fn on_update_sp(&mut self, sp: i64) {
fn on_update_sp(&mut self, sp: i64) -> RepaintMode {
if sp >= 0 {
self.sp_color = split_color(sp as u64);
} else {
self.sp_color = COLOR_RED;
}
RepaintMode::Nothing
}
fn on_mode_change(&mut self, mode: &str) {
fn on_mode_change(&mut self, mode: &str) -> RepaintMode {
match mode {
"normal" => self.mode = NvimMode::Normal,
"insert" => self.mode = NvimMode::Insert,
_ => self.mode = NvimMode::Other,
}
RepaintMode::Area(self.model.cur_point())
}
fn on_mouse_on(&mut self) {
fn on_mouse_on(&mut self) -> RepaintMode {
self.mouse_enabled = true;
RepaintMode::Nothing
}
fn on_mouse_off(&mut self) {
fn on_mouse_off(&mut self) -> RepaintMode {
self.mouse_enabled = false;
RepaintMode::Nothing
}
}

View File

@ -120,13 +120,17 @@ impl UiModel {
&self.model
}
pub fn cur_point(&self) -> ModelRect {
ModelRect::point(self.cur_row, self.cur_col)
}
pub fn set_cursor(&mut self, row: u64, col: u64) -> ModelRect {
let mut changed_region = ModelRect::point(self.cur_row, self.cur_col);
let mut changed_region = self.cur_point();
self.cur_row = row as usize;
self.cur_col = col as usize;
changed_region.join(&ModelRect::point(self.cur_row, self.cur_col));
changed_region.join(&self.cur_point());
changed_region
@ -137,8 +141,8 @@ impl UiModel {
}
pub fn put(&mut self, text: &str, attrs: Option<&Attrs>) -> ModelRect {
let changed_region = self.cur_point();
let mut cell = &mut self.model[self.cur_row][self.cur_col];
let changed_region = ModelRect::point(self.cur_row, self.cur_col);
cell.ch = text.chars().last().unwrap_or(' ');
cell.attrs = attrs.map(Attrs::clone).unwrap_or_else(|| Attrs::new());
@ -183,21 +187,19 @@ impl UiModel {
self.clear_region(top, (top - count - 1), left, right);
}
ModelRect::new(top, bot, left ,right)
ModelRect::new(top, bot, left, right)
}
pub fn clear(&mut self) -> ModelRect {
pub fn clear(&mut self) {
let (rows, columns) = (self.rows, self.columns);
self.clear_region(0, rows - 1, 0, columns - 1);
ModelRect::new(0, 0, rows -1, columns -1)
}
pub fn eol_clear(&mut self) -> ModelRect {
let (cur_row, cur_col, columns) = (self.cur_row, self.cur_col, self.columns);
self.clear_region(cur_row, cur_row, cur_col, columns - 1);
ModelRect::new(cur_row, cur_col, cur_col, columns -1)
ModelRect::new(cur_row, cur_col, cur_col, columns - 1)
}
fn clear_region(&mut self, top: usize, bot: usize, left: usize, right: usize) {
@ -209,6 +211,7 @@ impl UiModel {
}
}
#[derive(Clone)]
pub struct ModelRect {
top: usize,
bot: usize,
@ -260,8 +263,81 @@ impl ModelRect {
}
pub fn to_area(&self, line_height: i32, char_width: i32) -> (i32, i32, i32, i32) {
let y = self.top as i32 * line_height;
let x = self.left as i32 * char_width;
(x, y, self.right as i32 * char_width - x, self.bot as i32 * line_height - y)
(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)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cursor_area() {
let mut model = UiModel::new(10, 20);
model.set_cursor(1, 1);
let rect = model.set_cursor(5, 5);
assert_eq!(1, rect.top);
assert_eq!(1, rect.left);
assert_eq!(5, rect.bot);
assert_eq!(5, rect.right);
}
#[test]
fn test_eol_clear_area() {
let mut model = UiModel::new(10, 20);
model.set_cursor(1, 1);
let rect = model.eol_clear();
assert_eq!(1, rect.top);
assert_eq!(1, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(19, rect.right);
}
#[test]
fn test_repaint_rect() {
let rect = ModelRect::point(1, 1);
let (x, y, width, height) = rect.to_area(10, 5);
assert_eq!(5, x);
assert_eq!(10, y);
assert_eq!(5, width);
assert_eq!(10, height);
}
#[test]
fn test_put_area() {
let mut model = UiModel::new(10, 20);
model.set_cursor(1, 1);
let rect = model.put(" ", None);
assert_eq!(1, rect.top);
assert_eq!(1, rect.left);
assert_eq!(1, rect.bot);
assert_eq!(1, rect.right);
}
#[test]
fn test_scroll_area() {
let mut model = UiModel::new(10, 20);
model.set_scroll_region(1, 5, 1, 5);
let rect = model.scroll(3);
assert_eq!(1, rect.top);
assert_eq!(1, rect.left);
assert_eq!(5, rect.bot);
assert_eq!(5, rect.right);
}
}