Fix cursor appearing on rerender when at bottom
When sitting at the bottom of a room with cursor = Cursor::Bottom, a rerender would make the cursor jump to the lowest visible message. This of course should only happen when the screen is scrolled, not on almost every rerender.
This commit is contained in:
parent
7988daf34d
commit
816bf5be1c
3 changed files with 38 additions and 30 deletions
|
|
@ -24,6 +24,11 @@ use super::ChatMsg;
|
||||||
// State //
|
// State //
|
||||||
///////////
|
///////////
|
||||||
|
|
||||||
|
enum Correction {
|
||||||
|
MakeCursorVisible,
|
||||||
|
MoveCursorToVisibleArea,
|
||||||
|
}
|
||||||
|
|
||||||
struct InnerTreeViewState<M: Msg, S: MsgStore<M>> {
|
struct InnerTreeViewState<M: Msg, S: MsgStore<M>> {
|
||||||
store: S,
|
store: S,
|
||||||
|
|
||||||
|
|
@ -31,14 +36,11 @@ struct InnerTreeViewState<M: Msg, S: MsgStore<M>> {
|
||||||
last_cursor_line: i32,
|
last_cursor_line: i32,
|
||||||
|
|
||||||
cursor: Cursor<M::Id>,
|
cursor: Cursor<M::Id>,
|
||||||
/// Set to true if the chat should be scrolled such that the cursor is fully
|
|
||||||
/// visible (if possible). If set to false, then the cursor itself is moved
|
|
||||||
/// to a different message such that it remains visible.
|
|
||||||
make_cursor_visible: bool,
|
|
||||||
|
|
||||||
/// Scroll the view on the next render. Positive values scroll up and
|
/// Scroll the view on the next render. Positive values scroll up and
|
||||||
/// negative values scroll down.
|
/// negative values scroll down.
|
||||||
scroll: i32,
|
scroll: i32,
|
||||||
|
correction: Option<Correction>,
|
||||||
|
|
||||||
editor: EditorState,
|
editor: EditorState,
|
||||||
}
|
}
|
||||||
|
|
@ -50,8 +52,8 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
last_cursor: Cursor::Bottom,
|
last_cursor: Cursor::Bottom,
|
||||||
last_cursor_line: 0,
|
last_cursor_line: 0,
|
||||||
cursor: Cursor::Bottom,
|
cursor: Cursor::Bottom,
|
||||||
make_cursor_visible: false,
|
|
||||||
scroll: 0,
|
scroll: 0,
|
||||||
|
correction: None,
|
||||||
editor: EditorState::new(),
|
editor: EditorState::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
use crate::store::{Msg, MsgStore, Tree};
|
use crate::store::{Msg, MsgStore, Tree};
|
||||||
|
|
||||||
use super::InnerTreeViewState;
|
use super::{Correction, InnerTreeViewState};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Cursor<I> {
|
pub enum Cursor<I> {
|
||||||
|
|
@ -177,7 +177,7 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
self.cursor = Cursor::Msg(id);
|
self.cursor = Cursor::Msg(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.make_cursor_visible = true;
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn move_cursor_down(&mut self) {
|
pub async fn move_cursor_down(&mut self) {
|
||||||
|
|
@ -208,28 +208,30 @@ impl<M: Msg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
self.make_cursor_visible = true;
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn move_cursor_to_top(&mut self) {
|
pub async fn move_cursor_to_top(&mut self) {
|
||||||
if let Some(first_tree_id) = self.store.first_tree_id().await {
|
if let Some(first_tree_id) = self.store.first_tree_id().await {
|
||||||
self.cursor = Cursor::Msg(first_tree_id);
|
self.cursor = Cursor::Msg(first_tree_id);
|
||||||
self.make_cursor_visible = true;
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn move_cursor_to_bottom(&mut self) {
|
pub async fn move_cursor_to_bottom(&mut self) {
|
||||||
self.cursor = Cursor::Bottom;
|
self.cursor = Cursor::Bottom;
|
||||||
// Not really necessary; only here for consistency with other methods
|
// Not really necessary; only here for consistency with other methods
|
||||||
self.make_cursor_visible = true;
|
self.correction = Some(Correction::MakeCursorVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_up(&mut self, amount: i32) {
|
pub fn scroll_up(&mut self, amount: i32) {
|
||||||
self.scroll += amount;
|
self.scroll += amount;
|
||||||
|
self.correction = Some(Correction::MoveCursorToVisibleArea);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn scroll_down(&mut self, amount: i32) {
|
pub fn scroll_down(&mut self, amount: i32) {
|
||||||
self.scroll -= amount;
|
self.scroll -= amount;
|
||||||
|
self.correction = Some(Correction::MoveCursorToVisibleArea);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::ui::widgets::text::Text;
|
||||||
use crate::ui::ChatMsg;
|
use crate::ui::ChatMsg;
|
||||||
|
|
||||||
use super::tree_blocks::{BlockId, Root, TreeBlocks};
|
use super::tree_blocks::{BlockId, Root, TreeBlocks};
|
||||||
use super::{widgets, Cursor, InnerTreeViewState};
|
use super::{widgets, Correction, Cursor, InnerTreeViewState};
|
||||||
|
|
||||||
impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Path<M::Id> {
|
async fn cursor_path(&self, cursor: &Cursor<M::Id>) -> Path<M::Id> {
|
||||||
|
|
@ -410,11 +410,13 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.make_cursor_visible {
|
match self.correction {
|
||||||
|
Some(Correction::MakeCursorVisible) => {
|
||||||
self.scroll_so_cursor_is_visible(frame, &mut blocks);
|
self.scroll_so_cursor_is_visible(frame, &mut blocks);
|
||||||
self.fill_screen_and_clamp_scrolling(frame, &mut blocks)
|
self.fill_screen_and_clamp_scrolling(frame, &mut blocks)
|
||||||
.await;
|
.await;
|
||||||
} else {
|
}
|
||||||
|
Some(Correction::MoveCursorToVisibleArea) => {
|
||||||
let new_cursor_msg_id = self.move_cursor_so_it_is_visible(frame, &blocks);
|
let new_cursor_msg_id = self.move_cursor_so_it_is_visible(frame, &blocks);
|
||||||
if let Some(cursor_msg_id) = new_cursor_msg_id {
|
if let Some(cursor_msg_id) = new_cursor_msg_id {
|
||||||
// Moving the cursor invalidates our current blocks, so we sadly
|
// Moving the cursor invalidates our current blocks, so we sadly
|
||||||
|
|
@ -423,8 +425,8 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
|
|
||||||
self.last_cursor = self.cursor.clone();
|
self.last_cursor = self.cursor.clone();
|
||||||
self.last_cursor_line = self.cursor_line(&blocks);
|
self.last_cursor_line = self.cursor_line(&blocks);
|
||||||
self.make_cursor_visible = false;
|
|
||||||
self.scroll = 0;
|
self.scroll = 0;
|
||||||
|
self.correction = None;
|
||||||
|
|
||||||
let last_cursor_path = self.store.path(&cursor_msg_id).await;
|
let last_cursor_path = self.store.path(&cursor_msg_id).await;
|
||||||
blocks = self.layout_last_cursor_seed(frame, &last_cursor_path).await;
|
blocks = self.layout_last_cursor_seed(frame, &last_cursor_path).await;
|
||||||
|
|
@ -432,11 +434,13 @@ impl<M: Msg + ChatMsg, S: MsgStore<M>> InnerTreeViewState<M, S> {
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
|
||||||
self.last_cursor = self.cursor.clone();
|
self.last_cursor = self.cursor.clone();
|
||||||
self.last_cursor_line = self.cursor_line(&blocks);
|
self.last_cursor_line = self.cursor_line(&blocks);
|
||||||
self.make_cursor_visible = false;
|
|
||||||
self.scroll = 0;
|
self.scroll = 0;
|
||||||
|
self.correction = None;
|
||||||
|
|
||||||
blocks
|
blocks
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue