You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
973 lines
31 KiB
973 lines
31 KiB
|
3 years ago
|
-- Neuron is a World of Warcraft® user interface addon.
|
||
|
|
-- Copyright (c) 2017-2021 Britt W. Yazel
|
||
|
|
-- Copyright (c) 2006-2014 Connor H. Chenoweth
|
||
|
|
-- This code is licensed under the MIT license (see LICENSE for details)
|
||
|
|
|
||
|
|
local _, addonTable = ...
|
||
|
|
local Neuron = addonTable.Neuron
|
||
|
|
|
||
|
|
local Spec = addonTable.utilities.Spec
|
||
|
|
|
||
|
|
---@class ActionButton : Button @define class ActionButton inherits from class Button
|
||
|
|
local ActionButton = setmetatable({}, {__index = Neuron.Button}) --this is the metatable for our button object
|
||
|
|
Neuron.ActionButton = ActionButton
|
||
|
|
|
||
|
|
---------------------------------------------------------
|
||
|
|
-------------------declare globals-----------------------
|
||
|
|
---------------------------------------------------------
|
||
|
|
|
||
|
|
local COMMAND_LIST = {
|
||
|
|
[SLASH_CAST1] = true,
|
||
|
|
[SLASH_CAST2] = true,
|
||
|
|
[SLASH_CAST3] = true,
|
||
|
|
[SLASH_CAST4] = true,
|
||
|
|
[SLASH_CASTRANDOM1] = true,
|
||
|
|
[SLASH_CASTRANDOM2] = true,
|
||
|
|
[SLASH_CASTSEQUENCE1] = true,
|
||
|
|
[SLASH_CASTSEQUENCE2] = true,
|
||
|
|
[SLASH_EQUIP1] = true,
|
||
|
|
[SLASH_EQUIP2] = true,
|
||
|
|
[SLASH_EQUIP3] = true,
|
||
|
|
[SLASH_EQUIP4] = true,
|
||
|
|
[SLASH_EQUIP_TO_SLOT1] = true,
|
||
|
|
[SLASH_EQUIP_TO_SLOT2] = true,
|
||
|
|
[SLASH_USE1] = true,
|
||
|
|
[SLASH_USE2] = true,
|
||
|
|
[SLASH_USERANDOM1] = true,
|
||
|
|
[SLASH_USERANDOM2] = true,
|
||
|
|
["/cast"] = true,
|
||
|
|
["/castrandom"] = true,
|
||
|
|
["/castsequence"] = true,
|
||
|
|
["/spell"] = true,
|
||
|
|
["/equip"] = true,
|
||
|
|
["/eq"] = true,
|
||
|
|
["/equipslot"] = true,
|
||
|
|
["/use"] = true,
|
||
|
|
["/userandom"] = true,
|
||
|
|
["/summonpet"] = true,
|
||
|
|
["/click"] = true,
|
||
|
|
["#showtooltip"] = true,
|
||
|
|
}
|
||
|
|
|
||
|
|
---Constructor: Create a new Neuron Button object (this is the base object for all Neuron button types)
|
||
|
|
---@param bar Bar @Bar Object this button will be a child of
|
||
|
|
---@param buttonID number @Button ID that this button will be assigned
|
||
|
|
---@param defaults table @Default options table to be loaded onto the given button
|
||
|
|
---@return ActionButton @ A newly created ActionButton object
|
||
|
|
function ActionButton.new(bar, buttonID, defaults)
|
||
|
|
--call the parent object constructor with the provided information specific to this button type
|
||
|
|
local newButton = Neuron.Button.new(bar, buttonID, ActionButton, "ActionBar", "ActionButton", "NeuronActionButtonTemplate")
|
||
|
|
|
||
|
|
if defaults then
|
||
|
|
newButton:SetDefaults(defaults)
|
||
|
|
end
|
||
|
|
|
||
|
|
return newButton
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:InitializeButton()
|
||
|
|
self:ClearButton(true)
|
||
|
|
|
||
|
|
SecureHandler_OnLoad(self)
|
||
|
|
|
||
|
|
if self.class ~= "flyout" then
|
||
|
|
self:SetupEvents()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAttribute("type", "macro")
|
||
|
|
self:SetAttribute("*macrotext*", self.SanitizedMacro(self:GetMacroText()))
|
||
|
|
|
||
|
|
self:SetAttribute("hotkeypri", self.keys.hotKeyPri)
|
||
|
|
self:SetAttribute("hotkeys", self.keys.hotKeys)
|
||
|
|
|
||
|
|
self:SetScript("PostClick", function(_, mousebutton) self:PostClick(mousebutton) end)
|
||
|
|
self:SetScript("OnReceiveDrag", function(_, preclick) self:OnReceiveDrag(preclick) end)
|
||
|
|
self:SetScript("OnDragStart", function(_, mousebutton) self:OnDragStart(mousebutton) end)
|
||
|
|
|
||
|
|
--this is to allow for the correct releasing of the button when dragging icons off of the bar
|
||
|
|
--we need to hook to the WorldFrame OnReceiveDrag and OnMouseDown so that we can "let go" of the spell when we drag it off the bar
|
||
|
|
if not Neuron:IsHooked(WorldFrame, "OnReceiveDrag") then
|
||
|
|
Neuron:HookScript(WorldFrame, "OnReceiveDrag", function() ActionButton:WorldFrame_OnReceiveDrag() end)
|
||
|
|
end
|
||
|
|
if not Neuron:IsHooked(WorldFrame, "OnMouseDown") then
|
||
|
|
Neuron:HookScript(WorldFrame, "OnMouseDown", function() ActionButton:WorldFrame_OnReceiveDrag() end)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetScript("OnAttributeChanged", function(_, name, value) self:OnAttributeChanged(name, value) end)
|
||
|
|
self:SetScript("OnEnter", function() self:UpdateTooltip() end)
|
||
|
|
self:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
||
|
|
|
||
|
|
if Neuron.isWoWRetail then
|
||
|
|
self:SetAttribute("overrideID_Offset", 204)
|
||
|
|
self:SetAttribute("vehicleID_Offset", 180)
|
||
|
|
self:SetAttribute("dragonridingID_Offset", 120)
|
||
|
|
else
|
||
|
|
self:SetAttribute("overrideID_Offset", 156)
|
||
|
|
self:SetAttribute("vehicleID_Offset", 132)
|
||
|
|
end
|
||
|
|
|
||
|
|
--This is so that hotkeypri works properly with priority/locked buttons
|
||
|
|
self:WrapScript(self, "OnShow", [[
|
||
|
|
for i=1,select('#',(":"):split(self:GetAttribute("hotkeys"))) do
|
||
|
|
self:SetBindingClick(self:GetAttribute("hotkeypri"), select(i,(":"):split(self:GetAttribute("hotkeys"))), self:GetName())
|
||
|
|
end
|
||
|
|
]])
|
||
|
|
|
||
|
|
self:SetFrameRef("uiparent", UIParent)
|
||
|
|
self:WrapScript(self, "OnHide", [[
|
||
|
|
UIParent = self:GetFrameRef("uiparent")
|
||
|
|
if (not self:GetParent():GetAttribute("concealed")) and (not UIParent:IsShown() == false) then
|
||
|
|
for key in gmatch(self:GetAttribute("hotkeys"), "[^:]+") do
|
||
|
|
self:ClearBinding(key)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
]])
|
||
|
|
|
||
|
|
self:SetAttribute("_childupdate",
|
||
|
|
[[
|
||
|
|
if message then
|
||
|
|
local msg = (":"):split(message)
|
||
|
|
|
||
|
|
if msg:find("vehicle") then
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("vehicleID_Offset"))
|
||
|
|
end
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
elseif msg:find("dragonriding") then
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("dragonridingID_Offset"))
|
||
|
|
end
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
elseif msg:find("possess") then
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("vehicleID_Offset"))
|
||
|
|
end
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
elseif msg:find("override") then
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("overrideID_Offset"))
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
end
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
else
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "macro")
|
||
|
|
self:SetAttribute("*macrotext*", self:GetAttribute(msg.."-macro_Text"))
|
||
|
|
|
||
|
|
--if there is a macro present, or if showGrid is enabled, show the button. If not, hide it. This works in combat.
|
||
|
|
if (self:GetAttribute("*macrotext*") and #self:GetAttribute("*macrotext*") > 0) or self:GetAttribute("showGrid") then
|
||
|
|
self:Show()
|
||
|
|
else
|
||
|
|
self:Hide()
|
||
|
|
end
|
||
|
|
self:SetAttribute("HasActionID", false)
|
||
|
|
|
||
|
|
else
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
self:SetAttribute("activestate", msg)
|
||
|
|
end
|
||
|
|
]])
|
||
|
|
|
||
|
|
--this is our rangecheck timer for each button. Every 0.5 seconds it queries if the button is usable
|
||
|
|
--this doubles our CPU usage, but it really helps usability quite a bit
|
||
|
|
--this is a direct replacement to the old "onUpdate" code that did this job
|
||
|
|
|
||
|
|
if self:TimeLeft(self.rangeTimer) == 0 then
|
||
|
|
self.rangeTimer = self:ScheduleRepeatingTimer("UpdateUsable", 0.5)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:UpdateAll()
|
||
|
|
self:UpdateFlyout(true)
|
||
|
|
|
||
|
|
self:InitializeButtonSettings()
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:InitializeButtonSettings()
|
||
|
|
self:SetFrameStrata(Neuron.STRATAS[self.bar:GetStrata()-1])
|
||
|
|
self:SetScale(self.bar:GetBarScale())
|
||
|
|
|
||
|
|
if self.bar:GetShowBindText() then
|
||
|
|
self.Hotkey:Show()
|
||
|
|
self.Hotkey:SetTextColor(self.bar:GetBindColor()[1],self.bar:GetBindColor()[2],self.bar:GetBindColor()[3])
|
||
|
|
else
|
||
|
|
self.Hotkey:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
if self.bar:GetShowButtonText() then
|
||
|
|
self.Name:Show()
|
||
|
|
self.Name:SetTextColor(self.bar:GetMacroColor()[1],self.bar:GetMacroColor()[2],self.bar:GetMacroColor()[3])
|
||
|
|
else
|
||
|
|
self.Name:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
if self.bar:GetShowCountText() then
|
||
|
|
self.Count:Show()
|
||
|
|
self.Count:SetTextColor(self.bar:GetCountColor()[1],self.bar:GetCountColor()[2],self.bar:GetCountColor()[3])
|
||
|
|
else
|
||
|
|
self.Count:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
--[[
|
||
|
|
if self.bar:GetClickMode() == "UpClick" then
|
||
|
|
self:RegisterForClicks("AnyUp")
|
||
|
|
elseif self.bar:GetClickMode() == "DownClick" then
|
||
|
|
self:RegisterForClicks("AnyDown")
|
||
|
|
end
|
||
|
|
]]
|
||
|
|
self:RegisterForClicks("AnyUp")
|
||
|
|
|
||
|
|
self:RegisterForDrag("LeftButton", "RightButton")
|
||
|
|
self:SetSkinned()
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
function ActionButton:SetupEvents()
|
||
|
|
self:RegisterEvent("PLAYER_ENTERING_WORLD")
|
||
|
|
|
||
|
|
self:RegisterEvent("UPDATE_MACROS")
|
||
|
|
|
||
|
|
self:RegisterEvent("ACTIONBAR_SLOT_CHANGED", "UpdateAll")
|
||
|
|
self:RegisterEvent("ACTIONBAR_UPDATE_COOLDOWN", "UpdateCooldown")
|
||
|
|
|
||
|
|
self:RegisterEvent("SPELL_UPDATE_CHARGES", "UpdateCount")
|
||
|
|
|
||
|
|
self:RegisterEvent("PLAYER_EQUIPMENT_CHANGED", "UpdateAll")
|
||
|
|
|
||
|
|
self:RegisterEvent("SPELLS_CHANGED", "UpdateAll")
|
||
|
|
self:RegisterEvent("MODIFIER_STATE_CHANGED", "UpdateAll")
|
||
|
|
|
||
|
|
self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")
|
||
|
|
self:RegisterEvent("UNIT_SPELLCAST_FAILED", "UNIT_SPELLCAST_INTERRUPTED")
|
||
|
|
|
||
|
|
self:RegisterEvent("BAG_UPDATE_COOLDOWN", "UpdateStatus")
|
||
|
|
self:RegisterEvent("BAG_UPDATE", "UpdateStatus")
|
||
|
|
|
||
|
|
self:RegisterEvent("PLAYER_STARTED_MOVING", "UpdateUsable")
|
||
|
|
self:RegisterEvent("PLAYER_STOPPED_MOVING", "UpdateUsable")
|
||
|
|
|
||
|
|
self:RegisterEvent("ACTIONBAR_UPDATE_USABLE", "UpdateUsable")
|
||
|
|
|
||
|
|
self:RegisterEvent("ACTIONBAR_UPDATE_STATE", "UpdateAll")
|
||
|
|
self:RegisterEvent("TRADE_SKILL_SHOW", "UpdateAll")
|
||
|
|
self:RegisterEvent("TRADE_SKILL_CLOSE", "UpdateAll")
|
||
|
|
self:RegisterEvent("PLAYER_TARGET_CHANGED", "UpdateAll")
|
||
|
|
self:RegisterEvent("UNIT_PET", "UpdateAll")
|
||
|
|
|
||
|
|
if Neuron.isWoWRetail then
|
||
|
|
self:RegisterEvent("EQUIPMENT_SETS_CHANGED")
|
||
|
|
|
||
|
|
self:RegisterEvent("UNIT_ENTERED_VEHICLE", "UpdateAll")
|
||
|
|
self:RegisterEvent("UNIT_ENTERING_VEHICLE", "UpdateAll")
|
||
|
|
self:RegisterEvent("UNIT_EXITED_VEHICLE", "UpdateAll")
|
||
|
|
self:RegisterEvent("PLAYER_FOCUS_CHANGED", "UpdateAll")
|
||
|
|
self:RegisterEvent("COMPANION_UPDATE", "UpdateAll")
|
||
|
|
|
||
|
|
self:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_SHOW", "UpdateGlow")
|
||
|
|
self:RegisterEvent("SPELL_ACTIVATION_OVERLAY_GLOW_HIDE", "UpdateGlow")
|
||
|
|
|
||
|
|
self:RegisterEvent("UPDATE_VEHICLE_ACTIONBAR", "UpdateAll")
|
||
|
|
self:RegisterEvent("UPDATE_POSSESS_BAR", "UpdateAll")
|
||
|
|
self:RegisterEvent("UPDATE_OVERRIDE_ACTIONBAR", "UpdateAll")
|
||
|
|
self:RegisterEvent("UPDATE_BONUS_ACTIONBAR", "UpdateAll")
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:OnAttributeChanged(name, value)
|
||
|
|
if value and self.data then
|
||
|
|
if name == "activestate" then
|
||
|
|
--Part 2 of Druid Prowl overwrite fix (part 1 below)
|
||
|
|
-----------------------------------------------------
|
||
|
|
--breaks out of the loop due to flag set below
|
||
|
|
if Neuron.class == "DRUID" and self.ignoreNextOverrideStance == true and value == "homestate" then
|
||
|
|
self.ignoreNextOverrideStance = nil
|
||
|
|
self.bar:SetState("stealth") --have to add this in otherwise the button icons change but still retain the homestate ability actions
|
||
|
|
return
|
||
|
|
else
|
||
|
|
self.ignoreNextOverrideStance = nil
|
||
|
|
end
|
||
|
|
-----------------------------------------------------
|
||
|
|
-----------------------------------------------------
|
||
|
|
|
||
|
|
if self:GetAttribute("HasActionID") then
|
||
|
|
self.actionID = self:GetAttribute("*action*")
|
||
|
|
else
|
||
|
|
--clear any actionID that has been set
|
||
|
|
self.actionID = nil
|
||
|
|
|
||
|
|
--this is a safety check in case the state we're switching into doesn't have table set up for it yet
|
||
|
|
-- i.e. stealth1 or stance2
|
||
|
|
if not self.statedata[value] then
|
||
|
|
self.statedata[value] = {}
|
||
|
|
end
|
||
|
|
|
||
|
|
--Part 1 of Druid Prowl overwrite fix
|
||
|
|
---------------------------------------------------
|
||
|
|
--druids have an issue where once stance will get immediately overwritten by another. I.E. stealth immediately getting overwritten by homestate if they go immediately into prowl from caster form
|
||
|
|
--this conditional sets a flag to ignore the next most stance flag, as that one is most likely in error and should be ignored
|
||
|
|
if Neuron.class == "DRUID" and value == "stealth1" then
|
||
|
|
self.ignoreNextOverrideStance = true
|
||
|
|
end
|
||
|
|
------------------------------------------------------
|
||
|
|
------------------------------------------------------
|
||
|
|
|
||
|
|
--swap out our data with the data stored for the particular state
|
||
|
|
self.data = self.statedata[value]
|
||
|
|
self:ClearButton()
|
||
|
|
end
|
||
|
|
|
||
|
|
--This will remove any old button state data from the saved variable's memory
|
||
|
|
for id,data in pairs(self.statedata) do
|
||
|
|
if (self.bar.data[id:match("%a+")] or id == "") and self.bar.data["custom"] then
|
||
|
|
elseif not self.bar.data[id:match("%a+")] then
|
||
|
|
self.statedata[id]= nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
self:UpdateAll()
|
||
|
|
end
|
||
|
|
|
||
|
|
if name == "update" then
|
||
|
|
self:UpdateAll()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
function ActionButton:OnLeave(...)
|
||
|
|
GameTooltip:Hide()
|
||
|
|
|
||
|
|
if self.flyout and self.flyout.arrow then
|
||
|
|
self.flyout.arrow:SetPoint(self.flyout.arrowPoint, self.flyout.arrowX, self.flyout.arrowY)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
------------------------------------------------------------
|
||
|
|
--------------General Button Methods------------------------
|
||
|
|
------------------------------------------------------------
|
||
|
|
|
||
|
|
function ActionButton:GetDragAction()
|
||
|
|
return "macro"
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:ClearButton(clearAttributes)
|
||
|
|
self.spell = nil
|
||
|
|
self.spellID = nil
|
||
|
|
self.item = nil
|
||
|
|
self.unit = nil
|
||
|
|
|
||
|
|
if not InCombatLockdown() and clearAttributes then
|
||
|
|
self:SetAttribute("unit", nil)
|
||
|
|
self:SetAttribute("type", nil)
|
||
|
|
self:SetAttribute("type1", nil)
|
||
|
|
self:SetAttribute("type2", nil)
|
||
|
|
self:SetAttribute("*action*", nil)
|
||
|
|
self:SetAttribute("*macrotext*", nil)
|
||
|
|
self:SetAttribute("*action1", nil)
|
||
|
|
self:SetAttribute("*macrotext2", nil)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:UpdateGlow()
|
||
|
|
if self.bar:GetSpellGlow() and self.spellID then
|
||
|
|
--druid fix for thrash glow not showing for feral druids.
|
||
|
|
--Thrash Guardian: 77758
|
||
|
|
--Thrash Feral: 106832
|
||
|
|
--But the joint thrash is 106830 (this is the one that results true when the ability is procced)
|
||
|
|
|
||
|
|
--Swipe(Bear): 213771
|
||
|
|
--Swipe(Cat): 106785
|
||
|
|
--Swipe(NoForm): 213764
|
||
|
|
|
||
|
|
if self.spell and self.spell:lower() == "thrash()" and IsSpellOverlayed(106830) then --this is a hack for feral druids (Legion patch 7.3.0. Bug reported)
|
||
|
|
self:StartGlow()
|
||
|
|
elseif self.spell and self.spell:lower() == "swipe()" and IsSpellOverlayed(106785) then --this is a hack for feral druids (Legion patch 7.3.0. Bug reported)
|
||
|
|
self:StartGlow()
|
||
|
|
elseif IsSpellOverlayed(self.spellID) then --this is the default "true" condition
|
||
|
|
self:StartGlow()
|
||
|
|
else --this is the default "false" condition
|
||
|
|
self:StopGlow()
|
||
|
|
end
|
||
|
|
else --this stops the glow on buttons that have no spellID's, i.e. when switching states and a procced ability is overlapping an empty button
|
||
|
|
self:StopGlow()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
function ActionButton:StartGlow()
|
||
|
|
if self.bar:GetSpellGlow() == "default" then
|
||
|
|
ActionButton_ShowOverlayGlow(self)
|
||
|
|
else
|
||
|
|
self.Shine:Show()
|
||
|
|
AutoCastShine_AutoCastStart(self.Shine);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:StopGlow()
|
||
|
|
if self.bar:GetSpellGlow() == "default" then
|
||
|
|
ActionButton_HideOverlayGlow(self)
|
||
|
|
else
|
||
|
|
self.Shine:Hide()
|
||
|
|
AutoCastShine_AutoCastStop(self.Shine);
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
------------------------------------------------------------------------------
|
||
|
|
---------------------Event Functions------------------------------------------
|
||
|
|
------------------------------------------------------------------------------
|
||
|
|
|
||
|
|
function ActionButton:PLAYER_ENTERING_WORLD()
|
||
|
|
self:UpdateAll()
|
||
|
|
self:ApplyBindings()
|
||
|
|
|
||
|
|
-- if self.flyout then --this is a hack to get around CallPet not working on initial login. (weirdly it worked on /reload, but not login)
|
||
|
|
-- self:ScheduleTimer(function() self:InitializeButton() end, 1)
|
||
|
|
-- end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:UNIT_SPELLCAST_INTERRUPTED(unit)
|
||
|
|
if (unit == "player" or unit == "pet") and self.spell then
|
||
|
|
self:UpdateCooldown()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
function ActionButton:UPDATE_MACROS()
|
||
|
|
if not InCombatLockdown() and self:GetMacroBlizzMacro() then
|
||
|
|
self:PlaceBlizzMacro(self:GetMacroBlizzMacro())
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:EQUIPMENT_SETS_CHANGED()
|
||
|
|
if not InCombatLockdown() and self:GetMacroEquipmentSet() then
|
||
|
|
self:PlaceBlizzEquipSet(self:GetMacroEquipmentSet())
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------------------------------------
|
||
|
|
-----------------------------------------------------------------------------------------
|
||
|
|
|
||
|
|
function ActionButton.SanitizedMacro(macro)
|
||
|
|
if type(macro) == "string" and #macro > 0 then
|
||
|
|
--adds an empty line above and below the macro
|
||
|
|
macro = "\n"..macro.."\n"
|
||
|
|
--I'm not sure what this line does, but it adds spaces before control characters.
|
||
|
|
--Maybe it's adding spaces before newlines?
|
||
|
|
return macro:gsub("(%c+)", " %1")
|
||
|
|
else
|
||
|
|
return nil
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:UpdateButtonSpec()
|
||
|
|
local spec = Spec.active(self.bar:GetMultiSpec())
|
||
|
|
|
||
|
|
self:LoadDataFromDatabase(spec, self.bar.handler:GetAttribute("activestate") or "homestate")
|
||
|
|
self:InitializeButtonSettings()
|
||
|
|
self:UpdateFlyout()
|
||
|
|
self:UpdateAll()
|
||
|
|
end
|
||
|
|
|
||
|
|
--this function is used to "fake" a state change in the button editor so you can see what each state will look like
|
||
|
|
function ActionButton:FakeStateChange(state)
|
||
|
|
if state then
|
||
|
|
|
||
|
|
local msg = (":"):split(state)
|
||
|
|
|
||
|
|
if msg:find("vehicle") then
|
||
|
|
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("vehicleID_Offset"))
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
elseif msg:find("possess") then
|
||
|
|
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("vehicleID_Offset"))
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
elseif msg:find("override") then
|
||
|
|
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "action")
|
||
|
|
self:SetAttribute("*action*", self:GetAttribute("barPos")+self:GetAttribute("overrideID_Offset"))
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
self:Show()
|
||
|
|
|
||
|
|
else
|
||
|
|
|
||
|
|
if not self:GetAttribute(msg.."-actionID") then
|
||
|
|
self:SetAttribute("type", "macro")
|
||
|
|
self:SetAttribute("*self*", self:GetAttribute(msg.."-macro_Text"))
|
||
|
|
|
||
|
|
--if there is a macro present, or if showGrid is enabled, show the button. If not, hide it. This works in combat.
|
||
|
|
if self:GetAttribute("*macrotext*") and #self:GetAttribute("*macrotext*") > 0 or self:GetAttribute("showGrid") then
|
||
|
|
self:Show()
|
||
|
|
else
|
||
|
|
self:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAttribute("HasActionID", false)
|
||
|
|
else
|
||
|
|
self:SetAttribute("HasActionID", true)
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
self:SetAttribute("activestate", msg)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--this will generate a spell macro
|
||
|
|
--spell: name of spell to use
|
||
|
|
--subname: subname of spell to use (optional)
|
||
|
|
--return: macro text
|
||
|
|
function ActionButton:AutoWriteMacro(spell)
|
||
|
|
local DB = Neuron.db.profile
|
||
|
|
|
||
|
|
local spellName
|
||
|
|
local spellID
|
||
|
|
|
||
|
|
local altName
|
||
|
|
local altSpellID
|
||
|
|
|
||
|
|
--if there is an alt name associated with a given ability, and the alt name is known (i.e. the base spell) use the alt name instead
|
||
|
|
--This is important because a macro written with the base name "/cast Roll()" will work for talented abilities, but "/cast Chi Torpedo" won't work for base abilities
|
||
|
|
if Neuron.spellCache[spell:lower()] then
|
||
|
|
spellName = Neuron.spellCache[spell:lower()].spellName
|
||
|
|
spellID = Neuron.spellCache[spell:lower()].spellID
|
||
|
|
|
||
|
|
altName = Neuron.spellCache[spell:lower()].altName
|
||
|
|
altSpellID = Neuron.spellCache[spell:lower()].altSpellID
|
||
|
|
|
||
|
|
if altSpellID and IsSpellKnown(altSpellID) then
|
||
|
|
spell = altName
|
||
|
|
else
|
||
|
|
spell = spellName
|
||
|
|
end
|
||
|
|
else
|
||
|
|
_,_,_,_,_,_,spellID = GetSpellInfo(spell)
|
||
|
|
end
|
||
|
|
|
||
|
|
local modifier, modKey = " ", nil
|
||
|
|
local bar = Neuron.currentBar or self.bar
|
||
|
|
|
||
|
|
if bar.data.mouseOverCast and DB.mouseOverMod ~= "NONE" then
|
||
|
|
modKey = DB.mouseOverMod
|
||
|
|
modifier = modifier.."[@mouseover,mod:"..modKey.."]"
|
||
|
|
elseif bar.data.mouseOverCast and DB.mouseOverMod == "NONE" then
|
||
|
|
modifier = modifier.."[@mouseover,exists]"
|
||
|
|
end
|
||
|
|
|
||
|
|
if bar.data.selfCast and GetModifiedClick("SELFCAST") ~= "NONE" then
|
||
|
|
modKey = GetModifiedClick("SELFCAST")
|
||
|
|
modifier = modifier.."[@player,mod:"..modKey.."]"
|
||
|
|
end
|
||
|
|
|
||
|
|
if bar.data.focusCast and GetModifiedClick("FOCUSCAST") ~= "NONE" then
|
||
|
|
modKey = GetModifiedClick("FOCUSCAST")
|
||
|
|
modifier = modifier.."[@focus,exists,mod:"..modKey.."]"
|
||
|
|
end
|
||
|
|
|
||
|
|
if bar.data.rightClickTarget then
|
||
|
|
modKey = ""
|
||
|
|
modifier = modifier.."[@player"..modKey..",btn:2]"
|
||
|
|
end
|
||
|
|
|
||
|
|
if modifier ~= " " then --(modKey then
|
||
|
|
modifier = modifier.."[] "
|
||
|
|
end
|
||
|
|
|
||
|
|
return "#autowrite\n/cast"..modifier..spell.."()"
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:GetPosition(relFrame)
|
||
|
|
local point
|
||
|
|
|
||
|
|
if not relFrame then
|
||
|
|
relFrame = self:GetParent()
|
||
|
|
end
|
||
|
|
|
||
|
|
local s = self:GetScale()
|
||
|
|
local w, h = relFrame:GetWidth()/s, relFrame:GetHeight()/s
|
||
|
|
local x, y = self:GetCenter()
|
||
|
|
local vert = (y>h/1.5) and "TOP" or (y>h/3) and "CENTER" or "BOTTOM"
|
||
|
|
local horz = (x>w/1.5) and "RIGHT" or (x>w/3) and "CENTER" or "LEFT"
|
||
|
|
|
||
|
|
if vert == "CENTER" then
|
||
|
|
point = horz
|
||
|
|
elseif horz == "CENTER" then
|
||
|
|
point = vert
|
||
|
|
else
|
||
|
|
point = vert..horz
|
||
|
|
end
|
||
|
|
|
||
|
|
if vert:find("CENTER") then y = y - h/2 end
|
||
|
|
if horz:find("CENTER") then x = x - w/2 end
|
||
|
|
if point:find("RIGHT") then x = x - w end
|
||
|
|
if point:find("TOP") then y = y - h end
|
||
|
|
|
||
|
|
return point, x, y
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
--This will update the modifier value in a macro when a bar is set with a target conditional
|
||
|
|
--@spell: this is hte macro text to be updated
|
||
|
|
--return: updated macro text
|
||
|
|
--[[function ActionButton:AutoUpdateMacro(macro)
|
||
|
|
|
||
|
|
local DB = Neuron.db.profile
|
||
|
|
|
||
|
|
if GetModifiedClick("SELFCAST") ~= "NONE" then
|
||
|
|
macro = macro:gsub("%[@player,mod:%u+%]", "[@player,mod:"..GetModifiedClick("SELFCAST").."]")
|
||
|
|
else
|
||
|
|
macro = macro:gsub("%[@player,mod:%u+%]", "")
|
||
|
|
end
|
||
|
|
|
||
|
|
if GetModifiedClick("FOCUSCAST") ~= "NONE" then
|
||
|
|
macro = macro:gsub("%[@focus,mod:%u+%]", "[@focus,exists,mod:"..GetModifiedClick("FOCUSCAST").."]")
|
||
|
|
else
|
||
|
|
macro = macro:gsub("%[@focus,mod:%u+%]", "")
|
||
|
|
end
|
||
|
|
|
||
|
|
if DB.mouseOverMod ~= "NONE" then
|
||
|
|
macro = macro:gsub("%[@mouseover,mod:%u+%]", "[@mouseover,mod:"..DB.mouseOverMod .."]")
|
||
|
|
macro = macro:gsub("%[@mouseover,exists]", "[@mouseover,mod:"..DB.mouseOverMod .."]")
|
||
|
|
else
|
||
|
|
macro = macro:gsub("%[@mouseover,mod:%u+%]", "[@mouseover,exists]")
|
||
|
|
end
|
||
|
|
|
||
|
|
return macro
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
-- This will iterate through a set of buttons. For any buttons that have the #autowrite flag in its macro, that
|
||
|
|
-- macro will then be updated to via AutoWriteMacro to include selected target macro option, or via AutoUpdateMacro
|
||
|
|
-- to update a current target macro's toggle modifier.
|
||
|
|
-- @param global(boolean): if true will go though all buttons, else it will just update the button set for the current bar
|
||
|
|
function ActionButton:UpdateMacroCastTargets(global_update)
|
||
|
|
|
||
|
|
local button_list = {}
|
||
|
|
|
||
|
|
if global_update then
|
||
|
|
|
||
|
|
for _,bar in ipairs(Neuron.bars) do
|
||
|
|
for _, object in ipairs(bar.buttons) do
|
||
|
|
table.insert(button_list, object)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
else
|
||
|
|
local bar = Neuron.currentBar
|
||
|
|
for i, object in ipairs(bar.buttons) do
|
||
|
|
table.insert(button_list, object)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
for index, button in pairs(button_list) do
|
||
|
|
local cur_button = button.DB
|
||
|
|
local macro_update = false
|
||
|
|
|
||
|
|
for i = 1,2 do
|
||
|
|
for state, info in pairs(cur_button[i]) do
|
||
|
|
if info:GetMacroText() and info:GetMacroText():find("#autowrite\n/cast") then
|
||
|
|
local spell = ""
|
||
|
|
|
||
|
|
spell = info:GetMacroText():gsub("%[.*%]", "")
|
||
|
|
spell = spell:match("#autowrite\n/cast%s*(.+)%((.*)%)")
|
||
|
|
|
||
|
|
if spell then
|
||
|
|
if global_update then
|
||
|
|
info:SetMacroText(button:AutoUpdateMacro(info.macro_Text))
|
||
|
|
else
|
||
|
|
info:SetMacroText(button:AutoWriteMacro(spell))
|
||
|
|
end
|
||
|
|
|
||
|
|
end
|
||
|
|
macro_update = true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if macro_update then
|
||
|
|
button:UpdateFlyout()
|
||
|
|
button:InitializeButton()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end]]
|
||
|
|
|
||
|
|
|
||
|
|
-----------------------------------------------------
|
||
|
|
--------------------- Overrides ---------------------
|
||
|
|
-----------------------------------------------------
|
||
|
|
|
||
|
|
--overwrite function in parent class Button
|
||
|
|
function ActionButton:UpdateAll()
|
||
|
|
--pass to parent UpdateAll function
|
||
|
|
Neuron.Button.UpdateAll(self)
|
||
|
|
|
||
|
|
if Neuron.isWoWRetail then
|
||
|
|
self:UpdateGlow()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
---@return {}|{spell: string, spellID: number, unit:string}|{item:string, unit:string}
|
||
|
|
function ActionButton.ExtractMacroData(macro)
|
||
|
|
if not macro then
|
||
|
|
return {}
|
||
|
|
end
|
||
|
|
|
||
|
|
-- the results. probably either spell or item will be nil
|
||
|
|
---@type string|nil
|
||
|
|
local spell
|
||
|
|
---@type number|nil
|
||
|
|
local spellID
|
||
|
|
---@type string|nil
|
||
|
|
local item
|
||
|
|
---@type string
|
||
|
|
local unit
|
||
|
|
|
||
|
|
--extract the parsed contents of a macro and assign them for further processing
|
||
|
|
local command, abilityOrItem, target
|
||
|
|
for cmd, content in gmatch(macro, "(%c%p%a+)(%C+)") do
|
||
|
|
|
||
|
|
--"cmd" is "/cast" or "/use" or "#autowrite" or "#showtooltip" etc
|
||
|
|
--"content" is everything else, like "Chi Torpedo()"
|
||
|
|
|
||
|
|
if cmd then
|
||
|
|
cmd = cmd:gsub("^%c+", "") --remove unneeded characters
|
||
|
|
end
|
||
|
|
|
||
|
|
if content then
|
||
|
|
content = content:gsub("^%s+", "") --remove unneeded characters
|
||
|
|
end
|
||
|
|
|
||
|
|
--we only want the first in the list if there is a list, so if the first thing is a "#showtooltip" <ability> then we want to capture the ability
|
||
|
|
--if the first line is #showtootltip and it is blank after, we want to ignore this particular loop and jump to the next
|
||
|
|
if not abilityOrItem or #abilityOrItem < 1 then
|
||
|
|
abilityOrItem, target = SecureCmdOptionParse(content)
|
||
|
|
command = cmd
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
unit = target or "target"
|
||
|
|
|
||
|
|
if COMMAND_LIST[command] then
|
||
|
|
if abilityOrItem and #abilityOrItem > 0 and command:find("/castsequence") then --this always will set the button info the next ability or item in the sequence
|
||
|
|
_, item, spell = QueryCastSequence(abilityOrItem) --it will only ever return as either item or spell, never both
|
||
|
|
elseif abilityOrItem and #abilityOrItem > 0 then
|
||
|
|
if Neuron.itemCache[abilityOrItem:lower()] then --if our abilityOrItem is actually an item in our cache, amend it as such
|
||
|
|
item = abilityOrItem
|
||
|
|
elseif GetItemInfo(abilityOrItem) then
|
||
|
|
item = abilityOrItem
|
||
|
|
elseif tonumber(abilityOrItem) and GetInventoryItemLink("player", abilityOrItem) then --in case abilityOrItem is a number and corresponds to a valid inventory item
|
||
|
|
item = GetInventoryItemLink("player", abilityOrItem)
|
||
|
|
elseif Neuron.spellCache[abilityOrItem:lower()] then
|
||
|
|
spell = abilityOrItem
|
||
|
|
spellID = Neuron.spellCache[abilityOrItem:lower()].spellID
|
||
|
|
elseif GetSpellInfo(abilityOrItem) then
|
||
|
|
spell = abilityOrItem
|
||
|
|
_,_,_,_,_,_,spellID = GetSpellInfo(abilityOrItem)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
return {spell = spell, spellID = spellID, unit = unit, item = item}
|
||
|
|
end
|
||
|
|
|
||
|
|
--overwrite function in parent class Button
|
||
|
|
function ActionButton:UpdateData()
|
||
|
|
--clear any lingering values before we re-parse and reassign
|
||
|
|
self:ClearButton()
|
||
|
|
|
||
|
|
--if we have no macro content then bail immediately
|
||
|
|
--if we have an actionID on this button bail immediately
|
||
|
|
if self.actionID then
|
||
|
|
--don't set any values as they'll get in the way later
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local cleanMacro = self.SanitizedMacro(self:GetMacroText())
|
||
|
|
local spellItemUnit = self.ExtractMacroData(cleanMacro)
|
||
|
|
self.spell = spellItemUnit.spell
|
||
|
|
self.spellID = spellItemUnit.spellID
|
||
|
|
self.item = spellItemUnit.item
|
||
|
|
self.unit = spellItemUnit.unit
|
||
|
|
end
|
||
|
|
|
||
|
|
--overwrite function in parent class Button
|
||
|
|
function ActionButton:UpdateVisibility(show)
|
||
|
|
if self:HasAction() or Neuron.dragging or show or self.bar:GetShowGrid() or Neuron.buttonEditMode or Neuron.barEditMode or Neuron.bindingMode then
|
||
|
|
self.isShown = true
|
||
|
|
else
|
||
|
|
self.isShown = false
|
||
|
|
end
|
||
|
|
|
||
|
|
if not InCombatLockdown() then
|
||
|
|
self:SetAttribute("showGrid", self.bar:GetShowGrid()) --this is important because in our state switching code, we can't query self.showGrid directly
|
||
|
|
|
||
|
|
if self.isShown then
|
||
|
|
self:Show()
|
||
|
|
else
|
||
|
|
self:Hide()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
Neuron.Button.UpdateVisibility(self)
|
||
|
|
end
|
||
|
|
|
||
|
|
-----------------------------------------------------------------------------------------
|
||
|
|
-------------------------------------- Set Icon -----------------------------------------
|
||
|
|
-----------------------------------------------------------------------------------------
|
||
|
|
|
||
|
|
|
||
|
|
function ActionButton:UpdateIcon()
|
||
|
|
if Neuron.pendingReload then
|
||
|
|
return
|
||
|
|
end
|
||
|
|
|
||
|
|
local spec = Spec.active(self.bar:GetMultiSpec())
|
||
|
|
local state = self.bar.handler:GetAttribute("activestate") or "homestate"
|
||
|
|
|
||
|
|
-- if we have any issues with flyouts or other edge cases, then
|
||
|
|
-- then we can build our data from our ActionButton instead of using
|
||
|
|
-- the database values. but we need to keep GetAppearance stateless
|
||
|
|
-- so that we can use it in other contexts: like the settings dialog
|
||
|
|
---@type GenericSpecData
|
||
|
|
local data = (
|
||
|
|
self.DB
|
||
|
|
and CopyTable(self.DB[spec][state], true)
|
||
|
|
or {macro_Text = self:GetMacroText(), macro_Icon = self:GetMacroIcon()}
|
||
|
|
)
|
||
|
|
data.actionID = self.actionID -- this is for vehicle, possession, etc
|
||
|
|
|
||
|
|
self:ApplyAppearance(self:GetAppearance(data))
|
||
|
|
|
||
|
|
--make sure our button gets the correct Normal texture if we're not using a Masque skin
|
||
|
|
self:UpdateNormalTexture()
|
||
|
|
end
|
||
|
|
|
||
|
|
---@alias Border {[1]:number,[2]:number,[3]:number,[4]:number}|nil
|
||
|
|
---@alias TextureRef number|string
|
||
|
|
|
||
|
|
--- @param data GenericSpecData
|
||
|
|
--- @return TextureRef, Border an icon texture, and an rgb tuple, both nilable
|
||
|
|
function ActionButton:GetAppearance(data)
|
||
|
|
local spellItem = self.ExtractMacroData(self.SanitizedMacro(data.macro_Text))
|
||
|
|
local spell, item = spellItem.spell, spellItem.item
|
||
|
|
local texture, border
|
||
|
|
|
||
|
|
if data.actionID then
|
||
|
|
return self.GetActionAppearance(data.actionID)
|
||
|
|
elseif spell then
|
||
|
|
texture, border = self.GetSpellAppearance(spell)
|
||
|
|
elseif item then
|
||
|
|
texture, border = self.GetItemAppearance(item)
|
||
|
|
-- macro must go after spells and items, for blizz macro #showtooltip to work
|
||
|
|
elseif data.macro_Icon then
|
||
|
|
texture, border = data.macro_Icon, nil
|
||
|
|
else
|
||
|
|
texture, border = nil, nil
|
||
|
|
end
|
||
|
|
|
||
|
|
return texture, border
|
||
|
|
end
|
||
|
|
|
||
|
|
function ActionButton:ApplyAppearance(texture, border)
|
||
|
|
if texture then
|
||
|
|
self.Icon:SetTexture(texture)
|
||
|
|
self.Icon:Show()
|
||
|
|
else
|
||
|
|
self.Name:SetText("")
|
||
|
|
self.Icon:SetTexture("")
|
||
|
|
self.Icon:Hide()
|
||
|
|
end
|
||
|
|
|
||
|
|
if border then
|
||
|
|
self.Border:SetVertexColor(unpack(border))
|
||
|
|
self.Border:Show()
|
||
|
|
else
|
||
|
|
self.Border:Hide()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @return number|string, nil @an icon texture, and an rgb tuple, both nilable
|
||
|
|
function ActionButton.GetSpellAppearance(spell)
|
||
|
|
--Hide the border in case this button used to have an equipped item in it
|
||
|
|
--otherwise it will continue to have a green border until a reload takes place
|
||
|
|
local border = nil
|
||
|
|
|
||
|
|
---@type number|string|nil
|
||
|
|
local texture = GetSpellTexture(spell)
|
||
|
|
|
||
|
|
if not texture then
|
||
|
|
if Neuron.spellCache[spell:lower()] then
|
||
|
|
texture = Neuron.spellCache[spell:lower()].icon
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not texture then
|
||
|
|
texture = "INTERFACE\\ICONS\\INV_MISC_QUESTIONMARK"
|
||
|
|
end
|
||
|
|
|
||
|
|
return texture, border
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @return number|string, Border @an icon texture, and an rgb tuple, both nilable
|
||
|
|
function ActionButton.GetItemAppearance(item)
|
||
|
|
local border = nil
|
||
|
|
---@type number|string|nil
|
||
|
|
local texture = GetItemIcon(item)
|
||
|
|
|
||
|
|
if not texture then
|
||
|
|
if Neuron.itemCache[item:lower()] then
|
||
|
|
texture = GetItemIcon("item:"..Neuron.itemCache[item:lower()]..":0:0:0:0:0:0:0"--[[@as number]])
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if not texture then
|
||
|
|
texture = "INTERFACE\\ICONS\\INV_MISC_QUESTIONMARK"
|
||
|
|
end
|
||
|
|
|
||
|
|
if IsEquippedItem(item) then --makes the border green when item is equipped and dragged to a button
|
||
|
|
border = {0, 1.0, 0, 0.2}
|
||
|
|
end
|
||
|
|
|
||
|
|
return texture, border
|
||
|
|
end
|
||
|
|
|
||
|
|
--- @return texture, border an icon texture, and an rgb tuple, both nilable
|
||
|
|
function ActionButton.GetActionAppearance(actionID)
|
||
|
|
local texture, border
|
||
|
|
|
||
|
|
if HasAction(actionID) then
|
||
|
|
texture = GetActionTexture(actionID) or ""
|
||
|
|
end
|
||
|
|
return texture, border
|
||
|
|
end
|
||
|
|
|