-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgrid_cell.go
152 lines (129 loc) · 3.39 KB
/
grid_cell.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
package main
import (
"image"
"image/color"
"math"
"strconv"
"gioui.org/f32"
"gioui.org/io/pointer"
"gioui.org/layout"
"gioui.org/op/clip"
"gioui.org/op/paint"
"gioui.org/text"
"gioui.org/widget/material"
)
var (
colorBackground = color.NRGBA{R: 165, G: 165, B: 165, A: 255}
colorHidden = color.NRGBA{R: 195, G: 195, B: 195, A: 255}
colorFlagged = color.NRGBA{G: 170, A: 255}
colorMine = color.NRGBA{R: 255, A: 255}
colorsLabels = []color.NRGBA{
{B: 255, A: 255},
{G: 255, A: 255},
{R: 255, A: 255},
{B: 255, G: 255, A: 255},
{B: 255, R: 255, A: 255},
{G: 255, R: 255, A: 255},
{B: 80, G: 130, R: 208, A: 255},
{B: 25, G: 90, R: 110, A: 255},
}
)
type GridCell struct {
th *material.Theme
idx int
hovered bool
}
func NewGridCell(th *material.Theme, idx int) *GridCell {
return &GridCell{
th: th,
idx: idx,
}
}
func (c *GridCell) Layout(gtx C) D {
// Handle events.
for _, e := range gtx.Events(c) {
if e, ok := e.(pointer.Event); ok {
switch e.Type {
case pointer.Press:
ClickedCell(c.idx, e.Buttons.Contain(pointer.ButtonSecondary))
case pointer.Enter:
c.hovered = true
case pointer.Leave:
c.hovered = false
}
}
}
// Draw.
return c.draw(gtx)
}
func (c *GridCell) draw(gtx C) layout.Dimensions {
// Retrieve our state data.
cellState := state.Cells[c.idx]
return layout.Stack{Alignment: layout.Center}.Layout(gtx,
layout.Stacked(func(gtx C) D { // Background.
// Build a grid by giving each cell a bottom right border of one pixel.
max := gtx.Constraints.Max
max.X--
max.Y--
rect := clip.Rect{Max: max}
// Push onto op stack to confine the following actions to this area.
rectArea := rect.Push(gtx.Ops)
// Define input area.
pointer.InputOp{
Tag: c,
Types: pointer.Press | pointer.Enter | pointer.Leave,
}.Add(gtx.Ops)
// Define color.
paint.ColorOp{Color: colorBackground}.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
// Finish ops on this area.
rectArea.Pop()
// Draw inner area to distinct between hidden state.
if !cellState.IsRevealed {
inset := 2
if c.hovered {
inset = 3
}
min := image.Pt(inset, inset)
max.X -= inset
max.Y -= inset
rect = clip.Rect{Min: min, Max: max}
rectArea = rect.Push(gtx.Ops)
var color = colorHidden
if cellState.IsFlagged {
color = colorFlagged
}
paint.ColorOp{Color: color}.Add(gtx.Ops)
paint.PaintOp{}.Add(gtx.Ops)
rectArea.Pop()
}
return D{Size: gtx.Constraints.Max}
}),
layout.Stacked(func(gtx C) D { // Text.
return layout.Center.Layout(gtx, func(gtx C) D {
if !cellState.IsRevealed || cellState.IsEmpty() || cellState.IsMine {
return D{}
}
label := material.H4(c.th, strconv.Itoa(int(cellState.NumAdjacentMines)))
label.Alignment = text.Middle
label.Color = colorsLabels[cellState.NumAdjacentMines-1]
return label.Layout(gtx)
})
}),
layout.Stacked(func(gtx C) D { // Mine.
if !cellState.IsMine || (!cellState.IsRevealed && !state.Lost) {
return D{}
}
return layout.Center.Layout(gtx, func(gtx C) D {
const inset = 8
min := float32(math.Min(float64(gtx.Constraints.Max.X), float64(gtx.Constraints.Max.Y))) / 2.0
circle := clip.Ellipse{
Min: f32.Pt(-min+inset, -min+inset),
Max: f32.Pt(min-inset, min-inset),
}.Op(gtx.Ops)
paint.FillShape(gtx.Ops, colorMine, circle)
return D{}
})
}),
)
}