-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathevent_manager.go
289 lines (271 loc) · 10.3 KB
/
event_manager.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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
package consolizer
import (
"github.com/gdamore/tcell/v2"
"github.com/supercom32/consolizer/constants"
"github.com/supercom32/consolizer/internal/memory"
"github.com/supercom32/consolizer/types"
"strings"
"time"
)
type controlIdentifierType struct {
layerAlias string
controlAlias string
controlType int
}
type eventStateType struct {
stateId int
currentlyFocusedControl controlIdentifierType
// This variable is used to keep track of items which were highlighted so that they can be
// un-highlighted later. Currently, only used by selectors and tooltips
previouslyHighlightedControl controlIdentifierType
}
var eventStateMemory eventStateType
var eventIntervalTime time.Time
func UpdatePeriodicEvents() {
elapsedTime := time.Since(eventIntervalTime)
if elapsedTime >= 500*time.Millisecond {
eventIntervalTime = time.Now()
isScreenUpdateRequired := false
if Tooltip.updateMouseEventTooltip() {
isScreenUpdateRequired = true
}
if isScreenUpdateRequired == true {
UpdateDisplay(false)
}
}
}
/*
UpdateEventQueues allows you to update all event queues so that information
such as mouse clicks, keystrokes, and other events are properly registered.
*/
func UpdateEventQueues() {
event := commonResource.screen.PollEvent()
switch event := event.(type) {
case *tcell.EventResize:
commonResource.screen.Sync()
case *tcell.EventKey:
isScreenUpdateRequired := false
var keystroke []rune
if strings.Contains(event.Name(), "Rune") {
keystroke = []rune{event.Rune()}
} else {
keystroke = []rune(strings.ToLower(event.Name()))
}
if scrollbar.updateKeyboardEventScrollbar(keystroke) {
isScreenUpdateRequired = true
}
if TextField.updateKeyboardEventTextField(keystroke) {
isScreenUpdateRequired = true
}
if textbox.UpdateKeyboardEventTextbox(keystroke) {
isScreenUpdateRequired = true
}
if Selector.updateKeyboardEventSelector(keystroke) {
isScreenUpdateRequired = true
}
if isScreenUpdateRequired == true {
UpdateDisplay(false)
}
memory.KeyboardMemory.AddKeystrokeToKeyboardBuffer(keystroke)
case *tcell.EventMouse:
mouseXLocation, mouseYLocation := event.Position()
var mouseButtonNumber uint
mouseButton := event.Buttons()
for index := uint(0); index < 8; index++ {
if int(mouseButton)&(1<<index) != 0 {
mouseButtonNumber = index + 1
}
}
wheelState := ""
if mouseButton&tcell.WheelUp != 0 {
wheelState = "Up"
} else if mouseButton&tcell.WheelDown != 0 {
wheelState = "Down"
} else if mouseButton&tcell.WheelLeft != 0 {
wheelState = "Left"
} else if mouseButton&tcell.WheelRight != 0 {
wheelState = "Right"
}
isScreenUpdateRequired := false
memory.SetMouseStatus(mouseXLocation, mouseYLocation, mouseButtonNumber, wheelState)
bringLayerToFrontIfRequired()
if moveLayerIfRequired() {
isScreenUpdateRequired = true
}
if Tooltip.updateMouseEventTooltip() {
isScreenUpdateRequired = true
}
if TextField.updateMouseEventTextField() {
isScreenUpdateRequired = true
}
if Selector.updateMouseEventSelector() {
isScreenUpdateRequired = true
}
if textbox.updateMouseEventTextbox() {
isScreenUpdateRequired = true
}
if radioButton.updateMouseEventRadioButton() {
isScreenUpdateRequired = true
}
// This is done last so that it can update itself if a Selector or scroll bar change was detected.
if Dropdown.updateDropdownStateMouse() {
isScreenUpdateRequired = true
}
if Checkbox.updateMouseEventCheckbox() {
isScreenUpdateRequired = true
}
if Button.updateButtonStates(true) {
isScreenUpdateRequired = true
}
if scrollbar.updateMouseEventScrollbar() {
buttonHistory.layerAlias = ""
buttonHistory.buttonAlias = ""
isScreenUpdateRequired = true
}
// LogInfo("mouse scrollbar" + time.Now().String())
if Selector.updateMouseEventSelector() {
isScreenUpdateRequired = true
}
// LogInfo("mouse event selector" + time.Now().String())
if textbox.updateMouseEventTextbox() {
isScreenUpdateRequired = true
}
// LogInfo("mouse event textbox" + time.Now().String())
if radioButton.updateMouseEventRadioButton() {
isScreenUpdateRequired = true
}
// LogInfo("mouse event radio" + time.Now().String())
// This is done last so that it can update itself if a Selector or scroll bar change was detected.
if Dropdown.updateDropdownStateMouse() {
isScreenUpdateRequired = true
}
// LogInfo("mouse event dropdownb")
if isScreenUpdateRequired {
UpdateDisplay(false)
}
}
}
func setFocusedControl(layerAlias string, controlAlias string, controlType int) {
eventStateMemory.currentlyFocusedControl.layerAlias = layerAlias
eventStateMemory.currentlyFocusedControl.controlAlias = controlAlias
eventStateMemory.currentlyFocusedControl.controlType = controlType
}
func isControlCurrentlyFocused(layerAlias string, controlAlias string, cellType int) bool {
if eventStateMemory.currentlyFocusedControl.layerAlias == layerAlias &&
eventStateMemory.currentlyFocusedControl.controlAlias == controlAlias &&
eventStateMemory.currentlyFocusedControl.controlType == cellType {
return true
}
return false
}
func setPreviouslyHighlightedControl(layerAlias string, controlAlias string, controlType int) {
eventStateMemory.previouslyHighlightedControl.layerAlias = layerAlias
eventStateMemory.previouslyHighlightedControl.controlAlias = controlAlias
eventStateMemory.previouslyHighlightedControl.controlType = controlType
}
/*
moveLayerIfRequired allows you to move any interactive layer that has been
captured in a drag and drop action. If the mouse buttonType is pressed over an
interactive part of a layer and not released, this method will move the
layer according to the mice's new position. In addition, the following
information should be noted:
- If the layer being moved causes the top row of characters (the interactive
title bar of a layer) to fall outside the parent layers visible area, then
no movement is performed. This is done so that it is impossible to move
a window off-screen where it can never be grabbed again.
*/
func moveLayerIfRequired() bool {
isScreenUpdateRequired := false
mouseXLocation, mouseYLocation, buttonPressed, _ := memory.GetMouseStatus()
previousMouseXLocation, previousMouseYLocation, previousButtonPressed, _ := memory.GetPreviousMouseStatus()
if buttonPressed != 0 {
characterEntry := getCellInformationUnderMouseCursor(mouseXLocation, mouseYLocation)
if previousButtonPressed != 0 && eventStateMemory.stateId == constants.EventStateDragAndDrop && isLayerExists(eventStateMemory.currentlyFocusedControl.layerAlias) {
xMove := mouseXLocation - previousMouseXLocation
yMove := mouseYLocation - previousMouseYLocation
MoveLayerByRelativeValue(eventStateMemory.currentlyFocusedControl.layerAlias, xMove, yMove)
if isInteractiveLayerOffscreen(eventStateMemory.currentlyFocusedControl.layerAlias) {
MoveLayerByRelativeValue(eventStateMemory.currentlyFocusedControl.layerAlias, -xMove, -yMove)
}
isScreenUpdateRequired = true
}
if characterEntry.AttributeEntry.CellType == constants.CellTypeFrameTop {
eventStateMemory.stateId = constants.EventStateDragAndDrop
eventStateMemory.currentlyFocusedControl.layerAlias = characterEntry.LayerAlias
}
} else {
eventStateMemory.stateId = 0
}
return isScreenUpdateRequired
}
/*
bringLayerToFrontIfRequired allows you to bring a layer to the front of the
visible display area if the layer being clicked is focusable.
*/
func bringLayerToFrontIfRequired() {
mouseXLocation, mouseYLocation, buttonPressed, _ := memory.GetMouseStatus()
if buttonPressed != 0 {
characterEntry := getCellInformationUnderMouseCursor(mouseXLocation, mouseYLocation)
if characterEntry.LayerAlias == "" {
return
}
buttonHistory.layerAlias = ""
buttonHistory.buttonAlias = ""
// Protect against layer deletions.
if !memory.IsLayerExists(characterEntry.LayerAlias) {
return
}
layerEntry := memory.GetLayer(characterEntry.LayerAlias)
if layerEntry.IsFocusable == true {
return
}
layerAlias, previousLayerAlias := memory.GetRootParentLayerAlias(characterEntry.LayerAlias, "")
memory.SetHighestZOrderNumber(previousLayerAlias, layerAlias)
}
}
/*
isInteractiveLayerOffscreen allows you to detect if a layer has been moved
off-screen or not. This is useful for when you want to constrain a window
from moving off-screen because it would be impossible for the user to drag
it back to the visible viewing area. In addition, the following
information should be noted:
- This method only considers a layer off-screen if the top row of characters
are not visible (the interactive title bar of a layer).
- Layers that are moved to the far left are considered off-screen when only
two character spaces remain. This constraint is triggered two spaces early
to account for window drop shadows that are not part of the interactive
area.
- If a layer has a parent alias, then the constraining area is set to the
parent layer dimensions instead of the terminal window dimensions.
*/
func isInteractiveLayerOffscreen(layerAlias string) bool {
layerEntry := memory.GetLayer(layerAlias)
viewportWidth := commonResource.terminalWidth
viewportHeight := commonResource.terminalHeight
if layerEntry.ParentAlias != "" {
parentEntry := memory.GetLayer(layerEntry.ParentAlias)
viewportWidth = parentEntry.Width
viewportHeight = parentEntry.Height
}
if !(layerEntry.ScreenXLocation < viewportWidth && layerEntry.ScreenXLocation+layerEntry.Width-2 > 0) ||
!(layerEntry.ScreenYLocation >= 0 && layerEntry.ScreenYLocation < viewportHeight) {
return true
}
return false
}
/*
getButtonClickIdentifier allows you to obtain the layer alias and the buttonType
alias for the text cell currently under the mouse cursor. This is useful
for determining which buttonType the user has clicked (if any).
*/
func getCellInformationUnderMouseCursor(mouseXLocation int, mouseYLocation int) types.CharacterEntryType {
var characterEntry types.CharacterEntryType
layerEntry := commonResource.screenLayer
mouseYLocationOnLayer := mouseYLocation - layerEntry.ScreenYLocation
mouseXLocationOnLayer := mouseXLocation - layerEntry.ScreenXLocation
if mouseYLocationOnLayer >= 0 && mouseXLocationOnLayer >= 0 &&
mouseYLocationOnLayer < len(layerEntry.CharacterMemory) && mouseXLocationOnLayer < len(layerEntry.CharacterMemory[0]) {
characterEntry = layerEntry.CharacterMemory[mouseYLocation-layerEntry.ScreenYLocation][mouseXLocation-layerEntry.ScreenXLocation]
}
return characterEntry
}