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@28
|
44 elseif ReAction.Bar:IsInstance(x) then
|
flickerstreak@28
|
45 bar = x
|
flickerstreak@28
|
46 for k,v in pairs(ReAction.bars) do
|
flickerstreak@28
|
47 if v == bar then
|
flickerstreak@28
|
48 name = k
|
flickerstreak@28
|
49 end
|
flickerstreak@28
|
50 end
|
flickerstreak@28
|
51 else
|
flickerstreak@28
|
52 error("bad argument to SelectBar")
|
flickerstreak@28
|
53 end
|
flickerstreak@28
|
54 return bar, name
|
flickerstreak@28
|
55 end
|
flickerstreak@28
|
56
|
flickerstreak@28
|
57 DestroyBar = function(x)
|
flickerstreak@28
|
58 local bar, name = SelectBar(x)
|
flickerstreak@28
|
59 if name and bar then
|
flickerstreak@28
|
60 ReAction.bars[name] = nil
|
flickerstreak@28
|
61 ReAction:CallMethodOnAllModules("RemoveFromBar", bar)
|
flickerstreak@28
|
62 bar:Destroy()
|
flickerstreak@28
|
63 end
|
flickerstreak@28
|
64 end
|
flickerstreak@28
|
65
|
flickerstreak@28
|
66 InitializeBars = function ()
|
flickerstreak@28
|
67 if not(ReAction.inited) then
|
flickerstreak@28
|
68 for name, config in pairs(ReAction.db.profile.bars) do
|
flickerstreak@28
|
69 if config then
|
flickerstreak@28
|
70 ReAction:CreateBar(name, config)
|
flickerstreak@28
|
71 end
|
flickerstreak@28
|
72 end
|
flickerstreak@28
|
73 ReAction:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering
|
flickerstreak@28
|
74 ReAction.inited = true
|
flickerstreak@28
|
75 end
|
flickerstreak@28
|
76 end
|
flickerstreak@28
|
77
|
flickerstreak@28
|
78 TearDownBars = function()
|
flickerstreak@28
|
79 for name, bar in pairs(ReAction.bars) do
|
flickerstreak@28
|
80 if bar then
|
flickerstreak@28
|
81 ReAction.bars[name] = DestroyBar(bar)
|
flickerstreak@28
|
82 end
|
flickerstreak@28
|
83 end
|
flickerstreak@28
|
84 ReAction.inited = false
|
flickerstreak@28
|
85 end
|
flickerstreak@28
|
86
|
flickerstreak@28
|
87 DeepCopy = function(x)
|
flickerstreak@28
|
88 if type(x) ~= "table" then
|
flickerstreak@28
|
89 return x
|
flickerstreak@28
|
90 end
|
flickerstreak@28
|
91 local r = {}
|
flickerstreak@28
|
92 for k,v in pairs(x) do
|
flickerstreak@28
|
93 r[k] = DeepCopy(v)
|
flickerstreak@28
|
94 end
|
flickerstreak@28
|
95 return r
|
flickerstreak@28
|
96 end
|
flickerstreak@28
|
97
|
flickerstreak@28
|
98 SafeCall = function(f, ...)
|
flickerstreak@28
|
99 if f then
|
flickerstreak@28
|
100 local success, err = pcall(f,...)
|
flickerstreak@28
|
101 if not success then
|
flickerstreak@28
|
102 geterrorhandler()(err)
|
flickerstreak@28
|
103 end
|
flickerstreak@28
|
104 end
|
flickerstreak@28
|
105 end
|
flickerstreak@28
|
106
|
flickerstreak@28
|
107 CheckMethod = function(m)
|
flickerstreak@28
|
108 if type(m) == "function" then
|
flickerstreak@28
|
109 return m
|
flickerstreak@28
|
110 end
|
flickerstreak@28
|
111 if type(m) ~= "string" then
|
flickerstreak@28
|
112 error("Invalid method")
|
flickerstreak@28
|
113 end
|
flickerstreak@28
|
114 end
|
flickerstreak@30
|
115
|
flickerstreak@30
|
116 SlashHandler = function(option)
|
flickerstreak@30
|
117 if option == "config" then
|
flickerstreak@38
|
118 ReAction:ShowConfig()
|
flickerstreak@47
|
119 elseif option == "layout" then
|
flickerstreak@47
|
120 ReAction:ShowLayout()
|
flickerstreak@30
|
121 else
|
flickerstreak@36
|
122 ReAction:Print(("%3.1f.%d"):format(ReAction.version,ReAction.revision))
|
flickerstreak@30
|
123 ReAction:Print("/reaction config")
|
flickerstreak@47
|
124 ReAction:Print("/reaction layout")
|
flickerstreak@30
|
125 end
|
flickerstreak@30
|
126 end
|
flickerstreak@28
|
127 end
|
flickerstreak@28
|
128
|
flickerstreak@28
|
129
|
flickerstreak@28
|
130 ------ HANDLERS ------
|
flickerstreak@28
|
131 function ReAction:OnInitialize()
|
flickerstreak@28
|
132 self.db = LibStub("AceDB-3.0"):New("ReAction_DB",
|
flickerstreak@28
|
133 {
|
flickerstreak@28
|
134 profile = {
|
flickerstreak@28
|
135 bars = { },
|
flickerstreak@28
|
136 defaultBar = { }
|
flickerstreak@28
|
137 }
|
flickerstreak@28
|
138 }
|
flickerstreak@28
|
139 -- default profile is character-specific
|
flickerstreak@28
|
140 )
|
flickerstreak@28
|
141 self.db.RegisterCallback(self,"OnProfileChanged")
|
flickerstreak@43
|
142 self.db.RegisterCallback(self,"OnProfileReset","OnProfileChanged")
|
flickerstreak@30
|
143 self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
|
flickerstreak@30
|
144 self:RegisterChatCommand("reaction", SlashHandler)
|
flickerstreak@30
|
145 self:RegisterChatCommand("rxn", SlashHandler)
|
flickerstreak@33
|
146 self:RegisterEvent("PLAYER_REGEN_DISABLED")
|
flickerstreak@28
|
147
|
flickerstreak@28
|
148 self.bars = {}
|
flickerstreak@46
|
149 self.options = {}
|
flickerstreak@46
|
150
|
flickerstreak@46
|
151 self:RegisterOptions("global", self, {
|
flickerstreak@46
|
152 unlock = {
|
flickerstreak@46
|
153 type = "toggle",
|
flickerstreak@46
|
154 handler = module,
|
flickerstreak@46
|
155 name = L["Unlock Bars"],
|
flickerstreak@46
|
156 desc = L["Unlock bars for dragging and resizing with the mouse"],
|
flickerstreak@46
|
157 get = function() return self.configMode end,
|
flickerstreak@46
|
158 set = function(info, value) self:SetConfigMode(value) end,
|
flickerstreak@46
|
159 disabled = InCombatLockdown,
|
flickerstreak@46
|
160 order = 1
|
flickerstreak@46
|
161 },
|
flickerstreak@46
|
162 })
|
flickerstreak@46
|
163
|
flickerstreak@28
|
164 end
|
flickerstreak@28
|
165
|
flickerstreak@28
|
166 function ReAction:OnEnable()
|
flickerstreak@28
|
167 InitializeBars()
|
flickerstreak@28
|
168 end
|
flickerstreak@28
|
169
|
flickerstreak@28
|
170 function ReAction:OnDisable()
|
flickerstreak@28
|
171 TearDownBars()
|
flickerstreak@28
|
172 end
|
flickerstreak@28
|
173
|
flickerstreak@28
|
174 function ReAction:OnProfileChanged()
|
flickerstreak@33
|
175 TearDownBars()
|
flickerstreak@33
|
176 InitializeBars()
|
flickerstreak@28
|
177 end
|
flickerstreak@28
|
178
|
flickerstreak@28
|
179 function ReAction:OnModuleEnable(module)
|
flickerstreak@28
|
180 if module.ApplyToBar then
|
flickerstreak@28
|
181 for _, b in pairs(bars) do
|
flickerstreak@28
|
182 if b then
|
flickerstreak@28
|
183 module:ApplyToBar(b)
|
flickerstreak@28
|
184 end
|
flickerstreak@28
|
185 end
|
flickerstreak@28
|
186 end
|
flickerstreak@28
|
187 end
|
flickerstreak@28
|
188
|
flickerstreak@28
|
189 function ReAction:OnModuleDisable(module)
|
flickerstreak@28
|
190 if module.RemoveFromBar then
|
flickerstreak@28
|
191 for _, b in pairs(bars) do
|
flickerstreak@28
|
192 if b then
|
flickerstreak@28
|
193 module:RemoveFromBar(b)
|
flickerstreak@28
|
194 end
|
flickerstreak@28
|
195 end
|
flickerstreak@28
|
196 end
|
flickerstreak@28
|
197 end
|
flickerstreak@28
|
198
|
flickerstreak@33
|
199 function ReAction:PLAYER_REGEN_DISABLED()
|
flickerstreak@33
|
200 if self.configMode == true then
|
flickerstreak@33
|
201 UIErrorsFrame:AddMessage(L["ReAction config mode disabled during combat."])
|
flickerstreak@33
|
202 self:SetConfigMode(false)
|
flickerstreak@33
|
203 end
|
flickerstreak@33
|
204 end
|
flickerstreak@33
|
205
|
flickerstreak@33
|
206
|
flickerstreak@28
|
207
|
flickerstreak@28
|
208 ------ API ------
|
flickerstreak@28
|
209 function ReAction:CallMethodOnAllModules(method, ...)
|
flickerstreak@28
|
210 local m = CheckMethod(method)
|
flickerstreak@28
|
211 for _, x in self:IterateModules() do
|
flickerstreak@28
|
212 if x then
|
flickerstreak@28
|
213 SafeCall(m or x[method], x, ...)
|
flickerstreak@28
|
214 end
|
flickerstreak@28
|
215 end
|
flickerstreak@28
|
216 end
|
flickerstreak@28
|
217
|
flickerstreak@28
|
218 function ReAction:CallMethodOnAllBars(method,...)
|
flickerstreak@28
|
219 local m = CheckMethod(method)
|
flickerstreak@28
|
220 for _, x in pairs(self.bars) do
|
flickerstreak@28
|
221 if x then
|
flickerstreak@28
|
222 SafeCall(m or x[method], x, ...)
|
flickerstreak@28
|
223 end
|
flickerstreak@28
|
224 end
|
flickerstreak@28
|
225 end
|
flickerstreak@28
|
226
|
flickerstreak@38
|
227 function ReAction:CallModuleMethod(modulename, method, ...)
|
flickerstreak@38
|
228 local m = self:GetModule(modulename,true)
|
flickerstreak@38
|
229 if not m then
|
flickerstreak@38
|
230 LoadAddOn(("ReAction_%s"):format(modulename))
|
flickerstreak@38
|
231 m = self:GetModule(modulename,true)
|
flickerstreak@43
|
232 if m then
|
flickerstreak@43
|
233 dbprint(("succesfully loaded LOD module: %s"):format(modulename))
|
flickerstreak@43
|
234 end
|
flickerstreak@38
|
235 end
|
flickerstreak@38
|
236 if m then
|
flickerstreak@38
|
237 if type(m) == "table" and type(m[method]) == "function" then
|
flickerstreak@38
|
238 m[method](m,...)
|
flickerstreak@38
|
239 else
|
flickerstreak@38
|
240 dbprint(("Bad call '%s' to %s module"):format(tostring(method),modulename));
|
flickerstreak@38
|
241 end
|
flickerstreak@38
|
242 else
|
flickerstreak@38
|
243 self:Print(("Module '%s' not found"):format(tostring(modulename)))
|
flickerstreak@38
|
244 end
|
flickerstreak@38
|
245 end
|
flickerstreak@38
|
246
|
flickerstreak@38
|
247
|
flickerstreak@28
|
248 function ReAction:CreateBar(name, defaultConfig, prefix)
|
flickerstreak@28
|
249 local profile = self.db.profile
|
flickerstreak@28
|
250 defaultConfig = defaultConfig or profile.defaultBar
|
flickerstreak@28
|
251 prefix = prefix or L["Bar "]
|
flickerstreak@28
|
252 if not name then
|
flickerstreak@28
|
253 i = 1
|
flickerstreak@28
|
254 repeat
|
flickerstreak@28
|
255 name = prefix..i
|
flickerstreak@28
|
256 i = i + 1
|
flickerstreak@28
|
257 until self.bars[name] == nil
|
flickerstreak@28
|
258 end
|
flickerstreak@28
|
259 profile.bars[name] = profile.bars[name] or DeepCopy(defaultConfig)
|
flickerstreak@28
|
260 local bar = self.Bar:new( name, profile.bars[name] ) -- ReAction.Bar defined in Bar.lua
|
flickerstreak@28
|
261 self:CallMethodOnAllModules("ApplyToBar", bar)
|
flickerstreak@28
|
262 self.bars[name] = bar
|
flickerstreak@30
|
263 self.callbacks:Fire("OnCreateBar", bar)
|
flickerstreak@33
|
264 if self.configMode then
|
flickerstreak@33
|
265 bar:ShowControls(true)
|
flickerstreak@33
|
266 end
|
flickerstreak@33
|
267
|
flickerstreak@28
|
268 return bar
|
flickerstreak@28
|
269 end
|
flickerstreak@28
|
270
|
flickerstreak@28
|
271 function ReAction:EraseBar(x)
|
flickerstreak@28
|
272 local bar, name = SelectBar(x)
|
flickerstreak@28
|
273 if name and bar then
|
flickerstreak@28
|
274 DestroyBar(bar)
|
flickerstreak@28
|
275 self.db.profile.bars[name] = nil
|
flickerstreak@28
|
276 self:CallMethodOnAllModules("EraseBarConfig", name)
|
flickerstreak@30
|
277 self.callbacks:Fire("OnEraseBar",name)
|
flickerstreak@28
|
278 end
|
flickerstreak@28
|
279 end
|
flickerstreak@28
|
280
|
flickerstreak@28
|
281 function ReAction:GetBar(name)
|
flickerstreak@28
|
282 return self.bars[name]
|
flickerstreak@28
|
283 end
|
flickerstreak@28
|
284
|
flickerstreak@28
|
285 function ReAction:RenameBar(x, newname)
|
flickerstreak@28
|
286 local bar, name = SelectBar(x)
|
flickerstreak@28
|
287 if bar and name and newname then
|
flickerstreak@28
|
288 if self.bars[newname] then
|
flickerstreak@47
|
289 UIErrorsFrame:AddMessage(("%s ('%s')"):format(L["ReAction: name already in use"],newname))
|
flickerstreak@47
|
290 else
|
flickerstreak@47
|
291 self.bars[newname] = self.bars[name]
|
flickerstreak@47
|
292 self.bars[name] = nil
|
flickerstreak@47
|
293 bar:SetName(newname or "")
|
flickerstreak@47
|
294 local cfg = self.db.profile.bars
|
flickerstreak@47
|
295 cfg[newname], cfg[name] = cfg[name], nil
|
flickerstreak@47
|
296 self:CallMethodOnAllModules("RenameBarConfig", name, newname)
|
flickerstreak@47
|
297 self.callbacks:Fire("OnRenameBar", name, newname)
|
flickerstreak@28
|
298 end
|
flickerstreak@28
|
299 end
|
flickerstreak@28
|
300 end
|
flickerstreak@28
|
301
|
flickerstreak@30
|
302 -- See modules/ReAction_ConfigUI for valid options contexts.
|
flickerstreak@30
|
303 function ReAction:RegisterOptions(context, module, opts)
|
flickerstreak@30
|
304 if module == nil or context == nil then
|
flickerstreak@30
|
305 error("ReAction:RegisterOptions requires a module object and context ID")
|
flickerstreak@30
|
306 end
|
flickerstreak@30
|
307 if not self.options[context] then
|
flickerstreak@30
|
308 self.options[context] = {}
|
flickerstreak@30
|
309 end
|
flickerstreak@30
|
310 self.options[context][module] = opts
|
flickerstreak@30
|
311 self.callbacks:Fire("OnOptionsRegistered", context, module, opts)
|
flickerstreak@30
|
312 end
|
flickerstreak@28
|
313
|
flickerstreak@30
|
314 function ReAction:GetOptions(context)
|
flickerstreak@30
|
315 if context then
|
flickerstreak@30
|
316 if not self.options[context] then
|
flickerstreak@30
|
317 self.options[context] = { }
|
flickerstreak@30
|
318 end
|
flickerstreak@30
|
319 return self.options[context]
|
flickerstreak@30
|
320 end
|
flickerstreak@30
|
321 end
|
flickerstreak@30
|
322
|
flickerstreak@30
|
323 function ReAction:GetOptionContextList()
|
flickerstreak@30
|
324 local c = {}
|
flickerstreak@30
|
325 for k in self.options do
|
flickerstreak@30
|
326 tinsert(c,k)
|
flickerstreak@30
|
327 end
|
flickerstreak@30
|
328 return c
|
flickerstreak@30
|
329 end
|
flickerstreak@30
|
330
|
flickerstreak@30
|
331 function ReAction:RefreshOptions()
|
flickerstreak@30
|
332 self.callbacks:Fire("OnOptionsRefreshed")
|
flickerstreak@30
|
333 end
|
flickerstreak@33
|
334
|
flickerstreak@33
|
335 function ReAction:SetConfigMode( mode )
|
flickerstreak@33
|
336 self:CallMethodOnAllBars("ShowControls",mode)
|
flickerstreak@33
|
337 self:CallMethodOnAllModules("ApplyConfigMode",mode,self.bars)
|
flickerstreak@33
|
338 self.configMode = mode
|
flickerstreak@33
|
339 end
|
flickerstreak@38
|
340
|
flickerstreak@38
|
341 function ReAction:ShowConfig()
|
flickerstreak@38
|
342 self:CallModuleMethod("ConfigUI","OpenConfig")
|
flickerstreak@38
|
343 end
|
flickerstreak@38
|
344
|
flickerstreak@47
|
345 function ReAction:ShowLayout()
|
flickerstreak@47
|
346 self:CallModuleMethod("ConfigUI","LaunchLayoutEditor")
|
flickerstreak@47
|
347 end
|