Noah Petherbridge
8624a28ea9
* 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.
98 lines
2.0 KiB
Go
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()
|
|
}
|