Make repaint by regions

This commit is contained in:
daa 2017-04-22 18:00:06 +03:00
parent ee0af91043
commit 552021d2be

View File

@ -145,7 +145,6 @@ impl State {
_ => self.drawing_area.queue_draw(), _ => self.drawing_area.queue_draw(),
} }
} }
} }
pub struct UiState { pub struct UiState {
@ -347,28 +346,16 @@ fn gtk_scroll_event(state: &mut State, ev: &EventScroll) -> Inhibit {
match ev.as_ref().direction { match ev.as_ref().direction {
ScrollDirection::Right => { ScrollDirection::Right => {
mouse_input(state, mouse_input(state, "ScrollWheelRight", ev.get_state(), ev.get_position())
"ScrollWheelRight",
ev.get_state(),
ev.get_position())
} }
ScrollDirection::Left => { ScrollDirection::Left => {
mouse_input(state, mouse_input(state, "ScrollWheelLeft", ev.get_state(), ev.get_position())
"ScrollWheelLeft",
ev.get_state(),
ev.get_position())
} }
ScrollDirection::Up => { ScrollDirection::Up => {
mouse_input(state, mouse_input(state, "ScrollWheelUp", ev.get_state(), ev.get_position())
"ScrollWheelUp",
ev.get_state(),
ev.get_position())
} }
ScrollDirection::Down => { ScrollDirection::Down => {
mouse_input(state, mouse_input(state, "ScrollWheelDown", ev.get_state(), ev.get_position())
"ScrollWheelDown",
ev.get_state(),
ev.get_position())
} }
_ => (), _ => (),
} }
@ -383,18 +370,12 @@ fn gtk_button_press(shell: &mut State, ui_state: &mut UiState, ev: &EventButton)
if shell.mouse_enabled { if shell.mouse_enabled {
ui_state.mouse_pressed = true; ui_state.mouse_pressed = true;
mouse_input(shell, mouse_input(shell, "LeftMouse", ev.get_state(), ev.get_position());
"LeftMouse",
ev.get_state(),
ev.get_position());
} }
Inhibit(false) Inhibit(false)
} }
fn mouse_input(shell: &mut State, fn mouse_input(shell: &mut State, input: &str, state: ModifierType, position: (f64, f64)) {
input: &str,
state: ModifierType,
position: (f64, f64)) {
if let Some(line_height) = shell.line_height { if let Some(line_height) = shell.line_height {
if let Some(char_width) = shell.char_width { if let Some(char_width) = shell.char_width {
@ -416,10 +397,7 @@ fn gtk_button_release(ui_state: &mut UiState) -> Inhibit {
fn gtk_motion_notify(shell: &mut State, ui_state: &mut UiState, ev: &EventMotion) -> Inhibit { fn gtk_motion_notify(shell: &mut State, ui_state: &mut UiState, ev: &EventMotion) -> Inhibit {
if shell.mouse_enabled && ui_state.mouse_pressed { if shell.mouse_enabled && ui_state.mouse_pressed {
mouse_input(shell, mouse_input(shell, "LeftDrag", ev.get_state(), ev.get_position());
"LeftDrag",
ev.get_state(),
ev.get_position());
} }
Inhibit(false) Inhibit(false)
} }
@ -459,7 +437,11 @@ fn draw_joined_rect(state: &State,
} }
#[inline] #[inline]
fn get_model_clip(state: &State, line_height: f64, char_width: f64, clip: (f64, f64, f64, f64)) -> ModelRect { fn get_model_clip(state: &State,
line_height: f64,
char_width: f64,
clip: (f64, f64, f64, f64))
-> ModelRect {
let mut model_clip = let mut model_clip =
ModelRect::from_area(line_height, char_width, clip.0, clip.1, clip.2, clip.3); ModelRect::from_area(line_height, char_width, clip.0, clip.1, clip.2, clip.3);
// in some cases symbols from previous row affect next row // in some cases symbols from previous row affect next row
@ -472,7 +454,11 @@ fn get_model_clip(state: &State, line_height: f64, char_width: f64, clip: (f64,
} }
#[inline] #[inline]
fn draw_backgound(state: &State, ctx: &cairo::Context, line_height: f64, char_width: f64, model_clip: &ModelRect) { fn draw_backgound(state: &State,
ctx: &cairo::Context,
line_height: f64,
char_width: f64,
model_clip: &ModelRect) {
let line_x = model_clip.left as f64 * char_width; let line_x = model_clip.left as f64 * char_width;
let mut line_y: f64 = model_clip.top as f64 * line_height; let mut line_y: f64 = model_clip.top as f64 * line_height;
@ -515,109 +501,116 @@ fn draw_backgound(state: &State, ctx: &cairo::Context, line_height: f64, char_wi
} }
fn draw(state: &State, ctx: &cairo::Context) { fn draw(state: &State, ctx: &cairo::Context) {
ctx.set_source_rgb(state.bg_color.0, state.bg_color.1, state.bg_color.2); let layout = pc::create_layout(ctx);
ctx.paint(); let mut desc = state.create_pango_font();
let mut buf = String::with_capacity(4);
let (row, col) = state.model.get_cursor();
let line_height = state.line_height.unwrap(); let line_height = state.line_height.unwrap();
let char_width = state.char_width.unwrap(); let char_width = state.char_width.unwrap();
let model_clip = get_model_clip(state, line_height, char_width, ctx.clip_extents()); ctx.set_source_rgb(state.bg_color.0, state.bg_color.1, state.bg_color.2);
ctx.paint();
let line_x = model_clip.left as f64 * char_width; let clip_rects = &ctx.copy_clip_rectangle_list().rectangles;
let mut line_y: f64 = model_clip.top as f64 * line_height; for clip_idx in 0..clip_rects.len() {
let clip = clip_rects.get(clip_idx).unwrap();
let (row, col) = state.model.get_cursor(); let model_clip = get_model_clip(state,
let mut buf = String::with_capacity(4); line_height,
char_width,
(clip.x, clip.y, clip.x + clip.width, clip.y + clip.height));
let line_x = model_clip.left as f64 * char_width;
let mut line_y: f64 = model_clip.top as f64 * line_height;
let layout = pc::create_layout(ctx); draw_backgound(state, ctx, line_height, char_width, &model_clip);
let mut desc = state.create_pango_font();
draw_backgound(state, ctx, line_height, char_width, &model_clip); for (line_idx, line) in state.model.clip_model(&model_clip) {
for (line_idx, line) in state.model.clip_model(&model_clip) { ctx.move_to(line_x, line_y);
ctx.move_to(line_x, line_y); for (col_idx, cell) in line.iter() {
let double_width = line.get(col_idx + 1)
.map(|c| c.attrs.double_width)
.unwrap_or(false);
let current_point = ctx.get_current_point();
for (col_idx, cell) in line.iter() { let (bg, fg) = state.colors(cell);
let double_width = line.get(col_idx + 1)
.map(|c| c.attrs.double_width)
.unwrap_or(false);
let current_point = ctx.get_current_point();
let (bg, fg) = state.colors(cell); if row == line_idx && col == col_idx {
state
.cursor
.as_ref()
.unwrap()
.draw(ctx,
state,
char_width,
line_height,
line_y,
double_width,
bg);
if row == line_idx && col == col_idx { ctx.move_to(current_point.0, current_point.1);
state
.cursor
.as_ref()
.unwrap()
.draw(ctx,
state,
char_width,
line_height,
line_y,
double_width,
bg);
ctx.move_to(current_point.0, current_point.1);
}
if !cell.ch.is_whitespace() {
update_font_description(&mut desc, &cell.attrs);
layout.set_font_description(Some(&desc));
buf.clear();
buf.push(cell.ch);
layout.set_text(&buf, -1);
// correct layout for double_width chars
if double_width {
let (dw_width, dw_height) = layout.get_pixel_size();
let x_offset = (char_width * 2.0 - dw_width as f64) / 2.0;
let y_offset = (line_height - dw_height as f64) / 2.0;
ctx.rel_move_to(x_offset, y_offset);
} }
ctx.set_source_rgb(fg.0, fg.1, fg.2);
pc::update_layout(ctx, &layout);
pc::show_layout(ctx, &layout);
}
if cell.attrs.underline || cell.attrs.undercurl { if !cell.ch.is_whitespace() {
// [TODO]: Current gtk-rs bindings does not provide fontmetrics access update_font_description(&mut desc, &cell.attrs);
// so it is not possible to find right position for underline or undercurl position
// > update_font_description(&mut desc, &cell.attrs);
// > layout.get_context().unwrap().get_metrics();
let top_offset = line_height * 0.9;
let sp = if let Some(ref sp) = cell.attrs.special { layout.set_font_description(Some(&desc));
sp buf.clear();
} else { buf.push(cell.ch);
&state.sp_color layout.set_text(&buf, -1);
};
ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7); // correct layout for double_width chars
if cell.attrs.undercurl { if double_width {
ctx.set_dash(&[4.0, 2.0], 0.0); let (dw_width, dw_height) = layout.get_pixel_size();
ctx.set_line_width(2.0); let x_offset = (char_width * 2.0 - dw_width as f64) / 2.0;
ctx.move_to(current_point.0, line_y + top_offset); let y_offset = (line_height - dw_height as f64) / 2.0;
ctx.line_to(current_point.0 + char_width, line_y + top_offset); ctx.rel_move_to(x_offset, y_offset);
ctx.stroke(); }
ctx.set_dash(&[], 0.0);
} else if cell.attrs.underline { ctx.set_source_rgb(fg.0, fg.1, fg.2);
ctx.set_line_width(1.0); pc::update_layout(ctx, &layout);
ctx.move_to(current_point.0, line_y + top_offset); pc::show_layout(ctx, &layout);
ctx.line_to(current_point.0 + char_width, line_y + top_offset);
ctx.stroke();
} }
if cell.attrs.underline || cell.attrs.undercurl {
// [TODO]: Current gtk-rs bindings does not provide fontmetrics access
// so it is not possible to find right position for underline or undercurl position
// > update_font_description(&mut desc, &cell.attrs);
// > layout.get_context().unwrap().get_metrics();
let top_offset = line_height * 0.9;
let sp = if let Some(ref sp) = cell.attrs.special {
sp
} else {
&state.sp_color
};
ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7);
if cell.attrs.undercurl {
ctx.set_dash(&[4.0, 2.0], 0.0);
ctx.set_line_width(2.0);
ctx.move_to(current_point.0, line_y + top_offset);
ctx.line_to(current_point.0 + char_width, line_y + top_offset);
ctx.stroke();
ctx.set_dash(&[], 0.0);
} else if cell.attrs.underline {
ctx.set_line_width(1.0);
ctx.move_to(current_point.0, line_y + top_offset);
ctx.line_to(current_point.0 + char_width, line_y + top_offset);
ctx.stroke();
}
}
ctx.move_to(current_point.0 + char_width, current_point.1);
} }
ctx.move_to(current_point.0 + char_width, current_point.1); line_y += line_height;
} }
line_y += line_height;
} }
} }