Repository navigation
Expand file tree
/
Copy pathConfig.lua
More file actions
1183 lines (1080 loc) · 48.1 KB
/
Copy pathConfig.lua
File metadata and controls
1183 lines (1080 loc) · 48.1 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
---------------------------------------------------------
-- CastCount - Config window
-- Author: Dranged
---------------------------------------------------------
-- /castcount opens it. Tabs: Buttons (the picker), Blacklist, Appearance, Visibility, Conditions.
local ADDON, CC = ...
local UI = CC.UI
local Color = CC.Color
local W, H = 680, 500
local win
local pages, tabButtons = {}, {}
local current = "buttons"
local TABS = {
{ key = "buttons", label = "Buttons" },
{ key = "blacklist", label = "Blacklist" },
{ key = "text", label = "Appearance" },
{ key = "visibility", label = "Visibility" },
{ key = "conditions", label = "Conditions" },
}
-- Tabs where every selected count shows, whatever the visibility settings say.
local PREVIEW = { blacklist = true, text = true, conditions = true }
local function Version()
local get = (C_AddOns and C_AddOns.GetAddOnMetadata) or GetAddOnMetadata
return get and get(ADDON, "Version") or ""
end
local function Heading(page, text, x, y)
local fs = UI.Text(page, text, "GameFontNormal")
fs:SetPoint("TOPLEFT", x, y)
return fs
end
local function Note(page, text, x, y, w)
local fs = UI.Text(page, text, "GameFontHighlightSmall")
fs:SetPoint("TOPLEFT", x, y)
fs:SetWidth(w or 640)
fs:SetTextColor(0.75, 0.75, 0.75)
return fs
end
local function Refresher(fn) return UI.Track({ Refresh = fn }) end
local function Changed()
CC.MarkDirty()
end
---------------------------------------------------------
-- SECTION: Buttons tab
---------------------------------------------------------
local builders = {}
function builders.buttons(p)
local W = 652 -- page width
local function Centered(parent, text, font, y, width)
local fs = UI.Text(parent, text, font)
fs:SetPoint("TOP", parent, "TOP", 0, y)
fs:SetWidth(width or 560)
fs:SetJustifyH("CENTER")
return fs
end
-- What CastCount does, at the top.
Centered(p, "Choose your buttons", "GameFontNormalLarge", -16)
Centered(p, "CastCount shows how many times you can cast a spell with your current mana, right on "
.. "your action buttons. Pick the buttons you want counts on; every other button stays as it is.",
"GameFontHighlight", -44, 540)
-- How Button Mode works, in a panel in the middle.
local box = CreateFrame("Frame", nil, p, "BackdropTemplate")
box:SetSize(520, 118)
box:SetPoint("TOP", 0, -100)
UI.Backdrop(box, 0.08, 0.08, 0.09, 0.9)
local lines = {
{ "Choose buttons opens CastCount Button Mode. Then, on your action buttons:", 0 },
{ "|cffffd100Click|r to add/remove CastCount on the action button", 16 },
{ "|cffffd100Shift+Click|r to add/remove CastCount on the whole action bar", 16 },
{ "Already selected buttons are |cff33ff55green|r.", 0 },
}
local y = -14
for _, line in ipairs(lines) do
local fs = UI.Text(box, line[1])
fs:SetPoint("TOPLEFT", 18 + line[2], y)
y = y - 24
end
-- The button itself, centred under its heading.
Centered(p, "Choose which action buttons show a cast count", "GameFontNormal", -250)
local choose = UI.Button(p, "Choose buttons", 190, 28, function() CC.StartButtonMode() end)
choose:SetPoint("TOP", 0, -274)
local foot = Centered(p, "Works with Blizzard's action bars and EllesmereUI. Your selection is saved per character. "
.. "You can also type /cc buttons.", "GameFontHighlightSmall", -372, W - 40)
foot:SetTextColor(0.75, 0.75, 0.75)
end
---------------------------------------------------------
-- SECTION: Blacklist tab
---------------------------------------------------------
function builders.blacklist(p)
local COLW, ROWS, ROWH = 280, 14, 20
local RIGHT_X = COLW + 60
local source, manaOnly = "all", true
local known = {}
local leftList, rightList, rightSelName
local Rebuild
local function Add(e)
if not e then return end
CC.char.blacklist[e.name] = e.id or true
leftList.selected = nil
Rebuild()
Changed()
end
local function Remove(e)
if not e then return end
CC.char.blacklist[e.name] = nil
rightSelName = nil
Rebuild()
Changed()
end
Heading(p, "Your spells", 0, 0)
local search = CreateFrame("EditBox", nil, p, "InputBoxTemplate")
search:SetSize(COLW - 6, 20)
search:SetPoint("TOPLEFT", 6, -20)
search:SetAutoFocus(false)
local hint = UI.Text(search, "Search...", "GameFontDisable")
hint:SetPoint("LEFT", 2, 0)
search:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
search:SetScript("OnEnterPressed", function(self) self:ClearFocus() end)
local sourceDD = UI.Dropdown(p, 160, function()
return {
{ value = "all", label = "All known spells" },
{ value = "bars", label = "On my action bars" },
}
end, function() return source end, function(v) source = v; Rebuild() end)
sourceDD:SetPoint("TOPLEFT", 0, -46)
local manaCB = UI.Check(p, "Mana spells only", function() return manaOnly end,
function(v) manaOnly = v; Rebuild() end)
manaCB:SetPoint("TOPLEFT", 168, -45)
local function RenderLeft(row, e)
local label = e.name
if e.onBars and source == "all" then label = label .. " |cff888888(on bars)|r" end
UI.RenderRow(row, label, e.icon)
if e.mana then row.text:SetTextColor(1, 1, 1) else row.text:SetTextColor(0.6, 0.6, 0.6) end
end
local function RenderRight(row, e)
UI.RenderRow(row, e.name, e.icon)
row.text:SetTextColor(1, 1, 1)
end
leftList = UI.List(p, COLW, ROWH, ROWS, RenderLeft, function(list, e)
list.selected = e
list:Update()
end)
leftList:SetPoint("TOPLEFT", 0, -74)
leftList.onDouble = function(_, e) Add(e) end
Heading(p, "Blacklist: never show a count", RIGHT_X, 0)
Note(p, "Blacklisting a spell covers all of its ranks.", RIGHT_X, -24, COLW)
rightList = UI.List(p, COLW, ROWH, ROWS, RenderRight, function(list, e)
list.selected = e
rightSelName = e.name
list:Update()
end)
rightList:SetPoint("TOPLEFT", RIGHT_X, -74)
rightList.onDouble = function(_, e) Remove(e) end
local toRight = UI.Button(p, ">", 36, 26, function() Add(leftList.selected) end)
toRight:SetPoint("TOPLEFT", COLW + 12, -150)
local toLeft = UI.Button(p, "<", 36, 26, function() Remove(rightList.selected) end)
toLeft:SetPoint("TOPLEFT", COLW + 12, -186)
Note(p, "Select a spell and use the arrows, or double-click it to move it across. "
.. "Grey spells don't cost mana, so they never show a count anyway.", 0, -370, 620)
Rebuild = function()
local filter = (search:GetText() or ""):lower()
hint:SetShown(filter == "" and not search:HasFocus())
local left = {}
for _, e in ipairs(known) do
if not CC.char.blacklist[e.name]
and (source == "all" or e.onBars)
and (not manaOnly or e.mana)
and (filter == "" or e.name:lower():find(filter, 1, true)) then
left[#left + 1] = e
end
end
leftList:SetData(left)
local right = {}
for name, id in pairs(CC.char.blacklist) do
right[#right + 1] = { name = name, id = id, icon = CC.SpellIcon(type(id) == "number" and id or nil) }
end
table.sort(right, function(a, b) return a.name < b.name end)
rightList.selected = nil
rightList:SetData(right)
for _, e in ipairs(right) do
if e.name == rightSelName then rightList.selected = e end
end
rightList:Update()
end
search:SetScript("OnTextChanged", function() Rebuild() end)
search:SetScript("OnEditFocusGained", function() hint:Hide() end)
search:SetScript("OnEditFocusLost", function() Rebuild() end)
p:SetScript("OnShow", function()
known = CC.KnownSpells()
Rebuild()
end)
CC.On("SPELLS_CHANGED", function()
if p:IsVisible() then
known = CC.KnownSpells()
Rebuild()
end
end)
end
---------------------------------------------------------
-- SECTION: Text tab
---------------------------------------------------------
local ANCHORS = {
{ value = "TOPLEFT", label = "Top left" },
{ value = "TOP", label = "Top" },
{ value = "TOPRIGHT", label = "Top right" },
{ value = "LEFT", label = "Left" },
{ value = "CENTER", label = "Centre" },
{ value = "RIGHT", label = "Right" },
{ value = "BOTTOMLEFT", label = "Bottom left" },
{ value = "BOTTOM", label = "Bottom" },
{ value = "BOTTOMRIGHT", label = "Bottom right" },
}
local function LookItems()
local items = {}
for _, key in ipairs(CC.LOOKS) do items[#items + 1] = { value = key, label = CC.LOOK_LABELS[key] } end
items[#items + 1] = { value = "fill", label = "ManaFill" }
return items
end
-- The spell icon and size of the first selected mana-spell button, for the preview.
local function PreviewSource()
for name in pairs(CC.char.buttons) do
local btn = _G[name]
local spell = type(btn) == "table" and btn.GetObjectType and CC.ButtonSpell(btn)
if spell and CC.SpellCost(spell) == "mana" then
local w = btn:GetWidth()
return CC.SpellIcon(spell), (w and w > 10) and w or 45
end
end
return "Interface\\Icons\\Spell_Frost_FrostBolt02", 45
end
local PREVIEW_LABELS = { normal = "Default", low = "Low", oom = "Out of mana", free = "Free", fill = "ManaFill" }
-- A clickable mock action button showing a count in one look.
local function PreviewButton(parent, onClick)
local b = CreateFrame("Button", nil, parent, "BackdropTemplate")
UI.Backdrop(b, 0, 0, 0, 1, 0, 0, 0, 1)
b.sel = parent:CreateTexture(nil, "BORDER")
b.sel:SetColorTexture(1, 0.82, 0, 1)
b.sel:SetPoint("TOPLEFT", b, "TOPLEFT", -3, 3)
b.sel:SetPoint("BOTTOMRIGHT", b, "BOTTOMRIGHT", 3, -3)
b.sel:Hide()
b.icon = b:CreateTexture(nil, "ARTWORK")
b.icon:SetPoint("TOPLEFT", 1, -1)
b.icon:SetPoint("BOTTOMRIGHT", -1, 1)
b.icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
b.fill = CreateFrame("StatusBar", nil, b)
b.fill:SetPoint("TOPLEFT", 2, -2)
b.fill:SetPoint("BOTTOMRIGHT", -2, 2)
b.fill:SetOrientation("VERTICAL")
b.fill:SetFrameLevel(b:GetFrameLevel() + 1)
b.fill:SetMinMaxValues(0, 1)
b.fill:SetValue(0.6)
b.holder = CreateFrame("Frame", nil, b)
b.holder:SetAllPoints(b)
b.holder:SetFrameLevel(b:GetFrameLevel() + 2)
b.fs = b.holder:CreateFontString(nil, "OVERLAY")
b:SetHighlightTexture(UI.WHITE)
local hl = b:GetHighlightTexture()
hl:SetVertexColor(1, 1, 1)
hl:SetAlpha(0.12)
b:SetScript("OnClick", onClick)
return b
end
function builders.text(p)
local editing = "normal"
local function L() return CC.db.looks[editing] or CC.db.looks.normal end
local UpdatePreview
-- Restyle the real buttons and the preview together.
local function StyleChanged()
CC.ApplyStyle()
if UpdatePreview then UpdatePreview() end
end
local function Select(key)
editing = key
UI.RefreshAll()
end
-- Title naming the look being edited, so it's always clear which one the settings change.
local lookTitle = UI.Text(p, "", "GameFontNormalLarge")
lookTitle:SetPoint("TOPLEFT", 0, -2)
local styleLabel = UI.Text(p, "Edit:", "GameFontNormal")
styleLabel:SetPoint("TOPLEFT", 0, -30)
local which = UI.Dropdown(p, 160, LookItems, function() return editing end, Select)
which:SetPoint("TOPLEFT", 44, -26)
-- Copies one look's style onto another, keeping the target's colour (and the
-- Free look's own text).
local function CopyLook(from, to)
local keep = CC.db.looks[to]
local look = CC.CopyDeep(CC.db.looks[from])
look.color, look.text = keep.color, keep.text
-- The Free look keeps its own font when the new one can't draw its text.
if keep.text and not CC.FontCanDraw(CC.FontPath(look.font), keep.text) then look.font = keep.font end
CC.db.looks[to] = look
end
local function Tip(button, title, text)
button:SetScript("OnEnter", function(self)
GameTooltip:SetOwner(self, "ANCHOR_TOP")
GameTooltip:AddLine(title, 1, 1, 1)
GameTooltip:AddLine(text, nil, nil, nil, true)
GameTooltip:Show()
end)
button:SetScript("OnLeave", function() GameTooltip:Hide() end)
end
local copy = UI.Button(p, "Copy Default", 100, 22, function()
CopyLook("normal", editing)
StyleChanged()
UI.RefreshAll()
end)
copy:SetPoint("LEFT", which, "RIGHT", 10, 0)
Tip(copy, "Copy Default", "Gives this look the Default look's font, size, outline, shadow and position. Its colour stays.")
StaticPopupDialogs["CASTCOUNT_APPLY_LOOK"] = {
text = "Apply the %s look's font, size, outline, shadow and position to every other look?\n\nColours stay as they are.",
button1 = YES, button2 = NO,
OnAccept = function(_, from)
for _, key in ipairs(CC.LOOKS) do
if key ~= from then CopyLook(from, key) end
end
StyleChanged()
UI.RefreshAll()
end,
timeout = 0, whileDead = true, hideOnEscape = true,
}
local applyAll = UI.Button(p, "Apply to all", 100, 22, function()
local dialog = StaticPopup_Show("CASTCOUNT_APPLY_LOOK", CC.LOOK_LABELS[editing])
if dialog then dialog.data = editing end
end)
Tip(applyAll, "Apply to all looks", "Gives every other look this look's font, size, outline, shadow and position. Each keeps its own colour.")
-- When each look applies.
local lowRow = CreateFrame("Frame", nil, p)
lowRow:SetSize(400, 22)
lowRow:SetPoint("TOPLEFT", 0, -56)
local lowText = UI.Text(lowRow, "Use this look from 1 up to")
lowText:SetPoint("LEFT", 0, 0)
local lowAt = UI.Edit(lowRow, 36, true, function() return CC.db.lowAt end,
function(v) CC.db.lowAt = v; StyleChanged() end)
lowAt:SetPoint("LEFT", lowText, "RIGHT", 10, 0)
local lowText2 = UI.Text(lowRow, "casts left (0 turns it off)")
lowText2:SetPoint("LEFT", lowAt, "RIGHT", 6, 0)
local freeRow = CreateFrame("Frame", nil, p)
freeRow:SetSize(440, 22)
freeRow:SetPoint("TOPLEFT", 0, -56)
local freeLabel = UI.Text(freeRow, "Shows")
freeLabel:SetPoint("LEFT", 0, 0)
-- The infinity sign, drawn in the Free look's font (the UI font has no such character).
local freeText = freeRow:CreateFontString(nil, "ARTWORK")
freeText:SetPoint("LEFT", freeLabel, "RIGHT", 8, 0)
Refresher(function()
local look = CC.db.looks.free
freeText:SetFont(CC.LookFontPath(look, look.text), 18, "")
freeText:SetText(look.text)
freeText:SetTextColor(1, 0.82, 0)
end)
local freeNote = UI.Text(freeRow, "instead of the count", "GameFontHighlightSmall")
freeNote:SetPoint("LEFT", freeText, "RIGHT", 8, 0)
local when = Note(p, "", 0, -60, 440)
Refresher(function()
lowRow:SetShown(editing == "low")
freeRow:SetShown(editing == "free")
when:SetShown(editing == "normal" or editing == "oom" or editing == "fill")
lookTitle:SetText(editing == "fill" and "Edit ManaFill" or ("Edit look style : " .. CC.LOOK_LABELS[editing]))
copy:SetShown(editing ~= "normal" and editing ~= "fill")
applyAll:SetShown(editing ~= "fill")
applyAll:ClearAllPoints()
applyAll:SetPoint("LEFT", copy:IsShown() and copy or which, "RIGHT", 6, 0)
if editing == "normal" then
when:SetText("Used when you have more casts left than the Low look covers.")
elseif editing == "fill" then
when:SetText("While you can't afford a spell, its button fills from the bottom as your mana comes back.")
else
when:SetText("Used when you can't afford a single cast.")
end
end)
local y0 = -90
local lp = CreateFrame("Frame", nil, p)
lp:SetAllPoints(p)
Heading(lp, "Font", 0, y0)
local font = UI.Dropdown(lp, 220, function()
local items = {}
-- The Free look only lists fonts that can draw its text (the infinity sign).
local text = (editing == "free") and CC.db.looks.free.text or nil
for _, f in ipairs(CC.Fonts()) do
if not text or CC.FontCanDraw(f.path, text) then
items[#items + 1] = { value = f.name, label = f.name, font = f.path }
end
end
return items
end, function() return L().font end, function(v) L().font = v; StyleChanged() end)
font:SetPoint("TOPLEFT", 0, y0 - 20)
local fontNote = Note(lp, "Only fonts that can draw this text are listed.", 40, y0 - 2, 300)
Refresher(function() fontNote:SetShown(editing == "free") end)
local outline = UI.Dropdown(lp, 120, function()
return {
{ value = "NONE", label = "No outline" },
{ value = "OUTLINE", label = "Outline" },
{ value = "THICKOUTLINE", label = "Thick outline" },
}
end, function() return L().outline end, function(v) L().outline = v; StyleChanged() end)
outline:SetPoint("TOPLEFT", 230, y0 - 20)
local shadow = UI.Check(lp, "Shadow", function() return L().shadow end,
function(v) L().shadow = v; StyleChanged() end)
shadow:SetPoint("TOPLEFT", 358, y0 - 19)
local size = UI.Slider(lp, "Size", 8, 40, 1, 220, function() return L().size end,
function(v) L().size = v; StyleChanged() end)
size:SetPoint("TOPLEFT", 0, y0 - 56)
Heading(lp, "Colour", 0, y0 - 104)
local swatch = UI.Swatch(lp, function() return L().color end, StyleChanged)
swatch:SetPoint("TOPLEFT", 0, y0 - 124)
Note(lp, "Conditions can override it.", 30, y0 - 130, 300)
Heading(lp, "Position on the button", 0, y0 - 164)
local anchor = UI.Dropdown(lp, 160, function() return ANCHORS end,
function() return L().anchor end, function(v) L().anchor = v; StyleChanged() end)
anchor:SetPoint("TOPLEFT", 0, y0 - 184)
-- 0, 0 is the chosen position itself; the arrows nudge 1 (Shift 5, Ctrl 10).
local x = UI.Slider(lp, "X offset (left - / right +)", -50, 50, 1, 216, function() return L().x end,
function(v) L().x = v; StyleChanged() end, true)
x:SetPoint("TOPLEFT", 0, y0 - 218)
local y = UI.Slider(lp, "Y offset (down - / up +)", -50, 50, 1, 216, function() return L().y end,
function(v) L().y = v; StyleChanged() end, true)
y:SetPoint("TOPLEFT", 230, y0 - 218)
local reset = UI.Button(lp, "Reset all looks", 140, 22, function()
CC.ResetSection("looks")
StyleChanged()
UI.RefreshAll()
end)
local resetOne = UI.Button(lp, "Reset this look", 130, 22, function()
if CC.DEFAULTS.looks[editing] then
CC.db.looks[editing] = CC.CopyDeep(CC.DEFAULTS.looks[editing])
if editing == "low" then CC.db.lowAt = CC.DEFAULTS.lowAt end
end
StyleChanged()
UI.RefreshAll()
end)
resetOne:SetPoint("TOPLEFT", 0, y0 - 276)
reset:SetPoint("LEFT", resetOne, "RIGHT", 8, 0)
-- ManaFill settings, shown instead of the look settings when ManaFill is picked.
local function FS() return CC.db.fill end
local fp = CreateFrame("Frame", nil, p)
fp:SetAllPoints(p)
local fillOn = UI.Check(fp, "Show ManaFill", function() return FS().enabled end,
function(v) FS().enabled = v; StyleChanged() end)
fillOn:SetPoint("TOPLEFT", 0, y0)
Note(fp, "Full means you have enough mana for one cast; the fill disappears as soon as you can cast it.", 0, y0 - 28, 440)
Heading(fp, "Colour", 0, y0 - 56)
local fillColor = UI.Swatch(fp, function() return FS().color end, StyleChanged)
fillColor:SetPoint("TOPLEFT", 0, y0 - 76)
Note(fp, "The colour picker's opacity sets how see-through the fill is.", 30, y0 - 82, 400)
Heading(fp, "Texture", 0, y0 - 116)
local fillTex = UI.Dropdown(fp, 220, function()
local items = {}
for _, t in ipairs(CC.BarTextures()) do items[#items + 1] = { value = t.name, label = t.name } end
return items
end, function() return FS().texture end, function(v) FS().texture = v; StyleChanged() end)
fillTex:SetPoint("TOPLEFT", 0, y0 - 136)
local fillReset = UI.Button(fp, "Reset ManaFill", 140, 22, function()
CC.ResetSection("fill")
StyleChanged()
UI.RefreshAll()
end)
fillReset:SetPoint("TOPLEFT", 0, y0 - 180)
Refresher(function()
lp:SetShown(editing ~= "fill")
fp:SetShown(editing == "fill")
end)
Note(p, "While this tab is open every selected button shows its count, so you can see your changes.", 0, -394)
-- Preview, on the right: Default big, Low, Out of mana and Free smaller.
-- Clicking one picks that look to edit.
local box = CreateFrame("Frame", nil, p, "BackdropTemplate")
box:SetSize(176, 340)
box:SetPoint("TOPRIGHT", 0, 0)
UI.Backdrop(box, 0.03, 0.03, 0.035, 0.9)
local title = UI.Text(box, "Preview (click to edit)", "GameFontNormal")
title:SetPoint("TOP", 0, -8)
title:SetJustifyH("CENTER")
local previews = {}
local previewKeys = { "normal", "low", "oom", "free", "fill" }
for _, key in ipairs(previewKeys) do
local b = PreviewButton(box, function() Select(key) end)
b.label = UI.Text(box, "", "GameFontHighlightSmall")
b.label:SetPoint("TOP", b, "BOTTOM", 0, -4)
b.label:SetJustifyH("CENTER")
previews[key] = b
end
UpdatePreview = function()
if not box:IsVisible() then return end
local icon, size = PreviewSource()
local counts = {
normal = math.max(12, CC.db.lowAt + 5), low = math.max(1, CC.db.lowAt), oom = 0,
free = CC.db.looks.free.text,
}
local small = math.min(1, 46 / size)
local layout = {
normal = { scale = math.min(2, 120 / size), x = 88, y = 30 },
low = { scale = small, x = 32 },
oom = { scale = small, x = 88 },
free = { scale = small, x = 144 },
fill = { scale = small, x = 88 },
}
local bigH = size * layout.normal.scale
local row2 = 30 + bigH + 34
layout.fill.y = row2 + size * small + 30
for _, key in ipairs(previewKeys) do
local b, lay = previews[key], layout[key]
local look = CC.db.looks[key] or CC.db.looks.oom
b:SetScale(lay.scale)
b:SetSize(size, size)
b:ClearAllPoints()
b:SetPoint("TOP", box, "TOPLEFT", lay.x / lay.scale, -(lay.y or row2) / lay.scale)
b.icon:SetTexture(icon)
CC.StyleFont(b.fs, look, b.holder, CC.LookFontPath(look, key == "free" and counts.free or nil))
b.fs:SetText(key == "fill" and "" or counts[key])
b.fs:SetTextColor(look.color.r, look.color.g, look.color.b, look.color.a or 1)
CC.StyleFill(b.fill)
b.fill:SetShown(CC.db.fill.enabled and (key == "oom" or key == "fill"))
b.sel:SetShown(key == editing)
if key == editing then
b:SetBackdropBorderColor(1, 0.82, 0, 1)
else
b:SetBackdropBorderColor(0, 0, 0, 1)
end
b.label:SetText(PREVIEW_LABELS[key])
if key == "low" and CC.db.lowAt < 1 then b.label:SetText("Low (off)") end
b.label:SetTextColor(key == editing and 1 or 0.8, key == editing and 0.82 or 0.8, key == editing and 0 or 0.8)
end
end
box:SetScript("OnShow", UpdatePreview)
Refresher(function() UpdatePreview() end)
end
---------------------------------------------------------
-- SECTION: Visibility tab
---------------------------------------------------------
function builders.visibility(p)
local function S() return CC.db.show end
local function Check(label, key, x, y)
local cb = UI.Check(p, label, function() return S()[key] end, function(v) S()[key] = v; Changed() end)
cb:SetPoint("TOPLEFT", x, y)
return cb
end
Heading(p, "When to show the counts", 0, 0)
Check("Show in combat", "inCombat", 0, -22)
Check("Show out of combat", "outOfCombat", 0, -50)
Check("Show on mouse over", "onHover", 0, -78)
Check("Hide on full mana", "oocOnlyNotFull", 0, -106)
-- Fade on hide: counts fade away when hidden; they still appear instantly.
Check("Fade count on hide", "fadeOut", 0, -140)
local fadeTime = UI.Slider(p, "Fade time (seconds)", 0.1, 3, 0.1, 220,
function() return S().fadeTime or 0.5 end, function(v) S().fadeTime = v end)
fadeTime:SetPoint("TOPLEFT", 200, -132)
Refresher(function() fadeTime:SetAlpha(S().fadeOut and 1 or 0.4) end)
Heading(p, "Spells", 0, -184)
Check("Count spells cast by macros", "macros", 0, -206)
local reset = UI.Button(p, "Reset visibility settings", 180, 22, function()
CC.ResetSection("show")
Changed()
UI.RefreshAll()
end)
reset:SetPoint("TOPLEFT", 0, -246)
Heading(p, "Minimap", 0, -282)
local mm = UI.Check(p, "Show the minimap button", function() return not CC.db.minimap.hide end,
function(v) CC.SetMinimapShown(v) end)
mm:SetPoint("TOPLEFT", 0, -304)
Note(p, "Tip: untick both combat options and keep the mouse-over option ticked to see counts only when you hover a button.", 0, -386)
end
---------------------------------------------------------
-- SECTION: Conditions tab
---------------------------------------------------------
-- WeakAuras-style condition cards in a scrolling list, as many as you like:
-- If <check> [and/or more checks] Then <property change> [more changes]
-- Each card collapses, moves up/down, copies and deletes.
local SUBJECTS = {
{ value = "casts", label = "Casts left" },
{ value = "mana", label = "Mana %" },
{ value = "free", label = "Zero cost" },
{ value = "combat", label = "In combat" },
{ value = "hover", label = "Mouse is over the button" },
}
local IS_BOOL = { free = true, combat = true, hover = true }
local NUMBER_OPS = {
{ value = "<", label = "<" },
{ value = "<=", label = "<=" },
{ value = "=", label = "=" },
{ value = "!=", label = "!=" },
{ value = ">=", label = ">=" },
{ value = ">", label = ">" },
}
local BOOL_OPS = {
{ value = "true", label = "is true" },
{ value = "false", label = "is false" },
}
local PROPS = {
{ value = "textcolor", label = "Count colour" },
{ value = "alpha", label = "Count transparency" },
{ value = "hide", label = "Hide the count" },
{ value = "size", label = "Count size" },
{ value = "offset", label = "Move the count" },
{ value = "text", label = "Replace the count with text" },
{ value = "pulse", label = "Pulse the count" },
{ value = "glow", label = "Glow the button" },
{ value = "tint", label = "Tint the button" },
{ value = "sound", label = "Play a sound" },
{ value = "chat", label = "Chat message (only you)" },
}
local PROP_LABEL = {}
for _, pr in ipairs(PROPS) do PROP_LABEL[pr.value] = pr.label end
local SUBJECT_LABEL = {}
for _, s in ipairs(SUBJECTS) do SUBJECT_LABEL[s.value] = s.label end
local CARD_W, HEADER_H, ROW_H = 620, 28, 28
local function NewCheck() return { join = "and", subject = "casts", op = "<=", value = 1 } end
local JOINS = {
{ value = "and", label = "and" },
{ value = "or", label = "or" },
}
local function NewProp(t)
local pr = { type = t or "glow", color = Color(1, 0.82, 0), glowType = "button", sound = "raidwarning",
value = 50, text = "", x = 0, y = 0 }
if t == "size" then pr.value = 24 end
if t == "tint" then pr.color = Color(1, 0, 0, 0.35) end
if t == "textcolor" then pr.color = Color(1, 0.2, 0.2) end
return pr
end
local function NewCondition()
return { enabled = true, checks = { NewCheck() }, props = { NewProp("glow") } }
end
-- Keeps a check consistent after its subject changes.
local function FixCheck(ch)
if IS_BOOL[ch.subject] then
if ch.op ~= "true" and ch.op ~= "false" then ch.op = "true" end
elseif ch.op == "true" or ch.op == "false" then
ch.op = "<="
end
end
local function DropFocus()
local f = GetCurrentKeyBoardFocus and GetCurrentKeyBoardFocus()
if f then f:ClearFocus() end
end
local function SmallButton(parent, text, w, onClick)
local b = UI.Button(parent, text, w, 20, onClick)
return b
end
function builders.conditions(p)
local sf, content = UI.ScrollArea(p)
local function Conds() return CC.db.conditions end
local cards = {}
local add
local function Rebuild()
DropFocus()
Changed()
UI.RefreshAll()
end
Note(content, "Each condition is resolved top to bottom; a lower condition will be prioritised when "
.. "deciding between conditions.", 0, 0, 600)
-- One check row: subject, operator, value.
local function CheckRow(card, i)
local row = CreateFrame("Frame", nil, card)
row:SetSize(CARD_W - 30, ROW_H - 2)
local function Ch() return row.item or NewCheck() end
local function Set(field, v)
if not row.item then return end
row.item[field] = v
FixCheck(row.item)
Changed()
end
-- The first check reads "If", every later one says how it joins the ones before.
row.ifText = UI.Text(row, "If", "GameFontNormal")
row.ifText:SetPoint("LEFT", 8, 0)
row.join = UI.Dropdown(row, 56, function() return JOINS end,
function() return Ch().join or "and" end, function(v) Set("join", v); UI.RefreshAll() end)
row.join:SetPoint("LEFT", 0, 0)
local subject = UI.Dropdown(row, 190, function() return SUBJECTS end,
function() return Ch().subject end, function(v) Set("subject", v) end)
subject:SetPoint("LEFT", 62, 0)
local op = UI.Dropdown(row, 80, function() return IS_BOOL[Ch().subject] and BOOL_OPS or NUMBER_OPS end,
function() return Ch().op end, function(v) Set("op", v) end)
op:SetPoint("LEFT", subject, "RIGHT", 6, 0)
row.value = UI.Edit(row, 44, true, function() return Ch().value or 0 end, function(v) Set("value", v) end)
row.value:SetPoint("LEFT", op, "RIGHT", 10, 0)
row.unit = UI.Text(row, "")
row.unit:SetPoint("LEFT", row.value, "RIGHT", 4, 0)
row.remove = SmallButton(row, "X", 24, function()
local list = card.cond and card.cond.checks
if not list or #list < 2 then return end
for idx, ch in ipairs(list) do
if ch == row.item then table.remove(list, idx) break end
end
Rebuild()
end)
row.remove:SetPoint("LEFT", subject, "LEFT", 400, 0)
return row
end
-- One property row: what to change, and its settings.
local function PropRow(card, i)
local row = CreateFrame("Frame", nil, card)
row:SetSize(CARD_W - 30, ROW_H - 2)
local function Pr() return row.item or NewProp() end
local function Set(field, v)
if not row.item then return end
row.item[field] = v
-- Sensible starting values when the kind of change switches.
if field == "type" then
local pr = row.item
if v == "size" and ((pr.value or 0) < 6 or (pr.value or 0) > 60) then pr.value = 24 end
if v == "alpha" and (pr.value or 0) > 100 then pr.value = 50 end
if v == "tint" and pr.color and (pr.color.a or 1) > 0.6 then pr.color.a = 0.35 end
if v ~= "tint" and pr.color and (pr.color.a or 1) < 0.3 then pr.color.a = 1 end
UI.RefreshAll()
end
Changed()
end
local kind = UI.Dropdown(row, 200, function() return PROPS end,
function() return Pr().type end, function(v) Set("type", v) end)
kind:SetPoint("LEFT", 0, 0)
local x0 = 210
row.swatch = UI.Swatch(row, function() return Pr().color end, Changed)
row.number = UI.Edit(row, 44, true, function() return Pr().value or 0 end, function(v) Set("value", v) end)
row.numberUnit = UI.Text(row, "")
row.numberUnit:SetPoint("LEFT", row.number, "RIGHT", 4, 0)
row.text = UI.Edit(row, 150, false, function() return Pr().text or "" end, function(v) Set("text", v) end)
row.xLabel = UI.Text(row, "X")
row.x = UI.Edit(row, 44, "signed", function() return Pr().x or 0 end, function(v) Set("x", v) end)
row.yLabel = UI.Text(row, "Y")
row.y = UI.Edit(row, 44, "signed", function() return Pr().y or 0 end, function(v) Set("y", v) end)
row.glowType = UI.Dropdown(row, 150, function() return CC.GLOW_TYPES end,
function() return Pr().glowType end, function(v) Set("glowType", v) end)
row.sound = UI.Dropdown(row, 160, CC.SoundItems,
function() return Pr().sound end, function(v) Set("sound", v); CC.PlaySound(v) end)
row.test = SmallButton(row, "Test", 44, function() CC.PlaySound(Pr().sound) end)
row.swatch:SetPoint("LEFT", x0, 0)
row.number:SetPoint("LEFT", x0 + 6, 0)
row.text:SetPoint("LEFT", x0 + 6, 0)
row.xLabel:SetPoint("LEFT", x0, 0)
row.x:SetPoint("LEFT", row.xLabel, "RIGHT", 8, 0)
row.yLabel:SetPoint("LEFT", row.x, "RIGHT", 10, 0)
row.y:SetPoint("LEFT", row.yLabel, "RIGHT", 8, 0)
row.glowType:SetPoint("LEFT", x0, 0)
row.sound:SetPoint("LEFT", x0, 0)
row.test:SetPoint("LEFT", row.sound, "RIGHT", 6, 0)
row.remove = SmallButton(row, "X", 24, function()
local list = card.cond and card.cond.props
if not list then return end
for idx, pr in ipairs(list) do
if pr == row.item then table.remove(list, idx) break end
end
Rebuild()
end)
row.remove:SetPoint("LEFT", 420, 0)
function row:ShowFor(pr)
local t = pr.type
self.swatch:SetShown(t == "textcolor" or t == "tint" or t == "glow")
self.swatch:ClearAllPoints()
if t == "glow" then
self.swatch:SetPoint("LEFT", self.glowType, "RIGHT", 8, 0)
else
self.swatch:SetPoint("LEFT", x0, 0)
end
self.number:SetShown(t == "alpha" or t == "size")
self.numberUnit:SetShown(t == "alpha" or t == "size")
self.numberUnit:SetText(t == "alpha" and "% visible" or "pt")
self.text:SetShown(t == "text" or t == "chat")
self.text:SetWidth(t == "chat" and 200 or 120)
self.xLabel:SetShown(t == "offset")
self.x:SetShown(t == "offset")
self.yLabel:SetShown(t == "offset")
self.y:SetShown(t == "offset")
self.glowType:SetShown(t == "glow")
self.sound:SetShown(t == "sound")
self.test:SetShown(t == "sound")
end
return row
end
local function Card(i)
local card = CreateFrame("Frame", nil, content, "BackdropTemplate")
card:SetWidth(CARD_W)
UI.Backdrop(card, 0.08, 0.08, 0.09, 0.95)
card.checkRows, card.propRows = {}, {}
local function ToggleCollapsed()
if card.cond then card.cond.collapsed = not card.cond.collapsed end
Rebuild()
end
-- The whole header bar expands/collapses the card; it sits under the
-- header's own buttons and checkbox, so those still get their clicks.
card.header = CreateFrame("Button", nil, card)
card.header:SetPoint("TOPLEFT", 1, -1)
card.header:SetPoint("TOPRIGHT", -1, -1)
card.header:SetHeight(HEADER_H - 2)
card.header:SetHighlightTexture(UI.WHITE)
card.header:GetHighlightTexture():SetVertexColor(1, 1, 1)
card.header:GetHighlightTexture():SetAlpha(0.05)
card.header:SetScript("OnClick", ToggleCollapsed)
-- A slightly lighter title bar, with a thin gold line under it while the
-- card is open, so it reads as the card's header rather than part of the body.
local headerBg = card.header:CreateTexture(nil, "BACKGROUND")
headerBg:SetAllPoints()
headerBg:SetColorTexture(0.16, 0.16, 0.18, 1)
card.headerLine = card.header:CreateTexture(nil, "BORDER")
card.headerLine:SetPoint("BOTTOMLEFT", 0, 0)
card.headerLine:SetPoint("BOTTOMRIGHT", 0, 0)
card.headerLine:SetHeight(1)
card.headerLine:SetColorTexture(1, 0.82, 0, 0.35)
card.toggle = CreateFrame("Button", nil, card)
card.toggle:SetSize(16, 16)
card.toggle:SetPoint("TOPLEFT", 6, -6)
card.toggle:SetScript("OnClick", ToggleCollapsed)
card.enabled = UI.Check(card, "", function() return card.cond and card.cond.enabled end,
function(v) if card.cond then card.cond.enabled = v; Changed() end end)
card.enabled:SetPoint("TOPLEFT", 26, -2)
card.title = UI.Text(card.header, "", "GameFontNormal")
card.title:SetPoint("TOPLEFT", card, "TOPLEFT", 54, -8)
card.title:SetWidth(390)
card.title:SetWordWrap(false)
local function Move(dir)
local list = Conds()
for idx, c in ipairs(list) do
if c == card.cond then
local to = idx + dir
if to >= 1 and to <= #list then list[idx], list[to] = list[to], list[idx] end
break
end
end
Rebuild()
end
card.delete = SmallButton(card, "X", 24, function()
for idx, c in ipairs(Conds()) do
if c == card.cond then table.remove(Conds(), idx) break end
end
Rebuild()
end)
card.delete:SetPoint("TOPRIGHT", -6, -4)
card.copy = SmallButton(card, "Copy", 46, function()
for idx, c in ipairs(Conds()) do
if c == card.cond then table.insert(Conds(), idx + 1, CC.CopyDeep(c)) break end
end
Rebuild()
end)
card.copy:SetPoint("RIGHT", card.delete, "LEFT", -4, 0)
card.down = SmallButton(card, "Down", 46, function() Move(1) end)
card.down:SetPoint("RIGHT", card.copy, "LEFT", -4, 0)
card.up = SmallButton(card, "Up", 36, function() Move(-1) end)
card.up:SetPoint("RIGHT", card.down, "LEFT", -4, 0)
card.nameLabel = UI.Text(card, "Name", "GameFontNormal")
card.nameEdit = UI.Edit(card, 220, false, function() return card.cond and card.cond.name or "" end,
function(v) if card.cond then card.cond.name = (v ~= "") and v or nil; UI.RefreshAll() end end)
card.nameEdit.allowEmpty = true
card.nameNote = UI.Text(card, "optional", "GameFontDisableSmall")
card.logicNote = UI.Text(card, "\"and\" is checked before \"or\": A or B and C means A, or both B and C.",
"GameFontHighlightSmall")
card.logicNote:SetTextColor(0.75, 0.75, 0.75)
card.addCheck = SmallButton(card, "+ Add check", 100, function()
if card.cond then table.insert(card.cond.checks, NewCheck()) end
Rebuild()
end)
card.thenLabel = UI.Text(card, "Then", "GameFontNormal")
card.addProp = SmallButton(card, "+ Add property change", 160, function()
if card.cond then table.insert(card.cond.props, NewProp("textcolor")) end
Rebuild()
end)
card.warn = UI.Text(card, "Sounds and chat messages only work when every check is one CastCount can see "
.. "(Zero cost, In combat, Mouse over): Forever hides your mana.", "GameFontHighlightSmall")
card.warn:SetWidth(CARD_W - 90)
card.warn:SetTextColor(1, 0.5, 0.3)
-- Lays the card out for its condition and returns its height.
function card:Layout(index)
local c = self.cond
-- Title bar above the card's body, its own buttons above the bar.
local base = self:GetFrameLevel()
self.header:SetFrameLevel(base + 4)
for _, w in ipairs({ self.toggle, self.enabled, self.up, self.down, self.copy, self.delete }) do
w:SetFrameLevel(base + 6)
end
self.title:SetText((c.name and c.name ~= "") and c.name or ("Condition " .. index))
self.toggle:SetNormalTexture(c.collapsed and "Interface\\Buttons\\UI-PlusButton-Up"
or "Interface\\Buttons\\UI-MinusButton-Up")
self.up:SetEnabled(index > 1)
self.down:SetEnabled(index < #Conds())
local open = not c.collapsed
self.headerLine:SetShown(open)
for _, w in ipairs({ self.nameLabel, self.nameEdit, self.nameNote, self.logicNote, self.addCheck,
self.thenLabel, self.addProp, self.warn }) do
w:SetShown(open)
end
for _, r in ipairs(self.checkRows) do r:Hide() end
for _, r in ipairs(self.propRows) do r:Hide() end
if not open then return HEADER_H + 4 end
local y = -HEADER_H - 4
self.nameLabel:ClearAllPoints()
self.nameLabel:SetPoint("TOPLEFT", 10, y - 4)
self.nameEdit:ClearAllPoints()
self.nameEdit:SetPoint("TOPLEFT", 58, y)
self.nameNote:ClearAllPoints()
self.nameNote:SetPoint("LEFT", self.nameEdit, "RIGHT", 8, 0)
y = y - 30
local hasAnd, hasOr = false, false
for ci, ch in ipairs(c.checks) do
local r = self.checkRows[ci] or CheckRow(self, ci)
self.checkRows[ci] = r
r.item = ch
r:ClearAllPoints()
r:SetPoint("TOPLEFT", 10, y)
r.ifText:SetShown(ci == 1)
r.join:SetShown(ci > 1)
if ci > 1 then
if ch.join == "or" then hasOr = true else hasAnd = true end
end
local numeric = not IS_BOOL[ch.subject]
r.value:SetShown(numeric)
r.unit:SetShown(numeric)
r.unit:SetText(ch.subject == "mana" and "%" or (ch.subject == "casts" and "casts" or ""))
r.remove:SetShown(#c.checks > 1)
r:Show()
y = y - ROW_H
end
local mixed = hasAnd and hasOr
self.logicNote:SetShown(mixed)
if mixed then
self.logicNote:ClearAllPoints()
self.logicNote:SetPoint("TOPLEFT", 72, y - 2)
y = y - 18