1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
|
package app
// Scrollable implements vertical scrolling
type Scrollable struct {
scroll int
offset int
height int
elems int
}
func (s *Scrollable) Scroll() int {
return s.scroll
}
func (s *Scrollable) SetOffset(offset int) {
s.offset = offset
}
func (s *Scrollable) ScrollOffset() int {
return s.offset
}
func (s *Scrollable) PercentVisible() float64 {
if s.elems <= 0 {
return 1.0
}
return float64(s.height) / float64(s.elems)
}
func (s *Scrollable) PercentScrolled() float64 {
if s.elems <= 0 {
return 1.0
}
return float64(s.scroll) / float64(s.elems)
}
func (s *Scrollable) NeedScrollbar() bool {
needScrollbar := true
if s.PercentVisible() >= 1.0 {
needScrollbar = false
}
return needScrollbar
}
func (s *Scrollable) UpdateScroller(height, elems int) {
s.height = height
s.elems = elems
}
func (s *Scrollable) EnsureScroll(idx int) {
if idx < 0 {
return
}
middle := s.height / 2
switch {
case s.offset > middle:
s.scroll = idx - middle
case idx < s.scroll+s.offset:
s.scroll = idx - s.offset
case idx >= s.scroll-s.offset+s.height:
s.scroll = idx + s.offset - s.height + 1
}
s.checkBounds()
}
func (s *Scrollable) checkBounds() {
maxScroll := max(s.elems-s.height, 0)
if s.scroll > maxScroll {
s.scroll = maxScroll
}
if s.scroll < 0 {
s.scroll = 0
}
}
type AlignPosition uint
const (
AlignTop AlignPosition = iota
AlignCenter
AlignBottom
)
func (s *Scrollable) Align(idx int, pos AlignPosition) {
switch pos {
case AlignTop:
s.scroll = idx
case AlignCenter:
s.scroll = idx - s.height/2
case AlignBottom:
s.scroll = idx - s.height + 1
}
s.checkBounds()
}
|