flickerstreak@24
|
1 --[[
|
flickerstreak@53
|
2 ReAction Action button module.
|
flickerstreak@24
|
3
|
flickerstreak@24
|
4 The button module implements standard action button functionality by wrapping Blizzard's
|
flickerstreak@24
|
5 ActionButton frame and associated functions. It also provides some button layout
|
flickerstreak@24
|
6 modification tools.
|
flickerstreak@24
|
7
|
flickerstreak@24
|
8 --]]
|
flickerstreak@24
|
9
|
flickerstreak@24
|
10 -- local imports
|
flickerstreak@24
|
11 local ReAction = ReAction
|
flickerstreak@24
|
12 local L = ReAction.L
|
flickerstreak@24
|
13 local _G = _G
|
flickerstreak@24
|
14 local CreateFrame = CreateFrame
|
flickerstreak@24
|
15
|
flickerstreak@24
|
16 -- module declaration
|
flickerstreak@24
|
17 local moduleID = "Action"
|
flickerstreak@28
|
18 local module = ReAction:NewModule( moduleID )
|
flickerstreak@24
|
19
|
flickerstreak@24
|
20 -- module methods
|
flickerstreak@24
|
21 function module:OnInitialize()
|
flickerstreak@28
|
22 self.db = ReAction.db:RegisterNamespace( moduleID,
|
flickerstreak@24
|
23 {
|
flickerstreak@28
|
24 profile = {
|
flickerstreak@28
|
25 buttons = { }
|
flickerstreak@28
|
26 }
|
flickerstreak@24
|
27 }
|
flickerstreak@24
|
28 )
|
flickerstreak@24
|
29 self.buttons = { }
|
flickerstreak@49
|
30
|
flickerstreak@60
|
31 ReAction:RegisterOptions(self, {
|
flickerstreak@60
|
32 [moduleID] = {
|
flickerstreak@60
|
33 type = "group",
|
flickerstreak@60
|
34 name = L["Action Bars"],
|
flickerstreak@60
|
35 args = {
|
flickerstreak@60
|
36 hideEmpty = {
|
flickerstreak@60
|
37 type = "toggle",
|
flickerstreak@60
|
38 name = L["Hide Empty Buttons"],
|
flickerstreak@60
|
39 get = function() return self.db.profile.hideEmptyButtons end,
|
flickerstreak@60
|
40 set = function(info, val) module:SetHideEmptyButtons(val) end,
|
flickerstreak@60
|
41 }
|
flickerstreak@60
|
42 }
|
flickerstreak@60
|
43 }
|
flickerstreak@60
|
44 })
|
flickerstreak@63
|
45
|
flickerstreak@63
|
46 ReAction:RegisterBarOptionGenerator(self, "GetBarOptions")
|
flickerstreak@63
|
47
|
flickerstreak@63
|
48 ReAction.RegisterCallback(self, "OnCreateBar", "OnRefreshBar")
|
flickerstreak@63
|
49 ReAction.RegisterCallback(self, "OnDestroyBar")
|
flickerstreak@63
|
50 ReAction.RegisterCallback(self, "OnRefreshBar")
|
flickerstreak@63
|
51 ReAction.RegisterCallback(self, "OnEraseBar")
|
flickerstreak@63
|
52 ReAction.RegisterCallback(self, "OnRenameBar")
|
flickerstreak@63
|
53 ReAction.RegisterCallback(self, "OnConfigModeChanged")
|
flickerstreak@63
|
54
|
flickerstreak@24
|
55 end
|
flickerstreak@24
|
56
|
flickerstreak@24
|
57 function module:OnEnable()
|
flickerstreak@53
|
58 ReAction:RegisterBarType(L["Action Bar"],
|
flickerstreak@53
|
59 {
|
flickerstreak@53
|
60 type = moduleID,
|
flickerstreak@53
|
61 defaultButtonSize = 36,
|
flickerstreak@53
|
62 defaultBarRows = 1,
|
flickerstreak@53
|
63 defaultBarCols = 12,
|
flickerstreak@53
|
64 defaultBarSpacing = 3
|
flickerstreak@53
|
65 }, true)
|
flickerstreak@24
|
66 end
|
flickerstreak@24
|
67
|
flickerstreak@24
|
68 function module:OnDisable()
|
flickerstreak@53
|
69 ReAction:UnregisterBarType(L["Action Bar"])
|
flickerstreak@24
|
70 end
|
flickerstreak@24
|
71
|
flickerstreak@63
|
72 function module:OnRefreshBar(event, bar, name)
|
flickerstreak@53
|
73 if bar.config.type == moduleID then
|
flickerstreak@48
|
74 if self.buttons[bar] == nil then
|
flickerstreak@48
|
75 self.buttons[bar] = { }
|
flickerstreak@48
|
76 end
|
flickerstreak@48
|
77 local btns = self.buttons[bar]
|
flickerstreak@48
|
78 local profile = self.db.profile
|
flickerstreak@63
|
79 if profile.buttons[name] == nil then
|
flickerstreak@63
|
80 profile.buttons[name] = {}
|
flickerstreak@48
|
81 end
|
flickerstreak@63
|
82 local btnCfg = profile.buttons[name]
|
flickerstreak@24
|
83
|
flickerstreak@48
|
84 local r, c = bar:GetButtonGrid()
|
flickerstreak@48
|
85 local n = r*c
|
flickerstreak@48
|
86 for i = 1, n do
|
flickerstreak@48
|
87 if btnCfg[i] == nil then
|
flickerstreak@48
|
88 btnCfg[i] = {}
|
flickerstreak@48
|
89 end
|
flickerstreak@48
|
90 if btns[i] == nil then
|
flickerstreak@52
|
91 local ok, b = pcall(self.BtnClass.new, self.BtnClass, bar, i, btnCfg[i])
|
flickerstreak@52
|
92 if ok and b then
|
flickerstreak@52
|
93 btns[i] = b
|
flickerstreak@52
|
94 end
|
flickerstreak@48
|
95 else
|
flickerstreak@48
|
96 btns[i]:Refresh(bar,i)
|
flickerstreak@48
|
97 end
|
flickerstreak@24
|
98 end
|
flickerstreak@48
|
99 for i = n+1, #btns do
|
flickerstreak@52
|
100 if btns[i] then
|
flickerstreak@52
|
101 btns[i] = btns[i]:Destroy()
|
flickerstreak@52
|
102 if btnCfg[i] then
|
flickerstreak@52
|
103 btnCfg[i] = nil
|
flickerstreak@52
|
104 end
|
flickerstreak@48
|
105 end
|
flickerstreak@24
|
106 end
|
flickerstreak@24
|
107 end
|
flickerstreak@24
|
108 end
|
flickerstreak@24
|
109
|
flickerstreak@63
|
110 function module:OnDestroyBar(event, bar, name)
|
flickerstreak@24
|
111 if self.buttons[bar] then
|
flickerstreak@24
|
112 local btns = self.buttons[bar]
|
flickerstreak@24
|
113 for _,b in pairs(btns) do
|
flickerstreak@24
|
114 if b then
|
flickerstreak@24
|
115 b:Destroy()
|
flickerstreak@24
|
116 end
|
flickerstreak@24
|
117 end
|
flickerstreak@24
|
118 self.buttons[bar] = nil
|
flickerstreak@24
|
119 end
|
flickerstreak@24
|
120 end
|
flickerstreak@24
|
121
|
flickerstreak@63
|
122 function module:OnEraseBar(event, bar, name)
|
flickerstreak@63
|
123 self.db.profile.buttons[name] = nil
|
flickerstreak@24
|
124 end
|
flickerstreak@24
|
125
|
flickerstreak@63
|
126 function module:OnRenameBar(event, bar, oldname, newname)
|
flickerstreak@48
|
127 local b = self.db.profile.buttons
|
flickerstreak@48
|
128 b[newname], b[oldname] = b[oldname], nil
|
flickerstreak@48
|
129 end
|
flickerstreak@48
|
130
|
flickerstreak@49
|
131 function module:SetHideEmptyButtons(hide)
|
flickerstreak@49
|
132 if hide ~= self.db.profile.hideEmptyButtons then
|
flickerstreak@49
|
133 for _, bar in pairs(self.buttons) do
|
flickerstreak@49
|
134 for _, b in pairs(bar) do
|
flickerstreak@49
|
135 if hide then
|
flickerstreak@49
|
136 ActionButton_HideGrid(b.frame)
|
flickerstreak@49
|
137 else
|
flickerstreak@49
|
138 ActionButton_ShowGrid(b.frame)
|
flickerstreak@49
|
139 end
|
flickerstreak@49
|
140 end
|
flickerstreak@49
|
141 end
|
flickerstreak@49
|
142 self.db.profile.hideEmptyButtons = hide
|
flickerstreak@49
|
143 end
|
flickerstreak@49
|
144 end
|
flickerstreak@49
|
145
|
flickerstreak@63
|
146 function module:OnConfigModeChanged(event, mode)
|
flickerstreak@63
|
147 for _, bar in ReAction:IterateBars() do
|
flickerstreak@49
|
148 if bar and self.buttons[bar] then
|
flickerstreak@49
|
149 for _, b in pairs(self.buttons[bar]) do
|
flickerstreak@24
|
150 if b then
|
flickerstreak@24
|
151 if mode then
|
flickerstreak@49
|
152 ActionButton_ShowGrid(b.frame)
|
flickerstreak@50
|
153 self:showActionIDLabel(b)
|
flickerstreak@49
|
154 else
|
flickerstreak@49
|
155 ActionButton_HideGrid(b.frame)
|
flickerstreak@50
|
156 self:hideActionIDLabel(b)
|
flickerstreak@24
|
157 end
|
flickerstreak@24
|
158 end
|
flickerstreak@24
|
159 end
|
flickerstreak@24
|
160 end
|
flickerstreak@24
|
161 end
|
flickerstreak@24
|
162 end
|
flickerstreak@24
|
163
|
flickerstreak@50
|
164 function module:showActionIDLabel(button)
|
flickerstreak@52
|
165 if not button.actionIDLabel and button:GetActionID() then
|
flickerstreak@50
|
166 local label = button:GetFrame():CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
|
flickerstreak@50
|
167 label:SetAllPoints()
|
flickerstreak@50
|
168 label:SetJustifyH("CENTER")
|
flickerstreak@50
|
169 label:SetShadowColor(0,0,0,1)
|
flickerstreak@50
|
170 label:SetShadowOffset(2,-2)
|
flickerstreak@50
|
171 label:SetText(tostring(button:GetActionID()))
|
flickerstreak@50
|
172 button.actionIDLabel = label
|
flickerstreak@50
|
173 end
|
flickerstreak@50
|
174 button.actionIDLabel:Show()
|
flickerstreak@50
|
175 end
|
flickerstreak@50
|
176
|
flickerstreak@50
|
177 function module:hideActionIDLabel(button)
|
flickerstreak@50
|
178 if button.actionIDLabel then
|
flickerstreak@50
|
179 button.actionIDLabel:Hide()
|
flickerstreak@50
|
180 end
|
flickerstreak@50
|
181 end
|
flickerstreak@50
|
182
|
flickerstreak@50
|
183
|
flickerstreak@60
|
184 ---- Options ----
|
flickerstreak@60
|
185 function module:GetBarOptions(bar)
|
flickerstreak@63
|
186 return {
|
flickerstreak@63
|
187 type = "group",
|
flickerstreak@63
|
188 name = L["Action Buttons"],
|
flickerstreak@63
|
189 hidden = function() return bar.config.type ~= moduleID end,
|
flickerstreak@63
|
190 args = {
|
flickerstreak@60
|
191 }
|
flickerstreak@63
|
192 }
|
flickerstreak@59
|
193 end
|
flickerstreak@59
|
194
|
flickerstreak@50
|
195
|
flickerstreak@24
|
196 -- use-count of action IDs
|
flickerstreak@53
|
197 local nActionIDs = 120
|
flickerstreak@24
|
198 local ActionIDList = setmetatable( {}, {
|
flickerstreak@24
|
199 __index = function(self, idx)
|
flickerstreak@24
|
200 if idx == nil then
|
flickerstreak@53
|
201 for i = 1, nActionIDs do
|
flickerstreak@24
|
202 if rawget(self,i) == nil then
|
flickerstreak@24
|
203 rawset(self,i,1)
|
flickerstreak@24
|
204 return i
|
flickerstreak@24
|
205 end
|
flickerstreak@24
|
206 end
|
flickerstreak@52
|
207 error("ran out of action IDs")
|
flickerstreak@24
|
208 else
|
flickerstreak@24
|
209 local c = rawget(self,idx) or 0
|
flickerstreak@24
|
210 rawset(self,idx,c+1)
|
flickerstreak@24
|
211 return idx
|
flickerstreak@24
|
212 end
|
flickerstreak@24
|
213 end,
|
flickerstreak@24
|
214 __newindex = function(self,idx,value)
|
flickerstreak@24
|
215 if value == nil then
|
flickerstreak@24
|
216 value = rawget(self,idx)
|
flickerstreak@24
|
217 if value == 1 then
|
flickerstreak@24
|
218 value = nil
|
flickerstreak@24
|
219 elseif value then
|
flickerstreak@24
|
220 value = value - 1
|
flickerstreak@24
|
221 end
|
flickerstreak@24
|
222 end
|
flickerstreak@24
|
223 rawset(self,idx,value)
|
flickerstreak@24
|
224 end
|
flickerstreak@24
|
225 })
|
flickerstreak@24
|
226
|
flickerstreak@24
|
227
|
flickerstreak@24
|
228
|
flickerstreak@28
|
229
|
flickerstreak@28
|
230 ------ Button class ------
|
flickerstreak@28
|
231 local Button = { }
|
flickerstreak@28
|
232
|
flickerstreak@28
|
233 local function Constructor( self, bar, idx, config )
|
flickerstreak@24
|
234 self.bar, self.idx, self.config = bar, idx, config
|
flickerstreak@24
|
235
|
flickerstreak@24
|
236 local barFrame = bar:GetFrame()
|
flickerstreak@24
|
237
|
flickerstreak@56
|
238 config.name = config.name or ("ReAction_%s_%d"):format(bar:GetName(),idx)
|
flickerstreak@49
|
239 self.name = config.name
|
flickerstreak@24
|
240 config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured
|
flickerstreak@24
|
241
|
flickerstreak@24
|
242 local f = CreateFrame("CheckButton", self.name, barFrame, "ActionBarButtonTemplate")
|
flickerstreak@49
|
243
|
flickerstreak@24
|
244 -- TODO: re-implement ActionButton event handlers that don't do secure stuff
|
flickerstreak@24
|
245
|
flickerstreak@24
|
246 -- this will probably cause taint, using right now for display/debugging purposes
|
flickerstreak@30
|
247 f:SetScript("OnAttributeChanged", ActionButton_UpdateAction)
|
flickerstreak@24
|
248 f:SetAttribute("action", config.actionID)
|
flickerstreak@49
|
249
|
flickerstreak@24
|
250 barFrame:SetAttribute("addchild",f)
|
flickerstreak@49
|
251
|
flickerstreak@24
|
252 self.frame = f
|
flickerstreak@24
|
253 self:Refresh(bar,idx)
|
flickerstreak@49
|
254
|
flickerstreak@49
|
255 if not module.db.profile.hideEmptyButtons then
|
flickerstreak@49
|
256 ActionButton_ShowGrid(self.frame)
|
flickerstreak@49
|
257 end
|
flickerstreak@50
|
258
|
flickerstreak@50
|
259 if ReAction.configMode then
|
flickerstreak@50
|
260 ActionButton_ShowGrid(self.frame)
|
flickerstreak@50
|
261 module:showActionIDLabel(self)
|
flickerstreak@50
|
262 end
|
flickerstreak@24
|
263 end
|
flickerstreak@24
|
264
|
flickerstreak@24
|
265 function Button:Destroy()
|
flickerstreak@24
|
266 local f = self.frame
|
flickerstreak@24
|
267 f:UnregisterAllEvents()
|
flickerstreak@24
|
268 f:Hide()
|
flickerstreak@24
|
269 f:SetParent(UIParent)
|
flickerstreak@24
|
270 f:ClearAllPoints()
|
flickerstreak@28
|
271 if self.name then
|
flickerstreak@28
|
272 _G[self.name] = nil
|
flickerstreak@24
|
273 end
|
flickerstreak@52
|
274 if self.config.actionID then
|
flickerstreak@52
|
275 ActionIDList[self.config.actionID] = nil
|
flickerstreak@52
|
276 end
|
flickerstreak@24
|
277 self.frame = nil
|
flickerstreak@24
|
278 self.config = nil
|
flickerstreak@24
|
279 self.bar = nil
|
flickerstreak@24
|
280 end
|
flickerstreak@24
|
281
|
flickerstreak@24
|
282 function Button:Refresh(bar,idx)
|
flickerstreak@24
|
283 bar:PlaceButton(self.frame, idx, 36, 36)
|
flickerstreak@24
|
284 end
|
flickerstreak@24
|
285
|
flickerstreak@24
|
286 function Button:GetFrame()
|
flickerstreak@24
|
287 return self.frame
|
flickerstreak@24
|
288 end
|
flickerstreak@24
|
289
|
flickerstreak@24
|
290 function Button:GetName()
|
flickerstreak@24
|
291 return self.name
|
flickerstreak@24
|
292 end
|
flickerstreak@24
|
293
|
flickerstreak@24
|
294 function Button:GetActionID()
|
flickerstreak@24
|
295 return self.config.actionID
|
flickerstreak@24
|
296 end
|
flickerstreak@28
|
297
|
flickerstreak@28
|
298
|
flickerstreak@28
|
299 -- export as a class-factory to module
|
flickerstreak@28
|
300 module.BtnClass = {
|
flickerstreak@28
|
301 new = function(self, ...)
|
flickerstreak@28
|
302 local x = { }
|
flickerstreak@28
|
303 for k,v in pairs(Button) do
|
flickerstreak@28
|
304 x[k] = v
|
flickerstreak@28
|
305 end
|
flickerstreak@28
|
306 Constructor(x, ...)
|
flickerstreak@28
|
307 return x
|
flickerstreak@28
|
308 end
|
flickerstreak@28
|
309 }
|