1 package etk
2
3 import (
4 "image"
5 "image/color"
6
7 "github.com/hajimehoshi/ebiten/v2"
8 )
9
10
11 type Select struct {
12 *Box
13 label *Text
14 list *List
15 onSelect func(index int) (accept bool)
16 items []string
17 open bool
18 }
19
20
21 func NewSelect(itemHeight int, onSelect func(index int) (accept bool)) *Select {
22 s := &Select{
23 Box: NewBox(),
24 label: NewText(""),
25 onSelect: onSelect,
26 }
27 s.label.SetVertical(AlignCenter)
28 s.label.SetForeground(Style.ButtonTextColor)
29 s.SetBackground(Style.ButtonBgColor)
30 s.list = NewList(itemHeight, s.selectList)
31 s.list.SetBackground(Style.ButtonBgColor)
32 s.list.SetDrawBorder(true)
33 s.list.SetVisible(false)
34 s.list.SetSelectionMode(SelectRow)
35 s.AddChild(s.list)
36 s.updateLabel()
37 return s
38 }
39
40
41 func (s *Select) SetRect(r image.Rectangle) {
42 s.Lock()
43 defer s.Unlock()
44 s.rect = r
45 s.label.SetRect(r)
46 listRect := r.Add(image.Point{X: 0, Y: r.Dy()})
47 itemCount := len(s.items)
48 listRect.Max.Y = listRect.Min.Y + itemCount*s.list.itemHeight
49 _, height := ScreenSize()
50 if listRect.Max.Y > height {
51 listRect.Max.Y = height
52 }
53 s.list.SetRect(listRect)
54 }
55
56
57 func (s *Select) SetHighlightColor(c color.RGBA) {
58 s.list.SetHighlightColor(c)
59 }
60
61
62 func (s *Select) SetSelectedItem(index int) {
63 s.Lock()
64 defer s.Unlock()
65 if index < 0 || index >= len(s.items) {
66 return
67 }
68 s.list.SetSelectedItem(0, index)
69 s.updateLabel()
70 }
71
72
73 func (s *Select) Children() []Widget {
74 s.Lock()
75 defer s.Unlock()
76
77 return s.children
78 }
79
80
81 func (s *Select) AddChild(w ...Widget) {
82 s.Lock()
83 defer s.Unlock()
84
85 s.children = append(s.children, w...)
86 }
87
88
89 func (s *Select) Clear() {
90 s.Lock()
91 defer s.Unlock()
92
93 s.items = nil
94 s.list.Clear()
95 s.updateLabel()
96 }
97
98
99 func (s *Select) AddOption(label string) {
100 s.Lock()
101 defer s.Unlock()
102
103 s.items = append(s.items, label)
104 if len(s.items) == 1 {
105 s.list.selectedY = 0
106 s.updateLabel()
107 }
108
109 t := NewText(label)
110 t.SetVertical(AlignCenter)
111 t.SetForeground(Style.ButtonTextColor)
112 s.list.AddChildAt(t, 0, len(s.items)-1)
113 }
114
115 func (s *Select) updateLabel() {
116 var text string
117 if len(s.items) > 0 && s.list.selectedY >= 0 && s.list.selectedY < len(s.items) {
118 text = s.items[s.list.selectedY]
119 }
120 if s.open {
121 text = "▼ " + text
122 } else {
123 text = "▶ " + text
124 }
125 s.label.SetText(text)
126 }
127
128 func (s *Select) selectList(index int) (accept bool) {
129 s.Lock()
130 s.list.grid.visible = false
131 s.open = false
132 onSelect := s.onSelect
133 s.Unlock()
134
135 if onSelect != nil {
136 if !onSelect(index) {
137 return false
138 }
139 }
140
141 s.list.selectedY = index
142 s.updateLabel()
143 return true
144 }
145
146
147 func (s *Select) SetMenuVisible(visible bool) {
148 s.Lock()
149 defer s.Unlock()
150
151 s._setMenuVisible(visible)
152 }
153
154 func (s *Select) _setMenuVisible(visible bool) {
155 s.open = visible
156 s.list.SetVisible(visible)
157 s.updateLabel()
158
159 if !visible {
160 s.background = Style.ButtonBgColor
161 } else {
162 s.background = color.RGBA{uint8(float64(Style.ButtonBgColor.R) * 0.95), uint8(float64(Style.ButtonBgColor.G) * 0.95), uint8(float64(Style.ButtonBgColor.B) * 0.95), 255}
163 }
164 }
165
166
167
168 func (s *Select) Cursor() ebiten.CursorShapeType {
169 return ebiten.CursorShapePointer
170 }
171
172
173 func (s *Select) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
174 return false, nil
175 }
176
177
178 func (s *Select) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
179 s.Lock()
180 defer s.Unlock()
181
182 if clicked {
183 s._setMenuVisible(!s.open)
184 }
185 return true, nil
186 }
187
188
189 func (s *Select) Draw(screen *ebiten.Image) error {
190 s.Lock()
191 defer s.Unlock()
192
193
194 s.label.Draw(screen)
195
196
197 r := s.rect
198 borderSize := Scale(Style.ButtonBorderSize)
199 borderLeft, borderTop := Style.ButtonBorderLeft, Style.ButtonBorderTop
200 borderRight, borderBottom := Style.ButtonBorderRight, Style.ButtonBorderBottom
201 if !s.open {
202 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+borderSize, r.Max.Y)).(*ebiten.Image).Fill(borderLeft)
203 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+borderSize)).(*ebiten.Image).Fill(borderTop)
204 screen.SubImage(image.Rect(r.Max.X-borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(borderRight)
205 screen.SubImage(image.Rect(r.Min.X, r.Max.Y-borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(borderBottom)
206 } else {
207 borderLeft, borderTop, borderRight, borderBottom = borderRight, borderBottom, borderLeft, borderTop
208 screen.SubImage(image.Rect(r.Max.X-borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(borderRight)
209 screen.SubImage(image.Rect(r.Min.X, r.Max.Y-borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(borderBottom)
210 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+borderSize, r.Max.Y)).(*ebiten.Image).Fill(borderLeft)
211 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+borderSize)).(*ebiten.Image).Fill(borderTop)
212 }
213 return nil
214 }
215
View as plain text