From 3f62906faca91ec61c9b93b5ba759c08bca97c76 Mon Sep 17 00:00:00 2001 From: daa Date: Sun, 21 Jan 2018 23:19:00 +0300 Subject: [PATCH] Show block, blink cursor --- src/cmd_line.rs | 32 ++++++++++++---- src/cursor.rs | 87 ++++++++++++++++++++++++++++--------------- src/render/context.rs | 18 ++++----- src/render/mod.rs | 78 +++++++++++++++++++------------------- src/shell.rs | 7 ++-- 5 files changed, 136 insertions(+), 86 deletions(-) diff --git a/src/cmd_line.rs b/src/cmd_line.rs index cb1f0e0..dfc4d7e 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -26,6 +26,7 @@ impl Level { //TODO: double width chars render, also note in text wrapping //TODO: im //TODO: cursor + //TODO: delete pub fn replace_from_ctx(&mut self, ctx: &CmdLineContext, render_state: &shell::RenderState) { self.replace_line(&ctx.get_lines(), render_state, false); @@ -147,6 +148,7 @@ struct State { block: Option, render_state: Rc>, drawing_area: gtk::DrawingArea, + cursor: Option>, } impl State { @@ -156,6 +158,7 @@ impl State { block: None, render_state, drawing_area, + cursor: None, } } @@ -180,7 +183,19 @@ impl State { impl cursor::CursorRedrawCb for State { 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 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 { popover, @@ -240,6 +256,7 @@ impl CmdLine { }); self.popover.popup(); + state.cursor.as_mut().unwrap().start(); } else { state.drawing_area.queue_draw() } @@ -255,6 +272,7 @@ impl CmdLine { if state.levels.is_empty() { self.popover.hide(); self.displyed = false; + state.cursor.as_mut().unwrap().leave_focus(); } } @@ -298,7 +316,6 @@ impl CmdLine { fn gtk_draw( ctx: &cairo::Context, state: &Arc>, - cursor: &cursor::Cursor, ) -> Inhibit { let state = state.borrow(); let level = state.levels.last(); @@ -314,11 +331,12 @@ fn gtk_draw( ctx.translate(0.0, gap as f64 / 2.0); } + render::clear(ctx, &render_state.color_model); + if let Some(block) = block { - // TODO: disable cursor render::render( ctx, - cursor, + &cursor::EmptyCursor::new(), &render_state.font_ctx, &block.model_layout.model, &render_state.color_model, @@ -332,7 +350,7 @@ fn gtk_draw( //TODO: limit model to row filled render::render( ctx, - cursor, + state.cursor.as_ref().unwrap(), &render_state.font_ctx, &level.model_layout.model, &render_state.color_model, diff --git a/src/cursor.rs b/src/cursor.rs index 8070452..8c5068b 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -50,7 +50,7 @@ struct State { timer: Option, } -impl State { +impl State { fn new(redraw_cb: Weak>) -> Self { State { alpha: Alpha(1.0), @@ -69,13 +69,48 @@ impl State { } } -pub struct Cursor { +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 { state: Arc>>, } -impl Cursor { +impl BlinkCursor { pub fn new(redraw_cb: Weak>) -> 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) { @@ -110,8 +145,10 @@ impl Cursor { pub fn busy_off(&mut self) { self.start(); } +} - pub fn draw( +impl Cursor for BlinkCursor { + fn draw( &self, ctx: &cairo::Context, font_ctx: &render::Context, @@ -120,7 +157,6 @@ impl Cursor { double_width: bool, bg: &Color, ) { - let state = self.state.borrow(); if state.anim_phase == AnimPhase::Busy { @@ -155,9 +191,7 @@ fn cursor_rect( if let Some(mode_info) = mode.mode_info() { match mode_info.cursor_shape() { - None | - Some(&nvim::CursorShape::Unknown) | - Some(&nvim::CursorShape::Block) => { + None | Some(&nvim::CursorShape::Unknown) | Some(&nvim::CursorShape::Block) => { let cursor_width = if double_width { char_width * 2.0 } else { @@ -203,7 +237,7 @@ fn cursor_rect( } } -fn anim_step (state: &Arc>>) -> glib::Continue { +fn anim_step(state: &Arc>>) -> glib::Continue { let mut mut_state = state.borrow_mut(); let next_event = match mut_state.anim_phase { @@ -211,30 +245,26 @@ fn anim_step (state: &Arc>>) -> mut_state.anim_phase = AnimPhase::Hide; Some(60) } - AnimPhase::Hide => { - if !mut_state.alpha.hide(0.3) { - mut_state.anim_phase = AnimPhase::Hidden; + AnimPhase::Hide => if !mut_state.alpha.hide(0.3) { + mut_state.anim_phase = AnimPhase::Hidden; - Some(300) - } else { - None - } - } + Some(300) + } else { + None + }, AnimPhase::Hidden => { mut_state.anim_phase = AnimPhase::Show; Some(60) } - AnimPhase::Show => { - if !mut_state.alpha.show(0.3) { - mut_state.anim_phase = AnimPhase::Shown; + AnimPhase::Show => if !mut_state.alpha.show(0.3) { + mut_state.anim_phase = AnimPhase::Shown; - Some(500) - } else { - None - } - } - AnimPhase::NoFocus => None, + Some(500) + } else { + None + }, + AnimPhase::NoFocus => None, AnimPhase::Busy => None, }; @@ -251,10 +281,9 @@ fn anim_step (state: &Arc>>) -> } else { glib::Continue(true) } - } -impl Drop for Cursor { +impl Drop for BlinkCursor { fn drop(&mut self) { if let Some(timer_id) = self.state.borrow_mut().timer.take() { glib::source_remove(timer_id); diff --git a/src/render/context.rs b/src/render/context.rs index f8d6ba8..fbbb9eb 100644 --- a/src/render/context.rs +++ b/src/render/context.rs @@ -14,7 +14,9 @@ pub struct Context { impl Context { 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) { @@ -84,20 +86,18 @@ pub struct CellMetrics { impl CellMetrics { fn new(font_metrics: &pango::FontMetrics) -> Self { - CellMetrics { pango_ascent: font_metrics.get_ascent(), pango_descent: font_metrics.get_descent(), pango_char_width: font_metrics.get_approximate_digit_width(), ascent: font_metrics.get_ascent() as f64 / pango::SCALE as f64, - line_height: (font_metrics.get_ascent() + font_metrics.get_descent()) as f64 / - pango::SCALE as f64, + line_height: (font_metrics.get_ascent() + font_metrics.get_descent()) 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() - - font_metrics.get_underline_position()) as - f64 / pango::SCALE as f64, - underline_thickness: font_metrics.get_underline_thickness() as f64 / - pango::SCALE as f64, + underline_position: (font_metrics.get_ascent() - font_metrics.get_underline_position()) + as f64 / pango::SCALE as f64, + underline_thickness: font_metrics.get_underline_thickness() as f64 + / pango::SCALE as f64, } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 823f517..0f4f996 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -4,7 +4,7 @@ mod model_clip_iterator; pub use self::context::Context; pub use self::context::CellMetrics; -use self::model_clip_iterator::{RowView, ModelClipIteratorFactory}; +use self::model_clip_iterator::{ModelClipIteratorFactory, RowView}; use mode; use color; @@ -14,24 +14,26 @@ use pango; use cairo; use pangocairo; -use cursor; +use cursor::Cursor; use ui_model; -pub fn render( - ctx: &cairo::Context, - cursor: &cursor::Cursor, - font_ctx: &context::Context, - ui_model: &ui_model::UiModel, - color_model: &color::ColorModel, - mode: &mode::Mode, -) { +pub fn clear(ctx: &cairo::Context, color_model: &color::ColorModel) { ctx.set_source_rgb( color_model.bg_color.0, color_model.bg_color.1, color_model.bg_color.2, ); ctx.paint(); +} +pub fn render( + 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 &CellMetrics { char_width, .. } = cell_metrics; let (cursor_row, cursor_col) = ui_model.get_cursor(); @@ -47,19 +49,19 @@ pub fn render( for cell_view in ui_model.get_clip_iterator(ctx, cell_metrics) { 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() { - draw_cell(&cell_view, color_model, cell, col, line_x); draw_underline(&cell_view, color_model, cell, line_x); if row == cursor_row && col == cursor_col { - let double_width = line.line.get(col + 1).map_or( - false, - |c| c.attrs.double_width, - ); + let double_width = line.line + .get(col + 1) + .map_or(false, |c| c.attrs.double_width); ctx.move_to(line_x, line_y); cursor.draw( ctx, @@ -82,19 +84,18 @@ fn draw_underline( 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_metrics: + &CellMetrics { + line_height, + char_width, + underline_position, + underline_thickness, + .. + }, .. } = cell_view; @@ -106,7 +107,13 @@ fn draw_underline( let undercurl_height = (underline_thickness * 4.0).min(max_undercurl_height); 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 { let fg = color_model.actual_cell_fg(cell); ctx.set_source_rgb(fg.0, fg.1, fg.2); @@ -129,11 +136,12 @@ fn draw_cell_bg( ctx, line, line_y, - cell_metrics: &CellMetrics { - char_width, - line_height, - .. - }, + cell_metrics: + &CellMetrics { + char_width, + line_height, + .. + }, .. } = cell_view; @@ -157,7 +165,6 @@ fn draw_cell_bg( ctx.fill(); } } - } fn draw_cell( @@ -167,15 +174,11 @@ fn draw_cell( col: usize, line_x: f64, ) { - let &RowView { ctx, line, line_y, - cell_metrics: &CellMetrics { - ascent, - .. - }, + cell_metrics: &CellMetrics { ascent, .. }, .. } = cell_view; @@ -188,7 +191,6 @@ fn draw_cell( show_glyph_string(ctx, item.font(), glyphs); } - } } diff --git a/src/shell.rs b/src/shell.rs index 5bdab2c..74f0de5 100644 --- a/src/shell.rs +++ b/src/shell.rs @@ -26,7 +26,7 @@ use nvim::{self, RedrawEvents, GuiApi, RepaintMode, ErrorReport, NeovimClient, NeovimRef, NeovimClientAsync, CompleteItem}; use input; use input::keyval_to_input_string; -use cursor::{Cursor, CursorRedrawCb}; +use cursor::{BlinkCursor, Cursor, CursorRedrawCb}; use ui::UiMutex; use popup_menu::{self, PopupMenu}; use tabline::Tabline; @@ -94,7 +94,7 @@ pub struct State { cur_attrs: Option, mouse_enabled: bool, nvim: Rc, - cursor: Option>, + cursor: Option>, popup_menu: PopupMenu, cmd_line: CmdLine, settings: Rc>, @@ -449,7 +449,7 @@ impl Shell { }; 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 } @@ -807,6 +807,7 @@ fn gtk_draw(state_arc: &Arc>, ctx: &cairo::Context) -> Inhibit { let state = state_arc.borrow(); if state.nvim.is_initialized() { let render_state = state.render_state.borrow(); + render::clear(ctx, &render_state.color_model); render::render( ctx, state.cursor.as_ref().unwrap(),