Flick@276
|
1 local _, ns = ...
|
Flick@276
|
2 local ReAction = ns.ReAction
|
flickerstreak@122
|
3 local L = ReAction.L
|
flickerstreak@183
|
4 local LKB = ReAction.LKB
|
flickerstreak@122
|
5 local _G = _G
|
flickerstreak@122
|
6 local CreateFrame = CreateFrame
|
flickerstreak@122
|
7 local GetBindingKey = GetBindingKey
|
flickerstreak@122
|
8 local format = string.format
|
flickerstreak@122
|
9
|
flickerstreak@122
|
10 -- private
|
flickerstreak@122
|
11 local trash = CreateFrame("Frame")
|
flickerstreak@122
|
12 local frameList = { }
|
flickerstreak@122
|
13 local idPools = { }
|
flickerstreak@122
|
14
|
flickerstreak@122
|
15 local function kb_onEnter( frame )
|
flickerstreak@183
|
16 LKB:Set(frame)
|
flickerstreak@122
|
17 end
|
flickerstreak@122
|
18
|
flickerstreak@122
|
19 -- Button class
|
flickerstreak@218
|
20 local buttonTypeID = "Button"
|
flickerstreak@218
|
21 local Button = {
|
flickerstreak@218
|
22 defaultBarConfig = {
|
flickerstreak@218
|
23 type = buttonTypeID,
|
flickerstreak@218
|
24 btnWidth = 36,
|
flickerstreak@218
|
25 btnHeight = 36,
|
flickerstreak@218
|
26 btnRows = 1,
|
flickerstreak@218
|
27 btnColumns = 12,
|
flickerstreak@218
|
28 spacing = 3
|
flickerstreak@218
|
29 },
|
Flick@277
|
30 -- barType = L["Button Bar"], -- derived classes must declare
|
Flick@277
|
31 -- buttonTypeID = "Button" -- derived classes must declare
|
flickerstreak@218
|
32 }
|
flickerstreak@122
|
33
|
flickerstreak@122
|
34 ReAction.Button = Button -- export to ReAction
|
flickerstreak@122
|
35
|
Flick@277
|
36 function Button:New( config, bar, idx, inherits, buttonType )
|
flickerstreak@122
|
37 buttonType = buttonType or "CheckButton"
|
flickerstreak@122
|
38
|
Flick@277
|
39 local name = format("ReAction_%s_%s_%d",bar:GetName(), self.buttonTypeID, idx)
|
Flick@277
|
40
|
flickerstreak@122
|
41 -- create new self
|
flickerstreak@122
|
42 self = setmetatable(
|
flickerstreak@122
|
43 {
|
flickerstreak@122
|
44 bar = bar,
|
flickerstreak@122
|
45 idx = idx,
|
flickerstreak@129
|
46 config = config,
|
flickerstreak@122
|
47 name = name,
|
flickerstreak@122
|
48 },
|
flickerstreak@122
|
49 { __index = self } )
|
flickerstreak@122
|
50
|
flickerstreak@122
|
51 -- have to recycle frames with the same name: CreateFrame() doesn't overwrite
|
flickerstreak@122
|
52 -- existing globals. Can't set to nil in the global because it's then tainted.
|
flickerstreak@122
|
53 -- Caller is responsible for ensuring global uniqueness of names.
|
flickerstreak@122
|
54 local f = name and frameList[name]
|
flickerstreak@122
|
55 if f then
|
flickerstreak@122
|
56 f:SetParent(bar:GetFrame())
|
flickerstreak@122
|
57 else
|
flickerstreak@122
|
58 f = CreateFrame(buttonType, name, bar:GetFrame(), inherits)
|
flickerstreak@122
|
59 if name then
|
flickerstreak@122
|
60 frameList[name] = f
|
flickerstreak@122
|
61 end
|
flickerstreak@122
|
62 end
|
flickerstreak@122
|
63
|
flickerstreak@122
|
64 self.frame = f
|
flickerstreak@122
|
65
|
flickerstreak@131
|
66 local frames = { }
|
flickerstreak@131
|
67 self.frames = frames
|
flickerstreak@131
|
68 frames.icon = _G[name.."Icon"]
|
flickerstreak@131
|
69 frames.flash = _G[name.."Flash"]
|
flickerstreak@131
|
70 frames.hotkey = _G[name.."HotKey"]
|
flickerstreak@131
|
71 frames.count = _G[name.."Count"]
|
flickerstreak@131
|
72 frames.name = _G[name.."Name"]
|
flickerstreak@131
|
73 frames.border = _G[name.."Border"]
|
flickerstreak@131
|
74 frames.cooldown = _G[name.."Cooldown"]
|
flickerstreak@131
|
75 frames.normalTexture = _G[name.."NormalTexture"]
|
flickerstreak@131
|
76
|
flickerstreak@122
|
77 if config then
|
flickerstreak@122
|
78 config.name = name
|
flickerstreak@122
|
79 end
|
flickerstreak@122
|
80
|
flickerstreak@122
|
81 -- install LibKeyBound handlers onto frame
|
flickerstreak@122
|
82 function f:GetActionName()
|
flickerstreak@122
|
83 return format("%s:%s", bar:GetName(), idx)
|
flickerstreak@122
|
84 end
|
flickerstreak@122
|
85
|
Flick@259
|
86 -- mouse and clicking
|
Flick@259
|
87 -- set click handlers in subclasses
|
Flick@259
|
88 f:EnableMouse(true)
|
Flick@259
|
89 f:RegisterForClicks( bar:GetConfig().clickDown and "AnyDown" or "AnyUp" )
|
flickerstreak@122
|
90 local clickBinding = format("CLICK %s:LeftButton", name)
|
flickerstreak@122
|
91 function f:GetHotkey()
|
flickerstreak@183
|
92 return LKB:ToShortKey(GetBindingKey(clickBinding))
|
flickerstreak@122
|
93 end
|
flickerstreak@122
|
94
|
flickerstreak@122
|
95 return self
|
flickerstreak@122
|
96 end
|
flickerstreak@122
|
97
|
flickerstreak@122
|
98 function Button:Destroy()
|
flickerstreak@126
|
99 local f = self:GetFrame()
|
flickerstreak@132
|
100 f:UnregisterAllEvents()
|
flickerstreak@132
|
101 self:ReleaseActionID(self:GetActionID())
|
flickerstreak@126
|
102 if f then
|
flickerstreak@126
|
103 f:Hide()
|
flickerstreak@126
|
104 f:SetParent(trash)
|
flickerstreak@126
|
105 f:ClearAllPoints()
|
flickerstreak@126
|
106 end
|
flickerstreak@122
|
107 end
|
flickerstreak@122
|
108
|
flickerstreak@128
|
109 function Button:GetBar()
|
flickerstreak@128
|
110 return self.bar
|
flickerstreak@128
|
111 end
|
flickerstreak@128
|
112
|
flickerstreak@122
|
113 function Button:GetFrame()
|
flickerstreak@122
|
114 return self.frame
|
flickerstreak@122
|
115 end
|
flickerstreak@122
|
116
|
Flick@234
|
117 function Button:GetIndex()
|
Flick@234
|
118 return self.idx
|
Flick@234
|
119 end
|
Flick@234
|
120
|
flickerstreak@122
|
121 function Button:GetName()
|
flickerstreak@122
|
122 return self.name
|
flickerstreak@122
|
123 end
|
flickerstreak@122
|
124
|
flickerstreak@218
|
125 function Button:GetDefaultBarConfig()
|
flickerstreak@218
|
126 return self.defaultBarConfig
|
flickerstreak@218
|
127 end
|
flickerstreak@218
|
128
|
flickerstreak@218
|
129 function Button:GetBarType()
|
flickerstreak@218
|
130 return self.barType
|
flickerstreak@218
|
131 end
|
flickerstreak@218
|
132
|
Flick@231
|
133 function Button:GetButtonTypeID()
|
Flick@231
|
134 return self.buttonTypeID
|
Flick@231
|
135 end
|
Flick@231
|
136
|
flickerstreak@122
|
137 function Button:GetConfig()
|
flickerstreak@122
|
138 return self.config
|
flickerstreak@122
|
139 end
|
flickerstreak@122
|
140
|
flickerstreak@122
|
141 function Button:GetActionID()
|
flickerstreak@122
|
142 -- derived classes should override this
|
flickerstreak@122
|
143 return nil
|
flickerstreak@122
|
144 end
|
flickerstreak@122
|
145
|
flickerstreak@122
|
146 function Button:SetActionIDPool( poolID, maxID )
|
flickerstreak@122
|
147 self.actionPoolID = poolID
|
flickerstreak@122
|
148 self.actionMaxID = maxID
|
flickerstreak@122
|
149 end
|
flickerstreak@122
|
150
|
Flick@234
|
151 function Button:SetupBar( bar )
|
Flick@234
|
152 local config = bar:GetConfig()
|
Flick@234
|
153 if not config.buttons then
|
Flick@234
|
154 config.buttons = { }
|
Flick@234
|
155 end
|
Flick@234
|
156 local btnCfg = config.buttons
|
Flick@234
|
157
|
Flick@234
|
158 local r, c = bar:GetButtonGrid()
|
Flick@234
|
159 local n = r*c
|
Flick@235
|
160 local cfgN = n
|
Flick@234
|
161
|
Flick@234
|
162 local hint = nil
|
Flick@234
|
163 local i = 1
|
Flick@234
|
164 repeat
|
Flick@234
|
165 local b = bar:GetButton(i)
|
Flick@234
|
166 if b then
|
Flick@234
|
167 if i > n then
|
Flick@234
|
168 bar:RemoveButton(b)
|
Flick@234
|
169 b:Destroy()
|
Flick@235
|
170 if i > cfgN then
|
Flick@235
|
171 btnCfg[i] = nil
|
Flick@235
|
172 end
|
Flick@234
|
173 else
|
Flick@234
|
174 b:Refresh()
|
Flick@234
|
175 hint = b:GetActionID()
|
Flick@234
|
176 end
|
Flick@234
|
177 elseif i <= n then
|
Flick@234
|
178 local cfg = btnCfg[i] or { }
|
Flick@234
|
179 local success, r = pcall(self.New, self, cfg, bar, i, hint) -- note call semantics for derived class constructors
|
Flick@234
|
180 if success and r then
|
Flick@234
|
181 b = r
|
Flick@234
|
182 bar:AddButton(i,b)
|
Flick@234
|
183 btnCfg[i] = cfg
|
Flick@234
|
184 b:Refresh()
|
Flick@234
|
185 hint = b:GetActionID()
|
Flick@234
|
186 else
|
Flick@234
|
187 n = i - 1
|
Flick@234
|
188 if not success then
|
Flick@236
|
189 bar:ClipNButtons(n)
|
Flick@236
|
190 cfgN = n
|
Flick@279
|
191 if r then
|
Flick@279
|
192 geterrorhandler()(r)
|
Flick@279
|
193 end
|
Flick@234
|
194 end
|
Flick@234
|
195 end
|
Flick@234
|
196 end
|
Flick@234
|
197 i = i + 1
|
Flick@234
|
198 until b == nil
|
Flick@234
|
199 end
|
Flick@234
|
200
|
flickerstreak@122
|
201 function Button:AcquireActionID( id, hint, unique )
|
flickerstreak@122
|
202 local poolID = self.actionPoolID
|
flickerstreak@122
|
203 local maxID = self.actionMaxID
|
flickerstreak@122
|
204 if not poolID or not maxID then
|
flickerstreak@122
|
205 error("AcquireActionID: must setup pool first with SetActionIDPool")
|
flickerstreak@122
|
206 end
|
flickerstreak@123
|
207 local pool = idPools[poolID]
|
flickerstreak@122
|
208 if not pool then
|
flickerstreak@122
|
209 pool = { nWraps = 0, useCount = { } }
|
flickerstreak@122
|
210 for i = 1, maxID do
|
flickerstreak@122
|
211 pool.useCount[i] = 0
|
flickerstreak@122
|
212 end
|
flickerstreak@123
|
213 idPools[poolID] = pool
|
flickerstreak@122
|
214 end
|
flickerstreak@122
|
215 local useCount = pool.useCount
|
flickerstreak@122
|
216 if id == nil then
|
flickerstreak@122
|
217 repeat
|
flickerstreak@126
|
218 local nWraps = pool.nWraps or 0
|
flickerstreak@126
|
219 if hint and (useCount[hint] == nil or useCount[hint] == nWraps) then
|
flickerstreak@122
|
220 id = hint
|
flickerstreak@122
|
221 else
|
flickerstreak@122
|
222 local start = hint or 1
|
flickerstreak@122
|
223 for i = start, maxID do
|
flickerstreak@122
|
224 if useCount[i] == nil or useCount[i] == nWraps then
|
flickerstreak@122
|
225 id = i
|
flickerstreak@122
|
226 break
|
flickerstreak@122
|
227 end
|
flickerstreak@122
|
228 end
|
flickerstreak@122
|
229 if not id then
|
flickerstreak@122
|
230 for i = 1, start do
|
flickerstreak@122
|
231 if useCount[i] == nil or useCount[i] == nWraps then
|
flickerstreak@122
|
232 id = i
|
flickerstreak@122
|
233 break
|
flickerstreak@122
|
234 end
|
flickerstreak@122
|
235 end
|
flickerstreak@122
|
236 end
|
flickerstreak@122
|
237 end
|
flickerstreak@122
|
238 if id == nil then
|
flickerstreak@122
|
239 if unique then
|
Flick@279
|
240 ReAction:UserError(("All action IDs for bars of type '%s' are in use, cannot create any more buttons"):format(self.barType))
|
Flick@279
|
241 error(nil) -- no error message, user has already been notified, so don't put in Lua error handler
|
flickerstreak@122
|
242 end
|
flickerstreak@122
|
243 pool.nWraps = nWraps + 1
|
flickerstreak@122
|
244 end
|
flickerstreak@126
|
245 until id ~= nil
|
flickerstreak@122
|
246 end
|
flickerstreak@122
|
247 useCount[id] = (useCount[id] or 0) + 1
|
flickerstreak@122
|
248 return id
|
flickerstreak@122
|
249 end
|
flickerstreak@122
|
250
|
flickerstreak@122
|
251 function Button:ReleaseActionID( id )
|
flickerstreak@122
|
252 local poolID = self.actionPoolID
|
flickerstreak@122
|
253 if not poolID then
|
flickerstreak@122
|
254 error("ReleaseActionID: must setup pool first with SetActionIDPool")
|
flickerstreak@122
|
255 end
|
flickerstreak@123
|
256 local pool = idPools[poolID]
|
flickerstreak@122
|
257 if pool and id and pool.useCount[id] then
|
flickerstreak@122
|
258 pool.useCount[id] = pool.useCount[id] - 1
|
flickerstreak@122
|
259 pool.nWraps = min(pool.useCount[id], pool.nWraps)
|
flickerstreak@122
|
260 end
|
flickerstreak@122
|
261 end
|
flickerstreak@122
|
262
|
flickerstreak@122
|
263 function Button:Refresh()
|
flickerstreak@129
|
264 local f = self:GetFrame()
|
flickerstreak@129
|
265 self.bar:PlaceButton( self, f:GetWidth(), f:GetHeight() )
|
flickerstreak@122
|
266 end
|
flickerstreak@122
|
267
|
flickerstreak@122
|
268 function Button:SetKeybindMode( mode )
|
flickerstreak@122
|
269 local f = self.frame
|
flickerstreak@122
|
270 if mode then
|
flickerstreak@122
|
271 self.oldOnEnter = f:GetScript("OnEnter")
|
flickerstreak@122
|
272 f:SetScript("OnEnter", kb_onEnter)
|
flickerstreak@124
|
273 elseif self.oldOnEnter then
|
flickerstreak@122
|
274 f:SetScript("OnEnter", self.oldOnEnter)
|
flickerstreak@122
|
275 self.oldOnEnter = nil
|
flickerstreak@122
|
276 end
|
flickerstreak@128
|
277 self:ShowGridTemp(mode)
|
flickerstreak@122
|
278 self:UpdateKeybindModeDisplay( mode )
|
flickerstreak@122
|
279 end
|
flickerstreak@122
|
280
|
flickerstreak@122
|
281 function Button:UpdateKeybindModeDisplay( mode )
|
flickerstreak@131
|
282 local border = self.frames.border or _G[format("%sBorder",tostring(self:GetName()))]
|
flickerstreak@131
|
283 if border then
|
flickerstreak@122
|
284 if mode then
|
flickerstreak@183
|
285 border:SetVertexColor(LKB:GetColorKeyBoundMode())
|
flickerstreak@131
|
286 border:Show()
|
flickerstreak@122
|
287 else
|
flickerstreak@131
|
288 border:Hide()
|
flickerstreak@122
|
289 end
|
flickerstreak@122
|
290 end
|
flickerstreak@122
|
291 end
|
flickerstreak@122
|
292
|
flickerstreak@122
|
293 function Button:UpdateHotkey( hotkey )
|
flickerstreak@131
|
294 hotkey = hotkey or self.frames.hotkey
|
flickerstreak@122
|
295 if not hotkey then
|
flickerstreak@129
|
296 hotkey = _G[self:GetName().."HotKey"]
|
flickerstreak@131
|
297 self.frames.hotkey = hotkey
|
flickerstreak@122
|
298 end
|
flickerstreak@122
|
299 if hotkey then
|
flickerstreak@122
|
300 local txt = self.frame:GetHotkey()
|
flickerstreak@122
|
301 hotkey:SetText( txt )
|
flickerstreak@122
|
302 if txt == nil or txt == "" then
|
flickerstreak@122
|
303 hotkey:Hide()
|
flickerstreak@122
|
304 else
|
flickerstreak@122
|
305 hotkey:Show()
|
flickerstreak@122
|
306 end
|
flickerstreak@122
|
307 end
|
flickerstreak@122
|
308 end
|
flickerstreak@122
|
309
|
flickerstreak@122
|
310 function Button:GetActionIDLabel( create )
|
flickerstreak@129
|
311 local f = self:GetFrame()
|
flickerstreak@122
|
312 if not f.actionIDLabel and create then
|
flickerstreak@122
|
313 local label = f:CreateFontString(nil,"OVERLAY","GameFontNormalLarge")
|
flickerstreak@122
|
314 label:SetAllPoints()
|
flickerstreak@122
|
315 label:SetJustifyH("CENTER")
|
flickerstreak@122
|
316 label:SetShadowColor(0,0,0,1)
|
flickerstreak@122
|
317 label:SetShadowOffset(2,-2)
|
flickerstreak@122
|
318 f.actionIDLabel = label -- store the label with the frame for recycling
|
flickerstreak@122
|
319 end
|
flickerstreak@122
|
320 return f.actionIDLabel
|
flickerstreak@122
|
321 end
|
flickerstreak@122
|
322
|
flickerstreak@122
|
323 function Button:UpdateActionIDLabel( show )
|
flickerstreak@122
|
324 local label = self:GetActionIDLabel( show )
|
flickerstreak@122
|
325 if label then
|
flickerstreak@122
|
326 if show then
|
flickerstreak@122
|
327 local id = self:GetActionID()
|
flickerstreak@122
|
328 if id then
|
flickerstreak@122
|
329 label:SetText(tostring(id))
|
flickerstreak@122
|
330 label:Show()
|
flickerstreak@122
|
331 return
|
flickerstreak@122
|
332 end
|
flickerstreak@122
|
333 end
|
flickerstreak@122
|
334 label:Hide()
|
flickerstreak@122
|
335 end
|
flickerstreak@122
|
336 end
|
flickerstreak@122
|
337
|
flickerstreak@122
|
338 function Button:SetNormalVertexColor( r, g, b, a )
|
flickerstreak@213
|
339 if ReAction.LBF then
|
flickerstreak@213
|
340 ReAction.LBF:SetNormalVertexColor(self:GetFrame(), r, g, b, a)
|
flickerstreak@122
|
341 else
|
flickerstreak@129
|
342 self:GetFrame():GetNormalTexture():SetVertexColor(r,g,b,a)
|
flickerstreak@122
|
343 end
|
flickerstreak@122
|
344 end
|
flickerstreak@122
|
345
|
flickerstreak@122
|
346 function Button:GetNormalVertexColor()
|
flickerstreak@213
|
347 if ReAction.LBF then
|
flickerstreak@213
|
348 return ReAction.LBF:GetNormalVertexColor(self:GetFrame())
|
flickerstreak@122
|
349 else
|
flickerstreak@129
|
350 return self:GetFrame():GetNormalTexture():GetVertexColor()
|
flickerstreak@122
|
351 end
|
flickerstreak@122
|
352 end
|
flickerstreak@122
|
353
|
flickerstreak@122
|
354 function Button:UpdateShowGrid()
|
flickerstreak@122
|
355 -- does nothing by default
|
flickerstreak@122
|
356 end
|
flickerstreak@128
|
357
|
flickerstreak@128
|
358 function Button:ShowGridTemp(show)
|
flickerstreak@128
|
359 -- does nothing by default
|
flickerstreak@128
|
360 end
|
flickerstreak@128
|
361
|
flickerstreak@128
|
362 function Button:ShowGrid(show)
|
flickerstreak@128
|
363 -- does nothing by default
|
flickerstreak@128
|
364 end
|