annotate ReAction.lua @ 81:57f8151ea0f0

- Fixed some snafus with creating bars - Added support for opening the bar editor to a particular path - Creating bars/states now selects the new bar/state in the config editor - moved Bar:SetStateAttribute() back to working optionally on buttons rather than buttonFrame container
author Flick <flickerstreak@gmail.com>
date Wed, 25 Jun 2008 21:07:18 +0000
parents da8ba8783924
children fc83b3f5b322
rev   line source
flickerstreak@63 1 --[[
flickerstreak@63 2 ReAction.lua
flickerstreak@63 3
flickerstreak@63 4 The ReAction core manages 4 collections:
flickerstreak@63 5 - modules (via AceAddon)
flickerstreak@63 6 - bars
flickerstreak@63 7 - options
flickerstreak@63 8 - bar-type constructors
flickerstreak@63 9
flickerstreak@63 10 and publishes events when those collections change. It also implements a single property, 'config mode',
flickerstreak@63 11 and has a couple convenience methods which drill down to particular modules.
flickerstreak@63 12
flickerstreak@63 13 Most of the "real work" of the addon happens in Bar.lua and the various modules.
flickerstreak@63 14
flickerstreak@63 15 Events (with handler arguments):
flickerstreak@63 16 --------------------------------
flickerstreak@63 17 "OnCreateBar" (bar, name) : after a bar object is created
flickerstreak@63 18 "OnDestroyBar" (bar, name) : before a bar object is destroyed
flickerstreak@63 19 "OnEraseBar" (bar, name) : before a bar config is removed from the profile db
flickerstreak@63 20 "OnRenameBar" (bar, oldname, newname) : after a bar is renamed
flickerstreak@63 21 "OnRefreshBar" (bar, name) : after a bar's state has been updated
flickerstreak@63 22 "OnOptionsRefreshed" () : after the global options tree is refreshed
flickerstreak@63 23 "OnConfigModeChanged" (mode) : after the config mode is changed
flickerstreak@63 24 "OnBarOptionGeneratorRegistered" (module, function) : after an options generator function is registered
flickerstreak@63 25
flickerstreak@63 26 ReAction is also an AceAddon-3.0 and contains an AceDB-3.0, which in turn publish more events.
flickerstreak@63 27 ]]--
flickerstreak@63 28 local version = GetAddOnMetadata("ReAction","Version")
flickerstreak@27 29
flickerstreak@27 30 ------ CORE ------
flickerstreak@30 31 local ReAction = LibStub("AceAddon-3.0"):NewAddon( "ReAction",
flickerstreak@33 32 "AceConsole-3.0",
flickerstreak@33 33 "AceEvent-3.0"
flickerstreak@30 34 )
flickerstreak@33 35 ReAction.revision = tonumber(("$Revision$"):match("%d+"))
flickerstreak@27 36
flickerstreak@28 37 ------ GLOBALS ------
flickerstreak@28 38 _G["ReAction"] = ReAction
flickerstreak@27 39
flickerstreak@28 40 ------ DEBUGGING ------
flickerstreak@25 41 ReAction.debug = true
flickerstreak@36 42 local dbprint
flickerstreak@25 43 if ReAction.debug then
flickerstreak@36 44 dbprint = function(msg)
flickerstreak@25 45 DEFAULT_CHAT_FRAME:AddMessage(msg)
flickerstreak@25 46 end
flickerstreak@25 47 else
flickerstreak@36 48 dbprint = function() end
flickerstreak@25 49 end
flickerstreak@36 50 ReAction.dbprint = dbprint
flickerstreak@25 51
flickerstreak@33 52 ------ LIBRARIES ------
flickerstreak@63 53 local callbacks = LibStub("CallbackHandler-1.0"):New(ReAction)
flickerstreak@33 54 local L = LibStub("AceLocale-3.0"):GetLocale("ReAction")
flickerstreak@33 55 ReAction.L = L
flickerstreak@33 56
flickerstreak@28 57 ------ PRIVATE ------
flickerstreak@63 58 local private = { }
flickerstreak@63 59 local bars = {}
flickerstreak@63 60 local defaultBarConfig = {}
flickerstreak@63 61 local barOptionGenerators = { }
flickerstreak@63 62 local options = {
flickerstreak@63 63 type = "group",
flickerstreak@63 64 name = "ReAction",
flickerstreak@63 65 childGroups = "tab",
flickerstreak@63 66 args = {
flickerstreak@63 67 _desc = {
flickerstreak@63 68 type = "description",
flickerstreak@63 69 name = L["Customizable replacement for Blizzard's Action Bars"],
flickerstreak@63 70 order = 1,
flickerstreak@63 71 },
flickerstreak@63 72 global = {
flickerstreak@63 73 type = "group",
flickerstreak@63 74 name = L["Global Settings"],
flickerstreak@63 75 desc = L["Global configuration settings"],
flickerstreak@63 76 args = {
flickerstreak@63 77 unlock = {
flickerstreak@63 78 type = "toggle",
flickerstreak@63 79 name = L["Unlock Bars"],
flickerstreak@63 80 desc = L["Unlock bars for dragging and resizing with the mouse"],
flickerstreak@63 81 handler = ReAction,
flickerstreak@63 82 get = "GetConfigMode",
flickerstreak@63 83 set = function(info, value) ReAction:SetConfigMode(value) end,
flickerstreak@63 84 disabled = InCombatLockdown,
flickerstreak@63 85 order = 1
flickerstreak@63 86 },
flickerstreak@63 87 },
flickerstreak@63 88 plugins = { },
flickerstreak@63 89 order = 2,
flickerstreak@63 90 },
flickerstreak@63 91 module = {
flickerstreak@63 92 type = "group",
flickerstreak@63 93 childGroups = "select",
flickerstreak@63 94 name = L["Module Settings"],
flickerstreak@63 95 desc = L["Configuration settings for each module"],
flickerstreak@63 96 args = { },
flickerstreak@63 97 plugins = { },
flickerstreak@63 98 order = 3,
flickerstreak@63 99 },
flickerstreak@63 100 },
flickerstreak@63 101 plugins = { }
flickerstreak@63 102 }
flickerstreak@63 103 ReAction.options = options
flickerstreak@63 104
flickerstreak@63 105 local SelectBar, DestroyBar, InitializeBars, TearDownBars, DeepCopy, CallModuleMethod, SlashHandler
flickerstreak@28 106 do
flickerstreak@28 107 local pcall = pcall
flickerstreak@28 108 local geterrorhandler = geterrorhandler
flickerstreak@63 109 local self = ReAction
flickerstreak@63 110 local inited = false
flickerstreak@28 111
flickerstreak@63 112 function SelectBar(x)
flickerstreak@28 113 local bar, name
flickerstreak@28 114 if type(x) == "string" then
flickerstreak@28 115 name = x
flickerstreak@63 116 bar = self:GetBar(name)
flickerstreak@50 117 else
flickerstreak@63 118 for k,v in pairs(bars) do
flickerstreak@50 119 if v == x then
flickerstreak@28 120 name = k
flickerstreak@50 121 bar = x
flickerstreak@28 122 end
flickerstreak@28 123 end
flickerstreak@28 124 end
flickerstreak@28 125 return bar, name
flickerstreak@28 126 end
flickerstreak@28 127
flickerstreak@63 128 function DestroyBar(x)
flickerstreak@28 129 local bar, name = SelectBar(x)
flickerstreak@63 130 if bar and name then
flickerstreak@63 131 bars[name] = nil
flickerstreak@63 132 callbacks:Fire("OnDestroyBar", bar, name)
flickerstreak@28 133 bar:Destroy()
flickerstreak@28 134 end
flickerstreak@28 135 end
flickerstreak@28 136
flickerstreak@63 137 function InitializeBars()
flickerstreak@63 138 if not inited then
flickerstreak@63 139 for name, config in pairs(self.db.profile.bars) do
flickerstreak@28 140 if config then
flickerstreak@63 141 self:CreateBar(name, config)
flickerstreak@28 142 end
flickerstreak@28 143 end
flickerstreak@63 144 -- re-anchor in case anchor order does not match init order
flickerstreak@63 145 for name, bar in pairs(bars) do
flickerstreak@63 146 bar:ApplyAnchor()
flickerstreak@63 147 end
flickerstreak@63 148 inited = true
flickerstreak@28 149 end
flickerstreak@28 150 end
flickerstreak@28 151
flickerstreak@63 152 function TearDownBars()
flickerstreak@63 153 for name, bar in pairs(bars) do
flickerstreak@28 154 if bar then
flickerstreak@63 155 bars[name] = DestroyBar(bar)
flickerstreak@28 156 end
flickerstreak@28 157 end
flickerstreak@63 158 inited = false
flickerstreak@28 159 end
flickerstreak@28 160
flickerstreak@63 161 function DeepCopy(x)
flickerstreak@28 162 if type(x) ~= "table" then
flickerstreak@28 163 return x
flickerstreak@28 164 end
flickerstreak@28 165 local r = {}
flickerstreak@28 166 for k,v in pairs(x) do
flickerstreak@28 167 r[k] = DeepCopy(v)
flickerstreak@28 168 end
flickerstreak@28 169 return r
flickerstreak@28 170 end
flickerstreak@28 171
flickerstreak@63 172 function CallModuleMethod(modulename, method, ...)
flickerstreak@63 173 local m = self:GetModule(modulename,true)
flickerstreak@63 174 if not m then
flickerstreak@63 175 LoadAddOn(("ReAction_%s"):format(modulename))
flickerstreak@63 176 m = self:GetModule(modulename,true)
flickerstreak@63 177 if m then
flickerstreak@63 178 dbprint(("succesfully loaded LOD module: %s"):format(modulename))
flickerstreak@28 179 end
flickerstreak@28 180 end
flickerstreak@63 181 if m then
flickerstreak@63 182 if type(m) == "table" and type(m[method]) == "function" then
flickerstreak@63 183 m[method](m,...)
flickerstreak@63 184 else
flickerstreak@63 185 dbprint(("Bad call '%s' to %s module"):format(tostring(method),modulename));
flickerstreak@63 186 end
flickerstreak@63 187 else
flickerstreak@63 188 self:Print(("Module '%s' not found"):format(tostring(modulename)))
flickerstreak@63 189 end
flickerstreak@28 190 end
flickerstreak@28 191
flickerstreak@63 192 function SlashHandler(option)
flickerstreak@30 193 if option == "config" then
flickerstreak@63 194 self:ShowConfig()
flickerstreak@58 195 elseif option == "edit" then
flickerstreak@63 196 self:ShowEditor()
flickerstreak@50 197 elseif option == "unlock" then
flickerstreak@63 198 self:SetConfigMode(true)
flickerstreak@50 199 elseif option == "lock" then
flickerstreak@63 200 self:SetConfigMode(false)
flickerstreak@30 201 else
flickerstreak@63 202 self:Print(("%3.1f.%d"):format(version,self.revision))
flickerstreak@63 203 self:Print("/rxn config")
flickerstreak@63 204 self:Print("/rxn edit")
flickerstreak@63 205 self:Print("/rxn lock")
flickerstreak@63 206 self:Print("/rxn unlock")
flickerstreak@30 207 end
flickerstreak@30 208 end
flickerstreak@28 209 end
flickerstreak@28 210
flickerstreak@28 211
flickerstreak@28 212 ------ HANDLERS ------
flickerstreak@28 213 function ReAction:OnInitialize()
flickerstreak@28 214 self.db = LibStub("AceDB-3.0"):New("ReAction_DB",
flickerstreak@28 215 {
flickerstreak@28 216 profile = {
flickerstreak@28 217 bars = { },
flickerstreak@28 218 defaultBar = { }
flickerstreak@28 219 }
flickerstreak@28 220 }
flickerstreak@28 221 -- default profile is character-specific
flickerstreak@28 222 )
flickerstreak@28 223 self.db.RegisterCallback(self,"OnProfileChanged")
flickerstreak@43 224 self.db.RegisterCallback(self,"OnProfileReset","OnProfileChanged")
flickerstreak@63 225
flickerstreak@63 226 options.args.profile = LibStub("AceDBOptions-3.0"):GetOptionsTable(self.db)
flickerstreak@63 227
flickerstreak@30 228 self:RegisterChatCommand("reaction", SlashHandler)
flickerstreak@30 229 self:RegisterChatCommand("rxn", SlashHandler)
flickerstreak@33 230 self:RegisterEvent("PLAYER_REGEN_DISABLED")
flickerstreak@28 231 end
flickerstreak@28 232
flickerstreak@28 233 function ReAction:OnEnable()
flickerstreak@28 234 InitializeBars()
flickerstreak@28 235 end
flickerstreak@28 236
flickerstreak@28 237 function ReAction:OnDisable()
flickerstreak@28 238 TearDownBars()
flickerstreak@28 239 end
flickerstreak@28 240
flickerstreak@28 241 function ReAction:OnProfileChanged()
flickerstreak@33 242 TearDownBars()
flickerstreak@33 243 InitializeBars()
flickerstreak@28 244 end
flickerstreak@28 245
flickerstreak@33 246 function ReAction:PLAYER_REGEN_DISABLED()
flickerstreak@63 247 if private.configMode == true then
flickerstreak@63 248 self:UserError(L["ReAction config mode disabled during combat."])
flickerstreak@33 249 self:SetConfigMode(false)
flickerstreak@33 250 end
flickerstreak@33 251 end
flickerstreak@33 252
flickerstreak@33 253
flickerstreak@28 254
flickerstreak@28 255 ------ API ------
flickerstreak@77 256 function ReAction:UpdateRevision(str)
flickerstreak@77 257 local revision = tonumber(str:match("%d+"))
flickerstreak@77 258 if revision and revision > ReAction.revision then
flickerstreak@77 259 ReAction.revision = revision
flickerstreak@77 260 end
flickerstreak@77 261 end
flickerstreak@77 262
flickerstreak@61 263 function ReAction:UserError(msg)
flickerstreak@61 264 -- any user errors should be flashed to the UIErrorsFrame
flickerstreak@61 265 UIErrorsFrame:AddMessage(msg)
flickerstreak@61 266 end
flickerstreak@61 267
flickerstreak@63 268 -- usage:
flickerstreak@63 269 -- (1) ReAction:CreateBar(name, cfgTable)
flickerstreak@63 270 -- (2) ReAction:CreateBar(name, "barType", [nRows], [nCols], [btnSize], [btnSpacing])
flickerstreak@48 271 function ReAction:CreateBar(name, ...)
flickerstreak@48 272 local config = select(1,...)
flickerstreak@48 273 if config and type(config) ~= "table" then
flickerstreak@48 274 bartype = select(1,...)
flickerstreak@48 275 if type(bartype) ~= "string" then
flickerstreak@48 276 error("ReAction:CreateBar() - first argument must be a config table or a default config type string")
flickerstreak@48 277 end
flickerstreak@63 278 config = defaultBarConfig[bartype]
flickerstreak@48 279 if not config then
flickerstreak@48 280 error(("ReAction:CreateBar() - unknown bar type '%s'"):format(bartype))
flickerstreak@48 281 end
flickerstreak@48 282 config = DeepCopy(config)
flickerstreak@48 283 config.btnRows = select(2,...) or config.btnRows or 1
flickerstreak@48 284 config.btnColumns = select(3,...) or config.btnColumns or 12
flickerstreak@48 285 config.btnWidth = select(4,...) or config.btnWidth or 36
flickerstreak@48 286 config.btnHeight = select(4,...) or config.btnHeight or 36
flickerstreak@48 287 config.spacing = select(5,...) or config.spacing or 3
flickerstreak@48 288 config.width = config.width or config.btnColumns*(config.btnWidth + config.spacing) + 1
flickerstreak@48 289 config.height = config.height or config.btnRows*(config.btnHeight + config.spacing) + 1
flickerstreak@81 290 config.anchor = config.anchor or "UIParent"
flickerstreak@81 291 config.point = config.point or "BOTTOM"
flickerstreak@81 292 config.relpoint = config.relpoint or "BOTTOM"
flickerstreak@48 293 config.y = config.y or 200
flickerstreak@48 294 config.x = config.x or 0
flickerstreak@48 295 end
flickerstreak@28 296 local profile = self.db.profile
flickerstreak@48 297 config = config or DeepCopy(profile.defaultBar)
flickerstreak@28 298 prefix = prefix or L["Bar "]
flickerstreak@28 299 if not name then
flickerstreak@28 300 i = 1
flickerstreak@28 301 repeat
flickerstreak@28 302 name = prefix..i
flickerstreak@28 303 i = i + 1
flickerstreak@63 304 until bars[name] == nil
flickerstreak@28 305 end
flickerstreak@48 306 profile.bars[name] = profile.bars[name] or config
flickerstreak@75 307 local bar = self.Bar:New( name, profile.bars[name] ) -- ReAction.Bar defined in Bar.lua
flickerstreak@63 308 bars[name] = bar
flickerstreak@63 309 callbacks:Fire("OnCreateBar", bar, name)
flickerstreak@63 310 if private.configMode then
flickerstreak@33 311 bar:ShowControls(true)
flickerstreak@33 312 end
flickerstreak@33 313
flickerstreak@28 314 return bar
flickerstreak@28 315 end
flickerstreak@28 316
flickerstreak@28 317 function ReAction:EraseBar(x)
flickerstreak@28 318 local bar, name = SelectBar(x)
flickerstreak@63 319 if bar and name then
flickerstreak@63 320 callbacks:Fire("OnEraseBar", bar, name)
flickerstreak@28 321 DestroyBar(bar)
flickerstreak@28 322 self.db.profile.bars[name] = nil
flickerstreak@28 323 end
flickerstreak@28 324 end
flickerstreak@28 325
flickerstreak@28 326 function ReAction:GetBar(name)
flickerstreak@63 327 return bars[name]
flickerstreak@63 328 end
flickerstreak@63 329
flickerstreak@63 330 function ReAction:IterateBars()
flickerstreak@63 331 return pairs(bars)
flickerstreak@28 332 end
flickerstreak@28 333
flickerstreak@28 334 function ReAction:RenameBar(x, newname)
flickerstreak@28 335 local bar, name = SelectBar(x)
flickerstreak@63 336 if type(newname) ~= "string" then
flickerstreak@63 337 error("ReAction:RenameBar() - second argument must be a string")
flickerstreak@63 338 end
flickerstreak@63 339 if bar and name and #newname > 0 then
flickerstreak@63 340 if bars[newname] then
flickerstreak@63 341 self:UserError(("%s ('%s')"):format(L["ReAction: name already in use"],newname))
flickerstreak@47 342 else
flickerstreak@63 343 bars[newname], bars[name] = bars[name], nil
flickerstreak@47 344 bar:SetName(newname or "")
flickerstreak@47 345 local cfg = self.db.profile.bars
flickerstreak@47 346 cfg[newname], cfg[name] = cfg[name], nil
flickerstreak@63 347 callbacks:Fire("OnRenameBar", bar, name, newname)
flickerstreak@28 348 end
flickerstreak@28 349 end
flickerstreak@28 350 end
flickerstreak@28 351
flickerstreak@63 352 function ReAction:RefreshBar(x)
flickerstreak@63 353 local bar, name = SelectBar(x)
flickerstreak@63 354 if bar and name then
flickerstreak@63 355 callbacks:Fire("OnRefreshBar", bar, name)
flickerstreak@63 356 end
flickerstreak@63 357 end
flickerstreak@63 358
flickerstreak@53 359 function ReAction:RegisterBarType( name, config, isDefaultChoice )
flickerstreak@63 360 defaultBarConfig[name] = config
flickerstreak@48 361 if isDefaultChoice then
flickerstreak@81 362 private.defaultBarConfigChoice = name
flickerstreak@48 363 end
flickerstreak@48 364 self:RefreshOptions()
flickerstreak@48 365 end
flickerstreak@48 366
flickerstreak@53 367 function ReAction:UnregisterBarType( name )
flickerstreak@63 368 defaultBarConfig[name] = nil
flickerstreak@63 369 if private.defaultBarConfigChoice == name then
flickerstreak@63 370 private.defaultBarConfigChoice = nil
flickerstreak@48 371 end
flickerstreak@48 372 self:RefreshOptions()
flickerstreak@48 373 end
flickerstreak@48 374
flickerstreak@63 375 function ReAction:IterateBarTypes()
flickerstreak@63 376 return pairs(defaultBarConfig)
flickerstreak@63 377 end
flickerstreak@63 378
flickerstreak@63 379 function ReAction:GetBarTypeConfig(name)
flickerstreak@63 380 if name then
flickerstreak@63 381 return defaultBarConfig[name]
flickerstreak@63 382 end
flickerstreak@63 383 end
flickerstreak@63 384
flickerstreak@63 385 function ReAction:GetBarTypeOptions( fill )
flickerstreak@63 386 fill = fill or { }
flickerstreak@63 387 for k in self:IterateBarTypes() do
flickerstreak@63 388 fill[k] = k
flickerstreak@63 389 end
flickerstreak@63 390 return fill
flickerstreak@63 391 end
flickerstreak@63 392
flickerstreak@63 393 function ReAction:GetDefaultBarType()
flickerstreak@63 394 return private.defaultBarConfigChoice
flickerstreak@63 395 end
flickerstreak@63 396
flickerstreak@63 397 function ReAction:RegisterOptions(module, opts, global)
flickerstreak@63 398 options.args[global and "global" or "module"].plugins[module:GetName()] = opts
flickerstreak@63 399 self:RefreshOptions()
flickerstreak@30 400 end
flickerstreak@30 401
flickerstreak@30 402 function ReAction:RefreshOptions()
flickerstreak@63 403 callbacks:Fire("OnOptionsRefreshed")
flickerstreak@63 404 end
flickerstreak@63 405
flickerstreak@63 406 --
flickerstreak@63 407 -- In addition to global and general module options, options tables
flickerstreak@63 408 -- must be generated dynamically for each bar.
flickerstreak@63 409 --
flickerstreak@63 410 -- 'func' should be a function or a method string.
flickerstreak@63 411 -- The function or method will be passed the bar as its parameter.
flickerstreak@63 412 -- (methods will of course get the module as the first 'self' parameter)
flickerstreak@63 413 --
flickerstreak@63 414 -- A generator can be unregistered by passing a nil func.
flickerstreak@63 415 --
flickerstreak@63 416 function ReAction:RegisterBarOptionGenerator( module, func )
flickerstreak@63 417 if not module or type(module) ~= "table" then -- doesn't need to be a proper module, strictly
flickerstreak@63 418 error("ReAction:RegisterBarOptionGenerator() : Invalid module")
flickerstreak@63 419 end
flickerstreak@63 420 if type(func) == "string" then
flickerstreak@63 421 if not module[func] then
flickerstreak@63 422 error(("ReAction:RegisterBarOptionGenerator() : Invalid method '%s'"):format(func))
flickerstreak@63 423 end
flickerstreak@63 424 elseif func and type(func) ~= "function" then
flickerstreak@63 425 error("ReAction:RegisterBarOptionGenerator() : Invalid function")
flickerstreak@63 426 end
flickerstreak@63 427 barOptionGenerators[module] = func
flickerstreak@63 428 callbacks:Fire("OnBarOptionGeneratorRegistered", module, func)
flickerstreak@63 429 end
flickerstreak@63 430
flickerstreak@63 431 -- builds a table suitable for use as an AceConfig3 group 'plugins' sub-table
flickerstreak@63 432 function ReAction:GenerateBarOptionsTable( bar )
flickerstreak@63 433 local opts = { }
flickerstreak@63 434 for module, func in pairs(barOptionGenerators) do
flickerstreak@63 435 local success, r
flickerstreak@63 436 if type(func) == "string" then
flickerstreak@63 437 success, r = pcall(module[func], module, bar)
flickerstreak@63 438 else
flickerstreak@63 439 success, r = pcall(func, bar)
flickerstreak@63 440 end
flickerstreak@63 441 if success then
flickerstreak@63 442 opts[module:GetName()] = { [module:GetName()] = r }
flickerstreak@63 443 else
flickerstreak@63 444 geterrorhandler()(r)
flickerstreak@63 445 end
flickerstreak@63 446 end
flickerstreak@63 447 return opts
flickerstreak@30 448 end
flickerstreak@33 449
flickerstreak@33 450 function ReAction:SetConfigMode( mode )
flickerstreak@77 451 if mode ~= private.configMode then
flickerstreak@77 452 private.configMode = mode
flickerstreak@77 453 callbacks:Fire("OnConfigModeChanged", mode)
flickerstreak@77 454 end
flickerstreak@63 455 end
flickerstreak@63 456
flickerstreak@63 457 function ReAction:GetConfigMode()
flickerstreak@63 458 return private.configMode
flickerstreak@33 459 end
flickerstreak@38 460
flickerstreak@38 461 function ReAction:ShowConfig()
flickerstreak@63 462 CallModuleMethod("ConfigUI","OpenConfig")
flickerstreak@38 463 end
flickerstreak@38 464
flickerstreak@81 465 function ReAction:ShowEditor(bar, ...)
flickerstreak@81 466 CallModuleMethod("ConfigUI","LaunchBarEditor",bar, ...)
flickerstreak@47 467 end