flickerstreak@122
|
1 local ReAction = ReAction
|
flickerstreak@122
|
2 local L = ReAction.L
|
flickerstreak@122
|
3 local _G = _G
|
flickerstreak@122
|
4 local CreateFrame = CreateFrame
|
flickerstreak@122
|
5 local floor = math.floor
|
flickerstreak@122
|
6 local fmod = math.fmod
|
flickerstreak@122
|
7 local format = string.format
|
flickerstreak@122
|
8
|
flickerstreak@122
|
9 ReAction:UpdateRevision("$Revision$")
|
flickerstreak@122
|
10
|
flickerstreak@147
|
11 local KB = LibStub("LibKeyBound-1.0")
|
flickerstreak@147
|
12
|
flickerstreak@147
|
13 ---- Bar class ----
|
flickerstreak@122
|
14 local Bar = { }
|
flickerstreak@122
|
15 local weak = { __mode = "k" }
|
flickerstreak@147
|
16 local frameList = { }
|
flickerstreak@122
|
17
|
flickerstreak@122
|
18 ReAction.Bar = Bar -- export to ReAction
|
flickerstreak@122
|
19
|
flickerstreak@122
|
20 function Bar:New( name, config )
|
flickerstreak@122
|
21 if type(config) ~= "table" then
|
flickerstreak@122
|
22 error("ReAction.Bar: config table required")
|
flickerstreak@122
|
23 end
|
flickerstreak@122
|
24
|
flickerstreak@122
|
25 -- create new self
|
flickerstreak@122
|
26 self = setmetatable(
|
flickerstreak@122
|
27 {
|
flickerstreak@122
|
28 config = config,
|
flickerstreak@122
|
29 name = name,
|
flickerstreak@122
|
30 buttons = setmetatable( { }, weak ),
|
flickerstreak@122
|
31 width = config.width or 480,
|
flickerstreak@147
|
32 height = config.height or 40,
|
flickerstreak@122
|
33 },
|
flickerstreak@147
|
34 {__index = self} )
|
flickerstreak@122
|
35
|
flickerstreak@122
|
36 -- The frame type is 'Button' in order to have an OnClick handler. However, the frame itself is
|
flickerstreak@122
|
37 -- not mouse-clickable by the user.
|
flickerstreak@122
|
38 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
|
flickerstreak@147
|
39 name = name and "ReAction-"..name
|
flickerstreak@147
|
40 local f = name and frameList[name]
|
flickerstreak@147
|
41 if not f then
|
flickerstreak@147
|
42 f = CreateFrame("Button", name, parent, "SecureHandlerStateTemplate, SecureHandlerClickTemplate")
|
flickerstreak@147
|
43 if name then
|
flickerstreak@147
|
44 frameList[name] = f
|
flickerstreak@147
|
45 end
|
flickerstreak@147
|
46 end
|
flickerstreak@122
|
47 f:SetFrameStrata("MEDIUM")
|
flickerstreak@122
|
48 f:SetWidth(self.width)
|
flickerstreak@146
|
49 f:SetHeight(self.height)
|
flickerstreak@122
|
50 f:SetAlpha(config.alpha or 1.0)
|
flickerstreak@122
|
51 f:Show()
|
flickerstreak@122
|
52 f:EnableMouse(false)
|
flickerstreak@122
|
53 f:SetClampedToScreen(true)
|
flickerstreak@122
|
54
|
flickerstreak@122
|
55 f:SetAttribute("_onstate-showgrid",
|
flickerstreak@122
|
56 -- function(self,stateid,newstate)
|
flickerstreak@122
|
57 [[
|
flickerstreak@122
|
58 control:ChildUpdate(stateid,newstate)
|
flickerstreak@122
|
59 control:CallMethod("UpdateShowGrid")
|
flickerstreak@122
|
60 ]])
|
flickerstreak@122
|
61 f.UpdateShowGrid = function(frame)
|
flickerstreak@122
|
62 for button in self:IterateButtons() do
|
flickerstreak@122
|
63 button:UpdateShowGrid()
|
flickerstreak@122
|
64 end
|
flickerstreak@122
|
65 end
|
flickerstreak@122
|
66 ReAction.gridProxy:AddFrame(f)
|
flickerstreak@122
|
67
|
flickerstreak@122
|
68 -- Override the default frame accessor to provide strict read-only access
|
flickerstreak@122
|
69 function self:GetFrame()
|
flickerstreak@122
|
70 return f
|
flickerstreak@122
|
71 end
|
flickerstreak@122
|
72
|
flickerstreak@122
|
73 self:ApplyAnchor()
|
flickerstreak@147
|
74 self:SetConfigMode(ReAction:GetConfigMode())
|
flickerstreak@147
|
75 self:SetKeybindMode(ReAction:GetKeybindMode())
|
flickerstreak@147
|
76
|
flickerstreak@122
|
77 ReAction.RegisterCallback(self, "OnConfigModeChanged")
|
flickerstreak@147
|
78 KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED")
|
flickerstreak@147
|
79 KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED")
|
flickerstreak@147
|
80 KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED")
|
flickerstreak@122
|
81
|
flickerstreak@122
|
82 return self
|
flickerstreak@122
|
83 end
|
flickerstreak@122
|
84
|
flickerstreak@122
|
85 function Bar:Destroy()
|
flickerstreak@122
|
86 local f = self:GetFrame()
|
flickerstreak@122
|
87 f:UnregisterAllEvents()
|
flickerstreak@125
|
88 self:ShowControls(false)
|
flickerstreak@122
|
89 ReAction.UnregisterAllCallbacks(self)
|
flickerstreak@147
|
90 KB.UnregisterAllCallbacks(self)
|
flickerstreak@122
|
91 ReAction.gridProxy:RemoveFrame(f)
|
flickerstreak@122
|
92 f:SetParent(UIParent)
|
flickerstreak@122
|
93 f:ClearAllPoints()
|
flickerstreak@147
|
94 f:Hide()
|
flickerstreak@122
|
95 end
|
flickerstreak@122
|
96
|
flickerstreak@147
|
97 --
|
flickerstreak@147
|
98 -- Events
|
flickerstreak@147
|
99 --
|
flickerstreak@147
|
100
|
flickerstreak@147
|
101 function Bar:OnConfigModeChanged(event, mode)
|
flickerstreak@147
|
102 self:SetConfigMode(mode)
|
flickerstreak@123
|
103 end
|
flickerstreak@123
|
104
|
flickerstreak@147
|
105 function Bar:LIBKEYBOUND_ENABLED(evt)
|
flickerstreak@147
|
106 self:SetKeybindMode(true)
|
flickerstreak@147
|
107 end
|
flickerstreak@147
|
108
|
flickerstreak@147
|
109 function Bar:LIBKEYBOUND_DISABLED(evt)
|
flickerstreak@147
|
110 self:SetKeybindMode(false)
|
flickerstreak@122
|
111 end
|
flickerstreak@122
|
112
|
flickerstreak@153
|
113 --
|
flickerstreak@153
|
114 -- Accessors
|
flickerstreak@153
|
115 --
|
flickerstreak@153
|
116
|
flickerstreak@153
|
117 function Bar:GetName()
|
flickerstreak@153
|
118 return self.name
|
flickerstreak@153
|
119 end
|
flickerstreak@153
|
120
|
flickerstreak@153
|
121 -- only ReAction:RenameBar() should call this function. Calling from any other
|
flickerstreak@153
|
122 -- context will desync the bar list in the ReAction class.
|
flickerstreak@153
|
123 function Bar:SetName(name)
|
flickerstreak@153
|
124 self.name = name
|
flickerstreak@154
|
125 if self.overlay then
|
flickerstreak@154
|
126 self.overlay:SetLabel(self.name)
|
flickerstreak@154
|
127 end
|
flickerstreak@153
|
128 end
|
flickerstreak@153
|
129
|
flickerstreak@153
|
130 function Bar:GetFrame()
|
flickerstreak@153
|
131 -- this method is included for documentation purposes. It is overridden
|
flickerstreak@153
|
132 -- for each object in the :New() method.
|
flickerstreak@153
|
133 error("Invalid Bar object: used without initialization")
|
flickerstreak@153
|
134 end
|
flickerstreak@153
|
135
|
flickerstreak@153
|
136 function Bar:GetConfig()
|
flickerstreak@153
|
137 return self.config
|
flickerstreak@153
|
138 end
|
flickerstreak@153
|
139
|
flickerstreak@153
|
140 function Bar:GetAnchor()
|
flickerstreak@122
|
141 local c = self.config
|
flickerstreak@153
|
142 return (c.point or "CENTER"),
|
flickerstreak@153
|
143 (c.anchor or self:GetFrame():GetParent():GetName()),
|
flickerstreak@153
|
144 (c.relpoint or c.point or "CENTER"),
|
flickerstreak@153
|
145 (c.x or 0),
|
flickerstreak@153
|
146 (c.y or 0)
|
flickerstreak@122
|
147 end
|
flickerstreak@122
|
148
|
flickerstreak@122
|
149 function Bar:SetAnchor(point, frame, relativePoint, x, y)
|
flickerstreak@122
|
150 local c = self.config
|
flickerstreak@122
|
151 c.point = point or c.point
|
flickerstreak@122
|
152 c.anchor = frame or c.anchor
|
flickerstreak@122
|
153 c.relpoint = relativePoint or c.relpoint
|
flickerstreak@122
|
154 c.x = x or c.x
|
flickerstreak@122
|
155 c.y = y or c.y
|
flickerstreak@122
|
156 self:ApplyAnchor()
|
flickerstreak@122
|
157 ReAction:RefreshBar(self)
|
flickerstreak@122
|
158 end
|
flickerstreak@122
|
159
|
flickerstreak@122
|
160 function Bar:GetSize()
|
flickerstreak@122
|
161 local f = self:GetFrame()
|
flickerstreak@122
|
162 return f:GetWidth(), f:GetHeight()
|
flickerstreak@122
|
163 end
|
flickerstreak@122
|
164
|
flickerstreak@122
|
165 function Bar:SetSize(w,h)
|
flickerstreak@122
|
166 local f = self:GetFrame()
|
flickerstreak@122
|
167 self.config.width = w
|
flickerstreak@122
|
168 self.config.height = h
|
flickerstreak@122
|
169 f:SetWidth(w)
|
flickerstreak@122
|
170 f:SetHeight(h)
|
flickerstreak@122
|
171 end
|
flickerstreak@122
|
172
|
flickerstreak@122
|
173 function Bar:GetButtonSize()
|
flickerstreak@122
|
174 local w = self.config.btnWidth or 32
|
flickerstreak@122
|
175 local h = self.config.btnHeight or 32
|
flickerstreak@122
|
176 -- TODO: get from modules?
|
flickerstreak@122
|
177 return w,h
|
flickerstreak@122
|
178 end
|
flickerstreak@122
|
179
|
flickerstreak@122
|
180 function Bar:SetButtonSize(w,h)
|
flickerstreak@122
|
181 if w > 0 and h > 0 then
|
flickerstreak@122
|
182 self.config.btnWidth = w
|
flickerstreak@122
|
183 self.config.btnHeight = h
|
flickerstreak@122
|
184 end
|
flickerstreak@122
|
185 ReAction:RefreshBar(self)
|
flickerstreak@122
|
186 end
|
flickerstreak@122
|
187
|
flickerstreak@153
|
188 function Bar:GetNumButtons()
|
flickerstreak@153
|
189 local r,c = self:GetButtonGrid()
|
flickerstreak@153
|
190 return r*c
|
flickerstreak@153
|
191 end
|
flickerstreak@153
|
192
|
flickerstreak@122
|
193 function Bar:GetButtonGrid()
|
flickerstreak@122
|
194 local cfg = self.config
|
flickerstreak@122
|
195 local r = cfg.btnRows or 1
|
flickerstreak@122
|
196 local c = cfg.btnColumns or 1
|
flickerstreak@122
|
197 local s = cfg.spacing or 4
|
flickerstreak@122
|
198 return r,c,s
|
flickerstreak@122
|
199 end
|
flickerstreak@122
|
200
|
flickerstreak@122
|
201 function Bar:SetButtonGrid(r,c,s)
|
flickerstreak@122
|
202 if r > 0 and c > 0 and s > 0 then
|
flickerstreak@122
|
203 local cfg = self.config
|
flickerstreak@122
|
204 cfg.btnRows = r
|
flickerstreak@122
|
205 cfg.btnColumns = c
|
flickerstreak@122
|
206 cfg.spacing = s
|
flickerstreak@122
|
207 end
|
flickerstreak@122
|
208 ReAction:RefreshBar(self)
|
flickerstreak@122
|
209 end
|
flickerstreak@122
|
210
|
flickerstreak@122
|
211 function Bar:GetAlpha()
|
flickerstreak@122
|
212 return self.config.alpha or 1.0
|
flickerstreak@122
|
213 end
|
flickerstreak@122
|
214
|
flickerstreak@122
|
215 function Bar:SetAlpha(value)
|
flickerstreak@122
|
216 self.config.alpha = value
|
flickerstreak@122
|
217 self:GetFrame():SetAlpha(value or 1.0)
|
flickerstreak@122
|
218 ReAction:RefreshBar(self)
|
flickerstreak@122
|
219 end
|
flickerstreak@122
|
220
|
flickerstreak@122
|
221 -- iterator returns button, idx and does NOT iterate in index order
|
flickerstreak@122
|
222 function Bar:IterateButtons()
|
flickerstreak@122
|
223 return pairs(self.buttons)
|
flickerstreak@122
|
224 end
|
flickerstreak@122
|
225
|
flickerstreak@153
|
226 --
|
flickerstreak@153
|
227 -- Methods
|
flickerstreak@153
|
228 --
|
flickerstreak@153
|
229
|
flickerstreak@147
|
230 function Bar:SetConfigMode(mode)
|
flickerstreak@147
|
231 self:ShowControls(mode)
|
flickerstreak@148
|
232 if self.unitwatch then
|
flickerstreak@148
|
233 if mode then
|
flickerstreak@148
|
234 UnregisterUnitWatch(self:GetFrame())
|
flickerstreak@148
|
235 self:GetFrame():Show()
|
flickerstreak@148
|
236 else
|
flickerstreak@148
|
237 RegisterUnitWatch(self:GetFrame())
|
flickerstreak@148
|
238 end
|
flickerstreak@148
|
239 end
|
flickerstreak@147
|
240 for b in self:IterateButtons() do
|
flickerstreak@147
|
241 b:ShowGridTemp(mode)
|
flickerstreak@147
|
242 b:UpdateActionIDLabel(mode)
|
flickerstreak@147
|
243 end
|
flickerstreak@147
|
244 end
|
flickerstreak@147
|
245
|
flickerstreak@147
|
246 function Bar:SetKeybindMode(mode)
|
flickerstreak@148
|
247 if self.unitwatch then
|
flickerstreak@148
|
248 if mode then
|
flickerstreak@148
|
249 UnregisterUnitWatch(self:GetFrame())
|
flickerstreak@148
|
250 self:GetFrame():Show()
|
flickerstreak@148
|
251 else
|
flickerstreak@148
|
252 RegisterUnitWatch(self:GetFrame())
|
flickerstreak@148
|
253 end
|
flickerstreak@148
|
254 end
|
flickerstreak@147
|
255 for b in self:IterateButtons() do
|
flickerstreak@147
|
256 b:SetKeybindMode(mode)
|
flickerstreak@147
|
257 end
|
flickerstreak@147
|
258 end
|
flickerstreak@147
|
259
|
flickerstreak@153
|
260 function Bar:ApplyAnchor()
|
flickerstreak@153
|
261 local f = self:GetFrame()
|
flickerstreak@153
|
262 local c = self.config
|
flickerstreak@153
|
263 local p = c.point
|
flickerstreak@153
|
264
|
flickerstreak@153
|
265 f:SetWidth(c.width)
|
flickerstreak@153
|
266 f:SetHeight(c.height)
|
flickerstreak@153
|
267 f:ClearAllPoints()
|
flickerstreak@153
|
268
|
flickerstreak@153
|
269 if p then
|
flickerstreak@153
|
270 local a = f:GetParent()
|
flickerstreak@153
|
271 if c.anchor then
|
flickerstreak@153
|
272 local bar = ReAction:GetBar(c.anchor)
|
flickerstreak@153
|
273 if bar then
|
flickerstreak@153
|
274 a = bar:GetFrame()
|
flickerstreak@153
|
275 else
|
flickerstreak@153
|
276 a = _G[c.anchor]
|
flickerstreak@153
|
277 end
|
flickerstreak@153
|
278 end
|
flickerstreak@153
|
279 local fr = a or f:GetParent()
|
flickerstreak@153
|
280 f:SetPoint(p, a or f:GetParent(), c.relpoint, c.x or 0, c.y or 0)
|
flickerstreak@153
|
281 else
|
flickerstreak@153
|
282 f:SetPoint("CENTER")
|
flickerstreak@153
|
283 end
|
flickerstreak@153
|
284 end
|
flickerstreak@153
|
285
|
flickerstreak@153
|
286 function Bar:ClipNButtons( n )
|
flickerstreak@153
|
287 local cfg = self.config
|
flickerstreak@153
|
288 local r = cfg.btnRows or 1
|
flickerstreak@153
|
289 local c = cfg.btnColumns or 1
|
flickerstreak@153
|
290
|
flickerstreak@153
|
291 cfg.btnRows = ceil(n/c)
|
flickerstreak@153
|
292 cfg.btnColumns = min(n,c)
|
flickerstreak@153
|
293 end
|
flickerstreak@153
|
294
|
flickerstreak@153
|
295 function Bar:AddButton(idx, button)
|
flickerstreak@153
|
296 local f = self:GetFrame()
|
flickerstreak@153
|
297
|
flickerstreak@153
|
298 -- store in a weak reverse-index array
|
flickerstreak@153
|
299 self.buttons[button] = idx
|
flickerstreak@153
|
300
|
flickerstreak@153
|
301 -- Store a properly wrapped reference to the child frame as an attribute
|
flickerstreak@153
|
302 -- (accessible via "frameref-btn#")
|
flickerstreak@153
|
303 f:SetFrameRef(format("btn%d",idx), button:GetFrame())
|
flickerstreak@153
|
304 end
|
flickerstreak@153
|
305
|
flickerstreak@153
|
306 function Bar:RemoveButton(button)
|
flickerstreak@153
|
307 local idx = self.buttons[button]
|
flickerstreak@153
|
308 if idx then
|
flickerstreak@153
|
309 self:GetFrame():SetAttribute(format("frameref-btn%d",idx),nil)
|
flickerstreak@153
|
310 self.buttons[button] = nil
|
flickerstreak@153
|
311 end
|
flickerstreak@153
|
312 end
|
flickerstreak@153
|
313
|
flickerstreak@122
|
314 function Bar:PlaceButton(button, baseW, baseH)
|
flickerstreak@122
|
315 local idx = self.buttons[button]
|
flickerstreak@122
|
316 if idx then
|
flickerstreak@122
|
317 local r, c, s = self:GetButtonGrid()
|
flickerstreak@122
|
318 local bh, bw = self:GetButtonSize()
|
flickerstreak@122
|
319 local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
|
flickerstreak@122
|
320 local x, y = col*bw + (col+0.5)*s, -(row*bh + (row+0.5)*s)
|
flickerstreak@122
|
321 local scale = bw/baseW
|
flickerstreak@122
|
322 local b = button:GetFrame()
|
flickerstreak@122
|
323
|
flickerstreak@122
|
324 b:ClearAllPoints()
|
flickerstreak@122
|
325 b:SetPoint("TOPLEFT",x/scale,y/scale)
|
flickerstreak@122
|
326 b:SetScale(scale)
|
flickerstreak@122
|
327 end
|
flickerstreak@122
|
328 end
|
flickerstreak@122
|
329
|
flickerstreak@122
|
330 function Bar:SkinButton()
|
flickerstreak@122
|
331 -- does nothing by default
|
flickerstreak@147
|
332 end
|
flickerstreak@148
|
333
|
flickerstreak@154
|
334 function Bar:ShowControls(show)
|
flickerstreak@154
|
335 local f = self.overlay
|
flickerstreak@154
|
336 if show then
|
flickerstreak@154
|
337 if not f then
|
flickerstreak@154
|
338 f = Bar.Overlay:New(self) -- see Overlay.lua
|
flickerstreak@154
|
339 self.overlay = f
|
flickerstreak@154
|
340 end
|
flickerstreak@154
|
341 f:Show()
|
flickerstreak@154
|
342 elseif f then
|
flickerstreak@154
|
343 f:Hide()
|
flickerstreak@154
|
344 end
|
flickerstreak@154
|
345 end
|
flickerstreak@154
|
346
|
flickerstreak@154
|
347 function Bar:RefreshControls()
|
flickerstreak@154
|
348 if self.overlay and self.overlay:IsShown() then
|
flickerstreak@154
|
349 self.overlay:RefreshControls()
|
flickerstreak@154
|
350 end
|
flickerstreak@154
|
351 end
|
flickerstreak@154
|
352
|
flickerstreak@154
|
353 function Bar:SetLabelSubtext(text)
|
flickerstreak@154
|
354 if self.overlay then
|
flickerstreak@154
|
355 self.overlay:SetLabelSubtext(text)
|
flickerstreak@154
|
356 end
|
flickerstreak@154
|
357 end
|
flickerstreak@154
|
358
|
flickerstreak@154
|
359 --
|
flickerstreak@154
|
360 -- Secure state functions
|
flickerstreak@154
|
361 --
|
flickerstreak@154
|
362
|
flickerstreak@148
|
363 -- pass unit=nil to set up the unit elsewhere, if you want something more complex
|
flickerstreak@148
|
364 function Bar:RegisterUnitWatch( unit, enable )
|
flickerstreak@148
|
365 local f = self:GetFrame()
|
flickerstreak@148
|
366 if unit then
|
flickerstreak@148
|
367 f:SetAttribute("unit",unit)
|
flickerstreak@148
|
368 end
|
flickerstreak@148
|
369 if not ReAction:GetConfigMode() then
|
flickerstreak@148
|
370 if enable then
|
flickerstreak@148
|
371 RegisterUnitWatch(f)
|
flickerstreak@148
|
372 elseif self.unitwatch then
|
flickerstreak@148
|
373 UnregisterUnitWatch(f)
|
flickerstreak@148
|
374 end
|
flickerstreak@148
|
375 end
|
flickerstreak@148
|
376 self.unitwatch = enable
|
flickerstreak@148
|
377 end
|
flickerstreak@148
|
378
|