diff options
author | Jesse Duffield <jessedduffield@gmail.com> | 2022-04-16 15:27:56 +1000 |
---|---|---|
committer | Jesse Duffield <jessedduffield@gmail.com> | 2022-04-16 17:29:17 +1000 |
commit | e68093fe9974296fe5afb22ec8e0adb1eb2f4316 (patch) | |
tree | 040dbfdb4dc438271d9f3febae410d25698f1a38 /vendor | |
parent | b838b74801102b27782cc20c7396279630e77fba (diff) |
add scrollbars
Diffstat (limited to 'vendor')
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/gui.go | 110 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/scrollbar.go | 33 | ||||
-rw-r--r-- | vendor/github.com/jesseduffield/gocui/view.go | 69 | ||||
-rw-r--r-- | vendor/modules.txt | 2 |
4 files changed, 180 insertions, 34 deletions
diff --git a/vendor/github.com/jesseduffield/gocui/gui.go b/vendor/github.com/jesseduffield/gocui/gui.go index ba8d93ce2..58e396492 100644 --- a/vendor/github.com/jesseduffield/gocui/gui.go +++ b/vendor/github.com/jesseduffield/gocui/gui.go @@ -743,6 +743,8 @@ func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error { } } } + + showScrollbar, realScrollbarStart, realScrollbarEnd := calcRealScrollbarStartEnd(v) for y := v.y0 + 1; y < v.y1 && y < g.maxY; y++ { if y < 0 { continue @@ -753,7 +755,9 @@ func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error { } } if v.x1 > -1 && v.x1 < g.maxX { - if err := g.SetRune(v.x1, y, runeV, fgColor, bgColor); err != nil { + runeToPrint := calcScrollbarRune(showScrollbar, realScrollbarStart, realScrollbarEnd, v.y0+1, v.y1-1, y, runeV) + + if err := g.SetRune(v.x1, y, runeToPrint, fgColor, bgColor); err != nil { return err } } @@ -761,6 +765,44 @@ func (g *Gui) drawFrameEdges(v *View, fgColor, bgColor Attribute) error { return nil } +func calcScrollbarRune(showScrollbar bool, scrollbarStart int, scrollbarEnd int, rangeStart int, rangeEnd int, position int, runeV rune) rune { + if !showScrollbar { + return runeV + } else if position == rangeStart { + return '▲' + } else if position == rangeEnd { + return '▼' + } else if position > scrollbarStart && position < scrollbarEnd { + return '█' + } else if position > rangeStart && position < rangeEnd { + // keeping this as a separate branch in case we later want to render something different here. + return runeV + } else { + return runeV + } +} + +func calcRealScrollbarStartEnd(v *View) (bool, int, int) { + height := v.InnerHeight() + 1 + fullHeight := v.ViewLinesHeight() - v.scrollMargin() + + if v.CanScrollPastBottom { + fullHeight += height + } + + if height < 2 || height >= fullHeight { + return false, 0, 0 + } + + originY := v.OriginY() + scrollbarStart, scrollbarHeight := calcScrollbar(fullHeight, height, originY, height-1) + top := v.y0 + 1 + realScrollbarStart := top + scrollbarStart + realScrollbarEnd := realScrollbarStart + scrollbarHeight + + return true, realScrollbarStart, realScrollbarEnd +} + func cornerRune(index byte) rune { return []rune{' ', '│', '│', '│', '─', '┘', '┐', '┤', '─', '└', '┌', '├', '├', '┴', '┬', '┼'}[index] } @@ -1014,6 +1056,40 @@ func (g *Gui) draw(v *View) error { if !v.Visible || v.y1 < v.y0 { return nil } + + if g.Cursor { + if curview := g.currentView; curview != nil { + vMaxX, vMaxY := curview.Size() + if curview.cx < 0 { + curview.cx = 0 + } else if curview.cx >= vMaxX { + curview.cx = vMaxX - 1 + } + if curview.cy < 0 { + curview.cy = 0 + } else if curview.cy >= vMaxY { + curview.cy = vMaxY - 1 + } + + gMaxX, gMaxY := g.Size() + cx, cy := curview.x0+curview.cx+1, curview.y0+curview.cy+1 + // This test probably doesn't need to be here. + // tcell is hiding cursor by setting coordinates outside of screen. + // Keeping it here for now, as I'm not 100% sure :) + if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY { + Screen.ShowCursor(cx, cy) + } else { + Screen.HideCursor() + } + } + } else { + Screen.HideCursor() + } + + if err := v.draw(); err != nil { + return err + } + if v.Frame { var fgColor, bgColor, frameColor Attribute if g.Highlight && v == g.currentView { @@ -1057,38 +1133,6 @@ func (g *Gui) draw(v *View) error { } } - if g.Cursor { - if curview := g.currentView; curview != nil { - vMaxX, vMaxY := curview.Size() - if curview.cx < 0 { - curview.cx = 0 - } else if curview.cx >= vMaxX { - curview.cx = vMaxX - 1 - } - if curview.cy < 0 { - curview.cy = 0 - } else if curview.cy >= vMaxY { - curview.cy = vMaxY - 1 - } - - gMaxX, gMaxY := g.Size() - cx, cy := curview.x0+curview.cx+1, curview.y0+curview.cy+1 - // This test probably doesn't need to be here. - // tcell is hiding cursor by setting coordinates outside of screen. - // Keeping it here for now, as I'm not 100% sure :) - if cx >= 0 && cx < gMaxX && cy >= 0 && cy < gMaxY { - Screen.ShowCursor(cx, cy) - } else { - Screen.HideCursor() - } - } - } else { - Screen.HideCursor() - } - - if err := v.draw(); err != nil { - return err - } return nil } diff --git a/vendor/github.com/jesseduffield/gocui/scrollbar.go b/vendor/github.com/jesseduffield/gocui/scrollbar.go new file mode 100644 index 000000000..3bdb4a45c --- /dev/null +++ b/vendor/github.com/jesseduffield/gocui/scrollbar.go @@ -0,0 +1,33 @@ +package gocui + +import "math" + +// returns start and height of scrollbar +// `max` is the maximum possible value of `position` +func calcScrollbar(listSize int, pageSize int, position int, scrollAreaSize int) (int, int) { + height := calcScrollbarHeight(listSize, pageSize, scrollAreaSize) + // assume we can't scroll past the last item + maxPosition := listSize - pageSize + if maxPosition <= 0 { + return 0, height + } + if position == maxPosition { + return scrollAreaSize - height, height + } + // we only want to show the scrollbar at the top or bottom positions if we're at the end. Hence the .Ceil (for moving the scrollbar once we scroll down) and the -1 (for pretending there's a smaller range than we actually have, with the above condition ensuring we snap to the bottom once we're at the end of the list) + start := int(math.Ceil(((float64(position) / float64(maxPosition)) * float64(scrollAreaSize-height-1)))) + return start, height +} + +func calcScrollbarHeight(listSize int, pageSize int, scrollAreaSize int) int { + if pageSize >= listSize { + return scrollAreaSize + } + height := int((float64(pageSize) / float64(listSize)) * float64(scrollAreaSize)) + minHeight := 2 + if height < minHeight { + return minHeight + } + + return height +} diff --git a/vendor/github.com/jesseduffield/gocui/view.go b/vendor/github.com/jesseduffield/gocui/view.go index d2c2b75f1..8051cce72 100644 --- a/vendor/github.com/jesseduffield/gocui/view.go +++ b/vendor/github.com/jesseduffield/gocui/view.go @@ -158,6 +158,9 @@ type View struct { // something like '1 of 20' for a list view Footer string + + // if true, the user can scroll all the way past the last item until it appears at the top of the view + CanScrollPastBottom bool } // call this in the event of a view resize, or if you want to render new content @@ -1287,3 +1290,69 @@ func (v *View) OverwriteLines(y int, content string) { lines := strings.Replace(content, "\n", "\x1b[K\n", -1) v.writeString(lines) } + +func (v *View) ScrollUp(amount int) { + newOy := v.oy - amount + if newOy < 0 { + newOy = 0 + } + v.oy = newOy +} + +// ensures we don't scroll past the end of the view's content +func (v *View) ScrollDown(amount int) { + adjustedAmount := v.adjustDownwardScrollAmount(amount) + if adjustedAmount > 0 { + v.oy += adjustedAmount + } +} + +func (v *View) ScrollLeft(amount int) { + newOx := v.ox - amount + if newOx < 0 { + newOx = 0 + } + v.ox = newOx +} + +// not applying any limits to this +func (v *View) ScrollRight(amount int) { + v.ox += amount +} + +func (v *View) adjustDownwardScrollAmount(scrollHeight int) int { + _, oy := v.Origin() + y := oy + if !v.CanScrollPastBottom { + _, sy := v.Size() + y += sy + } + scrollableLines := v.ViewLinesHeight() - y + if scrollableLines < 0 { + return 0 + } + + margin := v.scrollMargin() + if scrollableLines-margin < scrollHeight { + scrollHeight = scrollableLines - margin + } + if oy+scrollHeight < 0 { + return 0 + } else { + return scrollHeight + } +} + +// scrollMargin is about how many lines must still appear if you scroll +// all the way down. We'll subtract this from the total amount of scrollable lines +func (v *View) scrollMargin() int { + if v.CanScrollPastBottom { + // Setting to 2 because of the newline at the end of the file that we're likely showing. + // If we want to scroll past bottom outside the context of reading a file's contents, + // we should make this into a field on the view to be configured by the client. + // For now we're hardcoding it. + return 2 + } else { + return 0 + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index a7f378b45..68bceb9b0 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -169,7 +169,7 @@ github.com/jesseduffield/go-git/v5/utils/merkletrie/filesystem github.com/jesseduffield/go-git/v5/utils/merkletrie/index github.com/jesseduffield/go-git/v5/utils/merkletrie/internal/frame github.com/jesseduffield/go-git/v5/utils/merkletrie/noder -# github.com/jesseduffield/gocui v0.3.1-0.20220415005542-2eb424ce3d0a +# github.com/jesseduffield/gocui v0.3.1-0.20220416053910-5b19e175bc67 ## explicit; go 1.12 github.com/jesseduffield/gocui # github.com/jesseduffield/minimal/gitignore v0.3.3-0.20211018110810-9cde264e6b1e |