92 lines
2.5 KiB
Go
92 lines
2.5 KiB
Go
package ui
|
|
|
|
import (
|
|
"opslag.de/schobers/geom"
|
|
)
|
|
|
|
type Scrollbar struct {
|
|
ControlBase
|
|
|
|
Orientation Orientation
|
|
|
|
Content float32
|
|
Offset float32
|
|
|
|
handle ScrollbarHandle
|
|
startDragOffset float32
|
|
}
|
|
|
|
func BuildScrollbar(o Orientation, fn func(s *Scrollbar)) *Scrollbar {
|
|
var s = &Scrollbar{Orientation: o, Content: 0, Offset: 0}
|
|
s.handle.OnDragStart(func(_ Context, _ Control, _ geom.PointF32) {
|
|
s.startDragOffset = s.Offset
|
|
})
|
|
s.handle.OnDragMove(func(_ Context, _ Control, start, move geom.PointF32) {
|
|
var length = s.Orientation.SizeParallel(s.bounds)
|
|
var handleMaxOffset = length - s.Orientation.SizeParallel(s.handle.bounds)
|
|
var hidden = s.Content - length
|
|
var offset = (s.Orientation.LengthParallel(move) - s.Orientation.LengthParallel(start)) / handleMaxOffset
|
|
s.Offset = 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) {
|
|
s.ControlBase.Arrange(ctx, bounds, offset)
|
|
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.Offset = geom.Max32(0, geom.Min32(s.Content-s.Orientation.SizeParallel(s.bounds), s.Offset-36*e.MouseWheel))
|
|
}
|
|
}
|
|
s.ControlBase.Handle(ctx, e)
|
|
}
|
|
|
|
func (s *Scrollbar) Render(ctx Context) {
|
|
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.Content > length {
|
|
handleLength = geom.Max32(2*width, length*length/s.Content)
|
|
var hidden = s.Content - length
|
|
if s.Offset > hidden {
|
|
s.Offset = hidden
|
|
}
|
|
var offset = geom.Min32(1, s.Offset/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)
|
|
}
|
|
|
|
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.PrimaryHighlight
|
|
}
|
|
ctx.Renderer().FillRectangle(h.bounds.Inset(1), fill)
|
|
}
|