-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathCore.lua
More file actions
4996 lines (4414 loc) · 202 KB
/
Core.lua
File metadata and controls
4996 lines (4414 loc) · 202 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
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
local addonName, DF = ...
-- Local caching of frequently used globals for performance
local pairs, ipairs, type, tonumber, tostring = pairs, ipairs, type, tonumber, tostring
local floor, ceil, min, max = math.floor, math.ceil, math.min, math.max
local format, sub, len, byte = string.format, string.sub, string.len, string.byte
-- Expose addon table globally
_G[addonName] = DF
-- Version - read from TOC file
local GetAddOnMetadata = C_AddOns and C_AddOns.GetAddOnMetadata or GetAddOnMetadata
DF.VERSION = GetAddOnMetadata(addonName, "Version") or "Unknown"
-- Debug flags
DF.debugEnabled = false
DF.demoMode = false
DF.demoPercent = 1
DF.initialized = false -- Set to true after frames are created and ready
-- Aura layout version: incremented when any layout-affecting setting changes.
-- Frames track the version they were last laid out with to avoid redundant work.
DF.auraLayoutVersion = 1
function DF:InvalidateAuraLayout()
DF.auraLayoutVersion = (DF.auraLayoutVersion or 0) + 1
end
-- ============================================================
-- TARGETED SLIDER UPDATE SYSTEM
-- ============================================================
-- Optimizes slider dragging by only updating the specific property being changed.
-- During slider drag: only update the one property (e.g., just frame height)
-- On slider release: perform full frame update to ensure everything is in sync
-- Debug flag for slider updates (toggle with /df debugslider)
DF.debugSliderUpdates = false
-- Track active slider dragging state
DF.sliderDragging = false
DF.sliderLightweightFunc = nil -- The lightweight update function to call during drag
DF.sliderLightweightName = nil -- Name of the lightweight function for debug
DF.sliderUpdateCallCount = 0 -- Call counter for debugging
-- Preview mode constants
local SIZE_UPDATE_INTERVAL = 0.033 -- ~30 FPS update rate for smooth dragging
local lastSizeUpdate = 0
-- Called when a slider starts being dragged
-- lightweightFunc: optional function that only updates the specific property
-- funcName: optional name for debug output
-- usePreviewMode: if true, hide frame elements for better performance
function DF:OnSliderDragStart(lightweightFunc, funcName, usePreviewMode)
DF.sliderDragging = true
DF.sliderLightweightFunc = lightweightFunc
DF.sliderLightweightName = funcName or "unknown"
DF.sliderUpdateCallCount = 0 -- Reset counter
if DF.debugSliderUpdates then
local previewStr = usePreviewMode and " |cffff00ff(PREVIEW MODE)|r" or ""
if lightweightFunc then
print("|cff00ff00[DF Slider]|r Drag START - lightweight: |cff88ff88" .. DF.sliderLightweightName .. "|r" .. previewStr)
else
print("|cff00ff00[DF Slider]|r Drag START - |cffff8888no lightweight function|r (will skip until release)" .. previewStr)
end
end
end
-- Called when a slider stops being dragged (mouse up)
function DF:OnSliderDragStop()
if DF.debugSliderUpdates then
print("|cff00ff00[DF Slider]|r Drag STOP - " .. DF.sliderUpdateCallCount .. " lightweight calls, now |cffffff00FULL UpdateAll()|r")
end
DF.sliderDragging = false
DF.sliderLightweightFunc = nil
DF.sliderLightweightName = nil
-- Perform full update now that dragging has stopped
local isRaidMode = DF.GUI and DF.GUI.SelectedMode == "raid"
if isRaidMode and DF.raidTestMode then
if DF.UpdateRaidTestFrames then
DF:UpdateRaidTestFrames()
end
if DF.UpdateAllRaidPetFrames then
DF:UpdateAllRaidPetFrames()
end
else
DF:UpdateAll()
-- UpdateAll already calls UpdateAllPetFrames
end
end
-- Called during slider value changes
-- If dragging with a lightweight function, call it directly (throttled)
-- If dragging without lightweight function, skip entirely until release
-- If not dragging, call UpdateAll directly (no throttle)
function DF:ThrottledUpdateAll()
if DF.sliderDragging then
if DF.sliderLightweightFunc then
-- During drag with lightweight function, call it (has its own throttle)
DF.sliderLightweightFunc()
end
-- If no lightweight func, just skip until release
return
end
-- Not dragging - just call UpdateAll directly
DF:UpdateAll()
end
-- ============================================================
-- LIGHTWEIGHT UPDATE FUNCTIONS
-- ============================================================
-- These update only specific properties during slider drag for performance
-- Helper to iterate frames in current mode via iterators
-- Automatically uses test frames when in test mode
local function IterateFramesInMode(mode, updateFunc)
if mode == "raid" then
-- Check for raid test mode first
if DF.raidTestMode and DF.testRaidFrames then
local raidDb = DF:GetRaidDB()
local testFrameCount = raidDb and raidDb.raidTestFrameCount or 10
for i = 1, testFrameCount do
local frame = DF.testRaidFrames[i]
if frame and frame:IsShown() then
if updateFunc(frame, i, "raid" .. i) then return end
end
end
elseif DF.IterateRaidFrames then
-- Live raid frames via iterator
DF:IterateRaidFrames(updateFunc)
end
else
-- Check for party test mode first
if DF.testMode and DF.testPartyFrames then
local db = DF:GetDB()
local testFrameCount = db and db.testFrameCount or 5
for i = 0, testFrameCount - 1 do
local frame = DF.testPartyFrames[i]
if frame and frame:IsShown() then
local unit = (i == 0) and "player" or ("party" .. i)
if updateFunc(frame, i, unit) then return end
end
end
elseif DF.IteratePartyFrames then
-- Live party frames via iterator
DF:IteratePartyFrames(updateFunc)
end
end
end
-- Update frame sizes AND layout positions
function DF:LightweightUpdateFrameSize()
-- Frame-skip throttle
local now = GetTime()
if now - lastSizeUpdate < SIZE_UPDATE_INTERVAL then
return
end
lastSizeUpdate = now
DF.sliderUpdateCallCount = DF.sliderUpdateCallCount + 1
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
if mode == "raid" then
-- Check for raid test mode
if DF.raidTestMode then
-- Full layout refresh including borders, health bars, fonts etc.
if DF.RefreshTestFramesWithLayout then
DF:RefreshTestFramesWithLayout()
end
else
-- Call real layout function for live frames
if DF.UpdateRaidLayout then
DF:UpdateRaidLayout()
end
end
else
-- Party frames - resize frame and update health bar with padding
local db = DF.db[mode]
if not db then return end
local frameWidth = db.frameWidth or 120
local frameHeight = db.frameHeight or 50
local padding = db.framePadding or 0
local function UpdateFrame(frame)
if not frame then return end
frame:SetSize(frameWidth, frameHeight)
if frame.healthBar then
frame.healthBar:ClearAllPoints()
frame.healthBar:SetPoint("TOPLEFT", frame, "TOPLEFT", padding, -padding)
frame.healthBar:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -padding, padding)
end
-- Update resource bar width to match new frame size
if db.resourceBarMatchWidth and frame.dfPowerBar and DF.ApplyResourceBarLayout then
DF:ApplyResourceBarLayout(frame)
end
end
IterateFramesInMode(mode, UpdateFrame)
-- Re-apply header settings so the container and header anchors
-- update to match the new frame dimensions during slider drag
if DF.headersInitialized and DF.ApplyHeaderSettings then
DF:ApplyHeaderSettings()
end
-- Update positioning for test frames
if DF.testMode and DF.LightweightPositionPartyTestFrames then
local testFrameCount = db.testFrameCount or 5
DF:LightweightPositionPartyTestFrames(testFrameCount)
end
-- Also update pet frames to re-center on new frame sizes
if DF.UpdateAllPetFrames then
DF:UpdateAllPetFrames(true)
end
end
end
-- Spacing/layout changes - needs to re-layout frames
function DF:LightweightUpdateFrameSpacing()
-- Frame-skip throttle
local now = GetTime()
if now - lastSizeUpdate < SIZE_UPDATE_INTERVAL then
return
end
lastSizeUpdate = now
-- Update secure headers if active (only for live frames, not test mode)
if not DF.testMode and not DF.raidTestMode then
if DF.headersInitialized and DF.ApplyHeaderSettings then
DF:ApplyHeaderSettings()
end
end
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
if mode == "raid" then
-- Check for raid test mode
if DF.raidTestMode then
-- Full layout refresh including borders, health bars, fonts etc.
if DF.RefreshTestFramesWithLayout then
DF:RefreshTestFramesWithLayout()
end
else
if DF.UpdateRaidLayout then
DF:UpdateRaidLayout()
end
end
else
-- Party mode
if DF.testMode then
-- Update test frame positioning
if DF.LightweightPositionPartyTestFrames then
local db = DF:GetDB()
local testFrameCount = db and db.testFrameCount or 5
DF:LightweightPositionPartyTestFrames(testFrameCount)
elseif DF.UpdateAllFrames then
DF:UpdateAllFrames()
end
else
-- Live frames - need to call UpdateAllFrames to recalculate positions
if DF.UpdateAllFrames then
DF:UpdateAllFrames()
end
end
-- Also update pet frames
if DF.UpdateAllPetFrames then
DF:UpdateAllPetFrames()
end
end
end
function DF:LightweightUpdateRaidLayout()
DF:LightweightUpdateFrameSize()
end
-- Update only frame alpha/opacity
function DF:LightweightUpdateAlpha()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local alpha = db.frameAlpha or 1
local bgAlpha = db.backgroundAlpha or 0.8
local bgTexture = db.backgroundTexture or "Solid"
local isTexturedBg = bgTexture ~= "Solid" and bgTexture ~= ""
local function UpdateFrameAlpha(frame)
if not frame then return end
frame:SetAlpha(alpha)
if frame.background then
local c = db.backgroundColor or {r = 0, g = 0, b = 0}
if isTexturedBg then
-- For textured backgrounds, ensure SetAlpha is 1.0 and control via vertex color only
frame.background:SetAlpha(1.0)
frame.background:SetVertexColor(c.r, c.g, c.b, bgAlpha)
else
frame.background:SetColorTexture(c.r, c.g, c.b, bgAlpha)
end
end
end
IterateFramesInMode(mode, UpdateFrameAlpha)
end
-- Update only background alpha
function DF:LightweightUpdateBackgroundAlpha()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local bgAlpha = db.backgroundAlpha or 0.8
local c = db.backgroundColor or {r = 0, g = 0, b = 0}
local bgTexture = db.backgroundTexture or "Solid"
local isTexturedBg = bgTexture ~= "Solid" and bgTexture ~= ""
local function UpdateBG(frame)
if frame and frame.background then
if isTexturedBg then
-- For textured backgrounds, ensure SetAlpha is 1.0 and control via vertex color only
frame.background:SetAlpha(1.0)
frame.background:SetVertexColor(c.r, c.g, c.b, bgAlpha)
else
frame.background:SetColorTexture(c.r, c.g, c.b, bgAlpha)
end
end
end
IterateFramesInMode(mode, UpdateBG)
end
-- Update only health bar texture
function DF:LightweightUpdateHealthTexture()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local tex = db.healthTexture or "Interface\\TargetingFrame\\UI-StatusBar"
local function UpdateTex(frame)
if frame and frame.healthBar then
frame.healthBar:SetStatusBarTexture(tex)
end
end
IterateFramesInMode(mode, UpdateTex)
end
-- Update only font shadows on all text elements
function DF:LightweightUpdateFontShadows()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local shadowX = db.fontShadowOffsetX or 1
local shadowY = db.fontShadowOffsetY or -1
local shadowColor = db.fontShadowColor or {r = 0, g = 0, b = 0, a = 1}
-- Check which elements use SHADOW outline
local nameShadow = (db.nameTextOutline == "SHADOW")
local healthShadow = (db.healthTextOutline == "SHADOW")
local statusShadow = (db.statusTextOutline == "SHADOW")
local function UpdateShadows(frame)
if not frame then return end
-- Update name text shadow
if frame.nameText then
if nameShadow then
frame.nameText:SetShadowOffset(shadowX, shadowY)
frame.nameText:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
end
-- Update health text shadow
if frame.healthText then
if healthShadow then
frame.healthText:SetShadowOffset(shadowX, shadowY)
frame.healthText:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
end
-- Update status text shadow
if frame.statusText then
if statusShadow then
frame.statusText:SetShadowOffset(shadowX, shadowY)
frame.statusText:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
end
-- Update buff/debuff duration and stack shadows
if frame.buffIcons then
local buffShadow = (db.buffDurationOutline == "SHADOW") or (db.buffStackOutline == "SHADOW")
if buffShadow then
for _, icon in ipairs(frame.buffIcons) do
if icon then
if icon.duration and (db.buffDurationOutline == "SHADOW") then
icon.duration:SetShadowOffset(shadowX, shadowY)
icon.duration:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
if icon.count and (db.buffStackOutline == "SHADOW") then
icon.count:SetShadowOffset(shadowX, shadowY)
icon.count:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
end
end
end
end
if frame.debuffIcons then
local debuffShadow = (db.debuffDurationOutline == "SHADOW") or (db.debuffStackOutline == "SHADOW")
if debuffShadow then
for _, icon in ipairs(frame.debuffIcons) do
if icon then
if icon.duration and (db.debuffDurationOutline == "SHADOW") then
icon.duration:SetShadowOffset(shadowX, shadowY)
icon.duration:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
if icon.count and (db.debuffStackOutline == "SHADOW") then
icon.count:SetShadowOffset(shadowX, shadowY)
icon.count:SetShadowColor(shadowColor.r or 0, shadowColor.g or 0, shadowColor.b or 0, shadowColor.a or 1)
end
end
end
end
end
end
IterateFramesInMode(mode, UpdateShadows)
end
-- Update only aura icon sizes
function DF:LightweightUpdateAuraSize(auraType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local size
local iconsKey
if auraType == "buff" then
size = db.buffSize or 20
iconsKey = "buffIcons"
else
size = db.debuffSize or 20
iconsKey = "debuffIcons"
end
local function UpdateIcons(frame)
if not frame or not frame[iconsKey] then return end
for _, icon in ipairs(frame[iconsKey]) do
if icon then
icon:SetSize(size, size)
end
end
end
IterateFramesInMode(mode, UpdateIcons)
end
-- Update only power/resource bar height
function DF:LightweightUpdatePowerBarSize()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local height = db.resourceBarHeight or 4
local width = db.resourceBarWidth or 50
local function UpdateBar(frame)
if frame and frame.dfPowerBar then
frame.dfPowerBar:SetHeight(height)
if not db.resourceBarMatchWidth then
frame.dfPowerBar:SetWidth(width)
end
end
end
IterateFramesInMode(mode, UpdateBar)
end
-- Update only border thickness
function DF:LightweightUpdateBorderThickness()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local thickness = db.borderThickness or 1
local function UpdateBorder(frame)
if not frame or not frame.borderTextures then return end
for _, tex in pairs(frame.borderTextures) do
if tex.isVertical then
tex:SetWidth(thickness)
else
tex:SetHeight(thickness)
end
end
end
IterateFramesInMode(mode, UpdateBorder)
end
-- Update only text font size
function DF:LightweightUpdateFontSize(textType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local function UpdateFont(frame)
if not frame then return end
if textType == "name" and frame.nameText then
local fontPath = db.nameFont or "Fonts\\FRIZQT__.TTF"
local fontOutline = db.nameTextOutline or "OUTLINE"
if fontOutline == "NONE" then fontOutline = "" end
local size = db.nameFontSize or 12
DF:SafeSetFont(frame.nameText, fontPath, size, fontOutline)
elseif textType == "health" and frame.healthText then
local fontPath = db.healthFont or "Fonts\\FRIZQT__.TTF"
local fontOutline = db.healthTextOutline or "OUTLINE"
if fontOutline == "NONE" then fontOutline = "" end
local size = db.healthFontSize or 11
DF:SafeSetFont(frame.healthText, fontPath, size, fontOutline)
elseif textType == "status" and frame.statusText then
local fontPath = db.statusTextFont or "Fonts\\FRIZQT__.TTF"
local fontOutline = db.statusTextOutline or "OUTLINE"
if fontOutline == "NONE" then fontOutline = "" end
local size = db.statusTextFontSize or 10
DF:SafeSetFont(frame.statusText, fontPath, size, fontOutline)
end
end
IterateFramesInMode(mode, UpdateFont)
end
-- Update text position
function DF:LightweightUpdateTextPosition(textType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local function UpdatePos(frame)
if not frame then return end
if textType == "name" and frame.nameText then
frame.nameText:ClearAllPoints()
local anchor = db.nameTextAnchor or "TOP"
frame.nameText:SetPoint(anchor, frame, anchor, db.nameTextX or 0, db.nameTextY or 0)
elseif textType == "health" and frame.healthText then
frame.healthText:ClearAllPoints()
local anchor = db.healthTextAnchor or "CENTER"
frame.healthText:SetPoint(anchor, frame, anchor, db.healthTextX or 0, db.healthTextY or 0)
elseif textType == "status" and frame.statusText then
frame.statusText:ClearAllPoints()
local anchor = db.statusTextAnchor or "BOTTOM"
frame.statusText:SetPoint(anchor, frame, anchor, db.statusTextX or 0, db.statusTextY or 0)
end
end
IterateFramesInMode(mode, UpdatePos)
end
-- Update icon scale/position
function DF:LightweightUpdateIconPosition(iconType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local function UpdateIcon(frame)
if not frame then return end
local icon, scale, x, y, anchor
if iconType == "role" then
icon = frame.roleIcon
scale = db.roleIconScale or 1
x = db.roleIconX or 0
y = db.roleIconY or 0
anchor = db.roleIconAnchor or "TOPLEFT"
elseif iconType == "raidTarget" then
icon = frame.raidTargetIcon
scale = db.raidTargetIconScale or 1
x = db.raidTargetIconX or 0
y = db.raidTargetIconY or 0
anchor = db.raidTargetIconAnchor or "CENTER"
elseif iconType == "readyCheck" then
icon = frame.readyCheckIcon
scale = db.readyCheckIconScale or 1
x = db.readyCheckIconX or 0
y = db.readyCheckIconY or 0
anchor = db.readyCheckIconAnchor or "CENTER"
elseif iconType == "centerStatus" then
icon = frame.centerStatusIcon
scale = db.centerStatusIconScale or 1
x = db.centerStatusIconX or 0
y = db.centerStatusIconY or 0
anchor = db.centerStatusIconAnchor or "CENTER"
elseif iconType == "leader" then
icon = frame.leaderIcon
scale = db.leaderIconScale or 1
x = db.leaderIconX or 0
y = db.leaderIconY or 0
anchor = db.leaderIconAnchor or "TOPLEFT"
elseif iconType == "summon" then
icon = frame.summonIcon
scale = db.summonIconScale or 1
x = db.summonIconX or 0
y = db.summonIconY or 0
anchor = db.summonIconAnchor or "CENTER"
elseif iconType == "resurrection" then
icon = frame.resurrectionIcon
scale = db.resurrectionIconScale or 1
x = db.resurrectionIconX or 0
y = db.resurrectionIconY or 0
anchor = db.resurrectionIconAnchor or "CENTER"
elseif iconType == "phased" then
icon = frame.phasedIcon
scale = db.phasedIconScale or 1
x = db.phasedIconX or 0
y = db.phasedIconY or 0
anchor = db.phasedIconAnchor or "TOPRIGHT"
elseif iconType == "afk" then
icon = frame.afkIcon
scale = db.afkIconScale or 1
x = db.afkIconX or 0
y = db.afkIconY or 0
anchor = db.afkIconAnchor or "CENTER"
elseif iconType == "vehicle" then
icon = frame.vehicleIcon
scale = db.vehicleIconScale or 1
x = db.vehicleIconX or 0
y = db.vehicleIconY or 0
anchor = db.vehicleIconAnchor or "BOTTOMRIGHT"
elseif iconType == "raidRole" then
icon = frame.raidRoleIcon
scale = db.raidRoleIconScale or 1
x = db.raidRoleIconX or 0
y = db.raidRoleIconY or 0
anchor = db.raidRoleIconAnchor or "BOTTOMLEFT"
end
if icon then
icon:SetScale(scale)
icon:ClearAllPoints()
icon:SetPoint(anchor, frame, anchor, x, y)
end
end
IterateFramesInMode(mode, UpdateIcon)
end
-- Lightweight alpha update for icons (no full frame rebuild)
function DF:LightweightUpdateIconAlpha(iconType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local function UpdateAlpha(frame)
if not frame then return end
local icon, alpha
if iconType == "role" then
icon = frame.roleIcon
alpha = db.roleIconAlpha or 1
elseif iconType == "raidTarget" then
icon = frame.raidTargetIcon
alpha = db.raidTargetIconAlpha or 1
elseif iconType == "readyCheck" then
icon = frame.readyCheckIcon
alpha = db.readyCheckIconAlpha or 1
elseif iconType == "leader" then
icon = frame.leaderIcon
alpha = db.leaderIconAlpha or 1
elseif iconType == "summon" then
icon = frame.summonIcon
alpha = db.summonIconAlpha or 1
elseif iconType == "resurrection" then
icon = frame.resurrectionIcon
alpha = db.resurrectionIconAlpha or 1
elseif iconType == "phased" then
icon = frame.phasedIcon
alpha = db.phasedIconAlpha or 1
elseif iconType == "afk" then
icon = frame.afkIcon
alpha = db.afkIconAlpha or 1
elseif iconType == "vehicle" then
icon = frame.vehicleIcon
alpha = db.vehicleIconAlpha or 1
elseif iconType == "raidRole" then
icon = frame.raidRoleIcon
alpha = db.raidRoleIconAlpha or 1
end
if icon then
icon:SetAlpha(alpha)
end
end
IterateFramesInMode(mode, UpdateAlpha)
end
-- Update aura position/size
function DF:LightweightUpdateAuraPosition(auraType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local iconsKey = auraType == "buff" and "buffIcons" or "debuffIcons"
local size = auraType == "buff" and (db.buffSize or 20) or (db.debuffSize or 20)
local scale = auraType == "buff" and (db.buffScale or 1) or (db.debuffScale or 1)
local alpha = auraType == "buff" and (db.buffAlpha or 1) or (db.debuffAlpha or 1)
local anchor = auraType == "buff" and (db.buffAnchor or "BOTTOMLEFT") or (db.debuffAnchor or "BOTTOMRIGHT")
local offsetX = auraType == "buff" and (db.buffOffsetX or 0) or (db.debuffOffsetX or 0)
local offsetY = auraType == "buff" and (db.buffOffsetY or 0) or (db.debuffOffsetY or 0)
local paddingX = auraType == "buff" and (db.buffPaddingX or 1) or (db.debuffPaddingX or 1)
local paddingY = auraType == "buff" and (db.buffPaddingY or 1) or (db.debuffPaddingY or 1)
local wrap = auraType == "buff" and (db.buffWrap or 4) or (db.debuffWrap or 4)
local growth = auraType == "buff" and (db.buffGrowth or "LEFT_UP") or (db.debuffGrowth or "RIGHT_UP")
local borderThickness = auraType == "buff" and (db.buffBorderThickness or 1) or (db.debuffBorderThickness or 1)
-- Apply pixel-perfect sizing to size and scale together, adjusting for border
if db.pixelPerfect then
size, scale, borderThickness = DF:PixelPerfectSizeAndScaleForBorder(size, scale, borderThickness)
end
-- Parse growth direction
local primary, secondary = strsplit("_", growth)
primary = primary or "LEFT"
secondary = secondary or "UP"
local function GetGrowthOffset(direction, iconSize, pad)
if direction == "LEFT" then
return -(iconSize + pad), 0
elseif direction == "RIGHT" then
return iconSize + pad, 0
elseif direction == "UP" then
return 0, iconSize + pad
elseif direction == "DOWN" then
return 0, -(iconSize + pad)
end
return 0, 0
end
-- Use scaled size for growth calculations (final rendered size)
local scaledSize = size * scale
local primaryX, primaryY = GetGrowthOffset(primary, scaledSize, paddingX)
local secondaryX, secondaryY = GetGrowthOffset(secondary, scaledSize, paddingY)
local function UpdateAuras(frame)
if not frame or not frame[iconsKey] then return end
for i, icon in ipairs(frame[iconsKey]) do
if icon then
local idx = i - 1
local row = math.floor(idx / wrap)
local col = idx % wrap
local x = offsetX + (col * primaryX) + (row * secondaryX)
local y = offsetY + (col * primaryY) + (row * secondaryY)
icon:SetSize(size, size)
icon:SetScale(scale)
icon:SetAlpha(alpha)
icon:ClearAllPoints()
icon:SetPoint(anchor, frame, anchor, x, y)
end
end
end
IterateFramesInMode(mode, UpdateAuras)
end
-- Update highlight thickness/inset
function DF:LightweightUpdateHighlight(highlightType)
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local function UpdateHighlight(frame)
if not frame then return end
local highlight, thickness, inset, alpha, color
if highlightType == "selection" then
highlight = frame.selectionHighlight or frame.dfSelectionHighlight
thickness = db.selectionHighlightThickness or 2
inset = db.selectionHighlightInset or 0
alpha = db.selectionHighlightAlpha or 1
color = db.selectionHighlightColor or {r = 1, g = 1, b = 1}
elseif highlightType == "hover" then
highlight = frame.hoverHighlight or frame.dfHoverHighlight
thickness = db.hoverHighlightThickness or 2
inset = db.hoverHighlightInset or 0
alpha = db.hoverHighlightAlpha or 0.8
color = db.hoverHighlightColor or {r = 1, g = 1, b = 1}
elseif highlightType == "aggro" then
highlight = frame.aggroHighlight or frame.dfAggroHighlight
thickness = db.aggroHighlightThickness or 2
inset = db.aggroHighlightInset or 0
alpha = db.aggroHighlightAlpha or 1
-- Aggro color depends on threat status - use stored color or get current threat
if frame.dfAggroColor then
color = frame.dfAggroColor
else
-- Determine color from threat status (or use tanking color for test/default)
local status = frame.unit and UnitThreatSituation(frame.unit) or 3
if db.aggroUseCustomColors then
if status == 3 then
color = db.aggroColorTanking or {r = 1, g = 0, b = 0}
elseif status == 2 then
color = db.aggroColorHighestThreat or {r = 1, g = 0.5, b = 0}
elseif status == 1 then
color = db.aggroColorHighThreat or {r = 1, g = 1, b = 0}
else
color = db.aggroColorTanking or {r = 1, g = 0, b = 0}
end
else
-- Default Blizzard colors
if status == 3 then
color = {r = 1, g = 0, b = 0}
elseif status == 2 then
color = {r = 1, g = 0.5, b = 0}
elseif status == 1 then
color = {r = 1, g = 1, b = 0}
else
color = {r = 1, g = 0, b = 0}
end
end
end
end
-- If highlight doesn't exist, call full UpdateHighlights to create it
if not highlight then
if DF.UpdateHighlights then
DF:UpdateHighlights(frame)
end
-- Re-get the highlight after creation
if highlightType == "selection" then
highlight = frame.selectionHighlight or frame.dfSelectionHighlight
elseif highlightType == "hover" then
highlight = frame.hoverHighlight or frame.dfHoverHighlight
elseif highlightType == "aggro" then
highlight = frame.aggroHighlight or frame.dfAggroHighlight
end
end
if highlight and highlight:IsShown() then
highlight:SetAlpha(alpha)
-- Update border textures - check both naming conventions
local top = highlight.top or highlight.topLine
local bottom = highlight.bottom or highlight.bottomLine
local left = highlight.left or highlight.leftLine
local right = highlight.right or highlight.rightLine
if top then
top:SetHeight(thickness)
top:ClearAllPoints()
top:SetPoint("TOPLEFT", frame, "TOPLEFT", inset, -inset)
top:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -inset, -inset)
top:SetColorTexture(color.r, color.g, color.b, 1)
end
if bottom then
bottom:SetHeight(thickness)
bottom:ClearAllPoints()
bottom:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", inset, inset)
bottom:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -inset, inset)
bottom:SetColorTexture(color.r, color.g, color.b, 1)
end
if left then
left:SetWidth(thickness)
left:ClearAllPoints()
left:SetPoint("TOPLEFT", frame, "TOPLEFT", inset, -inset)
left:SetPoint("BOTTOMLEFT", frame, "BOTTOMLEFT", inset, inset)
left:SetColorTexture(color.r, color.g, color.b, 1)
end
if right then
right:SetWidth(thickness)
right:ClearAllPoints()
right:SetPoint("TOPRIGHT", frame, "TOPRIGHT", -inset, -inset)
right:SetPoint("BOTTOMRIGHT", frame, "BOTTOMRIGHT", -inset, inset)
right:SetColorTexture(color.r, color.g, color.b, 1)
end
end
end
IterateFramesInMode(mode, UpdateHighlight)
end
-- Update power bar position
function DF:LightweightUpdatePowerBarPosition()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local anchor = db.resourceBarAnchor or "BOTTOM"
local x = db.resourceBarX or 0
local y = db.resourceBarY or 0
local function UpdateBar(frame)
if frame and frame.dfPowerBar then
frame.dfPowerBar:ClearAllPoints()
frame.dfPowerBar:SetPoint(anchor, frame, anchor, x, y)
end
end
IterateFramesInMode(mode, UpdateBar)
end
-- Update absorb bar size/position
function DF:LightweightUpdateAbsorbBar()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local width = db.absorbBarWidth or 50
local height = db.absorbBarHeight or 6
local anchor = db.absorbBarAnchor or "BOTTOM"
local x = db.absorbBarX or 0
local y = db.absorbBarY or 0
local function UpdateBar(frame)
if frame and frame.dfAbsorbBar then
frame.dfAbsorbBar:SetSize(width, height)
frame.dfAbsorbBar:ClearAllPoints()
frame.dfAbsorbBar:SetPoint(anchor, frame, anchor, x, y)
end
end
IterateFramesInMode(mode, UpdateBar)
end
-- Update heal absorb bar
function DF:LightweightUpdateHealAbsorbBar()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local width = db.healAbsorbBarWidth or 50
local height = db.healAbsorbBarHeight or 6
local anchor = db.healAbsorbBarAnchor or "BOTTOM"
local x = db.healAbsorbBarX or 0
local y = db.healAbsorbBarY or -10
local function UpdateBar(frame)
if frame and frame.dfHealAbsorbBar then
frame.dfHealAbsorbBar:SetSize(width, height)
frame.dfHealAbsorbBar:ClearAllPoints()
frame.dfHealAbsorbBar:SetPoint(anchor, frame, anchor, x, y)
end
end
IterateFramesInMode(mode, UpdateBar)
end
-- Update dispel overlay settings
function DF:LightweightUpdateDispelOverlay()
local mode = DF.GUI and DF.GUI.SelectedMode or "party"
local db = DF.db[mode]
if not db then return end
local borderSize = db.dispelBorderSize or 2
local borderInset = db.dispelBorderInset or 0
local borderAlpha = db.dispelBorderAlpha or 1
local gradientAlpha = db.dispelGradientAlpha or 0.5
local gradientIntensity = db.dispelGradientIntensity or 1.0
local gradientStyle = db.dispelGradientStyle or "FULL"
local gradientSize = db.dispelGradientSize or 0.3
local blendMode = db.dispelGradientBlendMode or "ADD"
local darkenAlpha = db.dispelGradientDarkenAlpha or 0.5
local iconSize = db.dispelIconSize or 20
local iconAlpha = db.dispelIconAlpha or 1
local iconPosition = db.dispelIconPosition or "CENTER"
local iconOffsetX = db.dispelIconOffsetX or 0
local iconOffsetY = db.dispelIconOffsetY or 0
local function UpdateDispel(frame)
if not frame or not frame.dfDispelOverlay then return end
local overlay = frame.dfDispelOverlay
-- Get current color from overlay's stored dispel type
local r, g, b = 1, 1, 1
if overlay.currentDispelType then
local dispelColors = {
Magic = db.dispelMagicColor or {r = 0, g = 0.6, b = 1},
Curse = db.dispelCurseColor or {r = 0.6, g = 0, b = 1},
Poison = db.dispelPoisonColor or {r = 0, g = 0.6, b = 0},
Disease = db.dispelDiseaseColor or {r = 0.6, g = 0.4, b = 0},
Bleed = db.dispelBleedColor or {r = 1, g = 0, b = 0},
}
local color = dispelColors[overlay.currentDispelType]
if color then
r, g, b = color.r, color.g, color.b
end
end