Show block, blink cursor

This commit is contained in:
daa 2018-01-21 23:19:00 +03:00
parent 29cf31914d
commit 3f62906fac
5 changed files with 136 additions and 86 deletions

View File

@ -26,6 +26,7 @@ impl Level {
//TODO: double width chars render, also note in text wrapping //TODO: double width chars render, also note in text wrapping
//TODO: im //TODO: im
//TODO: cursor //TODO: cursor
//TODO: delete
pub fn replace_from_ctx(&mut self, ctx: &CmdLineContext, render_state: &shell::RenderState) { pub fn replace_from_ctx(&mut self, ctx: &CmdLineContext, render_state: &shell::RenderState) {
self.replace_line(&ctx.get_lines(), render_state, false); self.replace_line(&ctx.get_lines(), render_state, false);
@ -147,6 +148,7 @@ struct State {
block: Option<Level>, block: Option<Level>,
render_state: Rc<RefCell<shell::RenderState>>, render_state: Rc<RefCell<shell::RenderState>>,
drawing_area: gtk::DrawingArea, drawing_area: gtk::DrawingArea,
cursor: Option<cursor::BlinkCursor<State>>,
} }
impl State { impl State {
@ -156,6 +158,7 @@ impl State {
block: None, block: None,
render_state, render_state,
drawing_area, drawing_area,
cursor: None,
} }
} }
@ -180,7 +183,19 @@ impl State {
impl cursor::CursorRedrawCb for State { impl cursor::CursorRedrawCb for State {
fn queue_redraw_cursor(&mut self) { fn queue_redraw_cursor(&mut self) {
// TODO: implement // TODO: take gap and preview offset here
if let Some(ref level) = self.levels.last() {
let model = &level.model_layout.model;
let mut cur_point = model.cur_point();
cur_point.extend_by_items(model);
let render_state = self.render_state.borrow();
let cell_metrics = render_state.font_ctx.cell_metrics();
let (x, y, width, height) = cur_point.to_area_extend_ink(model, cell_metrics);
self.drawing_area.queue_draw_area(x, y, width, height);
}
} }
} }
@ -202,9 +217,10 @@ impl CmdLine {
let state = Arc::new(UiMutex::new(State::new(drawing_area.clone(), render_state))); let state = Arc::new(UiMutex::new(State::new(drawing_area.clone(), render_state)));
let weak_cb = Arc::downgrade(&state); let weak_cb = Arc::downgrade(&state);
let cursor = cursor::Cursor::new(weak_cb); let cursor = cursor::BlinkCursor::new(weak_cb);
state.borrow_mut().cursor = Some(cursor);
drawing_area.connect_draw(clone!(state => move |_, ctx| gtk_draw(ctx, &state, &cursor))); drawing_area.connect_draw(clone!(state => move |_, ctx| gtk_draw(ctx, &state)));
CmdLine { CmdLine {
popover, popover,
@ -240,6 +256,7 @@ impl CmdLine {
}); });
self.popover.popup(); self.popover.popup();
state.cursor.as_mut().unwrap().start();
} else { } else {
state.drawing_area.queue_draw() state.drawing_area.queue_draw()
} }
@ -255,6 +272,7 @@ impl CmdLine {
if state.levels.is_empty() { if state.levels.is_empty() {
self.popover.hide(); self.popover.hide();
self.displyed = false; self.displyed = false;
state.cursor.as_mut().unwrap().leave_focus();
} }
} }
@ -298,7 +316,6 @@ impl CmdLine {
fn gtk_draw( fn gtk_draw(
ctx: &cairo::Context, ctx: &cairo::Context,
state: &Arc<UiMutex<State>>, state: &Arc<UiMutex<State>>,
cursor: &cursor::Cursor<State>,
) -> Inhibit { ) -> Inhibit {
let state = state.borrow(); let state = state.borrow();
let level = state.levels.last(); let level = state.levels.last();
@ -314,11 +331,12 @@ fn gtk_draw(
ctx.translate(0.0, gap as f64 / 2.0); ctx.translate(0.0, gap as f64 / 2.0);
} }
render::clear(ctx, &render_state.color_model);
if let Some(block) = block { if let Some(block) = block {
// TODO: disable cursor
render::render( render::render(
ctx, ctx,
cursor, &cursor::EmptyCursor::new(),
&render_state.font_ctx, &render_state.font_ctx,
&block.model_layout.model, &block.model_layout.model,
&render_state.color_model, &render_state.color_model,
@ -332,7 +350,7 @@ fn gtk_draw(
//TODO: limit model to row filled //TODO: limit model to row filled
render::render( render::render(
ctx, ctx,
cursor, state.cursor.as_ref().unwrap(),
&render_state.font_ctx, &render_state.font_ctx,
&level.model_layout.model, &level.model_layout.model,
&render_state.color_model, &render_state.color_model,

View File

@ -69,13 +69,48 @@ impl <CB: CursorRedrawCb> State <CB> {
} }
} }
pub struct Cursor <CB: CursorRedrawCb> { pub trait Cursor {
fn draw(
&self,
ctx: &cairo::Context,
font_ctx: &render::Context,
mode: &mode::Mode,
line_y: f64,
double_width: bool,
bg: &Color,
);
}
pub struct EmptyCursor;
impl EmptyCursor {
pub fn new() -> Self {
EmptyCursor { }
}
}
impl Cursor for EmptyCursor {
fn draw(
&self,
_ctx: &cairo::Context,
_font_ctx: &render::Context,
_mode: &mode::Mode,
_line_y: f64,
_double_width: bool,
_bg: &Color,
) {
}
}
pub struct BlinkCursor<CB: CursorRedrawCb> {
state: Arc<UiMutex<State<CB>>>, state: Arc<UiMutex<State<CB>>>,
} }
impl <CB: CursorRedrawCb + 'static> Cursor <CB> { impl<CB: CursorRedrawCb + 'static> BlinkCursor<CB> {
pub fn new(redraw_cb: Weak<UiMutex<CB>>) -> Self { pub fn new(redraw_cb: Weak<UiMutex<CB>>) -> Self {
Cursor { state: Arc::new(UiMutex::new(State::new(redraw_cb))) } BlinkCursor {
state: Arc::new(UiMutex::new(State::new(redraw_cb))),
}
} }
pub fn start(&mut self) { pub fn start(&mut self) {
@ -110,8 +145,10 @@ impl <CB: CursorRedrawCb + 'static> Cursor <CB> {
pub fn busy_off(&mut self) { pub fn busy_off(&mut self) {
self.start(); self.start();
} }
}
pub fn draw( impl<CB: CursorRedrawCb> Cursor for BlinkCursor<CB> {
fn draw(
&self, &self,
ctx: &cairo::Context, ctx: &cairo::Context,
font_ctx: &render::Context, font_ctx: &render::Context,
@ -120,7 +157,6 @@ impl <CB: CursorRedrawCb + 'static> Cursor <CB> {
double_width: bool, double_width: bool,
bg: &Color, bg: &Color,
) { ) {
let state = self.state.borrow(); let state = self.state.borrow();
if state.anim_phase == AnimPhase::Busy { if state.anim_phase == AnimPhase::Busy {
@ -155,9 +191,7 @@ fn cursor_rect(
if let Some(mode_info) = mode.mode_info() { if let Some(mode_info) = mode.mode_info() {
match mode_info.cursor_shape() { match mode_info.cursor_shape() {
None | None | Some(&nvim::CursorShape::Unknown) | Some(&nvim::CursorShape::Block) => {
Some(&nvim::CursorShape::Unknown) |
Some(&nvim::CursorShape::Block) => {
let cursor_width = if double_width { let cursor_width = if double_width {
char_width * 2.0 char_width * 2.0
} else { } else {
@ -211,29 +245,25 @@ fn anim_step<CB: CursorRedrawCb + 'static> (state: &Arc<UiMutex<State<CB>>>) ->
mut_state.anim_phase = AnimPhase::Hide; mut_state.anim_phase = AnimPhase::Hide;
Some(60) Some(60)
} }
AnimPhase::Hide => { AnimPhase::Hide => if !mut_state.alpha.hide(0.3) {
if !mut_state.alpha.hide(0.3) {
mut_state.anim_phase = AnimPhase::Hidden; mut_state.anim_phase = AnimPhase::Hidden;
Some(300) Some(300)
} else { } else {
None None
} },
}
AnimPhase::Hidden => { AnimPhase::Hidden => {
mut_state.anim_phase = AnimPhase::Show; mut_state.anim_phase = AnimPhase::Show;
Some(60) Some(60)
} }
AnimPhase::Show => { AnimPhase::Show => if !mut_state.alpha.show(0.3) {
if !mut_state.alpha.show(0.3) {
mut_state.anim_phase = AnimPhase::Shown; mut_state.anim_phase = AnimPhase::Shown;
Some(500) Some(500)
} else { } else {
None None
} },
}
AnimPhase::NoFocus => None, AnimPhase::NoFocus => None,
AnimPhase::Busy => None, AnimPhase::Busy => None,
}; };
@ -251,10 +281,9 @@ fn anim_step<CB: CursorRedrawCb + 'static> (state: &Arc<UiMutex<State<CB>>>) ->
} else { } else {
glib::Continue(true) glib::Continue(true)
} }
} }
impl <CB: CursorRedrawCb> Drop for Cursor<CB> { impl<CB: CursorRedrawCb> Drop for BlinkCursor<CB> {
fn drop(&mut self) { fn drop(&mut self) {
if let Some(timer_id) = self.state.borrow_mut().timer.take() { if let Some(timer_id) = self.state.borrow_mut().timer.take() {
glib::source_remove(timer_id); glib::source_remove(timer_id);

View File

@ -14,7 +14,9 @@ pub struct Context {
impl Context { impl Context {
pub fn new(font_desc: pango::FontDescription) -> Self { pub fn new(font_desc: pango::FontDescription) -> Self {
Context { state: ContextState::new(font_desc) } Context {
state: ContextState::new(font_desc),
}
} }
pub fn update(&mut self, font_desc: pango::FontDescription) { pub fn update(&mut self, font_desc: pango::FontDescription) {
@ -84,20 +86,18 @@ pub struct CellMetrics {
impl CellMetrics { impl CellMetrics {
fn new(font_metrics: &pango::FontMetrics) -> Self { fn new(font_metrics: &pango::FontMetrics) -> Self {
CellMetrics { CellMetrics {
pango_ascent: font_metrics.get_ascent(), pango_ascent: font_metrics.get_ascent(),
pango_descent: font_metrics.get_descent(), pango_descent: font_metrics.get_descent(),
pango_char_width: font_metrics.get_approximate_digit_width(), pango_char_width: font_metrics.get_approximate_digit_width(),
ascent: font_metrics.get_ascent() as f64 / pango::SCALE as f64, ascent: font_metrics.get_ascent() as f64 / pango::SCALE as f64,
line_height: (font_metrics.get_ascent() + font_metrics.get_descent()) as f64 / line_height: (font_metrics.get_ascent() + font_metrics.get_descent()) as f64
pango::SCALE as f64, / pango::SCALE as f64,
char_width: font_metrics.get_approximate_digit_width() as f64 / pango::SCALE as f64, char_width: font_metrics.get_approximate_digit_width() as f64 / pango::SCALE as f64,
underline_position: (font_metrics.get_ascent() - underline_position: (font_metrics.get_ascent() - font_metrics.get_underline_position())
font_metrics.get_underline_position()) as as f64 / pango::SCALE as f64,
f64 / pango::SCALE as f64, underline_thickness: font_metrics.get_underline_thickness() as f64
underline_thickness: font_metrics.get_underline_thickness() as f64 / / pango::SCALE as f64,
pango::SCALE as f64,
} }
} }

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::{RowView, ModelClipIteratorFactory}; use self::model_clip_iterator::{ModelClipIteratorFactory, RowView};
use mode; use mode;
use color; use color;
@ -14,24 +14,26 @@ use pango;
use cairo; use cairo;
use pangocairo; use pangocairo;
use cursor; use cursor::Cursor;
use ui_model; use ui_model;
pub fn render<RC: cursor::CursorRedrawCb + 'static>( pub fn clear(ctx: &cairo::Context, color_model: &color::ColorModel) {
ctx: &cairo::Context,
cursor: &cursor::Cursor<RC>,
font_ctx: &context::Context,
ui_model: &ui_model::UiModel,
color_model: &color::ColorModel,
mode: &mode::Mode,
) {
ctx.set_source_rgb( ctx.set_source_rgb(
color_model.bg_color.0, color_model.bg_color.0,
color_model.bg_color.1, color_model.bg_color.1,
color_model.bg_color.2, color_model.bg_color.2,
); );
ctx.paint(); ctx.paint();
}
pub fn render<C: Cursor>(
ctx: &cairo::Context,
cursor: &C,
font_ctx: &context::Context,
ui_model: &ui_model::UiModel,
color_model: &color::ColorModel,
mode: &mode::Mode,
) {
let cell_metrics = font_ctx.cell_metrics(); let cell_metrics = font_ctx.cell_metrics();
let &CellMetrics { char_width, .. } = cell_metrics; let &CellMetrics { char_width, .. } = cell_metrics;
let (cursor_row, cursor_col) = ui_model.get_cursor(); let (cursor_row, cursor_col) = ui_model.get_cursor();
@ -47,19 +49,19 @@ pub fn render<RC: cursor::CursorRedrawCb + 'static>(
for cell_view in ui_model.get_clip_iterator(ctx, cell_metrics) { for cell_view in ui_model.get_clip_iterator(ctx, cell_metrics) {
let mut line_x = 0.0; let mut line_x = 0.0;
let RowView { line, row, line_y, .. } = cell_view; let RowView {
line, row, line_y, ..
} = cell_view;
for (col, cell) in line.line.iter().enumerate() { for (col, cell) in line.line.iter().enumerate() {
draw_cell(&cell_view, color_model, cell, col, line_x); draw_cell(&cell_view, color_model, cell, col, line_x);
draw_underline(&cell_view, color_model, cell, line_x); draw_underline(&cell_view, color_model, cell, line_x);
if row == cursor_row && col == cursor_col { if row == cursor_row && col == cursor_col {
let double_width = line.line.get(col + 1).map_or( let double_width = line.line
false, .get(col + 1)
|c| c.attrs.double_width, .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,
@ -82,13 +84,12 @@ fn draw_underline(
cell: &ui_model::Cell, cell: &ui_model::Cell,
line_x: f64, line_x: f64,
) { ) {
if cell.attrs.underline || cell.attrs.undercurl { if cell.attrs.underline || cell.attrs.undercurl {
let &RowView { let &RowView {
ctx, ctx,
line_y, line_y,
cell_metrics: &CellMetrics { cell_metrics:
&CellMetrics {
line_height, line_height,
char_width, char_width,
underline_position, underline_position,
@ -106,7 +107,13 @@ fn draw_underline(
let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height); let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height);
let undercurl_y = line_y + underline_position - undercurl_height / 2.0; let undercurl_y = line_y + underline_position - undercurl_height / 2.0;
pangocairo::functions::error_underline_path(ctx, line_x, undercurl_y, char_width, undercurl_height); pangocairo::functions::error_underline_path(
ctx,
line_x,
undercurl_y,
char_width,
undercurl_height,
);
} else if cell.attrs.underline { } else if cell.attrs.underline {
let fg = color_model.actual_cell_fg(cell); let fg = color_model.actual_cell_fg(cell);
ctx.set_source_rgb(fg.0, fg.1, fg.2); ctx.set_source_rgb(fg.0, fg.1, fg.2);
@ -129,7 +136,8 @@ fn draw_cell_bg(
ctx, ctx,
line, line,
line_y, line_y,
cell_metrics: &CellMetrics { cell_metrics:
&CellMetrics {
char_width, char_width,
line_height, line_height,
.. ..
@ -157,7 +165,6 @@ fn draw_cell_bg(
ctx.fill(); ctx.fill();
} }
} }
} }
fn draw_cell( fn draw_cell(
@ -167,15 +174,11 @@ fn draw_cell(
col: usize, col: usize,
line_x: f64, line_x: f64,
) { ) {
let &RowView { let &RowView {
ctx, ctx,
line, line,
line_y, line_y,
cell_metrics: &CellMetrics { cell_metrics: &CellMetrics { ascent, .. },
ascent,
..
},
.. ..
} = cell_view; } = cell_view;
@ -188,7 +191,6 @@ fn draw_cell(
show_glyph_string(ctx, item.font(), glyphs); show_glyph_string(ctx, item.font(), glyphs);
} }
} }
} }

View File

@ -26,7 +26,7 @@ use nvim::{self, RedrawEvents, GuiApi, RepaintMode, ErrorReport, NeovimClient,
NeovimRef, NeovimClientAsync, CompleteItem}; NeovimRef, NeovimClientAsync, CompleteItem};
use input; use input;
use input::keyval_to_input_string; use input::keyval_to_input_string;
use cursor::{Cursor, CursorRedrawCb}; use cursor::{BlinkCursor, Cursor, CursorRedrawCb};
use ui::UiMutex; use ui::UiMutex;
use popup_menu::{self, PopupMenu}; use popup_menu::{self, PopupMenu};
use tabline::Tabline; use tabline::Tabline;
@ -94,7 +94,7 @@ pub struct State {
cur_attrs: Option<Attrs>, cur_attrs: Option<Attrs>,
mouse_enabled: bool, mouse_enabled: bool,
nvim: Rc<NeovimClient>, nvim: Rc<NeovimClient>,
cursor: Option<Cursor<State>>, cursor: Option<BlinkCursor<State>>,
popup_menu: PopupMenu, popup_menu: PopupMenu,
cmd_line: CmdLine, cmd_line: CmdLine,
settings: Rc<RefCell<Settings>>, settings: Rc<RefCell<Settings>>,
@ -449,7 +449,7 @@ impl Shell {
}; };
let shell_ref = Arc::downgrade(&shell.state); let shell_ref = Arc::downgrade(&shell.state);
shell.state.borrow_mut().cursor = Some(Cursor::new(shell_ref)); shell.state.borrow_mut().cursor = Some(BlinkCursor::new(shell_ref));
shell shell
} }
@ -807,6 +807,7 @@ fn gtk_draw(state_arc: &Arc<UiMutex<State>>, ctx: &cairo::Context) -> Inhibit {
let state = state_arc.borrow(); let state = state_arc.borrow();
if state.nvim.is_initialized() { if state.nvim.is_initialized() {
let render_state = state.render_state.borrow(); let render_state = state.render_state.borrow();
render::clear(ctx, &render_state.color_model);
render::render( render::render(
ctx, ctx,
state.cursor.as_ref().unwrap(), state.cursor.as_ref().unwrap(),