flickerstreak@25
|
1 local ReAction = ReAction
|
flickerstreak@25
|
2 local L = ReAction.L
|
flickerstreak@25
|
3 local _G = _G
|
flickerstreak@25
|
4 local CreateFrame = CreateFrame
|
flickerstreak@33
|
5 local floor = math.floor
|
flickerstreak@75
|
6 local fmod = math.fmod
|
flickerstreak@75
|
7 local format = string.format
|
flickerstreak@71
|
8 local SecureStateHeader_Refresh = SecureStateHeader_Refresh
|
flickerstreak@33
|
9
|
flickerstreak@33
|
10
|
flickerstreak@25
|
11 -- update ReAction revision if this file is newer
|
flickerstreak@33
|
12 local revision = tonumber(("$Revision$"):match("%d+"))
|
flickerstreak@25
|
13 if revision > ReAction.revision then
|
flickerstreak@52
|
14 ReAction.revision = revision
|
flickerstreak@25
|
15 end
|
flickerstreak@25
|
16
|
flickerstreak@75
|
17
|
flickerstreak@28
|
18 ------ BAR CLASS ------
|
flickerstreak@28
|
19 local Bar = { _classID = {} }
|
flickerstreak@25
|
20
|
flickerstreak@28
|
21 local function Constructor( self, name, config )
|
flickerstreak@25
|
22 if type(config) ~= "table" then
|
flickerstreak@28
|
23 error("ReAction.Bar: config table required")
|
flickerstreak@25
|
24 end
|
flickerstreak@75
|
25 config.width = config.width or 480
|
flickerstreak@75
|
26 config.height = config.height or 40
|
flickerstreak@75
|
27
|
flickerstreak@75
|
28 self.name, self.config = name, config
|
flickerstreak@75
|
29 self.buttons = setmetatable({},{__mode="k"})
|
flickerstreak@75
|
30 self.statedrivers = { }
|
flickerstreak@75
|
31 self.keybinds = { }
|
flickerstreak@25
|
32
|
flickerstreak@54
|
33 local parent = config.parent and (ReAction:GetBar(config.parent) or _G[config.parent]) or UIParent
|
flickerstreak@75
|
34 local f = CreateFrame("Button",name and format("ReAction-%s",name),parent,"SecureStateHeaderTemplate, SecureActionButtonTemplate")
|
flickerstreak@75
|
35
|
flickerstreak@75
|
36 -- The frame itself is read-only
|
flickerstreak@75
|
37 function self:GetFrame()
|
flickerstreak@75
|
38 return f
|
flickerstreak@75
|
39 end
|
flickerstreak@75
|
40
|
flickerstreak@75
|
41 -- The bar itself is also a Button derived from SecureActionButtonTemplate, so it has an OnClick handler
|
flickerstreak@75
|
42 -- which we can use as a virtual button for keybinds, which will send attribute-value changes to itself.
|
flickerstreak@75
|
43 -- However, we don't ever want the user to be able to click it directly.
|
flickerstreak@75
|
44 f:EnableMouse(false)
|
flickerstreak@75
|
45 f:SetAttribute("type","attribute")
|
flickerstreak@25
|
46 f:SetFrameStrata("MEDIUM")
|
flickerstreak@25
|
47 f:SetWidth(config.width)
|
flickerstreak@25
|
48 f:SetWidth(config.height)
|
flickerstreak@75
|
49 f:Show()
|
flickerstreak@25
|
50
|
flickerstreak@75
|
51 self:ApplyAnchor()
|
flickerstreak@63
|
52 ReAction.RegisterCallback(self, "OnConfigModeChanged")
|
flickerstreak@25
|
53 end
|
flickerstreak@25
|
54
|
flickerstreak@25
|
55 function Bar:Destroy()
|
flickerstreak@75
|
56 local f = self:GetFrame()
|
flickerstreak@25
|
57 f:UnregisterAllEvents()
|
flickerstreak@25
|
58 f:Hide()
|
flickerstreak@25
|
59 f:SetParent(UIParent)
|
flickerstreak@25
|
60 f:ClearAllPoints()
|
flickerstreak@63
|
61 ReAction.UnregisterAllCallbacks(self)
|
flickerstreak@75
|
62 for driver in pairs(self.statedrivers) do
|
flickerstreak@75
|
63 UnregisterStateDriver(f, driver)
|
flickerstreak@72
|
64 end
|
flickerstreak@25
|
65 self.labelString = nil
|
flickerstreak@25
|
66 self.controlFrame = nil
|
flickerstreak@25
|
67 self.config = nil
|
flickerstreak@25
|
68 end
|
flickerstreak@25
|
69
|
flickerstreak@63
|
70 function Bar:OnConfigModeChanged(event, mode)
|
flickerstreak@75
|
71 self:ShowControls(mode) -- Bar:ShowControls() defined in Overlay.lua
|
flickerstreak@25
|
72 end
|
flickerstreak@25
|
73
|
flickerstreak@25
|
74 function Bar:ApplyAnchor()
|
flickerstreak@75
|
75 local f, config = self:GetFrame(), self.config
|
flickerstreak@25
|
76 f:SetWidth(config.width)
|
flickerstreak@25
|
77 f:SetHeight(config.height)
|
flickerstreak@75
|
78 local point = config.point
|
flickerstreak@51
|
79 f:ClearAllPoints()
|
flickerstreak@75
|
80 if point then
|
flickerstreak@75
|
81 local anchor = f:GetParent()
|
flickerstreak@75
|
82 if config.anchor then
|
flickerstreak@75
|
83 local bar = ReAction:GetBar(config.anchor)
|
flickerstreak@52
|
84 if bar then
|
flickerstreak@75
|
85 anchor = bar:GetFrame()
|
flickerstreak@52
|
86 else
|
flickerstreak@75
|
87 anchor = _G[config.anchor]
|
flickerstreak@52
|
88 end
|
flickerstreak@25
|
89 end
|
flickerstreak@75
|
90 f:SetPoint(point, anchor or f:GetParent(), config.relpoint, config.x or 0, config.y or 0)
|
flickerstreak@25
|
91 else
|
flickerstreak@25
|
92 f:SetPoint("CENTER")
|
flickerstreak@25
|
93 end
|
flickerstreak@25
|
94 end
|
flickerstreak@25
|
95
|
flickerstreak@51
|
96 function Bar:SetAnchor(point, frame, relativePoint, x, y)
|
flickerstreak@51
|
97 local c = self.config
|
flickerstreak@75
|
98 c.point = point or c.point
|
flickerstreak@75
|
99 c.anchor = frame and frame:GetName() or c.anchor
|
flickerstreak@75
|
100 c.relpoint = relativePoint or c.relpoint
|
flickerstreak@51
|
101 c.x = x or c.x
|
flickerstreak@51
|
102 c.y = y or c.y
|
flickerstreak@51
|
103 self:ApplyAnchor()
|
flickerstreak@51
|
104 end
|
flickerstreak@51
|
105
|
flickerstreak@51
|
106 function Bar:GetAnchor()
|
flickerstreak@51
|
107 local c = self.config
|
flickerstreak@75
|
108 return (c.point or "CENTER"), (c.anchor or self:GetFrame():GetParent():GetName()), (c.relpoint or c.point or "CENTER"), (c.x or 0), (c.y or 0)
|
flickerstreak@25
|
109 end
|
flickerstreak@25
|
110
|
flickerstreak@25
|
111 function Bar:GetSize()
|
flickerstreak@75
|
112 local f = self:GetFrame()
|
flickerstreak@75
|
113 return f:GetWidth(), f:GetHeight()
|
flickerstreak@25
|
114 end
|
flickerstreak@25
|
115
|
flickerstreak@25
|
116 function Bar:SetSize(w,h)
|
flickerstreak@25
|
117 self.config.width = w
|
flickerstreak@25
|
118 self.config.height = h
|
flickerstreak@75
|
119 local f = self:GetFrame()
|
flickerstreak@75
|
120 f:SetWidth(w)
|
flickerstreak@75
|
121 f:SetHeight(h)
|
flickerstreak@25
|
122 end
|
flickerstreak@25
|
123
|
flickerstreak@25
|
124 function Bar:GetButtonSize()
|
flickerstreak@25
|
125 local w = self.config.btnWidth or 32
|
flickerstreak@25
|
126 local h = self.config.btnHeight or 32
|
flickerstreak@25
|
127 -- TODO: get from modules?
|
flickerstreak@25
|
128 return w,h
|
flickerstreak@25
|
129 end
|
flickerstreak@25
|
130
|
flickerstreak@25
|
131 function Bar:SetButtonSize(w,h)
|
flickerstreak@25
|
132 if w > 0 and h > 0 then
|
flickerstreak@25
|
133 self.config.btnWidth = w
|
flickerstreak@25
|
134 self.config.btnHeight = h
|
flickerstreak@25
|
135 end
|
flickerstreak@75
|
136 ReAction:RefreshBar(self)
|
flickerstreak@25
|
137 end
|
flickerstreak@25
|
138
|
flickerstreak@25
|
139 function Bar:GetButtonGrid()
|
flickerstreak@25
|
140 local cfg = self.config
|
flickerstreak@25
|
141 local r = cfg.btnRows or 1
|
flickerstreak@25
|
142 local c = cfg.btnColumns or 1
|
flickerstreak@25
|
143 local s = cfg.spacing or 4
|
flickerstreak@25
|
144 return r,c,s
|
flickerstreak@25
|
145 end
|
flickerstreak@25
|
146
|
flickerstreak@25
|
147 function Bar:SetButtonGrid(r,c,s)
|
flickerstreak@25
|
148 if r > 0 and c > 0 and s > 0 then
|
flickerstreak@25
|
149 local cfg = self.config
|
flickerstreak@25
|
150 cfg.btnRows = r
|
flickerstreak@25
|
151 cfg.btnColumns = c
|
flickerstreak@25
|
152 cfg.spacing = s
|
flickerstreak@25
|
153 end
|
flickerstreak@75
|
154 ReAction:RefreshBar(self)
|
flickerstreak@25
|
155 end
|
flickerstreak@25
|
156
|
flickerstreak@25
|
157 function Bar:GetName()
|
flickerstreak@25
|
158 return self.name
|
flickerstreak@25
|
159 end
|
flickerstreak@25
|
160
|
flickerstreak@75
|
161 -- only ReAction:RenameBar() should call this function
|
flickerstreak@33
|
162 function Bar:SetName(name)
|
flickerstreak@33
|
163 self.name = name
|
flickerstreak@75
|
164 -- controlLabelString is defined in Overlay.lua
|
flickerstreak@33
|
165 if self.controlLabelString then
|
flickerstreak@33
|
166 self.controlLabelString:SetText(self.name)
|
flickerstreak@33
|
167 end
|
flickerstreak@33
|
168 end
|
flickerstreak@33
|
169
|
flickerstreak@75
|
170 function Bar:AddButton(idx, button)
|
flickerstreak@75
|
171 self.buttons[button] = idx
|
flickerstreak@75
|
172 SecureStateHeader_Refresh(self:GetFrame())
|
flickerstreak@75
|
173 end
|
flickerstreak@75
|
174
|
flickerstreak@75
|
175 function Bar:RemoveButton(button)
|
flickerstreak@75
|
176 self.buttons[button] = nil
|
flickerstreak@75
|
177 end
|
flickerstreak@75
|
178
|
flickerstreak@75
|
179 function Bar:IterateButtons() -- iterator returns button, idx
|
flickerstreak@75
|
180 return pairs(self.buttons)
|
flickerstreak@75
|
181 end
|
flickerstreak@75
|
182
|
flickerstreak@75
|
183 function Bar:PlaceButton(button, baseW, baseH)
|
flickerstreak@75
|
184 local idx = self.buttons[button]
|
flickerstreak@75
|
185 if not idx then return end
|
flickerstreak@25
|
186 local r, c, s = self:GetButtonGrid()
|
flickerstreak@25
|
187 local bh, bw = self:GetButtonSize()
|
flickerstreak@75
|
188 local row, col = floor((idx-1)/c), fmod((idx-1),c) -- zero-based
|
flickerstreak@25
|
189 local x, y = col*bw + (col+0.5)*s, row*bh + (row+0.5)*s
|
flickerstreak@25
|
190 local scale = bw/baseW
|
flickerstreak@75
|
191 local f = button:GetFrame()
|
flickerstreak@25
|
192
|
flickerstreak@25
|
193 f:ClearAllPoints()
|
flickerstreak@25
|
194 f:SetPoint("TOPLEFT",x/scale,-y/scale)
|
flickerstreak@25
|
195 f:SetScale(scale)
|
flickerstreak@25
|
196 end
|
flickerstreak@25
|
197
|
flickerstreak@75
|
198 -- Creates (or updates) a named binding which binds a key press to a call to SetAttribute()
|
flickerstreak@75
|
199 -- pass a nil key to unbind
|
flickerstreak@75
|
200 function Bar:SetAttributeBinding( name, key, attribute, value )
|
flickerstreak@75
|
201 if not name then
|
flickerstreak@75
|
202 error("usage - Bar:SetAttributeBinding(name [, key, attribute, value]")
|
flickerstreak@75
|
203 end
|
flickerstreak@75
|
204 local f = self:GetFrame()
|
flickerstreak@71
|
205
|
flickerstreak@75
|
206 -- clear the old binding, if any
|
flickerstreak@75
|
207 if self.keybinds[name] then
|
flickerstreak@75
|
208 SetOverrideBinding(f, false, self.keybinds[name], nil)
|
flickerstreak@75
|
209 end
|
flickerstreak@75
|
210 if key then
|
flickerstreak@75
|
211 f:SetAttribute(format("attribute-name-%s",name), attribute)
|
flickerstreak@75
|
212 f:SetAttribute(format("attribute-value-%s",name), value)
|
flickerstreak@75
|
213 SetOverrideBindingClick(f, false, key, f:GetName(), name) -- binding name is the virtual mouse button
|
flickerstreak@75
|
214 end
|
flickerstreak@75
|
215 self.keybinds[name] = key
|
flickerstreak@68
|
216 end
|
flickerstreak@28
|
217
|
flickerstreak@75
|
218 -- Sets up a state driver 'name' for the bar, using the provided 'rule'
|
flickerstreak@75
|
219 -- Also sets attributes 'statemap-<name>-<key>'=<value> for each entry in the passed map
|
flickerstreak@75
|
220 -- if 'rule' is nil or an empty string, the driver is unregistered.
|
flickerstreak@75
|
221 function Bar:SetStateDriver( name, rule, map )
|
flickerstreak@75
|
222 local f = self:GetFrame()
|
flickerstreak@75
|
223 if rule and #rule > 0 then
|
flickerstreak@75
|
224 if map then
|
flickerstreak@75
|
225 for key, value in pairs(map) do
|
flickerstreak@75
|
226 f:SetAttribute( format("statemap-%s-%s",name,key), value )
|
flickerstreak@72
|
227 end
|
flickerstreak@72
|
228 end
|
flickerstreak@75
|
229 RegisterStateDriver(f, name, rule)
|
flickerstreak@75
|
230 self.statedrivers[name] = true
|
flickerstreak@75
|
231 elseif self.statedrivers[name] then
|
flickerstreak@75
|
232 UnregisterStateDriver(f, name)
|
flickerstreak@75
|
233 self.statedrivers[name] = nil
|
flickerstreak@72
|
234 end
|
flickerstreak@72
|
235 end
|
flickerstreak@72
|
236
|
flickerstreak@75
|
237 -- Set an attribute on the frame (or its buttons if 'doButtons' = true)
|
flickerstreak@75
|
238 -- Either or both 'map' and 'default' can be passed:
|
flickerstreak@75
|
239 -- - If 'map' is omitted, then 'default' is set to the attribute.
|
flickerstreak@75
|
240 -- - If 'map' is provided, then it is interpreted as an unordered
|
flickerstreak@75
|
241 -- table of the form { ["statename"] = ["value"] }, and will be
|
flickerstreak@75
|
242 -- converted into a SecureStateHeaderTemplate style state-parsed
|
flickerstreak@75
|
243 -- string, e.g. "<state1>:<value1>;<state2>:<value2>". If 'default'
|
flickerstreak@75
|
244 -- is also provided, then its value will be converted to a string
|
flickerstreak@75
|
245 -- and appended.
|
flickerstreak@75
|
246 function Bar:SetStateAttribute( attribute, map, default, doButtons )
|
flickerstreak@75
|
247 local value = default
|
flickerstreak@75
|
248 if map then
|
flickerstreak@75
|
249 local tmp = { }
|
flickerstreak@75
|
250 for state, value in pairs(map) do
|
flickerstreak@75
|
251 table.insert(tmp, format("%s:%s",tostring(state),tostring(value)))
|
flickerstreak@68
|
252 end
|
flickerstreak@75
|
253 if default then
|
flickerstreak@75
|
254 table.insert(tmp, tostring(default))
|
flickerstreak@75
|
255 end
|
flickerstreak@75
|
256 value = table.concat(tmp,";")
|
flickerstreak@68
|
257 end
|
flickerstreak@75
|
258 if doButtons then
|
flickerstreak@75
|
259 for b in pairs(self.buttons) do
|
flickerstreak@75
|
260 local f = b.GetFrame and b:GetFrame()
|
flickerstreak@75
|
261 if f then
|
flickerstreak@75
|
262 f:SetAttribute(attribute, value)
|
flickerstreak@71
|
263 end
|
flickerstreak@71
|
264 end
|
flickerstreak@75
|
265 else
|
flickerstreak@75
|
266 self:GetFrame():SetAttribute(attribute, value)
|
flickerstreak@71
|
267 end
|
flickerstreak@75
|
268 SecureStateHeader_Refresh(self:GetFrame())
|
flickerstreak@71
|
269 end
|
flickerstreak@71
|
270
|
flickerstreak@33
|
271
|
flickerstreak@28
|
272 ------ Export as a class-factory ------
|
flickerstreak@28
|
273 ReAction.Bar = {
|
flickerstreak@73
|
274 prototype = Bar,
|
flickerstreak@75
|
275 New = function(self, ...)
|
flickerstreak@28
|
276 local x = { }
|
flickerstreak@28
|
277 for k,v in pairs(Bar) do
|
flickerstreak@28
|
278 x[k] = v
|
flickerstreak@28
|
279 end
|
flickerstreak@28
|
280 Constructor(x, ...)
|
flickerstreak@28
|
281 return x
|
flickerstreak@28
|
282 end
|
flickerstreak@28
|
283 }
|