aboutsummaryrefslogtreecommitdiff
path: root/go/ui/collection.go
diff options
context:
space:
mode:
Diffstat (limited to 'go/ui/collection.go')
-rw-r--r--go/ui/collection.go153
1 files changed, 138 insertions, 15 deletions
diff --git a/go/ui/collection.go b/go/ui/collection.go
index 58cc4b85..bb7a4d53 100644
--- a/go/ui/collection.go
+++ b/go/ui/collection.go
@@ -8,10 +8,14 @@ import (
"golang.org/x/exp/slices"
)
+// Container to organise multiple Widgets
+// A collection does implement the Widget interface and thus can be nested in
+// another Collection.
type Collection struct {
Width, Height int
hoverDetector hoverDetector
widgets []Widget
+ focused Widget
}
func (c *Collection) Layout() (int, int) {
@@ -69,10 +73,17 @@ func (c *Collection) Draw(screen *ebiten.Image) {
}
}
-func (c *Collection) Update() error {
- x, y := ebiten.CursorPosition()
+func (c *Collection) Contains(x, y int) bool {
+ for _, w := range c.widgets {
+ if w.Contains(x, y) {
+ return true
+ }
+ }
+ return false
+}
+
+func (c *Collection) FindWidgetAt(x, y int) Widget {
- var activeWidget Widget
// Iterate the widget in reverse order to ensure that upper widgets are
// considered first
for i := len(c.widgets) - 1; i >= 0; i-- {
@@ -80,37 +91,149 @@ func (c *Collection) Update() error {
if !w.Contains(x, y) {
continue
}
- activeWidget = w
- break
+ return w
+ }
+ return nil
+}
+
+func (c *Collection) FindObjectAt(x, y int) interface{} {
+
+ // Iterate the widget in reverse order to ensure that upper widgets are
+ // considered first
+ for i := len(c.widgets) - 1; i >= 0; i-- {
+ w := c.widgets[i]
+ if o := w.FindObjectAt(x, y); o != nil {
+ return o
+ }
+ }
+
+ return nil
+}
+
+func (c *Collection) switchFocus(fcsbl Widget) {
+ log.Printf("switch focus from %v to %v\n", c.focused, fcsbl)
+ if c.focused != nil {
+ c.focused.Focus(false)
+
+ }
+ if fcsbl != nil {
+ fcsbl.Focus(true)
+ c.focused = fcsbl
+ } else {
+ c.focused = nil
+ }
+}
+
+func (c *Collection) handleTouchInputs() error {
+ for _, tap := range TouchManager.Taps {
+ for i := len(c.widgets) - 1; i >= 0; i-- {
+ w := c.widgets[i]
+ if !w.Contains(tap.X, tap.Y) {
+ continue
+ }
+ if w.IsClickable() {
+ w.Click(tap.X, tap.Y)
+ }
+ if w.IsFocusable() {
+ c.switchFocus(w)
+ } else if c.focused != nil {
+ c.switchFocus(nil)
+ }
+ break
+ }
+ }
+
+ // TODO: handle pinching
+ if TouchManager.Pan != nil {
+ pan := TouchManager.Pan
+ iX, iY := pan.Incremental()
+
+ w := c.FindWidgetAt(int(pan.originX), (pan.originY))
+ if w != nil && w.IsScrollable() {
+ w.Scroll(int(iX)/10, int(iY)/10)
+ }
}
+ return nil
+}
+
+func passInput(textInput *TextInput) {
+ var input []rune
+ input = ebiten.AppendInputChars(input)
+ if len(input) > 0 {
+ textInput.AddInput(input)
+ }
+ textInput.HandleKey()
+}
+
+func (c *Collection) IsUpdatable() bool {
+ return true
+}
+
+func (c *Collection) Update() error {
+ // Update all updatables
+ for _, w := range c.widgets {
+ if w.IsUpdatable() {
+ if err := w.Update(); err != nil {
+ return err
+ }
+ }
+ }
+
+ if err := c.handleTouchInputs(); err != nil {
+ return err
+ }
+
+ x, y := ebiten.CursorPosition()
+
+ activeWidget := c.FindWidgetAt(x, y)
+
c.hoverDetector.update(c, x, y, activeWidget)
if activeWidget == nil {
+ if txt, ok := c.focused.(*TextInput); ok {
+ if ebiten.IsKeyPressed(ebiten.KeyA) {
+ txt.AddInput([]rune{'a'})
+ }
+ passInput(txt)
+ }
return nil
}
scrollX, scrollY := ebiten.Wheel()
if scrollX != 0 || scrollY != 0 {
- if scrollable, ok := activeWidget.(Scrollable); ok {
- scrollable.Scroll(int(scrollX), int(scrollY))
+ if activeWidget.IsScrollable() {
+ activeWidget.Scroll(int(scrollX), int(scrollY))
}
}
if textInput, ok := activeWidget.(*TextInput); ok {
- var input []rune
- input = ebiten.AppendInputChars(input)
- if len(input) > 0 {
- textInput.AddInput(input)
- }
- textInput.HandleKey()
+ passInput(textInput)
}
if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
- if btn, ok := activeWidget.(Clickable); ok {
- btn.Click(x, y)
+ if activeWidget.IsClickable() {
+ activeWidget.Click(x, y)
}
}
return nil
}
+
+// The events for the contained widgets
+// are emitted during the collections
+// Update method.
+func (c *Collection) IsClickable() bool {
+ return false
+}
+func (c *Collection) Click(int, int) {}
+
+func (c *Collection) IsScrollable() bool {
+ return false
+}
+func (c *Collection) Scroll(int, int) {}
+
+func (c *Collection) IsFocusable() bool {
+ return false
+}
+func (c *Collection) Focus(bool) {}