--[[-------------------------------------------------------------------------- ManiaxSocial - the popups, the settings popover and the request toast. Three of these are StaticPopups rather than frames of our own, and that is deliberate: StaticPopup is what this client uses for exactly this shape of question, it is positioned and stacked by the client, Escape closes it, and it inherits the reskin for free. The idiom copied here - `self.editBox`, `self.button1`, `EditBoxOnTextChanged` disabling the accept button while the field is empty - is lifted from the client's own StaticPopup.lua (VOTE_BOOT_REASON_REQUIRED and RENAME_GUILD), not from a wiki. The settings popover and the toast are frames, because neither is a question: one is a pair of controls that stay put while you use them, the other has to be dismissable without answering. Both are built on UIPanelDialogTemplate, which is the client's own title-plate dialog. NO SOUND SPAM. A toast plays at most one sound every SOUND_INTERVAL seconds no matter how many requests arrive, and toasts queue rather than stack, so twenty requests are twenty cards in the tab and one banner at a time. ----------------------------------------------------------------------------]] local NS = ManiaxSocial if not NS then return end local SOUND_INTERVAL = 10 local lastSound = 0 --[[ static popups -------------------------------------------------------- ]] StaticPopupDialogs["MANIAXSOCIAL_ADD_FRIEND"] = { text = "Enter a character name.\n\nThe request goes to that character's account, not the character.", button1 = "Send Request", button2 = CANCEL, hasEditBox = 1, maxLetters = 12, OnShow = function(self) self.editBox:SetText("") self.editBox:SetFocus() self.button1:Disable() end, OnAccept = function(self) NS.Add(self.editBox:GetText()) end, EditBoxOnTextChanged = function(self) local parent = self:GetParent() if NS.Trim(self:GetText()) == "" then parent.button1:Disable() else parent.button1:Enable() end end, EditBoxOnEnterPressed = function(self) local parent = self:GetParent() if parent.button1:IsEnabled() == 1 then NS.Add(self:GetText()) parent:Hide() end end, EditBoxOnEscapePressed = function(self) self:GetParent():Hide() end, timeout = 0, whileDead = 1, hideOnEscape = 1, } StaticPopupDialogs["MANIAXSOCIAL_NOTE"] = { text = "Note for %s", button1 = SAVE, button2 = CANCEL, hasEditBox = 1, maxLetters = 48, OnShow = function(self) self.editBox:SetText(self.noteText or "") self.editBox:HighlightText() self.editBox:SetFocus() end, OnAccept = function(self) NS.Note(self.data, self.editBox:GetText()) end, EditBoxOnEnterPressed = function(self) local parent = self:GetParent() NS.Note(parent.data, self:GetText()) parent:Hide() end, EditBoxOnEscapePressed = function(self) self:GetParent():Hide() end, timeout = 0, whileDead = 1, hideOnEscape = 1, } StaticPopupDialogs["MANIAXSOCIAL_REMOVE"] = { text = "Remove %s from your account friends?", button1 = "Remove", button2 = CANCEL, OnAccept = function(self) NS.Remove(self.data) NS.selected = nil NS.Refresh() end, timeout = 0, whileDead = 1, hideOnEscape = 1, } function NS.ShowAddFriend() StaticPopup_Show("MANIAXSOCIAL_ADD_FRIEND") end function NS.ShowNoteEditor(handle, note) local dialog = StaticPopup_Show("MANIAXSOCIAL_NOTE", handle) if dialog then dialog.data = handle dialog.noteText = note dialog.editBox:SetText(note or "") dialog.editBox:HighlightText() end end function NS.ConfirmRemove(handle) local dialog = StaticPopup_Show("MANIAXSOCIAL_REMOVE", handle) if dialog then dialog.data = handle end end --[[ settings popover ----------------------------------------------------- ]] local settings = CreateFrame("Frame", "ManiaxSocialSettingsFrame", UIParent, "UIPanelDialogTemplate") settings:SetWidth(320) settings:SetHeight(196) settings:SetPoint("CENTER", UIParent, "CENTER", 0, 60) settings:SetToplevel(true) settings:Hide() if settings.title then settings.title:SetText("Settings") end tinsert(UISpecialFrames, "ManiaxSocialSettingsFrame") local privacyCheck = CreateFrame("CheckButton", "ManiaxSocialPrivacyCheck", settings, "UICheckButtonTemplate") privacyCheck:SetWidth(24) privacyCheck:SetHeight(24) privacyCheck:SetPoint("TOPLEFT", settings, "TOPLEFT", 18, -36) local privacyLabel = _G["ManiaxSocialPrivacyCheckText"] if privacyLabel then privacyLabel:SetText("Show my character to friends") privacyLabel:SetFontObject(GameFontHighlightSmall) end local privacyHint = settings:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall") privacyHint:SetPoint("TOPLEFT", privacyCheck, "BOTTOMLEFT", 4, 0) privacyHint:SetWidth(270) privacyHint:SetJustifyH("LEFT") privacyHint:SetText("When off, friends see only that you are online.") local rule = settings:CreateTexture(nil, "ARTWORK") rule:SetTexture(0.59, 0.70, 0.84, 0.25) rule:SetHeight(1) rule:SetPoint("TOPLEFT", privacyHint, "BOTTOMLEFT", -4, -12) rule:SetPoint("TOPRIGHT", settings, "TOPRIGHT", -18, 0) local handleLabel = settings:CreateFontString(nil, "ARTWORK", "GameFontNormalSmall") handleLabel:SetPoint("TOPLEFT", rule, "BOTTOMLEFT", 0, -10) handleLabel:SetText("Handle") local handleBox = CreateFrame("EditBox", "ManiaxSocialHandleBox", settings, "InputBoxTemplate") handleBox:SetWidth(170) handleBox:SetHeight(20) handleBox:SetPoint("TOPLEFT", handleLabel, "BOTTOMLEFT", 6, -6) handleBox:SetAutoFocus(false) handleBox:SetMaxLetters(16) local renameButton = CreateFrame("Button", "ManiaxSocialRenameButton", settings, "UIPanelButtonTemplate2") renameButton:SetWidth(84) renameButton:SetHeight(20) renameButton:SetPoint("LEFT", handleBox, "RIGHT", 10, 0) renameButton:SetText("Rename") local handleHint = settings:CreateFontString(nil, "ARTWORK", "GameFontDisableSmall") handleHint:SetPoint("TOPLEFT", handleLabel, "BOTTOMLEFT", 0, -32) handleHint:SetWidth(280) handleHint:SetJustifyH("LEFT") handleHint:SetText("3 to 16 characters. Must start with a letter; letters and numbers only.") -- Every disabled control here says why, in a tooltip, and none of them uses -- colour to say it. local function renameTooltip(reason) renameButton.reason = reason renameButton:SetScript("OnEnter", function(self) if not self.reason then return end GameTooltip:SetOwner(self, "ANCHOR_RIGHT") GameTooltip:SetText("Rename", 1, 1, 1) GameTooltip:AddLine(self.reason, nil, nil, nil, true) GameTooltip:Show() end) renameButton:SetScript("OnLeave", GameTooltip_Hide) end local function updateRenameButton() local typed = NS.Trim(handleBox:GetText()) if typed == "" or typed == (NS.state.handle or "") then renameButton:Disable() renameTooltip("Enter a different handle to rename.") elseif not NS.HandleIsLegal(typed) then renameButton:Disable() renameTooltip("3 to 16 characters, starting with a letter; letters and numbers only.") else renameButton:Enable() renameTooltip(nil) end end handleBox:SetScript("OnTextChanged", updateRenameButton) handleBox:SetScript("OnEscapePressed", function(self) self:ClearFocus() end) renameButton:SetScript("OnClick", function() local typed = NS.Trim(handleBox:GetText()) if not NS.HandleIsLegal(typed) then return end NS.SetHandle(typed) -- The protocol answers a rename with "OK HANDLE" and nothing else - it -- never states the handle - so this is the only place the client can learn -- its own name. It is adopted optimistically and an ERR puts it back. NS.state.handle = typed NS.Refresh() end) privacyCheck:SetScript("OnClick", function(self) local show = self:GetChecked() and true or false NS.Privacy(show) NS.state.showCharacter = show NS.Refresh() end) function NS.ToggleSettings() if settings:IsShown() then settings:Hide() return end -- The roster never carries our own settings, so the controls open showing -- what we last told the server, or the documented defaults when we have -- told it nothing. privacyCheck:SetChecked(NS.state.showCharacter ~= false) handleBox:SetText(NS.state.handle or "") updateRenameButton() settings:Show() end --[[ the request toast ---------------------------------------------------- ]] local toast = CreateFrame("Frame", "ManiaxSocialToast", UIParent, "UIPanelDialogTemplate") toast:SetWidth(340) toast:SetHeight(116) toast:SetPoint("TOP", UIParent, "TOP", 0, -160) toast:SetToplevel(true) toast:Hide() if toast.title then toast.title:SetText("Friend request") end local toastText = toast:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") toastText:SetPoint("TOPLEFT", toast, "TOPLEFT", 18, -34) toastText:SetWidth(300) toastText:SetJustifyH("LEFT") local toastAccept = CreateFrame("Button", "ManiaxSocialToastAccept", toast, "UIPanelButtonTemplate2") toastAccept:SetWidth(100) toastAccept:SetHeight(21) toastAccept:SetPoint("BOTTOMLEFT", toast, "BOTTOMLEFT", 52, 14) toastAccept:SetText(ACCEPT) local toastDecline = CreateFrame("Button", "ManiaxSocialToastDecline", toast, "UIPanelButtonTemplate2") toastDecline:SetWidth(100) toastDecline:SetHeight(21) toastDecline:SetPoint("LEFT", toastAccept, "RIGHT", 16, 0) toastDecline:SetText(DECLINE) local queue = {} local function showNext() local handle = table.remove(queue, 1) if not handle then toast:Hide() return end toast.handle = handle toastText:SetText(handle .. " has requested to add you as a friend.") toast:Show() if NS.Pref("toastSound") then local now = GetTime() if now - lastSound > SOUND_INTERVAL then lastSound = now PlaySound("TellMessage") end end end toastAccept:SetScript("OnClick", function() NS.Accept(toast.handle) NS.DropRequest(toast.handle) NS.Refresh() showNext() end) toastDecline:SetScript("OnClick", function() NS.Decline(toast.handle) NS.DropRequest(toast.handle) NS.Refresh() showNext() end) -- Dismissing the banner answers nothing: the request stays in the Account tab. toast:SetScript("OnHide", function() toast.handle = nil end) function NS.OnRequestArrived(handle) if not handle or handle == "" or not NS.Pref("toast") then return end for i = 1, #queue do if queue[i] == handle then return end end if toast:IsShown() and toast.handle == handle then return end queue[#queue + 1] = handle if not toast:IsShown() then showNext() end end