Mercurial > wow > reaction
diff classes/ActionButton.lua @ 122:a2d2f23137c8
- Rearranged and consolidated some files in modules directory
- Added 'classes' directory, moved Bar and Overlay there
- Added Button, ActionButton, and GridProxy classes, not in use yet
author | Flick <flickerstreak@gmail.com> |
---|---|
date | Mon, 23 Feb 2009 18:56:57 +0000 |
parents | |
children | 943eed2c7def |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/classes/ActionButton.lua Mon Feb 23 18:56:57 2009 +0000 @@ -0,0 +1,693 @@ +local ReAction = ReAction +local L = ReAction.L +local _G = _G +local CreateFrame = CreateFrame +local GetBindingKey = GetBindingKey +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 + +ReAction:UpdateRevision("$Revision: 154 $") + +-- +-- 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") + if idx and idx <= 12 then + action = 120 + idx + else + action = 0 + end + elseif page and state and page[state] then + action = self:GetAttribute("action-page"..page[state]) + else + action = self:GetAttribute("default-action") + end + + self:SetAttribute("action",action) + local hasaction = (action > 120) or self:GetAttribute("hasaction-"..action) + + if (self:GetAttribute("showgrid") + self:GetAttribute("showgrid-temp") == 0) and not hasaction then + self:Hide() + else + self:Show() + end +]] + +local _childupdate_vehicleExit = -- function(self, snippetid, message) +[[ + local show = (mcVehicleState == "vehicle") + if show then + self:SetAttribute("type","macro") + self:SetAttribute("macrotext","/run VehicleExit()") + self:Show() + else + self:SetAttribute("type","action") + end + control:CallMethod("ShowVehicleExit",show) +]] + +local _childupdate_showgrid = -- function(self, snippetid, message) +[[ + self:SetAttribute("showgrid-temp",message or 0) + local count = (message or 0) + (self:GetAttribute("showgrid") or 0) + if count == 0 then + local action = self:GetAttribute("action") + local hasaction = (action > 120) or self:GetAttribute("hasaction-"..action) + if hasaction then + self:Show() + else + self:Hide() + end + else + self:Show() + end +]] + +local _onDragStart = -- function(self, button, kind, value, ...) +[[ + if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then + return kind, value, ... + else + -- don't make any assumptions about hiding on grid show here, as we don't know if the + -- drag gets cancelled later. + return "action", self:GetAttribute("action") + end +]] + +local _onReceiveDrag = -- function(self, button, kind, value, ...) +[[ + if lockButtons and (PlayerInCombat() or not lockButtonsCombat) and not IsModifiedClick("PICKUPACTION") then + return kind, value, ... + else + if kind == "spell" or kind == "item" or kind == "macro" then + -- assume it's a valid action + self:SetAttribute("hasaction-"..self:GetAttribute("action"),true) + end + return "action", self:GetAttribute("action") + end +]] + +-- +-- private +-- +local eventList = { + "PLAYER_REGEN_ENABLED", + "PLAYER_ENTERING_WORLD", + "ACTIONBAR_PAGE_CHANGED", + "ACTIONBAR_SLOT_CHANGED", + "UPDATE_BINDINGS", + "ACTIONBAR_UPDATE_STATE", + "ACTIONBAR_UPDATE_USABLE", + "ACTIONBAR_UPDATE_COOLDOWN", + "UPDATE_INVENTORY_ALERTS", + "PLAYER_TARGET_CHANGED", + "TRADE_SKILL_SHOW", + "TRADE_SKILL_CLOSE", + "PLAYER_ENTER_COMBAT", + "PLAYER_LEAVE_COMBAT", + "START_AUTOREPEAT_SPELL", + "STOP_AUTOREPEAT_SPELL", + "UNIT_ENTERED_VEHICLE", + "UNIT_EXITED_VEHICLE", + "COMPANION_UPDATE", +} + +-- +-- Action Button class +-- +local Super = ReAction.Button +local Action = setmetatable( { }, { __index = Super } ) +ReAction.Button.Action = Action + +function Action:New( idx, config, bar, idHint ) + self = Super.New( + self, + format("ReAction_%s_Action_%d",bar:GetName(),idx), + config, + bar, + idx, + "ActionButtonTemplate, SecureActionButtonTemplate" ) + + local f = self:GetFrame() + local barFrame = bar:GetFrame() + + local frames = { } + self.frames = frames + frames.icon = _G[name.."Icon"] + frames.flash = _G[name.."Flash"] + frames.hotkey = _G[name.."HotKey"] + frames.count = _G[name.."Count"] + frames.name = _G[name.."Name"] + frames.border = _G[name.."Border"] + frames.cooldown = _G[name.."Cooldown"] + frames.normalTexture = _G[name.."NormalTexture"] + + self.hotkey = frames.hotkey -- alias for Button methods + self.border = frames.border -- alias for Button methods + + self.rangeTimer = TOOLTIP_UPDATE_TIME + + -- set up the base action ID + self:SetActionIDPool("action",120) + config.actionID = self:AcquireActionID(config.actionID, idHint) + self.actionID = config.actionID + self.nPages = 1 + + -- attribute setup + f:SetAttribute("type","action") + f:SetAttribute("checkselfcast", true) + f:SetAttribute("checkfocuscast", true) + f:SetAttribute("useparent-unit", true) + f:SetAttribute("action", config.actionID) + f:SetAttribute("default-action", config.actionID) + f:SetAttribute("showgrid",0) + f:SetAttribute("showgrid-temp",0) + f:SetAttribute("bar-idx",idx) + + -- 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) + + -- secure handlers + f:SetAttribute("_childupate", _childupdate) + f:SetAttribute("_childupdate-showgrid",_childupdate_showgrid) + barFrame:WrapScript(f, "OnDragStart", _onDragStart) + barFrame:WrapScript(f, "OnReceiveDrag", _onReceiveDrag) + if idx == 7 then + -- install vehicle-exit button on 7th button (only) + f:SetAttribute("_childupdate-vehicle", _childupdate_vehicleExit) + local button = self + function barFrame:ShowVehicleExit(show) + button:ShowVehicleExit(show) + end + end + + -- event registration + f:RegisterForDrag("LeftButton", "RightButton") + f:RegisterForClicks("AnyUp") + for _, evt in pairs(eventList) do + f:RegisterEvent(evt) + end + + -- attach to skinner + bar:SkinButton(self) + + -- initial display + self:ShowGrid(not barFrame:GetConfig().hideEmpty) + if ReAction:GetConfigMode() then + self:ShowGrid(true) + end + + self:Refresh() +end + +function Action:Destroy() + local f = self:GetFrame() + + f:UnregisterAllEvents() + + f:SetAttribute("_childupdate-vehicle",nil) + + self:ReleaseActionID(config.actionID) + if self.config.pageactions then + for _, id in ipairs(self.config.pageactions) do + self:ReleaseActionID(id) + end + end + + Super:Destroy() +end + +function Action:Refresh() + self.bar:PlaceButton(self, 36, 36) + self:RefreshPages() + self:UpdateAction() +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() + -- this is a little bit complicated because there's no + -- secure driver to handle show/hide grid events. + if InCombatLockdown() then + self.showgridPending = true -- handle after combat + else + self.showgridPending = false + -- check if each action has an action or not, and flag an attribute + -- so that the showgrid secure handler can make decisions accordingly + local f = self:GetFrame() + f:SetAttribute("hasaction-"..self.config.actionID, HasAction(self.config.actionID)) + for i = 1, self.nPages do + f:SetAttribute("hasaction-"..self.config.pageactions[i], HasAction(self.config.pageactions[i]) + end + -- the following is an out-of-combat show/hide to supplement the secure + -- handling and clean up after it when it guesses + if HasAction(self.actionID) then + f:Show() + else + f:Hide() + end + end +end + +function Action:UpdateIcon() + local action = self.actionID + local texture = GetActionTexture(action) + local icon = self.frames.icon + local hotkey = self.frames.hotkey + local f = self:GetFrame() + if texture then + icon:SetTexture(texture) + icon:Show() + self.rangeTimer = -1 + f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot2") + hotkey:SetVertexColor(1.0, 1.0, 1.0) + else + icon:Hide() + self.frames.cooldown:Hide() + self.rangeTimer = nil + f:SetNormalTexture("Interface\\Buttons\\UI-Quickslot") + hotkey:SetVertexColor(0.6, 0.6, 0.6) + end + end +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) + 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 = IsUsableAction(self.actionID) + if isUsable then + self.frames.icon:SetVertexColor(1.0, 1.0, 1.0) + self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0) + elseif notEnoughMana then + self.frames.icon:SetVertexColor(0.5, 0.5, 1.0) + self.frames.normalTexture:SetVertexColor(0.5, 0.5, 1.0) + else + self.frames.icon:SetVertexColor(0.4, 0.4, 0.4) + self.frames.normalTexture:SetVertexColor(1.0, 1.0, 1.0) + end +end + +function Action:UpdateCooldown() + CooldownFrame_SetTimer(self.frames.cooldown, 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 + if IsActionInRange(self.actionID) == 0 then + self.frames.icon:SetVertexColor(1.0,0.1,0.1) + else + self:UpdateUsable() + end + frame.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 + error("Action:SetActionID - invalid action ID") + 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.bar:GetConfig().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%d"):format(i),c[i]) + end + for i = nPages+1, #c do + self:ReleaseActionID(c[i]) + c[i] = nil + f:SetAttribute(("action-page%d"):format(i),nil) + end + self.nPages = nPages + end +end + +function Action:SetupBarHeader( bar ) -- call this as a static method + local f = bar:GetFrame() + local c = bar:GetConfig() + f:SetAttribute("mindcontrol",c.mindcontrol) + f:SetAttribute("vehicle",c.vehicle) + f:Execute( + [[ + doMindControl = self:GetAttribute("mindcontrol") + doVehicle = self:GetAttribute("vehicle") + control:ChildUpdate() + ]]) + + f:SetAttribute("_onstate-mc", _onstate_mc) + RegisterStateDriver(f, "mc", "[target=vehicle,exists] vehicle; [bonusbar:5] mc; none") + + f:SetAttribute("lockbuttons",c.lockButtons) + f:SetAttribute("lockbuttonscombat",c.lockButtonsCombat) + f:Execute( + [[ + lockButtons = self:GetAttribute("lockbuttons") + lockButtonsCombat = self:GetAttribute("lockbuttonscombat") + ]]) +end + + +function Action:ShowVehicleExit(show) + local f = self:GetFrame() + local tx = f.vehicleExitTexture + if show then + if not tx then + tx = f:CreateTexture(nil,"ARTWORK") + tx:SetAllPoints() + -- copied from Blizzard/VehicleMenuBar.lua SkinsData + tx:SetTexture("Interface\\Vehicles\\UI-Vehicles-Button-Exit-Up") + tx:SetTexCoord(0.140625, 0.859375, 0.140625, 0.859375) + f.vehicleExitTexture = tx + end + tx:Show() + f.vehicleExitMode = true + elseif tx then + tx:SetTexCoord(0,1,0,1) + tx:Hide() + f.vehicleExitMode = false + end +end + +function Action:OnEnter( ) + self:SetTooltip() +end + +function Action:OnLeave( ) + GameTooltip:Hide() +end + +function Action:OnAttributeChanged( attr, value ) + self:UpdateAction() +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:UpdateAction() + 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 +Action.TRADE_SKILL_SHOW = Action.ACTIONBAR_UPDATE_STATE +Action.TRADE_SKILL_CLOSE = Action.ACTIONBAR_UPDATE_STATE + +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:PLAYER_REGEN_ENABLED() + if self.showgridPending then + self:UpdateShowGrid() + end +end