Files
ElvUIModernized/ElvUI/Core/Math.lua
T
Bunny67 f65e8aa789 update
2018-07-11 23:24:37 +03:00

421 lines
12 KiB
Lua

local E, L, V, P, G = unpack(ElvUI); --Import: Engine, Locales, PrivateDB, ProfileDB, GlobalDB
--Cache global variables
--Lua functions
local unpack, assert, tonumber, type, pairs = unpack, assert, tonumber, type, pairs
local getn, tinsert, tremove = table.getn, tinsert, tremove
local abs, ceil, floor, modf, mod = math.abs, math.ceil, math.floor, math.modf, math.mod
local find, format, byte, len, sub, gsub, upper, split, utf8sub = string.find, string.format, string.byte, string.len, string.sub, string.gsub, string.upper, string.split, string.utf8sub
--WoW API / Variables
local GetScreenWidth, GetScreenHeight = GetScreenWidth, GetScreenHeight
local CreateFrame = CreateFrame
--Return short value of a number
local shortValueDec
function E:ShortValue(v)
shortValueDec = format("%%.%df", E.db.general.decimalLength or 1)
if E.db.general.numberPrefixStyle == "METRIC" then
if abs(v) >= 1e9 then
return format(shortValueDec.."G", v / 1e9)
elseif abs(v) >= 1e6 then
return format(shortValueDec.."M", v / 1e6)
elseif abs(v) >= 1e3 then
return format(shortValueDec.."k", v / 1e3)
else
return format("%s", v)
end
elseif E.db.general.numberPrefixStyle == "CHINESE" then
if abs(v) >= 1e8 then
return format(shortValueDec.."Y", v / 1e8)
elseif abs(v) >= 1e4 then
return format(shortValueDec.."W", v / 1e4)
else
return format("%s", v)
end
elseif E.db.general.numberPrefixStyle == "KOREAN" then
if abs(v) >= 1e8 then
return format(shortValueDec.."억", v / 1e8)
elseif abs(v) >= 1e4 then
return format(shortValueDec.."만", v / 1e4)
elseif abs(v) >= 1e3 then
return format(shortValueDec.."천", v / 1e3)
else
return format("%s", v)
end
elseif E.db.general.numberPrefixStyle == "GERMAN" then
if abs(v) >= 1e9 then
return format(shortValueDec.."Mrd", v / 1e9)
elseif abs(v) >= 1e6 then
return format(shortValueDec.."Mio", v / 1e6)
elseif abs(v) >= 1e3 then
return format(shortValueDec.."Tsd", v / 1e3)
else
return format("%s", v)
end
else
if abs(v) >= 1e9 then
return format(shortValueDec.."B", v / 1e9)
elseif abs(v) >= 1e6 then
return format(shortValueDec.."M", v / 1e6)
elseif abs(v) >= 1e3 then
return format(shortValueDec.."K", v / 1e3)
else
return format("%s", v)
end
end
end
function E:IsEvenNumber(num)
return mod(num, 2) == 0
end
function E:ColorGradient(perc, r1, g1, b1, r2, g2, b2, r3, g3, b3)
if perc >= 1 then
return r3, g3, b3
elseif perc <= 0 then
return r1, g1, b1
end
local segment, relperc = modf(perc)
if segment > 0 then
r1, g1, b1, r2, g2, b2 = r2, g2, b2, r3, g3, b3
end
return r1 + (r2-r1)*relperc, g1 + (g2-g1)*relperc, b1 + (b2-b1)*relperc
end
function E:Round(num, idp)
if idp and idp > 0 then
local mult = 10 ^ idp
return floor(num * mult + 0.5) / mult
end
return floor(num + 0.5)
end
function E:Truncate(v, decimals)
return v - (mod(v, 0.1 ^ (decimals or 0)))
end
function E:RGBToHex(r, g, b)
r = r <= 1 and r >= 0 and r or 0
g = g <= 1 and g >= 0 and g or 0
b = b <= 1 and b >= 0 and b or 0
return format("|cff%02x%02x%02x", r*255, g*255, b*255)
end
function E:HexToRGB(hex)
local rhex, ghex, bhex = sub(hex, 1, 2), sub(hex, 3, 4), sub(hex, 5, 6)
return tonumber(rhex, 16), tonumber(ghex, 16), tonumber(bhex, 16)
end
function E:FramesOverlap(frameA, frameB)
if not frameA or not frameB then return end
local sA, sB = frameA:GetEffectiveScale(), frameB:GetEffectiveScale()
if not sA or not sB then return end
local frameALeft = frameA:GetLeft()
local frameARight = frameA:GetRight()
local frameABottom = frameA:GetBottom()
local frameATop = frameA:GetTop()
local frameBLeft = frameB:GetLeft()
local frameBRight = frameB:GetRight()
local frameBBottom = frameB:GetBottom()
local frameBTop = frameB:GetTop()
if not frameALeft or not frameARight or not frameABottom or not frameATop then return end
if not frameBLeft or not frameBRight or not frameBBottom or not frameBTop then return end
return ((frameALeft*sA) < (frameBRight*sB))
and ((frameBLeft*sB) < (frameARight*sA))
and ((frameABottom*sA) < (frameBTop*sB))
and ((frameBBottom*sB) < (frameATop*sA))
end
function E:GetScreenQuadrant(frame)
local x, y = frame:GetCenter()
local screenWidth = GetScreenWidth()
local screenHeight = GetScreenHeight()
local point
if not frame:GetCenter() then
return "UNKNOWN", frame:GetName()
end
if (x > (screenWidth / 3) and x < (screenWidth / 3)*2) and y > (screenHeight / 3)*2 then
point = "TOP"
elseif x < (screenWidth / 3) and y > (screenHeight / 3)*2 then
point = "TOPLEFT"
elseif x > (screenWidth / 3)*2 and y > (screenHeight / 3)*2 then
point = "TOPRIGHT"
elseif (x > (screenWidth / 3) and x < (screenWidth / 3)*2) and y < (screenHeight / 3) then
point = "BOTTOM"
elseif x < (screenWidth / 3) and y < (screenHeight / 3) then
point = "BOTTOMLEFT"
elseif x > (screenWidth / 3)*2 and y < (screenHeight / 3) then
point = "BOTTOMRIGHT"
elseif x < (screenWidth / 3) and (y > (screenHeight / 3) and y < (screenHeight / 3)*2) then
point = "LEFT"
elseif x > (screenWidth / 3)*2 and y < (screenHeight / 3)*2 and y > (screenHeight / 3) then
point = "RIGHT"
else
point = "CENTER"
end
return point
end
function E:GetXYOffset(position, override)
local default = E.Spacing
local x, y = override or default, override or default
if position == "TOP" then
return 0, y
elseif position == "TOPLEFT" then
return x, y
elseif position == "TOPRIGHT" then
return -x, y
elseif position == "BOTTOM" then
return 0, -y
elseif(position == "BOTTOMLEFT") then
return x, -y
elseif position == "BOTTOMRIGHT" then
return -x, -y
elseif position == "LEFT" then
return -x, 0
elseif position == "RIGHT" then
return x, 0
elseif position == "CENTER" then
return 0, 0
end
end
local styles = {
-- keep percents in this table with `PERCENT` in the key, and `%.1f%%` in the value somewhere.
-- we use these two things to follow our setting for decimal length. they need to be EXACT.
["CURRENT"] = "%s",
["CURRENT_MAX"] = "%s - %s",
["CURRENT_PERCENT"] = "%s - %.1f%%",
["CURRENT_MAX_PERCENT"] = "%s - %s | %.1f%%",
["PERCENT"] = "%.1f%%",
["DEFICIT"] = "-%s"
}
function E:GetFormattedText(style, min, max)
assert(styles[style], "Invalid format style: "..style)
assert(min, "You need to provide a current value. Usage: E:GetFormattedText(style, min, max)")
assert(max, "You need to provide a maximum value. Usage: E:GetFormattedText(style, min, max)")
if max == 0 then max = 1 end
gftDec = E.db.general.decimalLength or 1
if gftDec ~= 1 and find(style, "PERCENT") then
gftUseStyle = gsub(styles[style], "%%%.1f%%%%", "%%."..gftDec.."f%%%%")
else
gftUseStyle = styles[style]
end
if style == "DEFICIT" then
gftDeficit = max - min
return ((gftDeficit > 0) and format(gftUseStyle, E:ShortValue(gftDeficit))) or ""
elseif style == "PERCENT" then
return format(gftUseStyle, min / max * 100)
elseif style == "CURRENT" or ((style == "CURRENT_MAX" or style == "CURRENT_MAX_PERCENT" or style == "CURRENT_PERCENT") and min == max) then
return format(styles["CURRENT"], E:ShortValue(min))
elseif style == "CURRENT_MAX" then
return format(gftUseStyle, E:ShortValue(min), E:ShortValue(max))
elseif style == "CURRENT_PERCENT" then
return format(gftUseStyle, E:ShortValue(min), min / max * 100)
elseif style == "CURRENT_MAX_PERCENT" then
return format(gftUseStyle, E:ShortValue(min), E:ShortValue(max), min / max * 100)
end
end
function E:AbbreviateString(string, allUpper)
local newString = ""
local words = {split(" ", string)}
for _, word in pairs(words) do
word = utf8sub(word, 1, 1)
if(allUpper) then
word = upper(word)
end
newString = newString..word
end
return newString
end
function E:ShortenString(string, numChars, dots)
local bytes = len(string)
if bytes <= numChars then
return string
else
local len, pos = 0, 1
while pos <= bytes do
len = len + 1
local c = byte(string, pos)
if c > 0 and c <= 127 then
pos = pos + 1
elseif c >= 192 and c <= 223 then
pos = pos + 2
elseif c >= 224 and c <= 239 then
pos = pos + 3
elseif c >= 240 and c <= 247 then
pos = pos + 4
end
if len == numChars then break end
end
if len == numChars and pos <= bytes then
return sub(string, 1, pos - 1)..(dots and "..." or "")
else
return string
end
end
end
local waitTable = {}
local waitFrame
function E:Delay(delay, func, ...)
if (type(delay) ~= "number") or (type(func) ~= "function") then
return false
end
if waitFrame == nil then
waitFrame = CreateFrame("Frame", "WaitFrame", E.UIParent)
waitFrame:SetScript("OnUpdate", function()
local waitRecord, waitDelay, waitFunc, waitParams
local i, count = 1, getn(waitTable)
while i <= count do
waitRecord = tremove(waitTable, i)
waitDelay = tremove(waitRecord, 1)
waitFunc = tremove(waitRecord, 1)
waitParams = tremove(waitRecord, 1)
if waitDelay > arg1 then
tinsert(waitTable, i, {waitDelay - arg1, waitFunc, waitParams})
i = i + 1
else
count = count - 1
waitFunc(unpack(waitParams))
end
end
end)
end
tinsert(waitTable, {delay, func, arg})
return true
end
function E:StringTitle(str)
return gsub(str, "(.)", upper, 1)
end
E.TimeColors = {
[0] = "|cffeeeeee",
[1] = "|cffeeeeee",
[2] = "|cffeeeeee",
[3] = "|cffeeeeee",
[4] = "|cfffe0000"
}
E.TimeFormats = {
[0] = {"%dd", "%dd"},
[1] = {"%dh", "%dh"},
[2] = {"%dm", "%dm"},
[3] = {"%ds", "%d"},
[4] = {"%.1fs", "%.1f"}
}
local DAY, HOUR, MINUTE = 86400, 3600, 60
local DAYISH, HOURISH, MINUTEISH = HOUR * 23.5, MINUTE * 59.5, 59.5
local HALFDAYISH, HALFHOURISH, HALFMINUTEISH = DAY/2 + 0.5, HOUR/2 + 0.5, MINUTE/2 + 0.5
function E:GetTimeInfo(s, threshhold)
if s < MINUTE then
if s >= threshhold then
return floor(s), 3, 0.51
else
return s, 4, 0.051
end
elseif s < HOUR then
local minutes = floor((s/MINUTE)+.5)
return ceil(s / MINUTE), 2, minutes > 1 and (s - (minutes*MINUTE - HALFMINUTEISH)) or (s - MINUTEISH)
elseif s < DAY then
local hours = floor((s/HOUR)+.5)
return ceil(s / HOUR), 1, hours > 1 and (s - (hours*HOUR - HALFHOURISH)) or (s - HOURISH)
else
local days = floor((s/DAY)+.5)
return ceil(s / DAY), 0, days > 1 and (s - (days*DAY - HALFDAYISH)) or (s - DAYISH)
end
end
local COLOR_COPPER = "|cffeda55f"
local COLOR_SILVER = "|cffc7c7cf"
local COLOR_GOLD = "|cffffd700"
function E:FormatMoney(amount, style)
local coppername = L.copperabbrev
local silvername = L.silverabbrev
local goldname = L.goldabbrev
local value = abs(amount)
local gold = floor(value / 10000)
local silver = floor(mod(value / 100, 100))
local copper = floor(mod(value, 100))
if not style or style == "SMART" then
local str = ""
if gold > 0 then
str = format("%d%s%s", gold, goldname, (silver > 0 or copper > 0) and " " or "")
end
if silver > 0 then
str = format("%s%d%s%s", str, silver, silvername, copper > 0 and " " or "")
end
if copper > 0 or value == 0 then
str = format("%s%d%s", str, copper, coppername)
end
return str
end
if style == "FULL" then
if gold > 0 then
return format("%d%s %d%s %d%s", gold, goldname, silver, silvername, copper, coppername)
elseif silver > 0 then
return format("%d%s %d%s", silver, silvername, copper, coppername)
else
return format("%d%s", copper, coppername)
end
elseif style == "SHORT" then
if gold > 0 then
return format("%.1f%s", amount / 10000, goldname)
elseif silver > 0 then
return format("%.1f%s", amount / 100, silvername)
else
return format("%d%s", amount, coppername)
end
elseif style == "SHORTINT" then
if gold > 0 then
return format("%d%s", gold, goldname)
elseif silver > 0 then
return format("%d%s", silver, silvername)
else
return format("%d%s", copper, coppername)
end
elseif style == "CONDENSED" then
if gold > 0 then
return format("%s%d|r.%s%02d|r.%s%02d|r", COLOR_GOLD, gold, COLOR_SILVER, silver, COLOR_COPPER, copper)
elseif silver > 0 then
return format("%s%d|r.%s%02d|r", COLOR_SILVER, silver, COLOR_COPPER, copper)
else
return format("%s%d|r", COLOR_COPPER, copper)
end
elseif style == "BLIZZARD" then
if gold > 0 then
return format("%s%s %d%s %d%s", gold, goldname, silver, silvername, copper, coppername)
elseif silver > 0 then
return format("%d%s %d%s", silver, silvername, copper, coppername)
else
return format("%d%s", copper, coppername)
end
end
return self:FormatMoney(amount, "SMART")
end