Mercurial > wow > reaction
view main.lua @ 20:2f3e45fcb9e2
Version 0.40
(dummy checkin)
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Tue, 22 May 2007 16:39:02 +0000 |
parents | 639282f3a0e0 |
children | 90bf38d48efd |
line wrap: on
line source
-- main.lua -- -- Top-level file for the ReAction Action Bar add-on -- -- implemented in terms of the Ace 2 development framework library: http://www.wowace.com -- -- Ace Library local object initialization local L = AceLibrary("AceLocale-2.2"):new("ReAction") local dewdrop = AceLibrary("Dewdrop-2.0") local tablet = AceLibrary("Tablet-2.0") local ReBound = AceLibrary("ReBound-1.0"):new("ReAction") -- private functions local function tcopy(t) local r = { } for k, v in pairs(t) do r[k] = (type(v) == "table" and tcopy(v) or v) end return r end -- private constants local EMPTY_BAR_SLOT = -1 -- key binding label constants BINDING_HEADER_REACTION = L["ReAction"] BINDING_NAME_REACTION_TOGGLELOCK = L["Toggle ReAction Bar Lock"] BINDING_NAME_REACTION_TOGGLEKEYBIND = L["ReAction Keybinding Mode"] -- UI panel strings REACTION_KEYBIND_TITLE = L["ReAction Keybinding"] REACTION_KEYBIND_SUBTITLE = L["Click Buttons to Set Keybindings"] REACTION_KEYBIND_DONE = L["Save"] REACTION_KEYBIND_REVERT = L["Revert"] ------------------------------ -- AceAddon setup ------------------------------ local main = AceLibrary("AceAddon-2.0"):new( "AceConsole-2.0", "AceEvent-2.0", "AceDB-2.0", "FuBarPlugin-2.0" ) function main:OnInitialize() self:RegisterChatCommand( {L["/reaction"], L["/rxn"]}, ReActionConsoleOptions, "REACTION" ) self:RegisterDB("ReActionDB","ReActionDBPC") self:RegisterDefaults("profile", ReAction_DefaultProfile) self:RegisterEvent("PLAYER_REGEN_DISABLED","CombatLockdown") self:DisableDefaultKeybindings() -- create update function for keybinding frame ReActionKeybindDialog:SetScript("OnHide", function(frame) main:HideKeybindDialog(frame) end) -- initial non-persistent state self.locked = true self.keybindMode = false self.bars = { } end -- OnEnable is called at PLAYER_LOGIN or when the addon is enabled. function main:OnEnable( ) self:HideDefaultBars() self:SetupProfile( ) end function main:OnDisable() self:Lock() end -- OnProfileEnable() is only called when switching profiles, NOT for the initial profile at load time. function main:OnProfileEnable( oldName, oldData ) self:UnregisterEvent("REBOUND_BIND") self:UnregisterEvent("REBOUND_UNBIND") ReBound:ClearRegisteredBindings() self:SetupProfile() end function main:SetupProfile( ) local profile = self.db.profile if profile.firstRunDone ~= true then profile.bars = tcopy(ReAction_DefaultBlizzardBars) end self:DestroyAllBars() self:UpgradeProfile() self:HideArt() self:SetupBars() self:SetupKeybindings() if profile.firstRunDone ~= true then self:Unlock() profile.firstRunDone = true end end -- Set a global variable for Bindings.xml (I use 'setglobal' for clarity, it's not strictly necessary) setglobal("ReActionAddOn", main) ------------------------------------------------------------ -- Profile conversion functions (from old profiles) -- -- NOTE: these will be REMOVED when alpha testing is over. ------------------------------------------------------------ function main:UpgradeBindingConfig() if #self.db.profile.bindings == 0 then for _, bar in pairs(self.bars) do for _, button in pairs(bar.buttons) do local key = ReBound:GetBinding(button:GetActionFrame(),"LeftButton") if key and #key > 0 and not self.db.profile.bindings[key] then self:REBOUND_BIND(key,button:GetActionFrame():GetName(),"LeftButton") end end end end end function main:UpgradeProfile() end -------------------------------------------- -- FuBar plugin setup -- Even if FuBar isn't installed, the plugin -- provides a nice minimap-button interface. --------------------------------------------- main.hasIcon = "Interface\\Icons\\INV_Qiraj_JewelEncased" main.hasNoColor = true main.hideMenuTitle = true main.defaultPosition = "LEFT" main.defaultMinimapPosition = 240 -- degrees main.OnMenuRequest = tcopy(ReActionGlobalMenuOptions) -- use a copy, or bar menus will have FuBar inserted items main.independentProfile = true -- set the handler for the global bar menu options -- have to do this after tcopy() above, otherwise it will try to copy the handler object (bad idea) ReActionGlobalMenuOptions.handler = main function main:OnTooltipUpdate() local c = tablet:AddCategory("columns", 2) c:AddLine("text", L["Bar lock"], "text2", self.locked and ("|cffff0000"..L["Locked"].."|r") or ("|cffffcc00"..L["Unlocked"].."|r")) c:AddLine("text", L["Button lock"], "text2", LOCK_ACTIONBAR == "1" and ("|cffcc0000"..L["Locked"].."|r") or ("|cff00cc00"..L["Unlocked"].."|r")) c:AddLine("text", L["Kebinding mode"], "text2", self:GetKeybindMode() and ("|cff33ff33"..L["On"].."|r") or ("|cffffcc00"..L["Off"].."|r")) tablet:SetHint(L["|cffffcc00Shift-Click for bar lock|n|cff33ff33Alt-Click|r for keybindings|nRight-click for menu"]) end function main:OnClick(button) if IsShiftKeyDown() then self:ToggleLocked() self:UpdateDisplay() elseif IsAltKeyDown() then self:ToggleKeybindMode() self:UpdateDisplay() end end ------------------------------ -- Key binding functions ------------------------------ function main:DisableDefaultKeybindings() -- change the labels on all actionbar keybindings in the default interface. local label = "|cff999999("..L["Use ReAction"]..")|r" for i = 1, 12 do setglobal("BINDING_NAME_ACTIONBUTTON"..i,label) for j = 1, 4 do setglobal("BINDING_NAME_MULTIACTIONBAR"..j.."BUTTON"..i,label) end end for i = 1, 6 do setglobal("BINDING_NAME_ACTIONPAGE"..i,label) end for i = 1, 10 do setglobal("BINDING_NAME_BONUSACTIONBUTTON"..i,label) -- setglobal("BINDING_NAME_SHAPESHIFTBUTTON"..i,label) end BINDING_HEADER_ACTIONBAR = "|cff999999"..L["Action Bar Functions Disabled"].."|r" BINDING_HEADER_MULTIACTIONBAR = "|cff999999"..L["Multi-Action Bar Functions Disabled"].."|r" BINDING_NAME_NEXTACTIONPAGE = label BINDING_NAME_PREVIOUSACTIONPAGE = label end function main:SetupKeybindings() if self.db.profile.firstRunDone ~= true then self:StealKeyBindings() else self:UpgradeBindingConfig() local needsSave = false for key, binding in pairs(self.db.profile.bindings) do local target = getglobal(binding.target) if target then if ReBound:GetBinding(target,binding.button) ~= key then ReBound:SetBinding(key,target,binding.button,true) needsSave = true end end end if needsSave then ReBound:SaveBindings() end end self:RegisterEvent("REBOUND_BIND") self:RegisterEvent("REBOUND_UNBIND") end function main:StealKeyBindings() -- steal the keybindings of the main action bar and assign them to rebar 1, buttons 1-12 local bar = self.bars[1] if bar and bar ~= EMPTY_BAR_SLOT then for i = 1, 12 do local key = GetBindingKey("ACTIONBUTTON"..i) if key and #key > 0 then local button = bar.buttons[i] if button then ReBound:SetBinding(key, button:GetActionFrame(),nil,true) end end end local key = GetBindingKey("NEXTACTIONPAGE") if key and #key > 0 then ReBound:SetBinding(key, bar.upArrow,nil,true) end key = GetBindingKey("PREVIOUSACTIONPAGE") if key and #key > 0 then ReBound:SetBinding(key, bar.downArrow,nil,true) end ReBound:SaveBindings() end end function main:REBOUND_BIND(id, key, target, button) if id == "ReAction" and key and target then self.db.profile.bindings[key] = { target = target, button = button } end end function main:REBOUND_UNBIND(id, key) if id == "ReAction" and key then self.db.profile.bindings[key] = nil end end function main:ToggleKeybindMode() self:SetKeybindMode(not self:GetKeybindMode()) end function main:GetKeybindMode() return self.keybindMode end function main:SetKeybindMode(enabled) if InCombatLockdown() then UIErrorsFrame:AddMessage(ERROR_NOT_IN_COMBAT) else self.keybindMode = enabled for _, bar in pairs(self.bars) do if bar and bar ~= EMPTY_BAR_SLOT then for __, button in pairs(bar.buttons) do if button then button:TempShow(enabled) end end end end if enabled then ReBound:ShowRegisteredFrames() ReActionKeybindDialog:Show() else ReBound:HideRegisteredFrames() if ReActionKeybindDialog:IsShown() then ReActionKeybindDialog:Hide() end end end end function main:HideKeybindDialog( frame ) self:SetKeybindMode(false) if frame.save then ReBound:SaveBindings() else ReBound:RevertBindings() end frame.save = false end ---------------------------- -- Bar lock/unlock functions ---------------------------- function main:CombatLockdown() if not self:IsLocked() then self:Lock() UIErrorsFrame:AddMessage(L["ReAction bars locked when in combat"]) end ReActionKeybindDialog:Hide() end function main:SetLocked( lock ) if lock ~= self.locked then if not lock and InCombatLockdown() then UIErrorsFrame:AddMessage(ERROR_NOT_IN_COMBAT) else self.locked = lock and true or false -- force data integrity for _, bar in pairs(self.bars) do if bar ~= EMPTY_BAR_SLOT then if self.locked then bar:HideControls() -- close any dewdrop menu owned by the bar if bar:GetControlFrame() == dewdrop:GetOpenedParent() then dewdrop:Close() end else bar:ShowControls() end end end end end end function main:IsLocked() return self.locked end function main:Lock() self:SetLocked(true) end function main:Unlock() self:SetLocked(false) end function main:ToggleLocked() self:SetLocked( not(self.locked) ) end -------------------------------------------------------- -- Functions to hide the default Blizzard main bar parts -------------------------------------------------------- function main:HideArt() if self.db.profile.hideArt then -- the pet bar is a child of MainMenuBar, but can't be hidden because it will -- break automatic pet bar show/hide. Need to reparent it. PetActionBarFrame:SetParent(UIParent) -- these two are the pet bar background -- unfortunately UIParent_ManageFramePositions() shows and hides these too -- so they get reparented to MainMenuBar SlidingActionBarTexture0:SetParent(MainMenuBar) SlidingActionBarTexture1:SetParent(MainMenuBar) MainMenuBar:Hide() -- this also hides the bags, xp bar, lag meter, and micro menu buttons. else SlidingActionBarTexture0:SetParent(PetActionBarFrame) SlidingActionBarTexture1:SetParent(PetActionBarFrame) PetActionBarFrame:SetParent(MainMenuBar) MainMenuBar:Show() end end function main:IsArtHidden() return self.db.profile.hideArt end function main:SetHideArt( hide ) if InCombatLockdown() then UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) else self.db.profile.hideArt = hide and true or false -- force data integrity self:HideArt() end end function main:ToggleHideArt() self:SetHideArt( not self:IsArtHidden() ) end -- Hide default Blizzard bars local blizzDefaultBars = { ActionButton1, ActionButton2, ActionButton3, ActionButton4, ActionButton5, ActionButton6, ActionButton7, ActionButton8, ActionButton9, ActionButton10, ActionButton11, ActionButton12, PetActionButton1, PetActionButton2, PetActionButton3, PetActionButton4, PetActionButton5, PetActionButton6, PetActionButton7, PetActionButton8, PetActionButton9, PetActionButton10, -- NOT the PetActionBarFrame, though - we need that to auto-hide/show our pet action bars MainMenuBarPageNumber, ActionBarUpButton, ActionBarDownButton, BonusActionBarFrame, ShapeshiftBarFrame, MultiBarLeft, MultiBarRight, MultiBarBottomLeft, MultiBarBottomRight, } local function disableUIOptions() -- disable the buttons to hide/show the blizzard multiaction bars -- see UIOptionsFrame.lua and .xml -- This is called every time the options panel is shown, after it is set up for _, idx in pairs( { 33, 34, 35, 36, 37, 40 } ) do local f = getglobal("UIOptionsFrameCheckButton"..idx) f.disabled = true OptionsFrame_DisableCheckBox(f) f:SetChecked(false) end end function main:HideDefaultBars() for _, f in pairs(blizzDefaultBars) do f:Hide() f:ClearAllPoints() f:SetParent(ReAction.recycler) f:SetPoint("TOPLEFT") end MainMenuBar:SetFrameStrata("LOW") -- otherwise it appears on top of bars, if it isn't hidden hooksecurefunc("UIOptionsFrame_Load",disableUIOptions) end --------------------------------------- -- Bar setup and manipulation functions --------------------------------------- -- Reset bars to blizzard defaults function main:ResetBars() if InCombatLockdown() then UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) else self.db.profile.bars = tcopy(ReAction_DefaultBlizzardBars) self:OnProfileEnable() -- treat it like a profile switch end end function main:DestroyAllBars() -- destroy any existing bars for id = 1, table.maxn(self.bars) do self:DestroyBar(id) end end function main:SetupBars() -- set up the bars from the profile -- note the use of table.maxn rather than # or ipairs: -- our array of bars can in fact contain holes for id = 1, table.maxn(self.db.profile.bars) do local config = self.db.profile.bars[id] if config then self.bars[id] = self:CreateBar(config, id) end end -- anchor the bars, have to do this in a second pass because -- they might be anchored to each other in a non-ordered way for _, bar in pairs(self.bars) do if bar ~= EMPTY_BAR_SLOT then bar:ApplyAnchor() end end end function main:CreateBar( config, id ) local buttonType = config.btnConfig and config.btnConfig.type and getglobal(config.btnConfig.type) local subtype = buttonType and buttonType:GetButtonType(config.btnConfig.subtype) if not subtype then self:Print(L["Tried to create a button of unknown type"]) return end local bar = ReBar:new(config, id) -- initialize dewdrop menu dewdrop:Register(bar:GetControlFrame(), 'children', function() dewdrop:FeedAceOptionsTable(ReActionGlobalMenuOptions) dewdrop:FeedAceOptionsTable(GenerateReActionBarOptions(bar,self)) dewdrop:FeedAceOptionsTable(subtype:GenerateOptionsTable(config.btnConfig, function() return bar:GetButtonList() end)) end, 'cursorX', true, 'cursorY', true ) -- register page up/down buttons with ReBound for keybinding ReBound:Register(bar.upArrow) ReBound:Register(bar.downArrow) if not self.locked then bar:ShowControls() end return bar end function main:DestroyBar( id ) local bar = self.bars[id] if bar and bar ~= EMPTY_BAR_SLOT then local cf = bar:GetControlFrame() if cf == dewdrop:GetOpenedParent() then dewdrop:Close() dewdrop:Unregister(cf) end bar:Destroy() -- we can't do tremove because each bar ID is encoded into the -- frame names as they're created. Need a blank entry in the table. -- The nice thing is that table.insert in NewBar() will automatically -- find the lowest numbered nil slot. self.bars[id] = EMPTY_BAR_SLOT end end -- -- this function is a wrapper for CreateBar() which looks up the bar type -- and constructs a new configuration object of the right type. function main:NewBar( type ) if InCombatLockdown() then UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) return end local t = ReAction:GetButtonType(type) if t then local c = tcopy(ReAction_DefaultBarConfig["ReAction"][type]) local id = nil for i = 1, table.maxn(self.bars) + 1 do -- there may be holes, so #self.bars won't work if self.bars[i] == nil or self.bars[i] == EMPTY_BAR_SLOT then id = i break end end self.bars[id] = self:CreateBar(c, id) self.db.profile.bars[id] = c self.bars[id]:ApplyAnchor() self:Unlock() end end -- -- This function is a wrapper for DestroyBar() which does in-combat -- checking and updates the config. function main:DeleteBar(id) if InCombatLockdown() then UIErrorsFrame:AddMessage(SPELL_FAILED_AFFECTING_COMBAT) else if self.bars[id] then self:DestroyBar(id) self.db.profile.bars[id] = nil end end end