package ui import ( "math" "opslag.de/schobers/galleg/allegro5" "opslag.de/schobers/geom" ) var _ Control = &ContentScrollbar{} type ContentScrollbarValueChangedFn func(float64) type ContentScrollbar struct { ControlBase Length float64 Value float64 Orientation Orientation OnChanged ContentScrollbarValueChangedFn handle *contentScrollbarHandle } 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() allegro5.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) barViewRange() (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.Max.Y max = s.Bounds.Min.Y } var length = (max - min) var bar = length if s.Length > length { bar = length * length / s.Length } if bar < 20 { if length < 40 { bar = .5 * length } else { bar = 20 } } return min + .5*bar, max - .5*bar } 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 n = y if OrientationHorizontal == s.Orientation { n = x } var min, max = s.barViewRange() if min == max { return 0 } var delta = s.Length - (max - min) var off = (n - min) / (max - min) var v = off * (s.Length - (max - min)) if v < 0 { v = 0 } else if v > delta { v = delta } return v } 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) { // var val = s.Value + d // if val < s.Minimum { // val = s.Minimum // } else if val > s.Maximum { // val = s.Maximum // } // s.change(val) } func (s *ContentScrollbar) Handle(ctx Context, ev allegro5.Event) { s.ControlBase.Handle(ctx, ev) s.handle.Handle(ctx, ev) switch e := ev.(type) { case *allegro5.MouseMoveEvent: if s.handle.IsPressed { s.snapTo(e.X, e.Y) } if 0 != e.DeltaZ && s.IsOver { var d = e.DeltaZ if allegro5.IsAnyKeyDown(allegro5.KeyLShift, allegro5.KeyRShift) { d *= 10 } s.increment(d) } case *allegro5.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) // var min, max = s.barViewRange() // var off = float64(s.Value-s.Minimum) / float64(s.Maximum-s.Minimum) // var centerH = min + (max-min)*off // var r = 0.5 * float64(s.handles[0].Width()) // var center = s.barViewCenter() // switch s.Orientation { // case OrientationHorizontal: // s.handle.SetRect(geom.RectF(centerH-r, center-r, centerH+r, center+r)) // default: // s.handle.SetRect(geom.RectF(center-r, centerH-r, center+r, centerH+r)) // } } func (s *ContentScrollbar) Render(ctx Context) { s.handle.Render(ctx) s.ControlBase.Render(ctx) }