--[[ Infield.lua A library of functions to keep frames within the UIParent's bounds --]] --constants local VERSION = 60825; if Infield and Infield.version >= VERSION then return; end local UPDATE_INTERVAL = 1; --[[ Local Functions ]]-- local function RegisterScaleEvents() --set the onupdate function InfieldUpdater:SetScript("OnEvent", function() local uiScale = UIParent:GetScale(); if this.currentScale ~= uiScale then for _, action in pairs(Infield.rescaleList) do action(); end this.currentScale = uiScale; end end); InfieldUpdater:RegisterEvent("PLAYER_ENTERING_WORLD"); InfieldUpdater:RegisterEvent("CVAR_UPDATE"); end --returns the adjusted x and y coordinates for a frame when scaled, keeping the topleft of the frame in the same relative spot local function GetAdjustedCoords(frame, nScale) if not ( frame:GetLeft() and frame:GetTop() ) then return; end return frame:GetLeft() * frame:GetScale() / nScale, frame:GetTop() * frame:GetScale() / nScale; end --[[ Update or Load Infield's Functions ]]-- --create a new infield instance if not Infield then Infield = { rescaleList = {} }; --do stuff needed to be done on a version change else local resList = Infield.rescaleList; Infield = { rescaleList = resList }; if InfieldUpdater and InfieldUpdater:GetScript("OnUpdate") then InfieldUpdater:Hide(); InfieldUpdater:SetScript("OnUpdate", nil); InfieldUpdater.elapsed = nil; RegisterScaleEvents(); end end Infield.version = VERSION; --Add a function to execute when the UI scale changes --This must be added before the PLAYER_LOGIN event takes place to detect the startup rescale. Infield.AddRescaleAction = function(funct) table.insert(Infield.rescaleList, funct); end --Sets 's scale , and repositions the frame if its out of the viewable screen area Infield.Scale = function(frame, scale) local x, y = GetAdjustedCoords(frame, scale); frame:SetScale(scale); if x and y then Infield.Place(frame, "TOPLEFT", UIParent, "BOTTOMLEFT", x, y); end end --Places a frame at a location and repositions it so that it is not outside of the UIParent --Syntax is similar to Frame:SetScale() Infield.Place = function(frame, point, parent, relPoint, x, y) frame:ClearAllPoints(); frame:SetPoint(point, parent, relPoint, x, y); Infield.Reposition(frame, UIParent); end --Moves a frame within the bounds of parent if its out of bounds Infield.Reposition = function(frame, parent) if frame:GetBottom() and frame:GetTop() and frame:GetLeft() and frame:GetRight() then local xoff = 0; local yoff = 0; local ratio = frame:GetScale(); --check and see if the frame is off the screen --Y bounds checking if frame:GetBottom() < 0 then yoff = 0 - frame:GetBottom(); elseif frame:GetTop() > (parent:GetTop() / ratio) then yoff = (parent:GetTop() / ratio) - frame:GetTop(); end --X bounds checking if frame:GetLeft() < 0 then xoff = 0 - frame:GetLeft(); elseif frame:GetRight() > (parent:GetRight() / ratio) then xoff = (parent:GetRight() / ratio) - frame:GetRight(); end --Reposition if anything was out of bounds if xoff ~= 0 or yoff ~= 0 then local x = frame:GetLeft() + xoff; local y = frame:GetTop() + yoff; frame:ClearAllPoints(); frame:SetPoint("TOPLEFT", parent, "BOTTOMLEFT", x , y); end end end --create the frame if not InfieldUpdater then CreateFrame("Frame", "InfieldUpdater"); RegisterScaleEvents(); end