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.
381 lines
11 KiB
381 lines
11 KiB
--------------------------------------------
|
|
-- http://wow.gamepedia.com/UI_Scale
|
|
-- http://www.wowinterface.com/forums/showthread.php?t=31813
|
|
--------------------------------------------
|
|
local _, addon = ...
|
|
addon.pixelPerfectFuncs = {}
|
|
|
|
local function Round(num, numDecimalPlaces)
|
|
if numDecimalPlaces and numDecimalPlaces >= 0 then
|
|
local mult = 10 ^ numDecimalPlaces
|
|
num = num * mult
|
|
if num >= 0 then
|
|
return floor(num + 0.5) / mult
|
|
else
|
|
return ceil(num - 0.5) / mult
|
|
end
|
|
end
|
|
|
|
if num >= 0 then
|
|
return floor(num + 0.5)
|
|
else
|
|
return ceil(num - 0.5)
|
|
end
|
|
end
|
|
|
|
local Clamp = Clamp
|
|
|
|
---@class PixelPerfectFuncs
|
|
local P = addon.pixelPerfectFuncs
|
|
|
|
function P.GetResolution()
|
|
-- return string.match(({GetScreenResolutions()})[GetCurrentResolution()], "(%d+)x(%d+)")
|
|
return GetPhysicalScreenSize()
|
|
end
|
|
|
|
-- The UI P.Scale goes from 1 to 0.64.
|
|
-- At 768y we see pixel-per-pixel accurate representation of our texture,
|
|
-- and again at 1200y if at 0.64 scale.
|
|
function P.GetPixelPerfectScale()
|
|
local hRes, vRes = P.GetResolution()
|
|
if vRes then
|
|
return 768 / vRes
|
|
else -- windowed mode before 8.0, or maybe something goes wrong?
|
|
return 1
|
|
end
|
|
end
|
|
|
|
function P.GetRecommendedScale()
|
|
local pScale = P.GetPixelPerfectScale()
|
|
local mult
|
|
if pScale >= 0.71 then -- 1080
|
|
mult = 1
|
|
elseif pScale >= 0.53 then -- 1440
|
|
mult = 1.2
|
|
else -- 2160
|
|
mult = 1.7
|
|
end
|
|
return Clamp(Round(pScale / UIParent:GetScale() * mult, 2), 0.5, 2)
|
|
end
|
|
|
|
-- scale perfect!
|
|
function P.PixelPerfectScale(frame)
|
|
frame:SetScale(P.GetPixelPerfectScale())
|
|
end
|
|
|
|
-- position perfect!
|
|
function P.PixelPerfectPoint(frame)
|
|
local left = frame:GetLeft()
|
|
local top = frame:GetTop()
|
|
|
|
frame:ClearAllPoints()
|
|
frame:SetPoint("TOPLEFT", CellParent, "BOTTOMLEFT", math.floor(left + 0.5), math.floor(top + 0.5))
|
|
end
|
|
|
|
--------------------------------------------
|
|
-- PixelUtil
|
|
--------------------------------------------
|
|
-- local effectiveScale = 1
|
|
-- function P.SetRelativeScale(scale)
|
|
-- effectiveScale = scale
|
|
-- end
|
|
|
|
-- function P.GetEffectiveScale()
|
|
-- return effectiveScale
|
|
-- end
|
|
|
|
-- function P.SetEffectiveScale(frame)
|
|
-- frame:SetScale(effectiveScale)
|
|
-- end
|
|
|
|
-- function P.Scale(uiUnitSize)
|
|
-- if uiUnitSize == 0 then
|
|
-- return 0
|
|
-- end
|
|
|
|
-- local uiUnitFactor = PixelUtil.GetPixelToUIUnitFactor()
|
|
-- local numPixels = Round((uiUnitSize * effectiveScale) / uiUnitFactor)
|
|
-- if uiUnitSize < 0.0 then
|
|
-- if numPixels > -1 then
|
|
-- numPixels = -1
|
|
-- end
|
|
-- else
|
|
-- if numPixels < 1 then
|
|
-- numPixels = 1
|
|
-- end
|
|
-- end
|
|
|
|
-- return numPixels * uiUnitFactor / effectiveScale
|
|
-- end
|
|
|
|
--------------------------------------------
|
|
-- some are stolen from ElvUI
|
|
--------------------------------------------
|
|
-- local function GetUIParentScale()
|
|
-- local scale = UIParent:GetScale()
|
|
-- return scale - scale % 0.1 ^ 2
|
|
-- end
|
|
|
|
local scale = 1
|
|
local mult = 1
|
|
---@deprecated
|
|
function P.SetRelativeScale(s)
|
|
mult = 1 / s
|
|
scale = s
|
|
end
|
|
|
|
---@deprecated
|
|
function P.GetEffectiveScale()
|
|
return P.GetPixelPerfectScale() / mult
|
|
end
|
|
|
|
---@deprecated
|
|
function P.SetEffectiveScale(frame)
|
|
frame:SetScale(P.GetEffectiveScale())
|
|
end
|
|
|
|
--[[
|
|
local trunc = function(s) return s >= 0 and s-s%01 or s-s%-1 end
|
|
local round = function(s) return s >= 0 and s-s%-1 or s-s%01 end
|
|
function P.Scale(n)
|
|
return (mult == 1 or n == 0) and n or ((mult < 1 and trunc(n/mult) or round(n/mult)) * mult)
|
|
end
|
|
]]
|
|
-- function P.Scale(n)
|
|
-- if mult == 1 or n == 0 then
|
|
-- return n
|
|
-- else
|
|
-- local x = mult > 1 and mult or -mult
|
|
-- return n - n % (n < 0 and x or -x)
|
|
-- end
|
|
-- end
|
|
|
|
local GetNearestPixelSize = PixelUtil.GetNearestPixelSize
|
|
|
|
function P.Scale(desiredPixels)
|
|
return GetNearestPixelSize(desiredPixels, CellParent:GetEffectiveScale())
|
|
end
|
|
|
|
function P.Size(frame, width, height)
|
|
frame.width = width
|
|
frame.height = height
|
|
frame:SetSize(P.Scale(width), P.Scale(height))
|
|
end
|
|
|
|
function P.Width(frame, width)
|
|
frame.width = width
|
|
frame:SetWidth(P.Scale(width))
|
|
end
|
|
|
|
function P.Height(frame, height)
|
|
frame.height = height
|
|
frame:SetHeight(P.Scale(height))
|
|
end
|
|
|
|
function P.SetGridSize(region, gridWidth, gridHeight, gridSpacingH, gridSpacingV, columns, rows)
|
|
region._size_grid = true
|
|
region._gridWidth = gridWidth
|
|
region._gridHeight = gridHeight
|
|
region._gridSpacingH = gridSpacingH
|
|
region._gridSpacingV = gridSpacingV
|
|
region._rows = rows
|
|
region._columns = columns
|
|
|
|
if columns == 0 then
|
|
region:SetWidth(0.001)
|
|
else
|
|
region:SetWidth(P.Scale(gridWidth) * columns + P.Scale(gridSpacingH) * (columns - 1))
|
|
end
|
|
|
|
if rows == 0 then
|
|
region:SetHeight(0.001)
|
|
else
|
|
region:SetHeight(P.Scale(gridHeight) * rows + P.Scale(gridSpacingV) * (rows - 1))
|
|
end
|
|
end
|
|
|
|
function P.Point(frame, ...)
|
|
if not frame.points then frame.points = {} end
|
|
local point, anchorTo, anchorPoint, x, y
|
|
|
|
local n = select("#", ...)
|
|
if n == 1 then
|
|
point = ...
|
|
elseif n == 3 and type(select(2, ...)) == "number" then
|
|
point, x, y = ...
|
|
elseif n == 4 then
|
|
point, anchorTo, x, y = ...
|
|
else
|
|
point, anchorTo, anchorPoint, x, y = ...
|
|
end
|
|
|
|
tinsert(frame.points, {point, anchorTo or frame:GetParent(), anchorPoint or point, x or 0, y or 0})
|
|
local n = #frame.points
|
|
frame:SetPoint(frame.points[n][1], frame.points[n][2], frame.points[n][3], P.Scale(frame.points[n][4]), P.Scale(frame.points[n][5]))
|
|
end
|
|
|
|
function P.ClearPoints(frame)
|
|
frame:ClearAllPoints()
|
|
if frame.points then wipe(frame.points) end
|
|
end
|
|
|
|
--------------------------------------------
|
|
-- scale changed
|
|
--------------------------------------------
|
|
function P.Resize(frame)
|
|
if frame._size_grid then
|
|
P.SetGridSize(frame, frame._gridWidth, frame._gridHeight, frame._gridSpacingH, frame._gridSpacingV, frame._columns, frame._rows)
|
|
else
|
|
if frame.width then
|
|
frame:SetWidth(P.Scale(frame.width))
|
|
end
|
|
if frame.height then
|
|
frame:SetHeight(P.Scale(frame.height))
|
|
end
|
|
end
|
|
end
|
|
|
|
function P.Reborder(frame, ignoreSnippetVar)
|
|
if not frame.backdropInfo then return end
|
|
|
|
local _r, _g, _b, _a = frame:GetBackdropColor()
|
|
local r, g, b, a = frame:GetBackdropBorderColor()
|
|
|
|
if ignoreSnippetVar then
|
|
frame.backdropInfo.edgeSize = P.Scale(1)
|
|
else
|
|
if CELL_BORDER_SIZE == 0 then
|
|
frame.backdropInfo.edgeFile = nil
|
|
frame.backdropInfo.edgeSize = nil
|
|
else
|
|
frame.backdropInfo.edgeSize = P.Scale(CELL_BORDER_SIZE or 1)
|
|
end
|
|
end
|
|
frame:ApplyBackdrop()
|
|
|
|
if _r then frame:SetBackdropColor(_r, _g, _b, _a) end
|
|
if r then frame:SetBackdropBorderColor(r, g, b, a) end
|
|
end
|
|
|
|
function P.Repoint(frame)
|
|
if not frame.points or #frame.points == 0 then return end
|
|
frame:ClearAllPoints()
|
|
for _, t in pairs(frame.points) do
|
|
frame:SetPoint(t[1], t[2], t[3], P.Scale(t[4]), P.Scale(t[5]))
|
|
end
|
|
end
|
|
|
|
-- local frames = {}
|
|
-- function P.SetPixelPerfect(frame)
|
|
-- tinsert(frames, frame)
|
|
-- end
|
|
|
|
-- function P.UpdatePixelPerfectFrames()
|
|
-- for _, f in pairs(frames) do
|
|
-- f:UpdatePixelPerfect()
|
|
-- end
|
|
-- end
|
|
|
|
--------------------------------------------
|
|
-- save & load position
|
|
--------------------------------------------
|
|
function P.SavePosition(frame, positionTable)
|
|
wipe(positionTable)
|
|
positionTable[1], positionTable[2], positionTable[3] = P.CalcPoint(frame)
|
|
-- local left = math.floor(frame:GetLeft() + 0.5)
|
|
-- local top = math.floor(frame:GetTop() + 0.5)
|
|
-- positionTable[1], positionTable[2] = left, top
|
|
end
|
|
|
|
function P.LoadPosition(frame, positionTable)
|
|
if type(positionTable) ~= "table" then return end
|
|
|
|
if #positionTable == 2 then
|
|
P.ClearPoints(frame)
|
|
P.Point(frame, "TOPLEFT", UIParent, "BOTTOMLEFT", positionTable[1], positionTable[2])
|
|
return true
|
|
elseif #positionTable == 3 then
|
|
P.ClearPoints(frame)
|
|
frame:SetPoint(positionTable[1], CellParent, positionTable[2], positionTable[3])
|
|
return true
|
|
end
|
|
end
|
|
|
|
function P.CalcPoint(frame)
|
|
local point, x, y
|
|
local centerX, centerY = CellParent:GetCenter()
|
|
local width = CellParent:GetRight()
|
|
x, y = frame:GetCenter()
|
|
|
|
if y >= centerY then
|
|
point = "TOP"
|
|
y = -(CellParent:GetTop() - frame:GetTop())
|
|
else
|
|
point = "BOTTOM"
|
|
y = frame:GetBottom()
|
|
end
|
|
|
|
if x >= (width * 2 / 3) then
|
|
point = point.."RIGHT"
|
|
x = frame:GetRight() - width
|
|
elseif x <= (width / 3) then
|
|
point = point.."LEFT"
|
|
x = frame:GetLeft()
|
|
else
|
|
x = x - centerX
|
|
end
|
|
|
|
-- x = tonumber(string.format("%.2f", x))
|
|
-- y = tonumber(string.format("%.2f", y))
|
|
x = Round(x, 1)
|
|
y = Round(y, 1)
|
|
|
|
return point, x, y
|
|
end
|
|
|
|
---------------------------------------------------------------------
|
|
-- pixel perfect (ElvUI)
|
|
---------------------------------------------------------------------
|
|
local function CheckPixelSnap(frame, snap)
|
|
if (frame and not frame:IsForbidden()) and frame.PixelSnapDisabled and snap then
|
|
frame.PixelSnapDisabled = nil
|
|
end
|
|
end
|
|
|
|
local function DisablePixelSnap(frame)
|
|
if (frame and not frame:IsForbidden()) and not frame.PixelSnapDisabled then
|
|
if frame.SetSnapToPixelGrid then
|
|
frame:SetSnapToPixelGrid(false)
|
|
frame:SetTexelSnappingBias(0)
|
|
frame.PixelSnapDisabled = true
|
|
elseif frame.GetStatusBarTexture then
|
|
local texture = frame:GetStatusBarTexture()
|
|
if type(texture) == "table" and texture.SetSnapToPixelGrid then
|
|
texture:SetSnapToPixelGrid(false)
|
|
texture:SetTexelSnappingBias(0)
|
|
frame.PixelSnapDisabled = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function UpdateMetatable(obj)
|
|
local t = getmetatable(obj).__index
|
|
|
|
if not obj.DisabledPixelSnap and (t.SetSnapToPixelGrid or t.SetStatusBarTexture or t.SetColorTexture or t.SetVertexColor or t.CreateTexture or t.SetTexCoord or t.SetTexture) then
|
|
if t.SetSnapToPixelGrid then hooksecurefunc(t, "SetSnapToPixelGrid", CheckPixelSnap) end
|
|
if t.SetStatusBarTexture then hooksecurefunc(t, "SetStatusBarTexture", DisablePixelSnap) end
|
|
if t.SetColorTexture then hooksecurefunc(t, "SetColorTexture", DisablePixelSnap) end
|
|
if t.SetVertexColor then hooksecurefunc(t, "SetVertexColor", DisablePixelSnap) end
|
|
if t.CreateTexture then hooksecurefunc(t, "CreateTexture", DisablePixelSnap) end
|
|
if t.SetTexCoord then hooksecurefunc(t, "SetTexCoord", DisablePixelSnap) end
|
|
if t.SetTexture then hooksecurefunc(t, "SetTexture", DisablePixelSnap) end
|
|
|
|
t.DisabledPixelSnap = true
|
|
end
|
|
end
|
|
|
|
local obj = CreateFrame("Frame")
|
|
UpdateMetatable(CreateFrame("StatusBar"))
|
|
UpdateMetatable(obj:CreateTexture())
|
|
UpdateMetatable(obj:CreateMaskTexture())
|