zntg/ui/scrollbar.go

93 lines
2.7 KiB
Go

package ui
import (
"opslag.de/schobers/geom"
)
type Scrollbar struct {
ControlBase
Orientation Orientation
ContentLength float32
ContentOffset float32
handle ScrollbarHandle
startDragOffset float32
}
func BuildScrollbar(o Orientation, fn func(s *Scrollbar)) *Scrollbar {
var s = &Scrollbar{Orientation: o, ContentLength: 0, ContentOffset: 0}
s.handle.OnDragStart(func(_ geom.PointF32) {
s.startDragOffset = s.ContentOffset
})
s.handle.OnDragMove(func(start, move geom.PointF32) {
var length = s.Orientation.SizeParallel(s.bounds)
var handleMaxOffset = length - s.Orientation.SizeParallel(s.handle.bounds)
var hidden = s.ContentLength - length
var offset = (s.Orientation.LengthParallel(move) - s.Orientation.LengthParallel(start)) / handleMaxOffset
s.ContentOffset = geom.Max32(0, geom.Min32(s.startDragOffset+offset*hidden, hidden))
})
if fn != nil {
fn(s)
}
return s
}
func (s *Scrollbar) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32, parent Control) {
s.ControlBase.Arrange(ctx, bounds, offset, parent)
s.updateBar(ctx)
}
func (s *Scrollbar) DesiredSize(ctx Context) geom.PointF32 {
return s.Orientation.Pt(geom.NaN32(), ctx.Style().Dimensions.ScrollbarWidth)
}
func (s *Scrollbar) Handle(ctx Context, e Event) {
s.handle.Handle(ctx, e)
switch e := e.(type) {
case *MouseMoveEvent:
if e.MouseWheel != 0 && e.Pos().Sub(s.offset).In(s.bounds) {
s.ContentOffset = geom.Max32(0, geom.Min32(s.ContentLength-s.Orientation.SizeParallel(s.bounds), s.ContentOffset-36*e.MouseWheel))
}
}
s.ControlBase.Handle(ctx, e)
}
func (s *Scrollbar) Render(ctx Context) {
ctx.Renderer().FillRectangle(s.bounds, RGBA(0, 0, 0, 1))
s.handle.Render(ctx)
}
func (s *Scrollbar) updateBar(ctx Context) {
var length = s.Orientation.SizeParallel(s.bounds)
var width = ctx.Style().Dimensions.ScrollbarWidth
var handleLength = length
var handleOffset = s.Orientation.LengthParallel(s.bounds.Min)
if s.ContentLength > length {
handleLength = geom.Max32(2*width, length*length/s.ContentLength)
var hidden = s.ContentLength - length
if s.ContentOffset > hidden {
s.ContentOffset = hidden
}
var offset = geom.Min32(1, s.ContentOffset/hidden)
handleOffset = handleOffset + offset*(length-handleLength)
}
var min = s.Orientation.Pt(handleOffset, s.Orientation.LengthPerpendicular(s.bounds.Max)-width)
s.handle.Arrange(ctx, s.Orientation.Rect(min, handleLength, width), s.offset, s)
}
type ScrollbarHandle struct {
ControlBase
}
func (h *ScrollbarHandle) Render(ctx Context) {
h.RenderBackground(ctx)
p := ctx.Style().Palette
fill := p.Primary
if h.over {
fill = p.PrimaryLight
}
ctx.Renderer().FillRectangle(h.bounds.Inset(1), fill)
}