Quantcast
--[[
##############################################################################
_____/\\\\\\\\\\\____/\\\________/\\\__/\\\________/\\\__/\\\\\\\\\\\_       #
 ___/\\\/////////\\\_\/\\\_______\/\\\_\/\\\_______\/\\\_\/////\\\///__      #
  __\//\\\______\///__\//\\\______/\\\__\/\\\_______\/\\\_____\/\\\_____     #
   ___\////\\\__________\//\\\____/\\\___\/\\\_______\/\\\_____\/\\\_____    #
    ______\////\\\________\//\\\__/\\\____\/\\\_______\/\\\_____\/\\\_____   #
     _________\////\\\______\//\\\/\\\_____\/\\\_______\/\\\_____\/\\\_____  #
      __/\\\______\//\\\______\//\\\\\______\//\\\______/\\\______\/\\\_____ #
       _\///\\\\\\\\\\\/________\//\\\________\///\\\\\\\\\/____/\\\\\\\\\\\_#
        ___\///////////___________\///___________\/////////_____\///////////_#
##############################################################################
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 ipairs 	= _G.ipairs;
local type 		= _G.type;
local tinsert 	= _G.tinsert;
local string 	= _G.string;
--[[ STRING METHODS ]]--
local format, gsub = string.format, string.gsub;
--[[
##########################################################
GET ADDON DATA
##########################################################
]]--
local SV, L, Registry = unpack(select(2, ...));
--[[
##########################################################
Simple click2cast spell binder(sBinder by Fernir)
##########################################################
]]--
local DB = {};
DB.spells = DB.spells or {}
DB.frames = DB.frames or {}
DB.keys = DB.keys or {}

local binder = CreateFrame("Frame", "SVUI_SpellBinder", SpellBookFrame, "ButtonFrameTemplate")
binder:SetPoint("TOPLEFT", SpellBookFrame, "TOPRIGHT", 100, 0)
binder:SetSize(300, 400)
binder:Hide()

binder.title = binder:CreateFontString(nil, "OVERLAY", "GameFontNormal")
binder.title:SetPoint("TOP", binder, "TOP", 0, -5)
binder.title:SetText("Click-Cast Bindings")

binder.sbOpen = false
binder.spellbuttons = {}

binder.list = CreateFrame("ScrollFrame", "SVUI_SpellBinderSpellList", _G["SVUI_SpellBinderInset"], "UIPanelScrollFrameTemplate")
binder.list.child = CreateFrame("Frame", nil, binder.list)
binder.list:SetPoint("TOPLEFT", _G["SVUI_SpellBinderInset"], "TOPLEFT", 0, -5)
binder.list:SetPoint("BOTTOMRIGHT", _G["SVUI_SpellBinderInset"], "BOTTOMRIGHT", -30, 5)
binder.list:SetScrollChild(binder.list.child)

binder.roster = {}

local BoundSpell_OnEnter = function(self)
	self.delete:GetNormalTexture():SetVertexColor(1, 0, 0)
	self:SetBackdrop({bgFile = "Interface\\Buttons\\WHITE8x8"})
	self:SetBackdropColor(0.2, 0.2, 0.2, 0.7)
end

local BoundSpell_OnLeave = function(self)
	self.delete:GetNormalTexture():SetVertexColor(0.8, 0, 0)
	self:SetBackdrop(nil)
end

local Temp_OnUpdate = function(self)
	self:UpdateAll()
	if self.updated then
		self:UnregisterEvent("PLAYER_REGEN_ENABLED")
	end
end

local SpellBindTab_OnEnter = function(self)
	GameTooltip:ClearLines()
	GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
	GameTooltip:AddLine("Click-Cast Binding")
	GameTooltip:Show()
end

local SpellBindTab_OnLeave = function(self)
	GameTooltip:Hide()
end

local SpellBindTab_OnShow = function(self)
	if binder:IsVisible() then self:SetChecked(true) end
	local num = GetNumSpellTabs()
	local lastTab = _G["SpellBookSkillLineTab"..num]

	self:ClearAllPoints()
	self:SetPoint("TOPLEFT", lastTab, "BOTTOMLEFT", 0, -17)

	self:SetScript("OnEnter", SpellBindTab_OnEnter)
	self:SetScript("OnLeave", SpellBindTab_OnLeave)
end

local SpellBindTab_OnClick = function(self)
	if InCombatLockdown() then binder:Hide() return end
	if binder:IsVisible() then
		binder:Hide()
		binder.sbOpen = false
	else
		binder:Show()
		binder.sbOpen = true
	end
	binder:ToggleButtons()
end

local SpellBindClose_OnClick = function(self)
	binder:Hide()
	binder.sbOpen = false
	binder:ToggleButtons()
end

local _hook_SpellBookFrame_OnUpdate = function(self)
	if binder.sbOpen then binder:ToggleButtons() end
end

local _hook_SpellBookFrame_OnHide = function(self)
	binder:Hide()
	binder.sbOpen = false
	binder:ToggleButtons()
end

local addSpell = function(self, button)
	if binder.sbOpen then
		local slot = SpellBook_GetSpellBookSlot(self:GetParent())
		local spellname, subtype = GetSpellBookItemName(slot, SpellBookFrame.bookType)
		local texture = GetSpellBookItemTexture(slot, SpellBookFrame.bookType)

		if spellname ~= 0 and ((SpellBookFrame.bookType == BOOKTYPE_PET) or (SpellBookFrame.selectedSkillLine > 1)) then
			local originalbutton = button
			local modifier = ""

			if IsShiftKeyDown() then modifier = "Shift-"..modifier end
			if IsControlKeyDown() then modifier = "Ctrl-"..modifier end
			if IsAltKeyDown() then modifier = "Alt-"..modifier end

			if IsHarmfulSpell(slot, SpellBookFrame.bookType) then
				button = format("%s%d", "harmbutton", SecureButton_GetButtonSuffix(button))
				originalbutton = "|cffff2222(harm)|r "..originalbutton
			else
				button = SecureButton_GetButtonSuffix(button)
			end

			for i, v in pairs(DB.spells) do if v.spell == spellname then return end end

			tinsert(DB.spells, {["id"] = slot, ["modifier"] = modifier, ["button"] = button, ["spell"] = spellname, ["rank"] = rank, ["texture"] = texture, ["origbutton"] = originalbutton,})
			binder:BuildSpells(false)
		end
	end
end

local SpellBind_OnEvent = function(self, event, ...)
	if event == "PLAYER_LOGIN" then
		DB = SVUI_Cache["Bindings"] or {}
		DB.spells = DB.spells or {}
		DB.frames = DB.frames or {}
		DB.keys = DB.keys or {}
		binder:BuildList()
		binder:BuildSpells(true)

		for i = 1, SPELLS_PER_PAGE do
			local parent = _G["SpellButton"..i]
			local button = CreateFrame("Button", "SpellButtonMask"..i, parent)
			button:SetID(parent:GetID())
			button:RegisterForClicks("AnyDown")
			button:SetAllPoints(parent)
			button:SetScript("OnClick", addSpell)

			button.shine = SpellBook_GetAutoCastShine()
			button.shine:Show()
			button.shine:SetParent(button)
			button.shine:SetAllPoints()
			AutoCastShine_AutoCastStart(button.shine)

			button:Hide()
			binder.spellbuttons[i] = button
		end

		self:UnregisterEvent("PLAYER_LOGIN")
	elseif event == "PLAYER_ENTERING_WORLD" or event == "GROUP_ROSTER_UPDATE" or event == "ZONE_CHANGED" or event == "ZONE_CHANGED_NEW_AREA" then
		binder:UpdateAll()
	end
end

local function binder_BuildSpells(self, delete)
	local oldb
	local scroll = self.list.child
	scroll:SetPoint("TOPLEFT")
	scroll:SetSize(270, 300)

	if delete then
		i = 1
		while _G[i.."_cbs"] do
			_G[i.."_fs"]:SetText("")
			_G[i.."_texture"]:SetTexture(0,0,0,0)
			_G[i.."_cbs"].checked = false
			_G[i.."_cbs"]:ClearAllPoints()
			_G[i.."_cbs"]:Hide()
			i = i + 1
		end
	end

	for i, spell in ipairs(DB.spells) do
		v = spell.spell
		if v then
			local bf = _G[i.."_cbs"] or CreateFrame("Button", i.."_cbs", scroll)
			spell.checked = spell.checked or false

			if i == 1 then
				bf:SetPoint("TOPLEFT", scroll, "TOPLEFT", 10, -10)
				bf:SetPoint("BOTTOMRIGHT", scroll, "TOPRIGHT", -10, -34)
			else
				bf:SetPoint("TOPLEFT", oldb, "BOTTOMLEFT", 0, -2)
				bf:SetPoint("BOTTOMRIGHT", oldb, "BOTTOMRIGHT", 0, -26)
			end

			bf:EnableMouse(true)

			bf.tex = bf.tex or bf:CreateTexture(i.."_texture", "OVERLAY")
			bf.tex:SetSize(22, 22)
			bf.tex:SetPoint("LEFT")
			bf.tex:SetTexture(spell.texture)
			bf.tex:SetTexCoord(0.1, 0.9, 0.1, 0.9)

			bf.delete = bf.delete or CreateFrame("Button", i.."_delete", bf)
			bf.delete:SetSize(16, 16)
			bf.delete:SetPoint("RIGHT")
			bf.delete:SetNormalTexture("Interface\\BUTTONS\\UI-GroupLoot-Pass-Up")
			bf.delete:GetNormalTexture():SetVertexColor(0.8, 0, 0)
			bf.delete:SetPushedTexture("Interface\\BUTTONS\\UI-GroupLoot-Pass-Up")
			bf.delete:SetHighlightTexture("Interface\\BUTTONS\\UI-GroupLoot-Pass-Up")
			bf.delete:SetScript("OnClick", function()
				for j, k in ipairs(DB.spells) do
					if k ~= spell then
						k.checked = false
						_G[j.."_cbs"]:SetBackdropColor(0, 0, 0, 0)
					end
				end
				spell.checked = not spell.checked
				binder:DeleteSpell()
			end)

			bf:SetScript("OnEnter", BoundSpell_OnEnter)
			bf:SetScript("OnLeave", BoundSpell_OnLeave)

			bf.fs = bf.fs or bf:CreateFontString(i.."_fs", "OVERLAY", "GameFontNormal")
			bf.fs:SetText(spell.modifier..spell.origbutton)
			bf.fs:SetPoint("RIGHT", bf.delete, "LEFT", -4, 0)

			for frame,_ in pairs(self.roster) do
				if frame and DB.frames[frame] then
					if frame:CanChangeAttribute() or frame:CanChangeProtectedState() then
						if frame:GetAttribute(spell.modifier.."type"..spell.button) ~= "menu" then
							--frame:RegisterForClicks("AnyDown")
							if spell.button:find("harmbutton") then
								frame:SetAttribute(spell.modifier..spell.button, spell.spell)
								frame:SetAttribute(spell.modifier.."type-"..spell.spell, "spell")
								frame:SetAttribute(spell.modifier.."spell-"..spell.spell, spell.spell)

								DB.keys[spell.modifier..spell.button] = spell.spell
								DB.keys[spell.modifier.."type-"..spell.spell] = "spell"
								DB.keys[spell.modifier.."spell-"..spell.spell] = spell.spell
							else
								frame:SetAttribute(spell.modifier.."type"..spell.button, "spell")
								frame:SetAttribute(spell.modifier.."spell"..spell.button, spell.spell)

								DB.keys[spell.modifier.."type"..spell.button] = "spell"
								DB.keys[spell.modifier.."spell"..spell.button] = spell.spell
							end
						end
					end
				end
			end

			bf:Show()
			oldb = bf
		end
	end
end

local function binder_BuildList(self)
	for frame,_ in pairs(self.roster) do
		DB.frames[frame] = DB.frames[frame] or true
	end
end

local function binder_ToggleButtons(self)
	for i = 1, SPELLS_PER_PAGE do
		if(binder.spellbuttons[i]) then
			binder.spellbuttons[i]:Hide()
			if binder.sbOpen and SpellBookFrame.bookType ~= BOOKTYPE_PROFESSION then
				local slot = SpellBook_GetSpellBookSlot(binder.spellbuttons[i]:GetParent())
				if slot then
					local spellname, subtype = GetSpellBookItemName(slot, SpellBookFrame.bookType)
					if spellname then
						binder.spellbuttons[i]:Show()
					end
				end
			end
		end
	end
	binder:BuildList()
	binder:BuildSpells(true)
	if binder:IsVisible() then binder.tab:SetChecked(true) else binder.tab:SetChecked(false) end
end

local function binder_DeleteSpell(self)
	local count = table.getn(DB.spells)
	for i, spell in ipairs(DB.spells) do
		if spell.checked then
			for frame,_ in pairs(self.roster) do
				local f
				if frame and type(frame) == "table" then f = frame:GetName() end
				if f then
					if frame:CanChangeAttribute() or frame:CanChangeProtectedState() then
						if frame:GetAttribute(spell.modifier.."type"..spell.button) ~= "menu" then
							if spell.button:find("harmbutton") then
								frame:SetAttribute(spell.modifier..spell.button, nil)
								frame:SetAttribute(spell.modifier.."type-"..spell.spell, nil)
								frame:SetAttribute(spell.modifier.."spell-"..spell.spell, nil)
							else
								frame:SetAttribute(spell.modifier.."type"..spell.button, nil)
								frame:SetAttribute(spell.modifier.."spell"..spell.button, nil)
							end
						end
					end
				end
			end
			tremove(DB.spells, i)
		end
	end
	self:BuildSpells(true)
end

local function binder_UpdateAll(self)
	if InCombatLockdown() then
		self:SheduleUpdate()
		return
	end
	self:BuildList()
	self:BuildSpells(true)
end

local function binder_SheduleUpdate(self)
	self.updated = false
	if InCombatLockdown() then
		self:RegisterEvent("PLAYER_REGEN_ENABLED")
		self:SetScript("OnEvent", Temp_OnUpdate)
	else
		self:UpdateAll()
	end
end
--[[
##########################################################
LOADER
##########################################################
]]--
local function enable(frame)
    if type(frame) == "string" then
        local frameName = frame
        frame = _G[frameName]
    end

    if frame then
        binder.roster[frame] = true
    end
end

local BindableFrames = SV.SVUnit.Roster
for frame,_ in pairs(BindableFrames) do
	binder.roster[frame] = true
end

binder.BuildSpells = binder_BuildSpells
binder.BuildList = binder_BuildList
binder.ToggleButtons = binder_ToggleButtons
binder.DeleteSpell = binder_DeleteSpell
binder.UpdateAll = binder_UpdateAll
binder.SheduleUpdate = binder_SheduleUpdate

_G["SVUI_SpellBinderCloseButton"]:SetScript("OnClick", SpellBindClose_OnClick)
hooksecurefunc("SpellBookFrame_Update", _hook_SpellBookFrame_OnUpdate)
hooksecurefunc(SpellBookFrame, "Hide", _hook_SpellBookFrame_OnHide)

binder:RemoveTextures()
_G["SVUI_SpellBinderInset"]:RemoveTextures()

binder:SetPanelTemplate("Action")
binder.Panel:SetPoint("TOPLEFT", -18, 0)
binder.Panel:SetPoint("BOTTOMRIGHT", 0, 0)

binder.list:RemoveTextures()
binder.list:SetPanelTemplate("Inset")

binder.tab = CreateFrame("CheckButton", nil, _G["SpellBookSkillLineTab1"], "SpellBookSkillLineTabTemplate")
binder.tab:RemoveTextures()
binder.tab:SetButtonTemplate()
binder.tab:SetNormalTexture("Interface\\ICONS\\Achievement_Guild_Doctorisin")
binder.tab:GetNormalTexture():ClearAllPoints()
binder.tab:GetNormalTexture():SetPoint("TOPLEFT", 2, -2)
binder.tab:GetNormalTexture():SetPoint("BOTTOMRIGHT", -2, 2)
binder.tab:GetNormalTexture():SetTexCoord(0.1, 0.9, 0.1, 0.9)
binder.tab:SetScript("OnShow", SpellBindTab_OnShow)
binder.tab:SetScript("OnClick", SpellBindTab_OnClick)
binder.tab:Show()

binder:RegisterEvent("GROUP_ROSTER_UPDATE")
binder:RegisterEvent("PLAYER_ENTERING_WORLD")
binder:RegisterEvent("PLAYER_LOGIN")
binder:RegisterEvent("ZONE_CHANGED_NEW_AREA")
binder:RegisterEvent("ZONE_CHANGED")
binder:SetScript("OnEvent", SpellBind_OnEvent)

local function LoadSpellBinder()
	local BindableFrames = SV.SVUnit.Roster
	for frame,_ in pairs(BindableFrames) do
		binder.roster[frame] = true
	end
end

Registry:NewScript(LoadSpellBinder)