-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathauras.lua
More file actions
949 lines (760 loc) · 32.4 KB
/
Copy pathauras.lua
File metadata and controls
949 lines (760 loc) · 32.4 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
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
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
--[[
# Element: Auras
Handles creation and updating of aura buttons.
---@class oUFAurasElement : Frame
---@field Buffs Frame|nil Container for buff buttons
---@field Debuffs Frame|nil Container for debuff buttons
---@class oUFAuraButton : Button
---@field icon Texture Aura icon
---@field count FontString|nil Application count
---@field duration number Aura duration remaining
---@field expirationTime number Aura expiration timestamp
---@field filter string Aura filter (HELPFUL/HARMFUL)
---@field auraIndex number|nil Index in aura list
## Widget
Auras - A Frame to hold `Button`s representing both buffs and debuffs.
Buffs - A Frame to hold `Button`s representing buffs.
Debuffs - A Frame to hold `Button`s representing debuffs.
## Notes
At least one of the above widgets must be present for the element to work.
## Options
.disableMouse - Disables mouse events (boolean)
.disableCooldown - Disables the cooldown spiral (boolean)
.size - Aura button size. Defaults to 16 (number)
.width - Aura button width. Takes priority over `size` (number)
.height - Aura button height. Takes priority over `size` (number)
.onlyShowPlayer - Shows only auras created by player/vehicle (boolean)
.showStealableBuffs - Displays the stealable texture on buffs that can be stolen (boolean)
.spacing - Spacing between each button. Defaults to 0 (number)
.spacingX - Horizontal spacing between each button. Takes priority over `spacing` (number)
.spacingY - Vertical spacing between each button. Takes priority over `spacing` (number)
.growthX - Horizontal growth direction. Defaults to 'RIGHT' (string)
.growthY - Vertical growth direction. Defaults to 'UP' (string)
.initialAnchor - Anchor point for the aura buttons. Defaults to 'BOTTOMLEFT' (string)
.filter - Custom filter list for auras to display. Defaults to 'HELPFUL' for buffs and 'HARMFUL' for
debuffs (string)
.tooltipAnchor - Anchor point for the tooltip. Defaults to 'ANCHOR_BOTTOMRIGHT', however, if a frame has
anchoring restrictions it will be set to 'ANCHOR_CURSOR' (string)
.reanchorIfVisibleChanged - Reanchors aura buttons when the number of visible auras has changed (boolean)
.showType - Show Overlay texture colored by oUF.colors.dispel (boolean)
.showDebuffType - Show Overlay texture colored by oUF.colors.dispel when it's a debuff. Exclusive with .showType (boolean)
.showBuffType - Show Overlay texture colored by oUF.colors.dispel when it's a buff. Exclusive with .showType (boolean)
.minCount - Minimum number of aura applications for the Count text to be visible. Defaults to 2 (number)
.maxCount - Maximum number of aura applications for the Count text, anything above renders "*". Defaults to 999 (number)
.maxCols - Maximum number of aura button columns before wrapping to a new row. Defaults to element width divided by aura button size (number)
## Options Auras
.numBuffs - The maximum number of buffs to display. Defaults to 32 (number)
.numDebuffs - The maximum number of debuffs to display. Defaults to 40 (number)
.numTotal - The maximum number of auras to display. Prioritizes buffs over debuffs. Defaults to the sum of
.numBuffs and .numDebuffs (number)
.gap - Controls the creation of an invisible button between buffs and debuffs. Defaults to false (boolean)
.buffFilter - Custom filter list for buffs to display. Takes priority over `filter` (string)
.debuffFilter - Custom filter list for debuffs to display. Takes priority over `filter` (string)
## Options Buffs
.num - Number of buffs to display. Defaults to 32 (number)
## Options Debuffs
.num - Number of debuffs to display. Defaults to 40 (number)
## Attributes
.dispelColorCurve - Curve object with points defined for each index in oUF.colors.dispel
## Button Attributes
button.auraInstanceID - unique ID for the current aura being tracked by the button (number)
button.isHarmfulAura - indicates if the button holds a debuff (boolean)
## Examples
-- Position and size
local Buffs = CreateFrame('Frame', nil, self)
Buffs:SetPoint('RIGHT', self, 'LEFT')
Buffs:SetSize(16 * 2, 16 * 16)
-- Register with oUF
self.Buffs = Buffs
--]]
local _, ns = ...
local oUF = ns.oUF
local Private = oUF.Private
local function UpdateTooltip(self)
if(GameTooltip:IsForbidden()) then return end
GameTooltip:SetUnitAuraByAuraInstanceID(self:GetParent().__owner.unit, self.auraInstanceID)
end
local function onEnter(self)
if(GameTooltip:IsForbidden() or not self:IsVisible()) then return end
-- Avoid parenting GameTooltip to frames with anchoring restrictions,
-- otherwise it'll inherit said restrictions which will cause issues with
-- its further positioning, clamping, etc
GameTooltip:SetOwner(self, self:GetParent().__restricted and 'ANCHOR_CURSOR' or self:GetParent().tooltipAnchor)
self:UpdateTooltip()
end
local function onLeave()
if(GameTooltip:IsForbidden()) then return end
GameTooltip:Hide()
end
local function CreateButton(element, index)
local button = CreateFrame('Button', element:GetDebugName() .. 'Button' .. index, element)
local cd = CreateFrame('Cooldown', '$parentCooldown', button, 'CooldownFrameTemplate')
cd:SetAllPoints()
button.Cooldown = cd
local icon = button:CreateTexture(nil, 'BORDER')
icon:SetAllPoints()
button.Icon = icon
local countFrame = CreateFrame('Frame', nil, button)
countFrame:SetAllPoints(button)
countFrame:SetFrameLevel(cd:GetFrameLevel() + 1)
local count = countFrame:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal')
count:SetPoint('BOTTOMRIGHT', countFrame, 'BOTTOMRIGHT', -1, 0)
button.Count = count
local overlay = button:CreateTexture(nil, 'OVERLAY')
overlay:SetTexture([[Interface\Buttons\UI-Debuff-Overlays]])
overlay:SetAllPoints()
overlay:SetTexCoord(0.296875, 0.5703125, 0, 0.515625)
button.Overlay = overlay
local stealable = button:CreateTexture(nil, 'OVERLAY')
stealable:SetTexture([[Interface\TargetingFrame\UI-TargetingFrame-Stealable]])
stealable:SetPoint('TOPLEFT', -3, 3)
stealable:SetPoint('BOTTOMRIGHT', 3, -3)
stealable:SetBlendMode('ADD')
button.Stealable = stealable
button.UpdateTooltip = UpdateTooltip
button:SetScript('OnEnter', onEnter)
button:SetScript('OnLeave', onLeave)
--[[ Callback: Auras:PostCreateButton(button)
Called after a new aura button has been created.
* self - the widget holding the aura buttons
* button - the newly created aura button (Button)
--]]
if(element.PostCreateButton) then element:PostCreateButton(button) end
return button
end
local function SetPosition(element, from, to)
local width = element.width or element.size or 16
local height = element.height or element.size or 16
local sizeX = width + (element.spacingX or element.spacing or 0)
local sizeY = height + (element.spacingY or element.spacing or 0)
local anchor = element.initialAnchor or 'BOTTOMLEFT'
local growthX = (element.growthX == 'LEFT' and -1) or 1
local growthY = (element.growthY == 'DOWN' and -1) or 1
local cols = element.maxCols or math.floor(element:GetWidth() / sizeX + 0.5)
for i = from, to do
local button = element[i]
if(not button) then break end
local col = (i - 1) % cols
local row = math.floor((i - 1) / cols)
button:ClearAllPoints()
button:SetPoint(anchor, element, anchor, col * sizeX * growthX, row * sizeY * growthY)
end
end
local function updateAura(element, unit, data, position)
if(not data) then return end
local button = element[position]
if(not button) then
--[[ Override: Auras:CreateButton(position)
Used to create an aura button at a given position.
* self - the widget holding the aura buttons
* position - the position at which the aura button is to be created (number)
## Returns
* button - the button used to represent the aura (Button)
--]]
button = (element.CreateButton or CreateButton) (element, position)
table.insert(element, button)
element.createdButtons = element.createdButtons + 1
end
-- for tooltips
button.auraInstanceID = data.auraInstanceID
if(button.Cooldown and not element.disableCooldown) then
local duration = C_UnitAuras.GetAuraDuration(unit, data.auraInstanceID)
if duration then
button.Cooldown:SetCooldownFromDurationObject(duration)
button.Cooldown:Show()
else
button.Cooldown:Hide()
end
end
if(button.Overlay) then
if(element.showType or (data.isHarmfulAura and element.showDebuffType) or (not data.isHarmfulAura and element.showBuffType)) then
local color = C_UnitAuras.GetAuraDispelTypeColor(unit, data.auraInstanceID, element.dispelColorCurve)
if color == nil then
-- BUG: this shouldn't happen but color can be nil, so default to None color
color = element.dispelColorCurve:Evaluate(0)
end
button.Overlay:SetVertexColor(color:GetRGBA())
button.Overlay:Show()
else
button.Overlay:Hide()
end
end
if(button.Stealable) then
if(element.showStealableBuffs and not UnitCanCooperate('player', unit)) then
button.Stealable:SetAlphaFromBoolean(data.isStealable, 1, 0)
else
button.Stealable:SetAlpha(0)
end
end
if(button.Icon) then button.Icon:SetTexture(data.icon) end
if(button.Count) then
button.Count:SetText(C_UnitAuras.GetAuraApplicationDisplayCount(unit, data.auraInstanceID, element.minCount or 2, element.maxCount or 999))
end
local width = element.width or element.size or 16
local height = element.height or element.size or 16
button:SetSize(width, height)
button:EnableMouse(not element.disableMouse)
button:Show()
--[[ Callback: Auras:PostUpdateButton(unit, button, data, position)
Called after the aura button has been updated.
* self - the widget holding the aura buttons
* button - the updated aura button (Button)
* unit - the unit for which the update has been triggered (string)
* data - the [AuraData](https://warcraft.wiki.gg/wiki/Struct_AuraData) object (table)
* position - the actual position of the aura button (number)
--]]
if(element.PostUpdateButton) then
element:PostUpdateButton(button, unit, data, position)
end
end
local function FilterAura(element, unit, data)
if((element.onlyShowPlayer and data.isPlayerAura) or not element.onlyShowPlayer) then
return true
end
end
-- see AuraUtil.DefaultAuraCompare
local function SortAuras(a, b)
if(a.isPlayerAura ~= b.isPlayerAura) then
return a.isPlayerAura
end
return a.auraInstanceID < b.auraInstanceID
end
local function processData(element, unit, data, filter)
if(not data) then return end
data.isPlayerAura = not C_UnitAuras.IsAuraFilteredOutByInstanceID(unit, data.auraInstanceID, filter .. '|PLAYER')
data.isHarmfulAura = filter:find('HARMFUL') and true -- "isHarmful" is a secret, use a different name
--[[ Callback: Auras:PostProcessAuraData(unit, data, filter)
Called after the aura data has been processed.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
* data - [AuraData](https://warcraft.wiki.gg/wiki/Struct_AuraData) object (table)
* filter - the aura filter for this aura type
## Returns
* data - the processed aura data (table)
--]]
if(element.PostProcessAuraData) then
data = element:PostProcessAuraData(unit, data, filter)
end
return data
end
local function UpdateAuras(self, event, unit, updateInfo)
-- Unit filtering handled by SmartRegisterUnitEvent - no manual check needed
local isFullUpdate = not updateInfo or updateInfo.isFullUpdate
local auras = self.Auras
if(auras) then
isFullUpdate = auras.needFullUpdate or isFullUpdate
auras.needFullUpdate = false
--[[ Callback: Auras:PreUpdate(unit, isFullUpdate)
Called before the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
* isFullUpdate - indicates whether the element is performing a full update (boolean)
--]]
if(auras.PreUpdate) then auras:PreUpdate(unit, isFullUpdate) end
local buffsChanged = false
local numBuffs = auras.numBuffs or 32
local buffFilter = auras.buffFilter or auras.filter or 'HELPFUL'
if(type(buffFilter) == 'function') then
buffFilter = buffFilter(auras, unit)
end
local debuffsChanged = false
local numDebuffs = auras.numDebuffs or 40
local debuffFilter = auras.debuffFilter or auras.filter or 'HARMFUL'
if(type(debuffFilter) == 'function') then
debuffFilter = debuffFilter(auras, unit)
end
local numTotal = auras.numTotal or numBuffs + numDebuffs
if(isFullUpdate) then
auras.allBuffs = table.wipe(auras.allBuffs or {})
auras.activeBuffs = table.wipe(auras.activeBuffs or {})
buffsChanged = true
local slots = {C_UnitAuras.GetAuraSlots(unit, buffFilter)}
for i = 2, #slots do -- #1 return is continuationToken, we don't care about it
local data = processData(auras, unit, C_UnitAuras.GetAuraDataBySlot(unit, slots[i]), buffFilter)
auras.allBuffs[data.auraInstanceID] = data
--[[ Override: Auras:FilterAura(unit, data, filter)
Defines a custom filter that controls if the aura button should be shown.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
* data - [AuraData](https://warcraft.wiki.gg/wiki/Struct_AuraData) object (table)
* filter - the aura filter for this aura type
## Returns
* show - indicates whether the aura button should be shown (boolean)
--]]
if((auras.FilterAura or FilterAura) (auras, unit, data, buffFilter)) then
auras.activeBuffs[data.auraInstanceID] = true
end
end
auras.allDebuffs = table.wipe(auras.allDebuffs or {})
auras.activeDebuffs = table.wipe(auras.activeDebuffs or {})
debuffsChanged = true
slots = {C_UnitAuras.GetAuraSlots(unit, debuffFilter)}
for i = 2, #slots do
local data = processData(auras, unit, C_UnitAuras.GetAuraDataBySlot(unit, slots[i]), debuffFilter)
auras.allDebuffs[data.auraInstanceID] = data
if((auras.FilterAura or FilterAura) (auras, unit, data, debuffFilter)) then
auras.activeDebuffs[data.auraInstanceID] = true
end
end
else
if(updateInfo.addedAuras) then
for _, data in next, updateInfo.addedAuras do
if(not C_UnitAuras.IsAuraFilteredOutByInstanceID(unit, data.auraInstanceID, buffFilter)) then
data = processData(auras, unit, data, buffFilter)
auras.allBuffs[data.auraInstanceID] = data
if((auras.FilterAura or FilterAura) (auras, unit, data, buffFilter)) then
auras.activeBuffs[data.auraInstanceID] = true
buffsChanged = true
end
elseif(not C_UnitAuras.IsAuraFilteredOutByInstanceID(unit, data.auraInstanceID, debuffFilter)) then
data = processData(auras, unit, data, debuffFilter)
auras.allDebuffs[data.auraInstanceID] = data
if((auras.FilterAura or FilterAura) (auras, unit, data, debuffFilter)) then
auras.activeDebuffs[data.auraInstanceID] = true
debuffsChanged = true
end
end
end
end
if(updateInfo.updatedAuraInstanceIDs) then
for _, auraInstanceID in next, updateInfo.updatedAuraInstanceIDs do
if(auras.allBuffs[auraInstanceID]) then
auras.allBuffs[auraInstanceID] = processData(auras, unit, C_UnitAuras.GetAuraDataByAuraInstanceID(unit, auraInstanceID), buffFilter)
-- only update if it's actually active
if(auras.activeBuffs[auraInstanceID]) then
auras.activeBuffs[auraInstanceID] = true
buffsChanged = true
end
elseif(auras.allDebuffs[auraInstanceID]) then
auras.allDebuffs[auraInstanceID] = processData(auras, unit, C_UnitAuras.GetAuraDataByAuraInstanceID(unit, auraInstanceID), debuffFilter)
if(auras.activeDebuffs[auraInstanceID]) then
auras.activeDebuffs[auraInstanceID] = true
debuffsChanged = true
end
end
end
end
if(updateInfo.removedAuraInstanceIDs) then
for _, auraInstanceID in next, updateInfo.removedAuraInstanceIDs do
if(auras.allBuffs[auraInstanceID]) then
auras.allBuffs[auraInstanceID] = nil
if(auras.activeBuffs[auraInstanceID]) then
auras.activeBuffs[auraInstanceID] = nil
buffsChanged = true
end
elseif(auras.allDebuffs[auraInstanceID]) then
auras.allDebuffs[auraInstanceID] = nil
if(auras.activeDebuffs[auraInstanceID]) then
auras.activeDebuffs[auraInstanceID] = nil
debuffsChanged = true
end
end
end
end
end
--[[ Callback: Auras:PostUpdateInfo(unit, buffsChanged, debuffsChanged)
Called after the aura update info has been updated and filtered, but before sorting.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
* buffsChanged - indicates whether the buff info has changed (boolean)
* debuffsChanged - indicates whether the debuff info has changed (boolean)
--]]
if(auras.PostUpdateInfo) then
auras:PostUpdateInfo(unit, buffsChanged, debuffsChanged)
end
if(buffsChanged or debuffsChanged) then
local numVisible
if(buffsChanged) then
-- instead of removing auras one by one, just wipe the tables entirely
-- and repopulate them, multiple table.remove calls are insanely slow
auras.sortedBuffs = table.wipe(auras.sortedBuffs or {})
for auraInstanceID in next, auras.activeBuffs do
table.insert(auras.sortedBuffs, auras.allBuffs[auraInstanceID])
end
--[[ Override: Auras:SortBuffs(a, b)
Defines a custom sorting algorithm for ordering the auras.
Defaults to [AuraUtil.DefaultAuraCompare](https://github.com/Gethe/wow-ui-source/search?q=symbol:DefaultAuraCompare).
--]]
--[[ Override: Auras:SortAuras(a, b)
Defines a custom sorting algorithm for ordering the auras.
Defaults to [AuraUtil.DefaultAuraCompare](https://github.com/Gethe/wow-ui-source/search?q=symbol:DefaultAuraCompare).
Overridden by the more specific SortBuffs and/or SortDebuffs overrides if they are defined.
--]]
table.sort(auras.sortedBuffs, auras.SortBuffs or auras.SortAuras or SortAuras)
numVisible = math.min(numBuffs, numTotal, #auras.sortedBuffs)
for i = 1, numVisible do
updateAura(auras, unit, auras.sortedBuffs[i], i)
end
else
numVisible = math.min(numBuffs, numTotal, #auras.sortedBuffs)
end
-- do it before adding the gap because numDebuffs could end up being 0
if(debuffsChanged) then
auras.sortedDebuffs = table.wipe(auras.sortedDebuffs or {})
for auraInstanceID in next, auras.activeDebuffs do
table.insert(auras.sortedDebuffs, auras.allDebuffs[auraInstanceID])
end
--[[ Override: Auras:SortDebuffs(a, b)
Defines a custom sorting algorithm for ordering the auras.
Defaults to [AuraUtil.DefaultAuraCompare](https://github.com/Gethe/wow-ui-source/search?q=symbol:DefaultAuraCompare).
--]]
table.sort(auras.sortedDebuffs, auras.SortDebuffs or auras.SortAuras or SortAuras)
end
numDebuffs = math.min(numDebuffs, numTotal - numVisible, #auras.sortedDebuffs)
if(auras.gap and numVisible > 0 and numDebuffs > 0) then
-- adjust the number of visible debuffs if there's an overflow
if(numVisible + numDebuffs == numTotal) then
numDebuffs = numDebuffs - 1
end
-- double check and skip it if we end up with 0 after the adjustment
if(numDebuffs > 0) then
numVisible = numVisible + 1
local button = auras[numVisible]
if(not button) then
button = (auras.CreateButton or CreateButton) (auras, numVisible)
table.insert(auras, button)
auras.createdButtons = auras.createdButtons + 1
end
-- prevent the button from displaying anything
if(button.Cooldown) then button.Cooldown:Hide() end
if(button.Icon) then button.Icon:SetTexture() end
if(button.Overlay) then button.Overlay:Hide() end
if(button.Stealable) then button.Stealable:Hide() end
if(button.Count) then button.Count:SetText() end
button:EnableMouse(false)
button:Show()
--[[ Callback: Auras:PostUpdateGapButton(unit, gapButton, position)
Called after an invisible aura button has been created. Only used by Auras when the `gap` option is enabled.
* self - the widget holding the aura buttons
* unit - the unit that has the invisible aura button (string)
* gapButton - the invisible aura button (Button)
* position - the position of the invisible aura button (number)
--]]
if(auras.PostUpdateGapButton) then
auras:PostUpdateGapButton(unit, button, numVisible)
end
end
end
-- any changes to buffs will affect debuffs, so just redraw them even if nothing changed
for i = 1, numDebuffs do
updateAura(auras, unit, auras.sortedDebuffs[i], numVisible + i)
end
numVisible = numVisible + numDebuffs
local visibleChanged = false
if(numVisible ~= auras.visibleButtons) then
auras.visibleButtons = numVisible
visibleChanged = auras.reanchorIfVisibleChanged -- more convenient than auras.reanchorIfVisibleChanged and visibleChanged
end
for i = numVisible + 1, #auras do
auras[i]:Hide()
end
if(visibleChanged or auras.createdButtons > auras.anchoredButtons) then
--[[ Override: Auras:SetPosition(from, to)
Used to (re-)anchor the aura buttons.
Called when new aura buttons have been created or the number of visible buttons has changed if the
`.reanchorIfVisibleChanged` option is enabled.
* self - the widget that holds the aura buttons
* from - the offset of the first aura button to be (re-)anchored (number)
* to - the offset of the last aura button to be (re-)anchored (number)
--]]
if(visibleChanged) then
-- this is useful for when people might want centred auras, like nameplates
(auras.SetPosition or SetPosition) (auras, 1, numVisible)
else
(auras.SetPosition or SetPosition) (auras, auras.anchoredButtons + 1, auras.createdButtons)
auras.anchoredButtons = auras.createdButtons
end
end
--[[ Callback: Auras:PostUpdate(unit)
Called after the element has been updated.
* self - the widget holding the aura buttons
* unit - the unit for which the update has been triggered (string)
--]]
if(auras.PostUpdate) then auras:PostUpdate(unit) end
end
end
local buffs = self.Buffs
if(buffs) then
isFullUpdate = buffs.needFullUpdate or isFullUpdate
buffs.needFullUpdate = false
if(buffs.PreUpdate) then buffs:PreUpdate(unit, isFullUpdate) end
local buffsChanged = false
local numBuffs = buffs.num or 32
local buffFilter = buffs.filter or 'HELPFUL'
if(type(buffFilter) == 'function') then
buffFilter = buffFilter(buffs, unit)
end
if(isFullUpdate) then
buffs.all = table.wipe(buffs.all or {})
buffs.active = table.wipe(buffs.active or {})
buffsChanged = true
local slots = {C_UnitAuras.GetAuraSlots(unit, buffFilter)}
for i = 2, #slots do
local data = processData(buffs, unit, C_UnitAuras.GetAuraDataBySlot(unit, slots[i]), buffFilter)
buffs.all[data.auraInstanceID] = data
if((buffs.FilterAura or FilterAura) (buffs, unit, data, buffFilter)) then
buffs.active[data.auraInstanceID] = true
end
end
else
if(updateInfo.addedAuras) then
for _, data in next, updateInfo.addedAuras do
if(not C_UnitAuras.IsAuraFilteredOutByInstanceID(unit, data.auraInstanceID, buffFilter)) then
buffs.all[data.auraInstanceID] = processData(buffs, unit, data, buffFilter)
if((buffs.FilterAura or FilterAura) (buffs, unit, data, buffFilter)) then
buffs.active[data.auraInstanceID] = true
buffsChanged = true
end
end
end
end
if(updateInfo.updatedAuraInstanceIDs) then
for _, auraInstanceID in next, updateInfo.updatedAuraInstanceIDs do
if(buffs.all[auraInstanceID]) then
buffs.all[auraInstanceID] = processData(buffs, unit, C_UnitAuras.GetAuraDataByAuraInstanceID(unit, auraInstanceID), buffFilter)
if(buffs.active[auraInstanceID]) then
buffs.active[auraInstanceID] = true
buffsChanged = true
end
end
end
end
if(updateInfo.removedAuraInstanceIDs) then
for _, auraInstanceID in next, updateInfo.removedAuraInstanceIDs do
if(buffs.all[auraInstanceID]) then
buffs.all[auraInstanceID] = nil
if(buffs.active[auraInstanceID]) then
buffs.active[auraInstanceID] = nil
buffsChanged = true
end
end
end
end
end
if(buffs.PostUpdateInfo) then
buffs:PostUpdateInfo(unit, buffsChanged)
end
if(buffsChanged) then
buffs.sorted = table.wipe(buffs.sorted or {})
for auraInstanceID in next, buffs.active do
table.insert(buffs.sorted, buffs.all[auraInstanceID])
end
table.sort(buffs.sorted, buffs.SortBuffs or buffs.SortAuras or SortAuras)
local numVisible = math.min(numBuffs, #buffs.sorted)
for i = 1, numVisible do
updateAura(buffs, unit, buffs.sorted[i], i)
end
local visibleChanged = false
if(numVisible ~= buffs.visibleButtons) then
buffs.visibleButtons = numVisible
visibleChanged = buffs.reanchorIfVisibleChanged
end
for i = numVisible + 1, #buffs do
buffs[i]:Hide()
end
if(visibleChanged or buffs.createdButtons > buffs.anchoredButtons) then
if(visibleChanged) then
(buffs.SetPosition or SetPosition) (buffs, 1, numVisible)
else
(buffs.SetPosition or SetPosition) (buffs, buffs.anchoredButtons + 1, buffs.createdButtons)
buffs.anchoredButtons = buffs.createdButtons
end
end
if(buffs.PostUpdate) then buffs:PostUpdate(unit) end
end
end
local debuffs = self.Debuffs
if(debuffs) then
isFullUpdate = debuffs.needFullUpdate or isFullUpdate
debuffs.needFullUpdate = false
if(debuffs.PreUpdate) then debuffs:PreUpdate(unit, isFullUpdate) end
local debuffsChanged = false
local numDebuffs = debuffs.num or 40
local debuffFilter = debuffs.filter or 'HARMFUL'
if(type(debuffFilter) == 'function') then
debuffFilter = debuffFilter(debuffs, unit)
end
if(isFullUpdate) then
debuffs.all = table.wipe(debuffs.all or {})
debuffs.active = table.wipe(debuffs.active or {})
debuffsChanged = true
local slots = {C_UnitAuras.GetAuraSlots(unit, debuffFilter)}
for i = 2, #slots do
local data = processData(debuffs, unit, C_UnitAuras.GetAuraDataBySlot(unit, slots[i]), debuffFilter)
debuffs.all[data.auraInstanceID] = data
if((debuffs.FilterAura or FilterAura) (debuffs, unit, data, debuffFilter)) then
debuffs.active[data.auraInstanceID] = true
end
end
else
if(updateInfo.addedAuras) then
for _, data in next, updateInfo.addedAuras do
if(not C_UnitAuras.IsAuraFilteredOutByInstanceID(unit, data.auraInstanceID, debuffFilter)) then
debuffs.all[data.auraInstanceID] = processData(debuffs, unit, data, debuffFilter)
if((debuffs.FilterAura or FilterAura) (debuffs, unit, data, debuffFilter)) then
debuffs.active[data.auraInstanceID] = true
debuffsChanged = true
end
end
end
end
if(updateInfo.updatedAuraInstanceIDs) then
for _, auraInstanceID in next, updateInfo.updatedAuraInstanceIDs do
if(debuffs.all[auraInstanceID]) then
debuffs.all[auraInstanceID] = processData(debuffs, unit, C_UnitAuras.GetAuraDataByAuraInstanceID(unit, auraInstanceID), debuffFilter)
if(debuffs.active[auraInstanceID]) then
debuffs.active[auraInstanceID] = true
debuffsChanged = true
end
end
end
end
if(updateInfo.removedAuraInstanceIDs) then
for _, auraInstanceID in next, updateInfo.removedAuraInstanceIDs do
if(debuffs.all[auraInstanceID]) then
debuffs.all[auraInstanceID] = nil
if(debuffs.active[auraInstanceID]) then
debuffs.active[auraInstanceID] = nil
debuffsChanged = true
end
end
end
end
end
if(debuffs.PostUpdateInfo) then
debuffs:PostUpdateInfo(unit, debuffsChanged)
end
if(debuffsChanged) then
debuffs.sorted = table.wipe(debuffs.sorted or {})
for auraInstanceID in next, debuffs.active do
table.insert(debuffs.sorted, debuffs.all[auraInstanceID])
end
table.sort(debuffs.sorted, debuffs.SortDebuffs or debuffs.SortAuras or SortAuras)
local numVisible = math.min(numDebuffs, #debuffs.sorted)
for i = 1, numVisible do
updateAura(debuffs, unit, debuffs.sorted[i], i)
end
local visibleChanged = false
if(numVisible ~= debuffs.visibleButtons) then
debuffs.visibleButtons = numVisible
visibleChanged = debuffs.reanchorIfVisibleChanged
end
for i = numVisible + 1, #debuffs do
debuffs[i]:Hide()
end
if(visibleChanged or debuffs.createdButtons > debuffs.anchoredButtons) then
if(visibleChanged) then
(debuffs.SetPosition or SetPosition) (debuffs, 1, numVisible)
else
(debuffs.SetPosition or SetPosition) (debuffs, debuffs.anchoredButtons + 1, debuffs.createdButtons)
debuffs.anchoredButtons = debuffs.createdButtons
end
end
if(debuffs.PostUpdate) then debuffs:PostUpdate(unit) end
end
end
end
local function Update(self, event, unit, updateInfo)
-- Unit filtering handled by SmartRegisterUnitEvent - no manual check needed
UpdateAuras(self, event, unit, updateInfo)
-- Assume no event means someone wants to re-anchor things. This is usually
-- done by UpdateAllElements and :ForceUpdate.
if(event == 'ForceUpdate' or not event) then
local auras = self.Auras
if(auras) then
(auras.SetPosition or SetPosition) (auras, 1, auras.createdButtons)
end
local buffs = self.Buffs
if(buffs) then
(buffs.SetPosition or SetPosition) (buffs, 1, buffs.createdButtons)
end
local debuffs = self.Debuffs
if(debuffs) then
(debuffs.SetPosition or SetPosition) (debuffs, 1, debuffs.createdButtons)
end
end
end
local function ForceUpdate(element)
return Update(element.__owner, 'ForceUpdate', element.__owner.unit)
end
local function Enable(self)
if(self.Auras or self.Buffs or self.Debuffs) then
Private.SmartRegisterUnitEvent(self, 'UNIT_AURA', self.unit, UpdateAuras)
local auras = self.Auras
if(auras) then
auras.__owner = self
-- check if there's any anchoring restrictions
auras.__restricted = not pcall(self.GetCenter, self)
auras.ForceUpdate = ForceUpdate
auras.createdButtons = auras.createdButtons or 0
auras.anchoredButtons = 0
auras.visibleButtons = 0
auras.tooltipAnchor = auras.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
auras.needFullUpdate = true
if(not auras.dispelColorCurve) then
auras.dispelColorCurve = C_CurveUtil.CreateColorCurve()
auras.dispelColorCurve:SetType(Enum.LuaCurveType.Step)
for _, dispelIndex in next, oUF.Enum.DispelType do
if(self.colors.dispel[dispelIndex]) then
auras.dispelColorCurve:AddPoint(dispelIndex, self.colors.dispel[dispelIndex])
end
end
end
auras:Show()
end
local buffs = self.Buffs
if(buffs) then
buffs.__owner = self
-- check if there's any anchoring restrictions
buffs.__restricted = not pcall(self.GetCenter, self)
buffs.ForceUpdate = ForceUpdate
buffs.createdButtons = buffs.createdButtons or 0
buffs.anchoredButtons = 0
buffs.visibleButtons = 0
buffs.tooltipAnchor = buffs.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
buffs.needFullUpdate = true
if(not buffs.dispelColorCurve) then
buffs.dispelColorCurve = C_CurveUtil.CreateColorCurve()
buffs.dispelColorCurve:SetType(Enum.LuaCurveType.Step)
for _, dispelIndex in next, oUF.Enum.DispelType do
if(self.colors.dispel[dispelIndex]) then
buffs.dispelColorCurve:AddPoint(dispelIndex, self.colors.dispel[dispelIndex])
end
end
end
buffs:Show()
end
local debuffs = self.Debuffs
if(debuffs) then
debuffs.__owner = self
-- check if there's any anchoring restrictions
debuffs.__restricted = not pcall(self.GetCenter, self)
debuffs.ForceUpdate = ForceUpdate
debuffs.createdButtons = debuffs.createdButtons or 0
debuffs.anchoredButtons = 0
debuffs.visibleButtons = 0
debuffs.tooltipAnchor = debuffs.tooltipAnchor or 'ANCHOR_BOTTOMRIGHT'
debuffs.needFullUpdate = true
if(not debuffs.dispelColorCurve) then
debuffs.dispelColorCurve = C_CurveUtil.CreateColorCurve()
debuffs.dispelColorCurve:SetType(Enum.LuaCurveType.Step)
for _, dispelIndex in next, oUF.Enum.DispelType do
if(self.colors.dispel[dispelIndex]) then
debuffs.dispelColorCurve:AddPoint(dispelIndex, self.colors.dispel[dispelIndex])
end
end
end
debuffs:Show()
end
return true
end
end
local function Disable(self)
if(self.Auras or self.Buffs or self.Debuffs) then
self:UnregisterEvent('UNIT_AURA', UpdateAuras)
if(self.Auras) then self.Auras:Hide() end
if(self.Buffs) then self.Buffs:Hide() end
if(self.Debuffs) then self.Debuffs:Hide() end
end
end
oUF:AddElement('Auras', Update, Enable, Disable)