doodle/ui/supervisor.go
Noah Petherbridge 8624a28ea9 Add StatusBar to Editor Mode, Iterate on UI Toolkit
* Added `BoxSize()` to Widget that reports the full box size including
  borders and margin.
* The Frame uses the `BoxSize()` of widgets to position them.
  Reintroduces some padding issues (boxes on the GUI Test stick out of
  bounds a bit) but is on the right track.
* Renamed `Padding` to `Margin` on the Widget object, since the Margin
  is taken into consideration along with Outline and Border in computing
  the widget's BoxSize.
* Restructured the Label widget to take a Text or TextVariable property
  and the font settings (render.Text) are in a new `Font` property.
2018-08-05 12:54:57 -07:00

98 lines
2.0 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{
widgets: []Widget{},
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, w.Point())
}
}
// Add a widget to be supervised.
func (s *Supervisor) Add(w Widget) {
s.lock.Lock()
s.widgets = append(s.widgets, w)
s.lock.Unlock()
}