From 2adccccd6b96c23a22d19c5bed8d17df681a4d4f Mon Sep 17 00:00:00 2001 From: Ville Hakulinen Date: Thu, 23 Jul 2020 12:49:51 +0300 Subject: Allow disabling the cursor movement animation --- runtime/autoload/gnvim/cursor.vim | 10 ++++++ runtime/doc/gnvim.txt | 3 ++ src/nvim_bridge/mod.rs | 8 +++++ src/ui/grid/context.rs | 10 +++++- src/ui/grid/cursor.rs | 76 ++++++++++++++++++++++++++------------- src/ui/grid/grid.rs | 15 +++++++- src/ui/state.rs | 14 ++++++++ src/ui/ui.rs | 2 ++ 8 files changed, 112 insertions(+), 26 deletions(-) create mode 100644 runtime/autoload/gnvim/cursor.vim diff --git a/runtime/autoload/gnvim/cursor.vim b/runtime/autoload/gnvim/cursor.vim new file mode 100644 index 0000000..caca879 --- /dev/null +++ b/runtime/autoload/gnvim/cursor.vim @@ -0,0 +1,10 @@ +command! -nargs=1 GnvimCursorEnableAnimations + \ call gnvim#cursor#enable_animations() + +function! gnvim#cursor#enable_animations(enable) + return rpcnotify( + \ g:gnvim_channel_id, + \ 'Gnvim', + \ 'EnableCursorAnimations', + \ a:enable == 1) +endfunction diff --git a/runtime/doc/gnvim.txt b/runtime/doc/gnvim.txt index 1e61859..2e524be 100644 --- a/runtime/doc/gnvim.txt +++ b/runtime/doc/gnvim.txt @@ -55,6 +55,9 @@ Gnvim's cursor can be set to blink with `guicursor`. Make cursor blink: `set guicursor+=a:blinkon333` Make cursor not to blink: `set guicursor+=a:blinkon0` +The cursor also has animated position movement, which is on by default. To +disable it, use `GnvimCursorEnableAnimations 0` . + ================================================================================ Commands *gnvim-commands* diff --git a/src/nvim_bridge/mod.rs b/src/nvim_bridge/mod.rs index 693d057..9a82571 100644 --- a/src/nvim_bridge/mod.rs +++ b/src/nvim_bridge/mod.rs @@ -976,6 +976,8 @@ pub enum GnvimEvent { PopupmenuWidthDetails(u64), PopupmenuShowMenuOnAllItems(bool), + EnableCursorAnimations(bool), + Unknown(String), } @@ -1261,6 +1263,12 @@ pub(crate) fn parse_gnvim_event( GnvimEvent::PopupmenuShowMenuOnAllItems(b != 0) } + "EnableCursorAnimations" => GnvimEvent::EnableCursorAnimations( + try_u64!( + args.get(1).ok_or("argument missing")?, + "failed to parse enable cursor animations argument" + ) == 1, + ), _ => GnvimEvent::Unknown(String::from(cmd)), }; diff --git a/src/ui/grid/context.rs b/src/ui/grid/context.rs index 9709ead..d62ab1e 100644 --- a/src/ui/grid/context.rs +++ b/src/ui/grid/context.rs @@ -45,6 +45,7 @@ impl Context { cols: usize, rows: usize, hl_defs: &HlDefs, + enable_cursor_animations: bool, ) -> Self { let pango_context = da.get_pango_context().unwrap(); @@ -89,13 +90,18 @@ impl Context { cairo::Context::new(&surface) }; + let cursor = Cursor { + disable_animation: !enable_cursor_animations, + ..Cursor::default() + }; + Context { cairo_context, cell_metrics, cell_metrics_update: None, rows: vec![], - cursor: Cursor::default(), + cursor, cursor_context, busy: false, @@ -282,6 +288,8 @@ impl Context { } pub fn cell_at_cursor(&self) -> Option<&Cell> { + // TODO(ville): In some (all?) cases we want to get animation's target position if it + // differs from the current position. self.cursor.pos.and_then(|pos| { self.rows .get(pos.0.ceil() as usize) diff --git a/src/ui/grid/cursor.rs b/src/ui/grid/cursor.rs index da1532b..3a3a5d4 100644 --- a/src/ui/grid/cursor.rs +++ b/src/ui/grid/cursor.rs @@ -1,7 +1,7 @@ use crate::ui::color::Color; #[derive(Default)] -struct Animation { +pub struct Animation { start: (f64, f64), end: (f64, f64), start_time: i64, @@ -12,7 +12,9 @@ struct Animation { pub struct Cursor { /// Position, (row, col). pub pos: Option<(f64, f64)>, - animation: Animation, + /// Flag for disabling the movement animation. + pub disable_animation: bool, + pub animation: Option, /// Alpha color. Used to make the cursor blink. pub alpha: f64, @@ -26,17 +28,24 @@ pub struct Cursor { impl Cursor { pub fn goto(&mut self, row: f64, col: f64, frame_time: i64) { + // When we get our first cursor_goto, set the position directly. if self.pos.is_none() { self.pos = Some((row, col)); } - let duration = 200; - self.animation = Animation { - start: self.pos.unwrap(), - end: (row, col), - start_time: frame_time, - end_time: frame_time + 1000 * duration, - }; + // If cursor animation is disabled, set the position directly. Otherwise, set the animation + // so that we can animate cursor position change. + if self.disable_animation { + self.pos = Some((row, col)); + } else { + let duration = 200; + self.animation = Some(Animation { + start: self.pos.unwrap(), + end: (row, col), + start_time: frame_time, + end_time: frame_time + 1000 * duration, + }); + } } pub fn tick(&mut self, frame_time: i64) { @@ -59,25 +68,27 @@ impl Cursor { } fn animate_position(&mut self, frame_time: i64) { - let Animation { + if let Some(Animation { start, end, start_time, end_time, - } = self.animation; - - let mut pos = self.pos.unwrap_or((0.0, 0.0)); - - if frame_time < end_time && pos != end { - let mut t = (frame_time - start_time) as f64 - / (end_time - start_time) as f64; - t = ease_out_cubic(t); - pos.0 = start.0 + t * (end.0 - start.0); - pos.1 = start.1 + t * (end.1 - start.1); - - self.pos = Some(pos); - } else if pos != end { - self.pos = Some(end); + }) = self.animation + { + let mut pos = self.pos.unwrap_or((0.0, 0.0)); + + if frame_time < end_time && pos != end { + let mut t = (frame_time - start_time) as f64 + / (end_time - start_time) as f64; + t = ease_out_cubic(t); + pos.0 = start.0 + t * (end.0 - start.0); + pos.1 = start.1 + t * (end.1 - start.1); + + self.pos = Some(pos); + } else { + self.pos = Some(end); + self.animation = None; + } } } } @@ -139,4 +150,21 @@ mod tests { cursor.tick(25000); assert_eq!(cursor.pos, Some((13.349666797203126, 13.349666797203126))); } + + #[test] + fn test_animate_position_animation_disabled() { + let mut cursor = Cursor::default(); + cursor.disable_animation = true; + + // When we first set the position, it should be set immediately. + cursor.goto(15.0, 15.0, 1); + assert_eq!(cursor.pos, Some((15.0, 15.0))); + + // Position animation is disabled, goto should change the position directly and tick + // shouldn't affect the position value at all. + cursor.goto(10.0, 10.0, 1); + assert_eq!(cursor.pos, Some((10.0, 10.0))); + cursor.tick(25000); + assert_eq!(cursor.pos, Some((10.0, 10.0))); + } } diff --git a/src/ui/grid/grid.rs b/src/ui/grid/grid.rs index 77939ca..f470467 100644 --- a/src/ui/grid/grid.rs +++ b/src/ui/grid/grid.rs @@ -89,10 +89,18 @@ impl Grid { cols: usize, rows: usize, hl_defs: &HlDefs, + enable_cursor_animations: bool, ) -> Self { let da = DrawingArea::new(); let ctx = Rc::new(RefCell::new(Context::new( - &da, win, font, line_space, cols, rows, hl_defs, + &da, + win, + font, + line_space, + cols, + rows, + hl_defs, + enable_cursor_animations, ))); da.connect_draw(clone!(ctx => move |_, cr| { @@ -461,6 +469,11 @@ impl Grid { ctx.busy = busy; } + + pub fn enable_cursor_animations(&self, enable: bool) { + let mut ctx = self.context.borrow_mut(); + ctx.cursor.disable_animation = !enable; + } } /// Handler for grid's drawingarea's draw event. Draws the internal cairo diff --git a/src/ui/state.rs b/src/ui/state.rs index dba0206..2374d4c 100644 --- a/src/ui/state.rs +++ b/src/ui/state.rs @@ -84,6 +84,8 @@ pub(crate) struct UIState { pub font: Font, pub line_space: i64, + + pub enable_cursor_animations: bool, } impl UIState { @@ -102,6 +104,7 @@ impl UIState { Notify::GnvimEvent(event) => match event { Ok(event) => self.handle_gnvim_event(&event, nvim), Err(err) => { + error!("Failed to parse notify: {}", err); let nvim = nvim.clone(); let msg = format!( "echom \"Failed to parse gnvim notify: '{}'\"", @@ -183,6 +186,7 @@ impl UIState { e.width as usize, e.height as usize, &self.hl_defs, + self.enable_cursor_animations, ); if let Some(ref mode) = self.current_mode { @@ -714,6 +718,13 @@ impl UIState { self.msg_window.set_pos(&grid, e.row as f64, h, e.scrolled); } + fn enable_cursor_animations(&mut self, enable: bool) { + self.enable_cursor_animations = enable; + self.grids + .values() + .for_each(|g| g.enable_cursor_animations(enable)); + } + fn handle_redraw_event( &mut self, window: >k::ApplicationWindow, @@ -830,6 +841,9 @@ impl UIState { GnvimEvent::PopupmenuShowMenuOnAllItems(should_show) => { self.popupmenu.set_show_menu_on_all_items(*should_show); } + GnvimEvent::EnableCursorAnimations(enable) => { + self.enable_cursor_animations(*enable); + } GnvimEvent::Unknown(msg) => { debug!("Received unknown GnvimEvent: {}", msg); } diff --git a/src/ui/ui.rs b/src/ui/ui.rs index bf79cbb..fcf4258 100644 --- a/src/ui/ui.rs +++ b/src/ui/ui.rs @@ -87,6 +87,7 @@ impl UI { 80, 30, &hl_defs, + true, ); // Mark the default grid as active at the beginning. grid.set_active(true); @@ -242,6 +243,7 @@ impl UI { font, line_space, current_mode: None, + enable_cursor_animations: true, })), nvim, } -- cgit v1.2.3