Files
coa-bartender/ActionButton.lua
T
Hendrik Leppkes 5efa96d0ee Added a Leave Vehicle Button to the Main Bar on Slot 12
The Possess Bar usually only uses 10 buttons to the limit of 10 buttons on the pet bar, that leaves button 11 and 12 empty. Button 12 (id 132) is now being used for a Leave Vehicle button to be able to leave vehicles properly.

Without a full 12-Button Main Bar, you probably want to Macro /script VehicleExit();

I may add another form of button for this at some point, but not right now.
2008-10-11 19:37:55 +02:00

667 lines
18 KiB
Lua

--[[
Action Button Template
Note:
Some IDs produce a special behaviour!
- Button ID 132 (Last Button in Possess Bar) Creates a Leave Vehicle Button
]]
local specialButtons = {
[132] = { script = "/script VehicleExit();", icon = "Interface\\Icons\\Spell_Shadow_SacrificialShield", tooltip = LEAVE_VEHICLE}, -- Vehicle Leave Button
}
local Button = CreateFrame("CheckButton")
local Button_MT = {__index = Button}
local onEnter, onLeave, onUpdate, onDragStart, onReceiveDrag
-- upvalues
local _G = _G
local format = string.format
local IsUsableAction = IsUsableAction
local IsActionInRange = IsActionInRange
local LBF = LibStub("LibButtonFacade", true)
local KeyBound = LibStub("LibKeyBound-1.0")
Bartender4.Button = {}
Bartender4.Button.prototype = Button
function Bartender4.Button:Create(id, parent)
local absid = (parent.id - 1) * 12 + id
local name = ("BT4Button%d"):format(absid)
local button = setmetatable(CreateFrame("CheckButton", name.."Secure", parent, "SecureActionButtonTemplate"), Button_MT)
-- work around for "blocked" message when using /click macros
GetClickFrame(name .. "Secure")
button.rid = id
button.id = absid
button.parent = parent
button.stateactions = {}
button:SetFrameStrata("MEDIUM")
button:SetFrameLevel(parent:GetFrameLevel() + 2)
button:SetWidth(36)
button:SetHeight(36)
button:SetPushedTexture("Interface\\Buttons\\UI-Quickslot-Depress")
button:SetHighlightTexture("Interface\\Buttons\\ButtonHilight-Square")
button:GetHighlightTexture():SetBlendMode("ADD")
button:SetCheckedTexture("Interface\\Buttons\\CheckButtonHilight")
button:GetCheckedTexture():SetBlendMode("ADD")
button:SetNormalTexture("")
button.Proxy = CreateFrame("CheckButton", name, button, "ActionButtonTemplate")
button.Proxy:SetFrameStrata("MEDIUM")
button.Proxy:SetFrameLevel(parent:GetFrameLevel() + 1)
button.Proxy:ClearAllPoints()
button.Proxy:SetAllPoints(button)
button.Proxy:SetPushedTexture("")
button.Proxy:SetHighlightTexture("")
button.Proxy:SetCheckedTexture("")
button.Proxy:Show()
button.Proxy.Secure = button
local NormalTexture = button.Proxy:GetNormalTexture()
NormalTexture:SetWidth(66)
NormalTexture:SetHeight(66)
NormalTexture:ClearAllPoints()
NormalTexture:SetPoint("CENTER", 0, -1)
NormalTexture:Show()
button.normalTexture = NormalTexture
button.pushedTexture = button:GetPushedTexture()
button.highlightTexture = button:GetHighlightTexture()
button:SetScript("OnEvent", button.EventHandler)
button:SetScript("OnUpdate", onUpdate)
button:SetScript("OnEnter", onEnter)
button:SetScript("OnLeave", onLeave)
button:SetScript("OnAttributeChanged", button.UpdateAction)
button:SetScript("OnDragStart", onDragStart)
button:SetScript("OnReceiveDrag", onReceiveDrag)
button:SetScript("PostClick", button.UpdateState)
button.icon = _G[("%sIcon"):format(name)]
button.border = _G[("%sBorder"):format(name)]
button.cooldown = _G[("%sCooldown"):format(name)]
button.macroName = _G[("%sName"):format(name)]
button.hotkey = _G[("%sHotKey"):format(name)]
button.count = _G[("%sCount"):format(name)]
button.flash = _G[("%sFlash"):format(name)]
button.flash:Hide()
button.textureCache = {}
button.textureCache.pushed = button.pushedTexture:GetTexture()
button.textureCache.highlight = button.highlightTexture:GetTexture()
button:SetAttribute("type", "action")
button:SetAttribute("action", absid)
button:SetAttribute("checkselfcast", true)
--button:SetAttribute("useparent-unit", true)
button:SetAttribute('_childupdate-state', [[
self:SetAttribute("state", message)
local action = self:GetAttribute("action-" .. message)
local special = self:GetAttribute("special-" .. tostring(action))
if special then
self:SetAttribute("type", "macro")
self:SetAttribute("macrotext", special)
else
self:SetAttribute("type", "action")
end
self:SetAttribute("action", action)
-- fix unit on state change
if self:GetAttribute("assisttype-"..message) == 1 then
self:SetAttribute("unit", G_assist_help)
elseif self:GetAttribute("assisttype-"..message) == 2 then
self:SetAttribute("unit", G_assist_harm)
else
self:SetAttribute("unit", nil)
end
G_state = message
]])
button:SetAttribute('_childupdate-assist-help', [[
if self:GetAttribute("assisttype-"..G_state) == 1 then
self:SetAttribute("unit", message)
end
G_assist_help = message
]])
button:SetAttribute('_childupdate-assist-harm', [[
if self:GetAttribute("assisttype"..G_state) == 2 then
self:SetAttribute("unit", message)
end
G_assist_harm = message
]])
button:RegisterForDrag("LeftButton", "RightButton")
button:RegisterForClicks("AnyUp")
button.showgrid = 0
button.flashing = 0
button.flashtime = 0
for k,v in pairs(specialButtons) do
button:SetAttribute("special-" .. tostring(k), v.script)
end
button:RegisterButtonEvents()
if LBF and parent.LBFGroup then
local group = parent.LBFGroup
button.LBFButtonData = {
Button = button.Proxy,
Highlight = button:GetHighlightTexture(),
Pushed = button:GetPushedTexture(),
Checked = button:GetCheckedTexture(),
}
group:AddButton(button.Proxy, button.LBFButtonData)
end
return button
end
function Button:SetLevels()
local parent = self:GetParent()
self:SetFrameLevel(parent:GetFrameLevel() + 3)
self.Proxy:SetFrameLevel(parent:GetFrameLevel() + 2)
end
function onDragStart(self)
if InCombatLockdown() then return end
if not Bartender4.db.profile.buttonlock or IsModifiedClick("PICKUPACTION") then
PickupAction(self.action)
self:UpdateState()
self:UpdateFlash()
self:RefreshStateAction()
end
end
function onReceiveDrag(self)
if InCombatLockdown() then return end
PlaceAction(self.action)
self:UpdateState()
self:UpdateFlash()
self:RefreshStateAction()
end
function onEnter(self)
if not (Bartender4.db.profile.tooltip == "nocombat" and InCombatLockdown()) and Bartender4.db.profile.tooltip ~= "disabled" then
self:SetTooltip()
end
KeyBound:Set(self)
end
function onLeave()
GameTooltip:Hide()
end
local oor, oorcolor, oomcolor
function onUpdate(self, elapsed)
if self.flashing == 1 then
self.flashtime = self.flashtime - elapsed
if self.flashtime <= 0 then
local overtime = -self.flashtime
if overtime >= ATTACK_BUTTON_FLASH_TIME then
overtime = 0
end
self.flashtime = ATTACK_BUTTON_FLASH_TIME - overtime
local flashTexture = self.flash
if flashTexture:IsVisible() then
flashTexture:Hide()
else
flashTexture:Show()
end
end
end
if self.rangeTimer then
self.rangeTimer = self.rangeTimer - elapsed
if self.rangeTimer <= 0 then
local valid = IsActionInRange(self.action)
local hotkey = self.hotkey
local hkshown = (hotkey:GetText() == RANGE_INDICATOR and oor == "hotkey")
if valid and hkshown then
hotkey:Show()
elseif hkshown then
hotkey:Hide()
end
self.outOfRange = (valid == 0)
self:UpdateUsable()
self.rangeTimer = TOOLTIP_UPDATE_TIME
end
end
end
function Button:ClearStateAction()
for state in pairs(self.stateactions) do
self.stateactions = {}
for i=0,10 do
self:SetAttribute("action-" .. i, nil)
end
end
end
function Button:SetStateAction(state, action)
self.stateactions[state] = action
self:RefreshStateAction(state)
end
function Button:RefreshAllStateActions()
self.stateconfig = {}
for state in pairs(self.stateactions) do
self:RefreshStateAction(state)
end
end
function Button:RefreshStateAction(state)
local state = tonumber(state or self:GetAttribute("state") or 0)
local action = self.stateactions[state]
self:SetAttribute("action-"..state, action)
self:SetAttribute("assisttype-"..state, nil)
self:SetAttribute("unit", nil)
if self.parent.config.autoassist then
local type, id, subtype = GetActionInfo(action)
if type == "spell" and id > 0 then
if IsHelpfulSpell(id, subtype) then
self:SetAttribute("assisttype-"..state, 1)
elseif IsHarmfulSpell(id, subtype) then
self:SetAttribute("assisttype-"..state, 2)
end
end
end
self:UpdateRightClickSelfCast()
end
function Button:UpdateRightClickSelfCast()
if Bartender4.db.profile.selfcastrightclick then
self:SetAttribute("unit2", "player")
else
self:SetAttribute("unit2", nil)
end
end
function Button:CalculateAction()
return SecureButton_GetModifiedAttribute(self, "action", SecureButton_GetEffectiveButton(self)) or 1
end
function Button:GetActionID()
return self.action
end
function Button:UpdateAction(force)
local action = self:CalculateAction()
if action ~= self.action or force then
self.action = action
self:Update()
end
end
function Button:Update()
local action = self.action
self:UpdateIcon()
self:UpdateCount()
self:UpdateHotkeys()
if HasAction(action) or specialButtons[action] then
self:RegisterActionEvents()
self:UpdateState()
self:UpdateUsable(true)
self:UpdateCooldown()
self:UpdateFlash()
self:ShowButton()
self:SetScript("OnUpdate", onUpdate)
else
self:UnregisterActionEvents()
self.cooldown:Hide()
if ( self.showgrid == 0 and not self.parent.config.showgrid ) then
self:HideButton()
end
self:SetScript("OnUpdate", nil)
end
if ( IsEquippedAction(action) ) then
self.border:SetVertexColor(0, 1.0, 0, 0.75)
self.border:Show()
else
self.border:Hide()
end
if ( GameTooltip:GetOwner() == self) then
self:SetTooltip()
end
if not IsConsumableAction(action) and not IsStackableAction(action) and not self.parent.config.hidemacrotext then
self.macroName:SetText(GetActionText(action))
else
self.macroName:SetText("")
end
end
function Button:UpdateIcon()
local texture = specialButtons[self.action] and specialButtons[self.action].icon or GetActionTexture(self.action)
if ( texture ) then
self.rangeTimer = -1
self.icon:SetTexture(texture)
self.icon:Show()
self.normalTexture:SetTexture("Interface\\Buttons\\UI-Quickslot2")
self.normalTexture:SetTexCoord(0, 0, 0, 0)
self.iconTex = texture
else
self.rangeTimer = nil
self.icon:Hide()
self.cooldown:Hide()
self.normalTexture:SetTexture("Interface\\Buttons\\UI-Quickslot")
self.normalTexture:SetTexCoord(-0.15, 1.15, -0.15, 1.17)
self.hotkey:SetVertexColor(0.6, 0.6, 0.6)
self.iconTex = nil
end
if self.parent.config.hidemacrotext then
self.macroName:Hide()
else
self.macroName:Show()
end
end
function Button:UpdateCount()
local action = self.action
if ( IsConsumableAction(action) or IsStackableAction(action) ) then
self.count:SetText(GetActionCount(action))
else
self.count:SetText("")
end
end
function Button:UpdateHotkeys()
local key = self:GetHotkey() or ""
local hotkey = self.hotkey
if key == "" or self.parent.config.hidehotkey or not HasAction(self.action) then
hotkey:SetText(RANGE_INDICATOR)
hotkey:SetPoint("TOPLEFT", self, "TOPLEFT", 1, -2)
hotkey:Hide()
else
hotkey:SetText(key)
hotkey:SetPoint("TOPLEFT", self, "TOPLEFT", -2, -2)
hotkey:Show()
end
end
function Button:GetHotkey()
local key = ((self.id <= 12) and GetBindingKey(format("ACTIONBUTTON%d", self.id))) or GetBindingKey("CLICK "..self:GetName()..":LeftButton")
return key and KeyBound:ToShortKey(key)
end
function Button:GetBindings()
local keys, binding = ""
if self.id <= 12 then
binding = format("ACTIONBUTTON%d", self.id)
for i = 1, select('#', GetBindingKey(binding)) do
local hotKey = select(i, GetBindingKey(binding))
if keys ~= "" then
keys = keys .. ', '
end
keys = keys .. GetBindingText(hotKey,'KEY_')
end
end
binding = "CLICK "..self:GetName()..":LeftButton"
for i = 1, select('#', GetBindingKey(binding)) do
local hotKey = select(i, GetBindingKey(binding))
if keys ~= "" then
keys = keys .. ', '
end
keys = keys .. GetBindingText(hotKey,'KEY_')
end
return keys
end
function Button:SetKey(key)
if self.id <= 12 then
SetBinding(key, format("ACTIONBUTTON%d", self.id))
else
SetBindingClick(key, self:GetName(), 'LeftButton')
end
end
function Button:ClearBindings()
if self.id <= 12 then
local binding = format("ACTIONBUTTON%d", self.id)
while GetBindingKey(binding) do
SetBinding(GetBindingKey(binding), nil)
end
end
local binding = "CLICK "..self:GetName()..":LeftButton"
while GetBindingKey(binding) do
SetBinding(GetBindingKey(binding), nil)
end
end
local actionTmpl = "BT4 Bar %d Button %d"
function Button:GetActionName()
return format(actionTmpl, self.parent.id, self.rid)
end
function Button:UpdateState()
local action = self.action
if ( IsCurrentAction(action) or IsAutoRepeatAction(action) ) then
self:SetChecked(1)
else
self:SetChecked(0)
end
end
function Button:UpdateUsable(force)
local isUsable, notEnoughMana = IsUsableAction(self.action)
local icon, hotkey = self.icon, self.hotkey
if force or not oor then
oor = Bartender4.db.profile.outofrange
oorcolor, oomcolor = Bartender4.db.profile.colors.range, Bartender4.db.profile.colors.mana
end
if oor == "button" and self.outOfRange then
icon:SetVertexColor(oorcolor.r, oorcolor.g, oorcolor.b)
hotkey:SetVertexColor(1.0, 1.0, 1.0)
else
if oor == "hotkey" and self.outOfRange then
hotkey:SetVertexColor(oorcolor.r, oorcolor.g, oorcolor.b)
else
hotkey:SetVertexColor(1.0, 1.0, 1.0)
end
if isUsable or specialButtons[self.action] then
icon:SetVertexColor(1.0, 1.0, 1.0)
elseif notEnoughMana then
icon:SetVertexColor(oomcolor.r, oomcolor.g, oomcolor.b)
else
icon:SetVertexColor(0.4, 0.4, 0.4)
end
end
end
function Button:UpdateCooldown()
local start, duration, enable = GetActionCooldown(self.action)
CooldownFrame_SetTimer(self.cooldown, start, duration, enable)
end
function Button:UpdateFlash()
local action = self.action
if ( (IsAttackAction(action) and IsCurrentAction(action)) or IsAutoRepeatAction(action) ) then
self:StartFlash()
else
self:StopFlash()
end
end
function Button:StartFlash()
self.flashing = 1
self.flashtime = 0
self:UpdateState()
end
function Button:StopFlash()
self.flashing = 0
self.flash:Hide()
self:UpdateState()
end
function Button:SetTooltip()
if ( GetCVar("UberTooltips") == "1" ) then
GameTooltip_SetDefaultAnchor(GameTooltip, self)
else
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
end
if specialButtons[self.action] then
GameTooltip:SetText(specialButtons[self.action].tooltip)
self.UpdateTooltip = self.SetTooltip
else
if ( GameTooltip:SetAction(self.action) ) then
self.UpdateTooltip = self.SetTooltip
else
self.UpdateTooltip = nil
end
end
end
function Button:ShowButton()
if self.Proxy:IsShown() then return end
self.pushedTexture:SetTexture(self.textureCache.pushed)
self.highlightTexture:SetTexture(self.textureCache.highlight)
self.Proxy:Show()
end
function Button:HideButton()
if not self.Proxy:IsShown() then return end
self.textureCache.pushed = self.pushedTexture:GetTexture()
self.textureCache.highlight = self.highlightTexture:GetTexture()
self.pushedTexture:SetTexture("")
self.highlightTexture:SetTexture("")
self.Proxy:Hide()
end
function Button:ShowGrid()
self.showgrid = self.showgrid + 1
self:ShowButton()
end
function Button:HideGrid()
if self.showgrid > 0 then self.showgrid = self.showgrid - 1 end
if ( self.showgrid == 0 and not HasAction(self.action) and not self.parent.config.showgrid ) then
self:HideButton()
end
end
function Button:RegisterButtonEvents()
self:RegisterEvent("ACTIONBAR_SLOT_CHANGED")
self:RegisterEvent("PLAYER_ENTERING_WORLD")
self:RegisterEvent("ACTIONBAR_PAGE_CHANGED")
self:RegisterEvent("ACTIONBAR_SHOWGRID")
self:RegisterEvent("ACTIONBAR_HIDEGRID")
self:RegisterEvent("UPDATE_BINDINGS")
self:RegisterEvent("UPDATE_SHAPESHIFT_FORM")
end
local actionevents = {
"PLAYER_TARGET_CHANGED",
"ACTIONBAR_UPDATE_STATE",
"ACTIONBAR_UPDATE_USABLE",
"ACTIONBAR_UPDATE_COOLDOWN",
--"UPDATE_INVENTORY_ALERTS",
--"PLAYER_AURAS_CHANGED",
"CRAFT_SHOW",
"CRAFT_CLOSE",
"TRADE_SKILL_SHOW",
"TRADE_SKILL_CLOSE",
"PLAYER_ENTER_COMBAT",
"PLAYER_LEAVE_COMBAT",
"START_AUTOREPEAT_SPELL",
"STOP_AUTOREPEAT_SPELL",
}
function Button:RegisterActionEvents()
if self.eventsregistered then return end
self.eventsregistered = true
for _, event in ipairs(actionevents) do
self:RegisterEvent(event)
end
end
function Button:UnregisterActionEvents()
if not self.eventsregistered then return end
self.eventsregistered = nil
for _, event in ipairs(actionevents) do
self:UnregisterEvent(event)
end
end
function Button:EventHandler(event, arg1)
if ( event == "ACTIONBAR_SLOT_CHANGED" ) then
if ( arg1 == 0 or arg1 == self.action ) then
self:Update()
end
elseif ( event == "PLAYER_ENTERING_WORLD" ) then
self:Update()
elseif ( event == "ACTIONBAR_PAGE_CHANGED" or event == "UPDATE_BONUS_ACTIONBAR" ) then
self:UpdateAction()
elseif ( event == "ACTIONBAR_SHOWGRID" ) then
self:ShowGrid()
elseif ( event == "ACTIONBAR_HIDEGRID" ) then
self:HideGrid()
elseif ( event == "UPDATE_BINDINGS" ) then
self:UpdateHotkeys()
elseif not self.eventsregistered then
return
-- Action Event Handlers, only set when the button actually has an action
elseif ( event == "PLAYER_TARGET_CHANGED" ) then
self.rangeTimer = -1
elseif ( event == "ACTIONBAR_UPDATE_STATE" ) then
self:UpdateState()
elseif ( event == "ACTIONBAR_UPDATE_USABLE" ) then
self:UpdateUsable()
elseif ( event == "ACTIONBAR_UPDATE_COOLDOWN" ) then
self:UpdateCooldown()
elseif ( event == "CRAFT_SHOW" or event == "CRAFT_CLOSE" or event == "TRADE_SKILL_SHOW" or event == "TRADE_SKILL_CLOSE" ) then
self:UpdateState()
elseif ( event == "PLAYER_ENTER_COMBAT" ) then
if ( IsAttackAction(self.action) ) then
self:StartFlash()
end
elseif ( event == "PLAYER_LEAVE_COMBAT" ) then
if ( IsAttackAction(self.action) ) then
self:StopFlash()
end
elseif ( event == "START_AUTOREPEAT_SPELL" ) then
if ( IsAutoRepeatAction(self.action) ) then
self:StartFlash()
end
elseif ( event == "STOP_AUTOREPEAT_SPELL" ) then
if ( self.flashing == 1 and not IsAttackAction(self.action) ) then
self:StopFlash()
end
end
end
function Button:ClearSetPoint(...)
self:ClearAllPoints()
self:SetPoint(...)
end