From 15b72df1dabb6675c20cff043648e97a209d2132 Mon Sep 17 00:00:00 2001 From: Jeffas Date: Tue, 9 Jun 2020 20:13:13 +0100 Subject: [PATCH] Rework msglist scrolling This changes the scrolling to be done on the draw, when the height is updated, ensuring that the selected item is kept on screen during resizing. Also, this ensures that messages will fill the screen when resizing the window, for instance, shrinking and then growing drags down more messages if possible. This is a transplant of the dirlist scrolling logic. --- commands/account/next-result.go | 4 +-- commands/account/next.go | 4 +-- commands/account/search.go | 2 +- commands/msg/archive.go | 2 +- commands/msg/delete.go | 4 +-- commands/msg/move.go | 2 +- widgets/msglist.go | 46 ++++++++++++++++++++++----------- 7 files changed, 40 insertions(+), 24 deletions(-) diff --git a/commands/account/next-result.go b/commands/account/next-result.go index 78d437d..fe835ea 100644 --- a/commands/account/next-result.go +++ b/commands/account/next-result.go @@ -34,13 +34,13 @@ func (NextPrevResult) Execute(aerc *widgets.Aerc, args []string) error { if store != nil { store.PrevResult() } - acct.Messages().Scroll() + acct.Messages().Invalidate() } else { store := acct.Store() if store != nil { store.NextResult() } - acct.Messages().Scroll() + acct.Messages().Invalidate() } return nil } diff --git a/commands/account/next.go b/commands/account/next.go index 5e4838e..427f563 100644 --- a/commands/account/next.go +++ b/commands/account/next.go @@ -65,13 +65,13 @@ func ExecuteNextPrevMessage(args []string, acct *widgets.AccountView, pct bool, store := acct.Store() if store != nil { store.NextPrev(-n) - acct.Messages().Scroll() + acct.Messages().Invalidate() } } else { store := acct.Store() if store != nil { store.NextPrev(n) - acct.Messages().Scroll() + acct.Messages().Invalidate() } } return nil diff --git a/commands/account/search.go b/commands/account/search.go index 1d2e7a2..607dc24 100644 --- a/commands/account/search.go +++ b/commands/account/search.go @@ -45,7 +45,7 @@ func (SearchFilter) Execute(aerc *widgets.Aerc, args []string) error { acct.Logger().Printf("Search results: %v", uids) store.ApplySearch(uids) // TODO: Remove when stores have multiple OnUpdate handlers - acct.Messages().Scroll() + acct.Messages().Invalidate() } } store.Search(args, cb) diff --git a/commands/msg/archive.go b/commands/msg/archive.go index 5561674..07de13f 100644 --- a/commands/msg/archive.go +++ b/commands/msg/archive.go @@ -53,7 +53,7 @@ func (Archive) Execute(aerc *widgets.Aerc, args []string) error { } archiveDir := acct.AccountConfig().Archive store.Next() - acct.Messages().Scroll() + acct.Messages().Invalidate() var uidMap map[string][]uint32 switch args[1] { diff --git a/commands/msg/delete.go b/commands/msg/delete.go index 4bda8b9..e74bf10 100644 --- a/commands/msg/delete.go +++ b/commands/msg/delete.go @@ -62,7 +62,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error { // no more messages in the list if next == nil { aerc.RemoveTab(h.msgProvider) - acct.Messages().Scroll() + acct.Messages().Invalidate() return nil } lib.NewMessageStoreView(next, store, aerc.DecryptKeys, @@ -76,7 +76,7 @@ func (Delete) Execute(aerc *widgets.Aerc, args []string) error { }) } } - acct.Messages().Scroll() + acct.Messages().Invalidate() return nil } diff --git a/commands/msg/move.go b/commands/msg/move.go index 830e752..41f61da 100644 --- a/commands/msg/move.go +++ b/commands/msg/move.go @@ -62,7 +62,7 @@ func (Move) Execute(aerc *widgets.Aerc, args []string) error { aerc.RemoveTab(h.msgProvider) } store.Next() - acct.Messages().Scroll() + acct.Messages().Invalidate() joinedArgs := strings.Join(args[optind:], " ") store.Move(uids, joinedArgs, createParents, func( msg types.WorkerMessage) { diff --git a/widgets/msglist.go b/widgets/msglist.go index 5aedb44..38b6369 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -63,6 +63,8 @@ func (ml *MessageList) Draw(ctx *ui.Context) { } } + ml.ensureScroll() + var ( needsHeaders []uint32 row int = 0 @@ -179,12 +181,12 @@ func (ml *MessageList) MouseEvent(localX int, localY int, event tcell.Event) { if ml.store != nil { ml.store.Next() } - ml.Scroll() + ml.Invalidate() case tcell.WheelUp: if ml.store != nil { ml.store.Prev() } - ml.Scroll() + ml.Invalidate() } } } @@ -225,7 +227,6 @@ func (ml *MessageList) storeUpdate(store *lib.MessageStore) { ml.nmsgs = len(uids) } - ml.Scroll() ml.Invalidate() } @@ -266,25 +267,40 @@ func (ml *MessageList) Selected() *models.MessageInfo { func (ml *MessageList) Select(index int) { store := ml.Store() store.Select(index) - ml.Scroll() + ml.Invalidate() } -func (ml *MessageList) Scroll() { +func (ml *MessageList) ensureScroll() { store := ml.Store() - if store == nil || len(store.Uids()) == 0 { return } - if ml.Height() != 0 { - // I'm too lazy to do the math right now - for store.SelectedIndex()-ml.scroll >= ml.Height() { - ml.scroll += 1 - } - for store.SelectedIndex()-ml.scroll < 0 { - ml.scroll -= 1 - } + + h := ml.Height() + + maxScroll := len(store.Uids()) - h + if maxScroll < 0 { + maxScroll = 0 + } + + selectedIndex := store.SelectedIndex() + + if selectedIndex >= ml.scroll && selectedIndex < ml.scroll+h { + if ml.scroll > maxScroll { + ml.scroll = maxScroll + } + return + } + + if selectedIndex >= ml.scroll+h { + ml.scroll = selectedIndex - h + 1 + } else if selectedIndex < ml.scroll { + ml.scroll = selectedIndex + } + + if ml.scroll > maxScroll { + ml.scroll = maxScroll } - ml.Invalidate() } func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) {