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 type 		= _G.type;
local string 	= _G.string;
local math 		= _G.math;
--[[ STRING METHODS ]]--
local format, split = string.format, string.split;
--[[ MATH METHODS ]]--
local min, floor = math.min, math.floor;
local parsefloat = math.parsefloat;
--[[
##########################################################
GET ADDON DATA
##########################################################
]]--
local SuperVillain, L = unpack(select(2, ...));
SuperVillain.MentaloFrames = {}
local Sticky = {};
Sticky.scripts = Sticky.scripts or {}
Sticky.rangeX = 15
Sticky.rangeY = 15
Sticky.sticky = Sticky.sticky or {}

local function SnapStickyFrame(frameA, frameB, left, top, right, bottom)
	local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale()
	local xA, yA = frameA:GetCenter()
	local xB, yB = frameB:GetCenter()
	local hA, hB = frameA:GetHeight()  /  2, ((frameB:GetHeight()  *  sB)  /  sA)  /  2
	local wA, wB = frameA:GetWidth()  /  2, ((frameB:GetWidth()  *  sB)  /  sA)  /  2
	local newX, newY = xA, yA
	if not left then left = 0 end
	if not top then top = 0 end
	if not right then right = 0 end
	if not bottom then bottom = 0 end
	if not xB or not yB or not sB or not sA or not sB then return end
	xB, yB = (xB * sB)  /  sA, (yB * sB)  /  sA
	local stickyAx, stickyAy = wA  *  0.75, hA  *  0.75
	local stickyBx, stickyBy = wB  *  0.75, hB  *  0.75
	local lA, tA, rA, bA = frameA:GetLeft(), frameA:GetTop(), frameA:GetRight(), frameA:GetBottom()
	local lB, tB, rB, bB = frameB:GetLeft(), frameB:GetTop(), frameB:GetRight(), frameB:GetBottom()
	local snap = nil
	lB, tB, rB, bB = (lB  *  sB)  /  sA, (tB  *  sB)  /  sA, (rB  *  sB)  /  sA, (bB  *  sB)  /  sA
	if (bA  <= tB and bB  <= tA) then
		if xA  <= (xB  +  Sticky.rangeX) and xA  >= (xB - Sticky.rangeX) then
			newX = xB
			snap = true
		end
		if lA  <= (lB  +  Sticky.rangeX) and lA  >= (lB - Sticky.rangeX) then
			newX = lB  +  wA
			if frameB == UIParent or frameB == WorldFrame or frameB == SVUIParent then
				newX = newX  +  4
			end
			snap = true
		end
		if rA  <= (rB  +  Sticky.rangeX) and rA  >= (rB - Sticky.rangeX) then
			newX = rB - wA
			if frameB == UIParent or frameB == WorldFrame or frameB == SVUIParent then
				newX = newX - 4
			end
			snap = true
		end
		if lA  <= (rB  +  Sticky.rangeX) and lA  >= (rB - Sticky.rangeX) then
			newX = rB  +  (wA - left)
			snap = true
		end
		if rA  <= (lB  +  Sticky.rangeX) and rA  >= (lB - Sticky.rangeX) then
			newX = lB - (wA - right)
			snap = true
		end
	end
	if (lA  <= rB and lB  <= rA) then
		if yA  <= (yB  +  Sticky.rangeY) and yA  >= (yB - Sticky.rangeY) then
			newY = yB
			snap = true
		end
		if tA  <= (tB  +  Sticky.rangeY) and tA  >= (tB - Sticky.rangeY) then
			newY = tB - hA
			if frameB == UIParent or frameB == WorldFrame or frameB == SVUIParent then
				newY = newY - 4
			end
			snap = true
		end
		if bA  <= (bB  +  Sticky.rangeY) and bA  >= (bB - Sticky.rangeY) then
			newY = bB  +  hA
			if frameB == UIParent or frameB == WorldFrame or frameB == SVUIParent then
				newY = newY  +  4
			end
			snap = true
		end
		if tA  <= (bB  +  Sticky.rangeY  +  bottom) and tA  >= (bB - Sticky.rangeY  +  bottom) then
			newY = bB - (hA - top)
			snap = true
		end
		if bA  <= (tB  +  Sticky.rangeY - top) and bA  >= (tB - Sticky.rangeY - top) then
			newY = tB  +  (hA - bottom)
			snap = true
		end
	end
	if snap then
		frameA:ClearAllPoints()
		frameA:SetPoint("CENTER", UIParent, "BOTTOMLEFT", newX, newY)
		return true
	end
end

local function GetStickyUpdate(frame, frameList, xoffset, yoffset, left, top, right, bottom)
	return function()
		local x, y = GetCursorPosition()
		local s = frame:GetEffectiveScale()
		local sticky = nil
		x, y = x / s, y / s
		frame:ClearAllPoints()
		frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x + xoffset, y + yoffset)
		Sticky.sticky[frame] = nil
		for i = 1, #frameList do
			local v = frameList[i]
			if frame  ~= v and frame  ~= v:GetParent() and not IsShiftKeyDown() and v:IsVisible() then
				if SnapStickyFrame(frame, v, left, top, right, bottom) then
					Sticky.sticky[frame] = v
					break
				end
			end
		end
	end
end

function Sticky:StartMoving(frame, frameList, left, top, right, bottom)
	local x, y = GetCursorPosition()
	local aX, aY = frame:GetCenter()
	local aS = frame:GetEffectiveScale()
	aX, aY = aX * aS, aY * aS
	local xoffset, yoffset = (aX - x), (aY - y)
	self.scripts[frame] = frame:GetScript("OnUpdate")
	frame:SetScript("OnUpdate", GetStickyUpdate(frame, frameList, xoffset, yoffset, left, top, right, bottom))
end

function Sticky:StopMoving(frame)
	frame:SetScript("OnUpdate", self.scripts[frame])
	self.scripts[frame] = nil
	if self.sticky[frame] then
		local sticky = self.sticky[frame]
		self.sticky[frame] = nil
		return true, sticky
	else
		return false, nil
	end
end
--[[
##########################################################
LOCAL VARS
##########################################################
]]--
local CurrentFrameTarget = false;
local UpdateFrameTarget = false;
local userHolding = false;
local HandledFrames = {};
local DraggableFrames = {
	"AchievementFrame",
	"AuctionFrame",
	"ArchaeologyFrame",
	"BattlefieldMinimap",
	"BarberShopFrame",
	"BlackMarketFrame",
	"CalendarFrame",
	"CharacterFrame",
	"ClassTrainerFrame",
	"DressUpFrame",
	"EncounterJournal",
	"FriendsFrame",
	"GameMenuFrame",
	"GMSurveyFrame",
	"GossipFrame",
	"GuildFrame",
	"GuildBankFrame",
	"GuildRegistrarFrame",
	"HelpFrame",
	"InterfaceOptionsFrame",
	"ItemUpgradeFrame",
	"KeyBindingFrame",
	"LFGDungeonReadyPopup",
	"LossOfControlFrame",
	"MacOptionsFrame",
	"MacroFrame",
	"MailFrame",
	"MerchantFrame",
	"PlayerTalentFrame",
	"PetJournalParent",
	"PVEFrame",
	"PVPFrame",
	"QuestFrame",
	"QuestLogFrame",
	"RaidBrowserFrame",
	"ReadyCheckFrame",
	"ReforgingFrame",
	"ReportCheatingDialog",
	"ReportPlayerNameDialog",
	"RolePollPopup",
	"ScrollOfResurrectionSelectionFrame",
	"SpellBookFrame",
	"TabardFrame",
	"TaxiFrame",
	"TimeManagerFrame",
	"TradeSkillFrame",
	"TradeFrame",
	"TransmorgifyFrame",
	"TutorialFrame",
	"VideoOptionsFrame",
	"VoidStorageFrame",
	--"WorldStateAlwaysUpFrame"
};

local theHand = CreateFrame("Frame", "SVUI_HandOfMentalo", SuperVillain.UIParent)
theHand:SetFrameStrata("DIALOG")
theHand:SetFrameLevel(99)
theHand:SetClampedToScreen(true)
theHand:SetSize(128,128)
theHand:SetPoint("CENTER")
--[[
##########################################################
LOCAL FUNCTIONS
##########################################################
]]--
local function Pinpoint(parent)
    local centerX, centerY = parent:GetCenter()
    local screenWidth = GetScreenWidth()
    local screenHeight = GetScreenHeight()
    local result;
    if not centerX or not centerY then
        return "CENTER"
    end
    local heightTop = screenHeight  *  0.75;
    local heightBottom = screenHeight  *  0.25;
    local widthLeft = screenWidth  *  0.25;
    local widthRight = screenWidth  *  0.75;
    if(((centerX > widthLeft) and (centerX < widthRight)) and (centerY > heightTop)) then
        result = "TOP"
    elseif((centerX < widthLeft) and (centerY > heightTop)) then
        result = "TOPLEFT"
    elseif((centerX > widthRight) and (centerY > heightTop)) then
        result = "TOPRIGHT"
    elseif(((centerX > widthLeft) and (centerX < widthRight)) and centerY < heightBottom) then
        result = "BOTTOM"
    elseif((centerX < widthLeft) and (centerY < heightBottom)) then
        result = "BOTTOMLEFT"
    elseif((centerX > widthRight) and (centerY < heightBottom)) then
        result = "BOTTOMRIGHT"
    elseif((centerX < widthLeft) and (centerY > heightBottom) and (centerY < heightTop)) then
        result = "LEFT"
    elseif((centerX > widthRight) and (centerY < heightTop) and (centerY > heightBottom)) then
        result = "RIGHT"
    else
        result = "CENTER"
    end
    return result
end

local function TheHand_SetPos(frame)
	theHand:SetPoint("CENTER", frame, "TOP", 0, 0)
end

local TheHand_OnUpdate = function(self, elapsed)
	self.elapsedTime = self.elapsedTime  +  elapsed
	if self.elapsedTime > 0.1 then
		self.elapsedTime = 0
		local x, y = GetCursorPosition()
		local scale = SuperVillain.UIParent:GetEffectiveScale()
		self:SetPoint("CENTER", SuperVillain.UIParent, "BOTTOMLEFT", (x  /  scale)  +  50, (y  /  scale)  +  50)
	end
end

local function EnableTheHand()
	theHand:Show()
	theHand.bg:SetTexture([[Interface\AddOns\SVUI\assets\artwork\Doodads\MENTALO-HAND-ON]])
	theHand.energy:Show()
	theHand.flash:Play()
	theHand:SetScript("OnUpdate", TheHand_OnUpdate)
end

local function DisableTheHand()
	theHand.flash:Stop()
	theHand.energy:Hide()
	theHand.bg:SetTexture([[Interface\AddOns\SVUI\assets\artwork\Doodads\MENTALO-HAND-OFF]])
	theHand:SetScript("OnUpdate", nil)
	theHand.elapsedTime = 0
	theHand:Hide()
end

local function Mentalo_OnSizeChanged(frame)
	if InCombatLockdown()then return end
	if frame.dirtyWidth and frame.dirtyHeight then
		frame.Avatar:Size(frame.dirtyWidth, frame.dirtyHeight)
	else
		frame.Avatar:Size(frame:GetSize())
	end
end

local function MakeMovable(frame)
	if HandledFrames then
		for _, f in pairs(HandledFrames)do
			if frame:GetName() == f then return end
		end
	end
	if SVUI and frame:GetName() == "LossOfControlFrame" then return end
	frame:EnableMouse(true)
	if frame:GetName() == "LFGDungeonReadyPopup" then
		LFGDungeonReadyDialog:EnableMouse(false)
	end
	frame:SetMovable(true)
	frame:RegisterForDrag("LeftButton")
	frame:SetClampedToScreen(true)
	frame:HookScript("OnUpdate", function(this)
		if InCombatLockdown() or this:GetName() == "GameMenuFrame" then return end
		if this.IsMoving then return end
		this:ClearAllPoints()
		if this:GetName() == "QuestFrame" then
			if SVUI_Cache["Mentalo"]["GossipFrame"].Points  ~= nil then
				this:SetPoint(unpack(SVUI_Cache["Mentalo"]["GossipFrame"].Points))
			end
		elseif SVUI_Cache["Mentalo"][this:GetName()].Points  ~= nil then
			this:SetPoint(unpack(SVUI_Cache["Mentalo"][this:GetName()].Points))
		end
	end)
	frame:SetScript("OnDragStart", function(this)
		if not this:IsMovable() then return end
		this:StartMoving()
		this.IsMoving = true
	end)
	frame:SetScript("OnDragStop", function(this)
		if not this:IsMovable() then return end
		this.IsMoving = false;
		this:StopMovingOrSizing()
		if this:GetName() == "GameMenuFrame"then return end
		local anchor1, parent, anchor2, x, y = this:GetPoint()
		parent = this:GetParent():GetName()
		this:ClearAllPoints()
		this:SetPoint(anchor1, parent, anchor2, x, y)
		if this:GetName() == "QuestFrame" then
			SVUI_Cache["Mentalo"]["GossipFrame"].Points = {anchor1, parent, anchor2, x, y}
		else
			SVUI_Cache["Mentalo"][this:GetName()].Points = {anchor1, parent, anchor2, x, y}
		end
	end)
	tinsert(HandledFrames, frame:GetName())
end

local function GrabUsableRegions(frame)
	local parent = frame or SuperVillain.UIParent
	local right = parent:GetRight()
	local top = parent:GetTop()
	local center = parent:GetCenter()
	return right, top, center
end

local function FindLoc(frame)
	if not frame then return end
	local anchor1, parent, anchor2, x, y = frame:GetPoint()
	if not parent then
		parent = SVUIParent
	end
	return format("%s\031%s\031%s\031%d\031%d", anchor1, parent:GetName(), anchor2, parsefloat(x), parsefloat(y))
end

local function ghost(list, alpha)
	local frame;
	for f, _ in pairs(list)do
		frame = _G[f]
		if frame then
			frame:SetAlpha(alpha)
		end
	end
end

local function SetSVMovable(frame, moveName, title, raised, snap, dragStopFunc)
	if not frame then return end
	if SuperVillain.MentaloFrames[moveName].Created then return end
	if raised == nil then raised = true end
	local movable = CreateFrame("Button", moveName, SuperVillain.UIParent)
	movable:SetFrameLevel(frame:GetFrameLevel()   +   1)
	movable:SetClampedToScreen(true)
	movable:SetWidth(frame:GetWidth())
	movable:SetHeight(frame:GetHeight())
	movable.parent = frame;
	movable.name = moveName;
	movable.textString = title;
	movable.postdrag = dragStopFunc;
	movable.overlay = raised;
	movable.snapOffset = snap or -2;
	SuperVillain.MentaloFrames[moveName].Avatar = movable;
	SuperVillain["snaps"][#SuperVillain["snaps"] + 1] = movable;
	if raised == true then
		movable:SetFrameStrata("DIALOG")
	else
		movable:SetFrameStrata("BACKGROUND")
	end
	local anchor1, anchorParent, anchor2, xPos, yPos = split("\031", FindLoc(frame))
	if SuperVillain.db.framelocations and SuperVillain.db.framelocations[moveName] then
		if type(SuperVillain.db.framelocations[moveName]) == "table"then
			movable:SetPoint(SuperVillain.db.framelocations[moveName]["p"], SuperVillain.UIParent, SuperVillain.db.framelocations[moveName]["p2"], SuperVillain.db.framelocations[moveName]["p3"], SuperVillain.db.framelocations[moveName]["p4"])
			SuperVillain.db.framelocations[moveName] = FindLoc(movable)
			movable:ClearAllPoints()
		end
		anchor1, anchorParent, anchor2, xPos, yPos = split("\031", SuperVillain.db.framelocations[moveName])
		movable:SetPoint(anchor1, anchorParent, anchor2, xPos, yPos)
	else
		movable:SetPoint(anchor1, anchorParent, anchor2, xPos, yPos)
	end
	movable:SetFixedPanelTemplate("Transparent")
	movable:SetAlpha(0.4)
	movable:RegisterForDrag("LeftButton", "RightButton")
	movable:SetScript("OnDragStart", function(this)
		if InCombatLockdown()then SuperVillain:AddonMessage(ERR_NOT_IN_COMBAT)return end
		if SuperVillain.db["system"].stickyFrames then
			Sticky:StartMoving(this, SuperVillain["snaps"], movable.snapOffset, movable.snapOffset, movable.snapOffset, movable.snapOffset)
		else
			this:StartMoving()
		end
		UpdateFrameTarget = this;
		_G["SVUI_MentaloEventHandler"]:Show()
		EnableTheHand()
		userHolding = true
	end)
	movable:SetScript("OnMouseUp", SuperVillain.MovableFocused)
	movable:SetScript("OnDragStop", function(this)
		if InCombatLockdown()then SuperVillain:AddonMessage(ERR_NOT_IN_COMBAT)return end
		userHolding = false;
		if SuperVillain.db["system"].stickyFrames then
			Sticky:StopMoving(this)
		else
			this:StopMovingOrSizing()
		end
		local pR, pT, pC = GrabUsableRegions()
		local cX, cY = this:GetCenter()
		local newAnchor;
		if cY   >= (pT   /   2) then
			newAnchor = "TOP";
			cY = (-(pT - this:GetTop()))
		else
			newAnchor = "BOTTOM"
			cY = this:GetBottom()
		end
		if cX   >= ((pR   *   2)   /   3) then
			newAnchor = newAnchor.."RIGHT"
			cX = this:GetRight() - pR
		elseif cX   <= (pR   /   3) then
			newAnchor = newAnchor.."LEFT"
			cX = this:GetLeft()
		else
			cX = cX - pC
		end
		if this.positionOverride then
			this.parent:ClearAllPoints()
			this.parent:Point(this.positionOverride, this, this.positionOverride)
		end
		this:ClearAllPoints()
		this:Point(newAnchor, SuperVillain.UIParent, newAnchor, cX, cY)
		SuperVillain:SaveMovableLoc(moveName)
		if SVUI_MentaloPrecision then
			SuperVillain:MentaloFocusUpdate(this)
		end
		UpdateFrameTarget = nil;
		_G["SVUI_MentaloEventHandler"]:Hide()
		if dragStopFunc  ~= nil and type(dragStopFunc) == "function" then
			dragStopFunc(this, Pinpoint(this))
		end
		this:SetUserPlaced(false)
		DisableTheHand()
	end)

	frame:SetScript("OnSizeChanged", Mentalo_OnSizeChanged)
	frame.Avatar = movable;
	frame:ClearAllPoints()
	frame:SetPoint(anchor1, movable, 0, 0)

	local u = movable:CreateFontString(nil, "OVERLAY")
	u:SetFontTemplate()
	u:SetJustifyH("CENTER")
	u:SetPoint("CENTER")
	u:SetText(title or moveName)
	u:SetTextColor(unpack(SuperVillain.Media.color.highlight))

	movable:SetFontString(u)
	movable.text = u;
	movable:SetScript("OnEnter", function(this)
		if userHolding then return end
		this:SetAlpha(1)
		this.text:SetTextColor(1, 1, 1)
		UpdateFrameTarget = this;
		_G["SVUI_MentaloEventHandler"]:GetScript("OnUpdate")(_G["SVUI_MentaloEventHandler"])
		SVUI_Mentalo.Avatar:SetTexture([[Interface\AddOns\SVUI\assets\artwork\Doodads\MENTALO-ON]])
		TheHand_SetPos(this)
		theHand:Show()
		if CurrentFrameTarget  ~= this then
			SVUI_MentaloPrecision:Hide()
			SuperVillain.MovableFocused(this)
		end
	end)
	movable:SetScript("OnMouseDown", function(this, arg)
		if arg == "RightButton"then
			userHolding = false;
			SVUI_MentaloPrecision:Show()
			if SuperVillain.db["system"].stickyFrames then
				Sticky:StopMoving(this)
			else
				this:StopMovingOrSizing()
			end
		end
	end)
	movable:SetScript("OnLeave", function(this)
		if userHolding then return end
		this:SetAlpha(0.4)
		this.text:SetTextColor(unpack(SuperVillain.Media.color.highlight))
		SVUI_Mentalo.Avatar:SetTexture([[Interface\AddOns\SVUI\assets\artwork\Doodads\MENTALO-OFF]])
		theHand:Hide()
	end)
	movable:SetScript("OnShow", function(this)this:SetBackdropBorderColor(unpack(SuperVillain.Media.color.highlight))end)
	movable:SetMovable(true)
	movable:Hide()
	if dragStopFunc  ~= nil and type(dragStopFunc) == "function"then
		movable:RegisterEvent("PLAYER_ENTERING_WORLD")
		movable:SetScript("OnEvent", function(this, event)
			dragStopFunc(movable, Pinpoint(movable))
			this:UnregisterAllEvents()
		end)
	end
	SuperVillain.MentaloFrames[moveName].Created = true
end
--[[
##########################################################
GLOBAL/MODULE FUNCTIONS
##########################################################
]]--
function SuperVillain:MentaloForced(frame)
	if _G[frame] and _G[frame]:GetScript("OnDragStop") then
		_G[frame]:GetScript("OnDragStop")(_G[frame])
	end
end

function SuperVillain:TestMovableMoved(frame)
	if SuperVillain.db.framelocations and SuperVillain.db.framelocations[frame] then
		return true
	else
		return false
	end
end

function SuperVillain:SaveMovableLoc(frame)
	if not _G[frame] then return end
	if not SuperVillain.db.framelocations then
		SuperVillain.db.framelocations = {}
	end
	SuperVillain.db.framelocations[frame] = FindLoc(_G[frame])
end

function SuperVillain:SetSnapOffset(frame, snapOffset)
	if not _G[frame] or not SuperVillain.MentaloFrames[frame] then return end
	SuperVillain.MentaloFrames[frame].Avatar.snapOffset = snapOffset or -2;
	SuperVillain.MentaloFrames[frame]["snapoffset"] = snapOffset or -2
end

function SuperVillain:SaveMovableOrigin(frame)
	if not _G[frame] then return end
	SuperVillain.MentaloFrames[frame]["point"] = FindLoc(_G[frame])
	SuperVillain.MentaloFrames[frame]["postdrag"](_G[frame], Pinpoint(_G[frame]))
end

function SuperVillain:SetSVMovable(frame, moveName, title, raised, snapOffset, dragStopFunc, movableGroup)
	if not movableGroup then movableGroup = "ALL, GENERAL" end
	if SuperVillain.MentaloFrames[moveName] == nil then
		SuperVillain.MentaloFrames[moveName] = {}
		SuperVillain.MentaloFrames[moveName]["parent"] = frame;
		SuperVillain.MentaloFrames[moveName]["text"] = title;
		SuperVillain.MentaloFrames[moveName]["overlay"] = raised;
		SuperVillain.MentaloFrames[moveName]["postdrag"] = dragStopFunc;
		SuperVillain.MentaloFrames[moveName]["snapoffset"] = snapOffset;
		SuperVillain.MentaloFrames[moveName]["point"] = FindLoc(frame)
		SuperVillain.MentaloFrames[moveName]["type"] = {}
		local group = {split(", ", movableGroup)}
		for i = 1, #group do
			local this = group[i]
			SuperVillain.MentaloFrames[moveName]["type"][this] = true
		end
	end
	SetSVMovable(frame, moveName, title, raised, snapOffset, dragStopFunc)
end

function SuperVillain:ToggleMovables(enabled, configType)
	for frameName, _ in pairs(SuperVillain.MentaloFrames)do
		if(_G[frameName]) then
			local movable = _G[frameName]
			if(not enabled) then
				movable:Hide()
			else
				if SuperVillain.MentaloFrames[frameName]["type"][configType]then
					movable:Show()
				else
					movable:Hide()
				end
			end
		end
	end
end

function SuperVillain:ResetMovables(request)
	if request == "" or request == nil then
		for name, _ in pairs(SuperVillain.MentaloFrames)do
			local frame = _G[name];
			if SuperVillain.MentaloFrames[name]["point"] then
				local u, v, w, x, y = split("\031", SuperVillain.MentaloFrames[name]["point"])
				frame:ClearAllPoints()
				frame:SetPoint(u, v, w, x, y)
				for arg, func in pairs(SuperVillain.MentaloFrames[name])do
					if arg == "postdrag" and type(func) == "function" then
						func(frame, Pinpoint(frame))
					end
				end
			end
		end
		SuperVillain.db:SetDefault("framelocations")
	else
		for name, _ in pairs(SuperVillain.MentaloFrames)do
			if SuperVillain.MentaloFrames[name]["point"] then
				for arg1, arg2 in pairs(SuperVillain.MentaloFrames[name])do
					local mover;
					if arg1 == "text" then
						if request == arg2 then
							local frame = _G[name]
							local u, v, w, x, y = split("\031", SuperVillain.MentaloFrames[name]["point"])
							frame:ClearAllPoints()
							frame:SetPoint(u, v, w, x, y)
							if SuperVillain.db.framelocations then
								SuperVillain.db.framelocations[name] = nil
							end
							if (SuperVillain.MentaloFrames[name]["postdrag"] ~= nil and type(SuperVillain.MentaloFrames[name]["postdrag"]) == "function")then
								SuperVillain.MentaloFrames[name]["postdrag"](frame, Pinpoint(frame))
							end
						end
					end
				end
			end
		end
	end
end

function SuperVillain:SetSVMovablesPositions()
	for name, _ in pairs(SuperVillain.MentaloFrames)do
		local frame = _G[name];
		local anchor1, parent, anchor2, x, y;
		if frame then
			if (SuperVillain.db.framelocations and SuperVillain.db.framelocations[name] and type(SuperVillain.db.framelocations[name]) == "string") then
				anchor1, parent, anchor2, x, y = split("\031", SuperVillain.db.framelocations[name])
				frame:ClearAllPoints()
				frame:SetPoint(anchor1, parent, anchor2, x, y)
			elseif SuperVillain.MentaloFrames[name]["point"] then
				anchor1, parent, anchor2, x, y = split("\031", SuperVillain.MentaloFrames[name]["point"])
				frame:ClearAllPoints()
				frame:SetPoint(anchor1, parent, anchor2, x, y)
			end
		end
	end
end

function SuperVillain:LoadMovables()
	theHand.bg = theHand:CreateTexture(nil, "OVERLAY")
	theHand.bg:SetAllPoints(theHand)
	theHand.bg:SetTexture([[Interface\AddOns\SVUI\assets\artwork\Doodads\MENTALO-HAND-OFF]])
	theHand.energy = theHand:CreateTexture(nil, "OVERLAY")
	theHand.energy:SetAllPoints(theHand)
	theHand.energy:SetTexture([[Interface\AddOns\SVUI\assets\artwork\Doodads\MENTALO-ENERGY]])
	SuperVillain.Animate:Orbit(theHand.energy, 10)
	theHand.flash = theHand.energy.anim;
	theHand.energy:Hide()
	theHand.elapsedTime = 0;
	theHand.flash:Stop()
	theHand:Hide()

	for name, _ in pairs(SuperVillain.MentaloFrames)do
		local parent, text, overlay, snapoffset, postdrag;
		for key, value in pairs(SuperVillain.MentaloFrames[name])do
			if(key == "parent") then
				parent = value
			elseif(key == "text") then
				text = value
			elseif(key == "overlay") then
				overlay = value
			elseif(key == "snapoffset") then
				snapoffset = value
			elseif(key == "postdrag") then
				postdrag = value
			end
		end
		SuperVillain:SetMentaloAlphas()
		SetSVMovable(parent, name, text, overlay, snapoffset, postdrag)
	end
end

function SuperVillain:UseMentalo(isConfigMode, configType)
	if(InCombatLockdown()) then return end
	local enabled = false;
	if(isConfigMode  ~= nil and isConfigMode  ~= "") then
		self.ConfigurationMode = isConfigMode
	end

	if(not self.ConfigurationMode) then
		if IsAddOnLoaded("SVUI_ConfigOMatic")then
			LibStub("AceConfigDialog-3.0"):Close("SVUI")
			GameTooltip:Hide()
			self.ConfigurationMode = true
		else
			self.ConfigurationMode = false
		end
	else
		self.ConfigurationMode = false
	end

	if(SVUI_Mentalo:IsShown()) then
		SVUI_Mentalo:Hide()
	else
		SVUI_Mentalo:Show()
		enabled = true
	end

	if(not configType or (configType and type(configType)  ~= "string")) then
		configType = "ALL"
	end

	self:ToggleMovables(enabled, configType)
end

function SuperVillain:MentaloFocus()
	local frame = CurrentFrameTarget;
	local s, t, u = GrabUsableRegions()
	local v, w = frame:GetCenter()
	local x;
	local y = s / 3;
	local z = s * 2 / 3;
	local A = t / 2;
	if w >= A then x = "TOP"else x = "BOTTOM"end
	if v >= z then x = x.."RIGHT"elseif v <= y then x = x.."LEFT"end
	v = tonumber(SVUI_MentaloPrecisionSetX.CurrentValue)
	w = tonumber(SVUI_MentaloPrecisionSetY.CurrentValue)
	frame:ClearAllPoints()
	frame:Point(x, SuperVillain.UIParent, x, v, w)
	SuperVillain:SaveMovableLoc(frame.name)
end

function SuperVillain:MentaloFocusUpdate(frame)
	local s, t, u = GrabUsableRegions()
	local v, w = frame:GetCenter()
	local y = (s / 3);
	local z = ((s * 2) / 3);
	local A = (t / 2);
	if w  >= A then w = -(t - frame:GetTop())else w = frame:GetBottom()end
	if v >= z then v = (frame:GetRight() - s) elseif v  <= y then v = frame:GetLeft()else v = (v - u) end
	v = parsefloat(v, 0)
	w = parsefloat(w, 0)
	SVUI_MentaloPrecisionSetX:SetText(v)
	SVUI_MentaloPrecisionSetY:SetText(w)
	SVUI_MentaloPrecisionSetX.CurrentValue = v;
	SVUI_MentaloPrecisionSetY.CurrentValue = w;
	SVUI_MentaloPrecision.Title:SetText(frame.textString)
end

function SuperVillain:MovableFocused()
	CurrentFrameTarget = self;
	SuperVillain:MentaloFocusUpdate(self)
end

function SuperVillain:SetMentaloAlphas()
	hooksecurefunc(SuperVillain, "SetSVMovable", function(_, frame)
		frame.Avatar:SetAlpha(0.5)
	end)
	ghost(SuperVillain.MentaloFrames, 0.5)
end
--[[
##########################################################
XML FRAME SCRIPT HANDLERS
##########################################################
]]--
function SVUI_MoveEventHandler_OnEvent()
	for _, frame in pairs(DraggableFrames)do
		if _G[frame] then
			if SVUI_Cache["Mentalo"][frame] == nil then
				SVUI_Cache["Mentalo"][frame] = {}
			end
			SVUI_Cache["Mentalo"]["GameMenuFrame"] = {}
			MakeMovable(_G[frame])
		end
	end
end

function SVUI_MentaloEventHandler_Update(self)
	_G["SVUI_MentaloEventHandler"] = self;
	local frame = UpdateFrameTarget;
	local rightPos, topPos, centerPos = GrabUsableRegions()
	local centerX, centerY = frame:GetCenter()
	local calc1 = rightPos  /  3;
	local calc2 = ((rightPos  *  2)  /  3);
	local calc3 = topPos  /  2;
	local anchor1, anchor2;
	if centerY  >= calc3 then
		anchor1 = "TOP"
		anchor2 = "BOTTOM"
		centerY = -(topPos - frame:GetTop())
	else
		anchor1 = "BOTTOM"
		anchor2 = "TOP"
		centerY = frame:GetBottom()
	end
	if centerX  >= calc2 then
		anchor1 = "RIGHT"
		anchor2 = "LEFT"
		centerX = (frame:GetRight() - rightPos)
	elseif centerX  <= calc1 then
		anchor1 = "LEFT"
		anchor2 = "RIGHT"
		centerX = frame:GetLeft()
	else
		centerX = (centerX - centerPos)
	end
	SVUI_MentaloPrecision:ClearAllPoints()
	SVUI_MentaloPrecision:SetPoint(anchor1, frame, anchor2, 0, 0)
	SuperVillain:MentaloFocusUpdate(frame)
end

function SVUI_Mentalo_OnLoad()
	_G["SVUI_Mentalo"]:RegisterEvent("PLAYER_REGEN_DISABLED")
	_G["SVUI_Mentalo"]:RegisterForDrag("LeftButton");
	_G["SVUI_Mentalo"]:SetButtonTemplate()
end

function SVUI_Mentalo_OnEvent()
	if _G["SVUI_Mentalo"]:IsShown() then
		_G["SVUI_Mentalo"]:Hide()
		SuperVillain:UseMentalo(true)
	end
end

function SVUI_MentaloLockButton_OnClick()
	SuperVillain:UseMentalo(true)
	if IsAddOnLoaded("SVUI_ConfigOMatic")then
		LibStub("AceConfigDialog-3.0"):Open("SVUI")
	end
end

function SVUI_MentaloPrecisionResetButton_OnClick()
	local name = CurrentFrameTarget.name
	SuperVillain:ResetMovables(name)
end

function SVUI_MentaloPrecisionInput_EscapePressed(self)
	self:SetText(parsefloat(self.CurrentValue))
	EditBox_ClearFocus(self)
end

function SVUI_MentaloPrecisionInput_EnterPressed(self)
	local txt = tonumber(self:GetText())
	if(txt) then
		self.CurrentValue = txt;
		SuperVillain:MentaloFocus()
	end
	self:SetText(parsefloat(self.CurrentValue))
	EditBox_ClearFocus(self)
end

function SVUI_MentaloPrecisionInput_FocusLost(self)
	self:SetText(parsefloat(self.CurrentValue))
end

function SVUI_MentaloPrecisionInput_OnShow(self)
	EditBox_ClearFocus(self)
	self:SetText(parsefloat(self.CurrentValue or 0))
end

function SVUI_MentaloPrecision_OnLoad()
	_G["SVUI_MentaloPrecisionSetX"].CurrentValue = 0;
	_G["SVUI_MentaloPrecisionSetY"].CurrentValue = 0;
	_G["SVUI_MentaloPrecision"]:EnableMouse(true)
	_G["SVUI_MentaloPrecisionSetX"]:SetEditboxTemplate()
	_G["SVUI_MentaloPrecisionSetY"]:SetEditboxTemplate()
	_G["SVUI_MentaloPrecisionUpButton"]:SetButtonTemplate()
	_G["SVUI_MentaloPrecisionDownButton"]:SetButtonTemplate()
	_G["SVUI_MentaloPrecisionLeftButton"]:SetButtonTemplate()
	_G["SVUI_MentaloPrecisionRightButton"]:SetButtonTemplate()
	CurrentFrameTarget = false;
end