-
Notifications
You must be signed in to change notification settings - Fork 38
/
radiobutton.go
182 lines (153 loc) · 4.25 KB
/
radiobutton.go
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package duit
import (
"image"
"9fans.net/go/draw"
)
// Radiobutton is typically part of a group of radiobuttons, with exactly one of them selected. Labels are not part of the radiobutton itself.
type Radiobutton struct {
Selected bool
Disabled bool // If set, cannot be selected.
Group RadiobuttonGroup // Other radiobuttons as part of this group. If a radiobutton is selected, others in the group are unselected.
Font *draw.Font `json:"-"` // Used only to determine size of radiobutton to draw.
Value interface{} `json:"-"` // Auxiliary data.
// Called for the radiobutton in the group that is newly selected, not for the other radiobuttons in the group.
// Not called if selected with Select().
Changed func(v interface{}) (e Event) `json:"-"`
m draw.Mouse
}
var _ UI = &Radiobutton{}
// RadiobuttonGroup is the group of all possible radiobuttons of which only one can be selected.
type RadiobuttonGroup []*Radiobutton
// Selected returns the currently selected radiobutton in the group.
func (g RadiobuttonGroup) Selected() *Radiobutton {
for _, r := range g {
if r.Selected {
return r
}
}
return nil
}
func (ui *Radiobutton) font(dui *DUI) *draw.Font {
if ui.Font != nil {
return ui.Font
}
return dui.Display.DefaultFont
}
func (ui *Radiobutton) size(dui *DUI) image.Point {
return pt(2*BorderSize + ui.innerDim(dui))
}
func (ui *Radiobutton) innerDim(dui *DUI) int {
return 7 * dui.Display.DefaultFont.Height / 10
}
func (ui *Radiobutton) Layout(dui *DUI, self *Kid, sizeAvail image.Point, force bool) {
dui.debugLayout(self)
hit := image.Point{0, 1}
size := pt(2*BorderSize + 7*dui.Display.DefaultFont.Height/10).Add(hit)
self.R = rect(size)
}
func (ui *Radiobutton) Draw(dui *DUI, self *Kid, img *draw.Image, orig image.Point, m draw.Mouse, force bool) {
dui.debugDraw(self)
r := rect(pt(2*BorderSize + 7*dui.Display.DefaultFont.Height/10))
hover := m.In(r)
r = r.Add(orig)
colors := dui.Regular.Normal
color := colors.Text
if ui.Disabled {
colors = dui.Disabled
color = colors.Border
} else if hover {
colors = dui.Regular.Hover
color = colors.Border
}
hit := pt(0)
if hover && m.Buttons&1 == 1 {
hit = image.Pt(0, 1)
}
img.Draw(extendY(r, 1), colors.Background, nil, image.ZP)
r = r.Add(hit)
radius := r.Dx() / 2
img.Arc(r.Min.Add(pt(radius)), radius, radius, 0, color, image.ZP, 0, 360)
cr := r.Inset((7 * dui.Display.DefaultFont.Height / 10) / 5)
if ui.Selected {
radius = cr.Dx() / 2
img.FillArc(cr.Min.Add(pt(radius)), radius, radius, 0, color, image.ZP, 0, 360)
}
}
// Select this radiobutton from the group, unselecting the previously selected radiobutton.
// Select does not call Changed.
func (ui *Radiobutton) Select(dui *DUI) {
if ui.Disabled {
return
}
ui.Selected = true
for _, o := range ui.Group {
if o != ui {
o.Selected = false
}
dui.MarkDraw(o)
}
}
func (ui *Radiobutton) check(self *Kid, r *Result) {
ui.Selected = true
for _, r := range ui.Group {
if r != ui {
r.Selected = false
}
}
if ui.Changed != nil {
e := ui.Changed(ui.Value)
propagateEvent(self, r, e)
}
}
func (ui *Radiobutton) markDraw(dui *DUI) {
for _, o := range ui.Group {
if o != ui {
dui.MarkDraw(o)
}
}
}
func (ui *Radiobutton) Mouse(dui *DUI, self *Kid, m draw.Mouse, origM draw.Mouse, orig image.Point) (r Result) {
if ui.Disabled {
return
}
rr := rect(ui.size(dui))
hover := m.In(rr)
if hover != ui.m.In(rr) {
self.Draw = Dirty
}
if hover && ui.m.Buttons&1 != m.Buttons&1 {
self.Draw = Dirty
ui.markDraw(dui)
if m.Buttons&1 == 0 {
r.Consumed = true
ui.check(self, &r)
}
}
ui.m = m
return
}
func (ui *Radiobutton) Key(dui *DUI, self *Kid, k rune, m draw.Mouse, orig image.Point) (r Result) {
if k == ' ' {
r.Consumed = true
self.Draw = Dirty
ui.markDraw(dui)
ui.check(self, &r)
}
return
}
func (ui *Radiobutton) FirstFocus(dui *DUI, self *Kid) *image.Point {
p := ui.size(dui).Mul(3).Div(4)
return &p
}
func (ui *Radiobutton) Focus(dui *DUI, self *Kid, o UI) *image.Point {
if o != ui {
return nil
}
return ui.FirstFocus(dui, self)
}
func (ui *Radiobutton) Mark(self *Kid, o UI, forLayout bool) (marked bool) {
return self.Mark(o, forLayout)
}
func (ui *Radiobutton) Print(self *Kid, indent int) {
PrintUI("Radiobutton", self, indent)
}