Mercurial > wow > reaction
view ActionButton.lua @ 276:36a29870bf34
- little bit of code & comment cleanup
- automatically report the version in the TOC
author | Flick |
---|---|
date | Wed, 11 May 2011 11:11:59 -0700 |
parents | 8fde9da21652 |
children | 4e325f1ea6e1 |
line wrap: on
line source
local _, ns = ... local ReAction = ns.ReAction local L = ReAction.L local _G = _G local CreateFrame = CreateFrame local format = string.format local IsUsableAction = IsUsableAction local IsEquippedAction = IsEquippedAction local IsConsumableAction = IsConsumableAction local IsStackableAction = IsStackableAction local GetActionText = GetActionText local GetCVar = GetCVar local GameTooltip_SetDefaultAnchor = GameTooltip_SetDefaultAnchor local IsCurrentAction = IsCurrentAction local IsAutoRepeatAction = IsAutoRepeatAction local IsUsableAction = IsUsableAction local IsAttackAction = IsAttackAction local CooldownFrame_SetTimer = CooldownFrame_SetTimer local GetActionCooldown = GetActionCooldown local GetActionTexture = GetActionTexture local ATTACK_BUTTON_FLASH_TIME = ATTACK_BUTTON_FLASH_TIME local TOOLTIP_UPDATE_TIME = TOOLTIP_UPDATE_TIME local IsActionInRange = IsActionInRange local InCombatLockdown = InCombatLockdown local HasAction = HasAction -- -- Secure snippets -- These are run within the context of the bar's sandbox, as the -- buttons themselves do not have their own sandbox. -- local _onstate_mc = -- function(self, stateid, newstate) [[ local oldMcVehicleState = mcVehicleState mcVehicleState = newstate control:ChildUpdate() if oldMcVehicleState == "vehicle" or mcVehicleState == "vehicle" then control:ChildUpdate("vehicle") end ]] local _childupdate = -- function(self, snippetid, message) [[ local action = nil if (doVehicle and mcVehicleState == "vehicle") or (doMindControl and mcVehicleState == "mc") then local idx = self:GetAttribute("bar-idx") local maxN = (doVehicle and mcVehicleState == "vehicle") and 7 or 12 if idx and idx <= maxN then action = 120 + idx else action = 0 end elseif state and settings[state] and settings[state].page then action = self:GetAttribute("action-"..settings[state].page) end if action == nil then action = self:GetAttribute("default-action") end self:SetAttribute("action",action) if not self:GetAttribute("showgrid") then local tempShow = self:GetAttribute("showgrid-temp") local evtShow = self:GetAttribute("showgrid-event") if tempShow then tempShow = (tempShow > 0) end if evtShow then evtShow = (evtShow > 0) end if tempShow or evtShow or HasAction(action) then self:Show() else self:Hide() end end ]] local _childupdate_vehicleExit = -- function(self, snippetid, message) [[ local show = (mcVehicleState == "vehicle") if show and doVehicle then self:SetAttribute("type","macro") self:Show() else self:SetAttribute("type","action") end control:CallMethod("ShowVehicleExit",show) ]] local _childupdate_showgrid = -- function(self, snippetid, message) [[ showgrid_event = message self:SetAttribute("showgrid-event",message) if not self:GetAttribute("showgrid") then local count = message + (self:GetAttribute("showgrid-temp") or 0) if count <= 0 then local action = self:GetAttribute("action") -- note that HasAction is not updated on the target of a drag until after ACTIONBAR_HIDEGRID -- so, we set a flag for this button in pre-click/receive-drag and check for it here if HasAction(action) or self:GetAttribute("showgrid-clicked") then if not self:IsShown() then self:Show() end self:SetAttribute("showgrid-clicked",false) else if self:IsShown() then self:Hide() end end else self:Show() end end ]] local _onDragStart = -- function(self, button, kind, value, ...) [[ if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then return kind, value, ... else return "action", self:GetAttribute("action") end ]] local _onReceiveDrag = -- function(self, button, kind, value, ...) [[ if kind ~= "spell" and kind ~= "item" and kind ~= "macro" and kind ~= "flyout" and kind ~= "equipmentset" and kind ~= "companion" then return kind, value, ... else if showgrid_event and showgrid_event > 0 then self:SetAttribute("showgrid-clicked",true) end return "action", self:GetAttribute("action") end ]] local _onClick = -- function(self, button, down) [[ if showgrid_event and showgrid_event > 0 then self:SetAttribute("showgrid-clicked",true) end return button ]] -- -- private -- local eventList = { "PLAYER_ENTERING_WORLD", "ACTIONBAR_PAGE_CHANGED", "ACTIONBAR_SLOT_CHANGED", "UPDATE_BINDINGS", "ACTIONBAR_UPDATE_STATE", "ACTIONBAR_UPDATE_USABLE", "ACTIONBAR_UPDATE_COOLDOWN", "UNIT_INVENTORY_CHANGED", "LEARNED_SPELL_IN_TAB", "UPDATE_INVENTORY_ALERTS", "PLAYER_TARGET_CHANGED", "TRADE_SKILL_SHOW", "TRADE_SKILL_CLOSE", "ARCHAEOLOGY_CLOSED", "PLAYER_ENTER_COMBAT", "PLAYER_LEAVE_COMBAT", "START_AUTOREPEAT_SPELL", "STOP_AUTOREPEAT_SPELL", "UNIT_ENTERED_VEHICLE", "UNIT_EXITED_VEHICLE", "COMPANION_UPDATE", } -- -- Action Button class -- local buttonTypeID = "Action" local Super = ReAction.Button local Action = setmetatable( { defaultBarConfig = { type = buttonTypeID, btnWidth = 36, btnHeight = 36, btnRows = 1, btnColumns = 12, spacing = 3, buttons = { }, }, barType = L["Action Bar"], buttonTypeID = buttonTypeID }, { __index = Super } ) ReAction.Button.Action = Action ReAction:RegisterBarType(Action, true) function Action:New( config, bar, idx, idHint ) local name = format("ReAction_%s_Action_%d",bar:GetName(),idx) self = Super.New(self, name, config, bar, idx, "SecureActionButtonTemplate, ActionButtonTemplate" ) self.barConfig = bar:GetConfig() local f = self:GetFrame() local barFrame = bar:GetFrame() self.rangeTimer = TOOLTIP_UPDATE_TIME -- set up the base action ID self:SetActionIDPool("action",120) config.actionID = self:AcquireActionID(config.actionID, idHint) self.nPages = 1 -- attribute setup f:SetAttribute("type","action") f:SetAttribute("checkselfcast", true) f:SetAttribute("checkfocuscast", true) f:SetAttribute("action", config.actionID) f:SetAttribute("default-action", config.actionID) f:SetAttribute("bar-idx",idx) f:SetAttribute("showgrid-temp",0) f:SetAttribute("showgrid-event",0) f:SetAttribute("showgrid",not self:GetBarConfig().hideEmpty) -- non secure scripts f:SetScript("OnEvent", function(frame, ...) self:OnEvent(...) end) f:SetScript("OnEnter", function(frame) self:OnEnter() end) f:SetScript("OnLeave", function(frame) self:OnLeave() end) f:SetScript("OnAttributeChanged", function(frame, attr, value) self:OnAttributeChanged(attr, value) end) f:SetScript("PostClick", function(frame, ...) self:PostClick(...) end) f:SetScript("OnUpdate", function(frame, elapsed) self:OnUpdate(elapsed) end) f:SetScript("OnDragStart", function(frame) self:OnDragStart() end) f:SetScript("OnReceiveDrag", function(frame) self:OnReceiveDrag() end) -- event registration f:RegisterForDrag("LeftButton", "RightButton") for _, evt in pairs(eventList) do f:RegisterEvent(evt) end f.action = config.actionID -- need this to support silly ActionButton_UpdateFlyout. Should not taint anything anymore. -- secure handlers f:SetAttribute("_childupdate", _childupdate) f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid) barFrame:WrapScript(f, "OnDragStart", _onDragStart) barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag) barFrame:WrapScript(f, "OnClick", _onClick) -- attach to skinner bar:SkinButton(self) -- initial display if ReAction:GetConfigMode() then self:ShowGridTemp(true) end self:Refresh() return self end function Action:Destroy() local f = self:GetFrame() local c = self:GetConfig() f:SetAttribute("_childupdate-vehicle",nil) f:SetAttribute("action",c.actionID) -- so that Super.Destroy releases the right one if c.pageactions and #c.pageactions > 1 then for i = 2, #c.pageactions do self:ReleaseActionID(c.pageactions[i]) self:ReleaseActionID(id) end end Super.Destroy(self) end function Action:GetBarConfig() -- this is the per-bar Action module config structure, -- not the config structure of the bar itself return self.barConfig end function Action:Refresh() Super.Refresh(self) self:RefreshPages() self:InstallVehicle() self:ShowGrid(not self:GetBarConfig().hideEmpty) self:UpdateAction() end function Action:InstallVehicle() local f = self:GetFrame() if self.idx == 7 and self:GetBarConfig().vehicle then if not self.vehicleInstalled then self.vehicleInstalled = true -- install vehicle-exit button on 7th button (only) f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit) f:SetAttribute("macrotext","/run VehicleExit()") self:GetBar():GetFrame().ShowVehicleExit = function(bar,show) self:ShowVehicleExit(show) end end -- setscale blows away tex coords self:UpdateIcon() elseif self.vehicleInstalled then self.vehicleInstalled = false f:SetAttribute("_childupdate-vehicle",nil) f:SetAttribute("macrotext",nil) end end function Action:ShowGrid( show ) if not InCombatLockdown() then self.frame:SetAttribute("showgrid", show) self:UpdateShowGrid() end end function Action:ShowGridTemp( show ) -- This function only modifies the show-grid when out -- of combat, and is ignored by the secure handler. Use -- it for configuration modes. if not InCombatLockdown() then local count = self.showGridTempCount or 0 if show then count = count + 1 else count = count - 1 end if count < 0 then count = 0 end self.showGridTempCount = count self:GetFrame():SetAttribute("showgrid-temp",count) self:UpdateShowGrid() end end function Action:UpdateAll() self:UpdateActionIDLabel(ReAction:GetConfigMode()) self:UpdateHotkey() self:UpdateShowGrid() self:UpdateIcon() self:UpdateBorder() self:UpdateMacroText() self:UpdateCount() self:UpdateTooltip() self:UpdateCheckedState() self:UpdateUsable() self:UpdateCooldown() self:UpdateFlash() end function Action:UpdateAction() local action = self:GetActionID() if action ~= self.actionID then self.actionID = action self:UpdateAll() end end function Action:UpdateShowGrid() if not InCombatLockdown() then local f = self:GetFrame() local count = (f:GetAttribute("showgrid-event") or 0) + (self.showGridTempCount or 0) + (f:GetAttribute("showgrid") and 1 or 0) if count <= 0 and not HasAction(self.actionID) then if f:IsShown() then f:Hide() end elseif not f:IsShown() then f:Show() end end end function Action:UpdateIcon() local texture, tLeft, tRight, tTop, tBottom = self:GetIconTexture() local icon = self.frames.icon local hotkey = self.frames.hotkey local f = self:GetFrame() if self.vehicleExitMode then texture = "Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up" icon:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375) icon:SetVertexColor(1,1,1) else icon:SetTexCoord(0,1,0,1) end if texture then icon:SetTexture(texture) if tLeft then icon:SetTexCoord(tLeft,tRight,tTop,tBottom) end icon:Show() self.rangeTimer = -1 f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") else icon:Hide() self.frames.cooldown:Hide() self.rangeTimer = nil f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot") end end function Action:GetIconTexture() return GetActionTexture(self.actionID) end function Action:UpdateBorder() local action = self.actionID if ReAction:GetKeybindMode() then self:UpdateKeybindModeDisplay(true) elseif IsEquippedAction(action) then self.frames.border:SetVertexColor(0, 1.0, 0, 0.35) self.frames.border:Show() else self.frames.border:Hide() end end function Action:UpdateMacroText() local action = self.actionID if not IsConsumableAction(action) and not IsStackableAction(action) then self.frames.name:SetText(GetActionText(action)) else self.frames.name:SetText("") end end function Action:UpdateCount() local action = self.actionID if IsConsumableAction(action) or IsStackableAction(action) then self.frames.count:SetText(GetActionCount(action)) else self.frames.count:SetText("") end end function Action:UpdateTooltip() local f = self:GetFrame() if GameTooltip:GetOwner() == f then self:SetTooltip() end end function Action:SetTooltip() local f = self:GetFrame() if GetCVar("UberTooltips") == "1" then GameTooltip_SetDefaultAnchor(GameTooltip, f) else GameTooltip:SetOwner(f,"ANCHOR_RIGHT") end GameTooltip:SetAction(self.actionID) end function Action:UpdateCheckedState() local action = self.actionID if IsCurrentAction(action) or IsAutoRepeatAction(action) then self:GetFrame():SetChecked(1) else self:GetFrame():SetChecked(0) end end function Action:UpdateUsable() local isUsable, notEnoughMana = self:GetUsable() local noRange = self:GetInRange() isUsable = self.vehicleExitMode or (isUsable and not noRange) if isUsable then if self.usableStatus ~= "usable" then self.frames.icon:SetVertexColor(1.0, 1.0, 1.0) self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0) self.usableStatus = "usable" end elseif noRange then if self.usableStatus ~= "norange" then self.frames.icon:SetVertexColor(1.0,0.1,0.1) self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0) self.usableStatus = "norange" end elseif notEnoughMana then if self.usableStatus ~= "oom" then self.frames.icon:SetVertexColor(0.5, 0.5, 1.0) self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0) self.usableStatus = "oom" end else if self.usableStatus ~= "unusable" then self.frames.icon:SetVertexColor(0.4, 0.4, 0.4) self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0) self.usableStatus = "unusable" end end end function Action:GetUsable() return IsUsableAction(self.actionID) end function Action:GetInRange() return IsActionInRange(self.actionID) == 0 end function Action:UpdateCooldown() CooldownFrame_SetTimer(self.frames.cooldown, self:GetCooldown()) end function Action:GetCooldown() return GetActionCooldown(self.actionID) end function Action:UpdateFlash() local action = self.actionID self:SetFlash( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) ) end function Action:SetFlash(flash) if self.flashing ~= flash then self.flashing = flash self.flashtime = 0 if not flash then self.frames.flash:Hide() end self:UpdateCheckedState() end end function Action:RunFlash(elapsed) if self.flashing then local flashtime = self.flashtime - elapsed self.flashtime = flashtime if flashtime <= 0 then local overtime = -flashtime if overtime >= ATTACK_BUTTON_FLASH_TIME then overtime = 0 end flashtime = ATTACK_BUTTON_FLASH_TIME - overtime local flash = self.frames.flash if flash:IsShown() then flash:Hide() else flash:Show() end end end end function Action:RunRangeFinder(elapsed) local rangeTimer = self.rangeTimer if rangeTimer then rangeTimer = rangeTimer - elapsed self.rangeTimer = rangeTimer if rangeTimer <= 0 then self:UpdateUsable() self.rangeTimer = TOOLTIP_UPDATE_TIME end end end function Action:GetActionID(page) if page == nil then -- get the effective ID return self:GetFrame():GetAttribute("action") else if page == 1 then return self.config.actionID else return self.config.pageactions and self.config.pageactions[page] or self.config.actionID end end end function Action:SetActionID( id, page ) id = tonumber(id) page = tonumber(page) if id == nil or id < 1 or id > 120 then ReAction:UserError(L["Action ID range is 1-120"]) return end if page and page ~= 1 then if not self.config.pageactions then self.config.pageactions = { } end self:ReleaseActionID(self.config.pageactions[page]) self.config.pageactions[page] = id self:AcquireActionID(self.config.pageactions[page]) self.frame:SetAttribute("action-page"..page,id) else self:ReleaseActionID(self.config.actionID) self.config.actionID = id self:AcquireActionID(self.config.actionID) self.frame:SetAttribute("action",id) self.frame:SetAttribute("default-action",id) if self.config.pageactions then self.config.pageactions[1] = id self.frame:SetAttribute("action-page1",id) end end end function Action:RefreshPages( force ) local nPages = self:GetBarConfig().nPages if nPages and (nPages ~= self.nPages or force) then local f = self:GetFrame() local c = self.config.pageactions if nPages > 1 and not c then c = { } self.config.pageactions = c end for i = 1, nPages do if i > 1 then c[i] = self:AcquireActionID(c[i], self.config.actionID + (i-1)*self.bar:GetNumButtons()) else c[i] = self.config.actionID -- page 1 is the same as the base actionID end f:SetAttribute("action-page"..i,c[i]) end for i = nPages+1, #c do self:ReleaseActionID(c[i]) c[i] = nil f:SetAttribute("action-page"..i,nil) end self.nPages = nPages end end function Action:SetupBar( bar ) Super.SetupBar(self,bar) local f = bar:GetFrame() local config = bar:GetConfig() f:SetAttribute("mindcontrol",config.mindcontrol) f:SetAttribute("vehicle",config.vehicle) f:Execute( [[ doMindControl = self:GetAttribute("mindcontrol") doVehicle = self:GetAttribute("vehicle") control:ChildUpdate() ]]) f:SetAttribute("_onstate-mc", _onstate_mc) RegisterStateDriver(f, "mc", "[vehicleui] vehicle; [bonusbar:5] mc; none") f:SetAttribute("lockbuttons",config.lockButtons) f:SetAttribute("lockbuttonscombat",config.lockButtonsCombat) f:Execute( [[ lockButtons = self:GetAttribute("lockbuttons") lockButtonsCombat = self:GetAttribute("lockbuttonscombat") ]]) end function Action:SetButtonLock( bar, lock, lockCombat ) local f = bar:GetFrame() f:SetAttribute("lockbuttons",lock) f:SetAttribute("lockbuttonscombat",lockCombat) f:Execute( [[ lockButtons = self:GetAttribute("lockbuttons") lockButtonsCombat = self:GetAttribute("lockbuttonscombat") ]]) end function Action:ShowVehicleExit(show) self.vehicleExitMode = show and self:GetBarConfig().vehicle self:UpdateIcon() end function Action:OnEnter( ) self:SetTooltip() end function Action:OnLeave( ) GameTooltip:Hide() end function Action:OnAttributeChanged( attr, value ) if attr ~= "statehidden" then self:UpdateAction() end local f = self:GetFrame() f.action = f:GetAttribute("action") -- support ActionButton_UpdateFlyout end function Action:PostClick( ) self:UpdateCheckedState() end function Action:OnUpdate( elapsed ) self:RunFlash(elapsed) self:RunRangeFinder(elapsed) end function Action:OnDragStart() self:UpdateCheckedState() self:UpdateFlash() end function Action:OnReceiveDrag() self:UpdateCheckedState() self:UpdateFlash() end function Action:OnEvent(event, ...) if self[event] then self[event](self, event, ...) end end function Action:ACTIONBAR_SLOT_CHANGED(event, action) if action == 0 or action == self.actionID then self:UpdateAll() end end function Action:PLAYER_ENTERING_WORLD() self:UpdateAction() end function Action:ACTIONBAR_PAGE_CHANGED() self:UpdateAction() end function Action:UPDATE_BONUS_ACTIONBAR() self:UpdateAction() end function Action:UPDATE_BINDINGS() self:UpdateHotkey() end function Action:PLAYER_TARGET_CHANGED() self.rangeTimer = -1 end function Action:ACTIONBAR_UPDATE_STATE() self:UpdateCheckedState() end function Action:TRADE_SKILL_SHOW() self:UpdateCheckedState() end Action.TRADE_SKILL_CLOSE = Action.TRADE_SKILL_SHOW Action.ARCHAEOLOGY_CLOSED = Action.TRADE_SKILL_SHOW function Action:UNIT_ENTERED_VEHICLE(event,unit) if unit == "player" then self:UpdateCheckedState() end end Action.UNIT_EXITED_VEHICLE = Action.UNIT_ENTERED_VEHICLE function Action:COMPANION_UPDATE(event,unit) if unit == "mount" then self:UpdateCheckedState() end end function Action:ACTIONBAR_UPDATE_USABLE() self:UpdateUsable() end function Action:ACTIONBAR_UPDATE_COOLDOWN() self:UpdateCooldown() end function Action:PLAYER_ENTER_COMBAT() if IsAttackAction(self.actionID) then self:SetFlash(true) end end function Action:PLAYER_LEAVE_COMBAT() if IsAttackAction(self.actionID) then self:SetFlash(false) end end function Action:START_AUTOREPEAT_SPELL() if IsAutoRepeatAction(self.actionID) then self:SetFlash(true) end end function Action:STOP_AUTOREPEAT_SPELL() if not IsAttackAction(self.actionID) then self:SetFlash(false) end end function Action:UNIT_INVENTORY_CHANGED(unit) if unit == "player" then self:UpdateTooltip() end end function Action:LEARNED_SPELL_IN_TAB() self:UpdateTooltip() end