--[[-------------------------------------------------------------------------- ManiaxSocial - the Account tab. WHAT THIS CLIENT'S FRIENDS LIST ACTUALLY IS, AND WHY THAT MATTERS It is NOT stock 3.3.5a FrameXML. `Interface\FrameXML\FriendsFrame.xml` and `.lua` are replaced out of `patch-enUS-3.MPQ` (204 KB against the stock 153 KB), by a Battle.net-era backport: the frame carries a `FriendsTabHeader` with THREE tabs - Friends, Ignore and Pending - a `FRIENDSFRAME_SUBFRAMES` list, `FriendsFrame_ShowSubFrame`, and a DynamicScrollFrame friends list. Read that file, not a 3.3.5 wiki page, and not the UI simulator: the simulator ships a modern FrameXML, and the stock WotLK FriendsFrame has no tab header at all. The dark "skin" is not an add-on either. Nothing in the pack restyles the Friends List; the art is replaced at the client level - the frame textures by the same `patch-enUS-3.MPQ`, the blue buttons by `patch-9.MPQ` (`Interface\Buttons\UI-Panel-Button-Up` and friends). That is the whole reason this file draws NOTHING of its own: every widget here is built from the client's own templates - TabButtonTemplate, UIPanelButtonTemplate2, UIPanelScrollFrameTemplate, UIPanelDialogTemplate - and from the client's own textures, so the reskin reaches it automatically. Hand-painting the mockup's sampled colours would have produced a tab that looked right today and wrong the next time the art changed. HOW THE TAB IS INJECTED `FriendsTabHeader` is an ordinary PanelTemplates tab group: tabs are `FriendsTabHeaderTab`, `PanelTemplates_UpdateTabs` walks 1..numTabs by global name. So a fourth tab is a Button named `FriendsTabHeaderTab4` with id 4, plus `PanelTemplates_SetNumTabs(FriendsTabHeader, 4)`. Selecting it leaves the stock `FriendsFrame_Update` in its "else" branch (the ignore list), so a post-hook takes over from there and shows our sub-frame instead. Our frame name is appended to `FRIENDSFRAME_SUBFRAMES`, which is what makes the client hide it again when any other tab is picked - no bookkeeping of our own, and nothing to forget. Tab 3 is hidden when `BNFeaturesEnabled()` is false, which it is here, so the Account tab anchors to whichever header tab is actually visible. If any of that is missing - a different FrameXML, another add-on that owns the header - the injection is refused as a whole and the same panel opens as a standalone window instead (mockup figure 7, pre-approved as the fallback). Every widget is anchored to `panel`, never to FriendsFrame, so the fallback is a re-parent and not a second layout. GEOMETRY comes from the client, not from the mockup image: the list sits where `FriendsFrameFriendsScrollFrame` sits (21, -100, 302 x 307) and the two bottom buttons are the 131 x 21 pair at the client's own offsets. The mockup's pixels are that same frame photographed at 1.151x. ----------------------------------------------------------------------------]] local NS = ManiaxSocial if not NS then return end local LIST_X, LIST_Y = 21, -100 local LIST_W, LIST_H = 302, 307 local ROW_H = 37 local ROW_SELECTED_H = 61 local CARD_H = 76 local HEADER_H = 17 local TEXTURE_ONLINE = "Interface\\FriendsFrame\\StatusIcon-Online" local TEXTURE_OFFLINE = "Interface\\FriendsFrame\\StatusIcon-Offline" local TEXTURE_HIGHLIGHT = "Interface\\FriendsFrame\\UI-FriendsFrame-HighlightBar" local TEXTURE_DIVIDER = "Interface\\FriendsFrame\\UI-FriendsFrame-OnlineDivider" -- Sampled from the client screenshot the mockup was measured against; the -- states the screenshot does not contain are the mockup's derived values. local COLOR_NAME = { 0.984, 0.910, 0.478 } local COLOR_INFO = { 0.592, 0.702, 0.839 } local COLOR_NAME_OFF = { 0.494, 0.478, 0.447 } local COLOR_INFO_OFF = { 0.373, 0.420, 0.463 } local COLOR_NOTE = { 0.714, 0.678, 0.612 } local COLOR_MUTED = { 0.427, 0.416, 0.388 } local TOOLTIP_OFFLINE = "Friend is offline." local TOOLTIP_HIDDEN = "This friend has chosen not to show their character." local TOOLTIP_NO_SELECTION = "Select a friend." local TOOLTIP_UNAVAILABLE = "Awaiting realm support." local TEXT_UNAVAILABLE = "Account service unavailable" NS.selected = nil -- {kind = "friend"|"request", handle = ...} NS.injected = false --[[ tooltips ------------------------------------------------------------- ]] -- A disabled control carries its reason. Nothing is greyed here without one. local function tip(widget, title, reason) widget.tipTitle, widget.tipReason = title, reason widget:SetScript("OnEnter", function(self) if not self.tipTitle and not self.tipReason then return end GameTooltip:SetOwner(self, "ANCHOR_RIGHT") if self.tipTitle then GameTooltip:SetText(self.tipTitle, 1, 1, 1) end if self.tipReason then GameTooltip:AddLine(self.tipReason, nil, nil, nil, true) end GameTooltip:Show() end) widget:SetScript("OnLeave", GameTooltip_Hide) end --[[ the panel ------------------------------------------------------------ ]] local panel = CreateFrame("Frame", "ManiaxSocialListFrame", UIParent) panel:Hide() NS.panel = panel local handleLabel = panel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") handleLabel:SetPoint("TOPLEFT", panel, "TOPLEFT", 140, -46) handleLabel:SetText("Handle:") handleLabel:SetTextColor(0.561, 0.533, 0.486) local handleText = panel:CreateFontString(nil, "OVERLAY", "GameFontNormal") handleText:SetPoint("LEFT", handleLabel, "RIGHT", 5, 0) local privacyText = panel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") privacyText:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -42, -46) privacyText:SetTextColor(COLOR_INFO[1], COLOR_INFO[2], COLOR_INFO[3]) local settingsButton = CreateFrame("Button", "ManiaxSocialSettingsButton", panel, "UIPanelButtonTemplate2") settingsButton:SetWidth(70) settingsButton:SetHeight(20) settingsButton:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -42, -68) settingsButton:SetText("Settings") settingsButton:SetScript("OnClick", function() NS.ToggleSettings() end) local scroll = CreateFrame("ScrollFrame", "ManiaxSocialScrollFrame", panel, "UIPanelScrollFrameTemplate") scroll:SetPoint("TOPLEFT", panel, "TOPLEFT", LIST_X, LIST_Y) scroll:SetWidth(LIST_W) scroll:SetHeight(LIST_H) local content = CreateFrame("Frame", "ManiaxSocialScrollChild", scroll) content:SetWidth(LIST_W) content:SetHeight(LIST_H) scroll:SetScrollChild(content) local emptyText = panel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall") emptyText:SetPoint("TOP", scroll, "TOP", 0, -24) emptyText:SetWidth(LIST_W - 40) emptyText:SetJustifyH("CENTER") emptyText:Hide() -- The empty line is a FontString, which cannot own a tooltip, so an invisible -- button sits over it to carry the reason. local emptyHover = CreateFrame("Button", nil, panel) emptyHover:SetPoint("TOPLEFT", emptyText, "TOPLEFT", 0, 0) emptyHover:SetPoint("BOTTOMRIGHT", emptyText, "BOTTOMRIGHT", 0, 0) emptyHover:Hide() local addButton = CreateFrame("Button", "ManiaxSocialAddFriendButton", panel, "UIPanelButtonTemplate2") addButton:SetWidth(131) addButton:SetHeight(21) addButton:SetPoint("BOTTOMLEFT", panel, "BOTTOMLEFT", 15, 81) addButton:SetText(ADD_FRIEND) addButton:SetScript("OnClick", function() NS.ShowAddFriend() end) local actionButton = CreateFrame("Button", "ManiaxSocialActionButton", panel, "UIPanelButtonTemplate2") actionButton:SetWidth(131) actionButton:SetHeight(21) actionButton:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -41, 81) actionButton:SetText(SEND_MESSAGE) --[[ widget pools --------------------------------------------------------- ]] local headers, rows, cards = {}, {}, {} local function acquireHeader(index) local header = headers[index] if not header then header = CreateFrame("Frame", nil, content) header:SetWidth(LIST_W) header:SetHeight(HEADER_H) header.text = header:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") header.text:SetPoint("LEFT", header, "LEFT", 8, 0) header.text:SetTextColor(COLOR_MUTED[1], COLOR_MUTED[2], COLOR_MUTED[3]) header.line = header:CreateTexture(nil, "ARTWORK") header.line:SetTexture(TEXTURE_DIVIDER) header.line:SetHeight(8) header.line:SetPoint("RIGHT", header, "RIGHT", -6, 0) headers[index] = header end header:Show() return header end local function selectEntry(kind, handle) if NS.selected and NS.selected.kind == kind and NS.selected.handle == handle then NS.selected = nil else NS.selected = { kind = kind, handle = handle } end PlaySound("igMainMenuOptionCheckBoxOn") NS.Refresh() end local function acquireRow(index) local row = rows[index] if not row then local name = "ManiaxSocialRow" .. index row = CreateFrame("Button", name, content) row:SetWidth(LIST_W) row:SetHeight(ROW_H) row:SetHighlightTexture(TEXTURE_HIGHLIGHT) row.selection = row:CreateTexture(nil, "BACKGROUND") row.selection:SetTexture(TEXTURE_HIGHLIGHT) row.selection:SetPoint("TOPLEFT", row, "TOPLEFT", 0, 0) row.selection:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", 0, 0) row.selection:Hide() row.icon = row:CreateTexture(nil, "ARTWORK") row.icon:SetWidth(16) row.icon:SetHeight(16) row.icon:SetPoint("TOPLEFT", row, "TOPLEFT", 6, -6) row.name = row:CreateFontString(nil, "ARTWORK", "GameFontNormal") row.name:SetPoint("TOPLEFT", row, "TOPLEFT", 27, -4) row.name:SetJustifyH("LEFT") row.info = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") row.info:SetPoint("TOPLEFT", row, "TOPLEFT", 27, -20) row.info:SetWidth(LIST_W - 40) row.info:SetJustifyH("LEFT") row.note = row:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") row.note:SetPoint("TOPLEFT", row, "TOPLEFT", 27, -36) row.note:SetWidth(LIST_W - 40) row.note:SetJustifyH("LEFT") row.note:SetTextColor(COLOR_NOTE[1], COLOR_NOTE[2], COLOR_NOTE[3]) row.editNote = CreateFrame("Button", name .. "EditNote", row, "UIPanelButtonTemplate2") row.editNote:SetWidth(78) row.editNote:SetHeight(19) row.editNote:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -92, 5) row.editNote:SetText("Edit Note") row.remove = CreateFrame("Button", name .. "Remove", row, "UIPanelButtonTemplate2") row.remove:SetWidth(78) row.remove:SetHeight(19) row.remove:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -10, 5) row.remove:SetText("Remove") row:SetScript("OnClick", function(self) selectEntry("friend", self.handle) end) rows[index] = row end row:Show() return row end local function acquireCard(index) local card = cards[index] if not card then local name = "ManiaxSocialRequest" .. index card = CreateFrame("Button", name, content) card:SetWidth(LIST_W - 12) card:SetHeight(CARD_H - 6) card:SetBackdrop({ bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border", tile = true, tileSize = 16, edgeSize = 16, insets = { left = 4, right = 4, top = 4, bottom = 4 }, }) card:SetBackdropColor(0.04, 0.04, 0.04, 0.9) card.name = card:CreateFontString(nil, "ARTWORK", "GameFontNormal") card.name:SetPoint("TOPLEFT", card, "TOPLEFT", 12, -10) card.name:SetTextColor(COLOR_NAME[1], COLOR_NAME[2], COLOR_NAME[3]) card.info = card:CreateFontString(nil, "ARTWORK", "GameFontHighlightSmall") card.info:SetPoint("TOPLEFT", card, "TOPLEFT", 12, -27) card.info:SetWidth(LIST_W - 40) card.info:SetJustifyH("LEFT") card.info:SetTextColor(COLOR_INFO[1], COLOR_INFO[2], COLOR_INFO[3]) card.info:SetText("Requested to add you as a friend.") card.accept = CreateFrame("Button", name .. "Accept", card, "UIPanelButtonTemplate2") card.accept:SetWidth(90) card.accept:SetHeight(20) card.accept:SetPoint("BOTTOMLEFT", card, "BOTTOMLEFT", 12, 9) card.accept:SetText(ACCEPT) card.decline = CreateFrame("Button", name .. "Decline", card, "UIPanelButtonTemplate2") card.decline:SetWidth(90) card.decline:SetHeight(20) card.decline:SetPoint("LEFT", card.accept, "RIGHT", 10, 0) card.decline:SetText(DECLINE) card:SetScript("OnClick", function(self) selectEntry("request", self.handle) end) cards[index] = card end card:Show() return card end local function hideFrom(pool, index) for i = index, #pool do pool[i]:Hide() end end --[[ row text ------------------------------------------------------------- ]] local function className(class) if not class or class == "" then return nil end local localised = LOCALIZED_CLASS_NAMES_MALE and LOCALIZED_CLASS_NAMES_MALE[class] return localised or class end -- The second line of a friend row, plus the reason it says what it says. function NS.FriendLine(friend) if friend.status == NS.STATUS_PENDING_OUT then return "Request sent", "Waiting for this friend to answer." end if not friend.online then return FRIENDS_LIST_OFFLINE, nil end if not friend.char or friend.char == "" then return "Online — another character", TOOLTIP_HIDDEN end local line = friend.char local class = className(friend.class) if friend.level and class then line = line .. ", " .. string.format(FRIENDS_LEVEL_TEMPLATE, friend.level, class) elseif friend.level then line = line .. ", Level " .. friend.level elseif class then line = line .. ", " .. class end local zone = NS.ZoneName and NS.ZoneName(friend.zone) if zone then line = line .. " — " .. zone end return line, nil end --[[ the contextual bottom-right button ----------------------------------- ]] local function updateActionButton() local selected = NS.selected if selected and selected.kind == "request" then actionButton:SetText("Accept Request") actionButton:Enable() actionButton:SetScript("OnClick", function() NS.Accept(selected.handle) NS.DropRequest(selected.handle) NS.selected = nil PlaySound("igMainMenuOptionCheckBoxOn") NS.Refresh() end) tip(actionButton, nil, "Accept " .. selected.handle .. "'s friend request.") return end actionButton:SetText(SEND_MESSAGE) local friend = selected and selected.kind == "friend" and NS.Friend(selected.handle) if friend and friend.online and friend.char and friend.char ~= "" then actionButton:Enable() actionButton:SetScript("OnClick", function() PlaySound("igMainMenuOptionCheckBoxOn") ChatFrame_SendTell(friend.char) end) tip(actionButton, nil, nil) return end actionButton:Disable() actionButton:SetScript("OnClick", nil) if not friend then tip(actionButton, SEND_MESSAGE, TOOLTIP_NO_SELECTION) elseif friend.online then tip(actionButton, SEND_MESSAGE, TOOLTIP_HIDDEN) else tip(actionButton, SEND_MESSAGE, TOOLTIP_OFFLINE) end end --[[ refresh -------------------------------------------------------------- ]] local function setEmpty(text, reason) if not text then emptyText:Hide() emptyHover:Hide() return end emptyText:SetText(text) emptyText:SetTextColor(COLOR_MUTED[1], COLOR_MUTED[2], COLOR_MUTED[3]) emptyText:Show() if reason then tip(emptyHover, text, reason) emptyHover:Show() else emptyHover:Hide() end end function NS.Refresh() if not panel:IsShown() then return end local state = NS.state handleText:SetText(state.handle or "—") if state.showCharacter == false then privacyText:SetText("Character hidden") else privacyText:SetText("Character shown") end local y = 0 local headerIndex, rowIndex, cardIndex = 1, 1, 1 local requests = state.requests if #requests > 0 then local header = acquireHeader(headerIndex) header:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -y) header.text:SetText(string.format("Requests %d of %d", #requests, NS.MaxRequests())) header.line:SetPoint("LEFT", header.text, "RIGHT", 8, 0) headerIndex = headerIndex + 1 y = y + HEADER_H for i = 1, #requests do local card = acquireCard(cardIndex) local handle = requests[i].handle card.handle = handle card.name:SetText(handle) card:SetPoint("TOPLEFT", content, "TOPLEFT", 6, -y) card.accept:SetScript("OnClick", function() NS.Accept(handle) NS.DropRequest(handle) NS.selected = nil PlaySound("igMainMenuOptionCheckBoxOn") NS.Refresh() end) card.decline:SetScript("OnClick", function() NS.Decline(handle) NS.DropRequest(handle) NS.selected = nil PlaySound("igMainMenuOptionCheckBoxOn") NS.Refresh() end) if NS.selected and NS.selected.kind == "request" and NS.selected.handle == handle then card:SetBackdropBorderColor(0.24, 0.45, 0.75) else card:SetBackdropBorderColor(1, 1, 1) end cardIndex = cardIndex + 1 y = y + CARD_H end end local friends = state.friends local header = acquireHeader(headerIndex) header:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -y) header.text:SetText(string.format("Friends %d of %d", #friends, NS.MaxFriends())) header.line:SetPoint("LEFT", header.text, "RIGHT", 8, 0) headerIndex = headerIndex + 1 y = y + HEADER_H for i = 1, #friends do local friend = friends[i] local row = acquireRow(rowIndex) local selected = NS.selected and NS.selected.kind == "friend" and NS.selected.handle == friend.handle row.handle = friend.handle row:SetPoint("TOPLEFT", content, "TOPLEFT", 0, -y) row:SetHeight(selected and ROW_SELECTED_H or ROW_H) row.icon:SetTexture(friend.online and TEXTURE_ONLINE or TEXTURE_OFFLINE) row.name:SetText(friend.handle) local line, reason = NS.FriendLine(friend) row.info:SetText(line) tip(row, friend.handle, reason) if friend.online then row.name:SetTextColor(COLOR_NAME[1], COLOR_NAME[2], COLOR_NAME[3]) row.info:SetTextColor(COLOR_INFO[1], COLOR_INFO[2], COLOR_INFO[3]) else row.name:SetTextColor(COLOR_NAME_OFF[1], COLOR_NAME_OFF[2], COLOR_NAME_OFF[3]) row.info:SetTextColor(COLOR_INFO_OFF[1], COLOR_INFO_OFF[2], COLOR_INFO_OFF[3]) end if selected then row.selection:Show() if friend.note and friend.note ~= "" then row.note:SetText("Note: " .. friend.note) else row.note:SetText("No note.") end row.note:Show() row.editNote:Show() row.remove:Show() row.editNote:SetScript("OnClick", function() NS.ShowNoteEditor(friend.handle, friend.note) end) row.remove:SetScript("OnClick", function() NS.ConfirmRemove(friend.handle) end) else row.selection:Hide() row.note:Hide() row.editNote:Hide() row.remove:Hide() end rowIndex = rowIndex + 1 y = y + (selected and ROW_SELECTED_H or ROW_H) end hideFrom(headers, headerIndex) hideFrom(rows, rowIndex) hideFrom(cards, cardIndex) content:SetHeight(y > 0 and y or 1) if not state.available then setEmpty(TEXT_UNAVAILABLE, TOOLTIP_UNAVAILABLE) elseif #friends == 0 and #requests == 0 then setEmpty("No friends yet.", nil) else setEmpty(nil) end updateActionButton() end -- Opening the tab is a good moment to re-ask for the roster, but -- FriendsFrame_Update fires on a dozen unrelated events, so this is metered: -- one LIST every ROSTER_REFRESH seconds, never one per event. local ROSTER_REFRESH = 15 local lastRosterRequest = 0 function NS.RequestRoster() local now = GetTime() if now - lastRosterRequest < ROSTER_REFRESH then return false end lastRosterRequest = now return NS.List() end --[[ tab injection -------------------------------------------------------- ]] local ACCOUNT_TAB_ID = 4 local function tabInjectable() return FriendsFrame and FriendsTabHeader and FriendsTabHeader.GetName and FriendsTabHeaderTab1 and FriendsTabHeaderTab2 and type(PanelTemplates_SetNumTabs) == "function" and type(FriendsFrame_ShowSubFrame) == "function" and type(FRIENDSFRAME_SUBFRAMES) == "table" and not _G["FriendsTabHeaderTab" .. ACCOUNT_TAB_ID] end local function injectTab() if not tabInjectable() then return false end local tab = CreateFrame("Button", "FriendsTabHeaderTab" .. ACCOUNT_TAB_ID, FriendsTabHeader, "TabButtonTemplate") tab:SetID(ACCOUNT_TAB_ID) tab:SetText("Account") PanelTemplates_TabResize(tab, 0) local highlight = _G[tab:GetName() .. "HighlightTexture"] if highlight then highlight:SetWidth(tab:GetTextWidth() + 31) end -- Tab 3 (Pending) is hidden when Battle.net features are off, which they -- are on this realm. Anchoring to a hidden tab would leave a hole. local anchor = FriendsTabHeaderTab2 if FriendsTabHeaderTab3 and FriendsTabHeaderTab3:IsShown() then anchor = FriendsTabHeaderTab3 end tab:SetPoint("LEFT", anchor, "RIGHT", 0, 0) tab:SetScript("OnClick", function(self) PanelTemplates_Tab_OnClick(self, FriendsTabHeader) FriendsFrame_Update() PlaySound("igMainMenuOptionCheckBoxOn") end) PanelTemplates_SetNumTabs(FriendsTabHeader, ACCOUNT_TAB_ID) PanelTemplates_UpdateTabs(FriendsTabHeader) panel:SetParent(FriendsFrame) panel:ClearAllPoints() panel:SetAllPoints(FriendsFrame) FRIENDSFRAME_SUBFRAMES[#FRIENDSFRAME_SUBFRAMES + 1] = "ManiaxSocialListFrame" hooksecurefunc("FriendsFrame_Update", function() if FriendsFrame.selectedTab ~= 1 or FriendsTabHeader.selectedTab ~= ACCOUNT_TAB_ID then return end -- The stock function has already run its "ignore list" branch by now, so -- this puts the frame back the way the Friends tab leaves it: same four -- art pieces, same title, our sub-frame instead of theirs. FriendsFrameTopLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopLeft-bnet") FriendsFrameTopRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-TopRight-bnet") FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameMute-BotLeft-bnet") FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrameMute-BotRight-bnet") FriendsFrameTitleText:SetText(FRIENDS_LIST) FriendsFrame_ShowSubFrame("ManiaxSocialListFrame") NS.Refresh() NS.RequestRoster() end) NS.injected = true return true end --[[ the standalone fallback ---------------------------------------------- ]] local function buildStandalone() local window = CreateFrame("Frame", "ManiaxSocialFrame", UIParent, "UIPanelDialogTemplate") window:SetWidth(384) window:SetHeight(460) window:SetPoint("CENTER", UIParent, "CENTER", 0, 0) window:SetMovable(true) window:EnableMouse(true) window:RegisterForDrag("LeftButton") window:SetScript("OnDragStart", window.StartMoving) window:SetScript("OnDragStop", window.StopMovingOrSizing) window:SetToplevel(true) window:Hide() if window.title then window.title:SetText("ManiaxSocial") end tinsert(UISpecialFrames, "ManiaxSocialFrame") panel:SetParent(window) panel:ClearAllPoints() panel:SetAllPoints(window) panel:Show() -- The window has no portrait band, so the list starts higher and the -- buttons sit on its own floor. scroll:ClearAllPoints() scroll:SetPoint("TOPLEFT", panel, "TOPLEFT", 21, -74) scroll:SetHeight(300) handleLabel:ClearAllPoints() handleLabel:SetPoint("TOPLEFT", panel, "TOPLEFT", 16, -30) settingsButton:ClearAllPoints() settingsButton:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -16, -28) addButton:ClearAllPoints() addButton:SetPoint("BOTTOMLEFT", panel, "BOTTOMLEFT", 15, 16) actionButton:ClearAllPoints() actionButton:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -15, 16) window:SetScript("OnShow", function() NS.Refresh() NS.RequestRoster() end) NS.window = window end function NS.OpenAccountTab() if NS.injected then if not FriendsFrame:IsShown() then ToggleFriendsFrame(1) else PanelTemplates_SetTab(FriendsFrame, 1) end PanelTemplates_SetTab(FriendsTabHeader, ACCOUNT_TAB_ID) FriendsFrame_Update() return end if NS.window then if NS.window:IsShown() then NS.window:Hide() else NS.window:Show() end end end --[[ startup -------------------------------------------------------------- ]] local loader = CreateFrame("Frame") loader:RegisterEvent("PLAYER_LOGIN") loader:SetScript("OnEvent", function() if not injectTab() then buildStandalone() NS.Print("the Friends List tab header could not be extended; " .. "ManiaxSocial opens as its own window (/msoc).") end NS.Subscribe(function(event, detail) NS.Refresh() if event == "REQ" and NS.OnRequestArrived then NS.OnRequestArrived(detail) end if event == "ERR" and NS.state.lastError then NS.Print(NS.state.lastError.text ~= "" and NS.state.lastError.text or ("error " .. tostring(NS.state.lastError.code))) end end) end)