You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

309 lines
8.8 KiB

-- NotifyFrame.lua
-- @Author : DengSir (tdaddon@163.com)
-- @Link : https://dengsir.github.io
-- @Date : 9/22/2018, 11:26:58 AM
local MAJOR, MINOR = 'NotifyFrame', 3
local GUI = LibStub('tdGUI-1.0')
local NotifyFrame, oldminor, ns = GUI:NewClass(MAJOR, MINOR, 'Button', 'Backdrop')
if not NotifyFrame then return end
NotifyFrame.opts = {}
local DEFAULT_ICON = [[Interface\Icons\INV_Misc_QuestionMark]]
local BACKGROP = {
bgFile = [[Interface\BUTTONS\WHITE8X8]],
edgeFile = [[Interface\BUTTONS\WHITE8X8]],
tile = true,
tileSize = 1,
edgeSize = 1,
insets = {left = 1, right = 1, top = 1, bottom = 1}
}
function NotifyFrame:Constructor()
self:Hide()
self:SetSize(350, 50)
self:SetFrameStrata('DIALOG')
self:RegisterForClicks('LeftButtonUp', 'RightButtonUp')
self:SetBackdrop(BACKGROP)
self:SetBackdropBorderColor(0, 0, 0, 1)
self:SetBackdropColor(0, 0, 0, 0.6)
self:SetScript('OnClick', self.OnClick)
self:SetScript('OnHide', self.OnHide)
local Close = CreateFrame('Button', nil, self, GUI.BackdropTemplate) do
Close:SetBackdrop(BACKGROP)
Close:SetBackdropBorderColor(0, 0, 0, 1)
Close:SetBackdropColor(0, 0, 0, 0.4)
Close:SetPoint('TOPRIGHT', 0, 0)
Close:SetSize(16, 16)
Close:SetScript('OnClick', function()
self:OnClick('RightButton')
end)
local padding = 4
local Line1 = Close:CreateLine(nil, 'ARTWORK') do
Line1:SetThickness(1)
Line1:SetStartPoint('TOPLEFT', padding, -padding)
Line1:SetEndPoint('BOTTOMRIGHT', -padding, padding)
Line1:SetColorTexture(0.5, 0.5, 0.5)
end
local Line2 = Close:CreateLine(nil, 'ARTWORK') do
Line2:SetThickness(1)
Line2:SetStartPoint('TOPRIGHT', -padding, -padding)
Line2:SetEndPoint('BOTTOMLEFT', padding, padding)
Line2:SetColorTexture(0.5, 0.5, 0.5)
end
end
local Icon = self:CreateTexture(nil, 'ARTWORK') do
Icon:SetPoint('LEFT', 4, 0)
Icon:SetSize(42, 42)
Icon:SetTexCoord(0.07, 0.93, 0.07, 0.93)
end
local Text = self:CreateFontString(nil, 'ARTWORK', 'GameFontHighlightLeft') do
Text:SetPoint('TOPRIGHT', -25, -5)
Text:SetPoint('LEFT', Icon, 'RIGHT', 5, 0)
end
local HelpText = self:CreateFontString(nil, 'ARTWORK', 'GameFontNormalLeft') do
HelpText:SetWordWrap(false)
HelpText:SetPoint('BOTTOM', 0, 4)
HelpText:SetPoint('LEFT', Icon, 'RIGHT', 5, 0)
HelpText:SetFont(HelpText:GetFont(), 11)
HelpText:SetTextColor(0.8, 0.8, 0.3)
end
local Anim = self:CreateAnimationGroup() do
Anim:SetToFinalAlpha(true)
Anim:SetScript('OnFinished', function()
if self:GetAlpha() == 0 then
self:Hide()
end
end)
end
local Alpha = Anim:CreateAnimation('Alpha') do
Alpha:SetDuration(0.5)
end
local IgnoreButton = CreateFrame('Button', nil, self, GUI.BackdropTemplate) do
IgnoreButton:SetBackdrop(BACKGROP)
IgnoreButton:SetBackdropBorderColor(0, 0, 0, 1)
IgnoreButton:SetBackdropColor(0, 0, 0, 0.4)
IgnoreButton:SetSize(80, 16)
IgnoreButton:SetPoint('BOTTOMRIGHT')
IgnoreButton:SetScript('OnClick', function()
self:OnIgnoreClick()
end)
local Text = IgnoreButton:CreateFontString(nil, 'OVERLAY', 'GameFontNormalGraySmall') do
Text:SetFont(Text:GetFont(), 11)
Text:SetPoint('CENTER')
IgnoreButton:SetFontString(Text)
IgnoreButton:SetHighlightFontObject('GameFontHighlightSmall')
IgnoreButton:SetNormalFontObject('GameFontNormalGraySmall')
end
end
self.Anim = Anim
self.Alpha = Alpha
self.Text = Text
self.Icon = Icon
self.HelpText = HelpText
self.IgnoreButton = IgnoreButton
end
function NotifyFrame:SetText(text)
self.Text:SetText(text)
self:SetHeight(max(50, self.Text:GetStringHeight() + self.HelpText:GetStringHeight() + 12))
end
function NotifyFrame:FadeIn()
self:Show()
self.Anim:Stop()
self.Alpha:SetFromAlpha(0)
self.Alpha:SetToAlpha(1)
self.Anim:Play()
end
function NotifyFrame:FadeOut()
self.Anim:Stop()
self.Alpha:SetFromAlpha(1)
self.Alpha:SetToAlpha(0)
self.Anim:Play()
end
function NotifyFrame:OnClick(click)
if self.Anim:IsPlaying() then
return
end
self:CallOptions(click == 'LeftButton' and 'OnAccept' or 'OnCancel')
self:FadeOut()
end
function NotifyFrame:OnIgnoreClick()
if self.Anim:IsPlaying() then
return
end
self:CallOptions('OnIgnore')
self:FadeOut()
end
function NotifyFrame:OnHide()
self.opts = nil
self:Fire('OnHide')
end
function NotifyFrame:SetOptions(opts)
self.opts = opts
self.Icon:SetTexture(opts.icon or DEFAULT_ICON)
self.IgnoreButton:SetText(opts.ignore or '')
self.IgnoreButton:SetShown(opts.ignore)
self.IgnoreButton:SetWidth(self.IgnoreButton:GetTextWidth() + 10)
self.HelpText:SetText(opts.help or 'Right click to close')
self:SetText(opts.text)
end
function NotifyFrame:GetOptions()
return self.opts
end
function NotifyFrame:CallOptions(method)
if type(self.opts[method]) == 'function' then
self.opts[method](self.opts)
end
end
-- public
local MAX_NOTIFIES = 4
ns.used = ns.used or {}
ns.unused = ns.unused or {}
ns.queue = ns.queue or {}
local NotifyManager = {}
local TYPES = {ONCE = true, DAY = true}
function NotifyManager:CheckOptions(opts)
if opts.ignore and self:GetStorage(opts, 'ignore') then
return
end
if opts.type then
local last = self:GetStorage(opts, 'last')
if last then
if opts.type == 'ONCE' then
return
end
if opts.type == 'DAY' and last == date('%Y/%m/%d') then
return
end
end
end
return true
end
function NotifyManager:SaveStorage(opts, key, value)
opts.storage[opts.id] = opts.storage[opts.id] or {}
opts.storage[opts.id][key] = value
end
function NotifyManager:GetStorage(opts, key)
return opts.storage[opts.id] and opts.storage[opts.id][key]
end
function NotifyManager:Pop()
while self:Update() do
end
self:UpdatePosition()
end
function NotifyManager:UpdatePosition()
for i, frame in ipairs(ns.used) do
if i == 1 then
frame:SetPoint('BOTTOMRIGHT', -25, 90)
else
frame:SetPoint('BOTTOMRIGHT', ns.used[i-1], 'TOPRIGHT', 0, 2)
end
end
end
function NotifyManager:Update()
if #ns.used >= MAX_NOTIFIES then
return
end
local opts = table.remove(ns.queue, 1)
if not opts then
return
end
if not self:CheckOptions(opts) then
return true
end
local notify = table.remove(ns.unused, 1) or NotifyFrame:New(UIParent)
notify:SetPoint('BOTTOMRIGHT', -25, 90)
notify:SetCallback('OnHide', function(notify)
tDeleteItem(ns.used, notify)
table.insert(ns.unused, notify)
self:Pop()
end)
notify:SetOptions(opts)
notify:FadeIn()
if opts.duration ~= -1 then
C_Timer.After(opts.duration or 5, function() notify:FadeOut() end)
end
table.insert(ns.used, notify)
if opts.type then
self:SaveStorage(opts, 'last', date('%Y/%m/%d'))
end
end
function GUI:Notify(opts)
if type(opts) ~= 'table' then
error(format([[bad argument #1 to 'Notify' (table expected, got %s]], type(opts)), 2)
end
if type(opts.text) ~= 'string' then
error(format([[bad argument opts.text to 'Notify' (string expected, got %s)]], type(opts.text)), 2)
end
if opts.type or opts.ignore then
if opts.type and not TYPES[opts.type] then
error(format([[bad argument opts.type to 'Notify' (ONCE|DAY)]]), 2)
end
if type(opts.storage) ~= 'table' then
error(format([[bad argument opts.storage to 'Notify' (table expected, got %s)]], type(opts.storage)), 2)
end
if not opts.id then
error(format([[bad argument opts.storage to 'Notify']]), 2)
end
end
if opts.ignore then
opts.OnIgnore = function(opts)
NotifyManager:SaveStorage(opts, 'ignore', true)
end
end
table.insert(ns.queue, opts)
NotifyManager:Pop()
end
function GUI:NotifyOnce(opts)
opts.type = 'ONCE'
return self:Notify(opts)
end
function GUI:NotifyDay(opts)
opts.type = 'DAY'
return self:Notify(opts)
end