github.com/elves/elvish@v0.15.0/pkg/cli/scrollbar.go (about) 1 package cli 2 3 import ( 4 "github.com/elves/elvish/pkg/cli/term" 5 "github.com/elves/elvish/pkg/ui" 6 ) 7 8 // VScrollbarContainer is a Renderer consisting of content and a vertical 9 // scrollbar on the right. 10 type VScrollbarContainer struct { 11 Content Renderer 12 Scrollbar VScrollbar 13 } 14 15 func (v VScrollbarContainer) Render(width, height int) *term.Buffer { 16 buf := v.Content.Render(width-1, height) 17 buf.ExtendRight(v.Scrollbar.Render(1, height)) 18 return buf 19 } 20 21 // VScrollbar is a Renderer for a vertical scrollbar. 22 type VScrollbar struct { 23 Total int 24 Low int 25 High int 26 } 27 28 var ( 29 vscrollbarThumb = ui.T(" ", ui.FgMagenta, ui.Inverse) 30 vscrollbarTrough = ui.T("│", ui.FgMagenta) 31 ) 32 33 func (v VScrollbar) Render(width, height int) *term.Buffer { 34 posLow, posHigh := findScrollInterval(v.Total, v.Low, v.High, height) 35 bb := term.NewBufferBuilder(1) 36 for i := 0; i < height; i++ { 37 if i > 0 { 38 bb.Newline() 39 } 40 if posLow <= i && i < posHigh { 41 bb.WriteStyled(vscrollbarThumb) 42 } else { 43 bb.WriteStyled(vscrollbarTrough) 44 } 45 } 46 return bb.Buffer() 47 } 48 49 // HScrollbar is a Renderer for a horizontal scrollbar. 50 type HScrollbar struct { 51 Total int 52 Low int 53 High int 54 } 55 56 var ( 57 hscrollbarThumb = ui.T(" ", ui.FgMagenta, ui.Inverse) 58 hscrollbarTrough = ui.T("━", ui.FgMagenta) 59 ) 60 61 func (h HScrollbar) Render(width, height int) *term.Buffer { 62 posLow, posHigh := findScrollInterval(h.Total, h.Low, h.High, width) 63 bb := term.NewBufferBuilder(width) 64 for i := 0; i < width; i++ { 65 if posLow <= i && i < posHigh { 66 bb.WriteStyled(hscrollbarThumb) 67 } else { 68 bb.WriteStyled(hscrollbarTrough) 69 } 70 } 71 return bb.Buffer() 72 } 73 74 func findScrollInterval(n, low, high, height int) (int, int) { 75 f := func(i int) int { 76 return int(float64(i)/float64(n)*float64(height) + 0.5) 77 } 78 scrollLow, scrollHigh := f(low), f(high) 79 if scrollLow == scrollHigh { 80 if scrollHigh == height { 81 scrollLow-- 82 } else { 83 scrollHigh++ 84 } 85 } 86 return scrollLow, scrollHigh 87 }