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

--------------------------------------------
-- 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())