Noah Petherbridge
602273aa16
The Buttons can now be managed by a ui.Supervisor and be notified when the mouse enters or leaves their bounding box and handle click events. Current event handlers supported: * MouseOver * MouseOut * MouseDown * MouseUp * Click Each of those events are only fired when the state of the event has changed, i.e. the first time the mouse enters the widget MouseOver is called and then when the mouse leaves later, MouseOut is called. A completed click event (mouse was released while pressed and hovering the button) triggers both MouseOut and Click, so the button can pop itself out and also run the click handler.
97 lines
1.9 KiB
Go
97 lines
1.9 KiB
Go
package ui
|
|
|
|
import (
|
|
"sync"
|
|
|
|
"git.kirsle.net/apps/doodle/events"
|
|
"git.kirsle.net/apps/doodle/render"
|
|
)
|
|
|
|
// Supervisor keeps track of widgets of interest to notify them about
|
|
// interaction events such as mouse hovers and clicks in their general
|
|
// vicinity.
|
|
type Supervisor struct {
|
|
lock sync.RWMutex
|
|
widgets []Widget
|
|
hovering map[int]interface{}
|
|
clicked map[int]interface{}
|
|
}
|
|
|
|
// NewSupervisor creates a supervisor.
|
|
func NewSupervisor() *Supervisor {
|
|
return &Supervisor{
|
|
hovering: map[int]interface{}{},
|
|
clicked: map[int]interface{}{},
|
|
}
|
|
}
|
|
|
|
// Loop to check events and pass them to managed widgets.
|
|
func (s *Supervisor) Loop(ev *events.State) {
|
|
var (
|
|
XY = render.Point{
|
|
X: ev.CursorX.Now,
|
|
Y: ev.CursorY.Now,
|
|
}
|
|
)
|
|
|
|
// See if we are hovering over any widgets.
|
|
for id, w := range s.widgets {
|
|
var (
|
|
P = w.Point()
|
|
S = w.Size()
|
|
P2 = render.Point{
|
|
X: P.X + S.W,
|
|
Y: P.Y + S.H,
|
|
}
|
|
)
|
|
|
|
if XY.X >= P.X && XY.X <= P2.X && XY.Y >= P.Y && XY.Y <= P2.Y {
|
|
// Cursor has intersected the widget.
|
|
if _, ok := s.hovering[id]; !ok {
|
|
w.Event("MouseOver", XY)
|
|
s.hovering[id] = nil
|
|
}
|
|
|
|
_, isClicked := s.clicked[id]
|
|
if ev.Button1.Now {
|
|
if !isClicked {
|
|
w.Event("MouseDown", XY)
|
|
s.clicked[id] = nil
|
|
}
|
|
} else if isClicked {
|
|
w.Event("MouseUp", XY)
|
|
w.Event("Click", XY)
|
|
delete(s.clicked, id)
|
|
}
|
|
} else {
|
|
// Cursor is not intersecting the widget.
|
|
if _, ok := s.hovering[id]; ok {
|
|
w.Event("MouseOut", XY)
|
|
delete(s.hovering, id)
|
|
}
|
|
|
|
if _, ok := s.clicked[id]; ok {
|
|
w.Event("MouseUp", XY)
|
|
delete(s.clicked, id)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Present all widgets managed by the supervisor.
|
|
func (s *Supervisor) Present(e render.Engine) {
|
|
s.lock.RLock()
|
|
defer s.lock.RUnlock()
|
|
|
|
for _, w := range s.widgets {
|
|
w.Present(e)
|
|
}
|
|
}
|
|
|
|
// Add a widget to be supervised.
|
|
func (s *Supervisor) Add(w Widget) {
|
|
s.lock.Lock()
|
|
s.widgets = append(s.widgets, w)
|
|
s.lock.Unlock()
|
|
}
|