From aeed4260343c076e2d3eae83f462f9633e78d889 Mon Sep 17 00:00:00 2001 From: Miguel Mota Date: Sun, 21 Feb 2021 23:13:39 -0800 Subject: [PATCH] Table scroll fix --- cointop/favorites.go | 5 +++ cointop/navigation.go | 82 ++++++++++++++++++++++++++++++------------- cointop/portfolio.go | 12 +++---- cointop/table.go | 32 ++++++++++------- pkg/ui/view.go | 20 +++++++++-- 5 files changed, 105 insertions(+), 46 deletions(-) diff --git a/cointop/favorites.go b/cointop/favorites.go index 7ff5172..be5d5f2 100644 --- a/cointop/favorites.go +++ b/cointop/favorites.go @@ -77,3 +77,8 @@ func (ct *Cointop) GetFavoritesSlice() []*Coin { func (ct *Cointop) IsFavoritesVisible() bool { return ct.State.selectedView == FavoritesView } + +// FavoritesLen returns the number of favorite coins +func (ct *Cointop) FavoritesLen() int { + return len(ct.GetFavoritesSlice()) +} diff --git a/cointop/navigation.go b/cointop/navigation.go index 92db9a1..b2a3cc4 100644 --- a/cointop/navigation.go +++ b/cointop/navigation.go @@ -52,8 +52,13 @@ func (ct *Cointop) CursorDown() error { } cx, cy := ct.Views.Table.Cursor() - if err := ct.Views.Table.SetCursor(cx, cy+1); err != nil { - ox, oy := ct.Views.Table.Origin() + y := cy + 1 + if err := ct.Views.Table.SetCursor(cx, y); err != nil { + return err + } + ox, oy := ct.Views.Table.Origin() + h := ct.Views.Table.Height() + if y < 0 || y >= h { // set origin scrolls if err := ct.Views.Table.SetOrigin(ox, oy+1); err != nil { return err @@ -73,8 +78,12 @@ func (ct *Cointop) CursorUp() error { ox, oy := ct.Views.Table.Origin() cx, cy := ct.Views.Table.Cursor() - - if err := ct.Views.Table.SetCursor(cx, cy-1); err != nil && oy > 0 { + y := cy - 1 + if err := ct.Views.Table.SetCursor(cx, y); err != nil { + return err + } + h := ct.Views.Table.Height() + if y < 0 || y >= h { // set origin scrolls if err := ct.Views.Table.SetOrigin(ox, oy-1); err != nil { return err @@ -180,16 +189,21 @@ func (ct *Cointop) NavigateLastLine() error { ox := ct.Views.Table.OriginX() cx := ct.Views.Table.CursorX() - sy := ct.Views.Table.Height() l := ct.TableRowsLen() - k := l - sy - if err := ct.Views.Table.SetOrigin(ox, k); err != nil { + h := ct.Views.Table.Height() + h = int(math.Min(float64(h), float64(l))) + k := l - h + if k < 0 { + k = l + } + y := h - 1 + if err := ct.Views.Table.SetCursor(cx, y); err != nil { return err } - if err := ct.Views.Table.SetCursor(cx, sy-1); err != nil { + // set origin scrolls + if err := ct.Views.Table.SetOrigin(ox, k); err != nil { return err } - ct.RowChanged() return nil } @@ -329,7 +343,6 @@ func (ct *Cointop) IsFirstRow() bool { ct.debuglog("isFirstRow()") oy := ct.Views.Table.OriginY() cy := ct.Views.Table.CursorY() - return (cy + oy) == 0 } @@ -339,7 +352,6 @@ func (ct *Cointop) IsLastRow() bool { oy := ct.Views.Table.OriginY() cy := ct.Views.Table.CursorY() numRows := ct.TableRowsLen() - 1 - return (cy + oy + 1) > numRows } @@ -383,6 +395,9 @@ func (ct *Cointop) IsPageLastLine() bool { // GoToPageRowIndex navigates to the selected row index of the page func (ct *Cointop) GoToPageRowIndex(idx int) error { ct.debuglog("goToPageRowIndex()") + if idx < 0 { + idx = 0 + } cx := ct.Views.Table.CursorX() if err := ct.Views.Table.SetCursor(cx, idx); err != nil { return err @@ -394,10 +409,10 @@ func (ct *Cointop) GoToPageRowIndex(idx int) error { // GoToGlobalIndex navigates to the selected row index of all page rows func (ct *Cointop) GoToGlobalIndex(idx int) error { ct.debuglog("goToGlobalIndex()") - perpage := ct.TotalPerPage() - atpage := idx / perpage + l := ct.TableRowsLen() + atpage := idx / l ct.SetPage(atpage) - rowIndex := (idx % perpage) + rowIndex := (idx % l) ct.HighlightRow(rowIndex) ct.UpdateTable() return nil @@ -405,29 +420,30 @@ func (ct *Cointop) GoToGlobalIndex(idx int) error { // HighlightRow highlights the row at index within page func (ct *Cointop) HighlightRow(pageRowIndex int) error { + if pageRowIndex < 0 { + pageRowIndex = 0 + } ct.debuglog("highlightRow()") ct.Views.Table.SetOrigin(0, 0) ct.Views.Table.SetCursor(0, 0) ox := ct.Views.Table.OriginX() cx := ct.Views.Table.CursorX() + l := ct.TableRowsLen() h := ct.Views.Table.Height() - perpage := ct.TotalPerPage() + h = int(math.Min(float64(h), float64(l))) oy := 0 cy := 0 if h > 0 { - _ = perpage cy = pageRowIndex % h oy = pageRowIndex - cy // end of page - if pageRowIndex >= perpage-h { - oy = perpage - h - cy = h - (perpage - pageRowIndex) + if pageRowIndex >= l-h { + oy = l - h + cy = h - (l - pageRowIndex) } } ct.debuglog(fmt.Sprintf("highlightRow idx:%v h:%v cy:%v oy:%v", pageRowIndex, h, cy, oy)) - if oy > 0 { - ct.Views.Table.SetOrigin(ox, oy) - } + ct.Views.Table.SetOrigin(ox, oy) ct.Views.Table.SetCursor(cx, cy) return nil } @@ -438,11 +454,11 @@ func (ct *Cointop) GoToCoinRow(coin *Coin) error { if coin == nil { return nil } - idx := ct.GetGlobalCoinIndex(coin) + idx := ct.GetCoinRowIndex(coin) return ct.GoToGlobalIndex(idx) } -// GetGlobalCoinIndex returns the index of the coin in from the coins list +// GetGlobalCoinIndex returns the index of the coin in from the gloal coins list func (ct *Cointop) GetGlobalCoinIndex(coin *Coin) int { var idx int for i, v := range ct.State.allCoins { @@ -454,6 +470,18 @@ func (ct *Cointop) GetGlobalCoinIndex(coin *Coin) int { return idx } +// GetCoinRowIndex returns the index of the coin in from the visible coins list +func (ct *Cointop) GetCoinRowIndex(coin *Coin) int { + var idx int + for i, v := range ct.State.coins { + if v == coin { + idx = i + break + } + } + return idx +} + // CursorDownOrNextPage moves the cursor down one row or goes to the next page if cursor is on the last row func (ct *Cointop) CursorDownOrNextPage() error { ct.debuglog("CursorDownOrNextPage()") @@ -552,6 +580,12 @@ func (ct *Cointop) MouseWheelDown() error { // TableRowsLen returns the number of table row entries func (ct *Cointop) TableRowsLen() int { ct.debuglog("TableRowsLen()") + if ct.IsFavoritesVisible() { + return ct.FavoritesLen() + } + if ct.IsPortfolioVisible() { + return ct.PortfolioLen() + } if ct.IsPriceAlertsVisible() { return ct.ActivePriceAlertsLen() } diff --git a/cointop/portfolio.go b/cointop/portfolio.go index 032af4c..4690b50 100644 --- a/cointop/portfolio.go +++ b/cointop/portfolio.go @@ -286,14 +286,7 @@ func (ct *Cointop) GetPortfolioTable() *table.Table { // TogglePortfolio toggles the portfolio view func (ct *Cointop) TogglePortfolio() error { ct.debuglog("togglePortfolio()") - if ct.IsPortfolioVisible() { - ct.GoToPageRowIndex(ct.State.lastSelectedRowIndex) - } else { - ct.State.lastSelectedRowIndex = ct.HighlightedPageRowIndex() - } - ct.ToggleSelectedView(PortfolioView) - go ct.UpdateChart() go ct.UpdateTable() return nil @@ -825,3 +818,8 @@ func (ct *Cointop) PrintTotalHoldings(options *TablePrintOptions) error { func (ct *Cointop) IsPortfolioVisible() bool { return ct.State.selectedView == PortfolioView } + +// PortfolioLen returns the number of portfolio entries +func (ct *Cointop) PortfolioLen() int { + return len(ct.GetPortfolioSlice()) +} diff --git a/cointop/table.go b/cointop/table.go index e3fa32b..248997c 100644 --- a/cointop/table.go +++ b/cointop/table.go @@ -2,6 +2,7 @@ package cointop import ( "fmt" + "math" "net/url" "strings" @@ -63,16 +64,6 @@ func (ct *Cointop) RefreshTable() error { } ct.table.HideColumHeaders = true - // highlight last row if current row is out of bounds (can happen when switching views). - // make sure to not highlight row when actively navigating, otherwise - // table will appear glitchy since this is method is async. - if ct.State.lastSelectedView != "" && ct.State.lastSelectedView != ct.State.selectedView { - currentRowIdx := ct.HighlightedRowIndex() - if len(ct.State.coins) > currentRowIdx { - ct.HighlightRow(currentRowIdx) - } - } - ct.UpdateUI(func() error { ct.Views.Table.Clear() if statusText == "" { @@ -171,12 +162,13 @@ func (ct *Cointop) HighlightedRowIndex() int { oy := ct.Views.Table.OriginY() cy := ct.Views.Table.CursorY() idx := oy + cy + l := ct.TableRowsLen() + if idx >= l { + idx = l - 1 + } if idx < 0 { idx = 0 } - if idx >= len(ct.State.coins) { - idx = len(ct.State.coins) - 1 - } return idx } @@ -273,9 +265,23 @@ func (ct *Cointop) SetSelectedView(viewName string) { // ToggleSelectedView toggles between current table view and last selected table view func (ct *Cointop) ToggleSelectedView(viewName string) { + if !(ct.IsPortfolioVisible() || ct.IsFavoritesVisible()) { + ct.State.lastSelectedRowIndex = ct.HighlightedPageRowIndex() + } if ct.State.lastSelectedView == "" || ct.State.selectedView != viewName { ct.SetSelectedView(viewName) } else { ct.SetSelectedView(ct.State.lastSelectedView) } + + l := ct.TableRowsLen() + if ct.IsPortfolioVisible() || ct.IsFavoritesVisible() { + // highlight last row if current row is out of bounds (can happen when switching views). + currentRowIdx := ct.HighlightedRowIndex() + if currentRowIdx >= l-1 { + ct.HighlightRow(l - 1) + } + } else { + ct.GoToPageRowIndex(int(math.Min(float64(l-1), float64(ct.State.lastSelectedRowIndex)))) + } } diff --git a/pkg/ui/view.go b/pkg/ui/view.go index 61fb426..6255aaa 100644 --- a/pkg/ui/view.go +++ b/pkg/ui/view.go @@ -41,10 +41,19 @@ func (view *View) HasBacking() bool { return view.backing != nil } +// Size returns the view size +func (view *View) Size() (int, int) { + if view.HasBacking() { + return view.backing.Size() + } + + return 0, 0 +} + // Height returns the view height func (view *View) Height() int { if view.HasBacking() { - _, h := view.backing.Size() + _, h := view.Size() return h } @@ -54,7 +63,7 @@ func (view *View) Height() int { // Width returns the view width func (view *View) Width() int { if view.HasBacking() { - w, _ := view.backing.Size() + w, _ := view.Size() return w } @@ -93,6 +102,10 @@ func (view *View) CursorY() int { // SetCursor sets the view's cursor func (view *View) SetCursor(x, y int) error { if view.HasBacking() { + maxX, maxY := view.Size() + if x < 0 || x >= maxX || y < 0 || y >= maxY { + return nil + } return view.backing.SetCursor(x, y) } @@ -131,6 +144,9 @@ func (view *View) OriginY() int { // SetOrigin sets the view's origin func (view *View) SetOrigin(x, y int) error { if view.HasBacking() { + if x < 0 || y < 0 { + return nil + } return view.backing.SetOrigin(x, y) }