flickerstreak@28
|
1 -- ReAction.lua
|
flickerstreak@28
|
2 -- See modules/ReAction_ModuleTemplate for Module API listing
|
flickerstreak@28
|
3 -- See Bar.lua for Bar object listing
|
flickerstreak@27
|
4
|
flickerstreak@27
|
5 ------ CORE ------
|
flickerstreak@30
|
6 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
|
flickerstreak@33
|
7 "AceConsole-3.0",
|
flickerstreak@33
|
8 "AceEvent-3.0"
|
flickerstreak@30
|
9 )
|
flickerstreak@33
|
10 ReAction.version = GetAddOnMetadata("ReAction","Version")
|
flickerstreak@33
|
11 ReAction.revision = tonumber(("$Revision$"):match("%d+"))
|
flickerstreak@27
|
12
|
flickerstreak@28
|
13 ------ GLOBALS ------
|
flickerstreak@28
|
14 _G["ReAction"] = ReAction
|
flickerstreak@27
|
15
|
flickerstreak@28
|
16 ------ DEBUGGING ------
|
flickerstreak@25
|
17 ReAction.debug = true
|
flickerstreak@36
|
18 local dbprint
|
flickerstreak@25
|
19 if ReAction.debug then
|
flickerstreak@36
|
20 dbprint = function(msg)
|
flickerstreak@25
|
21 DEFAULT_CHAT_FRAME:AddMessage(msg)
|
flickerstreak@25
|
22 end
|
flickerstreak@36
|
23 --seterrorhandler(dbprint)
|
flickerstreak@25
|
24 else
|
flickerstreak@36
|
25 dbprint = function() end
|
flickerstreak@25
|
26 end
|
flickerstreak@36
|
27 ReAction.dbprint = dbprint
|
flickerstreak@25
|
28
|
flickerstreak@33
|
29 ------ LIBRARIES ------
|
flickerstreak@33
|
30 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
|
flickerstreak@33
|
31 ReAction.L = L
|
flickerstreak@33
|
32
|
flickerstreak@28
|
33 ------ PRIVATE ------
|
flickerstreak@30
|
34 local SelectBar, DestroyBar, InitializeBars, TearDownBars, DeepCopy, SafeCall, CheckMethod, SlashHandler
|
flickerstreak@28
|
35 do
|
flickerstreak@28
|
36 local pcall = pcall
|
flickerstreak@28
|
37 local geterrorhandler = geterrorhandler
|
flickerstreak@28
|
38
|
flickerstreak@28
|
39 SelectBar = function(x)
|
flickerstreak@28
|
40 local bar, name
|
flickerstreak@28
|
41 if type(x) == "string" then
|
flickerstreak@28
|
42 name = x
|
flickerstreak@28
|
43 bar = ReAction:GetBar(name)
|
flickerstreak@50
|
44 else
|
flickerstreak@28
|
45 for k,v in pairs(ReAction.bars) do
|
flickerstreak@50
|
46 if v == x then
|
flickerstreak@28
|
47 name = k
|
flickerstreak@50
|
48 bar = x
|
flickerstreak@28
|
49 end
|
flickerstreak@28
|
50 end
|
flickerstreak@28
|
51 end
|
flickerstreak@28
|
52 return bar, name
|
flickerstreak@28
|
53 end
|
flickerstreak@28
|
54
|
flickerstreak@28
|
55 DestroyBar = function(x)
|
flickerstreak@28
|
56 local bar, name = SelectBar(x)
|
flickerstreak@28
|
57 if name and bar then
|
flickerstreak@28
|
58 ReAction.bars[name] = nil
|
flickerstreak@28
|
59 ReAction:CallMethodOnAllModules("RemoveFromBar", bar)
|
flickerstreak@28
|
60 bar:Destroy()
|
flickerstreak@28
|
61 end
|
flickerstreak@28
|
62 end
|
flickerstreak@28
|
63
|
flickerstreak@28
|
64 InitializeBars = function ()
|
flickerstreak@28
|
65 if not(ReAction.inited) then
|
flickerstreak@28
|
66 for name, config in pairs(ReAction.db.profile.bars) do
|
flickerstreak@28
|
67 if config then
|
flickerstreak@28
|
68 ReAction:CreateBar(name, config)
|
flickerstreak@28
|
69 end
|
flickerstreak@28
|
70 end
|
flickerstreak@28
|
71 ReAction:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering
|
flickerstreak@28
|
72 ReAction.inited = true
|
flickerstreak@28
|
73 end
|
flickerstreak@28
|
74 end
|
flickerstreak@28
|
75
|
flickerstreak@28
|
76 TearDownBars = function()
|
flickerstreak@28
|
77 for name, bar in pairs(ReAction.bars) do
|
flickerstreak@28
|
78 if bar then
|
flickerstreak@28
|
79 ReAction.bars[name] = DestroyBar(bar)
|
flickerstreak@28
|
80 end
|
flickerstreak@28
|
81 end
|
flickerstreak@28
|
82 ReAction.inited = false
|
flickerstreak@28
|
83 end
|
flickerstreak@28
|
84
|
flickerstreak@28
|
85 DeepCopy = function(x)
|
flickerstreak@28
|
86 if type(x) ~= "table" then
|
flickerstreak@28
|
87 return x
|
flickerstreak@28
|
88 end
|
flickerstreak@28
|
89 local r = {}
|
flickerstreak@28
|
90 for k,v in pairs(x) do
|
flickerstreak@28
|
91 r[k] = DeepCopy(v)
|
flickerstreak@28
|
92 end
|
flickerstreak@28
|
93 return r
|
flickerstreak@28
|
94 end
|
flickerstreak@28
|
95
|
flickerstreak@28
|
96 SafeCall = function(f, ...)
|
flickerstreak@28
|
97 if f then
|
flickerstreak@28
|
98 local success, err = pcall(f,...)
|
flickerstreak@28
|
99 if not success then
|
flickerstreak@28
|
100 geterrorhandler()(err)
|
flickerstreak@28
|
101 end
|
flickerstreak@28
|
102 end
|
flickerstreak@28
|
103 end
|
flickerstreak@28
|
104
|
flickerstreak@28
|
105 CheckMethod = function(m)
|
flickerstreak@28
|
106 if type(m) == "function" then
|
flickerstreak@28
|
107 return m
|
flickerstreak@28
|
108 end
|
flickerstreak@28
|
109 if type(m) ~= "string" then
|
flickerstreak@28
|
110 error("Invalid method")
|
flickerstreak@28
|
111 end
|
flickerstreak@28
|
112 end
|
flickerstreak@30
|
113
|
flickerstreak@30
|
114 SlashHandler = function(option)
|
flickerstreak@30
|
115 if option == "config" then
|
flickerstreak@38
|
116 ReAction:ShowConfig()
|
flickerstreak@58
|
117 elseif option == "edit" then
|
flickerstreak@58
|
118 ReAction:ShowEditor()
|
flickerstreak@50
|
119 elseif option == "unlock" then
|
flickerstreak@50
|
120 ReAction:SetConfigMode(true)
|
flickerstreak@50
|
121 elseif option == "lock" then
|
flickerstreak@50
|
122 ReAction:SetConfigMode(false)
|
flickerstreak@30
|
123 else
|
flickerstreak@36
|
124 ReAction:Print(("%3.1f.%d"):format(ReAction.version,ReAction.revision))
|
flickerstreak@30
|
125 ReAction:Print("/reaction config")
|
flickerstreak@58
|
126 ReAction:Print("/reaction edit")
|
flickerstreak@50
|
127 ReAction:Print("/reaction lock")
|
flickerstreak@50
|
128 ReAction:Print("/reaction unlock")
|
flickerstreak@30
|
129 end
|
flickerstreak@30
|
130 end
|
flickerstreak@28
|
131 end
|
flickerstreak@28
|
132
|
flickerstreak@28
|
133
|
flickerstreak@28
|
134 ------ HANDLERS ------
|
flickerstreak@28
|
135 function ReAction:OnInitialize()
|
flickerstreak@28
|
136 self.db = LibStub("AceDB-3.0"):New("ReAction_DB",
|
flickerstreak@28
|
137 {
|
flickerstreak@28
|
138 profile = {
|
flickerstreak@28
|
139 bars = { },
|
flickerstreak@28
|
140 defaultBar = { }
|
flickerstreak@28
|
141 }
|
flickerstreak@28
|
142 }
|
flickerstreak@28
|
143 -- default profile is character-specific
|
flickerstreak@28
|
144 )
|
flickerstreak@28
|
145 self.db.RegisterCallback(self,"OnProfileChanged")
|
flickerstreak@43
|
146 self.db.RegisterCallback(self,"OnProfileReset","OnProfileChanged")
|
flickerstreak@30
|
147 self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
|
flickerstreak@30
|
148 self:RegisterChatCommand("reaction", SlashHandler)
|
flickerstreak@30
|
149 self:RegisterChatCommand("rxn", SlashHandler)
|
flickerstreak@33
|
150 self:RegisterEvent("PLAYER_REGEN_DISABLED")
|
flickerstreak@28
|
151
|
flickerstreak@28
|
152 self.bars = {}
|
flickerstreak@48
|
153 self.defaultBarConfig = {}
|
flickerstreak@46
|
154
|
flickerstreak@60
|
155 self.options = {
|
flickerstreak@60
|
156 type = "group",
|
flickerstreak@60
|
157 name = "ReAction",
|
flickerstreak@60
|
158 childGroups = "tab",
|
flickerstreak@60
|
159 args = {
|
flickerstreak@60
|
160 _desc = {
|
flickerstreak@60
|
161 type = "description",
|
flickerstreak@60
|
162 name = L["Customizable replacement for Blizzard's Action Bars"],
|
flickerstreak@60
|
163 order = 1,
|
flickerstreak@60
|
164 },
|
flickerstreak@60
|
165 global = {
|
flickerstreak@60
|
166 type = "group",
|
flickerstreak@60
|
167 name = L["Global Settings"],
|
flickerstreak@60
|
168 desc = L["Global configuration settings"],
|
flickerstreak@60
|
169 args = {
|
flickerstreak@60
|
170 unlock = {
|
flickerstreak@60
|
171 type = "toggle",
|
flickerstreak@60
|
172 handler = module,
|
flickerstreak@60
|
173 name = L["Unlock Bars"],
|
flickerstreak@60
|
174 desc = L["Unlock bars for dragging and resizing with the mouse"],
|
flickerstreak@60
|
175 get = function() return self.configMode end,
|
flickerstreak@60
|
176 set = function(info, value) self:SetConfigMode(value) end,
|
flickerstreak@60
|
177 disabled = InCombatLockdown,
|
flickerstreak@60
|
178 order = 1
|
flickerstreak@60
|
179 },
|
flickerstreak@60
|
180 },
|
flickerstreak@60
|
181 plugins = { },
|
flickerstreak@60
|
182 order = 2,
|
flickerstreak@60
|
183 },
|
flickerstreak@60
|
184 module = {
|
flickerstreak@60
|
185 type = "group",
|
flickerstreak@60
|
186 childGroups = "select",
|
flickerstreak@60
|
187 name = L["Module Settings"],
|
flickerstreak@60
|
188 desc = L["Configuration settings for each module"],
|
flickerstreak@60
|
189 args = { },
|
flickerstreak@60
|
190 plugins = { },
|
flickerstreak@60
|
191 order = 3,
|
flickerstreak@60
|
192 },
|
flickerstreak@60
|
193 profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
|
flickerstreak@46
|
194 },
|
flickerstreak@60
|
195 plugins = { }
|
flickerstreak@60
|
196 }
|
flickerstreak@46
|
197
|
flickerstreak@28
|
198 end
|
flickerstreak@28
|
199
|
flickerstreak@28
|
200 function ReAction:OnEnable()
|
flickerstreak@28
|
201 InitializeBars()
|
flickerstreak@28
|
202 end
|
flickerstreak@28
|
203
|
flickerstreak@28
|
204 function ReAction:OnDisable()
|
flickerstreak@28
|
205 TearDownBars()
|
flickerstreak@28
|
206 end
|
flickerstreak@28
|
207
|
flickerstreak@28
|
208 function ReAction:OnProfileChanged()
|
flickerstreak@33
|
209 TearDownBars()
|
flickerstreak@33
|
210 InitializeBars()
|
flickerstreak@28
|
211 end
|
flickerstreak@28
|
212
|
flickerstreak@28
|
213 function ReAction:OnModuleEnable(module)
|
flickerstreak@28
|
214 if module.ApplyToBar then
|
flickerstreak@28
|
215 for _, b in pairs(bars) do
|
flickerstreak@28
|
216 if b then
|
flickerstreak@28
|
217 module:ApplyToBar(b)
|
flickerstreak@28
|
218 end
|
flickerstreak@28
|
219 end
|
flickerstreak@28
|
220 end
|
flickerstreak@28
|
221 end
|
flickerstreak@28
|
222
|
flickerstreak@28
|
223 function ReAction:OnModuleDisable(module)
|
flickerstreak@28
|
224 if module.RemoveFromBar then
|
flickerstreak@28
|
225 for _, b in pairs(bars) do
|
flickerstreak@28
|
226 if b then
|
flickerstreak@28
|
227 module:RemoveFromBar(b)
|
flickerstreak@28
|
228 end
|
flickerstreak@28
|
229 end
|
flickerstreak@28
|
230 end
|
flickerstreak@28
|
231 end
|
flickerstreak@28
|
232
|
flickerstreak@33
|
233 function ReAction:PLAYER_REGEN_DISABLED()
|
flickerstreak@33
|
234 if self.configMode == true then
|
flickerstreak@33
|
235 UIErrorsFrame:AddMessage(L["ReAction config mode disabled during combat."])
|
flickerstreak@33
|
236 self:SetConfigMode(false)
|
flickerstreak@33
|
237 end
|
flickerstreak@33
|
238 end
|
flickerstreak@33
|
239
|
flickerstreak@33
|
240
|
flickerstreak@28
|
241
|
flickerstreak@28
|
242 ------ API ------
|
flickerstreak@61
|
243 function ReAction:UserError(msg)
|
flickerstreak@61
|
244 -- any user errors should be flashed to the UIErrorsFrame
|
flickerstreak@61
|
245 UIErrorsFrame:AddMessage(msg)
|
flickerstreak@61
|
246 end
|
flickerstreak@61
|
247
|
flickerstreak@28
|
248 function ReAction:CallMethodOnAllModules(method, ...)
|
flickerstreak@28
|
249 local m = CheckMethod(method)
|
flickerstreak@28
|
250 for _, x in self:IterateModules() do
|
flickerstreak@28
|
251 if x then
|
flickerstreak@28
|
252 SafeCall(m or x[method], x, ...)
|
flickerstreak@28
|
253 end
|
flickerstreak@28
|
254 end
|
flickerstreak@28
|
255 end
|
flickerstreak@28
|
256
|
flickerstreak@28
|
257 function ReAction:CallMethodOnAllBars(method,...)
|
flickerstreak@28
|
258 local m = CheckMethod(method)
|
flickerstreak@28
|
259 for _, x in pairs(self.bars) do
|
flickerstreak@28
|
260 if x then
|
flickerstreak@28
|
261 SafeCall(m or x[method], x, ...)
|
flickerstreak@28
|
262 end
|
flickerstreak@28
|
263 end
|
flickerstreak@28
|
264 end
|
flickerstreak@28
|
265
|
flickerstreak@38
|
266 function ReAction:CallModuleMethod(modulename, method, ...)
|
flickerstreak@38
|
267 local m = self:GetModule(modulename,true)
|
flickerstreak@38
|
268 if not m then
|
flickerstreak@38
|
269 LoadAddOn(("ReAction_%s"):format(modulename))
|
flickerstreak@38
|
270 m = self:GetModule(modulename,true)
|
flickerstreak@43
|
271 if m then
|
flickerstreak@43
|
272 dbprint(("succesfully loaded LOD module: %s"):format(modulename))
|
flickerstreak@43
|
273 end
|
flickerstreak@38
|
274 end
|
flickerstreak@38
|
275 if m then
|
flickerstreak@38
|
276 if type(m) == "table" and type(m[method]) == "function" then
|
flickerstreak@38
|
277 m[method](m,...)
|
flickerstreak@38
|
278 else
|
flickerstreak@38
|
279 dbprint(("Bad call '%s' to %s module"):format(tostring(method),modulename));
|
flickerstreak@38
|
280 end
|
flickerstreak@38
|
281 else
|
flickerstreak@38
|
282 self:Print(("Module '%s' not found"):format(tostring(modulename)))
|
flickerstreak@38
|
283 end
|
flickerstreak@38
|
284 end
|
flickerstreak@38
|
285
|
flickerstreak@38
|
286
|
flickerstreak@48
|
287 function ReAction:CreateBar(name, ...)
|
flickerstreak@48
|
288 local config = select(1,...)
|
flickerstreak@48
|
289 if config and type(config) ~= "table" then
|
flickerstreak@48
|
290 bartype = select(1,...)
|
flickerstreak@48
|
291 if type(bartype) ~= "string" then
|
flickerstreak@48
|
292 error("ReAction:CreateBar() - first argument must be a config table or a default config type string")
|
flickerstreak@48
|
293 end
|
flickerstreak@48
|
294 config = self.defaultBarConfig[bartype]
|
flickerstreak@48
|
295 if not config then
|
flickerstreak@48
|
296 error(("ReAction:CreateBar() - unknown bar type '%s'"):format(bartype))
|
flickerstreak@48
|
297 end
|
flickerstreak@48
|
298 config = DeepCopy(config)
|
flickerstreak@48
|
299 config.btnRows = select(2,...) or config.btnRows or 1
|
flickerstreak@48
|
300 config.btnColumns = select(3,...) or config.btnColumns or 12
|
flickerstreak@48
|
301 config.btnWidth = select(4,...) or config.btnWidth or 36
|
flickerstreak@48
|
302 config.btnHeight = select(4,...) or config.btnHeight or 36
|
flickerstreak@48
|
303 config.spacing = select(5,...) or config.spacing or 3
|
flickerstreak@48
|
304 config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1
|
flickerstreak@48
|
305 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1
|
flickerstreak@48
|
306 config.anchor = config.anchor or "BOTTOM"
|
flickerstreak@48
|
307 config.anchorTo = config.anchorTo or "UIParent"
|
flickerstreak@48
|
308 config.relativePoint = config.relativePoint or "BOTTOM"
|
flickerstreak@48
|
309 config.y = config.y or 200
|
flickerstreak@48
|
310 config.x = config.x or 0
|
flickerstreak@48
|
311 end
|
flickerstreak@28
|
312 local profile = self.db.profile
|
flickerstreak@48
|
313 config = config or DeepCopy(profile.defaultBar)
|
flickerstreak@28
|
314 prefix = prefix or L["Bar "]
|
flickerstreak@28
|
315 if not name then
|
flickerstreak@28
|
316 i = 1
|
flickerstreak@28
|
317 repeat
|
flickerstreak@28
|
318 name = prefix..i
|
flickerstreak@28
|
319 i = i + 1
|
flickerstreak@28
|
320 until self.bars[name] == nil
|
flickerstreak@28
|
321 end
|
flickerstreak@48
|
322 profile.bars[name] = profile.bars[name] or config
|
flickerstreak@28
|
323 local bar = self.Bar:new( name, profile.bars[name] ) -- ReAction.Bar defined in Bar.lua
|
flickerstreak@28
|
324 self:CallMethodOnAllModules("ApplyToBar", bar)
|
flickerstreak@28
|
325 self.bars[name] = bar
|
flickerstreak@30
|
326 self.callbacks:Fire("OnCreateBar", bar)
|
flickerstreak@33
|
327 if self.configMode then
|
flickerstreak@33
|
328 bar:ShowControls(true)
|
flickerstreak@33
|
329 end
|
flickerstreak@33
|
330
|
flickerstreak@28
|
331 return bar
|
flickerstreak@28
|
332 end
|
flickerstreak@28
|
333
|
flickerstreak@28
|
334 function ReAction:EraseBar(x)
|
flickerstreak@28
|
335 local bar, name = SelectBar(x)
|
flickerstreak@28
|
336 if name and bar then
|
flickerstreak@28
|
337 DestroyBar(bar)
|
flickerstreak@28
|
338 self.db.profile.bars[name] = nil
|
flickerstreak@28
|
339 self:CallMethodOnAllModules("EraseBarConfig", name)
|
flickerstreak@30
|
340 self.callbacks:Fire("OnEraseBar",name)
|
flickerstreak@28
|
341 end
|
flickerstreak@28
|
342 end
|
flickerstreak@28
|
343
|
flickerstreak@28
|
344 function ReAction:GetBar(name)
|
flickerstreak@28
|
345 return self.bars[name]
|
flickerstreak@28
|
346 end
|
flickerstreak@28
|
347
|
flickerstreak@28
|
348 function ReAction:RenameBar(x, newname)
|
flickerstreak@28
|
349 local bar, name = SelectBar(x)
|
flickerstreak@28
|
350 if bar and name and newname then
|
flickerstreak@28
|
351 if self.bars[newname] then
|
flickerstreak@47
|
352 UIErrorsFrame:AddMessage(("%s ('%s')"):format(L["ReAction: name already in use"],newname))
|
flickerstreak@47
|
353 else
|
flickerstreak@47
|
354 self.bars[newname] = self.bars[name]
|
flickerstreak@47
|
355 self.bars[name] = nil
|
flickerstreak@47
|
356 bar:SetName(newname or "")
|
flickerstreak@47
|
357 local cfg = self.db.profile.bars
|
flickerstreak@47
|
358 cfg[newname], cfg[name] = cfg[name], nil
|
flickerstreak@47
|
359 self:CallMethodOnAllModules("RenameBarConfig", name, newname)
|
flickerstreak@47
|
360 self.callbacks:Fire("OnRenameBar", name, newname)
|
flickerstreak@28
|
361 end
|
flickerstreak@28
|
362 end
|
flickerstreak@28
|
363 end
|
flickerstreak@28
|
364
|
flickerstreak@53
|
365 function ReAction:RegisterBarType( name, config, isDefaultChoice )
|
flickerstreak@48
|
366 self.defaultBarConfig[name] = config
|
flickerstreak@48
|
367 if isDefaultChoice then
|
flickerstreak@48
|
368 self.defaultBarConfigChoice = name
|
flickerstreak@48
|
369 end
|
flickerstreak@48
|
370 self:RefreshOptions()
|
flickerstreak@48
|
371 end
|
flickerstreak@48
|
372
|
flickerstreak@53
|
373 function ReAction:UnregisterBarType( name )
|
flickerstreak@48
|
374 self.defaultBarConfig[name] = nil
|
flickerstreak@48
|
375 if self.defaultBarConfigChoice == name then
|
flickerstreak@48
|
376 self.defaultBarConfigChoice = nil
|
flickerstreak@48
|
377 end
|
flickerstreak@48
|
378 self:RefreshOptions()
|
flickerstreak@48
|
379 end
|
flickerstreak@48
|
380
|
flickerstreak@60
|
381 function ReAction:RegisterOptions(module, options, global)
|
flickerstreak@60
|
382 self.options.args[global and "global" or "module"].plugins[module:GetName()] = options
|
flickerstreak@30
|
383 end
|
flickerstreak@30
|
384
|
flickerstreak@30
|
385 function ReAction:RefreshOptions()
|
flickerstreak@30
|
386 self.callbacks:Fire("OnOptionsRefreshed")
|
flickerstreak@30
|
387 end
|
flickerstreak@33
|
388
|
flickerstreak@33
|
389 function ReAction:SetConfigMode( mode )
|
flickerstreak@33
|
390 self:CallMethodOnAllBars("ShowControls",mode)
|
flickerstreak@33
|
391 self:CallMethodOnAllModules("ApplyConfigMode",mode,self.bars)
|
flickerstreak@33
|
392 self.configMode = mode
|
flickerstreak@33
|
393 end
|
flickerstreak@38
|
394
|
flickerstreak@38
|
395 function ReAction:ShowConfig()
|
flickerstreak@38
|
396 self:CallModuleMethod("ConfigUI","OpenConfig")
|
flickerstreak@38
|
397 end
|
flickerstreak@38
|
398
|
flickerstreak@58
|
399 function ReAction:ShowEditor()
|
flickerstreak@58
|
400 self:CallModuleMethod("ConfigUI","LaunchBarEditor")
|
flickerstreak@47
|
401 end
|