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