-- NotifyFrame.lua -- @Author : DengSir (tdaddon@163.com) -- @Link : https://dengsir.github.io -- @Date : 9/22/2018, 11:26:58 AM local MAJOR, MINOR = 'NotifyFrame', 2 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() 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' (string 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