flickerstreak@25
|
1 --[[
|
flickerstreak@25
|
2 ReAction bar module.
|
flickerstreak@25
|
3
|
flickerstreak@25
|
4 This is the heart of ReAction, the bar management module. Many of its
|
flickerstreak@25
|
5 functions turn around and iterate all modules registered to the ReAction
|
flickerstreak@25
|
6 parent core.
|
flickerstreak@25
|
7
|
flickerstreak@25
|
8 Also defined in this file is the Bar class implementation, which can be
|
flickerstreak@25
|
9 used by other modules to manipulate the action bars. Many of the module
|
flickerstreak@25
|
10 iterated calls pass a bar or list of bars as an argument.
|
flickerstreak@25
|
11
|
flickerstreak@25
|
12 Module methods called by the Bar module:
|
flickerstreak@25
|
13 module:ApplyToBar(bar)
|
flickerstreak@25
|
14 module:RemoveFromBar(bar)
|
flickerstreak@25
|
15 module:RefreshBar(bar)
|
flickerstreak@25
|
16 module:ApplyConfigMode(mode,listOfBars)
|
flickerstreak@25
|
17 module:GetBarNameModifier(bar)
|
flickerstreak@25
|
18 module:EraseBarConfig(barName)
|
flickerstreak@25
|
19
|
flickerstreak@25
|
20
|
flickerstreak@25
|
21 useful Bar object API (partial list):
|
flickerstreak@25
|
22 f = bar:GetFrame() -- f is derived from SecureStateDriver
|
flickerstreak@25
|
23 bar:RefreshLayout()
|
flickerstreak@25
|
24 w,h = bar:GetSize()
|
flickerstreak@25
|
25 r,c,s = bar:GetButtonGrid() -- #rows, #columns, inter-button spacing
|
flickerstreak@25
|
26 name = bar:GetName()
|
flickerstreak@25
|
27 bar:PlaceButton(frame, idx, baseSizeX, baseSizeY) -- idx is 1-based
|
flickerstreak@25
|
28
|
flickerstreak@25
|
29 --]]
|
flickerstreak@25
|
30
|
flickerstreak@25
|
31 -- local imports
|
flickerstreak@25
|
32 local ReAction = ReAction
|
flickerstreak@25
|
33 local L = ReAction.L
|
flickerstreak@25
|
34 local _G = _G
|
flickerstreak@25
|
35 local AceOO = AceLibrary("AceOO-2.0")
|
flickerstreak@25
|
36 local CreateFrame = CreateFrame
|
flickerstreak@25
|
37 local geterrorhandler = geterrorhandler
|
flickerstreak@25
|
38 local pcall = pcall
|
flickerstreak@25
|
39 local print = ReAction.print
|
flickerstreak@25
|
40
|
flickerstreak@25
|
41 -- update ReAction revision if this file is newer
|
flickerstreak@25
|
42 local revision = tonumber(("$Revision: 1 $"):match("%d+"))
|
flickerstreak@25
|
43 if revision > ReAction.revision then
|
flickerstreak@25
|
44 Reaction.revision = revision
|
flickerstreak@25
|
45 end
|
flickerstreak@25
|
46
|
flickerstreak@25
|
47 local moduleID = "Bar"
|
flickerstreak@25
|
48
|
flickerstreak@25
|
49 --
|
flickerstreak@25
|
50 -- Bar module declaration
|
flickerstreak@25
|
51 --
|
flickerstreak@25
|
52 local module = ReAction:NewModule( moduleID )
|
flickerstreak@25
|
53
|
flickerstreak@25
|
54 --
|
flickerstreak@25
|
55 -- Bar class declaration
|
flickerstreak@25
|
56 --
|
flickerstreak@25
|
57 local BarClass = AceOO.Class()
|
flickerstreak@25
|
58 local Bar = BarClass.prototype
|
flickerstreak@25
|
59 module.BarClass = BarClass
|
flickerstreak@25
|
60
|
flickerstreak@27
|
61 --
|
flickerstreak@27
|
62 -- local utility
|
flickerstreak@27
|
63 --
|
flickerstreak@27
|
64 local function deepCopy(x)
|
flickerstreak@27
|
65 if type(x) ~= "table" then
|
flickerstreak@27
|
66 return x
|
flickerstreak@27
|
67 end
|
flickerstreak@27
|
68 local r = {}
|
flickerstreak@27
|
69 for k,v in pairs(x) do
|
flickerstreak@27
|
70 r[k] = deepCopy(v)
|
flickerstreak@27
|
71 end
|
flickerstreak@27
|
72 return r
|
flickerstreak@27
|
73 end
|
flickerstreak@25
|
74
|
flickerstreak@25
|
75 --
|
flickerstreak@25
|
76 -- Bar module implementation
|
flickerstreak@25
|
77 --
|
flickerstreak@25
|
78 function module:OnInitialize()
|
flickerstreak@25
|
79 self.db = ReAction:AcquireDBNamespace(moduleID)
|
flickerstreak@25
|
80 ReAction:RegisterDefaults(moduleID,"profile",
|
flickerstreak@25
|
81 {
|
flickerstreak@25
|
82 bars = { },
|
flickerstreak@25
|
83 defaultBar = { }
|
flickerstreak@25
|
84 }
|
flickerstreak@25
|
85 )
|
flickerstreak@25
|
86 self.bars = {}
|
flickerstreak@25
|
87 end
|
flickerstreak@25
|
88
|
flickerstreak@25
|
89 function module:OnEnable()
|
flickerstreak@25
|
90 self:InitializeBars()
|
flickerstreak@25
|
91 end
|
flickerstreak@25
|
92
|
flickerstreak@25
|
93 function module:OnDisable()
|
flickerstreak@25
|
94 self:TearDownBars()
|
flickerstreak@25
|
95 end
|
flickerstreak@25
|
96
|
flickerstreak@25
|
97 function module:OnProfileEnable()
|
flickerstreak@25
|
98 self:InitializeBars()
|
flickerstreak@25
|
99 end
|
flickerstreak@25
|
100
|
flickerstreak@25
|
101 function module:OnProfileDisable()
|
flickerstreak@25
|
102 self:TearDownBars()
|
flickerstreak@25
|
103 end
|
flickerstreak@25
|
104
|
flickerstreak@25
|
105 function module:InitializeBars()
|
flickerstreak@25
|
106 if not(self.inited) then
|
flickerstreak@25
|
107 for name, config in pairs(self.db.profile.bars) do
|
flickerstreak@25
|
108 if config then
|
flickerstreak@25
|
109 self:CreateBar(name, config)
|
flickerstreak@25
|
110 end
|
flickerstreak@25
|
111 end
|
flickerstreak@25
|
112 self:CallMethodOnAllBars("ApplyAnchor") -- re-anchor in the case of oddball ordering
|
flickerstreak@25
|
113 self.inited = true
|
flickerstreak@25
|
114 end
|
flickerstreak@25
|
115 end
|
flickerstreak@25
|
116
|
flickerstreak@25
|
117 function module:TearDownBars()
|
flickerstreak@25
|
118 for name, bar in pairs(self.bars) do
|
flickerstreak@25
|
119 if bar then
|
flickerstreak@25
|
120 self.bars[name] = self:DeleteBar(bar)
|
flickerstreak@25
|
121 end
|
flickerstreak@25
|
122 end
|
flickerstreak@25
|
123 self.inited = false
|
flickerstreak@25
|
124 end
|
flickerstreak@25
|
125
|
flickerstreak@25
|
126 -- Gets config from existing DB name or default if not supplied
|
flickerstreak@25
|
127 -- Saves to DB if name not known
|
flickerstreak@25
|
128 function module:CreateBar(name, config)
|
flickerstreak@25
|
129 local profile = self.db.profile
|
flickerstreak@25
|
130 if not name then
|
flickerstreak@25
|
131 i = 1
|
flickerstreak@25
|
132 repeat
|
flickerstreak@25
|
133 name = L["Bar "]..i
|
flickerstreak@25
|
134 i = i + 1
|
flickerstreak@25
|
135 until self.bars[name] == nil
|
flickerstreak@25
|
136 end
|
flickerstreak@25
|
137 config = config or profile.bars[name] or deepCopy(profile.defaultBar)
|
flickerstreak@25
|
138 if not profile.bars[name] then
|
flickerstreak@25
|
139 profile.bars[name] = config
|
flickerstreak@25
|
140 end
|
flickerstreak@25
|
141 local bar = self.BarClass:new( name, config )
|
flickerstreak@25
|
142 ReAction:CallMethodOnAllModules("ApplyToBar", bar)
|
flickerstreak@25
|
143 self.bars[name] = bar
|
flickerstreak@25
|
144 return bar
|
flickerstreak@25
|
145 end
|
flickerstreak@25
|
146
|
flickerstreak@25
|
147
|
flickerstreak@25
|
148 local SelectBar
|
flickerstreak@25
|
149 do
|
flickerstreak@25
|
150 SelectBar = function(x)
|
flickerstreak@25
|
151 local bar, name
|
flickerstreak@25
|
152 if type(x) == "string" then
|
flickerstreak@25
|
153 name = x
|
flickerstreak@25
|
154 bar = module:GetBar(name)
|
flickerstreak@25
|
155 elseif AceOO.inherits(x,BarClass) then
|
flickerstreak@25
|
156 bar = x
|
flickerstreak@25
|
157 for k,v in pairs(module.bars) do
|
flickerstreak@25
|
158 if v == bar then
|
flickerstreak@25
|
159 name = k
|
flickerstreak@25
|
160 end
|
flickerstreak@25
|
161 end
|
flickerstreak@25
|
162 else
|
flickerstreak@25
|
163 error("bad argument to SelectBar")
|
flickerstreak@25
|
164 end
|
flickerstreak@25
|
165 return bar, name
|
flickerstreak@25
|
166 end
|
flickerstreak@25
|
167 end
|
flickerstreak@25
|
168
|
flickerstreak@25
|
169 -- Takes either a bar name string or a bar object.
|
flickerstreak@25
|
170 -- Does NOT destroy the DB entry, this function is only used for
|
flickerstreak@25
|
171 -- enable/disable and profile switching. To remove a bar permanently,
|
flickerstreak@25
|
172 -- use EraseBar() instead.
|
flickerstreak@25
|
173 function module:DeleteBar(x)
|
flickerstreak@25
|
174 local bar, name = SelectBar(x)
|
flickerstreak@25
|
175 if name and bar then
|
flickerstreak@25
|
176 self.bars[name] = nil
|
flickerstreak@25
|
177 ReAction:CallMethodOnAllModules("RemoveFromBar", bar)
|
flickerstreak@25
|
178 bar:Destroy()
|
flickerstreak@25
|
179 end
|
flickerstreak@25
|
180 end
|
flickerstreak@25
|
181
|
flickerstreak@25
|
182 function module:EraseBar(x)
|
flickerstreak@25
|
183 local bar, name = SelectBar(x)
|
flickerstreak@25
|
184 if name and bar then
|
flickerstreak@25
|
185 self:DeleteBar(bar)
|
flickerstreak@25
|
186 self.db.profile.bars[name] = nil
|
flickerstreak@25
|
187 ReAction:CallMethodOnAllModules("EraseBarConfig", name)
|
flickerstreak@25
|
188 end
|
flickerstreak@25
|
189 end
|
flickerstreak@25
|
190
|
flickerstreak@25
|
191 function module:GetBar(name)
|
flickerstreak@25
|
192 return self.bars[name]
|
flickerstreak@25
|
193 end
|
flickerstreak@25
|
194
|
flickerstreak@25
|
195 function module:RenameBar(x, newname)
|
flickerstreak@25
|
196 local bar, name = SelectBar(x)
|
flickerstreak@25
|
197 if bar and name and newname then
|
flickerstreak@25
|
198 if self.bars[newname] then
|
flickerstreak@25
|
199 error(L["ReAction: name already in use"])
|
flickerstreak@25
|
200 end
|
flickerstreak@25
|
201 self.bars[newname] = self.bars[name]
|
flickerstreak@25
|
202 self.bars[name] = nil
|
flickerstreak@25
|
203 bar:SetName(newname)
|
flickerstreak@25
|
204 local cfg = self.db.profile.bars
|
flickerstreak@25
|
205 cfg[newname], cfg[name] = cfg[name], nil
|
flickerstreak@25
|
206 end
|
flickerstreak@25
|
207 end
|
flickerstreak@25
|
208
|
flickerstreak@25
|
209 function module:CallMethodOnAllBars(method,...)
|
flickerstreak@25
|
210 local m
|
flickerstreak@25
|
211 if type(method) == "function" then
|
flickerstreak@25
|
212 m = method
|
flickerstreak@25
|
213 elseif type(method) ~= "string" then
|
flickerstreak@25
|
214 error("Invalid method passed to ReAction_Bar:CallMethodOnAllBars()")
|
flickerstreak@25
|
215 end
|
flickerstreak@25
|
216 for _, bar in pairs(self.bars) do
|
flickerstreak@25
|
217 if bar then
|
flickerstreak@25
|
218 local m = m or bar[method]
|
flickerstreak@25
|
219 if m then
|
flickerstreak@25
|
220 local success,err = pcall(m,bar,...)
|
flickerstreak@25
|
221 if not success then
|
flickerstreak@25
|
222 geterrorhandler()(err)
|
flickerstreak@25
|
223 end
|
flickerstreak@25
|
224 end
|
flickerstreak@25
|
225 end
|
flickerstreak@25
|
226 end
|
flickerstreak@25
|
227 end
|
flickerstreak@25
|
228
|
flickerstreak@25
|
229
|
flickerstreak@25
|
230
|
flickerstreak@25
|
231 function module:GetBarMenuOptions(bar)
|
flickerstreak@25
|
232 if not(bar.modMenuOpts[moduleID]) then
|
flickerstreak@25
|
233 bar.modMenuOpts[moduleID] = {
|
flickerstreak@25
|
234 delete = {
|
flickerstreak@25
|
235 type = "execute",
|
flickerstreak@25
|
236 name = L["Delete Bar"],
|
flickerstreak@25
|
237 desc = L["Remove the bar from the current profile"],
|
flickerstreak@25
|
238 func = function() self:EraseBar(bar) end,
|
flickerstreak@25
|
239 order = 1
|
flickerstreak@25
|
240 },
|
flickerstreak@25
|
241 }
|
flickerstreak@25
|
242 end
|
flickerstreak@25
|
243 return bar.modMenuOpts[moduleID]
|
flickerstreak@25
|
244 end
|
flickerstreak@25
|
245
|
flickerstreak@25
|
246 function module:GetBarConfigOptions(bar, cfgModule)
|
flickerstreak@25
|
247 if not(bar.modConfigOpts[moduleID]) then
|
flickerstreak@25
|
248 bar.modConfigOpts[moduleID] = {
|
flickerstreak@25
|
249 delete = {
|
flickerstreak@25
|
250 type = "execute",
|
flickerstreak@25
|
251 name = L["Delete Bar"],
|
flickerstreak@25
|
252 desc = L["Remove the bar from the current profile"],
|
flickerstreak@25
|
253 func = function() self:EraseBar(bar); cfgModule:RefreshConfig() end
|
flickerstreak@25
|
254 },
|
flickerstreak@25
|
255 rename = {
|
flickerstreak@25
|
256 type = "text",
|
flickerstreak@25
|
257 name = L["Rename Bar"],
|
flickerstreak@25
|
258 desc = L["Set a name for the bar"],
|
flickerstreak@25
|
259 get = "GetName",
|
flickerstreak@25
|
260 set = function(name) self:RenameBar(bar,name); cfgModule:RefreshConfig() end
|
flickerstreak@25
|
261 }
|
flickerstreak@25
|
262 }
|
flickerstreak@25
|
263 end
|
flickerstreak@25
|
264 return bar.modConfigOpts[moduleID]
|
flickerstreak@25
|
265 end
|
flickerstreak@25
|
266
|
flickerstreak@25
|
267
|
flickerstreak@25
|
268
|
flickerstreak@25
|
269 --
|
flickerstreak@25
|
270 -- Bar class implementation
|
flickerstreak@25
|
271 --
|
flickerstreak@25
|
272 function Bar:init( name, config )
|
flickerstreak@25
|
273 BarClass.super.prototype.init(self)
|
flickerstreak@25
|
274 self.name, self.config = name, config
|
flickerstreak@25
|
275
|
flickerstreak@25
|
276 if type(config) ~= "table" then
|
flickerstreak@25
|
277 error("ReAction:Bar: config table required")
|
flickerstreak@25
|
278 end
|
flickerstreak@25
|
279
|
flickerstreak@25
|
280 local f = CreateFrame("Frame",nil,config.parent or UIParent,"SecureStateDriverTemplate")
|
flickerstreak@25
|
281 f:SetFrameStrata("MEDIUM")
|
flickerstreak@25
|
282 config.width = config.width or 400
|
flickerstreak@25
|
283 config.height = config.height or 80
|
flickerstreak@25
|
284 f:SetWidth(config.width)
|
flickerstreak@25
|
285 f:SetWidth(config.height)
|
flickerstreak@25
|
286
|
flickerstreak@25
|
287 self.frame = f
|
flickerstreak@25
|
288 self:RefreshLayout()
|
flickerstreak@25
|
289 self:ApplyAnchor()
|
flickerstreak@25
|
290 f:Show()
|
flickerstreak@25
|
291 end
|
flickerstreak@25
|
292
|
flickerstreak@25
|
293 function Bar:Destroy()
|
flickerstreak@25
|
294 local f = self.frame
|
flickerstreak@25
|
295 f:UnregisterAllEvents()
|
flickerstreak@25
|
296 f:Hide()
|
flickerstreak@25
|
297 f:SetParent(UIParent)
|
flickerstreak@25
|
298 f:ClearAllPoints()
|
flickerstreak@25
|
299 self.labelString = nil
|
flickerstreak@25
|
300 self.controlFrame = nil
|
flickerstreak@25
|
301 self.frame = nil
|
flickerstreak@25
|
302 self.config = nil
|
flickerstreak@25
|
303 end
|
flickerstreak@25
|
304
|
flickerstreak@25
|
305 function Bar:RefreshLayout()
|
flickerstreak@25
|
306 ReAction:CallMethodOnAllModules("RefreshBar", self)
|
flickerstreak@25
|
307 end
|
flickerstreak@25
|
308
|
flickerstreak@25
|
309 function Bar:ApplyAnchor()
|
flickerstreak@25
|
310 local f, config = self.frame, self.config
|
flickerstreak@25
|
311 f:SetWidth(config.width)
|
flickerstreak@25
|
312 f:SetHeight(config.height)
|
flickerstreak@25
|
313 local anchor = config.anchor
|
flickerstreak@25
|
314 if anchor then
|
flickerstreak@25
|
315 local anchorTo
|
flickerstreak@25
|
316 if config.anchorTo then
|
flickerstreak@25
|
317 anchorTo = module:GetBar(config.anchorTo) or _G[config.anchorTo]
|
flickerstreak@25
|
318 end
|
flickerstreak@25
|
319 f:SetPoint(anchor, anchorTo, config.relativePoint, config.x or 0, config.y or 0)
|
flickerstreak@25
|
320 else
|
flickerstreak@25
|
321 f:SetPoint("CENTER")
|
flickerstreak@25
|
322 end
|
flickerstreak@25
|
323 end
|
flickerstreak@25
|
324
|
flickerstreak@25
|
325 function Bar:GetFrame()
|
flickerstreak@25
|
326 return self.frame
|
flickerstreak@25
|
327 end
|
flickerstreak@25
|
328
|
flickerstreak@25
|
329 function Bar:GetSize()
|
flickerstreak@25
|
330 return self.frame:GetWidth() or 200, self.frame:GetHeight() or 200
|
flickerstreak@25
|
331 end
|
flickerstreak@25
|
332
|
flickerstreak@25
|
333 function Bar:SetSize(w,h)
|
flickerstreak@25
|
334 self.config.width = w
|
flickerstreak@25
|
335 self.config.height = h
|
flickerstreak@25
|
336 end
|
flickerstreak@25
|
337
|
flickerstreak@25
|
338 function Bar:GetButtonSize()
|
flickerstreak@25
|
339 local w = self.config.btnWidth or 32
|
flickerstreak@25
|
340 local h = self.config.btnHeight or 32
|
flickerstreak@25
|
341 -- TODO: get from modules?
|
flickerstreak@25
|
342 return w,h
|
flickerstreak@25
|
343 end
|
flickerstreak@25
|
344
|
flickerstreak@25
|
345 function Bar:SetButtonSize(w,h)
|
flickerstreak@25
|
346 if w > 0 and h > 0 then
|
flickerstreak@25
|
347 self.config.btnWidth = w
|
flickerstreak@25
|
348 self.config.btnHeight = h
|
flickerstreak@25
|
349 end
|
flickerstreak@25
|
350 end
|
flickerstreak@25
|
351
|
flickerstreak@25
|
352 function Bar:GetButtonGrid()
|
flickerstreak@25
|
353 local cfg = self.config
|
flickerstreak@25
|
354 local r = cfg.btnRows or 1
|
flickerstreak@25
|
355 local c = cfg.btnColumns or 1
|
flickerstreak@25
|
356 local s = cfg.spacing or 4
|
flickerstreak@25
|
357 return r,c,s
|
flickerstreak@25
|
358 end
|
flickerstreak@25
|
359
|
flickerstreak@25
|
360 function Bar:SetButtonGrid(r,c,s)
|
flickerstreak@25
|
361 if r > 0 and c > 0 and s > 0 then
|
flickerstreak@25
|
362 local cfg = self.config
|
flickerstreak@25
|
363 cfg.btnRows = r
|
flickerstreak@25
|
364 cfg.btnColumns = c
|
flickerstreak@25
|
365 cfg.spacing = s
|
flickerstreak@25
|
366 end
|
flickerstreak@25
|
367 end
|
flickerstreak@25
|
368
|
flickerstreak@25
|
369 -- This should only be called from module:RenameBar(), otherwise
|
flickerstreak@25
|
370 -- the bar's internal name and the module's list of bars by name
|
flickerstreak@25
|
371 -- can get out of sync.
|
flickerstreak@25
|
372 function Bar:SetName( name )
|
flickerstreak@25
|
373 name = name or ""
|
flickerstreak@25
|
374 self.name = name
|
flickerstreak@25
|
375 end
|
flickerstreak@25
|
376
|
flickerstreak@25
|
377 function Bar:GetName()
|
flickerstreak@25
|
378 return self.name
|
flickerstreak@25
|
379 end
|
flickerstreak@25
|
380
|
flickerstreak@25
|
381 function Bar:PlaceButton(f, idx, baseW, baseH)
|
flickerstreak@25
|
382 local r, c, s = self:GetButtonGrid()
|
flickerstreak@25
|
383 local bh, bw = self:GetButtonSize()
|
flickerstreak@25
|
384 local row, col = floor((idx-1)/c), mod((idx-1),c) -- zero-based
|
flickerstreak@25
|
385 local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s
|
flickerstreak@25
|
386 local scale = bw/baseW
|
flickerstreak@25
|
387
|
flickerstreak@25
|
388 f:ClearAllPoints()
|
flickerstreak@25
|
389 f:SetPoint("TOPLEFT",x/scale,-y/scale)
|
flickerstreak@25
|
390 f:SetScale(scale)
|
flickerstreak@25
|
391 -- f:Show()
|
flickerstreak@25
|
392 end
|
flickerstreak@25
|
393
|