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.

3610 lines
129 KiB

local addonName, addon = ...
local L = addon.L
local F = addon.funcs
local P = addon.pixelPerfectFuncs
local LCG = LibStub("LibCustomGlow-1.0")
-----------------------------------------
-- Color
-----------------------------------------
local colors = {
grey = {s="|cFFB2B2B2", t={0.7, 0.7, 0.7}},
yellow = {s="|cFFFFD100", t= {1, 0.82, 0}},
orange = {s="|cFFFFC0CB", t= {1, 0.65, 0}},
firebrick = {s="|cFFFF3030", t={1, 0.19, 0.19}},
skyblue = {s="|cFF00CCFF", t={0, 0.8, 1}},
chartreuse = {s="|cFF80FF00", t={0.5, 1, 0}},
}
local class = select(2, UnitClass("player"))
local accentColor = {s="|cCCB2B2B2", t={0.7, 0.7, 0.7}}
if class then
accentColor.t[1], accentColor.t[2], accentColor.t[3], accentColor.s = RAID_CLASS_COLORS[class].r, RAID_CLASS_COLORS[class].g, RAID_CLASS_COLORS[class].b, RAID_CLASS_COLORS[class].colorStr
accentColor.s = "|c"..accentColor.s
end
-----------------------------------------
-- Font
-----------------------------------------
-- local fonts = {}
-- local function SetFont(obj, font, size, flags)
-- -- store in fonts for resizing
-- tinsert(fonts, {
-- ["obj"] = obj,
-- ["font"] = font,
-- ["size"] = size,
-- ["flags"] = flags
-- })
-- obj:SetFont()
-- end
local font_title_name = strupper(addonName).."_FONT_WIDGET_TITLE"
local font_title_disable_name = strupper(addonName).."_FONT_WIDGET_TITLE_DISABLE"
local font_name = strupper(addonName).."_FONT_WIDGET"
local font_small_name = strupper(addonName).."_FONT_WIDGET_SMALL"
local font_chinese_name = strupper(addonName).."_FONT_CHINESE"
local font_disable_name = strupper(addonName).."_FONT_WIDGET_DISABLE"
local font_special_name = strupper(addonName).."_FONT_SPECIAL"
local font_class_title_name = strupper(addonName).."_FONT_CLASS_TITLE"
local font_class_name = strupper(addonName).."_FONT_CLASS"
local font_title = CreateFont(font_title_name)
font_title:SetFont(GameFontNormal:GetFont(), 14, "")
font_title:SetTextColor(1, 1, 1, 1)
font_title:SetShadowColor(0, 0, 0)
font_title:SetShadowOffset(1, -1)
font_title:SetJustifyH("CENTER")
local font_title_disable = CreateFont(font_title_disable_name)
font_title_disable:SetFont(GameFontNormal:GetFont(), 14, "")
font_title_disable:SetTextColor(0.4, 0.4, 0.4, 1)
font_title_disable:SetShadowColor(0, 0, 0)
font_title_disable:SetShadowOffset(1, -1)
font_title_disable:SetJustifyH("CENTER")
local font = CreateFont(font_name)
font:SetFont(GameFontNormal:GetFont(), 13, "")
font:SetTextColor(1, 1, 1, 1)
font:SetShadowColor(0, 0, 0)
font:SetShadowOffset(1, -1)
font:SetJustifyH("CENTER")
local font_small = CreateFont(font_small_name)
font_small:SetFont(GameFontNormal:GetFont(), 11, "")
font_small:SetTextColor(1, 1, 1, 1)
font_small:SetShadowColor(0, 0, 0)
font_small:SetShadowOffset(1, -1)
font_small:SetJustifyH("CENTER")
local font_chinese = CreateFont(font_chinese_name)
font_chinese:SetFont(UNIT_NAME_FONT_CHINESE, 14, "")
font_chinese:SetTextColor(1, 1, 1, 1)
font_chinese:SetShadowColor(0, 0, 0)
font_chinese:SetShadowOffset(1, -1)
font_chinese:SetJustifyH("CENTER")
local font_disable = CreateFont(font_disable_name)
font_disable:SetFont(GameFontNormal:GetFont(), 13, "")
font_disable:SetTextColor(0.4, 0.4, 0.4, 1)
font_disable:SetShadowColor(0, 0, 0)
font_disable:SetShadowOffset(1, -1)
font_disable:SetJustifyH("CENTER")
local font_special = CreateFont(font_special_name)
font_special:SetFont("Interface\\AddOns\\Cell\\Media\\Fonts\\font.ttf", 12, "")
font_special:SetTextColor(1, 1, 1, 1)
font_special:SetShadowColor(0, 0, 0)
font_special:SetShadowOffset(1, -1)
font_special:SetJustifyH("CENTER")
font_special:SetJustifyV("MIDDLE")
local font_class_title = CreateFont(font_class_title_name)
font_class_title:SetFont(GameFontNormal:GetFont(), 14, "")
font_class_title:SetTextColor(accentColor.t[1], accentColor.t[2], accentColor.t[3])
font_class_title:SetShadowColor(0, 0, 0)
font_class_title:SetShadowOffset(1, -1)
font_class_title:SetJustifyH("CENTER")
local font_class = CreateFont(font_class_name)
font_class:SetFont(GameFontNormal:GetFont(), 13, "")
font_class:SetTextColor(accentColor.t[1], accentColor.t[2], accentColor.t[3])
font_class:SetShadowColor(0, 0, 0)
font_class:SetShadowOffset(1, -1)
font_class:SetJustifyH("CENTER")
local defaultFont = GameFontNormal:GetFont()
local fontSizeOffset = 0
function addon:UpdateOptionsFont(offset, useGameFont)
if useGameFont then
defaultFont = GameFontNormal:GetFont()
else
defaultFont = "Interface\\AddOns\\Cell\\Media\\Fonts\\Accidental_Presidency.ttf"
end
fontSizeOffset = offset
font_title:SetFont(defaultFont, 14+offset, "")
font_title_disable:SetFont(defaultFont, 14+offset, "")
font:SetFont(defaultFont, 13+offset, "")
font_small:SetFont(defaultFont, 11+offset, "")
font_chinese:SetFont(UNIT_NAME_FONT_CHINESE, 14+offset, "")
font_disable:SetFont(defaultFont, 13+offset, "")
font_class_title:SetFont(defaultFont, 14+offset, "")
font_class:SetFont(defaultFont, 13+offset, "")
end
-----------------------------------------
-- Accent Color
-----------------------------------------
local accentColorOverride
function addon:OverrideAccentColor(cTable)
accentColorOverride = true
accentColor.t[1], accentColor.t[2], accentColor.t[3] = unpack(cTable)
accentColor.s = "|cFF"..F:ConvertRGBToHEX(F:ConvertRGB_256(unpack(cTable)))
font_class_title:SetTextColor(unpack(cTable))
font_class:SetTextColor(unpack(cTable))
end
function addon:GetAccentColorRGB()
return unpack(accentColor.t)
end
function addon:GetAccentColorTable(alpha)
if alpha then
return {accentColor.t[1], accentColor.t[2], accentColor.t[3], alpha}
else
return accentColor.t
end
end
function addon:GetAccentColorString()
return accentColor.s
end
function addon:ColorFontStringWithAccentColor(fs)
fs:SetTextColor(accentColor.t[1], accentColor.t[2], accentColor.t[3])
end
function addon:WrapTextInAccentColor(text)
return WrapTextInColorCode(text, accentColor.s) -- FIXME: ("|c%s%s|r"):format(colorHexString, text)
end
-----------------------------------------
-- enable/disable
-----------------------------------------
function addon:SetEnabled(isEnabled, ...)
for _, w in pairs({...}) do
if w:IsObjectType("FontString") then
if isEnabled then
w:SetTextColor(1, 1, 1, 1)
else
w:SetTextColor(0.4, 0.4, 0.4, 1)
end
elseif w:IsObjectType("Texture") then
if isEnabled then
w:SetDesaturated(false)
else
w:SetDesaturated(true)
end
elseif w.SetEnabled then
w:SetEnabled(isEnabled)
elseif isEnabled then
w:Show()
else
w:Hide()
end
end
end
-----------------------------------------
-- rainbow text
-----------------------------------------
local colorSelect = CreateFrame("Colorselect")
function addon:StartRainbowText(fs, reverse)
-- save original
fs.text = fs:GetText()
-- updater
fs.rainbow = true
if not fs.updater then
fs.updater = CreateFrame("Frame", nil, fs:GetParent())
end
local pos = 0
local step = 360 / (#fs.text-1)
local col
local str
fs.updater:SetScript("OnUpdate", function(self, elapsed)
local hue = pos
-- NOTE: lua 正则匹配中文,不知道会不会有问题
str = fs.text:gsub("[%z\1-\127\194-\244][\128-\191]*", function(char)
colorSelect:SetColorHSV(hue,1,1)
col = CreateColor(colorSelect:GetColorRGB())
hue = (hue+step) > 360 and (hue+step)-360 or hue+step
return col:WrapTextInColorCode(char)
end)
if reverse then
pos = (pos+1) > 360 and 0 or pos + 1
else
pos = (pos-1) < 0 and 360 or pos - 1
end
fs:SetText(str)
end)
end
function addon:StopRainbowText(fs)
fs.rainbow = nil
if fs.updater then
fs.updater:SetScript("OnUpdate", nil)
fs:SetText(fs.text)
end
end
-----------------------------------------
-- seperator
-----------------------------------------
function addon:CreateSeparator(text, parent, width, color)
if not color then color = {t={accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.777}, s=accentColor.s} end
if not width then width = parent:GetWidth()-10 end
local fs = parent:CreateFontString(nil, "OVERLAY", font_title_name)
fs:SetJustifyH("LEFT")
fs:SetTextColor(color.t[1], color.t[2], color.t[3])
fs:SetText(text)
local line = parent:CreateTexture()
P:Size(line, width, 1)
line:SetColorTexture(unpack(color.t))
P:Point(line, "TOPLEFT", fs, "BOTTOMLEFT", 0, -2)
local shadow = parent:CreateTexture()
P:Size(shadow, width, 1)
shadow:SetColorTexture(0, 0, 0, 1)
P:Point(shadow, "TOPLEFT", line, "TOPLEFT", 1, -1)
return fs
end
function addon:CreateTitledPane(parent, text, width, height, color)
if not color then color = {["r"]=accentColor.t[1], ["g"]=accentColor.t[2], ["b"]=accentColor.t[3], ["a"]=0.777, ["s"]=accentColor.s} end
local pane = CreateFrame("Frame", nil, parent, "BackdropTemplate")
P:Size(pane, width, height)
-- addon:StylizeFrame(pane, {0,1,0,0.1}, {0,0,0,0})
-- underline
local line = pane:CreateTexture()
pane.line = line
P:Height(line, 1)
line:SetColorTexture(color.r, color.g, color.b, color.a)
line:SetPoint("TOPLEFT", pane, "TOPLEFT", 0, P:Scale(-17))
line:SetPoint("TOPRIGHT", pane, "TOPRIGHT", 0, P:Scale(-17))
local shadow = pane:CreateTexture()
P:Height(shadow, 1)
shadow:SetColorTexture(0, 0, 0, 1)
shadow:SetPoint("TOPLEFT", line, "TOPLEFT", P:Scale(1), P:Scale(-1))
shadow:SetPoint("TOPRIGHT", line, "TOPRIGHT", P:Scale(1), P:Scale(-1))
-- title
local title = pane:CreateFontString(nil, "OVERLAY", font_title_name)
pane.title = title
title:SetJustifyH("LEFT")
title:SetTextColor(color.r, color.g, color.b)
title:SetText(text)
title:SetPoint("BOTTOMLEFT", line, "TOPLEFT", 0, P:Scale(2))
-- func
function pane:SetTitle(t)
title:SetText(t)
end
return pane
end
-----------------------------------------
-- Frame
-----------------------------------------
function addon:StylizeFrame(frame, color, borderColor)
if not color then color = {0.1, 0.1, 0.1, 0.9} end
if not borderColor then borderColor = {0, 0, 0, 1} end
frame:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
frame:SetBackdropColor(unpack(color))
frame:SetBackdropBorderColor(unpack(borderColor))
end
function addon:CreateFrame(name, parent, width, height, isTransparent, template)
local f = CreateFrame("Frame", name, parent, template and template..",BackdropTemplate" or "BackdropTemplate")
f:Hide()
if not isTransparent then addon:StylizeFrame(f) end
f:EnableMouse(true)
if width and height then P:Size(f, width, height) end
function f:UpdatePixelPerfect()
if not isTransparent then addon:StylizeFrame(f) end
P:Resize(f)
end
return f
end
function addon:CreateMovableFrame(title, name, width, height, frameStrata, frameLevel, notUserPlaced)
local f = CreateFrame("Frame", name, UIParent, "BackdropTemplate")
f:EnableMouse(true)
f:SetIgnoreParentScale(true)
-- f:SetResizable(false)
f:SetMovable(true)
f:SetUserPlaced(not notUserPlaced)
f:SetFrameStrata(frameStrata or "HIGH")
f:SetFrameLevel(frameLevel or 1)
f:SetClampedToScreen(true)
f:SetClampRectInsets(0, 0, P:Scale(20), 0)
P:Size(f, width, height)
f:SetPoint("CENTER")
f:Hide()
addon:StylizeFrame(f)
-- header
local header = CreateFrame("Frame", nil, f, "BackdropTemplate")
f.header = header
header:EnableMouse(true)
header:SetClampedToScreen(true)
header:RegisterForDrag("LeftButton")
header:SetScript("OnDragStart", function()
f:StartMoving()
if notUserPlaced then f:SetUserPlaced(false) end
end)
header:SetScript("OnDragStop", function() f:StopMovingOrSizing() end)
header:SetPoint("LEFT")
header:SetPoint("RIGHT")
header:SetPoint("BOTTOM", f, "TOP", 0, -1)
P:Height(header, 20)
addon:StylizeFrame(header, {0.115, 0.115, 0.115, 1})
header.text = header:CreateFontString(nil, "OVERLAY", font_class_title_name)
header.text:SetText(title)
header.text:SetPoint("CENTER", header)
header.closeBtn = addon:CreateButton(header, "×", "red", {20, 20}, false, false, "CELL_FONT_SPECIAL", "CELL_FONT_SPECIAL")
header.closeBtn:SetPoint("TOPRIGHT")
header.closeBtn:SetScript("OnClick", function() f:Hide() end)
function f:UpdatePixelPerfect()
f:SetClampRectInsets(0, 0, P:Scale(20), 0)
P:Resize(f)
addon:StylizeFrame(f)
P:Resize(header, 20)
P:Repoint(header)
addon:StylizeFrame(header, {0.115, 0.115, 0.115, 1})
header.closeBtn:UpdatePixelPerfect()
end
return f
end
-----------------------------------------
-- tooltip
-----------------------------------------
local function ShowTooltips(widget, anchor, x, y, tooltips)
if type(tooltips) ~= "table" or #tooltips == 0 then
CellTooltip:Hide()
return
end
CellTooltip:SetOwner(widget, anchor or "ANCHOR_TOP", x or 0, y or 0)
CellTooltip:AddLine(tooltips[1])
for i = 2, #tooltips do
if tooltips[i] then
CellTooltip:AddLine("|cffffffff" .. tooltips[i])
end
end
CellTooltip:Show()
end
function addon:SetTooltips(widget, anchor, x, y, ...)
if not widget._tooltipsInited then
widget._tooltipsInited = true
widget:HookScript("OnEnter", function()
ShowTooltips(widget, anchor, x, y, widget.tooltips)
end)
widget:HookScript("OnLeave", function()
CellTooltip:Hide()
end)
end
widget.tooltips = {...}
end
function addon:ClearTooltips(widget)
widget.tooltips = nil
end
-----------------------------------------
-- change frame size with animation
-----------------------------------------
function addon:ChangeSizeWithAnimation(frame, targetWidth, targetHeight, step, startFunc, endFunc, repoint)
if startFunc then startFunc() end
local currentHeight = frame:GetHeight()
local currentWidth = frame:GetWidth()
targetWidth = targetWidth or currentWidth
targetHeight = targetHeight or currentHeight
step = step or 6
local diffH = (targetHeight - currentHeight) / step
local diffW = (targetWidth - currentWidth) / step
local animationTimer
animationTimer = C_Timer.NewTicker(0.025, function()
if diffW ~= 0 then
if diffW > 0 then
currentWidth = math.min(currentWidth + diffW, targetWidth)
else
currentWidth = math.max(currentWidth + diffW, targetWidth)
end
P:Width(frame, currentWidth)
end
if diffH ~= 0 then
if diffH > 0 then
currentHeight = math.min(currentHeight + diffH, targetHeight)
else
currentHeight = math.max(currentHeight + diffH, targetHeight)
end
P:Height(frame, currentHeight)
end
if currentWidth == targetWidth and currentHeight == targetHeight then
animationTimer:Cancel()
animationTimer = nil
if endFunc then endFunc() end
if repoint then P:PixelPerfectPoint(frame) end -- already point to another frame
end
end)
end
-----------------------------------------
-- Button
-----------------------------------------
function addon:CreateButton(parent, text, buttonColor, size, noBorder, noBackground, fontNormal, fontDisable, template, ...)
local b = CreateFrame("Button", nil, parent, template and template..",BackdropTemplate" or "BackdropTemplate")
if parent then b:SetFrameLevel(parent:GetFrameLevel()+1) end
b:SetText(text)
P:Size(b, size[1], size[2])
local color, hoverColor
if buttonColor == "red" then
color = {0.6, 0.1, 0.1, 0.6}
hoverColor = {0.6, 0.1, 0.1, 1}
elseif buttonColor == "red-hover" then
color = {0.115, 0.115, 0.115, 1}
hoverColor = {0.6, 0.1, 0.1, 1}
elseif buttonColor == "green" then
color = {0.1, 0.6, 0.1, 0.6}
hoverColor = {0.1, 0.6, 0.1, 1}
elseif buttonColor == "green-hover" then
color = {0.115, 0.115, 0.115, 1}
hoverColor = {0.1, 0.6, 0.1, 1}
elseif buttonColor == "cyan" then
color = {0, 0.9, 0.9, 0.6}
hoverColor = {0, 0.9, 0.9, 1}
elseif buttonColor == "blue" then
color = {0, 0.5, 0.8, 0.6}
hoverColor = {0, 0.5, 0.8, 1}
elseif buttonColor == "blue-hover" then
color = {0.115, 0.115, 0.115, 1}
hoverColor = {0, 0.5, 0.8, 1}
elseif buttonColor == "yellow" then
color = {0.7, 0.7, 0, 0.6}
hoverColor = {0.7, 0.7, 0, 1}
elseif buttonColor == "yellow-hover" then
color = {0.115, 0.115, 0.115, 1}
hoverColor = {0.7, 0.7, 0, 1}
elseif buttonColor == "accent" then
if class == "PRIEST" and not accentColorOverride then
color = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.25}
hoverColor = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.5}
else
color = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.3}
hoverColor = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.6}
end
elseif buttonColor == "accent-hover" then
color = {0.115, 0.115, 0.115, 1}
if class == "PRIEST" and not accentColorOverride then
hoverColor = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.5}
else
hoverColor = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.6}
end
elseif buttonColor == "chartreuse" then
color = {0.5, 1, 0, 0.6}
hoverColor = {0.5, 1, 0, 0.8}
elseif buttonColor == "magenta" then
color = {0.6, 0.1, 0.6, 0.6}
hoverColor = {0.6, 0.1, 0.6, 1}
elseif buttonColor == "transparent" then -- drop down item
color = {0, 0, 0, 0}
hoverColor = {0.5, 1, 0, 0.7}
elseif buttonColor == "transparent-white" then -- drop down item
color = {0, 0, 0, 0}
hoverColor = {0.4, 0.4, 0.4, 0.7}
elseif buttonColor == "transparent-light" then -- drop down item
color = {0, 0, 0, 0}
hoverColor = {0.5, 1, 0, 0.5}
elseif buttonColor == "transparent-accent" then -- drop down item
color = {0, 0, 0, 0}
if class == "PRIEST" and not accentColorOverride then
hoverColor = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.4}
else
hoverColor = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.6}
end
elseif buttonColor == "none" then
color = {0, 0, 0, 0}
else
color = {0.115, 0.115, 0.115, 1}
hoverColor = {0.23, 0.23, 0.23, 1}
end
-- keep color & hoverColor
b.color = color
b.hoverColor = hoverColor
local s = b:GetFontString()
b.fs = s
if s then
s:SetWordWrap(false)
-- s:SetWidth(size[1])
s:SetPoint("LEFT")
s:SetPoint("RIGHT")
function b:SetTextColor(...)
s:SetTextColor(...)
end
end
if noBorder then
b:SetBackdrop({bgFile = Cell.vars.whiteTexture})
else
local n = P:Scale(1)
b:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = n, insets = {left=n, right=n, top=n, bottom=n}})
end
if buttonColor and string.find(buttonColor, "transparent") then -- drop down item
-- b:SetBackdrop({bgFile = Cell.vars.whiteTexture})
if s then
s:SetJustifyH("LEFT")
s:SetPoint("LEFT", 5, 0)
s:SetPoint("RIGHT", -5, 0)
end
b:SetBackdropBorderColor(1, 1, 1, 0)
b:SetPushedTextOffset(0, 0)
else
if not noBackground then
local bg = b:CreateTexture()
bg:SetDrawLayer("BACKGROUND", -8)
b.bg = bg
bg:SetAllPoints(b)
bg:SetColorTexture(0.115, 0.115, 0.115, 1)
end
b:SetBackdropBorderColor(0, 0, 0, 1)
b:SetPushedTextOffset(0, -1)
end
b:SetBackdropColor(unpack(color))
b:SetDisabledFontObject(fontDisable or font_disable)
b:SetNormalFontObject(fontNormal or font)
b:SetHighlightFontObject(fontNormal or font)
if buttonColor ~= "none" then
b:SetScript("OnEnter", function(self) self:SetBackdropColor(unpack(self.hoverColor)) end)
b:SetScript("OnLeave", function(self) self:SetBackdropColor(unpack(self.color)) end)
end
-- click sound
if not Cell.isVanilla then
b:SetScript("PostClick", function(self, button, down)
if template and strfind(template, "SecureActionButtonTemplate") then
-- NOTE: ActionButtonUseKeyDown will affect OnClick
if down == GetCVarBool("ActionButtonUseKeyDown") then
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
end
else
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
end
end)
else
b:SetScript("PostClick", function() PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON) end)
end
addon:SetTooltips(b, "ANCHOR_TOPLEFT", 0, 3, ...)
-- texture
function b:SetTexture(tex, texSize, point, isAtlas, noPushDownEffect)
b.tex = b:CreateTexture(nil, "ARTWORK")
b.tex:SetPoint(unpack(point))
b.tex:SetSize(unpack(texSize))
if isAtlas then
b.tex:SetAtlas(tex)
else
b.tex:SetTexture(tex)
end
-- update fontstring point
if s then
s:ClearAllPoints()
s:SetPoint("LEFT", b.tex, "RIGHT", point[2], 0)
s:SetPoint("RIGHT", -point[2], 0)
b:SetPushedTextOffset(0, 0)
end
-- push effect
if not noPushDownEffect then
b.onMouseDown = function()
b.tex:ClearAllPoints()
b.tex:SetPoint(point[1], point[2], point[3]-1)
end
b.onMouseUp = function()
b.tex:ClearAllPoints()
b.tex:SetPoint(unpack(point))
end
b:SetScript("OnMouseDown", b.onMouseDown)
b:SetScript("OnMouseUp", b.onMouseUp)
end
-- enable / disable
b:HookScript("OnEnable", function()
b.tex:SetVertexColor(1, 1, 1)
b:SetScript("OnMouseDown", b.onMouseDown)
b:SetScript("OnMouseUp", b.onMouseUp)
end)
b:HookScript("OnDisable", function()
b.tex:SetVertexColor(0.4, 0.4, 0.4)
b:SetScript("OnMouseDown", nil)
b:SetScript("OnMouseUp", nil)
end)
end
function b:UpdatePixelPerfect()
P:Resize(b)
P:Repoint(b)
if not noBorder then
-- backup colors
local currentBackdropColor = {b:GetBackdropColor()}
local currentBackdropBorderColor = {b:GetBackdropBorderColor()}
-- update backdrop
local n = P:Scale(1)
b:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = n, insets = {left=n, right=n, top=n, bottom=n}})
-- restore colors
b:SetBackdropColor(unpack(currentBackdropColor))
b:SetBackdropBorderColor(unpack(currentBackdropBorderColor))
currentBackdropColor = nil
currentBackdropBorderColor = nil
end
end
return b
end
-----------------------------------------
-- Button Group
-----------------------------------------
function addon:CreateButtonGroup(buttons, onClick, func1, func2, onEnter, onLeave)
local function HighlightButton(id)
for _, b in pairs(buttons) do
if id == b.id then
b:SetBackdropColor(unpack(b.hoverColor))
b:SetScript("OnEnter", function()
if b.ShowTooltip then b.ShowTooltip(b) end
if onEnter then onEnter(b) end
end)
b:SetScript("OnLeave", function()
if b.HideTooltip then b.HideTooltip() end
if onLeave then onLeave(b) end
end)
if func1 then func1(b.id, b) end
else
b:SetBackdropColor(unpack(b.color))
b:SetScript("OnEnter", function()
if b.ShowTooltip then b.ShowTooltip(b) end
b:SetBackdropColor(unpack(b.hoverColor))
if onEnter then onEnter(b) end
end)
b:SetScript("OnLeave", function()
if b.HideTooltip then b.HideTooltip() end
b:SetBackdropColor(unpack(b.color))
if onLeave then onLeave(b) end
end)
if func2 then func2(b.id, b) end
end
end
end
for _, b in pairs(buttons) do
b:SetScript("OnClick", function()
HighlightButton(b.id)
onClick(b.id, b)
end)
end
return HighlightButton
end
-----------------------------------------
-- tips button
-----------------------------------------
function addon:CreateTipsButton(parent, size, points, ...)
-- tips
local tips = Cell:CreateButton(parent, nil, "accent-hover", {size, size})
tips:SetPoint("TOPRIGHT")
tips.tex = tips:CreateTexture(nil, "ARTWORK")
tips.tex:SetAllPoints(tips)
tips.tex:SetTexture("Interface\\AddOns\\Cell\\Media\\Icons\\info2.tga")
local lines = {...}
tips:HookScript("OnEnter", function()
CellTooltip:SetOwner(tips, "ANCHOR_NONE")
for i, line in pairs(lines) do
if i == 1 then
CellTooltip:AddLine(line)
else
if type(line) == "string" then
CellTooltip:AddLine("|cffffffff"..line)
elseif type(line) == "table" then
CellTooltip:AddDoubleLine("|cffffffff"..line[1], "|cffffffff"..line[2])
end
end
end
if points == "BOTTOMLEFT" then
CellTooltip:SetPoint("BOTTOMLEFT", tips, "TOPLEFT", 0, 3)
elseif points == "BOTTOMRIGHT" then
CellTooltip:SetPoint("BOTTOMRIGHT", tips, "TOPRIGHT", 0, 3)
else
CellTooltip:SetPoint(unpack(points))
end
CellTooltip:Show()
end)
tips:HookScript("OnLeave", function()
CellTooltip:Hide()
end)
end
-----------------------------------------
-- check button
-----------------------------------------
function addon:CreateCheckButton(parent, label, onClick, ...)
-- InterfaceOptionsCheckButtonTemplate --> FrameXML\InterfaceOptionsPanels.xml line 19
-- OptionsBaseCheckButtonTemplate --> FrameXML\OptionsPanelTemplates.xml line 10
local cb = CreateFrame("CheckButton", nil, parent, "BackdropTemplate")
cb.onClick = onClick
cb:SetScript("OnClick", function(self)
PlaySound(self:GetChecked() and SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_ON or SOUNDKIT.IG_MAINMENU_OPTION_CHECKBOX_OFF)
if cb.onClick then cb.onClick(self:GetChecked() and true or false, self) end
end)
cb.label = cb:CreateFontString(nil, "OVERLAY", font_name)
cb.label:SetText(label)
cb.label:SetPoint("LEFT", cb, "RIGHT", P:Scale(5), 0)
-- cb.label:SetTextColor(accentColor.t[1], accentColor.t[2], accentColor.t[3])
P:Size(cb, 14, 14)
if strtrim(label) ~= "" then
cb:SetHitRectInsets(0, -cb.label:GetStringWidth()-5, 0, 0)
end
cb:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
cb:SetBackdropColor(0.115, 0.115, 0.115, 0.9)
cb:SetBackdropBorderColor(0, 0, 0, 1)
local checkedTexture = cb:CreateTexture(nil, "ARTWORK")
checkedTexture:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.7)
checkedTexture:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
checkedTexture:SetPoint("BOTTOMRIGHT", P:Scale(-1), P:Scale(1))
local highlightTexture = cb:CreateTexture(nil, "ARTWORK")
highlightTexture:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.1)
highlightTexture:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
highlightTexture:SetPoint("BOTTOMRIGHT", P:Scale(-1), P:Scale(1))
cb:SetCheckedTexture(checkedTexture)
cb:SetHighlightTexture(highlightTexture, "ADD")
-- cb:SetDisabledCheckedTexture([[Interface\AddOns\Cell\Media\CheckBox\CheckBox-DisabledChecked-16x16]])
cb:SetScript("OnEnable", function()
cb.label:SetTextColor(1, 1, 1)
checkedTexture:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.7)
cb:SetBackdropBorderColor(0, 0, 0, 1)
end)
cb:SetScript("OnDisable", function()
cb.label:SetTextColor(0.4, 0.4, 0.4)
checkedTexture:SetColorTexture(0.4, 0.4, 0.4)
cb:SetBackdropBorderColor(0, 0, 0, 0.4)
end)
function cb:SetText(text)
cb.label:SetText(text)
if strtrim(text) ~= "" then
cb:SetHitRectInsets(0, -cb.label:GetStringWidth()-5, 0, 0)
else
cb:SetHitRectInsets(0, 0, 0, 0)
end
end
addon:SetTooltips(cb, "ANCHOR_TOPLEFT", 0, 3, ...)
return cb
end
-----------------------------------------
-- colorpicker
-----------------------------------------
function addon:CreateColorPicker(parent, label, hasOpacity, onChange, onConfirm)
local cp = CreateFrame("Button", nil, parent, "BackdropTemplate")
P:Size(cp, 14, 14)
cp:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
cp:SetBackdropBorderColor(0, 0, 0, 1)
cp:SetScript("OnEnter", function()
cp:SetBackdropBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.5)
end)
cp:SetScript("OnLeave", function()
cp:SetBackdropBorderColor(0, 0, 0, 1)
end)
cp.label = cp:CreateFontString(nil, "OVERLAY", font_name)
cp.label:SetText(label)
cp.label:SetPoint("LEFT", cp, "RIGHT", 5, 0)
cp.mask = cp:CreateTexture(nil, "ARTWORK")
cp.mask:SetColorTexture(0.15, 0.15, 0.15, 0.7)
cp.mask:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
cp.mask:SetPoint("BOTTOMRIGHT", P:Scale(-1), P:Scale(1))
cp.mask:Hide()
-- local function ColorCallback(restore)
-- local newR, newG, newB, newA
-- if restore then
-- newR, newG, newB, newA = unpack(restore)
-- else
-- newA, newR, newG, newB = OpacitySliderFrame:GetValue(), ColorPickerFrame:GetColorRGB()
-- end
-- newR, newG, newB, newA = tonumber(string.format("%.3f", newR)), tonumber(string.format("%.3f", newG)), tonumber(string.format("%.3f", newB)), newA and tonumber(string.format("%.3f", newA))
-- newA = hasOpacity and newA or 1
-- cp:SetBackdropColor(newR, newG, newB, newA)
-- if func then
-- func(newR, newG, newB, newA)
-- cp.color[1] = newR
-- cp.color[2] = newG
-- cp.color[3] = newB
-- cp.color[4] = newA
-- end
-- end
-- local function ShowColorPicker()
-- ColorPickerFrame.hasOpacity = hasOpacity
-- ColorPickerFrame.opacity = cp.color[4]
-- ColorPickerFrame.previousValues = {unpack(cp.color)}
-- ColorPickerFrame.func, ColorPickerFrame.opacityFunc, ColorPickerFrame.cancelFunc = ColorCallback, ColorCallback, ColorCallback
-- ColorPickerFrame:SetColorRGB(unpack(cp.color))
-- ColorPickerFrame:Hide()
-- ColorPickerFrame:Show()
-- end
cp.hasOpacity = hasOpacity
function cp:EnableAlpha(enable)
addon:HideColorPicker()
cp.hasOpacity = enable
end
cp.onChange = onChange
cp.onConfirm = onConfirm
cp:SetScript("OnClick", function()
addon:ShowColorPicker(function(r, g, b, a)
cp:SetBackdropColor(r, g, b, a)
cp.color[1] = r
cp.color[2] = g
cp.color[3] = b
cp.color[4] = a
if cp.onChange then
cp.onChange(r, g, b, a)
end
end, cp.onConfirm, cp.hasOpacity, unpack(cp.color))
end)
cp.color = {1, 1, 1, 1}
function cp:SetColor(arg1, arg2, arg3, arg4)
if type(arg1) == "table" then
cp.color[1] = arg1[1]
cp.color[2] = arg1[2]
cp.color[3] = arg1[3]
cp.color[4] = arg1[4]
cp:SetBackdropColor(unpack(arg1))
else
cp.color[1] = arg1
cp.color[2] = arg2
cp.color[3] = arg3
cp.color[4] = arg4
cp:SetBackdropColor(arg1, arg2, arg3, arg4)
end
end
function cp:GetColor()
return cp.color
end
cp:SetScript("OnEnable", function()
cp.label:SetTextColor(1, 1, 1, 1)
cp.mask:Hide()
end)
cp:SetScript("OnDisable", function()
cp.label:SetTextColor(0.4, 0.4, 0.4, 1)
cp.mask:Show()
end)
return cp
end
-----------------------------------------
-- editbox
-----------------------------------------
function addon:CreateEditBox(parent, width, height, isTransparent, isMultiLine, isNumeric, font)
local eb = CreateFrame("EditBox", nil, parent, "BackdropTemplate")
if not isTransparent then addon:StylizeFrame(eb, {0.115, 0.115, 0.115, 0.9}) end
eb:SetFontObject(font or font_name)
eb:SetMultiLine(isMultiLine)
eb:SetMaxLetters(0)
eb:SetJustifyH("LEFT")
eb:SetJustifyV("MIDDLE")
P:Width(eb, width or 0)
P:Height(eb, height or 0)
eb:SetTextInsets(5, 5, 0, 0)
eb:SetAutoFocus(false)
eb:SetNumeric(isNumeric)
eb:SetScript("OnEscapePressed", function() eb:ClearFocus() end)
eb:SetScript("OnEnterPressed", function() eb:ClearFocus() end)
eb:SetScript("OnEditFocusGained", function() eb:HighlightText() end)
eb:SetScript("OnEditFocusLost", function() eb:HighlightText(0, 0) end)
eb:SetScript("OnDisable", function() eb:SetTextColor(0.4, 0.4, 0.4, 1) end)
eb:SetScript("OnEnable", function() eb:SetTextColor(1, 1, 1, 1) end)
return eb
end
function addon:CreateScrollEditBox(parent, onTextChanged, scrollStep)
scrollStep = scrollStep or 1
local frame = CreateFrame("Frame", nil, parent)
addon:CreateScrollFrame(frame)
addon:StylizeFrame(frame.scrollFrame, {0.15, 0.15, 0.15, 0.9})
frame.eb = addon:CreateEditBox(frame.scrollFrame.content, 10, 20, true, true)
frame.eb:SetPoint("TOPLEFT")
frame.eb:SetPoint("RIGHT")
frame.eb:SetTextInsets(2, 2, 2, 2)
frame.eb:SetScript("OnEditFocusGained", nil)
frame.eb:SetScript("OnEditFocusLost", nil)
frame.eb:SetScript("OnEnterPressed", function(self) self:Insert("\n") end)
-- https://wow.gamepedia.com/UIHANDLER_OnCursorChanged
frame.eb:SetScript("OnCursorChanged", function(self, x, y, arg, lineHeight)
frame.scrollFrame:SetScrollStep((lineHeight + frame.eb:GetSpacing()) * scrollStep)
local vs = frame.scrollFrame:GetVerticalScroll()
local h = frame.scrollFrame:GetHeight()
local cursorHeight = lineHeight - y
if vs + y > 0 then -- cursor above current view
frame.scrollFrame:SetVerticalScroll(-y)
elseif cursorHeight > h + vs then
frame.scrollFrame:SetVerticalScroll(-y-h+lineHeight+arg)
end
if frame.scrollFrame:GetVerticalScroll() > frame.scrollFrame:GetVerticalScrollRange() then frame.scrollFrame:ScrollToBottom() end
end)
frame.eb:SetScript("OnTextChanged", function(self, userChanged)
frame.scrollFrame:SetContentHeight(self:GetHeight())
if onTextChanged then
onTextChanged(self, userChanged)
end
end)
frame.scrollFrame:SetScript("OnMouseDown", function()
frame.eb:SetFocus(true)
end)
function frame:SetText(text)
frame.eb:SetText(text)
frame.scrollFrame:ResetScroll()
frame.eb:SetCursorPosition(0)
end
function frame:GetText()
return frame.eb:GetText()
end
function frame:SetEnabled(enabled)
frame.eb:SetEnabled(enabled)
end
return frame
end
-----------------------------------------
-- slider 2020-08-25 02:49:16
-----------------------------------------
-- Interface\FrameXML\OptionsPanelTemplates.xml, line 76, OptionsSliderTemplate
function addon:CreateSlider(name, parent, low, high, width, step, onValueChangedFn, afterValueChangedFn, isPercentage, ...)
local tooltips = {...}
local slider = CreateFrame("Slider", nil, parent, "BackdropTemplate")
slider:SetValueStep(step)
slider:SetObeyStepOnDrag(true)
slider:SetOrientation("HORIZONTAL")
P:Size(slider, width, 10)
local unit = isPercentage and "%" or ""
addon:StylizeFrame(slider, {0.115, 0.115, 0.115, 1})
local label = slider:CreateFontString(nil, "OVERLAY", font_name)
label:SetText(name)
label:SetPoint("BOTTOM", slider, "TOP", 0, 2)
function slider:SetLabel(n)
label:SetText(n)
end
local currentEditBox = addon:CreateEditBox(slider, 48, 14)
slider.currentEditBox = currentEditBox
P:Point(currentEditBox, "TOPLEFT", slider, "BOTTOMLEFT", math.ceil(width / 2 - 24), -1)
-- currentEditBox:SetPoint("TOP", slider, "BOTTOM", 0, -1)
currentEditBox:SetJustifyH("CENTER")
currentEditBox:SetScript("OnEditFocusGained", function(self)
self:HighlightText()
end)
currentEditBox:SetScript("OnEnterPressed", function(self)
self:ClearFocus()
local value = tonumber(self:GetText())
if value == self.oldValue then return end
if value then
if value < slider.low then value = slider.low end
if value > slider.high then value = slider.high end
self:SetText(value)
slider:SetValue(value)
if slider.onValueChangedFn then slider.onValueChangedFn(value) end
if slider.afterValueChangedFn then slider.afterValueChangedFn(value) end
else
self:SetText(self.oldValue)
end
end)
currentEditBox:SetScript("OnShow", function(self)
if self.oldValue then self:SetText(self.oldValue) end
end)
local lowText = slider:CreateFontString(nil, "OVERLAY", font_name)
slider.lowText = lowText
lowText:SetTextColor(unpack(colors.grey.t))
lowText:SetPoint("TOPLEFT", slider, "BOTTOMLEFT", 0, -1)
lowText:SetPoint("BOTTOM", currentEditBox)
local highText = slider:CreateFontString(nil, "OVERLAY", font_name)
slider.highText = highText
highText:SetTextColor(unpack(colors.grey.t))
highText:SetPoint("TOPRIGHT", slider, "BOTTOMRIGHT", 0, -1)
highText:SetPoint("BOTTOM", currentEditBox)
local tex = slider:CreateTexture(nil, "ARTWORK")
tex:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.7)
tex:SetSize(8, 8)
slider:SetThumbTexture(tex)
local valueBeforeClick
slider.onEnter = function()
tex:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
valueBeforeClick = slider:GetValue()
if #tooltips > 0 then
ShowTooltips(slider, "ANCHOR_TOPLEFT", 0, 3, tooltips)
end
end
slider:SetScript("OnEnter", slider.onEnter)
slider.onLeave = function()
tex:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.7)
CellTooltip:Hide()
end
slider:SetScript("OnLeave", slider.onLeave)
slider.onValueChangedFn = onValueChangedFn
slider.afterValueChangedFn = afterValueChangedFn
-- if tooltip then slider.tooltipText = tooltip end
local oldValue
slider:SetScript("OnValueChanged", function(self, value, userChanged)
if oldValue == value then return end
oldValue = value
if math.floor(value) < value then -- decimal
value = tonumber(string.format("%.2f", value))
end
currentEditBox:SetText(value)
currentEditBox.oldValue = value
if userChanged and slider.onValueChangedFn then slider.onValueChangedFn(value) end
end)
-- local valueBeforeClick
-- slider:HookScript("OnEnter", function(self, button, isMouseOver)
-- valueBeforeClick = slider:GetValue()
-- end)
slider:SetScript("OnMouseUp", function(self, button, isMouseOver)
if not slider:IsEnabled() then return end
-- oldValue here == newValue, OnMouseUp called after OnValueChanged
if valueBeforeClick ~= oldValue and slider.afterValueChangedFn then
valueBeforeClick = oldValue
local value = slider:GetValue()
if math.floor(value) < value then -- decimal
value = tonumber(string.format("%.2f", value))
end
slider.afterValueChangedFn(value)
end
end)
--[[
slider:EnableMouseWheel(true)
slider:SetScript("OnMouseWheel", function(self, delta)
if not IsShiftKeyDown() then return end
-- NOTE: OnValueChanged may not be called: value == low
oldValue = oldValue and oldValue or low
local value
if delta == 1 then -- scroll up
value = oldValue + step
value = value > high and high or value
elseif delta == -1 then -- scroll down
value = oldValue - step
value = value < low and low or value
end
if value ~= oldValue then
slider:SetValue(value)
if slider.onValueChangedFn then slider.onValueChangedFn(value) end
if slider.afterValueChangedFn then slider.afterValueChangedFn(value) end
end
end)
]]
slider:SetValue(low) -- NOTE: needs to be after OnValueChanged
slider:SetScript("OnDisable", function()
label:SetTextColor(0.4, 0.4, 0.4)
currentEditBox:SetEnabled(false)
slider:SetScript("OnEnter", nil)
slider:SetScript("OnLeave", nil)
tex:SetColorTexture(0.4, 0.4, 0.4, 0.7)
lowText:SetTextColor(0.4, 0.4, 0.4)
highText:SetTextColor(0.4, 0.4, 0.4)
end)
slider:SetScript("OnEnable", function()
label:SetTextColor(1, 1, 1)
currentEditBox:SetEnabled(true)
slider:SetScript("OnEnter", slider.onEnter)
slider:SetScript("OnLeave", slider.onLeave)
tex:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.7)
lowText:SetTextColor(unpack(colors.grey.t))
highText:SetTextColor(unpack(colors.grey.t))
end)
function slider:UpdateMinMaxValues(minV, maxV)
slider:SetMinMaxValues(minV, maxV)
slider.low = minV
slider.high = maxV
lowText:SetText(minV..unit)
highText:SetText(maxV..unit)
end
slider:UpdateMinMaxValues(low, high)
return slider
end
-----------------------------------------
-- switch
-----------------------------------------
function addon:CreateSwitch(parent, size, leftText, leftValue, rightText, rightValue, func)
local switch = CreateFrame("Frame", nil, parent, "BackdropTemplate")
P:Size(switch, size[1], size[2])
addon:StylizeFrame(switch, {0.115, 0.115, 0.115, 1})
local textLeft = switch:CreateFontString(nil, "OVERLAY", font_name)
textLeft:SetPoint("LEFT", 2, 0)
textLeft:SetPoint("RIGHT", switch, "CENTER", -1, 0)
textLeft:SetText(leftText)
local textRight = switch:CreateFontString(nil, "OVERLAY", font_name)
textRight:SetPoint("LEFT", switch, "CENTER", 1, 0)
textRight:SetPoint("RIGHT", -2, 0)
textRight:SetText(rightText)
local highlight = switch:CreateTexture(nil, "ARTWORK")
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.35)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.45)
end
local function UpdateHighlight(which)
highlight:ClearAllPoints()
if which == "LEFT" then
highlight:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
highlight:SetPoint("RIGHT", switch, "CENTER")
highlight:SetPoint("BOTTOM", 0, P:Scale(1))
else
highlight:SetPoint("TOPRIGHT", P:Scale(-1), P:Scale(-1))
highlight:SetPoint("LEFT", switch, "CENTER")
highlight:SetPoint("BOTTOM", 0, P:Scale(1))
end
end
local ag = highlight:CreateAnimationGroup()
local t1 = ag:CreateAnimation("Translation")
t1:SetOffset(highlight:GetWidth(), 0)
t1:SetDuration(0.2)
t1:SetSmoothing("IN_OUT")
ag:SetScript("OnPlay", function()
switch.isPlaying = true -- prevent continuous clicking
end)
ag:SetScript("OnFinished", function()
switch.isPlaying = false
if switch.selected == "LEFT" then
switch:SetSelected("RIGHT", true)
elseif switch.selected == "RIGHT" then
switch:SetSelected("LEFT", true)
end
end)
function switch:SetSelected(value, runFunc)
if value == leftValue or value == "LEFT" then
switch.selected = "LEFT"
switch.selectedValue = leftValue
UpdateHighlight("LEFT")
t1:SetOffset(highlight:GetWidth(), 0)
elseif value == rightValue or value == "RIGHT" then
switch.selected = "RIGHT"
switch.selectedValue = rightValue
UpdateHighlight("RIGHT")
t1:SetOffset(-highlight:GetWidth(), 0)
end
if func and runFunc then func(switch.selectedValue) end
end
switch:SetScript("OnMouseDown", function()
if switch.selected and not switch.isPlaying then
ag:Play()
end
end)
switch:SetScript("OnEnter", function()
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.55)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.65)
end
end)
switch:SetScript("OnLeave", function()
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.35)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.45)
end
end)
return switch
end
function addon:CreateTripleSwitch(parent, size, func)
local switch = CreateFrame("Frame", nil, parent, "BackdropTemplate")
P:Size(switch, size[1], size[2])
addon:StylizeFrame(switch, {0.115, 0.115, 0.115, 1})
local highlight = switch:CreateTexture(nil, "ARTWORK")
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.35)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.45)
end
local function UpdateHighlight(which)
local width = size[1] - 2
highlight:ClearAllPoints()
if which == "LEFT" then
highlight:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", switch, "BOTTOMLEFT", P:Scale(width/3+1), P:Scale(1))
elseif which == "CENTER" then
highlight:SetPoint("TOPLEFT", P:Scale(width/3+1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", P:Scale(-width/3-1), P:Scale(1))
else
highlight:SetPoint("TOPLEFT", P:Scale(width/3*2+1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", P:Scale(-1), P:Scale(1))
end
end
local ag = highlight:CreateAnimationGroup()
local t1 = ag:CreateAnimation("Translation")
-- t1:SetOffset(highlight:GetWidth(), 0)
t1:SetDuration(0.2)
t1:SetSmoothing("IN_OUT")
ag:SetScript("OnPlay", function()
switch.isPlaying = true -- prevent continuous clicking
end)
ag:SetScript("OnFinished", function()
switch.isPlaying = false
if switch.selected == "LEFT" then
switch:SetSelected("CENTER", true)
elseif switch.selected == "CENTER" then
switch:SetSelected("RIGHT", true)
else
switch:SetSelected("LEFT", true)
end
end)
function switch:SetSelected(value, runFunc)
local width = size[1] - 2
if value == "LEFT" then
switch.selected = "LEFT"
UpdateHighlight("LEFT")
t1:SetOffset(width/3, 0)
elseif value == "CENTER" then
switch.selected = "CENTER"
UpdateHighlight("CENTER")
t1:SetOffset(width/3, 0)
else
switch.selected = "RIGHT"
UpdateHighlight("RIGHT")
t1:SetOffset(-width/3*2, 0)
end
if func and runFunc then func(value) end
end
switch:SetScript("OnMouseDown", function()
if switch.selected and not switch.isPlaying then
ag:Play()
end
end)
switch:SetScript("OnEnter", function()
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.55)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.65)
end
end)
switch:SetScript("OnLeave", function()
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.35)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.45)
end
end)
return switch
end
function addon:CreateFourfoldSwitch(parent, size, func)
local switch = CreateFrame("Frame", nil, parent, "BackdropTemplate")
P:Size(switch, size[1], size[2])
addon:StylizeFrame(switch, {0.115, 0.115, 0.115, 1})
local highlight = switch:CreateTexture(nil, "ARTWORK")
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.35)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.45)
end
local function UpdateHighlight(value)
local width = size[1] - 2
highlight:ClearAllPoints()
if value == 1 then
highlight:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", switch, "BOTTOMLEFT", P:Scale(width/4+1), P:Scale(1))
elseif value == 2 then
highlight:SetPoint("TOPLEFT", P:Scale(width/4+1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", P:Scale(-width/4*2-1), P:Scale(1))
elseif value == 3 then
highlight:SetPoint("TOPLEFT", P:Scale(width/4*2+1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", P:Scale(-width/4-1), P:Scale(1))
else
highlight:SetPoint("TOPLEFT", P:Scale(width/4*3+1), P:Scale(-1))
highlight:SetPoint("BOTTOMRIGHT", P:Scale(-1), P:Scale(1))
end
end
local ag = highlight:CreateAnimationGroup()
local t1 = ag:CreateAnimation("Translation")
-- t1:SetOffset(highlight:GetWidth(), 0)
t1:SetDuration(0.2)
t1:SetSmoothing("IN_OUT")
ag:SetScript("OnPlay", function()
switch.isPlaying = true -- prevent continuous clicking
end)
ag:SetScript("OnFinished", function()
switch.isPlaying = false
switch:SetSelected(switch.selected == 4 and 1 or switch.selected + 1, true)
end)
function switch:SetSelected(value, runFunc)
local width = size[1] - 2
switch.selected = value
UpdateHighlight(value)
if value == 1 then
t1:SetOffset(width/4, 0)
elseif value == 2 then
t1:SetOffset(width/4, 0)
elseif value == 3 then
t1:SetOffset(width/4, 0)
else
t1:SetOffset(-width/4*3, 0)
end
if func and runFunc then func(value) end
end
switch:SetScript("OnMouseDown", function()
if switch.selected and not switch.isPlaying then
ag:Play()
end
end)
switch:SetScript("OnEnter", function()
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.55)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.65)
end
end)
switch:SetScript("OnLeave", function()
if class == "PRIEST" and not accentColorOverride then
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.35)
else
highlight:SetColorTexture(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.45)
end
end)
return switch
end
-----------------------------------------
-- status bar
-----------------------------------------
function addon:CreateStatusBar(name, parent, width, height, maxValue, smooth, func, showText, texture, color)
local bar = CreateFrame("StatusBar", name, parent, "BackdropTemplate")
if not color then color = {accentColor.t[1], accentColor.t[2], accentColor.t[3], 1} end
if not texture then texture = Cell.vars.whiteTexture end
bar:SetStatusBarTexture(texture)
bar:SetStatusBarColor(unpack(color))
bar:GetStatusBarTexture():SetDrawLayer("BORDER", -1)
P:Width(bar, width)
P:Height(bar, height)
bar:SetBackdrop({bgFile=Cell.vars.whiteTexture, edgeFile=Cell.vars.whiteTexture, edgeSize=P:Scale(1)})
bar:SetBackdropColor(0.07, 0.07, 0.07, 0.9)
bar:SetBackdropBorderColor(0, 0, 0, 1)
if showText then
bar.text = bar:CreateFontString(nil, "OVERLAY", font_name)
bar.text:SetJustifyH("CENTER")
bar.text:SetJustifyV("MIDDLE")
bar.text:SetPoint("CENTER")
bar.text:SetText("0%")
end
bar:SetMinMaxValues(0, maxValue)
bar:SetValue(0)
if smooth then Mixin(bar, SmoothStatusBarMixin) end -- Interface\SharedXML\SmoothStatusBar.lua
function bar:SetMaxValue(m)
maxValue = m
if smooth then
bar:SetMinMaxSmoothedValue(0, m)
else
bar:SetMinMaxValues(0, m)
end
end
function bar:Reset()
if smooth then
bar:SetSmoothedValue(0)
else
bar:SetValue(0)
end
end
bar:SetScript("OnValueChanged", function(self, value)
if showText then
bar.text:SetText(format("%d%%", value / maxValue * 100))
end
if func then func(value) end
end)
bar:SetScript("OnHide", function()
bar:SetValue(0)
end)
function bar:UpdatePixelPerfect()
P:Resize(bar)
P:Repoint(bar)
P:Reborder(bar)
end
return bar
end
function addon:CreateStatusBarButton(parent, text, size, maxValue, template)
local b = Cell:CreateButton(parent, text, "accent-hover", size, false, true, nil, nil, template)
b:SetFrameLevel(parent:GetFrameLevel()+2)
b:SetBackdropColor(0, 0, 0, 0)
b:SetScript("OnEnter", function()
b:SetBackdropBorderColor(unpack(accentColor.t))
end)
b:SetScript("OnLeave", function()
b:SetBackdropBorderColor(0, 0, 0, 1)
end)
local bar = CreateFrame("StatusBar", nil, b, "BackdropTemplate")
b.bar = bar
bar:SetPoint("TOPLEFT", b)
bar:SetPoint("BOTTOMRIGHT", b)
bar:SetStatusBarTexture("Interface\\AddOns\\Cell\\Media\\statusbar.tga")
bar:SetStatusBarColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.5)
bar:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = 1})
bar:SetBackdropColor(0.115, 0.115, 0.115, 1)
bar:SetBackdropBorderColor(0, 0, 0, 0)
P:Size(bar, size[1], size[2])
bar:SetMinMaxValues(0, maxValue)
bar:SetValue(0)
bar:SetFrameLevel(parent:GetFrameLevel()+1)
function b:Start()
bar:SetValue(select(2, bar:GetMinMaxValues()))
bar:SetScript("OnUpdate", function(self, elapsed)
bar:SetValue(bar:GetValue()-elapsed)
if bar:GetValue() <= 0 then
b:Stop()
end
end)
end
function b:Stop()
bar:SetValue(0)
bar:SetScript("OnUpdate", nil)
end
function b:SetMaxValue(value)
bar:SetMinMaxValues(0, value)
bar:SetValue(value)
end
b._UpdatePixelPerfect = b.UpdatePixelPerfect -- store UpdatePixelPerfect in CreateButton
function b:UpdatePixelPerfect()
b:_UpdatePixelPerfect()
P:Resize(bar)
P:Repoint(bar)
-- update bar
-- backup colors
local currentBackdropColor = {bar:GetBackdropColor()}
local currentBackdropBorderColor = {bar:GetBackdropBorderColor()}
-- update backdrop
bar:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
-- restore colors
bar:SetBackdropColor(unpack(currentBackdropColor))
bar:SetBackdropBorderColor(unpack(currentBackdropBorderColor))
currentBackdropColor = nil
currentBackdropBorderColor = nil
end
return b
end
-----------------------------------------
-- mask
-----------------------------------------
function addon:CreateMask(parent, text, points) -- points = {topleftX, topleftY, bottomrightX, bottomrightY}
if not parent.mask then -- not init
parent.mask = CreateFrame("Frame", nil, parent, "BackdropTemplate")
addon:StylizeFrame(parent.mask, {0.15, 0.15, 0.15, 0.7}, {0, 0, 0, 0})
-- parent.mask:SetFrameStrata("HIGH")
parent.mask:SetFrameLevel(parent:GetFrameLevel()+30)
parent.mask:EnableMouse(true) -- can't click-through
parent.mask:EnableMouseWheel(true) -- can't scroll-through
parent.mask.text = parent.mask:CreateFontString(nil, "OVERLAY", font_title_name)
parent.mask.text:SetTextColor(1, 0.2, 0.2)
parent.mask.text:SetPoint("LEFT", 5, 0)
parent.mask.text:SetPoint("RIGHT", -5, 0)
-- parent.mask:SetScript("OnUpdate", function()
-- if not parent:IsVisible() then
-- parent.mask:Hide()
-- end
-- end)
end
if not text then text = "" end
parent.mask.text:SetText(text)
parent.mask:ClearAllPoints() -- prepare for SetPoint()
if points then
local tlX, tlY, brX, brY = unpack(points)
parent.mask:SetPoint("TOPLEFT", P:Scale(tlX), P:Scale(tlY))
parent.mask:SetPoint("BOTTOMRIGHT", P:Scale(brX), P:Scale(brY))
else
parent.mask:SetAllPoints(parent) -- anchor points are set to those of its "parent"
end
parent.mask:Show()
end
function addon:CreateCombatMask(parent, x1, y1, x2, y2)
local mask = CreateFrame("Frame", nil, parent, "BackdropTemplate")
parent.combatMask = mask
mask:SetPoint("TOPLEFT", P:Scale(x1 or 1), P:Scale(y1 or -1))
mask:SetPoint("BOTTOMRIGHT", P:Scale(x2 or -1), P:Scale(y2 or 1))
addon:StylizeFrame(mask, {0.17, 0.15, 0.15, 0.8}, {0, 0, 0, 0})
-- mask:SetFrameStrata("DIALOG")
mask:SetFrameLevel(parent:GetFrameLevel()+100)
mask:EnableMouse(true) -- can't click-through
mask:EnableMouseWheel(true) -- can't scroll-through
mask.text = mask:CreateFontString(nil, "OVERLAY", font_title_name)
mask.text:SetTextColor(1, 0.2, 0.2)
mask.text:SetPoint("LEFT", 5, 0)
mask.text:SetPoint("RIGHT", -5, 0)
mask.text:SetText(L["Can't change options in combat"])
mask:Hide()
end
-----------------------------------------
-- create popup (delete/edit/... confirm) with mask
-----------------------------------------
function addon:CreateConfirmPopup(parent, width, text, onAccept, onReject, mask, hasEditBox, dropdowns)
if not parent.confirmPopup then -- not init
parent.confirmPopup = CreateFrame("Frame", nil, parent, "BackdropTemplate")
parent.confirmPopup:SetSize(width, 100)
addon:StylizeFrame(parent.confirmPopup, {0.1, 0.1, 0.1, 0.95}, {accentColor.t[1], accentColor.t[2], accentColor.t[3], 1})
parent.confirmPopup:EnableMouse(true)
parent.confirmPopup:SetClampedToScreen(true)
parent.confirmPopup:Hide()
parent.confirmPopup:SetScript("OnHide", function()
parent.confirmPopup:Hide()
-- hide mask
if mask and parent.mask then parent.mask:Hide() end
end)
parent.confirmPopup.text = parent.confirmPopup:CreateFontString(nil, "OVERLAY", font_title_name)
parent.confirmPopup.text:SetWordWrap(true)
parent.confirmPopup.text:SetSpacing(3)
parent.confirmPopup.text:SetJustifyH("CENTER")
parent.confirmPopup.text:SetPoint("TOPLEFT", 5, -8)
parent.confirmPopup.text:SetPoint("TOPRIGHT", -5, -8)
-- yes
parent.confirmPopup.button1 = addon:CreateButton(parent.confirmPopup, L["Yes"], "green", {35, 15})
-- button1:SetPoint("BOTTOMRIGHT", -45, 0)
parent.confirmPopup.button1:SetPoint("BOTTOMRIGHT", -34, 0)
parent.confirmPopup.button1:SetBackdropBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
-- no
parent.confirmPopup.button2 = addon:CreateButton(parent.confirmPopup, L["No"], "red", {35, 15})
parent.confirmPopup.button2:SetPoint("LEFT", parent.confirmPopup.button1, "RIGHT", P:Scale(-1), 0)
parent.confirmPopup.button2:SetBackdropBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
end
if hasEditBox then
if not parent.confirmPopup.editBox then
parent.confirmPopup.editBox = addon:CreateEditBox(parent.confirmPopup, width-40, 20)
parent.confirmPopup.editBox:SetPoint("TOP", parent.confirmPopup.text, "BOTTOM", 0, -5)
parent.confirmPopup.editBox:SetAutoFocus(true)
parent.confirmPopup.editBox:SetScript("OnHide", function()
parent.confirmPopup.editBox:SetText("")
end)
end
parent.confirmPopup.editBox:Show()
-- disable yes if editBox empty
parent.confirmPopup.button1:SetEnabled(false)
parent.confirmPopup.editBox:SetScript("OnTextChanged", function()
if not parent.confirmPopup.editBox:GetText() or strtrim(parent.confirmPopup.editBox:GetText()) == "" then
parent.confirmPopup.button1:SetEnabled(false)
else
parent.confirmPopup.button1:SetEnabled(true)
end
end)
elseif parent.confirmPopup.editBox then
parent.confirmPopup.editBox:Hide()
parent.confirmPopup.editBox:SetScript("OnTextChanged", nil)
parent.confirmPopup.button1:SetEnabled(true)
end
if dropdowns then
if not parent.confirmPopup.dropdown1 then
parent.confirmPopup.dropdown1 = addon:CreateDropdown(parent.confirmPopup, width-40)
parent.confirmPopup.dropdown1:SetPoint("LEFT", 20, 0)
if hasEditBox then
parent.confirmPopup.dropdown1:SetPoint("TOP", parent.confirmPopup.editBox, "BOTTOM", 0, -5)
else
parent.confirmPopup.dropdown1:SetPoint("TOP", parent.confirmPopup.text, "BOTTOM", 0, -5)
end
end
if not parent.confirmPopup.dropdown2 then
parent.confirmPopup.dropdown2 = addon:CreateDropdown(parent.confirmPopup, (width-40)/2-3)
parent.confirmPopup.dropdown2:SetPoint("LEFT", parent.confirmPopup.dropdown1, "RIGHT", 5, 0)
end
if dropdowns == 1 then
parent.confirmPopup.dropdown1:Show()
parent.confirmPopup.dropdown2:Hide()
elseif dropdowns == 2 then
parent.confirmPopup.dropdown1:Show()
parent.confirmPopup.dropdown2:Show()
parent.confirmPopup.dropdown1:SetWidth((width-40)/2-2)
end
elseif parent.confirmPopup.dropdown1 then
parent.confirmPopup.dropdown1:Hide()
parent.confirmPopup.dropdown2:Hide()
end
if mask then -- show mask?
if not parent.mask then
addon:CreateMask(parent, nil, {1, -1, -1, 1})
else
parent.mask:Show()
end
end
parent.confirmPopup.button1:SetScript("OnClick", function()
if onAccept then onAccept(parent.confirmPopup) end
-- hide mask
if mask and parent.mask then parent.mask:Hide() end
parent.confirmPopup:Hide()
end)
parent.confirmPopup.button2:SetScript("OnClick", function()
if onReject then onReject(parent.confirmPopup) end
-- hide mask
if mask and parent.mask then parent.mask:Hide() end
parent.confirmPopup:Hide()
end)
parent.confirmPopup:SetWidth(width)
parent.confirmPopup.text:SetText(text)
-- update height
parent.confirmPopup:SetScript("OnUpdate", function(self, elapsed)
local newHeight = parent.confirmPopup.text:GetStringHeight() + 30
if hasEditBox then newHeight = newHeight + 30 end
if dropdowns then newHeight = newHeight + 30 end
parent.confirmPopup:SetHeight(newHeight)
-- run OnUpdate once, stop updating height
parent.confirmPopup:SetScript("OnUpdate", nil)
end)
-- parent.confirmPopup:SetFrameStrata("DIALOG")
parent.confirmPopup:SetFrameLevel(parent:GetFrameLevel() + 300)
parent.confirmPopup:ClearAllPoints() -- prepare for SetPoint()
parent.confirmPopup:Show()
return parent.confirmPopup
end
-----------------------------------------
-- notification popup
-----------------------------------------
function addon:CreateNotificationPopup(parent, width, text, mask)
if not parent.notificationPopup then -- not init
parent.notificationPopup = CreateFrame("Frame", nil, parent, "BackdropTemplate")
parent.notificationPopup:SetSize(width, 100)
addon:StylizeFrame(parent.notificationPopup, {0.1, 0.1, 0.1, 0.95}, {accentColor.t[1], accentColor.t[2], accentColor.t[3], 1})
parent.notificationPopup:EnableMouse(true)
parent.notificationPopup:SetClampedToScreen(true)
parent.notificationPopup:Hide()
parent.notificationPopup:SetScript("OnHide", function()
parent.notificationPopup:Hide()
-- hide mask
if mask and parent.mask then parent.mask:Hide() end
end)
parent.notificationPopup.text = parent.notificationPopup:CreateFontString(nil, "OVERLAY", font_title_name)
parent.notificationPopup.text:SetWordWrap(true)
parent.notificationPopup.text:SetSpacing(3)
parent.notificationPopup.text:SetJustifyH("CENTER")
parent.notificationPopup.text:SetPoint("TOPLEFT", 5, -8)
parent.notificationPopup.text:SetPoint("TOPRIGHT", -5, -8)
-- ok
parent.notificationPopup.button = addon:CreateButton(parent.notificationPopup, _G.OKAY, "green", {37, 17})
parent.notificationPopup.button:SetPoint("BOTTOMRIGHT")
parent.notificationPopup.button:SetBackdropBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
end
if mask then -- show mask?
if not parent.mask then
addon:CreateMask(parent, nil, {1, -1, -1, 1})
else
parent.mask:Show()
end
end
parent.notificationPopup.button:SetScript("OnClick", function()
if mask and parent.mask then parent.mask:Hide() end
parent.notificationPopup:Hide()
end)
parent.notificationPopup:SetWidth(width)
parent.notificationPopup.text:SetText(text)
-- update height
parent.notificationPopup:SetScript("OnUpdate", function(self, elapsed)
local newHeight = parent.notificationPopup.text:GetStringHeight() + 30
parent.notificationPopup:SetHeight(newHeight)
-- run OnUpdate once, stop updating height
parent.notificationPopup:SetScript("OnUpdate", nil)
end)
-- parent.notificationPopup:SetFrameStrata("DIALOG")
parent.notificationPopup:SetFrameLevel(parent:GetFrameLevel() + 310)
parent.notificationPopup:ClearAllPoints() -- prepare for SetPoint()
parent.notificationPopup:Show()
return parent.notificationPopup
end
-----------------------------------------
-- popup edit box
-----------------------------------------
function addon:CreatePopupEditBox(parent, func, multiLine)
if not parent.popupEditBox then
local eb = CreateFrame("EditBox", nil, parent, "BackdropTemplate")
parent.popupEditBox = eb
eb:Hide()
eb:SetAutoFocus(true)
eb:SetFontObject(font)
eb:SetJustifyH("LEFT")
eb:SetMultiLine(true)
eb:SetMaxLetters(255)
eb:SetTextInsets(5, 5, 3, 4)
addon:StylizeFrame(eb, {0.115, 0.115, 0.115, 1}, {accentColor.t[1], accentColor.t[2], accentColor.t[3], 1})
eb:SetScript("OnEscapePressed", function()
eb:SetText("")
eb:Hide()
end)
function eb:ShowEditBox(text)
eb:SetText(text)
eb:Show()
end
local tipsText = eb:CreateFontString(nil, "OVERLAY", font_name)
tipsText:SetPoint("TOPLEFT", eb, "BOTTOMLEFT", 2, -1)
tipsText:SetJustifyH("LEFT")
tipsText:Hide()
local tipsBackground = eb:CreateTexture(nil, "ARTWORK")
tipsBackground:SetPoint("TOPLEFT", eb, "BOTTOMLEFT")
tipsBackground:SetPoint("TOPRIGHT", eb, "BOTTOMRIGHT")
tipsBackground:SetPoint("BOTTOM", tipsText, 0, -2)
tipsBackground:SetColorTexture(0.115, 0.115, 0.115, 0.9)
tipsBackground:Hide()
function eb:SetTips(text)
tipsText:SetText(text)
tipsText:Show()
tipsBackground:Show()
end
eb:SetScript("OnHide", function()
eb:Hide() -- hide self when parent hides
tipsText:Hide()
tipsBackground:Hide()
end)
end
parent.popupEditBox:SetScript("OnEnterPressed", function(self)
if multiLine and IsShiftKeyDown() then -- new line
self:Insert("\n")
else
func(self:GetText())
self:Hide()
self:SetText("")
end
end)
-- set parent(for hiding) & size
parent.popupEditBox:ClearAllPoints()
-- parent.popupEditBox:SetFrameStrata("DIALOG")
parent.popupEditBox:SetFrameLevel(parent:GetFrameLevel() + 50)
return parent.popupEditBox
end
-----------------------------------------
-- dual popup edit box
-----------------------------------------
function addon:CreateDualPopupEditBox(parent, leftTip, rightTip, isNumeric, func)
if not parent.dualPopupEditBox then
local f = CreateFrame("Frame", nil, parent)
parent.dualPopupEditBox = f
P:Size(f, 230, 20)
f:Hide()
-- ok
local ok = addon:CreateButton(f, "OK", "accent", {30, 20})
f.ok = ok
ok:SetPoint("TOPRIGHT")
-- left
local left = CreateFrame("EditBox", nil, f, "BackdropTemplate")
f.left = left
left:SetPoint("TOPLEFT")
P:Size(left, 100, 20)
left:SetAutoFocus(false)
left:SetFontObject(font)
left:SetJustifyH("LEFT")
left:SetMultiLine(false)
left:SetMaxLetters(255)
left:SetNumeric(isNumeric)
left:SetTextInsets(5, 5, 3, 4)
addon:StylizeFrame(left, {0.115, 0.115, 0.115, 1}, {accentColor.t[1], accentColor.t[2], accentColor.t[3], 1})
left:SetScript("OnEditFocusGained", function() left:HighlightText() end)
left:SetScript("OnEditFocusLost", function() left:HighlightText(0, 0) end)
left:SetScript("OnEscapePressed", function() f:Hide() end)
left:SetScript("OnTextChanged", function()
if not left:GetText() or strtrim(left:GetText()) == "" then
left.tip:Show()
else
left.tip:Hide()
end
end)
left:SetScript("OnTabPressed", function()
left:ClearFocus()
f.right:SetFocus(true)
end)
left.tip = left:CreateFontString(nil, "OVERLAY", font_name)
left.tip:SetPoint("LEFT", 5, 0)
-- right
local right = CreateFrame("EditBox", nil, f, "BackdropTemplate")
f.right = right
right:SetPoint("TOPLEFT", left, "TOPRIGHT", P:Scale(1), 0)
right:SetPoint("TOPRIGHT", ok, "TOPLEFT", P:Scale(-1), 0)
P:Size(right, 100, 20)
right:SetAutoFocus(false)
right:SetFontObject(font)
right:SetJustifyH("LEFT")
right:SetMultiLine(false)
right:SetMaxLetters(255)
right:SetNumeric(isNumeric)
right:SetTextInsets(5, 5, 3, 4)
addon:StylizeFrame(right, {0.115, 0.115, 0.115, 1}, {accentColor.t[1], accentColor.t[2], accentColor.t[3], 1})
right:SetScript("OnEditFocusGained", function() right:HighlightText() end)
right:SetScript("OnEditFocusLost", function() right:HighlightText(0, 0) end)
right:SetScript("OnEscapePressed", function() f:Hide() end)
right:SetScript("OnTextChanged", function()
if not right:GetText() or strtrim(right:GetText()) == "" then
right.tip:Show()
else
right.tip:Hide()
end
end)
right:SetScript("OnTabPressed", function()
right:ClearFocus()
f.left:SetFocus(true)
end)
right.tip = right:CreateFontString(nil, "OVERLAY", font_name)
right.tip:SetPoint("LEFT", 5, 0)
f:SetScript("OnShow", function()
left.tip:Show()
right.tip:Show()
end)
f:SetScript("OnHide", function()
f:Hide()
left:SetText("")
right:SetText("")
left:ClearFocus()
right:ClearFocus()
end)
function f:ShowEditBox(l, r)
f:Show()
left:SetText(l or "")
right:SetText(r or "")
left:SetFocus(true)
end
end
parent.dualPopupEditBox.left.tip:SetText("|cffababab"..leftTip)
parent.dualPopupEditBox.right.tip:SetText("|cffababab"..rightTip)
parent.dualPopupEditBox.ok:SetScript("OnClick", function()
if isNumeric then
func(tonumber(parent.dualPopupEditBox.left:GetText()), tonumber(parent.dualPopupEditBox.right:GetText()))
else
func(parent.dualPopupEditBox.left:GetText(), parent.dualPopupEditBox.right:GetText())
end
parent.dualPopupEditBox:Hide()
end)
parent.dualPopupEditBox:ClearAllPoints()
parent.dualPopupEditBox:SetFrameLevel(parent:GetFrameLevel() + 50)
return parent.dualPopupEditBox
end
-----------------------------------------
-- cascading menu
-----------------------------------------
local menu = addon:CreateFrame(addonName.."CascadingMenu", UIParent, 100, 20)
addon.menu = menu
tinsert(UISpecialFrames, menu:GetName())
menu:SetClampedToScreen(true)
menu:SetBackdropColor(0.115, 0.115, 0.115, 0.977)
menu:SetBackdropBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
menu:SetFrameStrata("TOOLTIP")
menu.items = {}
function menu:UpdatePixelPerfect()
menu:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
menu:SetBackdropColor(0.115, 0.115, 0.115, 0.977)
menu:SetBackdropBorderColor(Cell:GetAccentColorRGB())
end
-- items: menu items table
-- itemTable: table to store item buttons --> menu/submenu
-- itemParent: menu/submenu
-- level: menu level, 0, 1, 2, 3, ...
local function CreateItemButtons(items, itemTable, itemParent, level)
itemParent:SetScript("OnHide", function(self) self:Hide() end)
for i, item in pairs(items) do
local b
if itemTable[i] and itemTable[i]:GetObjectType() == "Button" then
b = itemTable[i]
b:SetText(item.text)
else
b = addon:CreateButton(itemParent, item.text, "transparent-accent", {98 ,18}, true)
tinsert(itemTable, b)
end
b:SetParent(itemParent)
b:ClearAllPoints()
if i == 1 then
b:SetPoint("TOPLEFT", 1, -1)
b:SetPoint("RIGHT", -1, 0)
else
b:SetPoint("TOPLEFT", itemTable[i-1], "BOTTOMLEFT")
b:SetPoint("RIGHT", itemTable[i-1])
end
if item.textColor then
b:GetFontString():SetTextColor(unpack(item.textColor))
end
if item.icon then
if not b.icon then
b.iconBg = b:CreateTexture(nil, "BORDER")
P:Size(b.iconBg, 16, 16)
b.iconBg:SetPoint("TOPLEFT", P:Scale(5), P:Scale(-1))
b.iconBg:SetColorTexture(0, 0, 0, 1)
b.icon = b:CreateTexture(nil, "ARTWORK")
b.icon:SetPoint("TOPLEFT", b.iconBg, P:Scale(1), P:Scale(-1))
b.icon:SetPoint("BOTTOMRIGHT", b.iconBg, P:Scale(-1), P:Scale(1))
b.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
end
b.icon:SetTexture(item.icon)
b.icon:Show()
b.iconBg:Show()
b:GetFontString():SetPoint("LEFT", b.iconBg, "RIGHT", P:Scale(2), 0)
else
if b.icon then
b.icon:Hide()
b.iconBg:Hide()
end
b:GetFontString():SetPoint("LEFT", P:Scale(5), 0)
end
if level == 0 then
b:Show()-- show valid top menu buttons
else
b:Hide()
b:SetScript("OnHide", function(self) self:Hide() end)
end
if item.children then
-- create sub menu level+1
if not menu[level+1] then
-- menu[level+1] parent == menu[level]
menu[level+1] = addon:CreateFrame(addonName.."CascadingSubMenu"..level, level == 0 and menu or menu[level], 100, 20)
menu[level+1]:SetBackdropColor(0.115, 0.115, 0.115, 1)
menu[level+1]:SetBackdropBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
-- menu[level+1]:SetScript("OnHide", function(self) self:Hide() end)
end
if not b.childrenSymbol then
b.childrenSymbol = b:CreateFontString(nil, "OVERLAY", font_name)
b.childrenSymbol:SetText("|cFF777777>")
b.childrenSymbol:SetPoint("RIGHT", -5, 0)
end
b.childrenSymbol:Show()
CreateItemButtons(item.children, b, menu[level+1], level+1) -- itemTable == b, insert children to its table
b:SetScript("OnEnter", function()
b:SetBackdropColor(unpack(b.hoverColor))
menu[level+1]:Hide()
menu[level+1]:ClearAllPoints()
menu[level+1]:SetPoint("TOPLEFT", b, "TOPRIGHT", 2, 1)
menu[level+1]:Show()
for _, b in ipairs(b) do
b:Show()
end
end)
-- clear parent menuItem's onClick
b:SetScript("OnClick", function()
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
end)
else
if b.childrenSymbol then b.childrenSymbol:Hide() end
b:SetScript("OnEnter", function()
b:SetBackdropColor(unpack(b.hoverColor))
if menu[level+1] then menu[level+1]:Hide() end
end)
b:SetScript("OnClick", function()
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
menu:Hide()
if item.onClick then item.onClick(item.text) end
end)
end
end
-- update menu/submenu height
itemParent:SetHeight(2 + #items*18)
end
local function CreateItemButtons_Scroll(items, itemTable, limit)
menu:SetScript("OnHide", function(self) self:Hide() end)
for i, item in pairs(items) do
local b
if itemTable[i] and itemTable[i]:GetObjectType() == "Button" then
b = itemTable[i]
b:SetText(item.text)
else
b = addon:CreateButton(menu.scrollFrame.content, item.text, "transparent-accent", {98 ,18}, true)
tinsert(itemTable, b)
end
b:Show()
b:SetParent(menu.scrollFrame.content)
b:ClearAllPoints()
if i == 1 then
b:SetPoint("TOPLEFT", 1, -1)
b:SetPoint("RIGHT", -1, 0)
else
b:SetPoint("TOPLEFT", itemTable[i-1], "BOTTOMLEFT")
b:SetPoint("RIGHT", itemTable[i-1])
end
if item.textColor then
b:GetFontString():SetTextColor(unpack(item.textColor))
end
if item.icon then
if not b.icon then
b.iconBg = b:CreateTexture(nil, "BORDER")
P:Size(b.iconBg, 16, 16)
b.iconBg:SetPoint("TOPLEFT", P:Scale(5), P:Scale(-1))
b.iconBg:SetColorTexture(0, 0, 0, 1)
b.icon = b:CreateTexture(nil, "ARTWORK")
b.icon:SetPoint("TOPLEFT", b.iconBg, P:Scale(1), P:Scale(-1))
b.icon:SetPoint("BOTTOMRIGHT", b.iconBg, P:Scale(-1), P:Scale(1))
b.icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
end
b.icon:SetTexture(item.icon)
b.icon:Show()
b.iconBg:Show()
b:GetFontString():SetPoint("LEFT", b.iconBg, "RIGHT", P:Scale(2), 0)
else
if b.icon then
b.icon:Hide()
b.iconBg:Hide()
end
b:GetFontString():SetPoint("LEFT", P:Scale(5), 0)
end
-- if item.marker then
-- if not b.marker then
-- b.marker = b:CreateTexture(nil, "OVERLAY")
-- P:Size(b.marker, 16, 16)
-- b.marker:SetAllPoints(b.iconBg)
-- end
-- b.marker:SetTexture("Interface\\AddOns\\Cell\\Media\\Icons\\icon_marker.tga")
-- b.marker:SetVertexColor(1, 1, 1, 0.77)
-- b.marker:SetBlendMode("ADD")
-- b.marker:Show()
-- else
-- if b.marker then
-- b.marker:Hide()
-- end
-- end
if b.childrenSymbol then b.childrenSymbol:Hide() end
b:SetScript("OnEnter", function()
b:SetBackdropColor(unpack(b.hoverColor))
end)
b:SetScript("OnClick", function()
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
menu:Hide()
if item.onClick then item.onClick(item.text) end
end)
end
-- update height
local n = #items
menu.scrollFrame:SetContentHeight(P:Scale(2) + n * P:Scale(18))
if n == 0 then
menu:SetHeight(P:Scale(5))
elseif n <= limit then
menu:SetHeight(P:Scale(2) + n * P:Scale(18))
else
menu:SetHeight(P:Scale(2) + limit * P:Scale(18))
end
end
function menu:SetItems(items, limit)
-- clear topmenu
for _, b in pairs({menu:GetChildren()}) do
if b:GetObjectType() == "Button" then
b:Hide()
end
end
if not menu.scrollFrame then
addon:CreateScrollFrame(menu)
menu.scrollFrame:SetScrollStep(18)
end
menu.scrollFrame:Reset()
-- create buttons -- items, itemTable, itemParent, level
if limit then
menu.scrollFrame:Show()
CreateItemButtons_Scroll(items, menu.items, limit)
else
menu.scrollFrame:Hide()
CreateItemButtons(items, menu.items, menu, 0)
end
end
function menu:SetWidths(...)
local widths = {...}
P:Width(menu, widths[1])
if #widths == 1 then
for _, m in ipairs(menu) do
P:Width(m, widths[1])
end
else
for i, m in ipairs(menu) do
if widths[i+1] then P:Width(m, widths[i+1]) end
end
end
end
function menu:ShowMenu()
for i, m in ipairs(menu) do
m:Hide()
end
menu:Show()
end
function menu:SetMenuParent(parent)
menu:SetParent(parent)
menu:SetFrameStrata("TOOLTIP")
end
-----------------------------------------
-- scroll text frame
-----------------------------------------
function addon:CreateScrollTextFrame(parent, s, timePerScroll, scrollStep, delayTime, noFadeIn)
if not delayTime then delayTime = 3 end
if not timePerScroll then timePerScroll = 0.02 end
if not scrollStep then scrollStep = 1 end
local frame = CreateFrame("ScrollFrame", nil, parent)
-- frame:Hide() -- hide by default
frame:SetHeight(20)
local content = CreateFrame("Frame", nil, frame)
content:SetSize(20, 20)
frame:SetScrollChild(content)
local text = content:CreateFontString(nil, "OVERLAY", font_name)
text:SetWordWrap(false)
text:SetPoint("LEFT")
text:SetText(s)
-- alpha changing animation
local fadeIn = text:CreateAnimationGroup()
local alpha = fadeIn:CreateAnimation("Alpha")
alpha:SetFromAlpha(0)
alpha:SetToAlpha(1)
alpha:SetDuration(0.5)
local fadeOutIn = text:CreateAnimationGroup()
local alpha1 = fadeOutIn:CreateAnimation("Alpha")
alpha1:SetStartDelay(delayTime)
alpha1:SetFromAlpha(1)
alpha1:SetToAlpha(0)
alpha1:SetDuration(0.5)
alpha1:SetOrder(1)
local alpha2 = fadeOutIn:CreateAnimation("Alpha")
alpha2:SetFromAlpha(0)
alpha2:SetToAlpha(1)
alpha2:SetDuration(0.5)
alpha2:SetOrder(2)
alpha2:SetStartDelay(0.1)
local maxHScrollRange
local elapsedTime, delay, scroll = 0, 0, 0
local wait, nextRound
alpha1:SetScript("OnFinished", function()
frame:SetHorizontalScroll(0)
end)
fadeOutIn:SetScript("OnFinished", function()
delay = 0
scroll = 0
nextRound = false
wait = false
end)
-- init frame
frame:SetScript("OnShow", function()
-- init
if not noFadeIn then fadeIn:Play() end
frame:SetHorizontalScroll(0)
elapsedTime, delay, scroll = 0, 0, 0
-- NOTE: frame:GetWidth() is valid on next OnUpdate
frame:SetScript("OnUpdate", function()
if frame:GetWidth() ~= 0 then
frame:SetScript("OnUpdate", nil)
if text:GetStringWidth() <= frame:GetWidth() then -- NOTE: frame in a scrollFrame will cause frame:GetWidth() == 0
frame:SetScript("OnUpdate", nil)
else
maxHScrollRange = text:GetStringWidth() - frame:GetWidth()
frame:SetScript("OnUpdate", function(self, elapsed)
elapsedTime = elapsedTime + elapsed
delay = delay + elapsed
if elapsedTime >= timePerScroll then
if not wait and delay >= delayTime then
if nextRound then
wait = true
fadeOutIn:Play()
elseif scroll >= maxHScrollRange then -- prepare for next round
nextRound = true
else
frame:SetHorizontalScroll(scroll)
scroll = scroll + scrollStep
end
end
elapsedTime = 0
end
end)
end
end
end)
end)
function frame:SetText(str)
text:SetText(str)
if frame:IsVisible() then
frame:GetScript("OnShow")()
end
end
return frame
end
-----------------------------------------------------------------------------------
-- create scroll frame (with scrollbar & content frame)
-----------------------------------------------------------------------------------
function addon:CreateScrollFrame(parent, top, bottom, color, border)
-- create scrollFrame & scrollbar seperately (instead of UIPanelScrollFrameTemplate), in order to custom it
local scrollFrame = CreateFrame("ScrollFrame", parent:GetName() and parent:GetName().."ScrollFrame" or nil, parent, "BackdropTemplate")
parent.scrollFrame = scrollFrame
top = top or 0
bottom = bottom or 0
scrollFrame:SetPoint("TOPLEFT", 0, top)
scrollFrame:SetPoint("BOTTOMRIGHT", 0, bottom)
if color then
addon:StylizeFrame(scrollFrame, color, border)
end
function scrollFrame:Resize(newTop, newBottom)
top = newTop
bottom = newBottom
scrollFrame:SetPoint("TOPLEFT", 0, top)
scrollFrame:SetPoint("BOTTOMRIGHT", 0, bottom)
end
-- content
local content = CreateFrame("Frame", nil, scrollFrame, "BackdropTemplate")
content:SetSize(scrollFrame:GetWidth(), 2)
scrollFrame:SetScrollChild(content)
scrollFrame.content = content
-- content:SetFrameLevel(2)
-- scrollbar
local scrollbar = CreateFrame("Frame", nil, scrollFrame, "BackdropTemplate")
scrollbar:SetPoint("TOPLEFT", scrollFrame, "TOPRIGHT", 2, 0)
scrollbar:SetPoint("BOTTOMRIGHT", scrollFrame, 7, 0)
scrollbar:Hide()
addon:StylizeFrame(scrollbar, {0.1, 0.1, 0.1, 0.8})
scrollFrame.scrollbar = scrollbar
-- scrollbar thumb
local scrollThumb = CreateFrame("Frame", nil, scrollbar, "BackdropTemplate")
scrollThumb:SetWidth(5) -- scrollbar's width is 5
scrollThumb:SetHeight(scrollbar:GetHeight())
scrollThumb:SetPoint("TOP")
addon:StylizeFrame(scrollThumb, {accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.8})
scrollThumb:EnableMouse(true)
scrollThumb:SetMovable(true)
scrollThumb:SetHitRectInsets(-5, -5, 0, 0) -- Frame:SetHitRectInsets(left, right, top, bottom)
scrollFrame.scrollThumb = scrollThumb
-- reset content height manually ==> content:GetBoundsRect() make it right @OnUpdate
function scrollFrame:ResetHeight()
content:SetHeight(2)
end
-- reset to top, useful when used with DropDownMenu (variable content height)
function scrollFrame:ResetScroll()
scrollFrame:SetVerticalScroll(0)
scrollThumb:SetPoint("TOP")
end
-- FIXME: GetVerticalScrollRange goes wrong in 9.0.1
function scrollFrame:GetVerticalScrollRange()
local range = content:GetHeight() - scrollFrame:GetHeight()
return range > 0 and range or 0
end
-- local scrollRange -- ACCURATE scroll range, for SetVerticalScroll(), instead of scrollFrame:GetVerticalScrollRange()
function scrollFrame:VerticalScroll(step)
local scroll = scrollFrame:GetVerticalScroll() + step
-- if CANNOT SCROLL then scroll = -25/25, scrollFrame:GetVerticalScrollRange() = 0
-- then scrollFrame:SetVerticalScroll(0) and scrollFrame:SetVerticalScroll(scrollFrame:GetVerticalScrollRange()) ARE THE SAME
if scroll <= 0 then
scrollFrame:SetVerticalScroll(0)
elseif scroll >= scrollFrame:GetVerticalScrollRange() then
scrollFrame:SetVerticalScroll(scrollFrame:GetVerticalScrollRange())
else
scrollFrame:SetVerticalScroll(scroll)
end
end
-- NOTE: this func should not be called before Show, or GetVerticalScrollRange will be incorrect.
function scrollFrame:ScrollToBottom()
scrollFrame:SetVerticalScroll(scrollFrame:GetVerticalScrollRange())
end
function scrollFrame:SetContentHeight(height, num, spacing)
if num and spacing then
content:SetHeight(num*height+(num-1)*spacing)
else
content:SetHeight(height)
end
end
--[[ BUG: not reliable
-- to remove/hide widgets "widget:SetParent(nil)" MUST be called!!!
scrollFrame:SetScript("OnUpdate", function()
-- set content height, check if it CAN SCROLL
local x, y, w, h = content:GetBoundsRect()
-- NOTE: if content is not IN SCREEN -> x,y<0 -> h==-y!
if x > 0 and y > 0 then
content:SetHeight(h)
end
end)
]]
-- stores all widgets on content frame
-- local autoWidthWidgets = {}
function scrollFrame:ClearContent()
for _, c in pairs({content:GetChildren()}) do
c:SetParent(nil) -- or it will show (OnUpdate)
c:ClearAllPoints()
c:Hide()
end
-- wipe(autoWidthWidgets)
scrollFrame:ResetHeight()
end
function scrollFrame:Reset()
scrollFrame:ResetScroll()
scrollFrame:ClearContent()
end
-- function scrollFrame:SetWidgetAutoWidth(widget)
-- table.insert(autoWidthWidgets, widget)
-- end
-- on width changed, make the same change to widgets
scrollFrame:SetScript("OnSizeChanged", function()
-- change widgets width (marked as auto width)
-- for i = 1, #autoWidthWidgets do
-- autoWidthWidgets[i]:SetWidth(scrollFrame:GetWidth())
-- end
-- update content width
content:SetWidth(scrollFrame:GetWidth())
end)
-- check if it can scroll
content:SetScript("OnSizeChanged", function()
-- set ACCURATE scroll range
-- scrollRange = content:GetHeight() - scrollFrame:GetHeight()
-- set thumb height (%)
local p = scrollFrame:GetHeight() / content:GetHeight()
p = tonumber(string.format("%.3f", p))
if p < 1 then -- can scroll
scrollThumb:SetHeight(scrollbar:GetHeight()*p)
-- space for scrollbar
scrollFrame:SetPoint("BOTTOMRIGHT", parent, -7, bottom)
scrollbar:Show()
else
scrollFrame:SetPoint("BOTTOMRIGHT", parent, 0, bottom)
scrollbar:Hide()
if scrollFrame:GetVerticalScroll() > 0 then scrollFrame:SetVerticalScroll(0) end
end
end)
-- DO NOT USE OnScrollRangeChanged to check whether it can scroll.
-- "invisible" widgets should be hidden, then the scroll range is NOT accurate!
-- scrollFrame:SetScript("OnScrollRangeChanged", function(self, xOffset, yOffset) end)
-- dragging and scrolling
scrollThumb:SetScript("OnMouseDown", function(self, button)
if button ~= 'LeftButton' then return end
local offsetY = select(5, scrollThumb:GetPoint(1))
local mouseY = select(2, GetCursorPosition())
local uiScale = UIParent:GetEffectiveScale() -- https://wowpedia.fandom.com/wiki/API_GetCursorPosition
local currentScroll = scrollFrame:GetVerticalScroll()
self:SetScript("OnUpdate", function(self)
--------------------- y offset before dragging + mouse offset
local newOffsetY = offsetY + (select(2, GetCursorPosition()) - mouseY) / uiScale
-- even scrollThumb:SetPoint is already done in OnVerticalScroll, but it's useful in some cases.
if newOffsetY >= 0 then -- @top
scrollThumb:SetPoint("TOP")
newOffsetY = 0
elseif (-newOffsetY) + scrollThumb:GetHeight() >= scrollbar:GetHeight() then -- @bottom
scrollThumb:SetPoint("TOP", 0, -(scrollbar:GetHeight() - scrollThumb:GetHeight()))
newOffsetY = -(scrollbar:GetHeight() - scrollThumb:GetHeight())
else
scrollThumb:SetPoint("TOP", 0, newOffsetY)
end
local vs = (-newOffsetY / (scrollbar:GetHeight()-scrollThumb:GetHeight())) * scrollFrame:GetVerticalScrollRange()
scrollFrame:SetVerticalScroll(vs)
end)
end)
scrollThumb:SetScript("OnMouseUp", function(self)
self:SetScript("OnUpdate", nil)
end)
scrollFrame:SetScript("OnVerticalScroll", function(self, offset)
if scrollFrame:GetVerticalScrollRange() ~= 0 then
local scrollP = scrollFrame:GetVerticalScroll()/scrollFrame:GetVerticalScrollRange()
local yoffset = -((scrollbar:GetHeight()-scrollThumb:GetHeight())*scrollP)
scrollThumb:SetPoint("TOP", 0, yoffset)
end
end)
function scrollFrame:UpdateSize()
content:GetScript("OnSizeChanged")(content)
scrollFrame:GetScript("OnVerticalScroll")(scrollFrame)
scrollFrame:VerticalScroll(0)
end
local step = 25
function scrollFrame:SetScrollStep(s)
step = s
end
-- enable mouse wheel scroll
scrollFrame:EnableMouseWheel(true)
scrollFrame:SetScript("OnMouseWheel", function(self, delta)
if delta == 1 then -- scroll up
scrollFrame:VerticalScroll(-step)
elseif delta == -1 then -- scroll down
scrollFrame:VerticalScroll(step)
end
end)
return scrollFrame
end
------------------------------------------------
-- dropdown menu
------------------------------------------------
local listInit, list, highlightTexture
list = CreateFrame("Frame", addonName.."DropdownList", UIParent, "BackdropTemplate")
list:SetIgnoreParentScale(true)
list:SetClampedToScreen(true)
-- addon:StylizeFrame(list, {0.115, 0.115, 0.115, 1})
list:Hide()
-- store created buttons
list.items = {}
-- highlight
highlightTexture = CreateFrame("Frame", nil, list, "BackdropTemplate")
-- highlightTexture:SetBackdrop({edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
-- highlightTexture:SetBackdropBorderColor(unpack(accentColor.t))
highlightTexture:Hide()
list:SetScript("OnShow", function()
list:SetScale(list.menu:GetEffectiveScale())
list:SetFrameStrata(list.menu:GetFrameStrata())
list:SetFrameLevel(list.menu:GetFrameLevel() + 20) -- top
end)
list:SetScript("OnHide", function() list:Hide() end)
-- close dropdown
function addon:RegisterForCloseDropdown(f)
if f:GetObjectType() == "Button" or f:GetObjectType() == "CheckButton" then
f:HookScript("OnClick", function()
list:Hide()
end)
elseif f:GetObjectType() == "Slider" then
f:HookScript("OnValueChanged", function()
list:Hide()
end)
end
end
local function SetHighlightItem(i)
if not i then
highlightTexture:ClearAllPoints()
highlightTexture:Hide()
else
highlightTexture:SetParent(list.items[i]) -- buttons show/hide automatically when scroll, so let highlightTexture to be the same
highlightTexture:ClearAllPoints()
highlightTexture:SetAllPoints(list.items[i])
highlightTexture:Show()
end
end
function addon:CreateDropdown(parent, width, dropdownType, isMini, isHorizontal)
local menu = CreateFrame("Frame", nil, parent, "BackdropTemplate")
P:Size(menu, width, 20)
menu:EnableMouse(true)
-- menu:SetFrameLevel(5)
addon:StylizeFrame(menu, {0.115, 0.115, 0.115, 1})
-- label
function menu:SetLabel(label)
menu.label = menu:CreateFontString(nil, "OVERLAY", font_name)
menu.label:SetPoint("BOTTOMLEFT", menu, "TOPLEFT", 0, P:Scale(1))
menu.label:SetText(label)
hooksecurefunc(menu, "SetEnabled", function(self, enabled)
if enabled then
menu.label:SetTextColor(1, 1, 1)
else
menu.label:SetTextColor(0.4, 0.4, 0.4)
end
end)
end
-- button: open/close menu list
if isMini then
menu.button = addon:CreateButton(menu, "", "transparent-accent", {18 ,18})
menu.button:SetAllPoints(menu)
menu.button:SetFrameLevel(menu:GetFrameLevel()+1)
-- selected item
menu.text = menu.button:CreateFontString(nil, "OVERLAY", font_name)
menu.text:SetPoint("LEFT", P:Scale(1), 0)
menu.text:SetPoint("RIGHT", P:Scale(-1), 0)
menu.text:SetJustifyH("CENTER")
else
menu.button = addon:CreateButton(menu, "", "transparent-accent", {18 ,20})
addon:StylizeFrame(menu.button, {0.115, 0.115, 0.115, 1})
menu.button:SetPoint("TOPRIGHT")
menu.button:SetFrameLevel(menu:GetFrameLevel()+1)
menu.button:SetNormalTexture([[Interface\AddOns\Cell\Media\Icons\dropdown-normal]])
menu.button:SetPushedTexture([[Interface\AddOns\Cell\Media\Icons\dropdown-pushed]])
local disabledTexture = menu.button:CreateTexture(nil, "OVERLAY")
disabledTexture:SetTexture([[Interface\AddOns\Cell\Media\Icons\dropdown-normal]])
disabledTexture:SetVertexColor(0.4, 0.4, 0.4, 1)
menu.button:SetDisabledTexture(disabledTexture)
-- selected item
menu.text = menu:CreateFontString(nil, "OVERLAY", font_name)
menu.text:SetPoint("TOPLEFT", P:Scale(5), P:Scale(-1))
menu.text:SetPoint("BOTTOMRIGHT", P:Scale(-18), P:Scale(1))
menu.text:SetJustifyH("LEFT")
end
-- selected item
menu.text:SetJustifyV("MIDDLE")
menu.text:SetWordWrap(false)
if dropdownType == "texture" then
menu.texture = menu:CreateTexture(nil, "ARTWORK")
menu.texture:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
menu.texture:SetPoint("BOTTOMRIGHT", P:Scale(-18), P:Scale(1))
menu.texture:SetVertexColor(1, 1, 1, 0.7)
end
-- keep all menu item buttons
menu.items = {}
-- index in items
-- menu.selected
function menu:SetSelected(text, value)
local valid
for i, item in pairs(menu.items) do
if item.text == text then
valid = true
-- store index for list
menu.selected = i
menu.text:SetText(text)
if dropdownType == "texture" then
menu.texture:SetTexture(value)
elseif dropdownType == "font" then
menu.text:SetFont(value, 13+fontSizeOffset, "")
end
break
end
end
if not valid then
menu.selected = nil
menu.text:SetText("")
SetHighlightItem()
end
end
function menu:ClearSelected()
menu.selected = nil
menu.text:SetText("")
SetHighlightItem()
end
function menu:SetSelectedValue(value)
for i, item in pairs(menu.items) do
if item.value == value then
menu.selected = i
menu.text:SetText(item.text)
break
end
end
end
function menu:GetSelected()
if menu.selected then
return menu.items[menu.selected].value or menu.items[menu.selected].text
end
return nil
end
function menu:SetSelectedItem(itemNum)
local item = menu.items[itemNum]
menu.text:SetText(item.text)
menu.selected = itemNum
end
-- items = {
-- {
-- ["text"] = (string),
-- ["value"] = (obj),
-- ["texture"] = (string),
-- ["onClick"] = (function)
-- },
-- }
function menu:SetItems(items)
menu.items = items
menu.reloadRequired = true
end
function menu:AddItem(item)
tinsert(menu.items, item)
menu.reloadRequired = true
end
function menu:RemoveCurrentItem()
tremove(menu.items, menu.selected)
menu.reloadRequired = true
end
function menu:ClearItems()
wipe(menu.items)
menu.selected = nil
menu.text:SetText("")
SetHighlightItem()
end
function menu:SetCurrentItem(item)
menu.items[menu.selected] = item
-- usually, update current item means to change its name (text) and func
menu.text:SetText(item["text"])
menu.reloadRequired = true
end
local function LoadItems()
if not listInit then
listInit = true
addon:CreateScrollFrame(list)
list.scrollFrame:SetScrollStep(18)
addon:StylizeFrame(list, {0.115, 0.115, 0.115, 1})
highlightTexture:SetBackdrop({edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
highlightTexture:SetBackdropBorderColor(unpack(accentColor.t))
end
-- hide highlight
SetHighlightItem()
-- hide all list items
list.scrollFrame:Reset()
-- load current dropdown
for i, item in pairs(menu.items) do
local b
if not list.items[i] then
-- init
b = addon:CreateButton(list.scrollFrame.content, item.text, "transparent-accent", {18 ,18}, true) --! width is not important
table.insert(list.items, b)
-- texture
b.texture = b:CreateTexture(nil, "ARTWORK")
b.texture:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
b.texture:SetPoint("BOTTOMRIGHT", P:Scale(-1), P:Scale(1))
b.texture:SetVertexColor(1, 1, 1, 0.7)
b.texture:Hide()
else
b = list.items[i]
b:SetText(item.text)
end
local fs = b:GetFontString()
if isMini then
fs:ClearAllPoints()
fs:SetJustifyH("CENTER")
fs:SetPoint("LEFT", 1, 0)
fs:SetPoint("RIGHT", -1, 0)
else
fs:ClearAllPoints()
fs:SetJustifyH("LEFT")
fs:SetPoint("LEFT", 5, 0)
fs:SetPoint("RIGHT", -5, 0)
end
b:SetEnabled(not item.disabled)
-- texture
if item.texture then
b.texture:SetTexture(item.texture)
b.texture:Show()
else
b.texture:Hide()
end
-- font
local f, s = font:GetFont()
if item.font then
b:GetFontString():SetFont(item.font, s, "")
else
b:GetFontString():SetFont(f, s, "")
end
-- highlight
if menu.selected == i then
SetHighlightItem(i)
end
b:SetScript("OnClick", function()
PlaySound(SOUNDKIT.U_CHAT_SCROLL_BUTTON)
if dropdownType == "texture" then
menu:SetSelected(item.text, item.texture)
elseif dropdownType == "font" then
menu:SetSelected(item.text, item.font)
else
menu:SetSelected(item.text)
end
list:Hide()
if item.onClick then item.onClick(item.text, item.value, menu.id) end
end)
-- update point
b:SetParent(list.scrollFrame.content)
b:Show()
if isMini and isHorizontal then
P:Width(b, width)
if i == 1 then
b:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
else
b:SetPoint("TOPLEFT", list.items[i-1], "TOPRIGHT")
end
else
if i == 1 then
b:SetPoint("TOPLEFT", P:Scale(1), P:Scale(-1))
b:SetPoint("TOPRIGHT", P:Scale(-1), P:Scale(-1))
else
b:SetPoint("TOPLEFT", list.items[i-1], "BOTTOMLEFT")
b:SetPoint("TOPRIGHT", list.items[i-1], "BOTTOMRIGHT")
end
end
end
-- update list size
list.menu = menu -- menu's OnHide -> list:Hide
list:ClearAllPoints()
if isMini and isHorizontal then
list:SetPoint("TOPLEFT", menu, "TOPRIGHT", 2, 0)
if #menu.items == 0 then
list:SetSize(P:Scale(5), menu:GetHeight())
else
list:SetSize(P:Scale(2) + #menu.items*P:Scale(width), menu:GetHeight())
end
list.scrollFrame:SetContentHeight(P:Scale(20))
else
list:SetPoint("TOPLEFT", menu, "BOTTOMLEFT", 0, -2)
if #menu.items == 0 then
list:SetSize(menu:GetWidth(), P:Scale(5))
elseif #menu.items <= 15 then
list:SetSize(menu:GetWidth(), P:Scale(2) + #menu.items*P:Scale(18))
list.scrollFrame:SetContentHeight(P:Scale(2) + #menu.items*P:Scale(18))
else
list:SetSize(menu:GetWidth(), P:Scale(2) + 11*P:Scale(18))
-- update list scrollFrame
list.scrollFrame:SetContentHeight(P:Scale(2) + #menu.items*P:Scale(18))
end
end
end
function menu:SetEnabled(f)
menu.button:SetEnabled(f)
if f then
menu.text:SetTextColor(1, 1, 1)
else
menu.text:SetTextColor(0.4, 0.4, 0.4)
if list.menu == menu then
list:Hide()
end
end
end
menu:SetScript("OnHide", function()
if list.menu == menu then
list:Hide()
end
end)
-- scripts
menu.button:HookScript("OnClick", function()
if list.menu ~= menu then -- list shown by other dropdown
LoadItems()
list:Show()
elseif list:IsShown() then -- list showing by this, hide it
list:Hide()
else
if menu.reloadRequired then
LoadItems()
menu.reloadRequired = false
else
-- update highlight
if menu.selected then
SetHighlightItem(menu.selected)
end
end
list:Show()
end
end)
return menu
end
-----------------------------------------
-- binding button
-----------------------------------------
local function GetModifier()
local modifier = "" -- "shift-", "ctrl-", "alt-", "ctrl-shift-", "alt-shift-", "alt-ctrl-", "alt-ctrl-shift-"
local alt = IsAltKeyDown()
local ctrl = IsControlKeyDown()
local shift = IsShiftKeyDown()
local meta = IsMetaKeyDown()
if alt then modifier = "alt-" end
if ctrl then modifier = modifier .. "ctrl-" end
if shift then modifier = modifier .. "shift-" end
if meta then modifier = modifier .. "meta-" end
return modifier
end
function addon:CreateBindingButton(parent, width)
if not parent.bindingButton then
parent.bindingButton = addon:CreateFrame("CellClickCastings_BindingButton", parent, 50, 20)
parent.bindingButton:SetFrameStrata("TOOLTIP")
parent.bindingButton:Hide()
tinsert(UISpecialFrames, parent.bindingButton:GetName())
addon:StylizeFrame(parent.bindingButton, {0.1, 0.1, 0.1, 1}, {accentColor.t[1], accentColor.t[2], accentColor.t[3]})
parent.bindingButton.close = addon:CreateButton(parent.bindingButton, "×", "red", {18, 18}, true, true, "CELL_FONT_SPECIAL", "CELL_FONT_SPECIAL")
parent.bindingButton.close:SetPoint("TOPRIGHT", -1, -1)
parent.bindingButton.close:SetScript("OnClick", function()
parent.bindingButton:Hide()
end)
parent.bindingButton.text = parent.bindingButton:CreateFontString(nil, "OVERLAY", font_name)
parent.bindingButton.text:SetPoint("LEFT")
-- parent.bindingButton.text:SetPoint("RIGHT", parent.bindingButton.close, "LEFT")
parent.bindingButton.text:SetText(L["Press Key to Bind"])
parent.bindingButton:SetScript("OnHide", function()
parent.bindingButton:Hide()
end)
parent.bindingButton:EnableMouse(true)
parent.bindingButton:EnableMouseWheel(true)
parent.bindingButton:EnableKeyboard(true)
-- mouse
parent.bindingButton:SetScript("OnMouseDown", function(self, key)
parent.bindingButton:Hide()
if key == "LeftButton" then
key = "Left"
elseif key == "RightButton" then
key = "Right"
elseif key == "MiddleButton" then
key = "Middle"
end
if parent.bindingButton.func then parent.bindingButton.func(GetModifier(), key) end
end)
-- mouse wheel
parent.bindingButton:SetScript("OnMouseWheel", function(self, key)
parent.bindingButton:Hide()
if parent.bindingButton.func then parent.bindingButton.func(GetModifier(), (key==1) and "ScrollUp" or "ScrollDown") end
end)
-- keyboard
parent.bindingButton:SetScript("OnKeyDown", function(self, key)
if key == "ESCAPE"
or key == "LALT" or key == "RALT"
or key == "LCTRL" or key == "RCTRL"
or key == "LSHIFT" or key == "RSHIFT"
or key == "LMETA" or key == "RMETA" then return end
parent.bindingButton:Hide()
if parent.bindingButton.func then parent.bindingButton.func(GetModifier(), key) end
end)
function parent.bindingButton:SetFunc(func)
parent.bindingButton.func = func
end
end
parent.bindingButton:ClearAllPoints()
P:Width(parent.bindingButton, width)
return parent.bindingButton
end
-----------------------------------------
-- binding list button
-----------------------------------------
local function CreateGrid(parent, text, width)
local grid = CreateFrame("Button", nil, parent, "BackdropTemplate")
grid:SetFrameLevel(6)
grid:SetSize(width, P:Scale(20))
grid:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
grid:SetBackdropColor(0, 0, 0, 0)
grid:SetBackdropBorderColor(0, 0, 0, 1)
-- to avoid SetText("") -> GetFontString() == nil
grid.text = grid:CreateFontString(nil, "OVERLAY", font_name)
grid.text:SetWordWrap(false)
grid.text:SetJustifyH("LEFT")
grid.text:SetPoint("LEFT", P:Scale(5), 0)
grid.text:SetPoint("RIGHT", P:Scale(-5), 0)
grid.text:SetText(text)
function grid:SetText(s)
grid.text:SetText(s)
end
function grid:GetText()
return grid.text:GetText()
end
function grid:IsTruncated()
return grid.text:IsTruncated()
end
grid:RegisterForClicks("LeftButtonUp", "RightButtonUp")
grid:SetScript("OnEnter", function()
grid:SetBackdropColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.15)
parent:Highlight()
end)
grid:SetScript("OnLeave", function()
grid:SetBackdropColor(0, 0, 0, 0)
parent:Unhighlight()
end)
grid:RegisterForDrag("LeftButton")
grid:SetScript("OnDragStart", function(self)
if parent.unmovable then return end
parent:Unhighlight()
parent:SetFrameStrata("TOOLTIP")
parent:StartMoving()
parent:SetUserPlaced(false)
end)
grid:SetScript("OnDragStop", function(self)
if parent.unmovable then return end
parent:StopMovingOrSizing()
parent:SetFrameStrata("LOW")
-- self:Hide() --! Hide() will cause OnDragStop trigger TWICE!!!
C_Timer.After(0.05, function()
local b = F:GetMouseFocus()
if b then b = b:GetParent() end
F:MoveClickCastings(parent.clickCastingIndex, b and b.clickCastingIndex)
end)
end)
return grid
end
function addon:CreateBindingListButton(parent, modifier, bindKey, bindType, bindAction)
local b = CreateFrame("Button", nil, parent, "BackdropTemplate")
b:SetFrameLevel(5)
P:Size(b, 100, 20)
b:SetBackdrop({bgFile = Cell.vars.whiteTexture, edgeFile = Cell.vars.whiteTexture, edgeSize = P:Scale(1)})
b:SetBackdropColor(0.115, 0.115, 0.115, 1)
b:SetBackdropBorderColor(0, 0, 0, 1)
b:SetMovable(true)
function b:Highlight()
b:SetBackdropColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 0.1)
end
function b:Unhighlight()
b:SetBackdropColor(0.115, 0.115, 0.115, 1)
end
local keyGrid = CreateGrid(b, modifier..bindKey, 130)
b.keyGrid = keyGrid
keyGrid:SetPoint("BOTTOMLEFT")
local typeGrid = CreateGrid(b, bindType, 70)
b.typeGrid = typeGrid
typeGrid:SetPoint("BOTTOMLEFT", keyGrid, "BOTTOMRIGHT", P:Scale(-1), 0)
local actionGrid = CreateGrid(b, bindAction, 100)
b.actionGrid = actionGrid
actionGrid:SetPoint("BOTTOMLEFT", typeGrid, "BOTTOMRIGHT", P:Scale(-1), 0)
actionGrid:SetPoint("BOTTOMRIGHT")
actionGrid:HookScript("OnEnter", function()
if actionGrid:IsTruncated() then
CellTooltip:SetOwner(actionGrid, "ANCHOR_TOPLEFT", 0, P:Scale(1))
CellTooltip:AddLine(L["Action"])
CellTooltip:AddLine("|cffffffff" .. actionGrid:GetText())
CellTooltip:Show()
end
end)
actionGrid:HookScript("OnLeave", function()
CellTooltip:Hide()
end)
-- spell icon
local spellIconBg = actionGrid:CreateTexture(nil, "BORDER")
P:Size(spellIconBg, 16, 16)
spellIconBg:SetPoint("TOPLEFT", P:Scale(2), P:Scale(-2))
spellIconBg:SetColorTexture(0, 0, 0, 1)
spellIconBg:Hide()
local spellIcon = actionGrid:CreateTexture(nil, "OVERLAY")
spellIcon:SetPoint("TOPLEFT", spellIconBg, P:Scale(1), P:Scale(-1))
spellIcon:SetPoint("BOTTOMRIGHT", spellIconBg, P:Scale(-1), P:Scale(1))
spellIcon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
spellIcon:Hide()
function b:ShowIcon(texture)
spellIcon:SetTexture(texture or 134400)
spellIconBg:Show()
spellIcon:Show()
-- actionGrid.text:ClearAllPoints()
actionGrid.text:SetPoint("LEFT", spellIconBg, "RIGHT", P:Scale(2), 0)
-- actionGrid.text:SetPoint("RIGHT", P:Scale(-5), 0)
end
function b:ShowSpellIcon(spell)
local icon = nil
if spell then
icon = select(2, F:GetSpellInfo(spell))
end
b:ShowIcon(icon)
end
function b:ShowItemIcon(itemslot)
b:ShowIcon(GetInventoryItemTexture("player", itemslot))
end
function b:ShowMacroIcon(macro)
b:ShowIcon(select(2, GetMacroInfo(GetMacroIndexByName(macro))))
end
function b:HideIcon()
spellIconBg:Hide()
spellIcon:Hide()
-- actionGrid.text:ClearAllPoints()
actionGrid.text:SetPoint("LEFT", P:Scale(5), 0)
-- actionGrid.text:SetPoint("RIGHT", P:Scale(-5), 0)
end
function b:SetBorderColor(...)
keyGrid:SetBackdropBorderColor(...)
typeGrid:SetBackdropBorderColor(...)
actionGrid:SetBackdropBorderColor(...)
end
function b:SetChanged(isChanged)
if isChanged then
b:SetBorderColor(accentColor.t[1], accentColor.t[2], accentColor.t[3], 1)
else
b:SetBorderColor(0, 0, 0, 1)
end
end
return b
end
-----------------------------------------
-- receiving frame
-----------------------------------------
function addon:CreateReceivingFrame(parent)
local f = CreateFrame("Frame", "CellReceivingFrame", parent, "BackdropTemplate")
f:EnableMouse(true)
f:SetMovable(true)
f:SetUserPlaced(true)
f:RegisterForDrag("LeftButton")
f:SetFrameStrata("DIALOG")
f:SetFrameLevel(277)
f:SetClampedToScreen(true)
P:Size(f, 249, 135)
f:SetPoint("TOPRIGHT", UIParent, "CENTER")
addon:StylizeFrame(f)
f:SetScript("OnDragStart", function() f:StartMoving() end)
f:SetScript("OnDragStop", function() f:StopMovingOrSizing() end)
-- labels
local typeLabel = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_CLASS")
typeLabel:SetPoint("TOPLEFT", 10, -10)
typeLabel:SetText(L["Type: "])
local nameLabel = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_CLASS")
nameLabel:SetPoint("LEFT", 10, 0)
nameLabel:SetText(L["Name: "])
local fromLabel = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_CLASS")
fromLabel:SetPoint("LEFT", 10, 0)
fromLabel:SetText(L["From: "])
local dataLabel = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_CLASS")
dataLabel:SetPoint("LEFT", 10, 0)
dataLabel:Hide()
-- texts
local typeText = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_WIDGET")
typeText:SetPoint("TOPLEFT", typeLabel, "TOPRIGHT")
typeText:SetPoint("RIGHT", -10, 0)
typeText:SetJustifyH("LEFT")
nameLabel:SetPoint("TOP", typeText, "BOTTOM", 0, -10)
local nameText = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_WIDGET")
nameText:SetPoint("TOPLEFT", nameLabel, "TOPRIGHT")
nameText:SetPoint("RIGHT", -10, 0)
nameText:SetJustifyH("LEFT")
nameText:SetWordWrap(true)
fromLabel:SetPoint("TOP", nameText, "BOTTOM", 0, -10)
local fromText = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_WIDGET")
fromText:SetPoint("TOPLEFT", fromLabel, "TOPRIGHT")
fromText:SetPoint("RIGHT", -10, 0)
fromText:SetJustifyH("LEFT")
fromText:SetWordWrap(true)
dataLabel:SetPoint("TOP", fromText, "BOTTOM", 0, -10)
local dataText = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_WIDGET")
dataText:SetPoint("TOPLEFT", dataLabel, "TOPRIGHT")
dataText:SetPoint("RIGHT", -10, 0)
dataText:SetJustifyH("LEFT")
dataText:SetWordWrap(true)
dataText:Hide()
-- error
local infoMsg = f:CreateFontString(nil, "OVERLAY", "CELL_FONT_WIDGET")
infoMsg:SetJustifyH("LEFT")
infoMsg:SetTextColor(unpack(colors.firebrick.t))
infoMsg:SetWordWrap(true)
infoMsg:Hide()
function infoMsg:SetMsg(msg, anchorTo)
infoMsg:SetText(msg)
infoMsg:ClearAllPoints()
infoMsg:SetPoint("LEFT", 10, 0)
infoMsg:SetPoint("RIGHT", -10, 0)
infoMsg:SetPoint("TOP", anchorTo, "BOTTOM", 0, -10)
end
-- buttons
local requestBtn = addon:CreateButton(f, L["Request"], "green", {125, 20})
requestBtn:SetPoint("BOTTOMLEFT")
local importBtn = addon:CreateButton(f, L["Import"], "green", {125, 20})
importBtn:SetPoint("BOTTOMLEFT")
local cancelBtn = addon:CreateButton(f, L["Cancel"], "red", {125, 20})
cancelBtn:SetPoint("BOTTOMLEFT", importBtn, "BOTTOMRIGHT", -1, 0)
cancelBtn:SetPoint("BOTTOMRIGHT")
-- bar
local progressBar = addon:CreateStatusBar("CellReceivingFrameBar", f, 198, 18, 0, true, nil, true, "Interface\\AddOns\\Cell\\Media\\statusbar.tga", {0.7, 0.7, 0, 1})
progressBar:SetPoint("BOTTOMLEFT", 1, 1)
progressBar:SetPoint("BOTTOMRIGHT", cancelBtn, "BOTTOMLEFT")
progressBar:Hide()
function f:ShowFrame(type, playerName, name1, name2)
P:Size(f, 249, 20) -- reset size
typeLabel:Hide()
nameLabel:Hide()
fromLabel:Hide()
typeText:Hide()
nameText:Hide()
fromText:Hide()
typeText:SetText(L[type])
if name2 then
nameText:SetText(name2.." ("..name1..")")
else
nameText:SetText(name1)
end
fromText:SetText(playerName)
local lines = typeText:GetNumLines() + nameText:GetNumLines() + fromText:GetNumLines()
addon:ChangeSizeWithAnimation(f, 249, 40 + lines*math.ceil(typeLabel:GetStringHeight()*1.4), 7, nil, function()
typeLabel:Show()
nameLabel:Show()
fromLabel:Show()
typeText:Show()
nameText:Show()
fromText:Show()
end)
-- NOTE: you cannot send to yourself
requestBtn:SetEnabled(playerName ~= Cell.vars.playerNameFull)
importBtn:Hide()
dataLabel:Hide()
dataText:Hide()
infoMsg:Hide()
requestBtn:Show()
f:Show()
end
local timeout
function f:SetOnRequest(func)
requestBtn:SetScript("OnClick", function(self)
requestBtn:Hide()
progressBar:SetValue(0)
progressBar:Show()
addon:ChangeSizeWithAnimation(importBtn, 200, 20, 7)
func(self)
infoMsg:Hide()
-- NOTE: timeout in 10 sec if can't receive any data
timeout = C_Timer.NewTimer(10, function()
if f:IsShown() and progressBar:GetValue() == 0 then
infoMsg:SetMsg(L["To transfer across realm, you need to be in the same group"], fromText)
addon:ChangeSizeWithAnimation(f, 249, f.height+15+math.ceil(infoMsg:GetStringHeight()), 7, nil, function()
infoMsg:Show()
end)
end
end)
end)
end
function f:SetOnCancel(func)
cancelBtn:SetScript("OnClick", function(self)
f:Hide()
progressBar:Hide()
importBtn:SetWidth(125)
func(self)
end)
end
function f:ShowProgress(done, total)
progressBar:SetMaxValue(total)
progressBar:SetSmoothedValue(done)
end
function f:ShowImport(status, received, func)
if timeout then
timeout:Cancel()
timeout = nil
end
addon:ChangeSizeWithAnimation(importBtn, 125, 20, 7)
progressBar:Hide()
importBtn:Show()
importBtn:SetEnabled(false)
if status then
if received["type"] == "Debuffs" then
local isCompatible = type(received["version"]) == "number" and received["version"] >= Cell.MIN_DEBUFFS_VERSION
F:Debug("|cffFFDAB9RECEIVED DEBUFFS:|r ", received["instanceId"], received["bossId"], received["data"])
local builtIn, custom = F:CalcRaidDebuffs(received["instanceId"], received["bossId"], received["data"])
dataLabel:SetText(L["Debuffs"] .. ": ")
dataText:SetText("|cff90EE90"..builtIn.." "..L["built-in(s)"].."|r, |cffFFB5C5"..custom.." "..L["custom(s)"].."|r")
importBtn:SetScript("OnClick", function()
F:UpdateRaidDebuffs(received["instanceId"], received["bossId"], received["data"], nameText:GetText())
F:ShowInstanceDebuffs(received["instanceId"], received["bossId"])
f:Hide()
end)
C_Timer.After(0.5, function()
if isCompatible then
infoMsg:SetMsg(L["This will overwrite your debuffs"], dataText)
else
infoMsg:SetMsg(L["Incompatible Version"], dataText)
end
addon:ChangeSizeWithAnimation(f, 249, f.height+15+math.ceil(dataText:GetStringHeight()+infoMsg:GetStringHeight()), 7, nil, function()
dataLabel:Show()
dataText:Show()
infoMsg:Show()
importBtn:SetEnabled(isCompatible)
if func then func() end
end)
end)
elseif received["type"] == "Layout" then
local isCompatible = type(received["version"]) == "number" and received["version"] >= Cell.MIN_LAYOUTS_VERSION
F:Debug("|cffFFDAB9RECEIVED LAYOUT:|r ", received["name"], received["data"])
importBtn:SetScript("OnClick", function()
-- check layout name
local layoutName = received["name"]
if CellDB["layouts"][layoutName] then
local i = 1
while true do
if not CellDB["layouts"][layoutName.." "..i] then
layoutName = layoutName.." "..i
break
end
i = i + 1
end
end
-- save
CellDB["layouts"][layoutName] = received["data"]
F:ShowLayout(layoutName)
f:Hide()
end)
C_Timer.After(0.5, function()
if isCompatible then
infoMsg:SetMsg(L["It will be renamed if this layout name already exists"], fromText)
else
infoMsg:SetMsg(L["Incompatible Version"], fromText)
end
addon:ChangeSizeWithAnimation(f, 249, f.height+15+math.ceil(infoMsg:GetStringHeight()), 7, nil, function()
dataLabel:Show()
dataText:Show()
infoMsg:Show()
importBtn:SetEnabled(isCompatible)
if func then func() end
end)
end)
end
else
infoMsg:SetMsg(L["Data transfer failed..."], fromText)
addon:ChangeSizeWithAnimation(f, 249, f.height+15+math.ceil(infoMsg:GetStringHeight()), 7, nil, function()
infoMsg:Show()
if func then func() end
end)
end
end
return f
end