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  }