1 package etk
2
3 import (
4 "image"
5 "image/color"
6
7 "code.rocket9labs.com/tslocum/etk/messeji"
8 "github.com/hajimehoshi/ebiten/v2"
9 "github.com/hajimehoshi/ebiten/v2/text/v2"
10 )
11
12
13 type Button struct {
14 *Box
15 field *messeji.TextField
16 btnBackground color.RGBA
17 textFont *text.GoTextFaceSource
18 textSize int
19 borderSize int
20 borderTop color.RGBA
21 borderRight color.RGBA
22 borderBottom color.RGBA
23 borderLeft color.RGBA
24 onSelected func() error
25 pressed bool
26 }
27
28
29 func NewButton(label string, onSelected func() error) *Button {
30 textColor := Style.ButtonTextColor
31 if textColor.A == 0 {
32 textColor = Style.TextColorDark
33 }
34 f := newText()
35 f.SetText(label)
36 f.SetForegroundColor(textColor)
37 f.SetHorizontal(messeji.AlignCenter)
38 f.SetVertical(messeji.AlignCenter)
39 f.SetAutoResize(true)
40
41 b := &Button{
42 Box: NewBox(),
43 field: f,
44 btnBackground: Style.ButtonBgColor,
45 textFont: Style.TextFont,
46 textSize: Scale(Style.TextSize),
47 onSelected: onSelected,
48 borderSize: Scale(Style.ButtonBorderSize),
49 borderTop: Style.ButtonBorderTop,
50 borderRight: Style.ButtonBorderRight,
51 borderBottom: Style.ButtonBorderBottom,
52 borderLeft: Style.ButtonBorderLeft,
53 }
54 b.SetBackground(Style.ButtonBgColor)
55 return b
56 }
57
58
59 func (b *Button) SetRect(r image.Rectangle) {
60 b.Box.rect = r
61
62 b.field.SetRect(r)
63
64 for _, w := range b.children {
65 w.SetRect(r)
66 }
67 }
68
69
70 func (b *Button) SetBorderSize(size int) {
71 b.Lock()
72 defer b.Unlock()
73
74 b.borderSize = size
75 }
76
77
78 func (b *Button) SetBorderColors(top color.RGBA, right color.RGBA, bottom color.RGBA, left color.RGBA) {
79 b.Lock()
80 defer b.Unlock()
81
82 b.borderTop = top
83 b.borderRight = right
84 b.borderBottom = bottom
85 b.borderLeft = left
86 }
87
88
89 func (b *Button) SetForeground(c color.RGBA) {
90 b.Lock()
91 defer b.Unlock()
92
93 b.field.SetForegroundColor(c)
94 }
95
96
97 func (b *Button) SetBackground(background color.RGBA) {
98 b.Lock()
99 defer b.Unlock()
100
101 b.btnBackground = background
102 b.background = background
103 }
104
105
106 func (b *Button) Text() string {
107 b.Lock()
108 defer b.Unlock()
109
110 return b.field.Text()
111 }
112
113
114 func (b *Button) SetText(text string) {
115 b.Lock()
116 defer b.Unlock()
117
118 b.field.SetText(text)
119 }
120
121
122 func (b *Button) SetFont(fnt *text.GoTextFaceSource, size int) {
123 b.Lock()
124 defer b.Unlock()
125
126 b.textFont, b.textSize = fnt, size
127 b.field.SetFont(b.textFont, b.textSize, fontMutex)
128 }
129
130
131 func (b *Button) SetHorizontal(h Alignment) {
132 b.Lock()
133 defer b.Unlock()
134
135 b.field.SetHorizontal(messeji.Alignment(h))
136 }
137
138
139 func (b *Button) SetVertical(v Alignment) {
140 b.Lock()
141 defer b.Unlock()
142
143 b.field.SetVertical(messeji.Alignment(v))
144 }
145
146
147
148 func (b *Button) Cursor() ebiten.CursorShapeType {
149 return ebiten.CursorShapePointer
150 }
151
152
153 func (b *Button) HandleKeyboard(ebiten.Key, rune) (handled bool, err error) {
154 return false, nil
155 }
156
157
158 func (b *Button) HandleMouse(cursor image.Point, pressed bool, clicked bool) (handled bool, err error) {
159 if !clicked {
160 if b.pressed && !pressed {
161 b.Lock()
162 b.pressed = false
163 b.background = b.btnBackground
164 b.Unlock()
165 }
166 return true, nil
167 }
168
169 const dim = 0.9
170 b.Lock()
171 b.pressed = true
172 b.background = color.RGBA{uint8(float64(b.btnBackground.R) * dim), uint8(float64(b.btnBackground.G) * dim), uint8(float64(b.btnBackground.B) * dim), 255}
173 onSelected := b.onSelected
174 if onSelected == nil {
175 b.Unlock()
176 return true, nil
177 }
178 b.Unlock()
179
180 return true, onSelected()
181 }
182
183
184 func (b *Button) Draw(screen *ebiten.Image) error {
185 r := b.rect
186
187
188 b.field.Draw(screen)
189
190
191 if b.borderSize != 0 {
192 if !b.pressed {
193 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+b.borderSize, r.Max.Y)).(*ebiten.Image).Fill(b.borderLeft)
194 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+b.borderSize)).(*ebiten.Image).Fill(b.borderTop)
195 screen.SubImage(image.Rect(r.Max.X-b.borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderRight)
196 screen.SubImage(image.Rect(r.Min.X, r.Max.Y-b.borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderBottom)
197 } else {
198 screen.SubImage(image.Rect(r.Max.X-b.borderSize, r.Min.Y, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderLeft)
199 screen.SubImage(image.Rect(r.Min.X, r.Max.Y-b.borderSize, r.Max.X, r.Max.Y)).(*ebiten.Image).Fill(b.borderTop)
200 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Min.X+b.borderSize, r.Max.Y)).(*ebiten.Image).Fill(b.borderRight)
201 screen.SubImage(image.Rect(r.Min.X, r.Min.Y, r.Max.X, r.Min.Y+b.borderSize)).(*ebiten.Image).Fill(b.borderBottom)
202 }
203 }
204
205 return nil
206 }
207
View as plain text