diff --git a/ui/allg5ui/renderer.go b/ui/allg5ui/renderer.go index 12d48ca..3ae5738 100644 --- a/ui/allg5ui/renderer.go +++ b/ui/allg5ui/renderer.go @@ -57,7 +57,7 @@ func (r *Renderer) PushEvents(t ui.EventTarget, wait bool) { case *allg5.MouseButtonUpEvent: t.Handle(&ui.MouseButtonUpEvent{MouseEvent: mouseEvent(e.MouseEvent), Button: ui.MouseButton(e.Button)}) case *allg5.MouseMoveEvent: - t.Handle(&ui.MouseMoveEvent{MouseEvent: mouseEvent(e.MouseEvent)}) + t.Handle(&ui.MouseMoveEvent{MouseEvent: mouseEvent(e.MouseEvent), MouseWheel: float32(e.DeltaZ)}) } ev = r.eq.Get() } diff --git a/ui/control.go b/ui/control.go index f03fb03..ae93029 100644 --- a/ui/control.go +++ b/ui/control.go @@ -11,6 +11,7 @@ type Control interface { Render(Context) Bounds() geom.RectangleF32 + Offset() geom.PointF32 OnClick(ClickFn) OnDragStart(DragStartFn) OnDragMove(DragMoveFn) diff --git a/ui/controlbase.go b/ui/controlbase.go index 6e11420..dc7d2f7 100644 --- a/ui/controlbase.go +++ b/ui/controlbase.go @@ -97,6 +97,8 @@ func (c *ControlBase) IsOver() bool { return c.over } func (c *ControlBase) IsPressed() bool { return c.pressed } +func (c *ControlBase) Offset() geom.PointF32 { return c.offset } + func (c *ControlBase) OnClick(fn ClickFn) { c.onClick = fn } diff --git a/ui/event.go b/ui/event.go index 4783075..79ca566 100644 --- a/ui/event.go +++ b/ui/event.go @@ -47,4 +47,5 @@ func (e *MouseEvent) Pos() geom.PointF32 { type MouseMoveEvent struct { MouseEvent + MouseWheel float32 } diff --git a/ui/overflow.go b/ui/overflow.go index 76715e7..4565ccb 100644 --- a/ui/overflow.go +++ b/ui/overflow.go @@ -14,6 +14,7 @@ type overflow struct { barWidth float32 desired geom.PointF32 bounds geom.RectangleF32 + offset geom.PointF32 buffer Image hor *Scrollbar @@ -61,6 +62,7 @@ func (o *overflow) Arrange(ctx Context, bounds geom.RectangleF32, offset geom.Po o.barWidth = ctx.Style().Dimensions.ScrollbarWidth o.desired = o.Content.DesiredSize(ctx) o.bounds = bounds + o.offset = offset var hor, ver = o.shouldScroll(bounds) var contentX, contentY float32 = 0, 0 @@ -92,9 +94,23 @@ func (o *overflow) Handle(ctx Context, e Event) { if ver { o.ver.Handle(ctx, e) } + switch e := e.(type) { + case *MouseMoveEvent: + if ver { + var contentO = o.Content.Offset() + var content = o.Content.Bounds() + content.Min = contentO + content.Max = content.Max.Add(contentO) + if e.MouseWheel != 0 && e.Pos().In(content) { + o.ver.Offset = geom.Max32(0, geom.Min32(o.ver.Content-content.Dy(), o.ver.Offset-36*e.MouseWheel)) + } + } + } o.Content.Handle(ctx, e) } +func (o *overflow) Offset() geom.PointF32 { return o.offset } + func (o *overflow) Render(ctx Context) { var renderer = ctx.Renderer() diff --git a/ui/proxy.go b/ui/proxy.go index 1ad365b..669fff5 100644 --- a/ui/proxy.go +++ b/ui/proxy.go @@ -28,6 +28,8 @@ func (p *Proxy) Bounds() geom.RectangleF32 { return p.Content.Bounds() } +func (p *Proxy) Offset() geom.PointF32 { return p.Content.Offset() } + func (p *Proxy) OnClick(fn ClickFn) { p.Content.OnClick(fn) } diff --git a/ui/scrollbar.go b/ui/scrollbar.go index 28bcb7c..c7ca03b 100644 --- a/ui/scrollbar.go +++ b/ui/scrollbar.go @@ -43,6 +43,12 @@ func (s *Scrollbar) DesiredSize(ctx Context) geom.PointF32 { 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) } @@ -56,8 +62,11 @@ func (s *Scrollbar) updateBar(ctx Context) { var handleLength = length var handleOffset = s.Orientation.LengthParallel(s.bounds.Min) if s.Content > length { - handleLength = geom.Max32(2*width, length/s.Content) + 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) }