204 lines
4.2 KiB
Go
204 lines
4.2 KiB
Go
package ui
|
|
|
|
import (
|
|
"math"
|
|
|
|
"opslag.de/schobers/geom"
|
|
"opslag.de/schobers/zntg/allg5"
|
|
)
|
|
|
|
var _ Control = &ContentScrollbar{}
|
|
|
|
type ContentScrollbarValueChangedFn func(float64)
|
|
|
|
type ContentScrollbar struct {
|
|
ControlBase
|
|
Length float64
|
|
Value float64
|
|
Orientation Orientation
|
|
OnChanged ContentScrollbarValueChangedFn
|
|
handle *contentScrollbarHandle
|
|
barLength float64
|
|
scrollDistance float64
|
|
}
|
|
|
|
type contentScrollbarHandle struct {
|
|
ControlBase
|
|
}
|
|
|
|
func (h *contentScrollbarHandle) Render(ctx Context) {
|
|
var c = ctx.Palette().Primary()
|
|
if h.IsOver {
|
|
if h.IsPressed {
|
|
} else {
|
|
}
|
|
}
|
|
var min = h.Bounds.Min.To32()
|
|
var max = h.Bounds.Max.To32()
|
|
allg5.DrawFilledRectangle(min.X, min.Y, max.X, max.Y, c)
|
|
}
|
|
|
|
func (s *ContentScrollbar) Created(ctx Context, p Container) error {
|
|
s.ControlBase.Created(ctx, p)
|
|
s.handle = &contentScrollbarHandle{}
|
|
s.handle.Created(ctx, nil)
|
|
return nil
|
|
}
|
|
|
|
func (s *ContentScrollbar) Destroyed(ctx Context) {
|
|
s.handle.Destroyed(ctx)
|
|
}
|
|
|
|
func (s *ContentScrollbar) length() (float64, float64) {
|
|
var min, max float64
|
|
switch s.Orientation {
|
|
case OrientationHorizontal:
|
|
min = s.Bounds.Min.X
|
|
max = s.Bounds.Max.X
|
|
default:
|
|
min = s.Bounds.Min.Y
|
|
max = s.Bounds.Max.Y
|
|
}
|
|
return max - min, min
|
|
}
|
|
|
|
func (s *ContentScrollbar) updateBarLength() {
|
|
var length, _ = s.length()
|
|
var bar = length
|
|
if s.Length > length {
|
|
bar = length * length / s.Length
|
|
}
|
|
if bar < 20 {
|
|
if length < 40 {
|
|
bar = .5 * length
|
|
} else {
|
|
bar = 20
|
|
}
|
|
}
|
|
s.barLength = bar
|
|
var d = s.Length - length
|
|
if d < 0 {
|
|
d = 0
|
|
}
|
|
s.scrollDistance = d
|
|
}
|
|
|
|
func (s *ContentScrollbar) barViewCenter() float64 {
|
|
switch s.Orientation {
|
|
case OrientationHorizontal:
|
|
return (s.Bounds.Min.Y + s.Bounds.Max.Y) * .5
|
|
default:
|
|
return (s.Bounds.Min.X + s.Bounds.Max.X) * .5
|
|
}
|
|
}
|
|
|
|
func (s *ContentScrollbar) toValue(x, y float64) float64 {
|
|
var pos = y
|
|
if OrientationHorizontal == s.Orientation {
|
|
pos = x
|
|
}
|
|
var length, min = s.length()
|
|
if length == 0 {
|
|
return 0
|
|
}
|
|
var offset = (pos - .5*s.barLength - min) / (length - s.barLength)
|
|
if offset < 0 {
|
|
return 0
|
|
} else if offset > 1 {
|
|
return s.scrollDistance
|
|
}
|
|
return s.scrollDistance * offset
|
|
}
|
|
|
|
func (s *ContentScrollbar) change(v float64) {
|
|
if v != s.Value {
|
|
s.Value = v
|
|
var onChanged = s.OnChanged
|
|
if nil != onChanged {
|
|
onChanged(v)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *ContentScrollbar) snapTo(x, y int) {
|
|
var val = s.toValue(float64(x), float64(y))
|
|
s.change(val)
|
|
}
|
|
|
|
func (s *ContentScrollbar) increment(d int) {
|
|
if s.Orientation == OrientationVertical {
|
|
d *= -1
|
|
}
|
|
var val = s.Value + float64(d)*ScrollbarWidth
|
|
if val < 0 {
|
|
val = 0
|
|
} else if val > s.scrollDistance {
|
|
val = s.scrollDistance
|
|
}
|
|
s.change(val)
|
|
}
|
|
|
|
func (s *ContentScrollbar) Handle(ctx Context, ev allg5.Event) {
|
|
s.ControlBase.Handle(ctx, ev)
|
|
s.handle.Handle(ctx, ev)
|
|
switch e := ev.(type) {
|
|
case *allg5.MouseMoveEvent:
|
|
if s.handle.IsPressed {
|
|
s.snapTo(e.X, e.Y)
|
|
}
|
|
if 0 != e.DeltaZ && s.IsOver {
|
|
var d = e.DeltaZ
|
|
if allg5.IsAnyKeyDown(allg5.KeyLShift, allg5.KeyRShift) {
|
|
d *= 10
|
|
}
|
|
s.increment(d)
|
|
}
|
|
case *allg5.MouseButtonDownEvent:
|
|
if !s.handle.IsPressed && s.IsOver {
|
|
s.snapTo(e.X, e.Y)
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *ContentScrollbar) DesiredSize(Context) geom.PointF {
|
|
switch s.Orientation {
|
|
case OrientationHorizontal:
|
|
return geom.PtF(math.NaN(), ScrollbarWidth)
|
|
}
|
|
return geom.PtF(ScrollbarWidth, math.NaN())
|
|
}
|
|
|
|
func (s *ContentScrollbar) SetRect(rect geom.RectangleF) {
|
|
switch s.Orientation {
|
|
case OrientationHorizontal:
|
|
if rect.Dy() > ScrollbarWidth {
|
|
rect.Min.Y = rect.Max.Y - ScrollbarWidth
|
|
}
|
|
default:
|
|
if rect.Dx() > ScrollbarWidth {
|
|
rect.Min.X = rect.Max.X - ScrollbarWidth
|
|
}
|
|
}
|
|
s.ControlBase.SetRect(rect)
|
|
s.updateBarLength()
|
|
|
|
var offset float64
|
|
if 0 < s.scrollDistance {
|
|
offset = s.Value / s.scrollDistance
|
|
}
|
|
var length, min = s.length()
|
|
var begin = min + (length-s.barLength)*offset
|
|
var end = begin + s.barLength
|
|
switch s.Orientation {
|
|
case OrientationHorizontal:
|
|
s.handle.SetRect(geom.RectF(begin, rect.Min.Y, end, rect.Max.Y))
|
|
default:
|
|
s.handle.SetRect(geom.RectF(rect.Min.X, begin, rect.Max.X, end))
|
|
}
|
|
}
|
|
|
|
func (s *ContentScrollbar) Render(ctx Context) {
|
|
s.handle.Render(ctx)
|
|
s.ControlBase.Render(ctx)
|
|
}
|