aboutsummaryrefslogtreecommitdiff
path: root/go/ui/collection.go
blob: 58cc4b859443c6acccc2cdd2753ecfc9a0f41be8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
package ui

import (
	"log"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
	"golang.org/x/exp/slices"
)

type Collection struct {
	Width, Height int
	hoverDetector hoverDetector
	widgets       []Widget
}

func (c *Collection) Layout() (int, int) {
	return c.Width, c.Height
}

func (c *Collection) Widgets() []Widget {
	return c.widgets
}

func (c *Collection) Clear() {
	c.widgets = []Widget{}
}

func (c *Collection) ResetHover() {
	c.hoverDetector.reset(0, 0)
}

func (c *Collection) AddWidget(w Widget) {
	if w == nil {
		log.Panicf("Adding nil widget to collection")
	}
	if slices.Contains(c.widgets, w) {
		log.Panicf("Double insertion of %v", w)
	}
	c.widgets = append(c.widgets, w)
}

func (c *Collection) FindWidget(toFind Widget) int {
	for i, w := range c.widgets {
		if w != toFind {
			continue
		}
		return i
	}
	return -1
}

func (c *Collection) RemoveWidget(widget Widget) {
	idx := c.FindWidget(widget)
	if idx != -1 {
		c.RemoveWidgetAt(idx)
	}
}

func (c *Collection) RemoveWidgetAt(idx int) {
	nwidgets := len(c.widgets)
	c.widgets[idx] = c.widgets[nwidgets-1]
	c.widgets = c.widgets[:nwidgets-1]
}

func (c *Collection) Draw(screen *ebiten.Image) {
	for _, w := range c.widgets {
		w.Draw(screen)
	}
}

func (c *Collection) Update() error {
	x, y := ebiten.CursorPosition()

	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-- {
		w := c.widgets[i]
		if !w.Contains(x, y) {
			continue
		}
		activeWidget = w
		break
	}

	c.hoverDetector.update(c, x, y, activeWidget)

	if activeWidget == nil {
		return nil
	}

	scrollX, scrollY := ebiten.Wheel()
	if scrollX != 0 || scrollY != 0 {
		if scrollable, ok := activeWidget.(Scrollable); ok {
			scrollable.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()
	}

	if inpututil.IsMouseButtonJustPressed(ebiten.MouseButtonLeft) {
		if btn, ok := activeWidget.(Clickable); ok {
			btn.Click(x, y)
		}
	}

	return nil
}