-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathui_box_modal.go
132 lines (107 loc) · 2.86 KB
/
ui_box_modal.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
package main
import (
"github.com/gdamore/tcell/v2"
)
type drawModalContent func(x, y int)
type modalInputHandler func(e *tcell.EventKey)
type modal struct {
*box
amb *amb
d drawModalContent
h modalInputHandler
c func()
coveredContent []coveredCell
log chan<- []byte
}
type coveredCell struct {
x int
y int
primary rune
combining []rune
style tcell.Style
}
// newModal builds a new modal ready for use. It requires the screen to be drawn on, an input handler, a content drawing
// function a cleanup function and a logging channel.
func newModal(s tcell.Screen, opts boxOpts, handler modalInputHandler, drawer drawModalContent, cleanup func(), log chan<- []byte) *modal {
return &modal{
box: newBox(s, opts),
d: drawer,
h: handler,
c: cleanup,
log: log,
}
}
// draw draws the modal in the center of the screen when it is activated. The return values are the top left corner of
// the modal.
func (m *modal) draw(animated bool, _, _ int) (int, int) {
m.Lock()
defer m.Unlock()
x, y := m.getXY()
if !m.active {
return x, y
}
if m.redraw != nil {
m.redraw()
}
m.drawBorders(x, y, animated)
if m.d != nil {
// Custom drawing.
m.d(x+1, y+1)
} else {
// Default drawing.
m.renderContent()
m.drawContent()
}
return x, y
}
// activate sets the active flag to true, stores the part of the screen that will be overwritten and draws the box.
func (m *modal) activate(amb *amb) <-chan struct{} {
if m.opts.needAmiibo && (amb == nil || amb.a == nil) {
m.log <- encodeStringCell("No amiibo data!")
return nil
}
m.done = make(chan struct{})
m.amb = amb
m.active = true
x, y := m.getXY()
// Check that m.coveredContent is nil to make the activate function idempotent.
if m.coveredContent == nil {
for i := 0; i <= m.width(); i++ {
for j := 0; j <= m.height(); j++ {
primary, combining, style, _ := m.s.GetContent(x+i, y+j)
m.coveredContent = append(m.coveredContent, coveredCell{x + i, y + j, primary, combining, style})
}
}
}
m.draw(false, m.opts.xPos, m.opts.yPos)
return m.done
}
// deactivate sets the active flag to false and restores the screen to the state before drawing.
func (m *modal) deactivate() {
m.active = false
m.amb = nil
if m.c != nil {
m.c()
}
for _, c := range m.coveredContent {
m.s.SetContent(c.x, c.y, c.primary, c.combining, c.style)
}
m.coveredContent = nil
m.s.Show()
m.end()
}
// handleKey will take over the event listening routine so the user can control the box.
func (m *modal) handleKey(e *tcell.EventKey) {
if m.h != nil {
// Custom input handling.
m.h(e)
} else {
// Default to scroll behavior.
m.scroll(e)
}
}
// getXY returns the x and y coordinates to start drawing from.
func (m *modal) getXY() (int, int) {
w, h := m.s.Size()
return (w - m.width()) / 2, (h - m.height()) / 2
}