Mercurial > wow > reaction
view modules/ReAction_PetAction/ReAction_PetAction.lua @ 93:567a885cdfad
- pet hotkey support
- fixed showgrid when in keybind mode for action buttons
- fixed a typo (bad 'self') in overlay.lua
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Fri, 17 Oct 2008 23:13:44 +0000 |
parents | c2504a8b996c |
children | 39265b16d208 |
line wrap: on
line source
--[[ ReAction Pet Action button module The button module implements standard action button functionality by wrapping Blizzard's PetActionButton frame and associated functions. --]] -- local imports local ReAction = ReAction local L = ReAction.L local _G = _G local CreateFrame = CreateFrame ReAction:UpdateRevision("$Revision$") -- libraries local KB = LibStub("LibKeyBound-1.0") -- module declaration local moduleID = "PetAction" local module = ReAction:NewModule( moduleID ) -- Button class declaration local Button = { } -- module methods function module:OnInitialize() self.db = ReAction.db:RegisterNamespace( moduleID, { profile = { buttons = { } } } ) self.buttons = { } ReAction:RegisterBarOptionGenerator(self, "GetBarOptions") ReAction.RegisterCallback(self, "OnCreateBar") ReAction.RegisterCallback(self, "OnDestroyBar") ReAction.RegisterCallback(self, "OnRefreshBar") ReAction.RegisterCallback(self, "OnEraseBar") ReAction.RegisterCallback(self, "OnRenameBar") ReAction.RegisterCallback(self, "OnConfigModeChanged") KB.RegisterCallback(self, "LIBKEYBOUND_ENABLED") KB.RegisterCallback(self, "LIBKEYBOUND_DISABLED") KB.RegisterCallback(self, "LIBKEYBOUND_MODE_COLOR_CHANGED","LIBKEYBOUND_ENABLED") end function module:OnEnable() ReAction:RegisterBarType(L["Pet Action Bar"], { type = moduleID , defaultButtonSize = 30, defaultBarRows = 1, defaultBarCols = 10, defaultBarSpacing = 8 }) end function module:OnDisable() ReAction:UnregisterBarType(L["Pet Action Bar"]) end function module:OnCreateBar(event, bar, name) if bar.config.type == moduleID then -- auto show/hide when pet exists bar:GetFrame():SetAttribute("unit","pet") if not ReAction:GetConfigMode() then RegisterUnitWatch(bar:GetFrame()) end self:OnRefreshBar(event, bar, name) end end function module:OnRefreshBar(event, bar, name) if bar.config.type == moduleID then if self.buttons[bar] == nil then self.buttons[bar] = { } end local btns = self.buttons[bar] local profile = self.db.profile if profile.buttons[name] == nil then profile.buttons[name] = {} end local btnCfg = profile.buttons[name] local r, c = bar:GetButtonGrid() local n = r*c for i = 1, n do if btnCfg[i] == nil then btnCfg[i] = {} end if btns[i] == nil then local b = Button:New(bar,i,btnCfg[i]) btns[i] = b bar:AddButton(i,b) end btns[i]:Refresh() end for i = n+1, #btns do if btns[i] then bar:RemoveButton(btns[i]) btns[i] = btns[i]:Destroy() if btnCfg[i] then btnCfg[i] = nil end end end end end function module:OnDestroyBar(event, bar, name) if self.buttons[bar] then local btns = self.buttons[bar] for _,b in pairs(btns) do if b then b:Destroy() end end self.buttons[bar] = nil end end function module:OnEraseBar(event, bar, name) self.db.profile.buttons[name] = nil end function module:OnRenameBar(event, bar, oldname, newname) local b = self.db.profile.buttons b[newname], b[oldname] = b[oldname], nil end function module:OnConfigModeChanged(event, mode) for _, buttons in pairs(self.buttons) do for _, b in pairs(buttons) do b:ShowActionIDLabel(mode) end end for _, bar in ReAction:IterateBars() do if bar and self.buttons[bar] then local f = bar:GetFrame() if mode then UnregisterUnitWatch(f) f:Show() else RegisterUnitWatch(f) end end end end function module:LIBKEYBOUND_ENABLED(evt) for _, buttons in pairs(self.buttons) do for _, b in pairs(buttons) do b:SetKeybindMode(true) end end end function module:LIBKEYBOUND_DISABLED(evt) for _, buttons in pairs(self.buttons) do for _, b in pairs(buttons) do b:SetKeybindMode(false) end end end ---- Options ---- function module:GetBarOptions(bar) if bar.config.type == moduleID then return { type = "group", name = L["Pet Buttons"], args = { } } end end ------ Button class ------ -- use-count of action IDs local nActionIDs = NUM_PET_ACTION_SLOTS local ActionIDList = setmetatable( {}, { __index = function(self, idx) if idx == nil then for i = 1, nActionIDs do if rawget(self,i) == nil then rawset(self,i,1) return i end end error("ran out of pet action IDs") else local c = rawget(self,idx) or 0 rawset(self,idx,c+1) return idx end end, __newindex = function(self,idx,value) if value == nil then value = rawget(self,idx) if value == 1 then value = nil elseif value then value = value - 1 end end rawset(self,idx,value) end }) local frameRecycler = {} local trash = CreateFrame("Frame") local KBAttach, GetActionName, GetHotkey, SetKey, FreeKey, ClearBindings, GetBindings do local buttonLookup = setmetatable({},{__mode="kv"}) -- Use KeyBound-1.0 for binding, but use Override bindings instead of -- regular bindings to support multiple profile use. This is a little -- weird with the KeyBound dialog box (which has per-char selector as well -- as an OK/Cancel box) but it's the least amount of effort to implement. function GetActionName(f) local b = buttonLookup[f] if b then return format("%s:%s", b.bar:GetName(), b.idx) end end function GetHotkey(f) local b = buttonLookup[f] if b then return KB:ToShortKey(b:GetConfig().hotkey) end end function SetKey(f, key) local b = buttonLookup[f] if b then local c = b:GetConfig() if c.hotkey then SetOverrideBinding(f, false, c.hotkey, nil) end if key then SetOverrideBindingClick(f, false, key, f:GetName(), nil) end c.hotkey = key b:DisplayHotkey(GetHotkey(f)) end end function FreeKey(f, key) local b = buttonLookup[f] if b then local c = b:GetConfig() if c.hotkey == key then local action = f:GetActionName() SetOverrideBinding(f, false, c.hotkey, nil) c.hotkey = nil b:DisplayHotkey(nil) return action end end return ReAction:FreeOverrideHotkey(key) end function ClearBindings(f) SetKey(f, nil) end function GetBindings(f) local b = buttonLookup[f] if b then return b:GetConfig().hotkey end end function KBAttach( button ) local f = button:GetFrame() f.GetActionName = GetActionName f.GetHotkey = GetHotkey f.SetKey = SetKey f.FreeKey = FreeKey f.ClearBindings = ClearBindings f.GetBindings = GetBindings buttonLookup[f] = button f:SetKey(button:GetConfig().hotkey) ReAction:RegisterKeybindFrame(f) if ReAction:GetKeybindMode() then button.border:SetVertexColor(KB:GetColorKeyBoundMode()) button.border:Show() end end end local meta = { __index = Button } function Button:New( bar, idx, config ) -- create new self self = setmetatable( { bar = bar, idx = idx, config = config, }, meta ) local name = config.name or ("ReAction_%s_%s_%d"):format(bar:GetName(),moduleID,idx) config.name = name self.name = name config.actionID = ActionIDList[config.actionID] -- gets a free one if none configured -- have to recycle frames with the same name: -- otherwise you either get references to old textures because named CreateFrame() -- doesn't overwrite existing globals. Can't set them to nil in the global table, -- as it causes taint. local parent = bar:GetFrame() local f = frameRecycler[name] if f then f:SetParent(parent) else f = CreateFrame("CheckButton", name, parent, "PetActionButtonTemplate") -- ditch the old hotkey text because it's tied in ActionButton_Update() to the -- standard binding. We use override bindings. local hotkey = _G[name.."HotKey"] hotkey:SetParent(trash) hotkey = f:CreateFontString(nil, "ARTWORK", "NumberFontNormalSmallGray") hotkey:SetWidth(36) hotkey:SetHeight(18) hotkey:SetJustifyH("RIGHT") hotkey:SetJustifyV("TOP") hotkey:SetPoint("TOPLEFT",f,"TOPLEFT",-2,-2) f.hotkey = hotkey f:HookScript("OnDragStart", function() self:Update() end) f:HookScript("OnReceiveDrag", function() self:Update() end) end if config.actionID then f:SetID(config.actionID) -- PetActionButtonTemplate isn't a proper SecureActionButton end f:SetFrameStrata("MEDIUM") self.frame = f self.icon = _G[("%sIcon"):format(name)] self.acTex = _G[("%sAutoCastable"):format(name)] self.acModel = _G[("%sShine"):format(name)] self.cooldown = _G[("%sCooldown"):format(name)] self.hotkey = f.hotkey self.border = _G[("%sBorder"):format(name)] f:RegisterEvent("PLAYER_CONTROL_LOST"); f:RegisterEvent("PLAYER_CONTROL_GAINED"); f:RegisterEvent("PLAYER_FARSIGHT_FOCUS_CHANGED"); f:RegisterEvent("UNIT_PET"); f:RegisterEvent("UNIT_FLAGS"); f:RegisterEvent("UNIT_AURA"); f:RegisterEvent("PET_BAR_UPDATE"); f:RegisterEvent("PET_BAR_UPDATE_COOLDOWN"); f:SetScript("OnEvent", function(event,arg1) if event =="PET_BAR_UPDATE_COOLDOWN" then self:UpdateCooldown() elseif event == "UPDATE_BINDINGS" then self:UpdateHotkey() else self:Update() end end) KBAttach(self) self:Refresh() self:SetKeybindMode(ReAction:GetKeybindMode()) return self end function Button:Destroy() local f = self.frame f:UnregisterAllEvents() f:Hide() f:SetParent(UIParent) f:ClearAllPoints() if self.name then frameRecycler[self.name] = f _G[self.name] = nil end if self.config.actionID then ActionIDList[self.config.actionID] = nil end self.frame = nil self.config = nil self.bar = nil end function Button:Refresh() self.bar:PlaceButton(self, 30, 30) self:Update() self:UpdateHotkey() end function Button:GetFrame() return self.frame end function Button:GetName() return self.name end function Button:GetConfig() return self.config end function Button:GetActionID() return self.config.actionID end function Button:Update() local id = self.frame:GetID() local name, subtext, texture, isToken, isActive, autoCastAllowed, autoCastEnabled = GetPetActionInfo(id); local f = self.frame --ReAction:Print(("id %d: '%s', '%s', '%s', '%s', '%s', '%s', '%s'"):format(tostring(id), tostring(name),tostring(subtext),tostring(texture),tostring(isToken),tostring(isActive),tostring(autoCastAllowed),tostring(autoCastEnabled))) if isToken then self.icon:SetTexture(_G[texture]); f.tooltipName = _G[name]; else self.icon:SetTexture(texture); f.tooltipName = name; end f.isToken = isToken; f.tooltipSubtext = subtext; f:SetChecked( isActive and 1 or 0); if autoCastAllowed then self.acTex:Show(); else self.acTex:Hide(); end if autoCastEnabled then AutoCastShine_AutoCastStart(self.acModel) else AutoCastShine_AutoCastStop(self.acModel) end if texture then if GetPetActionSlotUsable(id) then SetDesaturation(self.icon,nil) else SetDesaturation(self.icon,1) end self.icon:Show(); f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2"); else self.icon:Hide(); f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot"); end self:UpdateCooldown() end function Button:UpdateCooldown() local start, duration, enable = GetPetActionCooldown(self.frame:GetID()); CooldownFrame_SetTimer(self.cooldown, start, duration, enable); end function Button:UpdateHotkey() self:DisplayHotkey(GetHotkey(self.frame)) end function Button:ShowActionIDLabel(show) if show then -- store the action ID label in the frame due to frame recycling if not self.actionIDLabel and self:GetActionID() then local label = self.frame:CreateFontString(nil,"OVERLAY","GameFontNormalLarge") label:SetAllPoints() label:SetJustifyH("CENTER") label:SetShadowColor(0,0,0,1) label:SetShadowOffset(2,-2) label:SetText(tostring(self:GetActionID())) self.actionIDLabel = label end self.actionIDLabel:Show() elseif self.actionIDLabel then self.actionIDLabel:Hide() end end function Button:SetKeybindMode(mode) if mode then self.border:SetVertexColor(KB:GetColorKeyBoundMode()) self.border:Show() else self.border:Hide() end end function Button:DisplayHotkey( key ) self.hotkey:SetText(key or "") end