diff --git a/ui/controlbase.go b/ui/controlbase.go index f430c78..7df85ce 100644 --- a/ui/controlbase.go +++ b/ui/controlbase.go @@ -16,12 +16,12 @@ type MouseLeaveFn func() var _ Control = &ControlBase{} type ControlBase struct { - bounds geom.RectangleF32 - offset geom.PointF32 - parent Control - dragStart *geom.PointF32 - over bool - pressed bool + bounds geom.RectangleF32 + offset geom.PointF32 + parent Control + drag Dragable + over bool + pressed bool onClick ClickFn onDragEnd DragEndFn @@ -62,18 +62,18 @@ func (c *ControlBase) Handle(ctx Context, e Event) { case *MouseMoveEvent: c.over = over(e.MouseEvent) if c.pressed { - if c.dragStart == nil { - var start = c.ToControlPosition(e.Pos()) - c.dragStart = &start - if c.onDragStart != nil { - c.onDragStart(start) - } - } else { - var start = *c.dragStart + if start, ok := c.drag.IsDragging(); ok { var move = c.ToControlPosition(e.Pos()) + c.drag.Move(move) if c.onDragMove != nil { c.onDragMove(start, move) } + } else { + var start = c.ToControlPosition(e.Pos()) + c.drag.Start(start) + if c.onDragStart != nil { + c.onDragStart(start) + } } } case *MouseLeaveEvent: @@ -85,10 +85,9 @@ func (c *ControlBase) Handle(ctx Context, e Event) { } case *MouseButtonUpEvent: if e.Button == MouseButtonLeft { - if c.dragStart != nil { - var start = *c.dragStart + if start, ok := c.drag.IsDragging(); ok { var end = c.ToControlPosition(e.Pos()) - c.dragStart = nil + c.drag.Cancel() if c.onDragEnd != nil { c.onDragEnd(start, end) } diff --git a/ui/dragable.go b/ui/dragable.go new file mode 100644 index 0000000..fe889a5 --- /dev/null +++ b/ui/dragable.go @@ -0,0 +1,44 @@ +package ui + +import "opslag.de/schobers/geom" + +// Dragable keeps track of the mouse position during a drag operation. +type Dragable struct { + start *geom.PointF32 + current *geom.PointF32 +} + +// Cancel cancels the drag operation and returns the start and end position. +func (d *Dragable) Cancel() (geom.PointF32, geom.PointF32) { + if d.start == nil { + return geom.ZeroPtF32, geom.ZeroPtF32 + } + start, end := *d.start, *d.current + d.start = nil + d.current = nil + return start, end +} + +// IsDragging returns if the drag operation is in progress and the start location if so. +func (d *Dragable) IsDragging() (geom.PointF32, bool) { + if d.start != nil { + return *d.start, true + } + return geom.ZeroPtF32, false +} + +// Move calculates the delta between the start point and the current position. +func (d *Dragable) Move(p geom.PointF32) (geom.PointF32, bool) { + if d.start == nil { + return geom.ZeroPtF32, false + } + delta := p.Sub(*d.current) + d.current = &p + return delta, true +} + +// Start set the start point of the drag operation. +func (d *Dragable) Start(p geom.PointF32) { + d.start = &p + d.current = &p +}