Mercurial > wow > reaction
comparison ReAction.lua @ 257:920d17851a93 stable
Merge 1.1 beta 4 to stable
author | Flick |
---|---|
date | Tue, 12 Apr 2011 16:06:31 -0700 |
parents | 47818b3938c9 |
children | 9e708a155ab9 |
comparison
equal
deleted
inserted
replaced
210:b2b105747466 | 257:920d17851a93 |
---|---|
1 local addonName, addonTable = ... | 1 local addonName, addonTable = ... |
2 local pcall = pcall | 2 local pcall = pcall |
3 local pairs = pairs | 3 local pairs = pairs |
4 local type = type | 4 local type = type |
5 local geterrorhandler = geterrorhandler | 5 local geterrorhandler = geterrorhandler |
6 local LKB = LibStub("LibKeyBound-1.0") | |
7 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction") | 6 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction") |
7 local LKB = LibStub("LibKeyBound-1.0",true) | |
8 if not LKB then | |
9 LoadAddOn("LibKeyBound-1.0") | |
10 LKB = LibStub("LibKeyBound-1.0") | |
11 end | |
8 | 12 |
9 ------ Utility ------ | 13 ------ Utility ------ |
10 local tcopy | 14 -- make a deep copy of a table |
11 do | 15 local function tcopy(x) |
12 function tcopy(x) | 16 if type(x) ~= "table" then |
13 if type(x) ~= "table" then | 17 return x |
14 return x | 18 end |
15 end | 19 local r = {} |
16 local r = {} | 20 for k,v in pairs(x) do |
17 for k,v in pairs(x) do | 21 r[k] = tcopy(v) |
18 r[k] = tcopy(v) | 22 end |
19 end | 23 return r |
20 return r | 24 end |
21 end | 25 |
22 end | 26 -- traverse a table tree by key list and fetch the result or first nil |
27 local function tfetch(t, ...) | |
28 for i = 1, select('#', ...) do | |
29 t = t and t[select(i, ...)] | |
30 end | |
31 return t | |
32 end | |
33 | |
34 -- traverse a table tree by key list and build tree as necessary | |
35 local function tbuild(t, ...) | |
36 for i = 1, select('#', ...) do | |
37 local key = select(i, ...) | |
38 if not t[key] then t[key] = { } end | |
39 t = t[key] | |
40 end | |
41 return t | |
42 end | |
43 | |
44 -- return a new array of keys of table 't', sorted by comparing | |
45 -- sub-fields (obtained via tfetch) of the table values | |
46 local function fieldsort( t, ... ) | |
47 local r = { } | |
48 for k in pairs(t) do | |
49 table.insert(r,k) | |
50 end | |
51 local path = { ... } | |
52 table.sort(r, function(lhs, rhs) | |
53 local olhs = tfetch(t[lhs], unpack(path)) or 0 | |
54 local orhs = tfetch(t[rhs], unpack(path)) or 0 | |
55 return olhs < orhs | |
56 end) | |
57 return r | |
58 end | |
59 | |
60 -- store in the addon table | |
61 addonTable.tcopy = tcopy | |
62 addonTable.tfetch = tfetch | |
63 addonTable.tbuild = tbuild | |
64 addonTable.fieldsort = fieldsort | |
23 | 65 |
24 ------ Core ------ | 66 ------ Core ------ |
25 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction", | 67 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction", |
26 "AceEvent-3.0" | 68 "AceEvent-3.0" |
27 ) | 69 ) |
28 addonTable.ReAction = ReAction | 70 addonTable.ReAction = ReAction |
29 ReAction.version = "1.1" | 71 ReAction.version = GetAddOnMetadata("ReAction","Version") |
30 ReAction.L = L | 72 ReAction.L = L |
31 ReAction.LKB = LKB | 73 ReAction.LKB = LKB |
32 | 74 |
75 | |
76 ReAction.barTypes = { } | |
33 | 77 |
34 ------ Handlers ------ | 78 ------ Handlers ------ |
35 function ReAction:OnInitialize() | 79 function ReAction:OnInitialize() |
36 self.db = LibStub("AceDB-3.0"):New("ReAction_DB", | 80 self.db = LibStub("AceDB-3.0"):New("ReAction_DB", |
37 { | 81 self.defaultProfile, |
38 profile = { | |
39 bars = { }, | |
40 defaultBar = { }, | |
41 } | |
42 }, | |
43 true -- use global 'Default' (locale-specific) | 82 true -- use global 'Default' (locale-specific) |
44 ) | 83 ) |
45 | 84 |
85 self:UpgradeProfile() | |
86 | |
46 self.bars = { } | 87 self.bars = { } |
47 self.defaultBarConfig = { } | 88 |
89 self.LBF = LibStub("LibButtonFacade",true) | |
90 if self.LBF then | |
91 self.LBF:RegisterSkinCallback("ReAction", self.OnSkinChanged, self) | |
92 end | |
93 | |
94 -- It's fairly normal to use the Blizzard vehicle bar, and to have | |
95 -- your regular buttons in the same location. If you do this, and don't | |
96 -- bother to hide your buttons, they'll obscure some parts of the vehicle bar. | |
97 VehicleMenuBar:SetFrameLevel(VehicleMenuBar:GetFrameLevel()+3) | |
48 | 98 |
49 self.callbacks = LibStub("CallbackHandler-1.0"):New(self) | 99 self.callbacks = LibStub("CallbackHandler-1.0"):New(self) |
100 | |
50 LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED") | 101 LKB.RegisterCallback(self,"LIBKEYBOUND_ENABLED") |
51 LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED") | 102 LKB.RegisterCallback(self,"LIBKEYBOUND_DISABLED") |
52 LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") | 103 LKB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") |
104 | |
105 -- see Profile.lua for these callback implementations | |
106 self.db.RegisterCallback(self,"OnProfileChanged") | |
107 self.db.RegisterCallback(self,"OnProfileCopied","OnProfileChanged") | |
108 self.db.RegisterCallback(self,"OnNewProfile") | |
109 self.db.RegisterCallback(self,"OnProfileReset", "OnNewProfile") | |
110 | |
53 self:RegisterEvent("PLAYER_REGEN_DISABLED") | 111 self:RegisterEvent("PLAYER_REGEN_DISABLED") |
112 self:RegisterEvent("UPDATE_SHAPESHIFT_FORMS") | |
113 | |
54 self:InitializeOptions() | 114 self:InitializeOptions() |
55 end | 115 end |
56 | 116 |
57 function ReAction:OnEnable() | 117 function ReAction:OnEnable() |
58 self:InitializeBars() | 118 self:InitializeBars() |
119 self:UPDATE_SHAPESHIFT_FORMS() -- it doesn't fire on a /reloadui | |
59 end | 120 end |
60 | 121 |
61 function ReAction:OnDisable() | 122 function ReAction:OnDisable() |
62 self:TearDownBars() | 123 self:TearDownBars() |
63 end | 124 end |
69 self:SetKeybindMode(false) | 130 self:SetKeybindMode(false) |
70 self:CloseEditor() | 131 self:CloseEditor() |
71 end | 132 end |
72 end | 133 end |
73 | 134 |
135 function ReAction:UPDATE_SHAPESHIFT_FORMS() | |
136 -- Re-parse the rules table according to the new form list. | |
137 -- This happens both at initial login (after PLAYER_ENTERING_WORLD) | |
138 -- as well as when gaining new abilities. | |
139 self.Bar:InitRuleFormats() | |
140 for _, bar in self:IterateBars() do | |
141 bar:ApplyStates() | |
142 end | |
143 end | |
144 | |
74 function ReAction:LIBKEYBOUND_ENABLED( evt ) | 145 function ReAction:LIBKEYBOUND_ENABLED( evt ) |
75 self:SetKeybindMode(true) | 146 self:SetKeybindMode(true) |
76 end | 147 end |
77 | 148 |
78 function ReAction:LIBKEYBOUND_DISABLED( evt ) | 149 function ReAction:LIBKEYBOUND_DISABLED( evt ) |
79 return self:SetKeybindMode(false) | 150 return self:SetKeybindMode(false) |
151 end | |
152 | |
153 function ReAction:OnSkinChanged( skinID, gloss, backdrop, group, button, colors ) | |
154 if group == nil then | |
155 -- don't store global | |
156 else | |
157 -- 'group' is the bar-name | |
158 local bar = self:GetBar(group) | |
159 if bar then | |
160 local c = bar:GetConfig().ButtonFacade | |
161 if c then | |
162 c.skinID = skinID | |
163 c.gloss = gloss | |
164 c.backdrop = backdrop | |
165 c.colors = colors | |
166 end | |
167 end | |
168 end | |
80 end | 169 end |
81 | 170 |
82 | 171 |
83 ------ Methods ------ | 172 ------ Methods ------ |
84 | 173 |
108 -- (1) ReAction:CreateBar(name, [cfgTable]) | 197 -- (1) ReAction:CreateBar(name, [cfgTable]) |
109 -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing]) | 198 -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing]) |
110 function ReAction:CreateBar(name, config, ...) | 199 function ReAction:CreateBar(name, config, ...) |
111 local profile = self.db.profile | 200 local profile = self.db.profile |
112 | 201 |
113 if name then | 202 name = tostring(name) |
114 if self.bars[name] then | 203 if not name or name == "" then |
115 self:UserError(format(L["ReAction: name '%s' already in use"],name)) | 204 error("ReAction:CreateBar() - bar name string required") |
116 return nil | 205 elseif self.bars[name] then |
117 end | 206 self:UserError(format(L["ReAction: name '%s' already in use"],name)) |
118 else | 207 return nil |
119 local prefix = L["Bar "] | 208 end |
120 local i = 1 | 209 |
121 repeat | 210 local class |
122 name = prefix..i | |
123 i = i + 1 | |
124 until self.bars[name] == nil | |
125 end | |
126 | |
127 if type(config) == "string" then | 211 if type(config) == "string" then |
128 config = self.defaultBarConfig[config] | 212 class = self.barTypes[config] |
129 if not config then | 213 if not class then |
130 error(("ReAction:CreateBar() - unknown bar type '%s'"):format(tostring(select(1,...)))) | 214 error(("ReAction:CreateBar() - unknown bar type '%s'"):format(config)) |
131 end | 215 end |
132 config = tcopy(config) | 216 config = tcopy(class:GetDefaultBarConfig()) |
133 config.btnRows = select(1,...) or config.btnRows or 1 | 217 config.btnRows = select(1,...) or config.btnRows |
134 config.btnColumns = select(2,...) or config.btnColumns or 12 | 218 config.btnColumns = select(2,...) or config.btnColumns |
135 config.btnWidth = select(3,...) or config.btnWidth or 36 | 219 config.btnWidth = select(3,...) or config.btnWidth |
136 config.btnHeight = select(3,...) or config.btnHeight or 36 | 220 config.btnHeight = select(3,...) or config.btnHeight |
137 config.spacing = select(4,...) or config.spacing or 3 | 221 config.spacing = select(4,...) or config.spacing |
138 config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1 | 222 config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1 |
139 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1 | 223 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1 |
140 config.anchor = config.anchor or "UIParent" | 224 config.anchor = config.anchor or "UIParent" |
141 config.point = config.point or "BOTTOM" | 225 config.point = config.point or "BOTTOM" |
142 config.relpoint = config.relpoint or "BOTTOM" | 226 config.relpoint = config.relpoint or "BOTTOM" |
143 config.y = config.y or 200 | 227 config.y = config.y or 200 |
144 config.x = config.x or 0 | 228 config.x = config.x or 0 |
145 end | 229 else |
146 config = config or profile.bars[name] or tcopy(profile.defaultBar) | 230 config = config or profile.bars[name] or { } |
231 if not config or not config.type or not self.barTypes[config.type] then | |
232 error(("ReAction: Unable to construct/fetch config table for bar '%s'"):format(name)) | |
233 end | |
234 class = self.barTypes[config.type] | |
235 end | |
147 | 236 |
148 profile.bars[name] = config | 237 profile.bars[name] = config |
149 local bar = self.Bar:New( name, config ) -- ReAction.Bar defined in Bar.lua | 238 local bar = self.Bar:New( name, config, class ) -- ReAction.Bar defined in Bar.lua |
150 self.bars[name] = bar | 239 self.bars[name] = bar |
151 self.callbacks:Fire("OnCreateBar", bar, name) | 240 self.callbacks:Fire("OnCreateBar", bar, name) |
152 if self.configMode then | 241 if self.configMode then |
153 bar:ShowControls(true) | 242 bar:ShowControls(true) |
154 end | 243 end |
163 self.callbacks:Fire("OnDestroyBar", bar, name) | 252 self.callbacks:Fire("OnDestroyBar", bar, name) |
164 bar:Destroy() | 253 bar:Destroy() |
165 end | 254 end |
166 end | 255 end |
167 | 256 |
168 function ReAction:RefreshBar(x) | |
169 local bar, name = self:GetBar(x) | |
170 if bar and name then | |
171 self.callbacks:Fire("OnRefreshBar", bar, name) | |
172 end | |
173 end | |
174 | |
175 function ReAction:InitializeBars() | 257 function ReAction:InitializeBars() |
176 if not self.barsInitialized then | 258 if not self.barsInitialized then |
259 self:ManageBlizzardBars() | |
260 | |
177 for name, config in pairs(self.db.profile.bars) do | 261 for name, config in pairs(self.db.profile.bars) do |
178 if config then | 262 if config then |
179 self:CreateBar(name, config) | 263 self:CreateBar(name, config) |
180 end | 264 end |
181 end | 265 end |
182 -- re-anchor and refresh in case anchor order does not match init order | 266 -- re-anchor in case anchor order does not match init order |
183 for name, bar in pairs(self.bars) do | 267 for name, bar in pairs(self.bars) do |
184 bar:ApplyAnchor() | 268 bar:ApplyAnchor() |
185 self.callbacks:Fire("OnRefreshBar", bar, name) | |
186 end | 269 end |
187 self.barsInitialized = true | 270 self.barsInitialized = true |
188 end | 271 end |
189 end | 272 end |
190 | 273 |
224 end | 307 end |
225 | 308 |
226 function ReAction:EraseBar(x) | 309 function ReAction:EraseBar(x) |
227 local bar, name = self:GetBar(x) | 310 local bar, name = self:GetBar(x) |
228 if bar and name then | 311 if bar and name then |
229 self.callbacks:Fire("OnEraseBar", bar, name) | |
230 self:DestroyBar(bar) | 312 self:DestroyBar(bar) |
231 self.db.profile.bars[name] = nil | 313 self.db.profile.bars[name] = nil |
232 end | 314 end |
233 end | 315 end |
234 | 316 |
235 function ReAction:RegisterBarType( name, config, isDefaultChoice ) | 317 local blizzFrames = { |
236 self.defaultBarConfig[name] = config | 318 MainMenuBar, |
237 if isDefaultChoice then | 319 MultiBarLeft, |
238 self.defaultBarConfigChoice = name | 320 MultiBarRight, |
239 end | 321 MultiBarBottomLeft, |
240 self:RefreshEditor() | 322 MultiBarBottomRight, |
241 end | 323 } |
242 | 324 |
243 function ReAction:UnregisterBarType( name ) | 325 local hideFrame = CreateFrame("Frame") |
244 self.defaultBarConfig[name] = nil | 326 hideFrame:Hide() |
245 if self.defaultBarConfigChoice == name then | 327 local hiddenParents = { } |
246 self.defaultBarConfigChoice = nil | 328 local function ManageBlizzFrame(f, hide) |
247 end | 329 if hide and not hiddenParents[f] then |
248 self:RefreshEditor() | 330 hiddenParents[f] = f:GetParent() |
331 f:SetParent(hideFrame) | |
332 elseif not hide and hiddenParents[f] then | |
333 f:SetParent(hiddenParents[f]) | |
334 hiddenParents[f] = nil | |
335 if f:IsShown() then | |
336 f:Show() -- refresh | |
337 end | |
338 end | |
339 end | |
340 | |
341 function ReAction:ManageBlizzardBars() | |
342 for _, f in pairs(blizzFrames) do | |
343 ManageBlizzFrame(f, self.db.profile.options.hideBlizzardBars) | |
344 end | |
345 ManageBlizzFrame(VehicleMenuBar, self.db.profile.options.hideBlizzardVehicleBar) | |
346 end | |
347 | |
348 function ReAction:RegisterBarType( class, isDefault ) | |
349 local name = class:GetButtonTypeID() | |
350 self.barTypes[name] = class | |
351 if isDefault then | |
352 self.defaultBarType = name | |
353 end | |
249 end | 354 end |
250 | 355 |
251 function ReAction:IterateBarTypes() | 356 function ReAction:IterateBarTypes() |
252 return pairs(self.defaultBarConfig) | 357 return pairs(self.barTypes) |
253 end | 358 end |
254 | 359 |
255 function ReAction:GetBarTypeConfig(name) | 360 function ReAction:GetDefaultBarConfig(barType) |
256 if name then | 361 if barType and self.barTypes[barType] then |
257 return self.defaultBarConfig[name] | 362 return self.barTypes[barType]:GetDefaultBarConfig() |
258 end | 363 end |
259 end | 364 end |
260 | 365 |
261 function ReAction:GetBarTypeOptions( fill ) | 366 function ReAction:GetBarTypeOptions( fill ) |
262 fill = fill or { } | 367 fill = fill or { } |
265 end | 370 end |
266 return fill | 371 return fill |
267 end | 372 end |
268 | 373 |
269 function ReAction:GetDefaultBarType() | 374 function ReAction:GetDefaultBarType() |
270 return self.defaultBarConfigChoice | 375 return self.defaultBarType |
271 end | 376 end |
272 | 377 |
273 function ReAction:SetConfigMode( mode ) | 378 function ReAction:SetConfigMode( mode ) |
274 if mode ~= self.configMode then | 379 if mode ~= self.configMode then |
275 if mode then | 380 if mode then |
300 end | 405 end |
301 | 406 |
302 function ReAction:GetKeybindMode( mode ) | 407 function ReAction:GetKeybindMode( mode ) |
303 return self.kbMode | 408 return self.kbMode |
304 end | 409 end |
410 | |
411 | |
412 -- ConfigMode support | |
413 CONFIGMODE_CALLBACKS = CONFIGMODE_CALLBACKS or {} | |
414 | |
415 function CONFIGMODE_CALLBACKS.ReAction( action, mode ) | |
416 if action == "ON" then | |
417 ReAction:SetConfigMode(true) | |
418 elseif action == "OFF" then | |
419 ReAction:SetConfigMode(false) | |
420 elseif action == "LISTMODES" then | |
421 -- no modes | |
422 end | |
423 end | |
424 |