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()
|
||
|
}
|