-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCore.lua
More file actions
307 lines (280 loc) · 10 KB
/
Core.lua
File metadata and controls
307 lines (280 loc) · 10 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
--
-- Masque Blizzard Bars
-- Enables Masque to skin the built-in WoW action bars
--
-- Copyright 2022 - 2024 SimGuy
--
-- Use of this source code is governed by an MIT-style
-- license that can be found in the LICENSE file or at
-- https://opensource.org/licenses/MIT.
--
local Masque = LibStub("Masque")
local ACR = LibStub("AceConfigRegistry-3.0")
local ACD = LibStub("AceConfigDialog-3.0")
local AddonName, Shared = ...
-- From Locales/Locales.lua
local L = Shared.Locale
-- From Metadata.lua
local Metadata = Shared.Metadata
local Groups = Metadata.Groups
local Types = Metadata.Types
-- Push us into shared object
local Core = {}
Shared.Core = Core
local _, _, _, ver = GetBuildInfo()
local SkinnedKey = "_"..AddonName.."Skinned"
-- Get an option for the AceConfigDialog
function Core:GetOption(key)
if not key then
if self and self[#self] then
key = self[#self]
else
return nil
end
end
local value = false;
local settings = _G[AddonName]
if settings and settings[key] ~= nil then
value = settings[key]
elseif Metadata.Defaults and Metadata.Defaults[key] ~= nil then
value = Metadata.Defaults[key]
end
--print("GetOption", key, value)
return value
end
-- Set an option from the AceConfigDialog
function Core:SetOption(...)
local key = self[#self]
if not key then return nil end
local value = ...
local settings = _G[AddonName]
--print("SetOption", key, value)
if settings and settings[key] ~= value then
settings[key] = value
end
if Metadata.OptionCallbacks and Metadata.OptionCallbacks[key] then
--print("OptionCallback", key)
local func = Metadata.OptionCallbacks[key]
func(key, value)
end
end
-- Handle the load event to initialize things that require Saved Variables
function Core:HandleEvent(event, target)
if event == "ADDON_LOADED" and target == AddonName then
if not _G[AddonName] then
_G[AddonName] = {}
end
-- Don't register options unless they're defined.
if Metadata.Options then
Metadata.Options.get = Core.GetOption
Metadata.Options.set = Core.SetOption
ACR:RegisterOptionsTable(AddonName, Metadata.Options)
ACD:AddToBlizOptions(AddonName, Metadata.FriendlyName)
end
end
end
-- Return a regions table based on the information passed for this button.
-- This needs to be called for every individual button being skinned, as
-- it returns actual references to the children of the button instance, not
-- key names.
function Core:MakeRegions(button, map)
-- If map is empty, then do nothing
if not map then return nil end
local regions = {}
for region, key in pairs(map) do
local frame = button and button[key]
if frame then
-- If this is a function, call it now to get
-- the object for the Masque region, otherwise
-- assume the object is literal.
if type(frame) == "function" then
--print("regions function:", region, key, frame)
regions[region] = frame(button)
else
--print("regions frame:", region, key, frame)
regions[region] = frame
end
end
end
return regions
end
-- Skin any buttons in the table as members of the given Masque group.
-- If parent is set, then the button names are children of the parent
-- table. The buttons value can be a nested table.
--
-- If bclass is specified, limit this pass to a specific button class
-- within the group. This is used for frames where new buttons get
-- added only as needed. We assume the current number of slots in the
-- Metadata is how many were already skinned, and we'll just skin the
-- difference up to the total new slots. If these numbers are equal
-- we won't do anything.
--
-- If this is a nested button structure, the caller needs to pass the
-- buttons subtree containing the button name, the parent frame, and
-- the prefix (parent name) or else this won't correctly find the button.
function Core:Skin(buttons, group, bclass, slots, parent, prefix)
if not parent then parent = _G end
if not prefix then prefix = "" end
-- If button isn't set, we want to skin every class of button we were
-- given and add it to the group, recursively if needed.
for button, children in pairs(buttons) do
-- If children is a table, process the table recursively as a set
-- of buttons. If bclass was passed, don't do any recursion.
if not bclass and type(children) == "table" then
if parent[button] then
--print('recurse:', button, parent[button])
Core:Skin(children, group, nil, nil, parent[button], prefix .. button)
end
-- Otherwise, try to skin all the expected buttons at this level.
-- If bclass was passed, only act on the specific button class.
-- If children wasn't a number, we shouldn't be here, so skip this button.
elseif (bclass == button or not bclass) and type(children) ~= "table" then
-- Pass the correct type for this button so that Masque
-- doesn't have to try to figure it out.
--print("map: type: ", prefix .. button)
local button_type = Types[prefix .. button] or {}
local default_type = Types['DEFAULT'] or {}
local final_type = button_type.type or default_type.type or nil
local map = button_type.map or nil
-- If -1, assume button is the actual button name
-- If slots was set, we're confused, don't do anything
if children == -1 and not slots then
--print("button:", button, children, parent[button])
local frame = parent[button]
if frame and not frame[SkinnedKey] then
local regions = Core:MakeRegions(frame, map)
group:AddButton(frame, regions, final_type)
frame[SkinnedKey] = true
end
-- If a string, assume button is a reference to a function or table
-- If slots was set, we're confused, don't do anything
elseif type(children) == 'string' and not slots then
local container = parent[button]
local contents = container[children]
--print("button:", button, children, type(contents), contents)
local frames = {}
if type(contents) == 'function' then
-- We're trusting this function return a table
frames = contents(container)
elseif type(contents) == 'table' then
frames = contents
end
for _, frame in ipairs(frames) do
if not frame[SkinnedKey] then
local regions = Core:MakeRegions(frame, map)
group:AddButton(frame, regions, final_type)
frame[SkinnedKey] = true
end
end
-- Otherwise, append a range of numbers to the name.
--
-- If we're not updating total slots, then loop through all
-- buttons from 1 to the total number of expected children.
--
-- If we're update total slots, then start from the number
-- we already had plus 1, and loop through any additional
-- slots up to the total expected slots.
--
-- If updating total slots, update the new count after we're
-- finished.
elseif (not slots and children > 0) or
(slots and children >= 0 and children < slots) then
local min, max = 1, children
if slots then
min = children + 1
max = slots
end
--print("button range:", button, min, max)
for i = min, max do
--print("button:", button, i, parent[button..i])
local frame = parent[button..i]
if frame and not frame[SkinnedKey] then
local regions = Core:MakeRegions(frame, map)
group:AddButton(frame, regions, final_type)
frame[SkinnedKey] = true
end
end
if slots then
buttons[button] = slots
end
end
end
end
end
-- In 11.0 Blizzard added an itemButtonPool concept which makes finding all the
-- buttons in a container really easy.
function Core:SkinButtonPool(pools, group)
for _, frame in ipairs(pools) do
if frame.itemButtonPool then
for button in frame.itemButtonPool:EnumerateActive() do
-- TODO These should always be ItemButtons by
-- nature of Blizzard code, but support regions
-- just in case.
if not button[SkinnedKey] then
group:AddButton(button, nil, "Item")
button[SkinnedKey] = true
end
end
end
end
end
-- This function will perform a generic hook and attempt to skin the buttons in
-- the frame whenever that hook is called. This is useful for frames that are
-- frequently changing. The addon can provide a PreHookFunction to be called to
-- do any needed setup.
function Core:SkinByHook(...)
local frameName = self:GetName()
if frameName and Groups[frameName] and Groups[frameName].Buttons[frameName] then
if Groups[frameName]['PreHookFunction'] then
Groups[frameName]['PreHookFunction'](self, ...)
end
Core:Skin(Groups[frameName].Buttons, Groups[frameName].Group)
end
end
-- Check if the current interface version is between the low number (inclusive)
-- and the high number (exclusive) for implementations that are dependent upon
-- client version.
function Core:CheckVersion(versions)
if not versions then
return true
else
for i = 1, #versions, 2 do
if (not versions[i] or ver >= versions[i]) and
(not versions[i+1] or ver < versions[i+1]) then
return true
end
end
return false
end
end
function Core:Init()
-- Init Custom Options
Core.Events = CreateFrame("Frame")
Core.Events:RegisterEvent("ADDON_LOADED")
Core.Events:SetScript("OnEvent", Core.HandleEvent)
-- Create groups for each defined button group and add any buttons
-- that should exist at this point
for id, cont in pairs(Groups) do
if Core:CheckVersion(cont.Versions) then
cont.Group = Masque:Group(Metadata.MasqueFriendlyName, cont.Title, id)
-- Reset l10n group names after ensuring migration to Static IDs
cont.Group:SetName(L[cont.Title])
if cont.Init then
cont.Init(cont.Buttons)
end
if cont.HookFunction then
for buttonFrame, _ in pairs(cont.Buttons) do
if _G[buttonFrame] and _G[buttonFrame][cont.HookFunction] then
hooksecurefunc(_G[buttonFrame], cont.HookFunction, Core.SkinByHook)
end
end
end
if cont.Notes then
cont.Group.Notes = cont.Notes
end
if not cont.Delayed then
Core:Skin(cont.Buttons, cont.Group)
end
end
end
end