forked from michaelnpsp/Grid2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathGridUtils.lua
498 lines (466 loc) · 14.6 KB
/
GridUtils.lua
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
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
-- Misc functions
local media = LibStub("LibSharedMedia-3.0", true)
local L = LibStub:GetLibrary("AceLocale-3.0"):GetLocale("Grid2")
local Grid2 = Grid2
local select = select
local strtrim = strtrim
local type = type
local pairs = pairs
local tonumber = tonumber
local tremove = table.remove
-- Dummy function
function Grid2.Dummy()
end
-- Fetch LibSharedMedia resources
function Grid2:MediaFetch(mediatype, key, def)
return (key and media:Fetch(mediatype, key)) or (def and media:Fetch(mediatype, def))
end
-- Default Colors
do
local defaultColors = {
TRANSPARENT = {r=0,g=0,b=0,a=0},
BLACK = {r=0,g=0,b=0,a=1},
WHITE = {r=1,g=1,b=1,a=1},
}
function Grid2:MakeColor(color, default)
return color or defaultColors[default or "TRANSPARENT"]
end
Grid2.defaultColors = defaultColors
end
-- Repeating Timer Management
do
local frame = CreateFrame("Frame")
local timers = {}
local function SetDuration(self, duration)
self.animation:SetDuration(duration)
end
-- Grid2:CreateTimer(func, duration, play)
-- play=true|nil => timer running; play=false => timer paused
-- timer methods: timer:Play() timer:Stop() timer:SetDuration()
function Grid2:CreateTimer( func, duration, play )
local timer = tremove(timers)
if not timer then
timer = frame:CreateAnimationGroup()
timer.animation = timer:CreateAnimation()
timer.SetDuration = SetDuration
timer:SetLooping("REPEAT")
end
timer:SetScript("OnLoop", func)
if duration then
timer:SetDuration(duration)
if play~=false then timer:Play() end
end
return timer
end
-- Grid2:CancelTimer(timer)
function Grid2:CancelTimer( timer )
if timer then
timer:Stop()
timers[#timers+1] = timer
end
end
end
-- iterate over a list of values example: for value in Grid2.IterateValues(4,2,7,1) do
function Grid2.IterateValues(...)
local i, t = 0, {...}
return function() i = i + 1; return t[i] end
end
-- retrieve config value, falling back to default
function Grid2.GetSetupValue(condition, value, default)
if condition and value~=nil then
return value
else
return default
end
end
-- UTF8 string truncate
do
local strbyte = string.byte
function Grid2.strcututf8(s, c)
local l, i = #s, 1
while c>0 and i<=l do
local b = strbyte(s, i)
if b < 192 then i = i + 1
elseif b < 224 then i = i + 2
elseif b < 240 then i = i + 3
else i = i + 4
end
c = c - 1
end
return s:sub(1, i-1)
end
end
-- Transliterate texts, cyrilic to latin conversion
do
local gsub = string.gsub
local Cyr2Lat = {
["А"] = "A", ["а"] = "a", ["Б"] = "B", ["б"] = "b", ["В"] = "V", ["в"] = "v", ["Г"] = "G", ["г"] = "g", ["Д"] = "D", ["д"] = "d", ["Е"] = "E",
["е"] = "e", ["Ё"] = "e", ["ё"] = "e", ["Ж"] = "Zh", ["ж"] = "zh", ["З"] = "Z", ["з"] = "z", ["И"] = "I", ["и"] = "i", ["Й"] = "Y", ["й"] = "y",
["К"] = "K", ["к"] = "k", ["Л"] = "L", ["л"] = "l", ["М"] = "M", ["м"] = "m", ["Н"] = "N", ["н"] = "n", ["О"] = "O", ["о"] = "o", ["П"] = "P",
["п"] = "p", ["Р"] = "R", ["р"] = "r", ["С"] = "S", ["с"] = "s", ["Т"] = "T", ["т"] = "t", ["У"] = "U", ["у"] = "u", ["Ф"] = "F", ["ф"] = "f",
["Х"] = "Kh", ["х"] = "kh", ["Ц"] = "Ts", ["ц"] = "ts", ["Ч"] = "Ch", ["ч"] = "ch", ["Ш"] = "Sh", ["ш"] = "sh", ["Щ"] = "Shch", ["щ"] = "shch",
["Ъ"] = "", ["ъ"] = "", ["Ы"] = "Y", ["ы"] = "y", ["Ь"] = "", ["ь"] = "", ["Э"] = "E", ["э"] = "e", ["Ю"] = "Yu", ["ю"] = "yu", ["Я"] = "Ya",
["я"] = "ya"
}
function Grid2.strCyr2Lat(str)
return gsub(str, "..", Cyr2Lat)
end
end
-- Table Deep Copy used by GridDefaults.lua
function Grid2.CopyTable(src, dst)
if type(dst)~="table" then dst = {} end
for k,v in pairs(src) do
if type(v)=="table" then
dst[k] = Grid2.CopyTable(v,dst[k])
elseif dst[k]==nil then
dst[k] = v
end
end
return dst
end
-- Remove item by value in a ipairs table
function Grid2.TableRemoveByValue(t,v)
for i=#t,1,-1 do
if t[i]==v then
tremove(t, i)
return
end
end
end
-- Creates a location table, used by GridDefaults.lua
function Grid2.CreateLocation(a,b,c,d)
local p = a or "TOPLEFT"
if type(b)=="string" then
return { relPoint = p, point = b, x = c or 0, y = d or 0 }
else
return { relPoint = p, point = p, x = b or 0, y = c or 0 }
end
end
-- Common methods repository for statuses
Grid2.statusLibrary = {
IsActive = function()
return true
end,
GetColor = function(self)
local c = self.dbx.color1
return c.r, c.g, c.b, c.a
end,
GetPercent = function(self)
return self.dbx.color1.a
end,
UpdateAllUnits = function(self)
for unit in Grid2:IterateRosterUnits() do
self:UpdateIndicators(unit)
end
end,
GetTexCoord = function()
return 0.05, 0.95, 0.05, 0.95
end,
GetTexCoordZoomed = function()
return 0.08, 0.92, 0.08, 0.92
end,
}
-- Used by bar indicators
Grid2.AlignPoints= {
HORIZONTAL = {
[true] = { "TOPLEFT", "TOPRIGHT", "BOTTOMLEFT", "BOTTOMRIGHT" }, -- normal Fill
[false] = { "BOTTOMRIGHT", "BOTTOMLEFT", "TOPRIGHT", "TOPLEFT" }, -- reverse Fill
},
VERTICAL = {
[true] = { "BOTTOMLEFT","TOPLEFT","BOTTOMRIGHT","TOPRIGHT" }, -- normal Fill
[false] = { "TOPRIGHT", "BOTTOMRIGHT","TOPLEFT","BOTTOMLEFT" }, -- reverse Fill
}
}
-- Create/Manage/Sets frame backdrops
do
local format = string.format
local tostring = tostring
local backdrops = {}
-- Generates a backdrop table, reuses tables avoiding to create duplicates
function Grid2:GetBackdropTable(edgeFile, edgeSize, bgFile, tile, tileSize, inset)
inset = inset or edgeSize
local key = format("%s;%s;%d;%s;%d;%d", bgFile or "", edgeFile or "", edgeSize or -1, tostring(tile), tileSize or -1, inset or -1)
local backdrop = backdrops[key]
if not backdrop then
backdrop = {
bgFile = bgFile,
tile = tile,
tileSize = tileSize,
edgeFile = edgeFile,
edgeSize = edgeSize,
insets = { left = inset, right = inset, top = inset, bottom = inset },
}
backdrops[key] = backdrop
end
return backdrop
end
-- Sets a backdrop only if necessary to alleviate game freezes, see ticket #640
function Grid2:SetFrameBackdrop(frame, backdrop)
if backdrop~=frame.currentBackdrop then
frame:SetBackdrop(backdrop)
frame.currentBackdrop = backdrop
end
end
end
-- Grid2:RunSecure(priority, object, method, arg)
-- Queue some methods to be executed when out of combat, if we are not in combat do nothing.
-- Methods with lower priority value override the execution of methods with higher priority value.
-- Methods executed (in order of priority): ReloadProfile(1), ReloadTheme(2), ReloadLayout(3), ReloadFilter(4), FixRoster(5), UpdateSize(6), UpdateVisibility(7)
do
local sec_priority, sec_object, sec_method, sec_arg
function Grid2:PLAYER_REGEN_ENABLED()
if sec_priority then
sec_priority = nil
sec_object[sec_method](sec_object, sec_arg)
end
end
function Grid2:RunSecure(priority, object, method, arg)
if InCombatLockdown() then
if not sec_priority or priority<sec_priority then
sec_priority, sec_object, sec_method, sec_arg = priority, object, method, arg
end
return true
end
end
end
-- Grid2:RunThrottled(object or arg1, method or func, delay)
-- Delays and throttles the execution of a method or function
do
local counts = {}
function Grid2:RunThrottled(object, method, delay)
local func = object[method] or method
local count = counts[func]
counts[func] = (count or 0) + 1
if not count then
local callback
callback = function()
if counts[func]>0 then
counts[func] = 0
func(object)
C_Timer.After(delay or 0.1, callback)
else
counts[func] = nil
end
end
C_Timer.After(delay or 0.1, callback)
end
end
end
-- dispellable by player spells types tracking
do
local class, dispel, func = Grid2.playerClass, {}, nil
if Grid2.isClassic then
if class == 'DRUID' then
func = function()
dispel.Poison = IsPlayerSpell(2893) or IsPlayerSpell(8946)
dispel.Curse = IsPlayerSpell(2782)
end
elseif class == 'PALADIN' then
func = function()
dispel.Poison = IsPlayerSpell(4987) or IsPlayerSpell(1152)
dispel.Disease = IsPlayerSpell(4987) or IsPlayerSpell(1152)
dispel.Magic = IsPlayerSpell(4987)
end
elseif class == 'PRIEST' then
func = function()
dispel.Magic = IsPlayerSpell(527)
dispel.Disease = IsPlayerSpell(552) or IsPlayerSpell(528)
end
elseif class == 'SHAMAN' then
func = Grid2.isWrath and (function()
dispel.Disease = IsPlayerSpell(2870) or IsPlayerSpell(526) or IsPlayerSpell(51886)
dispel.Poison = IsPlayerSpell(526) or IsPlayerSpell(51886)
dispel.Curse = IsPlayerSpell(51886)
end) or (function()
dispel.Disease = IsPlayerSpell(2870)
dispel.Poison = IsPlayerSpell(526)
end)
elseif class == 'MAGE' then
func = function()
dispel.Curse = IsPlayerSpell(475)
end
elseif class == 'WARLOCK' then
func = function()
dispel.Magic = IsPlayerSpell(19505)
end
end
else -- retail
if class == 'DRUID' then
func = function()
dispel.Magic = IsPlayerSpell(88423)
dispel.Curse = IsPlayerSpell(88423) or IsPlayerSpell(2782)
dispel.Poison = IsPlayerSpell(88423) or IsPlayerSpell(2782)
end
elseif class == 'PALADIN' then
func = function()
dispel.Magic = IsPlayerSpell(4987)
dispel.Disease = IsPlayerSpell(4987) or IsPlayerSpell(213644)
dispel.Poison = IsPlayerSpell(4987) or IsPlayerSpell(213644)
end
elseif class == 'PRIEST' then
func = function()
dispel.Magic = IsPlayerSpell(527)
dispel.Disease = IsPlayerSpell(527) or IsPlayerSpell(213634)
end
elseif class == 'SHAMAN' then
func = function(self, event)
dispel.Magic = IsPlayerSpell(77130)
dispel.Curse = IsPlayerSpell(77130) or IsPlayerSpell(51886)
end
elseif class == 'MAGE' then
func = function()
dispel.Curse = IsPlayerSpell(475)
end
elseif class == 'WARLOCK' then
func = function()
dispel.Magic = IsPlayerSpell(115276) or IsPlayerSpell(89808)
end
elseif class == 'MONK' then
func = function()
dispel.Magic = IsPlayerSpell(115450)
dispel.Disease = IsPlayerSpell(115450) or IsPlayerSpell(218164)
dispel.Poison = IsPlayerSpell(115450) or IsPlayerSpell(218164)
end
elseif class == 'EVOKER' then
func = function()
dispel.Magic = IsPlayerSpell(360823)
dispel.Curse = IsPlayerSpell(374251)
dispel.Poison = IsPlayerSpell(360823) or IsPlayerSpell(365585)
dispel.Disease = IsPlayerSpell(374251)
end
end
end
-- publish usefull tables and methods
Grid2.debuffPlayerDispelTypes = dispel
Grid2.UpdatePlayerDispelTypes = func
end
-- Change default theme, theme = number(theme index starting in 0) or string(theme name)
function Grid2:SetDefaultTheme(theme)
local themes = self.db.profile.themes
if type(theme)~='number' then
for index,name in pairs(themes.names) do
if theme==name then theme = index; break; end
end
if type(theme)~='number' and (theme=='Default' or theme==L['Default']) then
theme = 0
end
end
if theme==0 or themes.names[theme] then
themes.enabled.default = theme
self:ReloadTheme()
return true
end
end
-- Enable or disable profiles per specialization
function Grid2:EnableProfilesPerSpec(enabled)
local db = self.profiles.char
if not enabled ~= not (db[1] and db.enabled) and not self.isClassic then
wipe(db)
db.enabled = enabled or nil
if enabled then
local pro = self.db:GetCurrentProfile()
for i=1,GetNumSpecializations() or 0 do
db[i] = pro
end
end
self:ReloadProfile()
end
end
-- Set a profile for the specified specIndex or the general profile if specIndex==nil
function Grid2:SetProfileForSpec(profileName, specIndex)
if self.db.profiles[profileName] then
if not specIndex then
self.db:SetProfile(profileName)
elseif self.profiles.char[specIndex] then
self.profiles.char[specIndex] = profileName
self:ReloadProfile()
end
end
end
-- MinimapIcon visibility: value = true | false | nil => toggle
function Grid2:SetMinimapIcon(value)
local minimapIcon = Grid2Layout.db.shared.minimapIcon
if value == nil then
minimapIcon.hide = not minimapIcon.hide
else
minimapIcon.hide = not value
end
if minimapIcon.hide then
Grid2Layout.minimapIcon:Hide("Grid2")
else
Grid2Layout.minimapIcon:Show("Grid2")
end
end
-- Hide blizzard raid & party frames
do
local hiddenFrame
local function rehide(self)
if not InCombatLockdown() then self:Hide() end
end
local function unregister(f)
if f then f:UnregisterAllEvents() end
end
local function hideFrame(frame)
if frame then
UnregisterUnitWatch(frame)
frame:Hide()
frame:UnregisterAllEvents()
frame:SetParent(hiddenFrame)
frame:HookScript("OnShow", rehide)
unregister(frame.healthbar)
unregister(frame.manabar)
unregister(frame.powerBarAlt)
unregister(frame.spellbar)
end
end
-- party frames
local function HidePartyFrames()
hiddenFrame = hiddenFrame or CreateFrame('Frame')
hiddenFrame:Hide()
if PartyFrame then
hideFrame(PartyFrame)
for frame in PartyFrame.PartyMemberFramePool:EnumerateActive() do
hideFrame(frame)
hideFrame(frame.HealthBar)
hideFrame(frame.ManaBar)
end
PartyFrame.PartyMemberFramePool:ReleaseAll()
end
hideFrame(CompactPartyFrame)
UIParent:UnregisterEvent("GROUP_ROSTER_UPDATE") -- used by compact party frame
end
-- raid frames
local function HideRaidFrames()
if not CompactRaidFrameManager then return end
local function HideFrames()
CompactRaidFrameManager:UnregisterAllEvents()
CompactRaidFrameContainer:UnregisterAllEvents()
if not InCombatLockdown() then
CompactRaidFrameManager:Hide()
local shown = CompactRaidFrameManager_GetSetting('IsShown')
if shown and shown ~= '0' then
CompactRaidFrameManager_SetSetting('IsShown', '0')
end
end
end
hiddenFrame = hiddenFrame or CreateFrame('Frame')
hiddenFrame:Hide()
hooksecurefunc('CompactRaidFrameManager_UpdateShown', HideFrames)
CompactRaidFrameManager:HookScript('OnShow', HideFrames)
CompactRaidFrameContainer:HookScript('OnShow', HideFrames)
HideFrames()
end
-- Only for dragonflight, for classic compactRaidFrames addon is disabled from options
function Grid2:UpdateBlizzardFrames()
if self.isWoW90 then
local v = self.db.profile.hideBlizzardRaidFrames
if v==true or v==2 then
HideRaidFrames()
end
if v==true or v==1 then
HidePartyFrames()
end
end
self.UpdateBlizzardFrames = nil
end
end