flickerstreak@201
|
1 local addonName, addonTable = ...
|
flickerstreak@205
|
2 local pcall = pcall
|
flickerstreak@205
|
3 local pairs = pairs
|
flickerstreak@205
|
4 local type = type
|
flickerstreak@205
|
5 local geterrorhandler = geterrorhandler
|
flickerstreak@33
|
6 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
|
Flick@230
|
7 local LKB = LibStub("LibKeyBound-1.0",true)
|
Flick@230
|
8 if not LKB then
|
Flick@230
|
9 LoadAddOn("LibKeyBound-1.0")
|
Flick@230
|
10 LKB = LibStub("LibKeyBound-1.0")
|
Flick@230
|
11 end
|
flickerstreak@33
|
12
|
flickerstreak@205
|
13 ------ Utility ------
|
flickerstreak@205
|
14 local tcopy
|
flickerstreak@28
|
15 do
|
flickerstreak@205
|
16 function tcopy(x)
|
flickerstreak@28
|
17 if type(x) ~= "table" then
|
flickerstreak@28
|
18 return x
|
flickerstreak@28
|
19 end
|
flickerstreak@28
|
20 local r = {}
|
flickerstreak@28
|
21 for k,v in pairs(x) do
|
flickerstreak@205
|
22 r[k] = tcopy(v)
|
flickerstreak@28
|
23 end
|
flickerstreak@28
|
24 return r
|
flickerstreak@28
|
25 end
|
flickerstreak@28
|
26 end
|
flickerstreak@28
|
27
|
flickerstreak@205
|
28 ------ Core ------
|
flickerstreak@205
|
29 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
|
flickerstreak@205
|
30 "AceEvent-3.0"
|
flickerstreak@205
|
31 )
|
flickerstreak@205
|
32 addonTable.ReAction = ReAction
|
flickerstreak@205
|
33 ReAction.version = "1.1"
|
flickerstreak@205
|
34 ReAction.L = L
|
flickerstreak@205
|
35 ReAction.LKB = LKB
|
flickerstreak@28
|
36
|
flickerstreak@205
|
37
|
flickerstreak@223
|
38 ReAction.barTypes = { }
|
flickerstreak@223
|
39
|
flickerstreak@205
|
40 ------ Handlers ------
|
flickerstreak@28
|
41 function ReAction:OnInitialize()
|
flickerstreak@28
|
42 self.db = LibStub("AceDB-3.0"):New("ReAction_DB",
|
flickerstreak@213
|
43 self.defaultProfile,
|
flickerstreak@182
|
44 true -- use global 'Default' (locale-specific)
|
flickerstreak@28
|
45 )
|
flickerstreak@205
|
46
|
flickerstreak@213
|
47 self:UpgradeProfile()
|
flickerstreak@211
|
48
|
flickerstreak@205
|
49 self.bars = { }
|
flickerstreak@205
|
50
|
flickerstreak@213
|
51 self.LBF = LibStub("LibButtonFacade",true)
|
flickerstreak@213
|
52 if self.LBF then
|
flickerstreak@213
|
53 self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self)
|
flickerstreak@213
|
54 end
|
flickerstreak@213
|
55
|
flickerstreak@211
|
56 -- It's fairly normal to use the Blizzard vehicle bar, and to have
|
flickerstreak@211
|
57 -- your regular buttons in the same location. If you do this, and don't
|
flickerstreak@211
|
58 -- bother to hide your buttons, they'll obscure some parts of the vehicle bar.
|
flickerstreak@211
|
59 VehicleMenuBar:SetFrameLevel(VehicleMenuBar:GetFrameLevel()+3)
|
flickerstreak@211
|
60
|
flickerstreak@205
|
61 self.callbacks = LibStub("CallbackHandler-1.0"):New(self)
|
Flick@227
|
62
|
flickerstreak@184
|
63 LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED")
|
flickerstreak@184
|
64 LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED")
|
flickerstreak@207
|
65 LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
|
Flick@227
|
66
|
Flick@227
|
67 -- see Profile.lua for these callback implementations
|
Flick@227
|
68 self.db.RegisterCallback(self,"OnProfileChanged")
|
Flick@227
|
69 self.db.RegisterCallback(self,"OnProfileCopied","OnProfileChanged")
|
Flick@227
|
70 self.db.RegisterCallback(self,"OnNewProfile")
|
Flick@227
|
71 self.db.RegisterCallback(self,"OnProfileReset", "OnNewProfile")
|
Flick@227
|
72
|
flickerstreak@182
|
73 self:RegisterEvent("PLAYER_REGEN_DISABLED")
|
Flick@227
|
74
|
flickerstreak@182
|
75 self:InitializeOptions()
|
flickerstreak@28
|
76 end
|
flickerstreak@28
|
77
|
flickerstreak@28
|
78 function ReAction:OnEnable()
|
flickerstreak@205
|
79 self:InitializeBars()
|
flickerstreak@28
|
80 end
|
flickerstreak@28
|
81
|
flickerstreak@28
|
82 function ReAction:OnDisable()
|
flickerstreak@205
|
83 self:TearDownBars()
|
flickerstreak@28
|
84 end
|
flickerstreak@28
|
85
|
flickerstreak@33
|
86 function ReAction:PLAYER_REGEN_DISABLED()
|
flickerstreak@205
|
87 if self.configMode == true then
|
flickerstreak@63
|
88 self:UserError(L["ReAction config mode disabled during combat."])
|
flickerstreak@33
|
89 self:SetConfigMode(false)
|
flickerstreak@88
|
90 self:SetKeybindMode(false)
|
flickerstreak@185
|
91 self:CloseEditor()
|
flickerstreak@33
|
92 end
|
flickerstreak@33
|
93 end
|
flickerstreak@33
|
94
|
flickerstreak@88
|
95 function ReAction:LIBKEYBOUND_ENABLED( evt )
|
flickerstreak@88
|
96 self:SetKeybindMode(true)
|
flickerstreak@88
|
97 end
|
flickerstreak@88
|
98
|
flickerstreak@88
|
99 function ReAction:LIBKEYBOUND_DISABLED( evt )
|
flickerstreak@88
|
100 return self:SetKeybindMode(false)
|
flickerstreak@88
|
101 end
|
flickerstreak@88
|
102
|
flickerstreak@213
|
103 function ReAction:OnSkinChanged( skinID, gloss, backdrop, group, button, colors )
|
flickerstreak@213
|
104 if group == nil then
|
flickerstreak@213
|
105 -- don't store global
|
flickerstreak@213
|
106 else
|
flickerstreak@213
|
107 -- 'group' is the bar-name
|
flickerstreak@213
|
108 local bar = self:GetBar(group)
|
flickerstreak@213
|
109 if bar then
|
flickerstreak@213
|
110 local c = bar:GetConfig().ButtonFacade
|
flickerstreak@213
|
111 if c then
|
flickerstreak@213
|
112 c.skinID = skinID
|
flickerstreak@213
|
113 c.gloss = gloss
|
flickerstreak@213
|
114 c.backdrop = backdrop
|
flickerstreak@213
|
115 c.colors = colors
|
flickerstreak@213
|
116 end
|
flickerstreak@213
|
117 end
|
flickerstreak@213
|
118 end
|
flickerstreak@213
|
119 end
|
flickerstreak@213
|
120
|
flickerstreak@33
|
121
|
flickerstreak@205
|
122 ------ Methods ------
|
flickerstreak@77
|
123
|
flickerstreak@61
|
124 function ReAction:UserError(msg)
|
flickerstreak@61
|
125 UIErrorsFrame:AddMessage(msg)
|
flickerstreak@61
|
126 end
|
flickerstreak@61
|
127
|
flickerstreak@205
|
128 function ReAction:GetBar(arg)
|
flickerstreak@205
|
129 if type(arg) == "string" then
|
flickerstreak@205
|
130 return self.bars[arg], arg
|
flickerstreak@205
|
131 elseif type(arg) == "table" then -- reverse lookup
|
flickerstreak@205
|
132 for name, bar in pairs(self.bars) do
|
flickerstreak@205
|
133 if arg == bar then
|
flickerstreak@205
|
134 return bar, name
|
flickerstreak@205
|
135 end
|
flickerstreak@205
|
136 end
|
flickerstreak@205
|
137 else
|
flickerstreak@205
|
138 error("ReAction:GetBar() requires either a name or a bar table arg")
|
flickerstreak@205
|
139 end
|
flickerstreak@184
|
140 end
|
flickerstreak@184
|
141
|
flickerstreak@205
|
142 function ReAction:IterateBars()
|
flickerstreak@205
|
143 return pairs(self.bars)
|
flickerstreak@205
|
144 end
|
flickerstreak@184
|
145
|
flickerstreak@63
|
146 -- usage:
|
flickerstreak@91
|
147 -- (1) ReAction:CreateBar(name, [cfgTable])
|
flickerstreak@63
|
148 -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing])
|
flickerstreak@91
|
149 function ReAction:CreateBar(name, config, ...)
|
flickerstreak@91
|
150 local profile = self.db.profile
|
flickerstreak@91
|
151
|
flickerstreak@217
|
152 name = tostring(name)
|
flickerstreak@217
|
153 if not name or name == "" then
|
flickerstreak@217
|
154 error("ReAction:CreateBar() - bar name string required")
|
flickerstreak@217
|
155 elseif self.bars[name] then
|
flickerstreak@217
|
156 self:UserError(format(L["ReAction: name '%s' already in use"],name))
|
flickerstreak@217
|
157 return nil
|
flickerstreak@91
|
158 end
|
flickerstreak@91
|
159
|
flickerstreak@223
|
160 local class
|
flickerstreak@91
|
161 if type(config) == "string" then
|
flickerstreak@223
|
162 class = self.barTypes[config]
|
flickerstreak@218
|
163 if not class then
|
flickerstreak@218
|
164 error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config))
|
flickerstreak@48
|
165 end
|
flickerstreak@218
|
166 config = tcopy(class:GetDefaultBarConfig())
|
flickerstreak@218
|
167 config.btnRows = select(1,...) or config.btnRows
|
flickerstreak@218
|
168 config.btnColumns = select(2,...) or config.btnColumns
|
flickerstreak@218
|
169 config.btnWidth = select(3,...) or config.btnWidth
|
flickerstreak@218
|
170 config.btnHeight = select(3,...) or config.btnHeight
|
flickerstreak@218
|
171 config.spacing = select(4,...) or config.spacing
|
flickerstreak@48
|
172 config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1
|
flickerstreak@48
|
173 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1
|
flickerstreak@81
|
174 config.anchor = config.anchor or "UIParent"
|
flickerstreak@81
|
175 config.point = config.point or "BOTTOM"
|
flickerstreak@81
|
176 config.relpoint = config.relpoint or "BOTTOM"
|
flickerstreak@48
|
177 config.y = config.y or 200
|
flickerstreak@48
|
178 config.x = config.x or 0
|
flickerstreak@223
|
179 else
|
flickerstreak@223
|
180 config = config or profile.bars[name] or { }
|
flickerstreak@223
|
181 if not config or not config.type or not self.barTypes[config.type] then
|
flickerstreak@223
|
182 error(("ReAction: Unable to construct/fetch config table for bar '%s'"):format(name))
|
flickerstreak@223
|
183 end
|
flickerstreak@223
|
184 class = self.barTypes[config.type]
|
flickerstreak@48
|
185 end
|
flickerstreak@91
|
186
|
flickerstreak@91
|
187 profile.bars[name] = config
|
flickerstreak@91
|
188 local bar = self.Bar:New( name, config ) -- ReAction.Bar defined in Bar.lua
|
flickerstreak@205
|
189 self.bars[name] = bar
|
flickerstreak@205
|
190 self.callbacks:Fire("OnCreateBar", bar, name)
|
flickerstreak@205
|
191 if self.configMode then
|
flickerstreak@33
|
192 bar:ShowControls(true)
|
flickerstreak@33
|
193 end
|
flickerstreak@33
|
194
|
flickerstreak@28
|
195 return bar
|
flickerstreak@28
|
196 end
|
flickerstreak@28
|
197
|
flickerstreak@205
|
198 function ReAction:DestroyBar(x)
|
flickerstreak@205
|
199 local bar, name = self:GetBar(x)
|
flickerstreak@63
|
200 if bar and name then
|
flickerstreak@205
|
201 self.bars[name] = nil
|
flickerstreak@205
|
202 self.callbacks:Fire("OnDestroyBar", bar, name)
|
flickerstreak@205
|
203 bar:Destroy()
|
flickerstreak@28
|
204 end
|
flickerstreak@28
|
205 end
|
flickerstreak@28
|
206
|
flickerstreak@205
|
207 function ReAction:RefreshBar(x)
|
flickerstreak@205
|
208 local bar, name = self:GetBar(x)
|
flickerstreak@205
|
209 if bar and name then
|
flickerstreak@205
|
210 self.callbacks:Fire("OnRefreshBar", bar, name)
|
flickerstreak@205
|
211 end
|
flickerstreak@63
|
212 end
|
flickerstreak@63
|
213
|
flickerstreak@205
|
214 function ReAction:InitializeBars()
|
flickerstreak@205
|
215 if not self.barsInitialized then
|
flickerstreak@211
|
216 self:ManageBlizzardBars()
|
flickerstreak@211
|
217
|
flickerstreak@205
|
218 for name, config in pairs(self.db.profile.bars) do
|
flickerstreak@205
|
219 if config then
|
flickerstreak@205
|
220 self:CreateBar(name, config)
|
flickerstreak@205
|
221 end
|
flickerstreak@205
|
222 end
|
flickerstreak@205
|
223 -- re-anchor and refresh in case anchor order does not match init order
|
flickerstreak@205
|
224 for name, bar in pairs(self.bars) do
|
flickerstreak@205
|
225 bar:ApplyAnchor()
|
flickerstreak@205
|
226 self.callbacks:Fire("OnRefreshBar", bar, name)
|
flickerstreak@205
|
227 end
|
flickerstreak@205
|
228 self.barsInitialized = true
|
flickerstreak@205
|
229 end
|
flickerstreak@205
|
230 end
|
flickerstreak@205
|
231
|
flickerstreak@205
|
232 function ReAction:TearDownBars()
|
flickerstreak@205
|
233 for name, bar in pairs(self.bars) do
|
flickerstreak@205
|
234 if bar then
|
flickerstreak@208
|
235 self.bars[name] = self:DestroyBar(bar)
|
flickerstreak@205
|
236 end
|
flickerstreak@205
|
237 end
|
flickerstreak@205
|
238 self.barsInitialized = false
|
flickerstreak@205
|
239 end
|
flickerstreak@205
|
240
|
flickerstreak@205
|
241 function ReAction:RebuildAll()
|
flickerstreak@205
|
242 self:TearDownBars()
|
flickerstreak@205
|
243 self:InitializeBars()
|
flickerstreak@28
|
244 end
|
flickerstreak@28
|
245
|
flickerstreak@28
|
246 function ReAction:RenameBar(x, newname)
|
flickerstreak@205
|
247 local bar, name = self:GetBar(x)
|
flickerstreak@63
|
248 if type(newname) ~= "string" then
|
flickerstreak@63
|
249 error("ReAction:RenameBar() - second argument must be a string")
|
flickerstreak@63
|
250 end
|
flickerstreak@63
|
251 if bar and name and #newname > 0 then
|
flickerstreak@127
|
252 if newname == name then
|
flickerstreak@127
|
253 return
|
flickerstreak@127
|
254 end
|
flickerstreak@205
|
255 if self.bars[newname] then
|
flickerstreak@127
|
256 self:UserError(format(L["ReAction: name '%s' already in use"],newname))
|
flickerstreak@47
|
257 else
|
flickerstreak@205
|
258 self.bars[newname], self.bars[name] = self.bars[name], nil
|
flickerstreak@47
|
259 bar:SetName(newname or "")
|
flickerstreak@47
|
260 local cfg = self.db.profile.bars
|
flickerstreak@47
|
261 cfg[newname], cfg[name] = cfg[name], nil
|
flickerstreak@205
|
262 self.callbacks:Fire("OnRenameBar", bar, name, newname)
|
flickerstreak@28
|
263 end
|
flickerstreak@28
|
264 end
|
flickerstreak@28
|
265 end
|
flickerstreak@28
|
266
|
flickerstreak@205
|
267 function ReAction:EraseBar(x)
|
flickerstreak@205
|
268 local bar, name = self:GetBar(x)
|
flickerstreak@63
|
269 if bar and name then
|
flickerstreak@205
|
270 self.callbacks:Fire("OnEraseBar", bar, name)
|
flickerstreak@208
|
271 self:DestroyBar(bar)
|
flickerstreak@205
|
272 self.db.profile.bars[name] = nil
|
flickerstreak@63
|
273 end
|
flickerstreak@63
|
274 end
|
flickerstreak@63
|
275
|
flickerstreak@211
|
276 local blizzFrames = {
|
flickerstreak@211
|
277 MainMenuBar,
|
flickerstreak@211
|
278 MultiBarLeft,
|
flickerstreak@211
|
279 MultiBarRight,
|
flickerstreak@211
|
280 MultiBarBottomLeft,
|
flickerstreak@211
|
281 MultiBarBottomRight,
|
flickerstreak@211
|
282 }
|
flickerstreak@211
|
283
|
flickerstreak@211
|
284 local hideFrame = CreateFrame("Frame")
|
flickerstreak@211
|
285 hideFrame:Hide()
|
flickerstreak@211
|
286 local hiddenParents = { }
|
flickerstreak@211
|
287 local function ManageBlizzFrame(f, hide)
|
flickerstreak@211
|
288 if hide and not hiddenParents[f] then
|
flickerstreak@211
|
289 hiddenParents[f] = f:GetParent()
|
flickerstreak@211
|
290 f:SetParent(hideFrame)
|
flickerstreak@211
|
291 elseif not hide and hiddenParents[f] then
|
flickerstreak@211
|
292 f:SetParent(hiddenParents[f])
|
flickerstreak@211
|
293 hiddenParents[f] = nil
|
flickerstreak@211
|
294 if f:IsShown() then
|
flickerstreak@211
|
295 f:Show() -- refresh
|
flickerstreak@211
|
296 end
|
flickerstreak@211
|
297 end
|
flickerstreak@211
|
298 end
|
flickerstreak@211
|
299
|
flickerstreak@211
|
300 function ReAction:ManageBlizzardBars()
|
flickerstreak@211
|
301 for _, f in pairs(blizzFrames) do
|
flickerstreak@211
|
302 ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars)
|
flickerstreak@211
|
303 end
|
flickerstreak@211
|
304 ManageBlizzFrame(VehicleMenuBar, self.db.profile.options.hideBlizzardVehicleBar)
|
flickerstreak@211
|
305 end
|
flickerstreak@211
|
306
|
flickerstreak@218
|
307 function ReAction:RegisterBarType( class, isDefault )
|
flickerstreak@218
|
308 local name = class:GetBarType()
|
flickerstreak@218
|
309 self.barTypes[name] = class
|
flickerstreak@218
|
310 if isDefault then
|
flickerstreak@218
|
311 self.defaultBarType = name
|
flickerstreak@48
|
312 end
|
flickerstreak@185
|
313 self:RefreshEditor()
|
flickerstreak@48
|
314 end
|
flickerstreak@48
|
315
|
flickerstreak@63
|
316 function ReAction:IterateBarTypes()
|
flickerstreak@218
|
317 return pairs(self.barTypes)
|
flickerstreak@63
|
318 end
|
flickerstreak@63
|
319
|
flickerstreak@218
|
320 function ReAction:GetDefaultBarConfig(barType)
|
flickerstreak@218
|
321 if barType and self.barTypes[barType] then
|
flickerstreak@218
|
322 return self.barTypes[barType]:GetDefaultBarConfig()
|
flickerstreak@63
|
323 end
|
flickerstreak@63
|
324 end
|
flickerstreak@63
|
325
|
flickerstreak@63
|
326 function ReAction:GetBarTypeOptions( fill )
|
flickerstreak@63
|
327 fill = fill or { }
|
flickerstreak@63
|
328 for k in self:IterateBarTypes() do
|
flickerstreak@63
|
329 fill[k] = k
|
flickerstreak@63
|
330 end
|
flickerstreak@63
|
331 return fill
|
flickerstreak@63
|
332 end
|
flickerstreak@63
|
333
|
flickerstreak@63
|
334 function ReAction:GetDefaultBarType()
|
flickerstreak@218
|
335 return self.defaultBarType
|
flickerstreak@63
|
336 end
|
flickerstreak@63
|
337
|
flickerstreak@33
|
338 function ReAction:SetConfigMode( mode )
|
flickerstreak@205
|
339 if mode ~= self.configMode then
|
flickerstreak@207
|
340 if mode then
|
flickerstreak@207
|
341 self:SetKeybindMode(false)
|
flickerstreak@207
|
342 end
|
flickerstreak@205
|
343 self.configMode = mode
|
flickerstreak@205
|
344 self.callbacks:Fire("OnConfigModeChanged", mode)
|
flickerstreak@77
|
345 end
|
flickerstreak@63
|
346 end
|
flickerstreak@63
|
347
|
flickerstreak@63
|
348 function ReAction:GetConfigMode()
|
flickerstreak@205
|
349 return self.configMode
|
flickerstreak@33
|
350 end
|
flickerstreak@38
|
351
|
flickerstreak@88
|
352 function ReAction:SetKeybindMode( mode )
|
flickerstreak@205
|
353 if mode ~= self.kbMode then
|
flickerstreak@88
|
354 if mode then
|
flickerstreak@207
|
355 self:SetConfigMode(false)
|
flickerstreak@184
|
356 LKB:Activate()
|
flickerstreak@88
|
357 else
|
flickerstreak@184
|
358 LKB:Deactivate()
|
flickerstreak@88
|
359 end
|
flickerstreak@207
|
360 for _, bar in self:IterateBars() do
|
flickerstreak@207
|
361 bar:SetKeybindMode(mode)
|
flickerstreak@207
|
362 end
|
flickerstreak@205
|
363 self.kbMode = LKB:IsShown() or false
|
flickerstreak@88
|
364 end
|
flickerstreak@88
|
365 end
|
flickerstreak@88
|
366
|
flickerstreak@88
|
367 function ReAction:GetKeybindMode( mode )
|
flickerstreak@205
|
368 return self.kbMode
|
flickerstreak@88
|
369 end
|
Flick@225
|
370
|
Flick@225
|
371
|
Flick@225
|
372 -- ConfigMode support
|
Flick@225
|
373 CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {}
|
Flick@225
|
374
|
Flick@225
|
375 function CONFIGMODE_CALLBACKS.ReAction( action, mode )
|
Flick@225
|
376 if action == "ON" then
|
Flick@225
|
377 ReAction:SetConfigMode(true)
|
Flick@225
|
378 elseif action == "OFF" then
|
Flick@225
|
379 ReAction:SetConfigMode(false)
|
Flick@225
|
380 elseif action == "LISTMODES" then
|
Flick@225
|
381 -- no modes
|
Flick@225
|
382 end
|
Flick@225
|
383 end
|
Flick@225
|
384
|