2019-03-05 20:52:18 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
2020-12-12 13:43:07 +00:00
|
|
|
"image/color"
|
|
|
|
|
2019-03-05 20:52:18 +00:00
|
|
|
"opslag.de/schobers/geom"
|
2020-05-15 13:42:24 +00:00
|
|
|
"opslag.de/schobers/zntg"
|
2019-03-05 20:52:18 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Scrollbar struct {
|
|
|
|
ControlBase
|
|
|
|
|
|
|
|
Orientation Orientation
|
|
|
|
|
2020-12-12 13:43:07 +00:00
|
|
|
BarColor color.Color
|
|
|
|
BarHoverColor color.Color
|
2019-04-11 21:38:32 +00:00
|
|
|
ContentLength float32
|
|
|
|
ContentOffset float32
|
2019-03-05 20:52:18 +00:00
|
|
|
|
|
|
|
handle ScrollbarHandle
|
|
|
|
startDragOffset float32
|
|
|
|
}
|
|
|
|
|
|
|
|
func BuildScrollbar(o Orientation, fn func(s *Scrollbar)) *Scrollbar {
|
2019-04-11 21:38:32 +00:00
|
|
|
var s = &Scrollbar{Orientation: o, ContentLength: 0, ContentOffset: 0}
|
2020-05-15 17:00:43 +00:00
|
|
|
s.handle.DragStarted().AddHandler(func(Context, DragStartedArgs) {
|
2019-04-11 21:38:32 +00:00
|
|
|
s.startDragOffset = s.ContentOffset
|
2019-03-05 20:52:18 +00:00
|
|
|
})
|
2020-05-15 17:00:43 +00:00
|
|
|
s.handle.DragMoved().AddHandler(func(_ Context, args DragMovedArgs) {
|
2019-03-05 20:52:18 +00:00
|
|
|
var length = s.Orientation.SizeParallel(s.bounds)
|
|
|
|
var handleMaxOffset = length - s.Orientation.SizeParallel(s.handle.bounds)
|
2019-04-11 21:38:32 +00:00
|
|
|
var hidden = s.ContentLength - length
|
2020-05-15 17:00:43 +00:00
|
|
|
var offset = (s.Orientation.LengthParallel(args.Current) - s.Orientation.LengthParallel(args.Start)) / handleMaxOffset
|
2019-04-11 21:38:32 +00:00
|
|
|
s.ContentOffset = geom.Max32(0, geom.Min32(s.startDragOffset+offset*hidden, hidden))
|
2019-03-05 20:52:18 +00:00
|
|
|
})
|
2019-03-12 20:11:43 +00:00
|
|
|
if fn != nil {
|
|
|
|
fn(s)
|
|
|
|
}
|
2019-03-05 20:52:18 +00:00
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2019-04-11 21:38:32 +00:00
|
|
|
func (s *Scrollbar) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.PointF32, parent Control) {
|
|
|
|
s.ControlBase.Arrange(ctx, bounds, offset, parent)
|
2019-03-05 20:52:18 +00:00
|
|
|
s.updateBar(ctx)
|
|
|
|
}
|
|
|
|
|
2020-05-16 13:37:53 +00:00
|
|
|
func (s *Scrollbar) DesiredSize(ctx Context, _ geom.PointF32) geom.PointF32 {
|
2019-03-05 20:52:18 +00:00
|
|
|
return s.Orientation.Pt(geom.NaN32(), ctx.Style().Dimensions.ScrollbarWidth)
|
|
|
|
}
|
|
|
|
|
2020-05-15 17:00:43 +00:00
|
|
|
func (s *Scrollbar) Handle(ctx Context, e Event) bool {
|
2019-03-05 20:52:18 +00:00
|
|
|
s.handle.Handle(ctx, e)
|
2019-03-05 21:42:57 +00:00
|
|
|
switch e := e.(type) {
|
|
|
|
case *MouseMoveEvent:
|
|
|
|
if e.MouseWheel != 0 && e.Pos().Sub(s.offset).In(s.bounds) {
|
2019-04-11 21:38:32 +00:00
|
|
|
s.ContentOffset = geom.Max32(0, geom.Min32(s.ContentLength-s.Orientation.SizeParallel(s.bounds), s.ContentOffset-36*e.MouseWheel))
|
2020-05-15 17:00:43 +00:00
|
|
|
return true
|
2019-03-05 21:42:57 +00:00
|
|
|
}
|
|
|
|
}
|
2020-05-15 17:00:43 +00:00
|
|
|
return s.ControlBase.Handle(ctx, e)
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Scrollbar) Render(ctx Context) {
|
2020-05-15 13:42:24 +00:00
|
|
|
ctx.Renderer().FillRectangle(s.bounds, zntg.RGBA(0, 0, 0, 1))
|
2020-12-12 13:43:07 +00:00
|
|
|
s.handle.Render(ctx, s)
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
2019-04-11 21:38:32 +00:00
|
|
|
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
|
2019-03-05 21:42:57 +00:00
|
|
|
}
|
2019-04-11 21:38:32 +00:00
|
|
|
var offset = geom.Min32(1, s.ContentOffset/hidden)
|
2019-03-05 20:52:18 +00:00
|
|
|
handleOffset = handleOffset + offset*(length-handleLength)
|
|
|
|
}
|
|
|
|
var min = s.Orientation.Pt(handleOffset, s.Orientation.LengthPerpendicular(s.bounds.Max)-width)
|
2019-04-11 21:38:32 +00:00
|
|
|
s.handle.Arrange(ctx, s.Orientation.Rect(min, handleLength, width), s.offset, s)
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ScrollbarHandle struct {
|
|
|
|
ControlBase
|
|
|
|
}
|
|
|
|
|
2020-12-12 13:43:07 +00:00
|
|
|
func (h *ScrollbarHandle) Render(ctx Context, s *Scrollbar) {
|
2019-03-05 20:52:18 +00:00
|
|
|
h.RenderBackground(ctx)
|
|
|
|
p := ctx.Style().Palette
|
2020-12-12 13:43:07 +00:00
|
|
|
var fill color.Color
|
2019-03-05 20:52:18 +00:00
|
|
|
if h.over {
|
2020-12-12 13:43:07 +00:00
|
|
|
if s.BarHoverColor == nil {
|
|
|
|
fill = p.PrimaryLight
|
|
|
|
} else {
|
|
|
|
fill = s.BarHoverColor
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if s.BarColor == nil {
|
|
|
|
fill = p.Primary
|
|
|
|
} else {
|
|
|
|
fill = s.BarColor
|
|
|
|
}
|
2019-03-05 20:52:18 +00:00
|
|
|
}
|
|
|
|
ctx.Renderer().FillRectangle(h.bounds.Inset(1), fill)
|
|
|
|
}
|