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