forked from HACKERALERT/giu
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Msgbox.go
174 lines (147 loc) · 4 KB
/
Msgbox.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
package giu
import "fmt"
// DialogResult represents dialog result
// dialog resullt is bool. if OK/Yes it is true, else (Cancel/No) - false
type DialogResult bool
// dialog results
const (
DialogResultOK DialogResult = true
DialogResultCancel DialogResult = false
DialogResultYes = DialogResultOK
DialogResultNo = DialogResultCancel
)
// MsgboxButtons determines which buttons are in the dialog.
type MsgboxButtons uint8
// button sets
const (
// Yes-No question
MsgboxButtonsYesNo MsgboxButtons = 1 << iota
// Ok / Cancel dialog
MsgboxButtonsOkCancel
// info
MsgboxButtonsOk
)
// DialogResultCallback is a callback for dialogs
type DialogResultCallback func(DialogResult)
var _ Disposable = &msgboxState{}
type msgboxState struct {
title string
content string
resultCallback DialogResultCallback
buttons MsgboxButtons
open bool
}
// Dispose implements disposable interface
func (ms *msgboxState) Dispose() {
// Nothing to do here.
}
func msgboxInvokeCallback(result DialogResult, callback DialogResultCallback) {
CloseCurrentPopup()
if callback != nil {
callback(result)
}
}
func buildMsgboxButtons(buttons MsgboxButtons, callback DialogResultCallback) Layout {
switch buttons {
case MsgboxButtonsOk:
return Layout{
Button(" Ok ").OnClick(func() {
msgboxInvokeCallback(DialogResultOK, callback)
}),
}
case MsgboxButtonsOkCancel:
return Layout{
Row(
Button(" Ok ").OnClick(func() {
msgboxInvokeCallback(DialogResultOK, callback)
}),
Button("Cancel").OnClick(func() {
msgboxInvokeCallback(DialogResultCancel, callback)
}),
),
}
case MsgboxButtonsYesNo:
return Layout{
Row(
Button(" Yes ").OnClick(func() {
msgboxInvokeCallback(DialogResultYes, callback)
}),
Button(" No ").OnClick(func() {
msgboxInvokeCallback(DialogResultNo, callback)
}),
),
}
default:
return Layout{
Button(" Ok ").OnClick(func() {
msgboxInvokeCallback(DialogResultOK, callback)
}),
}
}
}
const msgboxID string = "###Msgbox"
// PrepareMsgbox should be invoked in function in the same layout level where you call g.Msgbox.
// BUG: calling this more than 1 time per frame causes unexpected
// merging msgboxes layouts (see https://github.com/HACKERALERT/giu/issues/290)
func PrepareMsgbox() Layout {
return Layout{
Custom(func() {
var state *msgboxState
// Register state.
stateRaw := Context.GetState(msgboxID)
if stateRaw == nil {
state = &msgboxState{title: "Info", content: "Content", buttons: MsgboxButtonsOk, resultCallback: nil, open: false}
Context.SetState(msgboxID, state)
} else {
state = stateRaw.(*msgboxState)
}
if state.open {
OpenPopup(msgboxID)
state.open = false
}
SetNextWindowSize(300, 0)
PopupModal(fmt.Sprintf("%s%s", state.title, msgboxID)).Layout(
Custom(func() {
// Ensure the state is valid.
Context.GetState(msgboxID)
}),
Label(state.content).Wrapped(true),
buildMsgboxButtons(state.buttons, state.resultCallback),
).Build()
}),
}
}
// MsgboxWidget represents message dialog
type MsgboxWidget struct{}
func (m *MsgboxWidget) getState() *msgboxState {
stateRaw := Context.GetState(msgboxID)
if stateRaw == nil {
panic("Msgbox is not prepared. Invoke giu.PrepareMsgbox in the end of the layout.")
}
return stateRaw.(*msgboxState)
}
// Msgbox opens message box.
// call it whenever you want to open popup with
// question / info
func Msgbox(title, content string) *MsgboxWidget {
result := &MsgboxWidget{}
state := result.getState()
state.title = title
state.content = content
state.buttons = MsgboxButtonsOk
state.resultCallback = nil
state.open = true
return result
}
// Buttons sets which buttons should be possible
func (m *MsgboxWidget) Buttons(buttons MsgboxButtons) *MsgboxWidget {
s := m.getState()
s.buttons = buttons
return m
}
// ResultCallback sets result callback
func (m *MsgboxWidget) ResultCallback(cb DialogResultCallback) *MsgboxWidget {
s := m.getState()
s.resultCallback = cb
return m
}