From 6114f69ee5ef38d0adac4a0d2fc1294e7ec19083 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sun, 18 Aug 2024 20:51:38 +0200 Subject: [PATCH] Scroll views up if needed to show all their content There are many situations where this can arise. Some examples are: - the terminal window is small, and you are showing a view that shows more content than fits into the view port, and the view is scrolled all the way down; now you resize the terminal window to a taller size. Previously, the scroll position of the view would stay the same, so it would add blank space at the bottom; now it will scroll to fill that blank space with content - expandFocusedSidePanel is on, you go to the bottom of a list view, now switch to a different panel, then scroll that (now unfocused) panel all the way down with the scroll wheel; now you focus that panel again. It becomes larger because of the accordion behavior, but would show blank space at the bottom. And probably others that I can't remember right now. I only remember that I always found it confusing to look at a view that had blank space at the bottom even though it had more content to scroll into view. --- pkg/gui/context/base_context.go | 4 ++++ pkg/gui/context/list_context_trait.go | 8 ++++++++ pkg/gui/layout.go | 13 +++++++++++++ pkg/gui/types/context.go | 3 +++ 4 files changed, 28 insertions(+) diff --git a/pkg/gui/context/base_context.go b/pkg/gui/context/base_context.go index ca04a2fa9..2fd37bb9a 100644 --- a/pkg/gui/context/base_context.go +++ b/pkg/gui/context/base_context.go @@ -212,3 +212,7 @@ func (self *BaseContext) NeedsRerenderOnHeightChange() bool { func (self *BaseContext) Title() string { return "" } + +func (self *BaseContext) TotalContentHeight() int { + return self.view.ViewLinesHeight() +} diff --git a/pkg/gui/context/list_context_trait.go b/pkg/gui/context/list_context_trait.go index 773f946a9..bce3ae344 100644 --- a/pkg/gui/context/list_context_trait.go +++ b/pkg/gui/context/list_context_trait.go @@ -140,3 +140,11 @@ func (self *ListContextTrait) RangeSelectEnabled() bool { func (self *ListContextTrait) RenderOnlyVisibleLines() bool { return self.renderOnlyVisibleLines } + +func (self *ListContextTrait) TotalContentHeight() int { + result := self.list.Len() + if self.getNonModelItems != nil { + result += len(self.getNonModelItems()) + } + return result +} diff --git a/pkg/gui/layout.go b/pkg/gui/layout.go index 62c2233dd..03cd07b60 100644 --- a/pkg/gui/layout.go +++ b/pkg/gui/layout.go @@ -73,6 +73,19 @@ func (gui *Gui) layout(g *gocui.Gui) error { } mustRerender := false + newHeight := dimensionsObj.Y1 - dimensionsObj.Y0 + 2*frameOffset + maxOriginY := context.TotalContentHeight() + if !view.CanScrollPastBottom { + maxOriginY -= newHeight - 1 + } + if oldOriginY := view.OriginY(); oldOriginY > maxOriginY { + view.ScrollUp(oldOriginY - maxOriginY) + // the view might not have scrolled actually (if it was at the limit + // already), so we need to check if it did + if oldOriginY != view.OriginY() && context.NeedsRerenderOnHeightChange() { + mustRerender = true + } + } if context.NeedsRerenderOnWidthChange() == types.NEEDS_RERENDER_ON_WIDTH_CHANGE_WHEN_WIDTH_CHANGES { // view.Width() returns the width -1 for some reason oldWidth := view.Width() + 1 diff --git a/pkg/gui/types/context.go b/pkg/gui/types/context.go index 2948f2eda..f48a6b595 100644 --- a/pkg/gui/types/context.go +++ b/pkg/gui/types/context.go @@ -71,6 +71,9 @@ type IBaseContext interface { // determined independently. HasControlledBounds() bool + // the total height of the content that the view is currently showing + TotalContentHeight() int + // to what extent the view needs to be rerendered when its width changes NeedsRerenderOnWidthChange() NeedsRerenderOnWidthChangeLevel