1 package etk
2
3 import (
4 "fmt"
5 "image"
6
7 "github.com/hajimehoshi/ebiten/v2"
8 "golang.org/x/image/font/sfnt"
9 )
10
11
12
13 type Window struct {
14 *Box
15 font *sfnt.Font
16 fontSize int
17 frameSize int
18 list *List
19 listH Alignment
20 listV Alignment
21 listSize int
22 listWidget *WithoutFocus
23 defaultFocus []Widget
24 labels []string
25 active int
26 modified bool
27 listModified bool
28 firstDraw bool
29 }
30
31
32 func NewWindow() *Window {
33 w := &Window{
34 Box: NewBox(),
35 font: Style.TextFont,
36 fontSize: Scale(Style.TextSize),
37 frameSize: Scale(4),
38 listSize: Scale(172),
39 listH: AlignEnd,
40 listV: AlignCenter,
41 active: -1,
42 firstDraw: true,
43 }
44 w.list = NewList(int(float64(Scale(Style.TextSize))*1.5), w.selectItem)
45 w.listWidget = &WithoutFocus{w.list}
46 return w
47 }
48
49
50 func (w *Window) SetRect(r image.Rectangle) {
51 w.Lock()
52 defer w.Unlock()
53
54 w.rect = r
55 w.modified = true
56 }
57
58
59 func (w *Window) SetFont(fnt *sfnt.Font, size int) {
60 w.Lock()
61 defer w.Unlock()
62
63 w.font = fnt
64 w.fontSize = size
65 w.list.SetItemHeight(size)
66 }
67
68
69 func (w *Window) SetFrameSize(size int) {
70 w.Lock()
71 defer w.Unlock()
72
73 w.frameSize = size
74 w.modified = true
75 }
76
77
78 func (w *Window) SetListSize(size int) {
79 w.Lock()
80 defer w.Unlock()
81
82 w.listSize = size
83 w.modified = true
84 }
85
86
87 func (w *Window) SetListHorizontal(h Alignment) {
88 w.Lock()
89 defer w.Unlock()
90
91 w.listH = h
92 w.modified = true
93 }
94
95
96 func (w *Window) SetListVertical(v Alignment) {
97 w.Lock()
98 defer w.Unlock()
99
100 w.listV = v
101 w.modified = true
102 }
103
104
105 func (w *Window) Show(index int) {
106 w.Lock()
107 defer w.Unlock()
108
109 if index >= 0 && index < len(w.children) {
110 w.active = index
111 SetFocus(w.defaultFocus[index])
112 } else {
113 w.active = -1
114 }
115 w.modified = true
116 }
117
118
119 func (w *Window) Hide() {
120 w.Lock()
121 defer w.Unlock()
122
123 w.active = -1
124 w.modified = true
125 }
126
127
128 func (w *Window) Children() []Widget {
129 w.Lock()
130 defer w.Unlock()
131
132 if w.active >= 0 && w.active < len(w.children) {
133 if w.listSize > 0 {
134 return []Widget{w.children[w.active], w.listWidget}
135 }
136 return []Widget{w.children[w.active]}
137 } else if w.listSize > 0 {
138 return []Widget{w.listWidget}
139 }
140 return nil
141 }
142
143
144 func (w *Window) Clear() {
145 w.Lock()
146 defer w.Unlock()
147
148 w.children = w.children[:0]
149 w.labels = w.labels[:0]
150 w.active = -1
151 w.listModified = true
152 w.firstDraw = true
153 }
154
155 func (w *Window) selectItem(index int) (accept bool) {
156 if index >= 0 && index < len(w.children) {
157 w.active = index
158 w.modified = true
159 SetFocus(w.defaultFocus[index])
160 }
161 return true
162 }
163
164
165 func (w *Window) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
166 return true, nil
167 }
168
169
170 func (w *Window) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
171 return true, nil
172 }
173
174
175 func (w *Window) Draw(screen *ebiten.Image) error {
176 if w.listModified {
177 w.list.SetItemHeight(int(float64(Scale(w.fontSize)) * 1.5))
178 w.list.Clear()
179 for i := range w.labels {
180 label := w.labels[i]
181 if label == "" {
182 label = fmt.Sprintf("#%d", i)
183 }
184 t := NewText(label)
185 t.SetFont(w.font, Scale(w.fontSize))
186 t.SetAutoResize(true)
187 t.SetVertical(AlignCenter)
188 w.list.AddChildAt(t, 0, i)
189 w.list.SetSelectedItem(0, w.active)
190 }
191 w.listModified = false
192 }
193 if w.modified {
194 if w.active >= 0 {
195 wr := w.rect
196 if w.listSize > 0 {
197 var lr image.Rectangle
198 switch w.listH {
199 case AlignStart:
200 lr = image.Rect(wr.Min.X, wr.Min.Y, wr.Min.X+w.listSize, wr.Max.Y)
201 case AlignEnd:
202 lr = image.Rect(wr.Max.X-w.listSize, wr.Min.Y, wr.Max.X, wr.Max.Y)
203 }
204 switch w.listV {
205 case AlignStart:
206 lr = image.Rect(wr.Min.X, wr.Min.Y, wr.Max.X, wr.Min.Y+w.listSize)
207 case AlignEnd:
208 lr = image.Rect(wr.Min.X, wr.Max.Y-w.listSize, wr.Max.X, wr.Max.Y)
209 }
210 dx, dy := lr.Dx(), lr.Dy()
211 if dx > 0 && dy > 0 && dx <= wr.Dx() && dy <= wr.Dy() {
212 switch w.listH {
213 case AlignStart:
214 wr.Min.X += w.listSize
215 case AlignEnd:
216 wr.Max.X -= w.listSize
217 }
218 switch w.listV {
219 case AlignStart:
220 wr.Min.Y += w.listSize
221 case AlignEnd:
222 wr.Max.Y -= w.listSize
223 }
224 w.list.SetRect(lr)
225 }
226 }
227 w.children[w.active].SetRect(wr)
228 if w.firstDraw {
229 SetFocus(w.children[w.active])
230 w.firstDraw = false
231 }
232 }
233 w.modified = false
234 }
235 return nil
236 }
237
238
239 func (w *Window) AddChild(wgt ...Widget) {
240 w.Lock()
241 defer w.Unlock()
242
243 for _, widget := range wgt {
244 w.children = append(w.children, widget)
245 w.defaultFocus = append(w.defaultFocus, widget)
246 w.labels = append(w.labels, "")
247 }
248 w.modified = true
249 w.listModified = true
250 }
251
252
253 func (w *Window) AddChildWithLabel(wgt Widget, defaultFocus Widget, label string) int {
254 w.Lock()
255 defer w.Unlock()
256
257 w.children = append(w.children, wgt)
258 w.defaultFocus = append(w.defaultFocus, defaultFocus)
259 w.labels = append(w.labels, label)
260
261 w.modified = true
262 w.listModified = true
263 return len(w.children) - 1
264 }
265
View as plain text