| flickerstreak@7 | 1 -- main.lua | 
| flickerstreak@1 | 2 -- | 
| flickerstreak@1 | 3 -- Top-level file for the ReAction Action Bar add-on | 
| flickerstreak@1 | 4 -- | 
| flickerstreak@7 | 5 -- implemented in terms of the Ace 2 development framework library: http://www.wowace.com | 
| flickerstreak@1 | 6 -- | 
| flickerstreak@1 | 7 | 
| flickerstreak@7 | 8 -- Ace Library local object initialization | 
| flickerstreak@7 | 9 local L       = AceLibrary("AceLocale-2.2"):new("ReAction") | 
| flickerstreak@7 | 10 local dewdrop = AceLibrary("Dewdrop-2.0") | 
| flickerstreak@7 | 11 local tablet  = AceLibrary("Tablet-2.0") | 
| flickerstreak@1 | 12 | 
| flickerstreak@7 | 13 -- private functions | 
| flickerstreak@2 | 14 local function tcopy(t) | 
| flickerstreak@2 | 15   local r = { } | 
| flickerstreak@2 | 16   for k, v in pairs(t) do | 
| flickerstreak@2 | 17     r[k] = (type(v) == "table" and tcopy(v) or v) | 
| flickerstreak@2 | 18   end | 
| flickerstreak@2 | 19   return r | 
| flickerstreak@2 | 20 end | 
| flickerstreak@2 | 21 | 
| flickerstreak@7 | 22 -- private constants | 
| flickerstreak@7 | 23 local EMPTY_BAR_SLOT = -1 | 
| flickerstreak@7 | 24 | 
| flickerstreak@7 | 25 -- key binding label constants | 
| flickerstreak@7 | 26 BINDING_HEADER_REACTION                = L["ReAction"] | 
| flickerstreak@7 | 27 BINDING_NAME_REACTION_TOGGLELOCK       = L["Toggle ReAction Bar Lock"] | 
| flickerstreak@7 | 28 BINDING_NAME_REBOUND_TOGGLEBINDINGMODE = L["Toggle ReBound Keybinding Mode"] | 
| flickerstreak@7 | 29 | 
| flickerstreak@7 | 30 | 
| flickerstreak@7 | 31 -- main object | 
| flickerstreak@7 | 32 local main = AceLibrary("AceAddon-2.0"):new( | 
| flickerstreak@7 | 33   "AceConsole-2.0", | 
| flickerstreak@7 | 34   "AceEvent-2.0", | 
| flickerstreak@7 | 35   "AceDB-2.0", | 
| flickerstreak@7 | 36   "FuBarPlugin-2.0" | 
| flickerstreak@7 | 37 ) | 
| flickerstreak@1 | 38 | 
| flickerstreak@1 | 39 -- initial non-persistent state | 
| flickerstreak@7 | 40 main.locked = true | 
| flickerstreak@1 | 41 | 
| flickerstreak@7 | 42 -- set a global variable for Bindings.xml | 
| flickerstreak@7 | 43 ReActionAddOn = main | 
| flickerstreak@7 | 44 | 
| flickerstreak@7 | 45 | 
| flickerstreak@7 | 46 -- FuBar plugin setup | 
| flickerstreak@7 | 47 -- Even if FuBar isn't installed, this gives us a nice minimap-button interface. | 
| flickerstreak@7 | 48 main.hasIcon = "Interface\\Icons\\INV_Qiraj_JewelEncased" | 
| flickerstreak@7 | 49 main.hasNoColor = true | 
| flickerstreak@7 | 50 main.hideMenuTitle = true | 
| flickerstreak@7 | 51 main.defaultPosition = "LEFT" | 
| flickerstreak@7 | 52 main.defaultMinimapPosition = 240 -- degrees | 
| flickerstreak@7 | 53 main.OnMenuRequest = tcopy(ReActionGlobalMenuOptions) -- use a copy, or bar menus will have FuBar inserted items | 
| flickerstreak@7 | 54 main.independentProfile = true | 
| flickerstreak@7 | 55 | 
| flickerstreak@7 | 56 -- set the handler for the global bar menu options | 
| flickerstreak@7 | 57 -- have to do this after tcopy() above, otherwise it will try to copy the handler object (bad idea) | 
| flickerstreak@7 | 58 ReActionGlobalMenuOptions.handler = main | 
| flickerstreak@7 | 59 | 
| flickerstreak@1 | 60 | 
| flickerstreak@1 | 61 | 
| flickerstreak@1 | 62 | 
| flickerstreak@1 | 63 -- Event handling | 
| flickerstreak@7 | 64 function main:OnInitialize() | 
| flickerstreak@7 | 65   self:RegisterChatCommand( {L["/reaction"], L["/rxn"]}, ReActionConsoleOptions, "REACTION" ) | 
| flickerstreak@1 | 66   self:RegisterDB("ReActionDB","ReActionDBPC") | 
| flickerstreak@7 | 67   self:RegisterDefaults("profile", ReAction_DefaultProfile) | 
| flickerstreak@1 | 68   self:RegisterEvent("PLAYER_REGEN_DISABLED","CombatLockdown") | 
| flickerstreak@2 | 69   self:RegisterEvent("PLAYER_ENTERING_WORLD","HideDefaultBars") | 
| flickerstreak@7 | 70   self:RegisterEvent("EVENT_REBOUND_KEYBINDING_MODE") | 
| flickerstreak@1 | 71 end | 
| flickerstreak@1 | 72 | 
| flickerstreak@7 | 73 function main:OnEnable() | 
| flickerstreak@7 | 74   -- this gets called at startup and when the profile is changed | 
| flickerstreak@1 | 75   if self.db.profile.firstRunDone ~= true then | 
| flickerstreak@1 | 76     -- Do some "first-run" setup | 
| flickerstreak@7 | 77     self:StealKeyBindings() | 
| flickerstreak@1 | 78     self.db.profile.firstRunDone = true | 
| flickerstreak@7 | 79     self.db.profile.bars = tcopy(ReAction_DefaultBlizzardBars) | 
| flickerstreak@1 | 80   end | 
| flickerstreak@7 | 81   self:DestroyAllBars() | 
| flickerstreak@2 | 82   self:SetupBars() | 
| flickerstreak@1 | 83 end | 
| flickerstreak@1 | 84 | 
| flickerstreak@7 | 85 function main:OnDisable() | 
| flickerstreak@1 | 86   self:Lock() | 
| flickerstreak@1 | 87 end | 
| flickerstreak@1 | 88 | 
| flickerstreak@7 | 89 function main:OnProfileEnable() | 
| flickerstreak@7 | 90   -- for profile switching | 
| flickerstreak@7 | 91   self:OnEnable() | 
| flickerstreak@1 | 92 end | 
| flickerstreak@1 | 93 | 
| flickerstreak@7 | 94 function main:CombatLockdown() | 
| flickerstreak@1 | 95   if not self:IsLocked() then | 
| flickerstreak@1 | 96     self:Lock() | 
| flickerstreak@7 | 97     ReBound:Disable() | 
| flickerstreak@7 | 98     UIErrorsFrame:AddMessage(L["ReAction bars locked when in combat"]) | 
| flickerstreak@1 | 99   end | 
| flickerstreak@1 | 100 end | 
| flickerstreak@1 | 101 | 
| flickerstreak@7 | 102 function main:EVENT_REBOUND_KEYBINDING_MODE(enabled) | 
| flickerstreak@7 | 103   for _, bar in pairs(self.bars) do | 
| flickerstreak@7 | 104     for __, button in pairs(bar.buttons) do | 
| flickerstreak@8 | 105       if button and button ~= EMPTY_BAR_SLOT then | 
| flickerstreak@8 | 106         button:TempShow(enabled) | 
| flickerstreak@8 | 107       end | 
| flickerstreak@7 | 108     end | 
| flickerstreak@7 | 109   end | 
| flickerstreak@7 | 110 end | 
| flickerstreak@1 | 111 | 
| flickerstreak@7 | 112 | 
| flickerstreak@7 | 113 -- FuBar plugin methods | 
| flickerstreak@7 | 114 function main:OnTooltipUpdate() | 
| flickerstreak@7 | 115 	local c = tablet:AddCategory("columns", 2) | 
| flickerstreak@7 | 116 	c:AddLine("text", L["Bar lock"], "text2", self.locked and ("|cffff0000"..L["Locked"].."|r") or ("|cffffcc00"..L["Unlocked"].."|r")) | 
| flickerstreak@7 | 117   c:AddLine("text", L["Button lock"], "text2", LOCK_ACTIONBAR == "1" and ("|cffcc0000"..L["Locked"].."|r") or ("|cff00cc00"..L["Unlocked"].."|r")) | 
| flickerstreak@7 | 118   c:AddLine("text", L["Kebinding mode"], "text2", ReBound:IsEnabled() and ("|cff33ff33"..L["On"].."|r") or ("|cffffcc00"..L["Off"].."|r")) | 
| flickerstreak@7 | 119 	tablet:SetHint(L["|cffffcc00Shift-Click for bar lock|n|cff33ff33Alt-Click|r for keybindings|nRight-click for menu"]) | 
| flickerstreak@7 | 120 end | 
| flickerstreak@7 | 121 | 
| flickerstreak@7 | 122 function main:OnClick(button) | 
| flickerstreak@7 | 123 	if IsShiftKeyDown() then | 
| flickerstreak@7 | 124 	  self:ToggleLocked() | 
| flickerstreak@7 | 125     self:UpdateDisplay() | 
| flickerstreak@7 | 126 	elseif IsAltKeyDown() then | 
| flickerstreak@7 | 127     ReBound:ToggleEnabled() | 
| flickerstreak@7 | 128     self:UpdateDisplay() | 
| flickerstreak@7 | 129   end | 
| flickerstreak@7 | 130 end | 
| flickerstreak@7 | 131 | 
| flickerstreak@7 | 132 | 
| flickerstreak@7 | 133 -- lock/unlock bars | 
| flickerstreak@7 | 134 function main:SetLocked( lock ) | 
| flickerstreak@2 | 135   if lock ~= self.locked then | 
| flickerstreak@2 | 136     if not lock and InCombatLockdown() then | 
| flickerstreak@2 | 137       UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) | 
| flickerstreak@2 | 138     else | 
| flickerstreak@2 | 139       self.locked = lock and true or false -- force data integrity | 
| flickerstreak@2 | 140       for _, bar in pairs(self.bars) do | 
| flickerstreak@7 | 141         if bar ~= EMPTY_BAR_SLOT then | 
| flickerstreak@7 | 142           if self.locked then | 
| flickerstreak@7 | 143             bar:HideControls() | 
| flickerstreak@7 | 144             -- close any dewdrop menu owned by the bar | 
| flickerstreak@7 | 145             if bar:GetControlFrame() == dewdrop:GetOpenedParent() then | 
| flickerstreak@7 | 146               dewdrop:Close() | 
| flickerstreak@7 | 147             end | 
| flickerstreak@7 | 148           else | 
| flickerstreak@7 | 149             bar:ShowControls() | 
| flickerstreak@7 | 150           end | 
| flickerstreak@7 | 151         end | 
| flickerstreak@2 | 152       end | 
| flickerstreak@2 | 153     end | 
| flickerstreak@1 | 154   end | 
| flickerstreak@1 | 155 end | 
| flickerstreak@1 | 156 | 
| flickerstreak@7 | 157 function main:IsLocked() | 
| flickerstreak@1 | 158   return self.locked | 
| flickerstreak@1 | 159 end | 
| flickerstreak@1 | 160 | 
| flickerstreak@7 | 161 function main:Lock() | 
| flickerstreak@1 | 162   self:SetLocked(true) | 
| flickerstreak@1 | 163 end | 
| flickerstreak@1 | 164 | 
| flickerstreak@7 | 165 function main:Unlock() | 
| flickerstreak@1 | 166   self:SetLocked(false) | 
| flickerstreak@1 | 167 end | 
| flickerstreak@1 | 168 | 
| flickerstreak@7 | 169 function main:ToggleLocked() | 
| flickerstreak@7 | 170   main:SetLocked( not(self.locked) ) | 
| flickerstreak@1 | 171 end | 
| flickerstreak@1 | 172 | 
| flickerstreak@1 | 173 | 
| flickerstreak@1 | 174 | 
| flickerstreak@1 | 175 -- Hide the default Blizzard main bar artwork | 
| flickerstreak@7 | 176 function main:HideArt() | 
| flickerstreak@1 | 177   if self.db.profile.hideArt then | 
| flickerstreak@7 | 178     -- the pet bar is a child of MainMenuBar, and can't be hidden. Need to reparent it | 
| flickerstreak@7 | 179     PetActionBarFrame:SetParent(UIParent) | 
| flickerstreak@1 | 180     MainMenuBar:Hide() -- this also hides the bags, xp bar, lag meter, and micro menu buttons. | 
| flickerstreak@7 | 181     -- these two are the pet bar background | 
| flickerstreak@7 | 182     -- unfortunately UIParent_ManageFramePositions() shows and hides these too | 
| flickerstreak@7 | 183     -- so they get reparented to MainMenuBar | 
| flickerstreak@7 | 184     SlidingActionBarTexture0:SetParent(MainMenuBar) | 
| flickerstreak@7 | 185     SlidingActionBarTexture1:SetParent(MainMenuBar) | 
| flickerstreak@1 | 186   else | 
| flickerstreak@7 | 187     SlidingActionBarTexture0:SetParent(PetActionBarFrame) | 
| flickerstreak@7 | 188     SlidingActionBarTexture1:SetParent(PetActionBarFrame) | 
| flickerstreak@1 | 189     MainMenuBar:Show() | 
| flickerstreak@1 | 190   end | 
| flickerstreak@1 | 191 end | 
| flickerstreak@1 | 192 | 
| flickerstreak@7 | 193 function main:IsArtHidden() | 
| flickerstreak@1 | 194   return self.db.profile.hideArt | 
| flickerstreak@1 | 195 end | 
| flickerstreak@1 | 196 | 
| flickerstreak@7 | 197 function main:SetHideArt( hide ) | 
| flickerstreak@2 | 198   if InCombatLockdown() then | 
| flickerstreak@2 | 199     UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) | 
| flickerstreak@2 | 200   else | 
| flickerstreak@2 | 201     self.db.profile.hideArt = hide and true or false -- force data integrity | 
| flickerstreak@2 | 202     self:HideArt() | 
| flickerstreak@2 | 203   end | 
| flickerstreak@1 | 204 end | 
| flickerstreak@1 | 205 | 
| flickerstreak@7 | 206 function main:ToggleHideArt() | 
| flickerstreak@1 | 207   self:SetHideArt( not self:IsArtHidden() ) | 
| flickerstreak@1 | 208 end | 
| flickerstreak@1 | 209 | 
| flickerstreak@1 | 210 | 
| flickerstreak@1 | 211 | 
| flickerstreak@1 | 212 -- Hide default Blizzard bars | 
| flickerstreak@1 | 213 local blizzDefaultBars = { | 
| flickerstreak@1 | 214   ActionButton1, | 
| flickerstreak@1 | 215   ActionButton2, | 
| flickerstreak@1 | 216   ActionButton3, | 
| flickerstreak@1 | 217   ActionButton4, | 
| flickerstreak@1 | 218   ActionButton5, | 
| flickerstreak@1 | 219   ActionButton6, | 
| flickerstreak@1 | 220   ActionButton7, | 
| flickerstreak@1 | 221   ActionButton8, | 
| flickerstreak@1 | 222   ActionButton9, | 
| flickerstreak@1 | 223   ActionButton10, | 
| flickerstreak@1 | 224   ActionButton11, | 
| flickerstreak@1 | 225   ActionButton12, | 
| flickerstreak@7 | 226   PetActionButton1, | 
| flickerstreak@7 | 227   PetActionButton2, | 
| flickerstreak@7 | 228   PetActionButton3, | 
| flickerstreak@7 | 229   PetActionButton4, | 
| flickerstreak@7 | 230   PetActionButton5, | 
| flickerstreak@7 | 231   PetActionButton6, | 
| flickerstreak@7 | 232   PetActionButton7, | 
| flickerstreak@7 | 233   PetActionButton8, | 
| flickerstreak@7 | 234   PetActionButton9, | 
| flickerstreak@7 | 235   PetActionButton10, | 
| flickerstreak@7 | 236   -- NOT the PetActionBarFrame, though - we need that to auto-hide/show our pet action bars | 
| flickerstreak@7 | 237   MainMenuBarPageNumber, | 
| flickerstreak@7 | 238   ActionBarUpButton, | 
| flickerstreak@7 | 239   ActionBarDownButton, | 
| flickerstreak@1 | 240   BonusActionBarFrame, | 
| flickerstreak@7 | 241   ShapeshiftBarFrame, | 
| flickerstreak@1 | 242   MultiBarLeft, | 
| flickerstreak@1 | 243   MultiBarRight, | 
| flickerstreak@1 | 244   MultiBarBottomLeft, | 
| flickerstreak@7 | 245   MultiBarBottomRight, | 
| flickerstreak@1 | 246 } | 
| flickerstreak@1 | 247 | 
| flickerstreak@7 | 248 function main:StealKeyBindings() | 
| flickerstreak@7 | 249   -- steal the keybindings of the main action bar and assign them to rebar 1, buttons 1-12 | 
| flickerstreak@7 | 250   for i = 1, 12 do | 
| flickerstreak@7 | 251     -- TODO: when we convert to override bindings | 
| flickerstreak@1 | 252   end | 
| flickerstreak@1 | 253 end | 
| flickerstreak@1 | 254 | 
| flickerstreak@7 | 255 local function disableUIOptions() | 
| flickerstreak@7 | 256   -- disable the buttons to hide/show the blizzard multiaction bars | 
| flickerstreak@7 | 257   -- see UIOptionsFrame.lua and .xml | 
| flickerstreak@7 | 258   -- This is called every time the options panel is shown, after it is set up | 
| flickerstreak@7 | 259   for _, idx in pairs( { 33, 34, 35, 36, 37, 40 } ) do | 
| flickerstreak@7 | 260     local f = getglobal("UIOptionsFrameCheckButton"..idx) | 
| flickerstreak@7 | 261     f.disabled = true | 
| flickerstreak@7 | 262     OptionsFrame_DisableCheckBox(f) | 
| flickerstreak@7 | 263     f:SetChecked(false) | 
| flickerstreak@7 | 264   end | 
| flickerstreak@7 | 265 end | 
| flickerstreak@1 | 266 | 
| flickerstreak@7 | 267 function main:HideDefaultBars() | 
| flickerstreak@7 | 268   for _, f in pairs(blizzDefaultBars) do | 
| flickerstreak@7 | 269     f:Hide() | 
| flickerstreak@7 | 270     f:ClearAllPoints() | 
| flickerstreak@7 | 271     f:SetParent(ReAction.recycler) | 
| flickerstreak@7 | 272     f:SetPoint("TOPLEFT") | 
| flickerstreak@7 | 273   end | 
| flickerstreak@7 | 274 | 
| flickerstreak@7 | 275   MainMenuBar:SetFrameStrata("LOW") -- otherwise it appears on top of bars, if it isn't hidden | 
| flickerstreak@7 | 276   hooksecurefunc("UIOptionsFrame_Load",disableUIOptions) | 
| flickerstreak@7 | 277 end | 
| flickerstreak@7 | 278 | 
| flickerstreak@7 | 279 | 
| flickerstreak@7 | 280 -- Reset bars to blizzard defaults | 
| flickerstreak@7 | 281 function main:ResetBars() | 
| flickerstreak@2 | 282   if InCombatLockdown() then | 
| flickerstreak@2 | 283     UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) | 
| flickerstreak@2 | 284   else | 
| flickerstreak@7 | 285     self:DestroyAllBars() | 
| flickerstreak@7 | 286     self.db.profile.bars = tcopy(ReAction_DefaultBlizzardBars) | 
| flickerstreak@2 | 287     self:SetupBars() | 
| flickerstreak@2 | 288   end | 
| flickerstreak@1 | 289 end | 
| flickerstreak@1 | 290 | 
| flickerstreak@1 | 291 | 
| flickerstreak@1 | 292 -- re-sync action IDs | 
| flickerstreak@7 | 293 function main:ResyncActionIDs() | 
| flickerstreak@1 | 294   -- TODO | 
| flickerstreak@1 | 295 end | 
| flickerstreak@1 | 296 | 
| flickerstreak@1 | 297 | 
| flickerstreak@1 | 298 | 
| flickerstreak@1 | 299 -- Bar manipulation | 
| flickerstreak@7 | 300 main.bars    = { } | 
| flickerstreak@1 | 301 | 
| flickerstreak@7 | 302 function main:DestroyAllBars() | 
| flickerstreak@7 | 303   -- destroy any existing bars | 
| flickerstreak@7 | 304   for id = 1, table.maxn(self.bars) do | 
| flickerstreak@7 | 305     self:DestroyBar(id) | 
| flickerstreak@7 | 306   end | 
| flickerstreak@7 | 307 end | 
| flickerstreak@7 | 308 | 
| flickerstreak@7 | 309 | 
| flickerstreak@7 | 310 function main:SetupBars() | 
| flickerstreak@1 | 311   -- hide the default Blizzard art, if configued | 
| flickerstreak@1 | 312   self:HideArt() | 
| flickerstreak@1 | 313 | 
| flickerstreak@1 | 314   -- set up the bars from the profile | 
| flickerstreak@2 | 315   -- note the use of table.maxn rather than # or ipairs: | 
| flickerstreak@2 | 316   -- our array of bars can in fact contain holes | 
| flickerstreak@2 | 317   for id = 1, table.maxn(self.db.profile.bars) do | 
| flickerstreak@2 | 318     local config = self.db.profile.bars[id] | 
| flickerstreak@2 | 319     if config then | 
| flickerstreak@7 | 320       self:CreateBar(config, id) | 
| flickerstreak@2 | 321     end | 
| flickerstreak@1 | 322   end | 
| flickerstreak@1 | 323 | 
| flickerstreak@1 | 324   -- anchor the bars, have to do this in a second pass because | 
| flickerstreak@1 | 325   -- they might be anchored to each other in a non-ordered way | 
| flickerstreak@2 | 326   for _, bar in pairs(self.bars) do | 
| flickerstreak@7 | 327     if bar ~= EMPTY_BAR_SLOT then | 
| flickerstreak@7 | 328       bar:ApplyAnchor() | 
| flickerstreak@2 | 329     end | 
| flickerstreak@2 | 330   end | 
| flickerstreak@1 | 331 end | 
| flickerstreak@1 | 332 | 
| flickerstreak@7 | 333 function main:CreateBar( config, id ) | 
| flickerstreak@7 | 334   local bar = ReBar:new(config, id) | 
| flickerstreak@7 | 335   local buttonType = ReAction:GetButtonType(config.btnConfig.subtype) | 
| flickerstreak@1 | 336 | 
| flickerstreak@7 | 337   if buttonType then | 
| flickerstreak@7 | 338     self.bars[id] = bar | 
| flickerstreak@7 | 339     self.db.profile.bars[id] = config | 
| flickerstreak@7 | 340 | 
| flickerstreak@7 | 341     -- initialize dewdrop menu | 
| flickerstreak@7 | 342     local cf = bar:GetControlFrame() | 
| flickerstreak@7 | 343     dewdrop:Register(cf, | 
| flickerstreak@7 | 344       'children', | 
| flickerstreak@7 | 345       function() | 
| flickerstreak@7 | 346         dewdrop:FeedAceOptionsTable(ReActionGlobalMenuOptions) | 
| flickerstreak@7 | 347         dewdrop:FeedAceOptionsTable(GenerateReActionBarOptions(bar,self)) | 
| flickerstreak@7 | 348         dewdrop:FeedAceOptionsTable(buttonType:GenerateOptionsTable(config.btnConfig, function() return bar:GetButtonList() end)) | 
| flickerstreak@7 | 349       end, | 
| flickerstreak@7 | 350       'cursorX', true, | 
| flickerstreak@7 | 351       'cursorY', true | 
| flickerstreak@7 | 352     ) | 
| flickerstreak@7 | 353 | 
| flickerstreak@7 | 354     bar:GetControlFrame():SetScript("OnClick", | 
| flickerstreak@7 | 355       function(btn) | 
| flickerstreak@7 | 356         if btn == "RightButton" then | 
| flickerstreak@7 | 357           dewdrop:Open(cf) | 
| flickerstreak@7 | 358         end | 
| flickerstreak@7 | 359       end | 
| flickerstreak@7 | 360     ) | 
| flickerstreak@7 | 361 | 
| flickerstreak@7 | 362     if not self.locked then | 
| flickerstreak@7 | 363       bar:ShowControls() | 
| flickerstreak@7 | 364     end | 
| flickerstreak@7 | 365     return bar | 
| flickerstreak@7 | 366   else | 
| flickerstreak@7 | 367     if bar then | 
| flickerstreak@7 | 368       bar:Destroy() | 
| flickerstreak@7 | 369     end | 
| flickerstreak@7 | 370     error(L["Tried to create a button of unknown type"]) | 
| flickerstreak@7 | 371   end | 
| flickerstreak@7 | 372 end | 
| flickerstreak@7 | 373 | 
| flickerstreak@7 | 374 function main:DestroyBar( id ) | 
| flickerstreak@7 | 375   local bar = self.bars[id] | 
| flickerstreak@7 | 376   if bar and bar ~= EMPTY_BAR_SLOT then | 
| flickerstreak@7 | 377     local cf = bar:GetControlFrame() | 
| flickerstreak@7 | 378     if cf == dewdrop:GetOpenedParent() then | 
| flickerstreak@7 | 379       dewdrop:Close() | 
| flickerstreak@7 | 380       dewdrop:Unregister(cf) | 
| flickerstreak@7 | 381     end | 
| flickerstreak@7 | 382     bar:Destroy() | 
| flickerstreak@7 | 383     -- we can't do tremove because each bar ID is encoded into the | 
| flickerstreak@7 | 384     -- frame names as they're created. Need a blank entry in the table. | 
| flickerstreak@7 | 385     -- The nice thing is that table.insert in NewBar() will automatically | 
| flickerstreak@7 | 386     -- find the lowest numbered nil slot. | 
| flickerstreak@7 | 387     self.bars[id] = EMPTY_BAR_SLOT | 
| flickerstreak@7 | 388   end | 
| flickerstreak@7 | 389 end | 
| flickerstreak@7 | 390 | 
| flickerstreak@7 | 391 function main:NewBar( type ) | 
| flickerstreak@7 | 392   if InCombatLockdown() then | 
| flickerstreak@7 | 393     UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) | 
| flickerstreak@7 | 394   else | 
| flickerstreak@7 | 395     local t = ReAction:GetButtonType(type) | 
| flickerstreak@7 | 396     if t then | 
| flickerstreak@7 | 397       local c = tcopy(ReAction_DefaultBarConfig["ReAction"][type]) | 
| flickerstreak@7 | 398       local id = nil | 
| flickerstreak@7 | 399       for i = 1, table.maxn(self.bars) + 1 do  -- there may be holes, so #self.bars won't work | 
| flickerstreak@7 | 400         if self.bars[i] == nil or self.bars[i] == EMPTY_BAR_SLOT then | 
| flickerstreak@7 | 401           id = i | 
| flickerstreak@7 | 402           break | 
| flickerstreak@7 | 403         end | 
| flickerstreak@7 | 404       end | 
| flickerstreak@7 | 405       local bar = self:CreateBar(c, id) | 
| flickerstreak@7 | 406       bar:ApplyAnchor() | 
| flickerstreak@7 | 407       self:Unlock() | 
| flickerstreak@7 | 408     end | 
| flickerstreak@7 | 409   end | 
| flickerstreak@7 | 410 end | 
| flickerstreak@7 | 411 | 
| flickerstreak@7 | 412 | 
| flickerstreak@7 | 413 function main:DeleteBar(id) | 
| flickerstreak@2 | 414   if InCombatLockdown() then | 
| flickerstreak@2 | 415     UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) | 
| flickerstreak@2 | 416   else | 
| flickerstreak@2 | 417     if self.bars[id] then | 
| flickerstreak@7 | 418       self:DestroyBar(id) | 
| flickerstreak@2 | 419       self.db.profile.bars[id] = nil | 
| flickerstreak@2 | 420     end | 
| flickerstreak@1 | 421   end | 
| flickerstreak@1 | 422 end | 
| flickerstreak@1 | 423 | 
| flickerstreak@7 | 424 function main:ToggleIds() | 
| flickerstreak@7 | 425   if self.showIds then | 
| flickerstreak@7 | 426     ReAction:HideAllIds() | 
| flickerstreak@1 | 427   else | 
| flickerstreak@7 | 428     ReAction:ShowAllIds() | 
| flickerstreak@1 | 429   end | 
| flickerstreak@7 | 430   self.showIds = not self.showIds | 
| flickerstreak@1 | 431 end | 
| flickerstreak@1 | 432 | 
| flickerstreak@7 | 433 function main:AreIdsVisible() | 
| flickerstreak@7 | 434   return self.showIds | 
| flickerstreak@1 | 435 end | 
| flickerstreak@1 | 436 | 
| flickerstreak@1 | 437 | 
| flickerstreak@1 | 438 |