Support double_width chars

This commit is contained in:
daa84 2017-09-13 12:39:02 +03:00
parent 31a0fea819
commit dc8d6d5a70
5 changed files with 132 additions and 63 deletions

2
Cargo.lock generated
View File

@ -1,6 +1,6 @@
[root] [root]
name = "nvim-gtk" name = "nvim-gtk"
version = "0.1.2" version = "0.2.0"
dependencies = [ dependencies = [
"cairo-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "cairo-rs 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nvim-gtk" name = "nvim-gtk"
version = "0.1.2" version = "0.2.0"
authors = ["daa84 <daa84@inbox.ru>"] authors = ["daa84 <daa84@inbox.ru>"]
build = "build.rs" build = "build.rs"

View File

@ -4,7 +4,7 @@ mod model_clip_iterator;
pub use self::context::Context; pub use self::context::Context;
pub use self::context::CellMetrics; pub use self::context::CellMetrics;
use self::model_clip_iterator::ModelClipIteratorFactory; use self::model_clip_iterator::{RowView, ModelClipIteratorFactory};
use mode; use mode;
use color; use color;
@ -31,62 +31,34 @@ pub fn render(
ctx.paint(); ctx.paint();
let cell_metrics = font_ctx.cell_metrics(); let cell_metrics = font_ctx.cell_metrics();
let &CellMetrics { let &CellMetrics { char_width, .. } = cell_metrics;
line_height,
char_width,
underline_position,
underline_thickness,
..
} = cell_metrics;
let (cursor_row, cursor_col) = ui_model.get_cursor(); let (cursor_row, cursor_col) = ui_model.get_cursor();
for (row, line) in ui_model.get_clip_iterator(ctx, cell_metrics) { for cell_view in ui_model.get_clip_iterator(ctx, cell_metrics) {
let line_y = row as f64 * line_height;
let mut line_x = 0.0; let mut line_x = 0.0;
let RowView { line, row, line_y, .. } = cell_view;
for col in 0..line.line.len() { for col in 0..line.line.len() {
let cell = &line.line[col]; let cell = &line.line[col];
draw_cell( draw_cell(&cell_view, color_model, cell, col, line_x);
ctx,
cell_metrics,
color_model,
line,
cell,
col,
line_x,
line_y,
);
if cell.attrs.underline || cell.attrs.undercurl { draw_underline(&cell_view, color_model, cell, line_x);
if cell.attrs.undercurl {
let sp = color_model.actual_cell_sp(cell);
ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7);
let max_undercurl_height = (line_height - underline_position) * 2.0;
let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height);
let undercurl_y = line_y + underline_position - undercurl_height / 2.0;
ctx.show_error_underline(line_x, undercurl_y, char_width, undercurl_height);
} else if cell.attrs.underline {
let fg = color_model.actual_cell_fg(cell);
ctx.set_source_rgb(fg.0, fg.1, fg.2);
ctx.set_line_width(underline_thickness);
ctx.move_to(line_x, line_y + underline_position);
ctx.line_to(line_x + char_width, line_y + underline_position);
ctx.stroke();
}
}
if row == cursor_row && col == cursor_col { if row == cursor_row && col == cursor_col {
let double_width = line.line.get(col + 1).map_or(
false,
|c| c.attrs.double_width,
);
ctx.move_to(line_x, line_y); ctx.move_to(line_x, line_y);
cursor.draw( cursor.draw(
ctx, ctx,
font_ctx, font_ctx,
mode, mode,
line_y, line_y,
false, //TODO: double_width, double_width,
color_model.actual_cell_bg(cell), color_model.actual_cell_bg(cell),
); );
} }
@ -96,23 +68,68 @@ pub fn render(
} }
} }
fn draw_cell( fn draw_underline(
ctx: &cairo::Context, cell_view: &RowView,
cell_metrics: &CellMetrics, color_model: &color::ColorModel,
cell: &ui_model::Cell,
line_x: f64,
) {
if cell.attrs.underline || cell.attrs.undercurl {
let &RowView {
ctx,
line_y,
cell_metrics: &CellMetrics {
line_height,
char_width,
underline_position,
underline_thickness,
..
},
..
} = cell_view;
if cell.attrs.undercurl {
let sp = color_model.actual_cell_sp(cell);
ctx.set_source_rgba(sp.0, sp.1, sp.2, 0.7);
let max_undercurl_height = (line_height - underline_position) * 2.0;
let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height);
let undercurl_y = line_y + underline_position - undercurl_height / 2.0;
ctx.show_error_underline(line_x, undercurl_y, char_width, undercurl_height);
} else if cell.attrs.underline {
let fg = color_model.actual_cell_fg(cell);
ctx.set_source_rgb(fg.0, fg.1, fg.2);
ctx.set_line_width(underline_thickness);
ctx.move_to(line_x, line_y + underline_position);
ctx.line_to(line_x + char_width, line_y + underline_position);
ctx.stroke();
}
}
}
fn draw_cell(
cell_view: &RowView,
color_model: &color::ColorModel, color_model: &color::ColorModel,
line: &ui_model::Line,
cell: &ui_model::Cell, cell: &ui_model::Cell,
col: usize, col: usize,
line_x: f64, line_x: f64,
line_y: f64,
) { ) {
let &CellMetrics { let &RowView {
char_width, ctx,
line_height, line,
ascent, line_y,
cell_metrics: &CellMetrics {
char_width,
line_height,
ascent,
..
},
.. ..
} = cell_metrics; } = cell_view;
let (bg, fg) = color_model.cell_colors(cell); let (bg, fg) = color_model.cell_colors(cell);

View File

@ -4,25 +4,57 @@ use cairo;
use super::context::CellMetrics; use super::context::CellMetrics;
use ui_model; use ui_model;
pub struct RowView<'a> {
pub row: usize,
pub line: &'a ui_model::Line,
pub cell_metrics: &'a CellMetrics,
pub line_y: f64,
pub ctx: &'a cairo::Context,
}
impl<'a> RowView<'a> {
pub fn new(
row: usize,
ctx: &'a cairo::Context,
cell_metrics: &'a CellMetrics,
line: &'a ui_model::Line,
) -> Self {
RowView {
line,
line_y: row as f64 * cell_metrics.line_height,
row,
cell_metrics,
ctx,
}
}
}
pub struct ModelClipIterator<'a> { pub struct ModelClipIterator<'a> {
model_idx: usize, model_idx: usize,
model_iter: Iter<'a, ui_model::Line>, model_iter: Iter<'a, ui_model::Line>,
cell_metrics: &'a CellMetrics,
ctx: &'a cairo::Context,
} }
pub trait ModelClipIteratorFactory { pub trait ModelClipIteratorFactory {
fn get_clip_iterator( fn get_clip_iterator<'a>(
&self, &'a self,
ctx: &cairo::Context, ctx: &'a cairo::Context,
cell_metrics: &CellMetrics, cell_metrics: &'a CellMetrics,
) -> ModelClipIterator; ) -> ModelClipIterator;
} }
impl<'a> Iterator for ModelClipIterator<'a> { impl<'a> Iterator for ModelClipIterator<'a> {
type Item = (usize, &'a ui_model::Line); type Item = RowView<'a>;
fn next(&mut self) -> Option<(usize, &'a ui_model::Line)> { fn next(&mut self) -> Option<RowView<'a>> {
let next = if let Some(line) = self.model_iter.next() { let next = if let Some(line) = self.model_iter.next() {
Some((self.model_idx, line)) Some(RowView::new(
self.model_idx,
self.ctx,
self.cell_metrics,
line,
))
} else { } else {
None None
}; };
@ -36,11 +68,11 @@ impl<'a> Iterator for ModelClipIterator<'a> {
/// this is because in some cases(like 'g' character) drawing character does not fit to calculated bounds /// this is because in some cases(like 'g' character) drawing character does not fit to calculated bounds
/// and if one line must be repainted - also previous and next line must be repainted to /// and if one line must be repainted - also previous and next line must be repainted to
impl ModelClipIteratorFactory for ui_model::UiModel { impl ModelClipIteratorFactory for ui_model::UiModel {
fn get_clip_iterator( fn get_clip_iterator<'a>(
&self, &'a self,
ctx: &cairo::Context, ctx: &'a cairo::Context,
cell_metrics: &CellMetrics, cell_metrics: &'a CellMetrics,
) -> ModelClipIterator { ) -> ModelClipIterator<'a> {
let model = self.model(); let model = self.model();
let (x1, y1, x2, y2) = ctx.clip_extents(); let (x1, y1, x2, y2) = ctx.clip_extents();
@ -59,6 +91,8 @@ impl ModelClipIteratorFactory for ui_model::UiModel {
ModelClipIterator { ModelClipIterator {
model_idx: model_clip_top, model_idx: model_clip_top,
model_iter: model[model_clip_top..model_clip_bot + 1].iter(), model_iter: model[model_clip_top..model_clip_bot + 1].iter(),
ctx,
cell_metrics,
} }
} }
} }

View File

@ -108,6 +108,24 @@ impl ModelRect {
if right < self.right + len_since_right { if right < self.right + len_since_right {
right = self.right + len_since_right; right = self.right + len_since_right;
} }
// extend also double_width chars
let cell = &line.line[self.left];
if self.left > 0 && cell.attrs.double_width {
let dw_char_idx = self.left - 1;
if dw_char_idx < left {
left = dw_char_idx;
}
}
let dw_char_idx = self.right + 1;
if let Some(cell) = line.line.get(dw_char_idx) {
if cell.attrs.double_width {
if right < dw_char_idx {
right = dw_char_idx;
}
}
}
} }
self.left = left; self.left = left;