2018-07-26 03:25:02 +00:00
|
|
|
package ui
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
|
|
|
|
|
|
|
"git.kirsle.net/apps/doodle/events"
|
|
|
|
"git.kirsle.net/apps/doodle/render"
|
|
|
|
)
|
|
|
|
|
2018-08-17 03:37:19 +00:00
|
|
|
// Event is a named event that the supervisor will send.
|
|
|
|
type Event int
|
|
|
|
|
|
|
|
// Events.
|
|
|
|
const (
|
|
|
|
NullEvent Event = iota
|
|
|
|
MouseOver
|
|
|
|
MouseOut
|
|
|
|
MouseDown
|
|
|
|
MouseUp
|
|
|
|
Click
|
|
|
|
KeyDown
|
|
|
|
KeyUp
|
|
|
|
KeyPress
|
|
|
|
)
|
|
|
|
|
2018-07-26 03:25:02 +00:00
|
|
|
// 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{
|
2018-08-05 19:54:57 +00:00
|
|
|
widgets: []Widget{},
|
2018-07-26 03:25:02 +00:00
|
|
|
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 {
|
2018-08-17 03:37:19 +00:00
|
|
|
w.Event(MouseOver, XY)
|
2018-07-26 03:25:02 +00:00
|
|
|
s.hovering[id] = nil
|
|
|
|
}
|
|
|
|
|
|
|
|
_, isClicked := s.clicked[id]
|
|
|
|
if ev.Button1.Now {
|
|
|
|
if !isClicked {
|
2018-08-17 03:37:19 +00:00
|
|
|
w.Event(MouseDown, XY)
|
2018-07-26 03:25:02 +00:00
|
|
|
s.clicked[id] = nil
|
|
|
|
}
|
|
|
|
} else if isClicked {
|
2018-08-17 03:37:19 +00:00
|
|
|
w.Event(MouseUp, XY)
|
|
|
|
w.Event(Click, XY)
|
2018-07-26 03:25:02 +00:00
|
|
|
delete(s.clicked, id)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Cursor is not intersecting the widget.
|
|
|
|
if _, ok := s.hovering[id]; ok {
|
2018-08-17 03:37:19 +00:00
|
|
|
w.Event(MouseOut, XY)
|
2018-07-26 03:25:02 +00:00
|
|
|
delete(s.hovering, id)
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, ok := s.clicked[id]; ok {
|
2018-08-17 03:37:19 +00:00
|
|
|
w.Event(MouseUp, XY)
|
2018-07-26 03:25:02 +00:00
|
|
|
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 {
|
2018-08-05 19:54:57 +00:00
|
|
|
w.Present(e, w.Point())
|
2018-07-26 03:25:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Add a widget to be supervised.
|
|
|
|
func (s *Supervisor) Add(w Widget) {
|
|
|
|
s.lock.Lock()
|
|
|
|
s.widgets = append(s.widgets, w)
|
|
|
|
s.lock.Unlock()
|
|
|
|
}
|