--[[ ############################################################################## _____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_ # ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__ # __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____ # ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____ # ______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____ # _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____ # __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ # _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_# ___\///////////___________\///___________\/////////_____\///////////_# ############################################################################## S U P E R - V I L L A I N - U I By: Munglunch # ############################################################################## ########################################################## LOCALIZED LUA FUNCTIONS ########################################################## ]]-- --[[ GLOBALS ]]-- local _G = _G; local unpack = _G.unpack; local select = _G.select; local pairs = _G.pairs; local string = _G.string; local math = _G.math; --[[ STRING METHODS ]]-- local find, format, split = string.find, string.format, string.split; local gsub = string.gsub; --[[ MATH METHODS ]]-- local ceil = math.ceil; --[[ ########################################################## GET ADDON DATA ########################################################## ]]-- local SV = select(2, ...) local L = SV.L; local SuperButton = _G["SVUI_SuperButtonFrame"]; SuperButton.RegisteredButtons = {}; SuperButton.ActionBlackList = {}; SuperButton.SpellBlackList = {}; SuperButton.ItemBlackList = {}; local ORDERED_LIST = {}; local NO_ART = [[Interface\AddOns\SVUI\assets\artwork\Template\EMPTY]]; --[[ ########################################################## HELPERS ########################################################## ]]-- local UpdateActionCooldown = function(self) if(self:IsShown() and self.action) then local start, duration, enable = GetActionCooldown(self.action) if((start and start > 0) and (duration and duration > 0)) then self.Cooldown:SetCooldown(start, duration) self.Cooldown:Show() else self.Cooldown:Hide() end end end local UpdateSpellCooldown = function(self) if(self:IsShown() and self.spellName) then local start, duration, enable = GetSpellCooldown(self.spellName) if((start and start > 0) and (duration and duration > 0)) then self.Cooldown:SetCooldown(start, duration) self.Cooldown:Show() else self.Cooldown:Hide() end end end local UpdateItemCooldown = function(self) if(self:IsShown() and self.itemID) then local start, duration, enable = GetItemCooldown(self.itemID) if((start and start > 0) and (duration and duration > 0)) then self.Cooldown:SetCooldown(start, duration) self.Cooldown:Show() else self.Cooldown:Hide() end end end --[[ ########################################################## SCRIPT HANDLERS ########################################################## ]]-- local SuperActionButton_OnEnter = function(self) if(self.action) then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:SetAction(self.action) end end local SuperSpellButton_OnEnter = function(self) if(self.spellID) then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:SetSpellByID(self.spellID) end end local SuperItemButton_OnEnter = function(self) if(self.itemID) then GameTooltip:SetOwner(self, 'ANCHOR_LEFT') GameTooltip:SetHyperlink(self.itemLink) end end local SuperButton_OnShow = function(self) SuperButton.isActive = true; if(self.Artwork) then self.Artwork:SetAlpha(1) end self:FadeIn() end local SuperButton_OnHide = function(self) SuperButton.isActive = false; if(self.Artwork) then self.Artwork:SetAlpha(0) end end local GetSetPositions = function(self) local highestIndex = 0; local lastFrame = SuperButton; for name, frame in pairs(SuperButton.RegisteredButtons) do if((frame ~= self) and frame:IsShown() and (frame.___posIndex > highestIndex)) then highestIndex = frame.___posIndex; lastFrame = name; end end self.___posIndex = highestIndex + 1; --print(self:GetName() .. " = " .. self.___posIndex) return lastFrame; end local GetResetPositions = function(self) self.___posIndex = 0; for name, frame in pairs(SuperButton.RegisteredButtons) do if((frame ~= self) and frame:IsShown() and (frame.___posIndex == 1)) then tinsert(ORDERED_LIST, name) end end for name, frame in pairs(SuperButton.RegisteredButtons) do if((frame ~= self) and frame:IsShown() and (frame.___posIndex > 1)) then tinsert(ORDERED_LIST, name) end end return ORDERED_LIST; end local UpdateGeneric = function(self) return true; end local SuperButtonAction_OnEvent = function(self, event) if(event == 'PLAYER_REGEN_ENABLED') then self:SetAttribute('action', self.attribute) self:UnregisterEvent(event) self:UpdateCooldown() elseif(event == 'UPDATE_BINDINGS') then if(self:IsShown()) then self:SetAbility() self:SetAttribute('binding', GetTime()) end else self:Update() end end local SuperButtonSpell_OnEvent = function(self, event) if(event == 'PLAYER_REGEN_ENABLED') then self:SetAttribute('spell', self.attribute) self:UnregisterEvent(event) self:UpdateCooldown() elseif(event == 'UPDATE_BINDINGS') then if(self:IsShown()) then self:SetAbility() self:SetAttribute('binding', GetTime()) end else self:Update() end end local SuperButtonItem_OnEvent = function(self, event) if(event == 'BAG_UPDATE_COOLDOWN') then self:UpdateCooldown() elseif(event == 'PLAYER_REGEN_ENABLED') then self:SetAttribute('item', self.attribute) self:UnregisterEvent(event) self:UpdateCooldown() elseif(event == 'UPDATE_BINDINGS') then if(self:IsShown()) then self:SetAbility() self:SetAttribute('binding', GetTime()) end else self:Update() end end --[[ ########################################################## ACTION BUTTON INTERNALS ########################################################## ]]-- local SetSuperButtonAction = function(self, action) if(action) then if(action == self.action and self:IsShown()) then return false end self.action = action if(SuperButton.ActionBlackList[self.action]) then return false end end local HotKey = self.HotKey local key = GetBindingKey(self.___binding) if(key) then HotKey:SetText(GetBindingText(key, 1)) HotKey:Show() elseif(ActionHasRange(self.action)) then HotKey:SetText(RANGE_INDICATOR) HotKey:Show() else HotKey:Hide() end if(InCombatLockdown()) then self.attribute = self.action self:RegisterEvent('PLAYER_REGEN_ENABLED') else self:SetAttribute('action', self.action) self:UpdateCooldown() end return true end local RemoveSuperButtonAction = function(self) self:FadeOut() if(InCombatLockdown()) then self.attribute = nil; self:RegisterEvent('PLAYER_REGEN_ENABLED') else self:SetAttribute('action', nil) end end local SuperActionButton_OnUpdate = function(self, elapsed) if(not self.action) then return end if(self.rangeTimer > 0.2) then local HotKey = self.HotKey local inRange = IsActionInRange(self.action, 'target') if(HotKey:GetText() == RANGE_INDICATOR) then if(inRange == false) then HotKey:SetTextColor(1, 0.1, 0.1) HotKey:Show() elseif(inRange) then HotKey:SetTextColor(1, 1, 1) HotKey:Show() else HotKey:Hide() end else if(inRange == false) then HotKey:SetTextColor(1, 0.1, 0.1) else HotKey:SetTextColor(1, 1, 1) end end self.rangeTimer = 0 else self.rangeTimer = self.rangeTimer + elapsed end if(self.updateTimer > 5) then self:Update() self.updateTimer = 0 else self.updateTimer = self.updateTimer + elapsed end end --[[ ########################################################## SPELL BUTTON INTERNALS ########################################################## ]]-- local SetSuperButtonSpell = function(self, spellID, spellName, texture) if(spellID and spellName) then if(spellID == self.spellID and self:IsShown()) then return false end self.Icon:SetTexture(texture) self.spellID = spellID self.spellName = spellName if(SuperButton.SpellBlackList[self.spellID]) then return false end end local HotKey = self.HotKey local key = GetBindingKey(self.___binding) if(key) then HotKey:SetText(GetBindingText(key, 1)) HotKey:Show() elseif(SpellHasRange(self.spellName)) then HotKey:SetText(RANGE_INDICATOR) HotKey:Show() else HotKey:Hide() end if(InCombatLockdown()) then self.attribute = self.spellName self:RegisterEvent('PLAYER_REGEN_ENABLED') else self:SetAttribute('spell', self.spellName) self:UpdateCooldown() end return true end local RemoveSuperButtonSpell = function(self) self:FadeOut() if(InCombatLockdown()) then self.attribute = nil; self:RegisterEvent('PLAYER_REGEN_ENABLED'); else self:SetAttribute('spell', nil); end end local SuperSpellButton_OnUpdate = function(self, elapsed) if(not self.spellName) then return end if(self.rangeTimer > 0.2) then local HotKey = self.HotKey local inRange = IsSpellInRange(self.spellName, 'target') if(HotKey:GetText() == RANGE_INDICATOR) then if(inRange == false) then HotKey:SetTextColor(1, 0.1, 0.1) HotKey:Show() elseif(inRange) then HotKey:SetTextColor(1, 1, 1) HotKey:Show() else HotKey:Hide() end else if(inRange == false) then HotKey:SetTextColor(1, 0.1, 0.1) else HotKey:SetTextColor(1, 1, 1) end end self.rangeTimer = 0 else self.rangeTimer = self.rangeTimer + elapsed end if(self.updateTimer > 5) then self:Update() self.updateTimer = 0 else self.updateTimer = self.updateTimer + elapsed end end --[[ ########################################################## ITEM BUTTON INTERNALS ########################################################## ]]-- local SetSuperButtonItem = function(self, itemLink, texture) if(itemLink) then if(itemLink == self.itemLink and self:IsShown()) then return false end self.Icon:SetTexture(texture) self.itemID, self.itemName = string.match(itemLink, '|Hitem:(.-):.-|h%[(.+)%]|h') self.itemLink = itemLink if(SuperButton.ItemBlackList[self.itemID]) then return false end end local HotKey = self.HotKey local key = GetBindingKey(self.___binding) if(key) then HotKey:SetText(GetBindingText(key, 1)) HotKey:Show() elseif(ItemHasRange(self.itemLink)) then HotKey:SetText(RANGE_INDICATOR) HotKey:Show() else HotKey:Hide() end if(InCombatLockdown()) then self.attribute = self.itemName self:RegisterEvent('PLAYER_REGEN_ENABLED') else self:SetAttribute('item', self.itemName) self:UpdateCooldown() end return true end local RemoveSuperButtonItem = function(self) self:FadeOut() if(InCombatLockdown()) then self.attribute = nil; self:RegisterEvent('PLAYER_REGEN_ENABLED'); else self:SetAttribute('item', nil) end end local SuperItemButton_OnUpdate = function(self, elapsed) if(not self.itemID) then return end if(self.rangeTimer > 0.2) then local HotKey = self.HotKey local inRange = IsItemInRange(self.itemID, 'target') if(HotKey:GetText() == RANGE_INDICATOR) then if(inRange == false) then HotKey:SetTextColor(1, 0.1, 0.1) HotKey:Show() elseif(inRange) then HotKey:SetTextColor(1, 1, 1) HotKey:Show() else HotKey:Hide() end else if(inRange == false) then HotKey:SetTextColor(1, 0.1, 0.1) else HotKey:SetTextColor(1, 1, 1) end end self.rangeTimer = 0 else self.rangeTimer = self.rangeTimer + elapsed end if(self.updateTimer > 5) then self:Update() self.updateTimer = 0 else self.updateTimer = self.updateTimer + elapsed end end --[[ ########################################################## CONSTRUCTS ########################################################## ]]-- function SuperButton:SetFrameReferences() local listing = self.RegisteredButtons; for buttonName, button in pairs(listing) do button:SetFrameRef("SVUI_SuperButtonFrame", SVUI_SuperButtonFrame); for name, frame in pairs(listing) do if(frame ~= button) then button:SetFrameRef(name, frame); end end end end function SuperButton:AddAction(buttonName, updateFunc, eventFunc, bindingKey) local special = CreateFrame('Button', buttonName, UIParent, 'SecureActionButtonTemplate, SecureHandlerStateTemplate, SecureHandlerAttributeTemplate'); special:SetSizeToScale(50,50); special:SetPointToScale("CENTER", self, "CENTER", 0, 0); special:SetAlpha(0); special:SetStylePanel("Icon"); special:SetScript('OnEnter', SuperActionButton_OnEnter); special:SetScript('OnLeave', GameTooltip_Hide); special:SetScript('OnShow', SuperButton_OnShow); special:SetScript('OnHide', SuperButton_OnHide); special.___posIndex = 1; special.___binding = bindingKey; special.updateTimer = 0; special.rangeTimer = 0; special.GetPositionRef = GetSetPositions; special.GetResetRefList = GetResetPositions; special.SetAbility = SetSuperButtonAction; special.RemoveAbility = RemoveSuperButtonAction; special.UpdateCooldown = UpdateActionCooldown; if(updateFunc and type(updateFunc) == 'function') then special.Update = updateFunc; else special.Update = UpdateGeneric; end if(eventFunc and type(eventFunc) == 'function') then special:SetScript('OnEvent', eventFunc) else special:SetScript('OnEvent', SuperButtonAction_OnEvent) end local Artwork = special.Panel:CreateTexture('$parentArtwork', 'BACKGROUND') Artwork:SetPoint('CENTER', -2, 2) Artwork:SetSizeToScale(256, 128) Artwork:SetTexture(NO_ART) Artwork:SetAlpha(0) special.Artwork = Artwork local Icon = special:CreateTexture('$parentIcon', 'BACKGROUND') Icon:SetTexCoord(0.1, 0.9, 0.1, 0.9) Icon:SetAllPoints() special.Icon = Icon local HotKey = special:CreateFontString('$parentHotKey', nil, 'NumberFontNormal') HotKey:SetPoint('BOTTOMRIGHT', -5, 5) special.HotKey = HotKey local Cooldown = CreateFrame('Cooldown', '$parentCooldown', special, 'CooldownFrameTemplate') Cooldown:ClearAllPoints() Cooldown:SetPoint('TOPRIGHT', -2, -3) Cooldown:SetPoint('BOTTOMLEFT', 2, 1) Cooldown:Hide() special.Cooldown = Cooldown local Count = Cooldown:CreateFontString(nil, 'OVERLAY', 'NumberFontNormal') Count:SetPoint('BOTTOMLEFT', 5, 5) special.Count = Count special:SetScript('OnUpdate', SuperActionButton_OnUpdate) special:RegisterEvent('UPDATE_BINDINGS') special:SetAttribute('type', 'action'); special:SetAttribute('_onattributechanged', [[ if(name == 'action') then if(value and not self:IsShown()) then local refName = self:CallMethod('GetPositionRef'); local lastFrame = self:GetFrameRef(refName); if(lastFrame) then self:ClearAllPoints() self:SetPoint("BOTTOM", lastFrame, "TOP", 0, 8) end self:Show() elseif(not value) then local refList = self:CallMethod('GetResetRefList'); local lastFrame, nextFrame; if(refList) then for _,refName in ipairs(refList) do nextFrame = self:GetFrameRef(refName); if(nextFrame) then nextFrame:ClearAllPoints() if(not lastFrame) then lastFrame = self:GetFrameRef("SVUI_SuperButtonFrame"); nextFrame:SetPoint("CENTER", lastFrame, "CENTER", 0, 0); else nextFrame:SetPoint("BOTTOM", lastFrame, "TOP", 0, 8); end end end end self:Hide() self:ClearBindings() end end if(self:IsShown() and (self.___binding) and (name == 'action' or name == 'binding')) then self:ClearBindings() local key = GetBindingKey(self.___binding) if(key) then self:SetBindingClick(1, key, self, 'LeftButton') end end ]]); self.RegisteredButtons[buttonName] = special; self:SetFrameReferences() --special:Hide() return special end function SuperButton:AddSpell(buttonName, updateFunc, eventFunc, bindingKey) local special = CreateFrame('Button', buttonName, UIParent, 'SecureActionButtonTemplate, SecureHandlerStateTemplate, SecureHandlerAttributeTemplate'); special:SetSizeToScale(50,50); special:SetPointToScale("CENTER", self, "CENTER", 0, 0); special:SetAlpha(0); special:SetStylePanel("Icon"); special:SetScript('OnEnter', SuperSpellButton_OnEnter); special:SetScript('OnLeave', GameTooltip_Hide); special:SetScript('OnShow', SuperButton_OnShow); special:SetScript('OnHide', SuperButton_OnHide); special.___posIndex = 1; special.___binding = bindingKey; special.updateTimer = 0; special.rangeTimer = 0; special.GetPositionRef = GetSetPositions; special.GetResetRefList = GetResetPositions; special.SetAbility = SetSuperButtonSpell; special.RemoveAbility = RemoveSuperButtonSpell; special.UpdateCooldown = UpdateSpellCooldown; if(updateFunc and type(updateFunc) == 'function') then special.Update = updateFunc else special.Update = UpdateGeneric end if(eventFunc and type(eventFunc) == 'function') then special:SetScript('OnEvent', eventFunc) else special:SetScript('OnEvent', SuperButtonSpell_OnEvent) end local Artwork = special.Panel:CreateTexture('$parentArtwork', 'BACKGROUND') Artwork:SetPoint('CENTER', -2, 2) Artwork:SetSizeToScale(256, 128) Artwork:SetTexture(NO_ART) Artwork:SetAlpha(0) special.Artwork = Artwork local Icon = special:CreateTexture('$parentIcon', 'BACKGROUND') Icon:SetTexCoord(0.1, 0.9, 0.1, 0.9) Icon:SetAllPoints() special.Icon = Icon local HotKey = special:CreateFontString('$parentHotKey', nil, 'NumberFontNormal') HotKey:SetPoint('BOTTOMRIGHT', -5, 5) special.HotKey = HotKey local Cooldown = CreateFrame('Cooldown', '$parentCooldown', special, 'CooldownFrameTemplate') Cooldown:ClearAllPoints() Cooldown:SetPoint('TOPRIGHT', -2, -3) Cooldown:SetPoint('BOTTOMLEFT', 2, 1) Cooldown:Hide() special.Cooldown = Cooldown special:SetScript('OnUpdate', SuperSpellButton_OnUpdate) special:RegisterEvent('UPDATE_BINDINGS') special:SetAttribute('type', 'spell'); special:SetAttribute('_onattributechanged', [[ if(name == 'spell') then if(value and not self:IsShown()) then local refName = self:CallMethod('GetPositionRef'); local lastFrame = self:GetFrameRef(refName); if(lastFrame) then self:ClearAllPoints() self:SetPoint("BOTTOM", lastFrame, "TOP", 0, 8) end self:Show() elseif(not value) then local refList = self:CallMethod('GetResetRefList'); local lastFrame, nextFrame; if(refList) then for _,refName in ipairs(refList) do nextFrame = self:GetFrameRef(refName); if(nextFrame) then nextFrame:ClearAllPoints() if(not lastFrame) then lastFrame = self:GetFrameRef("SVUI_SuperButtonFrame"); nextFrame:SetPoint("CENTER", lastFrame, "CENTER", 0, 0); else nextFrame:SetPoint("BOTTOM", lastFrame, "TOP", 0, 8); end end end end self:Hide() self:ClearBindings() end end if(self:IsShown() and (self.___binding) and (name == 'spell' or name == 'binding')) then self:ClearBindings() local key = GetBindingKey(self.___binding) if(key) then self:SetBindingClick(1, key, self, 'LeftButton') end end ]]); self.RegisteredButtons[buttonName] = special; self:SetFrameReferences() --special:Hide() return special end function SuperButton:AddItem(buttonName, updateFunc, eventFunc, bindingKey) local special = CreateFrame('Button', buttonName, UIParent, 'SecureActionButtonTemplate, SecureHandlerStateTemplate, SecureHandlerAttributeTemplate'); special:SetSizeToScale(50,50); special:SetPointToScale("CENTER", self, "CENTER", 0, 0); special:SetAlpha(0); special:SetStylePanel("Icon"); special:SetScript('OnEnter', SuperItemButton_OnEnter); special:SetScript('OnLeave', GameTooltip_Hide); special:SetScript('OnShow', SuperButton_OnShow); special:SetScript('OnHide', SuperButton_OnHide); special.___posIndex = 1; special.___binding = bindingKey; special.updateTimer = 0; special.rangeTimer = 0; special.GetPositionRef = GetSetPositions; special.GetResetRefList = GetResetPositions; special.SetAbility = SetSuperButtonItem; special.RemoveAbility = RemoveSuperButtonItem; special.UpdateCooldown = UpdateItemCooldown; if(updateFunc and type(updateFunc) == 'function') then special.Update = updateFunc else special.Update = UpdateGeneric end if(eventFunc and type(eventFunc) == 'function') then special:SetScript('OnEvent', eventFunc) else special:SetScript('OnEvent', SuperButtonItem_OnEvent) end local Artwork = special.Panel:CreateTexture('$parentArtwork', 'BACKGROUND') Artwork:SetPoint('CENTER', -2, 2) Artwork:SetSizeToScale(256, 128) Artwork:SetTexture(NO_ART) Artwork:SetAlpha(0) special.Artwork = Artwork local Icon = special:CreateTexture('$parentIcon', 'BACKGROUND') Icon:SetTexCoord(0.1, 0.9, 0.1, 0.9) Icon:SetAllPoints() special.Icon = Icon local HotKey = special:CreateFontString('$parentHotKey', nil, 'NumberFontNormal') HotKey:SetPoint('BOTTOMRIGHT', -5, 5) special.HotKey = HotKey local Cooldown = CreateFrame('Cooldown', '$parentCooldown', special, 'CooldownFrameTemplate') Cooldown:ClearAllPoints() Cooldown:SetPoint('TOPRIGHT', -2, -3) Cooldown:SetPoint('BOTTOMLEFT', 2, 1) Cooldown:Hide() special.Cooldown = Cooldown special:RegisterEvent('UPDATE_BINDINGS') special:SetAttribute('type', 'item'); special:SetAttribute('_onattributechanged', [[ if(name == 'item') then if(value and not self:IsShown()) then local refName = self:CallMethod('GetPositionRef'); local lastFrame = self:GetFrameRef(refName); if(lastFrame) then self:ClearAllPoints() self:SetPoint("BOTTOM", lastFrame, "TOP", 0, 8) end self:Show() elseif(not value) then local refList = self:CallMethod('GetResetRefList'); local lastFrame, nextFrame; if(refList) then for _,refName in ipairs(refList) do nextFrame = self:GetFrameRef(refName); if(nextFrame) then nextFrame:ClearAllPoints() if(not lastFrame) then lastFrame = self:GetFrameRef("SVUI_SuperButtonFrame"); nextFrame:SetPoint("CENTER", lastFrame, "CENTER", 0, 0); else nextFrame:SetPoint("BOTTOM", lastFrame, "TOP", 0, 8); end end end end self:Hide() self:ClearBindings() end end if(self:IsShown() and (self.___binding) and (name == 'item' or name == 'binding')) then self:ClearBindings() local key = GetBindingKey(self.___binding) if(key) then self:SetBindingClick(1, key, self, 'LeftButton') end end ]]); self.RegisteredButtons[buttonName] = special; self:SetFrameReferences() --special:Hide() return special end --[[ ########################################################## PACKAGE CALL ########################################################## ]]-- function SuperButton:Initialize() self:SetParent(SV.Screen) self:SetPointToScale("BOTTOM", SV.Screen, "BOTTOM", 0, 325) self:SetSizeToScale(50,50) SV.Mentalo:Add(self, L["Special Ability Button"]) end SV.SuperButton = SuperButton;