Implement scroll

This commit is contained in:
daa 2016-04-03 18:13:18 +03:00
parent 0c64c43278
commit b3c2744e2d
4 changed files with 102 additions and 16 deletions

View File

@ -1,2 +1,5 @@
test:
RUST_BACKTRACE=1 cargo test
run:
RUST_BACKTRACE=1 cargo run

View File

@ -23,6 +23,10 @@ pub trait RedrawEvents {
fn on_highlight_set(&mut self, attrs: &HashMap<String, Value>);
fn on_eol_clear(&mut self);
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64);
fn on_scroll(&mut self, count: i64);
}
macro_rules! try_str {
@ -33,9 +37,17 @@ macro_rules! try_str {
}
macro_rules! try_int {
($expr:expr) => (match $expr {
Value::Integer(Integer::U64(val)) => val as i64,
Value::Integer(Integer::I64(val)) => val,
_ => return Err("Can't convert argument to int".to_owned())
})
}
macro_rules! try_uint {
($exp:expr) => (match $exp {
Value::Integer(Integer::U64(val)) => val,
_ => return Err("Can't convert argument to int".to_owned())
_ => return Err("Can't convert argument to u64".to_owned())
})
}
@ -93,7 +105,7 @@ fn call(method: &str, args: Vec<Value>) {
match method {
"cursor_goto" => {
safe_call(move |ui| {
ui.on_cursor_goto(try_int!(args[0]), try_int!(args[1]));
ui.on_cursor_goto(try_uint!(args[0]), try_uint!(args[1]));
Ok(())
})
}
@ -111,19 +123,29 @@ fn call(method: &str, args: Vec<Value>) {
}
"resize" => {
safe_call(move |ui| {
ui.on_resize(try_int!(args[0]), try_int!(args[1]));
ui.on_resize(try_uint!(args[0]), try_uint!(args[1]));
Ok(())
});
}
"highlight_set" => {
safe_call(move |ui| {
if let Value::Map(ref attrs) = args[0] {
let attrs_map: HashMap<String, Value> = attrs.iter().map(|v| {
match v {
&(Value::String(ref key), ref value) => (key.clone(), value.clone()),
_ => panic!("attribute key must be string"),
}
}).collect();
let attrs_map: HashMap<String, Value> = attrs.iter()
.map(|v| {
match v {
&(Value::String(ref key),
ref value) => {
(key.clone(),
value.clone())
}
_ => {
panic!("attribute \
key must be \
string")
}
}
})
.collect();
ui.on_highlight_set(&attrs_map);
} else {
panic!("Supports only map value as argument");
@ -137,6 +159,18 @@ fn call(method: &str, args: Vec<Value>) {
Ok(())
})
}
"set_scroll_region" => {
safe_call(move |ui| {
ui.on_set_scroll_region(try_uint!(args[0]), try_uint!(args[1]), try_uint!(args[2]), try_uint!(args[3]));
Ok(())
});
}
"scroll" => {
safe_call(move |ui| {
ui.on_scroll(try_int!(args[0]));
Ok(())
});
}
_ => println!("Event {}({:?})", method, args),
};
}

View File

@ -244,6 +244,14 @@ impl RedrawEvents for Ui {
self.drawing_area.queue_draw();
}
fn on_set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) {
self.model.set_scroll_region(top, bot, left, right);
}
fn on_scroll(&mut self, count: i64) {
self.model.scroll(count);
}
fn on_highlight_set(&mut self, attrs: &HashMap<String, Value>) {
let mut model_attrs = Attrs::new();
if let Some(&Value::Integer(Integer::U64(fg))) = attrs.get("foreground") {

View File

@ -31,6 +31,7 @@ impl Attrs {
}
}
#[derive(Clone)]
pub struct Cell {
pub ch: char,
pub attrs: Attrs,
@ -56,6 +57,10 @@ pub struct UiModel {
cur_row: usize,
cur_col: usize,
model: Vec<Vec<Cell>>,
top: usize,
bot: usize,
left: usize,
right: usize,
}
impl UiModel {
@ -78,6 +83,10 @@ impl UiModel {
cur_row: 0,
cur_col: 0,
model: model,
top: 0,
bot: 0,
left: 0,
right: 0,
}
}
@ -97,12 +106,44 @@ impl UiModel {
self.cur_col += 1;
}
pub fn clear(&mut self) {
for row in 0..self.rows {
for col in 0..self.columns {
self.model[row][col].clear();
pub fn set_scroll_region(&mut self, top: u64, bot: u64, left: u64, right: u64) {
self.top = top as usize;
self.bot = bot as usize;
self.left = left as usize;
self.right = right as usize;
}
fn copy_row(&mut self, row: usize, offset: i64, left: usize, right: usize) {
for col in left..right + 1 {
let from_row = (row as i64 + offset) as usize;
let from_cell = self.model[from_row][col].clone();
self.model[row][col] = from_cell;
}
}
pub fn scroll(&mut self, count: i64) {
let (top, bot, left, right) = (self.top as i64, self.bot as i64, self.left, self.right);
if count > 0 {
for row in top as usize..(bot - count + 1) as usize {
self.copy_row(row, count, left, right);
}
} else {
for row in ((top - count) as usize..(bot + 1) as usize).rev() {
self.copy_row(row, count, left, right);
}
}
if count > 0 {
self.clear_region((bot - count + 1) as usize, bot as usize, left, right);
} else {
self.clear_region(top as usize, (top - count - 1) as usize, left, right);
}
}
pub fn clear(&mut self) {
let (rows, columns) = (self.rows, self.columns);
self.clear_region(0, rows - 1, 0, columns - 1);
}
pub fn eol_clear(&mut self) {
@ -111,9 +152,9 @@ impl UiModel {
}
fn clear_region(&mut self, top: usize, bot: usize, left: usize, right: usize) {
for row in top..bot + 1 {
for col in left..right + 1 {
self.model[row][col].clear();
for row in &mut self.model[top..bot + 1] {
for cell in &mut row[left..right + 1] {
cell.clear();
}
}
}