-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathCursor.lua
More file actions
executable file
·262 lines (224 loc) · 8.84 KB
/
Cursor.lua
File metadata and controls
executable file
·262 lines (224 loc) · 8.84 KB
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
-- Cursor Helper
-- TODO - subscribe to CURSOR_CHANGED which erases a cached cursor. the Cursor:get() caches itself for reuse
-------------------------------------------------------------------------------
-- Module Loading
-------------------------------------------------------------------------------
---@type Ufo
local ADDON_NAME, Ufo = ...
Ufo.Wormhole() -- Lua voodoo magic that replaces the current Global namespace with the Ufo object
local zebug = Zebug:new(Z_VOLUME_GLOBAL_OVERRIDE or Zebug.INFO)
---@class Cursor : UfoMixIn
---@field type string
---@field id any
---@field index number
---@field itemLink string
---@field bookType any
---@field overriddenSpellId number
---@field amount number
---@field whenWasCached number
---@field ufoType string The classname
Cursor = {
ufoType = "Cursor"
}
UfoMixIn:mixInto(Cursor)
-------------------------------------------------------------------------------
-- Data
-------------------------------------------------------------------------------
local cachedCursor
-------------------------------------------------------------------------------
-- Methods
-------------------------------------------------------------------------------
---@return Cursor
function Cursor:get()
self = self:asInstance(true)
local type, a, b, c, d = GetCursorInfo()
if type == ButtonType.ITEM then
self.id = a
self.itemLink = b
elseif type == ButtonType.SPELL then
self.id = c
self.index = a
self.bookType = b
self.overriddenSpellId = d
elseif type == ButtonType.PSPELL then
self.id = a
self.index = b
elseif type == ButtonType.MACRO then
self.id = a
elseif type == "money" then
self.amount = a
elseif type == ButtonType.MOUNT then
self.id = a
self.index = b
elseif type == "merchant" then
self.id = a
elseif type == ButtonType.PET then
self.id = a
end
self.type = type
if type then
-- this is kind of expensive... maybe reconsider
local b = ButtonDef:getFromCursor("rando", "silence")
self.name = b and b:getName()
end
cachedCursor = self
self.whenWasCached = time()
return self
end
local maxAge = 0 -- seconds. disabled this entirely because the user can click really fast
-- bypass the cache - should only need to be used by other subscribers of CURSOR_CHANGED due to race condition
function Cursor:getFresh(event)
if cachedCursor then
local age = time() - cachedCursor.whenWasCached
zebug.trace:event(event):print("age", age)
if age >= maxAge then
zebug.trace:event(event):print("clearing cache because it's too old!")
cachedCursor = nil
else
zebug.trace:event(event):print("not clearing cache. cache is young!")
end
else
zebug.trace:event(event):print("no cache to clear")
end
return self:get()
end
function Cursor:asInstance(skipPop)
if self ~= Cursor then
return self
end
if cachedCursor then
return cachedCursor
end
self = deepcopy(self, {})
self:installMyToString()
if not skipPop then
self = self:get()
end
return self
end
function Cursor:populateIfInstance()
if self.ufoType == "Cursor" and self ~= Cursor then
self:get()
end
return self -- support cmd chaining
end
function Cursor:isEmpty()
return not self:isNotEmpty()
end
function Cursor:isNotEmpty()
local type
if self == Cursor then
type = GetCursorInfo()
else
type = self.type
end
return (type or false) and true
end
function amEmpty()
return Cursor:isEmpty() and "already empty... supposedly" or ""
end
function Cursor:clear(event)
zebug.info:owner(amEmpty):event(event):print("clearing cursor and cache")
ClearCursor()
cachedCursor = nil
end
---@param btnSlotIndex number the bliz identifier for an action bar button.
---@param event string|Event custom UFO metadata describing the instigating event - good for debugging
function Cursor:dropOntoActionBar(btnSlotIndex, event)
self = self:asInstance()
zebug.info:event(event):owner(self):print("dropping onto btnSlotIndex",btnSlotIndex)
PlaceAction(btnSlotIndex)
self:populateIfInstance() -- I am now something different so find out what I am
end
---@param btnSlotIndex number the bliz identifier for an action bar button.
---@param event string|Event custom UFO metadata describing the instigating event - good for debugging
---@return Cursor, Cursor - (1) what's on the cursor now, (2) what was on the cursor before, if anything
function Cursor:pickupFromActionBar(btnSlotIndex, event)
self = self:asInstance()
local wasCursorEmpty = self:isEmpty()
zebug.info:event(event):owner(self):print("pickup from btnSlotIndex",btnSlotIndex)
PickupAction(btnSlotIndex)
return self:populateIfInstance()
end
---@param macroNameOrId string|number duh
---@param event string|Event custom UFO metadata describing the instigating event - good for debugging
function Cursor:pickupMacro(macroNameOrId, event)
-- -d-o-n-'-t- DO (see below) pickup the same macro if it's already on the cursor
-- because Bliz will spam extraneous and/or misleading CURSOR_CHANGED events which fuck up any subscribers who need accurate info.
-- For example, doing so will trigger a CURSOR_CHANGED event at which time the Bliz cursor API will report that it is empty.
-- Ok, fine, but then there is no subsequent event to indicate that the macro ever made it onto the cursor.
-- So, the Bliz API fucking lies to you and says "yep, the cursor is empty and stayed that way." Fuck you Bliz.
local isAlreadyOnCursor
local type, id = GetCursorInfo()
if type == ButtonType.MACRO then
if isNumber(macroNameOrId) then
isAlreadyOnCursor = macroNameOrId == id
else
local id2 = getMacroIndexByNameOrNil(macroNameOrId)
isAlreadyOnCursor = id2 == id
end
end
if isAlreadyOnCursor then
-- if I EditMacro(.., newIcon) a macro that is currently being dragged around by the cursor it won't display the changed icon.
-- The cursor will display the old version of the macro UNLESS I explicitly pick it up again.
-- WORSE YET, if I DON'T first ClearCursor() before PickupMacro() again, then,
-- the fucking BLIZ event dispatcher issues a single CURSOR_CHANGED event during which PickupMacro() thinks the cursor is EMPTY.
-- There is never CURSOR_CHANGED event to indicate it carries the new version of the macro. Shit kicking mutherfucking Bliz API.
zebug.info:mCross():mMoon():event(event):owner(self):print("macro",id, "is already on the cursor. NOP... errr, I mean, I must clear it first to avoid Bliz Bullshit")
ClearCursor()
--return -- nope, keep going and do the PickupMacro()
end
--zebug.info:event(event):owner(self):print("BEFORE PickupMacro()... macroNameOrId",macroNameOrId, "GetCursorInfo->",GetCursorInfo())
PickupMacro(macroNameOrId)
--zebug.info:event(event):owner(self):print("AFTER PickupMacro()... macroNameOrId",macroNameOrId, "GetCursorInfo->",GetCursorInfo())
return self:populateIfInstance()
-- TODO ---@return Cursor, Cursor : (1) what's on the cursor now; (2) what was on the cursor before, if anything
end
function Cursor:isUfoPlaceholder()
self = self:asInstance()
if self.type == ButtonType.MACRO then
local name = GetMacroInfo(self.id)
return name == PLACEHOLDER_MACRO_NAME
end
return false
end
---@return FlyoutDef
function Cursor:isUfoProxyForFlyout()
self = self:asInstance()
zebug.trace:print("type", self.type, "id", self.id)
return UfoProxy:isFlyoutOnCursor(self)
end
---@return ButtonDef
function Cursor:isUfoProxyForButton()
self = self:asInstance()
return UfoProxy:isButtonOnCursor()
end
function Cursor:clearCache(event)
zebug.trace:event(event):name("handler"):print("erasing cachedCursor")
cachedCursor = nil
end
CURSOR_CHANGED_EMPTY = "CURSOR_CHANGED_{ }"
CURSOR_CHANGED_FULL = "CURSOR_CHANGED_{#}"
function Cursor:nameMakerForCursorChanged(isCursorEmpty)
return isCursorEmpty and CURSOR_CHANGED_EMPTY or CURSOR_CHANGED_FULL
end
function Cursor:toString()
if self == Cursor then
return self:asInstance():toString()-- "CuRsOr"
else
if self:isEmpty() then
return "<Cursor: EMPTY>"
else
local name = self.name
if self.type == ButtonType.MACRO then
if name == PROXY_MACRO_NAME then
name = UfoProxy:toString()
-- name = "UfoProxy: ".. (UfoProxy:getFlyoutName() or "UnKnOwN")
elseif name == PLACEHOLDER_MACRO_NAME then
name = Placeholder:toString()
end
end
return string.format("<Cursor: %s:%s %s>", nilStr(self.type), nilStr(self.id), nilStr(name))
end
end
end