Files
benilla-octo/crates/benilla-app/assets/ui/FriendsFrame.xml
T
SamandClaude Fable 5 5a12410f5b raid tab art is back, set bonuses fit, and 12 voices bound the mix
- the mix is bounded the way the reference's is: FMOD gave 1.12 exactly twelve software channels and nothing else limits a priest buffing five people — ported as a 12-voice ceiling (a probe capture read 42 live voices at +13 dBFS, the limiter pumping 13 dB to hold it), plus same-kit copies started in one frame capped at two, since five sample-aligned Fortitudes are one sound +14 dB; `$WOW_SOUND_PROBE` records the mix before and after the limiter with a timeline, F9 stamps the moment
- the raid tab draws its window art again — its four corner textures were written with single backslashes, which Lua drops silently, and a sweep now reads every archive path a shipped Lua chunk names; a drag whose release never arrives (pointer left the window, a second press) ends instead of gluing the frame to the cursor for the rest of the session, and `WOW_PROBE_DRAG` drives any UI drag headlessly in a live client
- the item tooltip fits its set bonuses again: an emptied line kept its last measured height forever (a pooled cell with no way to say "empty"), and the two blank rows above the set block are the reference's own literal (a space and a newline) — a whole row each, not the empty string
- an equipped BoE or BoP piece reads Soulbound: the bind line reads the item's own flags through the client's bound predicate instead of the template's bonding, one predicate shared with the enchant cursor's bind confirm

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 18:25:07 +07:00

3332 lines
211 KiB
XML

<Ui xmlns="http://www.blizzard.com/wow/ui/">
<!--
The social window (decision 0668) — our FriendsFrame. The patch-chain FrameXML (mpqx
extraction, decision 0246) is the SPECIFICATION: `FriendsFrame.lua` (987 lines) and
`FriendsFrame.xml` (the FriendsListFrame / IgnoreListFrame / WhoFrame subtrees) fix the
global names addons bind to, the geometry, the row counts and the art paths, and the
strings are GlobalStrings' own. The code answering to all that is ours.
Shape: ONE window with a tab strip, and inside tab 1 a second Friends/Ignore toggle-tab
pair — the ref's own two-level arrangement, not a simplification. `FriendsFrame.selectedTab`
picks the sub-frame; `FriendsFrame.showFriendsList` picks between the two tab-1 lists.
Every list is a FAUX scroll: 10/20/17 fixed row buttons repainted from an offset, never a
row per friend. Row heights come from the ref's own constants (34/16/16 — note the friend
row's *button* is 31 tall while the scroll step is 34; both are the ref's).
SCOPE (stated, not hidden):
· Tab 3 GUILD is LIVE (decision 1257's guild arc). It is enabled or disabled by
`InGuildCheck` off `IsInGuild()` — greyed and un-clickable for a guildless character,
exactly as the reference greys it, and live the moment the server says we are in one.
The four guild windows below (GuildFrame, GuildControlPopupFrame, GuildInfoFrame,
GuildMemberDetailFrame) answer to the ref's FriendsFrame.xml l.1719-3438 as their
SPECIFICATION — every global, frame, template, event, texture, sound and number below
is the contract addons bind to — but the code is ours. It did not start that way: the
guild landing transcribed those windows and said so here, which is the thing the hard
rule forbids outright, so they were rewritten in our own terms (decision 1334).
· Tab 4 RAID is LIVE (decision 1549). It lives in its own file, `RaidFrame.xml`, which
is the reference's own split — `RaidFrame` is a child of this window but a separate
FrameXML file there too — and it is loaded straight after this one, because a child
cannot be declared before its parent. This file owns only the tab: the button, the
`selectedTab == 4` arm, the subframe list entry, and the OnHide that shuts
RaidInfoFrame with the window. `PanelTemplates_SetNumTabs` now says 4, as the ref's
does. (It said 3 for as long as the pane did not exist, which was honest; the note
that stood here said "the tab is absent until that arc lands" — this is that arc.)
· FOUNDING a guild is out of scope and deliberately so (1257's own boundary): no
GuildRegistrar / PetitionFrame / TabardFrame, no charter or emblem path. Nothing in it
is reachable until you are IN a guild, which is what this file now covers.
· The row right-click menu IS the shared UnitPopup "FRIEND" menu, addressed by name
(see `BenillaFriendsFrame_ShowDropdown`). Its TARGET row stays hidden by UnitPopup's
own deferred set; its GUILD_PROMOTE/GUILD_LEAVE rows are live but gate themselves on
`GuildFrame:IsVisible()`, so a friends-list or /who row still opens
Whisper / Invite / Cancel and a guild roster row opens more.
THE ENGINE API THIS FILE NEEDS. The guild windows are Lua over ~47 engine globals
(`GetGuildRosterInfo`, `GuildControlGetRankFlags`, `IsInGuild`, …) bound in
`benilla-ui/src/script/guild.rs`. Two of them are read at LOAD time, so this file does not
load standalone without them: `FriendsFrame_OnLoad` calls `SetGuildRosterSelection(0)` and
`GetGuildRosterMOTD()` (both the reference's own load-time reads), and
`GuildControlPopupFrame_OnLoad` calls
`GuildControlGetRankFlags()`. That is the reference's own shape, not ours.
-->
<Script><![CDATA[
-- ── Strings (GlobalStrings.lua, verbatim) ───────────────────────────────────────────────
FRIENDS_LIST = "Friends List" -- l.1991
IGNORE_LIST = "Ignore List" -- l.2306
WHO_LIST = "Who List" -- l.5440
FRIENDS_LIST_TEMPLATE = "%s |cffffffff- %s|r %s" -- l.1993
FRIENDS_LIST_OFFLINE_TEMPLATE = "|cff999999%s - Offline|r" -- l.1992
FRIENDS_LEVEL_TEMPLATE = "Level %d %s" -- l.1990
WHO_FRAME_TOTAL_TEMPLATE = "%d Person Found" -- l.5438
WHO_FRAME_TOTAL_TEMPLATE_P1 = "%d People Found" -- l.5439
WHO_FRAME_SHOWN_TEMPLATE = "(%d displayed)" -- l.5437
WHO_TAG_ZONE = "z-" -- l.5449
ADD_FRIEND = "Add Friend" -- l.34
ADD_FRIEND_LABEL = "Enter name of friend to add:" -- l.35
REMOVE_FRIEND = "Remove Friend" -- l.3315
SEND_MESSAGE = "Send Message" -- l.3414
GROUP_INVITE = "Group Invite" -- l.2031
IGNORE_PLAYER = "Ignore Player" -- l.2307
ADD_IGNORE_LABEL = ADD_IGNORE_LABEL or "Enter name of player to ignore:"
STOP_IGNORE = "Remove Player" -- l.4202
UNKNOWN = "Unknown" -- l.4443
-- ── The guild strings (GlobalStrings.lua, verbatim) ────────────────────────────────────
-- The `text=` attributes on the guild frames below name these KEYS rather than spelling
-- the words, which is what the reference's own XML does and what the loader resolves
-- (0991). In a real session the app has already run the shipped GlobalStrings.lua, so
-- these lines are the standalone-load copy — same values, same file, line numbers named.
--
-- `X = X or "…"` throughout, not a bare assignment (the file's own ADD_IGNORE_LABEL
-- precedent, and UIParent.xml's): a dozen of these are GENERIC names — NAME, ZONE, CLASS,
-- RANK, REMOVE, ACCEPT — that other windows and the real string table already own, and a
-- bare `=` would overwrite the shipped value with this copy on every load. Identical
-- today; a silent divergence the day either side changes.
GUILD_MOTD_LABEL = GUILD_MOTD_LABEL or "Guild Message Of The Day:" -- l.2087
GUILD_MOTD_EDITLABEL = GUILD_MOTD_EDITLABEL or "Click here to set the Guild Message Of The Day." -- l.2086
GUILD_INFO_EDITLABEL = GUILD_INFO_EDITLABEL or "Click here to set message" -- l.2078
GUILD_NOTE_EDITLABEL = GUILD_NOTE_EDITLABEL or "Click here to set a Public Note." -- l.2093
GUILD_OFFICERNOTE_EDITLABEL = GUILD_OFFICERNOTE_EDITLABEL or "Click here to set an Officer's Note." -- l.2096
GUILD_ONLINE_LABEL = GUILD_ONLINE_LABEL or "Online" -- l.2098
GUILD_STATUS = GUILD_STATUS or "Show Guild Status" -- l.2109
PLAYER_STATUS = PLAYER_STATUS or "Show Player Status" -- l.3082
GUILD_TOTAL = GUILD_TOTAL or "|cffffffff%d|r Guild Member" -- l.2113
GUILD_TOTAL_P1 = GUILD_TOTAL_P1 or "|cffffffff%d|r Guild Members" -- l.2112
GUILD_TOTALONLINE = GUILD_TOTALONLINE or "(|cffffffff%d|r |cff00ff00Online|r)" -- l.2114
GUILD_INFORMATION = GUILD_INFORMATION or "Guild Information" -- l.2077
GUILD_MEMBER_OPTIONS = GUILD_MEMBER_OPTIONS or "Guild Member Options" -- l.2082
GUILDCONTROL = GUILDCONTROL or "Guild Control" -- l.2034
GUILDCONTROL_SELECTRANK = GUILDCONTROL_SELECTRANK or "Select guild rank to modify:" -- l.2050
GUILDCONTROL_ALLOWRANK = GUILDCONTROL_ALLOWRANK or "Allow this rank to:" -- l.2035
GUILDCONTROL_RANKLABEL = GUILDCONTROL_RANKLABEL or "Rank Label:" -- l.2049
GUILDADDRANK_BUTTON_TOOLTIP = GUILDADDRANK_BUTTON_TOOLTIP or "Click to add rank" -- l.2033
GUILDREMOVERANK_BUTTON_TOOLTIP = GUILDREMOVERANK_BUTTON_TOOLTIP or "Click to remove this rank" -- l.2055
ADDMEMBER = ADDMEMBER or "Add Member" -- l.14
SHOW_OFFLINE_MEMBERS = SHOW_OFFLINE_MEMBERS or "Show Offline Members" -- l.3450
LASTONLINE = LASTONLINE or "Last Online" -- l.2541
LASTONLINE_MINS = LASTONLINE_MINS or "< an hour" -- l.2546
LASTONLINE_HOURS = LASTONLINE_HOURS or "%d hour" -- l.2544
LASTONLINE_HOURS_P1 = LASTONLINE_HOURS_P1 or "%d hours" -- l.2545
LASTONLINE_DAYS = LASTONLINE_DAYS or "%d day" -- l.2543
LASTONLINE_DAYS_P1 = LASTONLINE_DAYS_P1 or "%d days" -- l.2542
LASTONLINE_MONTHS = LASTONLINE_MONTHS or "%d month" -- l.2548
LASTONLINE_MONTHS_P1 = LASTONLINE_MONTHS_P1 or "%d months" -- l.2547
LASTONLINE_YEARS = LASTONLINE_YEARS or "%d year" -- l.2550
LASTONLINE_YEARS_P1 = LASTONLINE_YEARS_P1 or "%d years" -- l.2549
LAST_ONLINE_COLON = LAST_ONLINE_COLON or "Last Online:" -- l.2551
ZONE_COLON = ZONE_COLON or "Zone:" -- l.5468
RANK_COLON = RANK_COLON or "Rank:" -- l.3298
NOTE_COLON = NOTE_COLON or "Note:" -- l.2799
OFFICER_NOTE_COLON = OFFICER_NOTE_COLON or "Officer's Note" -- l.2817
LABEL_NOTE = LABEL_NOTE or "Note" -- l.2539
LEVEL_ABBR = LEVEL_ABBR or "Lvl" -- l.2568
NAME = NAME or "Name" -- l.2711
ZONE = ZONE or "Zone" -- l.5467
CLASS = CLASS or "Class" -- l.751
RANK = RANK or "Rank" -- l.3297
REMOVE = REMOVE or "Remove" -- l.3313
PROMOTE = PROMOTE or "Promote" -- l.3125
DEMOTE = DEMOTE or "Demote" -- l.926
-- The 13 rank-permission labels, in CHECKBOX order (l.2036-2048). The order is the
-- reference's own numbering and it is NOT the order of the underlying rights bits —
-- Promote/Demote are options 5/6 while sitting above Invite/Remove in bit value. The Lua
-- only ever passes `this:GetID()` through to `GuildControlSetRankFlag`, so the index→bit
-- map lives engine-side, not here.
GUILDCONTROL_OPTION1 = GUILDCONTROL_OPTION1 or "Guildchat Listen"
GUILDCONTROL_OPTION2 = GUILDCONTROL_OPTION2 or "Guildchat Speak"
GUILDCONTROL_OPTION3 = GUILDCONTROL_OPTION3 or "Officerchat Listen"
GUILDCONTROL_OPTION4 = GUILDCONTROL_OPTION4 or "Officerchat Speak"
GUILDCONTROL_OPTION5 = GUILDCONTROL_OPTION5 or "Promote"
GUILDCONTROL_OPTION6 = GUILDCONTROL_OPTION6 or "Demote"
GUILDCONTROL_OPTION7 = GUILDCONTROL_OPTION7 or "Invite Member"
GUILDCONTROL_OPTION8 = GUILDCONTROL_OPTION8 or "Remove Member"
GUILDCONTROL_OPTION9 = GUILDCONTROL_OPTION9 or "Set MOTD"
GUILDCONTROL_OPTION10 = GUILDCONTROL_OPTION10 or "Edit Public Note"
GUILDCONTROL_OPTION11 = GUILDCONTROL_OPTION11 or "View Officer Note"
GUILDCONTROL_OPTION12 = GUILDCONTROL_OPTION12 or "Edit Officer Note"
GUILDCONTROL_OPTION13 = GUILDCONTROL_OPTION13 or "Modify Guild Info"
-- The guild dialogs' strings (StaticPopup entries at the foot of this file).
GUILD_INVITATION = GUILD_INVITATION or "%s invites you to join %s" -- l.2080
CONFIRM_GUILD_LEAVE = CONFIRM_GUILD_LEAVE or "Really leave %s?" -- l.845
CONFIRM_GUILD_PROMOTE = CONFIRM_GUILD_PROMOTE or "Really promote %s to Guildmaster?" -- l.846
CONFIRM_GUILD_DISBAND = CONFIRM_GUILD_DISBAND or "Do you really want to disband your guild?" -- l.844
ADD_GUILDMEMBER_LABEL = ADD_GUILDMEMBER_LABEL or "Add Guild Member:" -- l.36
REMOVE_GUILDMEMBER_LABEL = REMOVE_GUILDMEMBER_LABEL or "Are you sure you want to remove %s from the guild?" -- l.3316
ADD_GUILDRANK_LABEL = ADD_GUILDRANK_LABEL or "Add Guild Rank:" -- l.37
SET_GUILDMOTD_LABEL = SET_GUILDMOTD_LABEL or "Set Guild Message Of The Day:" -- l.3419
SET_GUILDPLAYERNOTE_LABEL = SET_GUILDPLAYERNOTE_LABEL or "Set Player Note:" -- l.3421
SET_GUILDOFFICERNOTE_LABEL = SET_GUILDOFFICERNOTE_LABEL or "Set Officer Note:" -- l.3420
ACCEPT = ACCEPT or "Accept" -- l.11
DECLINE = DECLINE or "Decline" -- l.908
YES = YES or "Yes" -- l.5463
NO = NO or "No" -- l.2794
CANCEL = CANCEL or "Cancel" -- l.465
CLOSE = CLOSE or "Close" -- l.760
-- The ref's own display constants (FriendsFrame.lua l.1-15).
FRIENDS_TO_DISPLAY = 10
FRIENDS_FRAME_FRIEND_HEIGHT = 34
IGNORES_TO_DISPLAY = 20
FRIENDS_FRAME_IGNORE_HEIGHT = 16
WHOS_TO_DISPLAY = 17
FRIENDS_FRAME_WHO_HEIGHT = 16
MAX_WHOS_FROM_SERVER = 50
-- Says 12 where there are THIRTEEN checkboxes and thirteen GUILDCONTROL_OPTION strings.
-- That is the reference's own number (l.11) and nothing in the reference reads it — the
-- rank editor loops over what `GuildControlGetRankFlags` returns, not over this. Carried
-- verbatim, and named here so nobody "fixes" it into a 13 that would then be load-bearing.
MAX_GUILDCONTROL_OPTIONS = 12
-- The guild list's own row count and step, kept with the rest of the guild constants
-- rather than up with the other three lists': every other guild number is down here.
GUILDMEMBERS_TO_DISPLAY = 13
FRIENDS_FRAME_GUILD_HEIGHT = 14
CURRENT_GUILD_MOTD = ""
SHOW_OFFLINE_GUILD_MEMBERS = 1 -- saved (RegisterForSave, in the checkbox's OnLoad)
-- The member-detail window's two heights: the officer-note pane is 60px of extra frame,
-- shown only to a rank that may VIEW officer notes (ref l.14-15, l.382-390).
GUILD_DETAIL_NORM_HEIGHT = 195
GUILD_DETAIL_OFFICER_HEIGHT = 255
-- The who list's variable column (l.18-22): the dropdown picks which of the three the
-- middle column shows, and its `sortType` is what the header sort sends.
WHOFRAME_DROPDOWN_LIST = {
{ name = "Zone", sortType = "zone" },
{ name = "Guild", sortType = "guild" },
{ name = "Race", sortType = "race" },
}
-- Ref FRIENDSFRAME_SUBFRAMES (l.24), now including "RaidFrame" (decision 1549). Drives
-- both `FriendsFrame_ShowSubFrame` and `FriendsFrame_OnHide`.
--
-- RaidFrame is declared in the NEXT file loaded, so at the moment this table is built the
-- name resolves to nothing. That is fine and is the reference's own situation twice over
-- (its RaidFrame.xml loads after this file; its raid GRID loads on demand, hours later):
-- the table holds NAMES, and every consumer resolves them through `getglobal` at call
-- time, by which point the window has been shown at least once and everything exists.
BENILLA_FRIENDS_SUBFRAMES = {
"FriendsListFrame", "IgnoreListFrame", "WhoFrame", "GuildFrame", "RaidFrame",
}
-- Six of this window's buttons are live only while a row of the right kind is selected,
-- and each list re-decides all of its own on every repaint. One call per button, taking
-- the condition, keeps that decision readable as the one-liner it actually is.
local function set_enabled(widget, on)
if on then
widget:Enable()
else
widget:Disable()
end
end
-- The same shape again, for the other two things a list decides per row: whether a seat
-- carries the selection highlight, and whether it is a seat at all. `set_shown` is handed
-- FontStrings as well as buttons, which is why none of the three says `button`.
local function set_highlighted(widget, on)
if on then
widget:LockHighlight()
else
widget:UnlockHighlight()
end
end
local function set_shown(widget, on)
if on then
widget:Show()
else
widget:Hide()
end
end
-- ALL FOUR lists in this window seat a row the same way — friends, ignore, who and both
-- guild views: the highlight follows that list's own selection, and a seat past the end of
-- the list leaves rather than sit blank behind the last real row. One rule, four callers.
local function seat_row(widget, selected, present)
set_highlighted(widget, selected)
set_shown(widget, present)
end
-- The guild pane's three satellites are TOPLEVEL frames of their own rather than children
-- of the pane, so nothing hides them implicitly — each has to be told. They are also
-- mutually exclusive: opening any one shuts the other two, which is the same call with the
-- one being opened named. RaidInfoFrame is the ref's fourth and is NOT in this list, which
-- is the reference's own arrangement rather than an omission: it belongs to a different
-- tab, so it can never be on screen at the same time as any of these three. It is closed
-- by `FriendsFrame_OnHide` with everything else.
BENILLA_GUILD_SATELLITES = {
"GuildControlPopupFrame", "GuildMemberDetailFrame", "GuildInfoFrame",
}
function BenillaGuild_HideSatellitesExcept(keep)
for i = 1, table.getn(BENILLA_GUILD_SATELLITES) do
local name = BENILLA_GUILD_SATELLITES[i]
if name ~= keep then
getglobal(name):Hide()
end
end
end
-- ── Sub-frame switching (ref FriendsFrame_ShowSubFrame l.25-33) ────────────────────────
function FriendsFrame_ShowSubFrame(frameName)
for i = 1, table.getn(BENILLA_FRIENDS_SUBFRAMES) do
local value = BENILLA_FRIENDS_SUBFRAMES[i]
set_shown(getglobal(value), value == frameName)
end
end
-- ── The row right-click menu (ref FriendsFrame_ShowDropdown l.35-47) ───────────────────
-- A row's right-click opens the shared UnitPopup "FRIEND" menu addressed by NAME rather
-- than by a unit token — which is the whole reason that menu exists: a friend or a /who
-- hit is a name with no unit behind it (they need not even be in the world). The kit
-- already supports that shape (`UnitPopup_ShowMenu(menu, which, unit, name)`), and its
-- WHISPER/INVITE rows fall back to the by-name calls when `unit` is nil.
--
-- `connected` gates the whole menu, ref-verbatim: there is nothing to offer an offline
-- player. A /who hit is by definition online, so that call passes 1.
function BenillaFriendsFrame_ShowDropdown(name, connected)
HideDropDownMenu(1)
if not connected or not name or name == "" then
return
end
BenillaFriendsDropDown.initialize = BenillaFriendsFrameDropDown_Initialize
BenillaFriendsDropDown.displayMode = "MENU"
BenillaFriendsDropDown.name = name
ToggleDropDownMenu(1, nil, BenillaFriendsDropDown, "cursor")
end
function BenillaFriendsFrameDropDown_Initialize()
UnitPopup_ShowMenu(getglobal(UIDROPDOWNMENU_OPEN_MENU), "FRIEND", nil,
BenillaFriendsDropDown.name)
end
-- ── The window's repaint (ref FriendsFrame_Update l.81-126) ────────────────────────────
-- Each tab swaps the four corner art textures as well as the sub-frame: the ref reuses one
-- 384x512 window shell for lists that want different bottom art.
function FriendsFrame_Update()
local frame = FriendsFrame
if frame.selectedTab == 1 then
FriendsFrameTopLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft")
FriendsFrameTopRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight")
if frame.showFriendsList then
FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-BotLeft")
FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-FriendsFrame-BotRight")
FriendsFrameTitleText:SetText(FRIENDS_LIST)
FriendsList_Update()
FriendsFrame_ShowSubFrame("FriendsListFrame")
else
FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\UI-IgnoreFrame-BotLeft")
FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\UI-IgnoreFrame-BotRight")
FriendsFrameTitleText:SetText(IGNORE_LIST)
IgnoreList_Update()
FriendsFrame_ShowSubFrame("IgnoreListFrame")
end
elseif frame.selectedTab == 2 then
FriendsFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft")
FriendsFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight")
FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\WhoFrame-BotLeft")
FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\WhoFrame-BotRight")
FriendsFrameTitleText:SetText(WHO_LIST)
WhoList_Update()
FriendsFrame_ShowSubFrame("WhoFrame")
elseif frame.selectedTab == 3 then
-- The guild pane (ref l.108-117). Its title is the GUILD'S OWN NAME, not a
-- constant — the one tab whose header changes per character.
FriendsFrameTopLeft:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopLeft")
FriendsFrameTopRight:SetTexture("Interface\\ClassTrainerFrame\\UI-ClassTrainer-TopRight")
FriendsFrameBottomLeft:SetTexture("Interface\\FriendsFrame\\GuildFrame-BotLeft")
FriendsFrameBottomRight:SetTexture("Interface\\FriendsFrame\\GuildFrame-BotRight")
local guildName = GetGuildInfo("player")
FriendsFrameTitleText:SetText(guildName)
FriendsFrame_ShowSubFrame("GuildFrame")
GuildStatus_Update()
elseif frame.selectedTab == 4 then
-- The raid pane (ref l.118-125, decision 1549). The only tab that reuses the
-- CHARACTER window's bottom art rather than art of its own — there is no
-- RaidFrame-BotLeft in the patch chain, because the pane is a grid on a plain
-- parchment rather than a list in a frame.
FriendsFrameTopLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopLeft")
FriendsFrameTopRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-TopRight")
FriendsFrameBottomLeft:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomLeft")
FriendsFrameBottomRight:SetTexture("Interface\\PaperDollInfoFrame\\UI-Character-General-BottomRight")
FriendsFrameTitleText:SetText(RAID)
FriendsFrame_ShowSubFrame("RaidFrame")
end
end
-- ── The friends list (ref FriendsList_Update l.142-210) ────────────────────────────────
function FriendsList_Update()
local frame = FriendsFrame
local numFriends = GetNumFriends()
frame.selectedFriend = GetSelectedFriend()
-- A non-empty list always has a selection; the first row stands in if nothing else
-- does (spec: ref l.154-158).
local anyFriends = numFriends > 0
if anyFriends and frame.selectedFriend == 0 then
SetSelectedFriend(1)
frame.selectedFriend = GetSelectedFriend()
end
-- The three action buttons follow the SELECTED friend, not the list — and only two of
-- them need that friend to be online: you can drop someone from the list whether or
-- not they are logged in, but there is nobody there to whisper or invite (ref
-- l.159-172).
local online = anyFriends and select(5, GetFriendInfo(frame.selectedFriend))
set_enabled(FriendsFrameSendMessageButton, online)
set_enabled(FriendsFrameGroupInviteButton, online)
set_enabled(FriendsFrameRemoveFriendButton, anyFriends)
local offset = FauxScrollFrame_GetOffset(FriendsFrameFriendsScrollFrame)
for i = 1, FRIENDS_TO_DISPLAY do
local index = offset + i
local name, level, class, area, connected, status = GetFriendInfo(index)
local nameLocation = getglobal("FriendsFrameFriendButton" .. i .. "NameLocation")
local info = getglobal("FriendsFrameFriendButton" .. i .. "Info")
if not name or name == "" then
name = UNKNOWN
end
if connected then
nameLocation:SetText(format(FRIENDS_LIST_TEMPLATE, name, area, status or ""))
info:SetText(format(FRIENDS_LEVEL_TEMPLATE, level, class))
else
nameLocation:SetText(format(FRIENDS_LIST_OFFLINE_TEMPLATE, name))
info:SetText(UNKNOWN)
end
local button = getglobal("FriendsFrameFriendButton" .. i)
button:SetID(index)
seat_row(button, index == frame.selectedFriend, index <= numFriends)
end
FauxScrollFrame_Update(FriendsFrameFriendsScrollFrame, numFriends,
FRIENDS_TO_DISPLAY, FRIENDS_FRAME_FRIEND_HEIGHT)
end
-- ── The ignore list (ref IgnoreList_Update l.212-251) ──────────────────────────────────
function IgnoreList_Update()
local frame = FriendsFrame
local numIgnores = GetNumIgnores()
frame.selectedIgnore = GetSelectedIgnore()
local anyIgnores = numIgnores > 0
if anyIgnores and frame.selectedIgnore == 0 then
SetSelectedIgnore(1)
frame.selectedIgnore = GetSelectedIgnore()
end
set_enabled(FriendsFrameStopIgnoreButton, anyIgnores)
local offset = FauxScrollFrame_GetOffset(FriendsFrameIgnoreScrollFrame)
for i = 1, IGNORES_TO_DISPLAY do
local index = offset + i
getglobal("FriendsFrameIgnoreButton" .. i .. "Name")
:SetText(GetIgnoreName(index) or "")
local button = getglobal("FriendsFrameIgnoreButton" .. i)
button:SetID(index)
seat_row(button, index == frame.selectedIgnore, index <= numIgnores)
end
FauxScrollFrame_Update(FriendsFrameIgnoreScrollFrame, numIgnores,
IGNORES_TO_DISPLAY, FRIENDS_FRAME_IGNORE_HEIGHT)
end
-- ── The who list (ref WhoList_Update l.253-325) ────────────────────────────────────────
function WhoList_Update()
local numWhos, totalCount = GetNumWhoResults()
local frame = WhoFrame
-- "132 People Found (50 displayed)" — the suffix appears only when the server
-- matched more than it could send (ref l.264-268).
local displayedText = ""
if totalCount > MAX_WHOS_FROM_SERVER then
displayedText = format(WHO_FRAME_SHOWN_TEMPLATE, MAX_WHOS_FROM_SERVER)
end
local totalTemplate = WHO_FRAME_TOTAL_TEMPLATE_P1
if totalCount == 1 then
totalTemplate = WHO_FRAME_TOTAL_TEMPLATE
end
WhoFrameTotals:SetText(format(totalTemplate, totalCount) .. " " .. displayedText)
local showScrollBar = nil
if numWhos > WHOS_TO_DISPLAY then
showScrollBar = 1
end
local column = UIDropDownMenu_GetSelectedID(WhoFrameDropDown) or 1
local offset = FauxScrollFrame_GetOffset(WhoListScrollFrame)
for i = 1, WHOS_TO_DISPLAY do
local index = offset + i
local button = getglobal("WhoFrameButton" .. i)
button.whoIndex = index
local name, guild, level, race, class, zone = GetWhoInfo(index)
getglobal("WhoFrameButton" .. i .. "Name"):SetText(name or "")
getglobal("WhoFrameButton" .. i .. "Level"):SetText(level or "")
getglobal("WhoFrameButton" .. i .. "Class"):SetText(class or "")
-- The variable column follows the dropdown: zone / guild / race (ref l.274-279).
local columnTable = { zone, guild, race }
local variable = getglobal("WhoFrameButton" .. i .. "Variable")
variable:SetText(columnTable[column] or "")
if showScrollBar then
variable:SetWidth(95)
else
variable:SetWidth(110)
end
seat_row(button, frame.selectedWho == index, index <= numWhos)
end
-- The two who buttons need a selected row, and both act by NAME — so the selection is
-- resolved to one here and the buttons read it back (ref l.302-309).
set_enabled(WhoFrameGroupInviteButton, frame.selectedWho)
set_enabled(WhoFrameAddFriendButton, frame.selectedWho)
if frame.selectedWho then
frame.selectedName = GetWhoInfo(frame.selectedWho)
end
-- The middle column and the dropdown narrow to make room for the bar (ref l.311-318).
if showScrollBar then
WhoFrameColumn_SetWidth(105, WhoFrameColumnHeader2)
UIDropDownMenu_SetWidth(80, WhoFrameDropDown)
else
WhoFrameColumn_SetWidth(120, WhoFrameColumnHeader2)
UIDropDownMenu_SetWidth(95, WhoFrameDropDown)
end
FauxScrollFrame_Update(WhoListScrollFrame, numWhos, WHOS_TO_DISPLAY,
FRIENDS_FRAME_WHO_HEIGHT)
end
-- Ref WhoFrameColumn_SetWidth l.605-611: the header's middle slice carries the width less
-- the two 9px end caps. The `frame` default is the ref's own and it is load-bearing — the
-- eight GUILD column headers below call this from their OnLoad with the width alone
-- (`WhoFrameColumn_SetWidth(83)`), leaning on `this`, while the /who headers pass the
-- frame explicitly. Both spellings are the reference's, in the same file.
function WhoFrameColumn_SetWidth(width, frame)
if not frame then
frame = this
end
frame:SetWidth(width)
getglobal(frame:GetName() .. "Middle"):SetWidth(width - 9)
end
-- ── The who column dropdown (ref WhoFrameDropDown_* l.613-633) ─────────────────────────
function WhoFrameDropDown_Initialize()
for i = 1, table.getn(WHOFRAME_DROPDOWN_LIST) do
local info = {}
info.text = WHOFRAME_DROPDOWN_LIST[i].name
info.func = WhoFrameDropDownButton_OnClick
UIDropDownMenu_AddButton(info)
end
end
function WhoFrameDropDown_OnLoad()
UIDropDownMenu_Initialize(this, WhoFrameDropDown_Initialize)
UIDropDownMenu_SetWidth(80, this)
UIDropDownMenu_SetButtonWidth(24, this)
UIDropDownMenu_JustifyText("LEFT", this)
end
function WhoFrameDropDownButton_OnClick()
UIDropDownMenu_SetSelectedID(WhoFrameDropDown, this:GetID())
-- The ref sorts on the dropdown's OnMouseUp; doing it on the pick is the same intent
-- with one fewer hook, and keeps the column and its sort in step.
local entry = WHOFRAME_DROPDOWN_LIST[this:GetID()]
if entry and entry.sortType then
SortWho(entry.sortType)
end
WhoList_Update()
end
-- ══ THE GUILD PANE ═══════════════════════════════════════════════════════════════════════
-- Ref FriendsFrame.lua l.327-603 (the repaint), l.690-712 (the row click), l.800-987 (rank
-- control, the two toggles, the last-online formatter). Everything below is that file,
-- with the deviations named at each site.
--
-- ONE repaint drives TWO different lists over one set of scroll offsets:
-- `FriendsFrame.playerStatusFrame` picks between the PLAYER view (name/zone/level/class,
-- `GuildFrameButtonN`) and the GUILD-STATUS view (name/rank/note/last-online,
-- `GuildFrameGuildStatusButtonN`). The little page button between the column headers and
-- the list flips it. Both views are 13 rows over the same `GuildListScrollFrame`.
-- `GetText(TOKEN, nil, n)` is the reference's plural-aware GlobalString lookup, and it
-- lives in `LocaleProperties.lua`, which this house does not transcribe. Its enUS rule is
-- the singular token for exactly 1 and the `_P1` twin otherwise — the identical collapse
-- UIParent.xml already made for `SecondsToTime` — so it becomes this, over the shipped
-- pairs (GUILD_TOTAL/_P1, LASTONLINE_{HOURS,DAYS,MONTHS,YEARS}/_P1).
local function guildPlural(token, n)
if n ~= 1 then
local p1 = getglobal(token .. "_P1")
if p1 then
return p1
end
end
return getglobal(token)
end
-- `Button:IsEnabled()` answers 1/0 in 1.12 and a BOOLEAN in this engine
-- (`benilla-ui/src/script/button.rs`), so the ref's own `IsEnabled() == 0` test would be
-- false forever here and the promote/demote pair would never hide. This reads both
-- spellings and is the only place in the file that needs to.
local function guildButtonDisabled(button)
local enabled = button:IsEnabled()
return (not enabled) or (enabled == 0)
end
-- The page button and the view's squeezable column share one rule: a visible scroll bar
-- takes width off the middle column and pulls the button 23px left. Which column, and
-- which pair of widths, is all that differs between the two views.
local function seatListToggle(label, header, crowded, tightWidth, wideWidth)
GuildFrameGuildListToggleButton:SetText(label)
if crowded then
WhoFrameColumn_SetWidth(tightWidth, header)
GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 284, -67)
else
WhoFrameColumn_SetWidth(wideWidth, header)
GuildFrameGuildListToggleButton:SetPoint("LEFT", "GuildFrame", "LEFT", 307, -67)
end
end
-- Both views paint four columns the same way: offline greys the row wholesale, online
-- gives the NAME the gold this window gives every roster name and leaves the rest white.
local function paintRowColumns(row, columns, online)
for column = 1, table.getn(columns) do
local field = getglobal(row .. columns[column])
if not online then
field:SetTextColor(0.5, 0.5, 0.5)
elseif column == 1 then
field:SetTextColor(1.0, 0.82, 0.0)
else
field:SetTextColor(1.0, 1.0, 1.0)
end
end
end
local PLAYER_VIEW_COLUMNS = { "Name", "Zone", "Level", "Class" }
local STATUS_VIEW_COLUMNS = { "Name", "Rank", "Note", "Online" }
-- The PLAYER view: name / zone / level / class. The roster carries level, class and zone
-- for offline members too, which is why these columns stay filled and only lose their
-- colour — unlike the friends list, where an offline friend has no level at all.
local function paintPlayerView(memberCount, crowded)
local offset = FauxScrollFrame_GetOffset(GuildListScrollFrame)
for seat = 1, GUILDMEMBERS_TO_DISPLAY do
local guildIndex = offset + seat
local row = "GuildFrameButton" .. seat
local button = getglobal(row)
button.guildIndex = guildIndex
local name, _, _, level, class, zone, _, _, online = GetGuildRosterInfo(guildIndex)
getglobal(row .. "Name"):SetText(name)
getglobal(row .. "Zone"):SetText(zone)
getglobal(row .. "Level"):SetText(level)
getglobal(row .. "Class"):SetText(class)
paintRowColumns(row, PLAYER_VIEW_COLUMNS, online)
if crowded then
getglobal(row .. "Zone"):SetWidth(95)
else
getglobal(row .. "Zone"):SetWidth(110)
end
seat_row(button, GetGuildRosterSelection() == guildIndex,
guildIndex <= memberCount)
end
seatListToggle(PLAYER_STATUS, GuildFrameColumnHeader2, crowded, 105, 120)
FauxScrollFrame_Update(GuildListScrollFrame, memberCount,
GUILDMEMBERS_TO_DISPLAY, FRIENDS_FRAME_GUILD_HEIGHT)
GuildPlayerStatusFrame:Show()
GuildStatusFrame:Hide()
end
-- The GUILD-STATUS view: name / rank / note / last-online. `status` is
-- `GetGuildRosterInfo`'s TENTH return, the AFK/DND tag, and it takes the place of the
-- plain "Online" label when set — this is the only caller in the file that reads it.
local function paintStatusView(memberCount, crowded)
local offset = FauxScrollFrame_GetOffset(GuildListScrollFrame)
for seat = 1, GUILDMEMBERS_TO_DISPLAY do
local guildIndex = offset + seat
local row = "GuildFrameGuildStatusButton" .. seat
local button = getglobal(row)
button.guildIndex = guildIndex
local name, rank, _, _, _, _, note, _, online, status =
GetGuildRosterInfo(guildIndex)
getglobal(row .. "Name"):SetText(name)
getglobal(row .. "Rank"):SetText(rank)
getglobal(row .. "Note"):SetText(note)
if not online then
getglobal(row .. "Online"):SetText(GuildFrame_GetLastOnline(guildIndex))
elseif status == "" then
getglobal(row .. "Online"):SetText(GUILD_ONLINE_LABEL)
else
getglobal(row .. "Online"):SetText(status)
end
paintRowColumns(row, STATUS_VIEW_COLUMNS, online)
if crowded then
getglobal(row .. "Note"):SetWidth(70)
else
getglobal(row .. "Note"):SetWidth(85)
end
seat_row(button, GetGuildRosterSelection() == guildIndex,
guildIndex <= memberCount)
end
seatListToggle(GUILD_STATUS, GuildFrameGuildStatusColumnHeader3, crowded, 75, 90)
FauxScrollFrame_Update(GuildListScrollFrame, memberCount,
GUILDMEMBERS_TO_DISPLAY, FRIENDS_FRAME_GUILD_HEIGHT)
GuildPlayerStatusFrame:Hide()
GuildStatusFrame:Show()
end
-- Both notes on the detail card follow ONE rule: a rank that may edit gets white text, an
-- invitation in place of an empty note, and a pane that takes the mouse; a rank that may
-- not gets grey text and a dead pane. `EnableMouse` is what makes the click reach the
-- dialog at all, which is why it is re-decided on every repaint rather than set in the XML.
local function paintGuildNote(label, pane, note, mayEdit, invitation)
if mayEdit then
label:SetTextColor(1.0, 1.0, 1.0)
if (not note) or (note == "") then
note = invitation
end
else
label:SetTextColor(0.65, 0.65, 0.65)
end
pane:EnableMouse(mayEdit)
label:SetText(note)
end
-- The selected member's detail card (ref l.344-423). `selectedName` is read off the roster
-- at the selection index UNCONDITIONALLY — index 0 included, where the engine answers
-- nothing — because the card's own buttons act by name, not by index.
local function paintGuildDetail(selection, myRankIndex, bottomRankIndex)
local name, rank, rankIndex, level, class, zone, note, officernote, online =
GetGuildRosterInfo(selection)
GuildFrame.selectedName = name
if selection <= 0 then
return
end
GuildMemberDetailName:SetText(name)
GuildMemberDetailLevel:SetText(format(FRIENDS_LEVEL_TEMPLATE, level, class))
GuildMemberDetailZoneText:SetText(zone)
GuildMemberDetailRankText:SetText(rank)
if online then
GuildMemberDetailOnlineText:SetText(GUILD_ONLINE_LABEL)
else
GuildMemberDetailOnlineText:SetText(GuildFrame_GetLastOnline(selection))
end
paintGuildNote(PersonalNoteText, GuildMemberNoteBackground, note,
CanEditPublicNote(), GUILD_NOTE_EDITLABEL)
-- The officer note is a THIRD state: may-edit / may-view-only / may-not-see. The last
-- of those takes 60px off the card rather than showing an empty pane.
local mayViewOfficer = CanViewOfficerNote()
set_shown(GuildMemberDetailOfficerNoteLabel, mayViewOfficer)
set_shown(GuildMemberOfficerNoteBackground, mayViewOfficer)
if mayViewOfficer then
paintGuildNote(OfficerNoteText, GuildMemberOfficerNoteBackground, officernote,
CanEditOfficerNote(), GUILD_OFFICERNOTE_EDITLABEL)
GuildMemberDetailFrame:SetHeight(GUILD_DETAIL_OFFICER_HEIGHT)
else
GuildMemberDetailFrame:SetHeight(GUILD_DETAIL_NORM_HEIGHT)
end
-- The rank verbs (ref l.393-420). Each is a right AND a rank comparison, and the
-- comparisons are the reference's exactly — note that `rankIndex` here is the ROSTER's
-- 0-based index (0 = guild master) while the whole GuildControl* family one window
-- over is 1-based. Promote refuses to make a second-in-command your equal; demote
-- refuses on the bottom rank, there being nothing under it.
set_enabled(GuildFramePromoteButton,
CanGuildPromote() and (rankIndex > 1) and (rankIndex > (myRankIndex + 1)))
set_enabled(GuildFrameDemoteButton,
CanGuildDemote() and (rankIndex >= 1) and (rankIndex > myRankIndex)
and (rankIndex ~= bottomRankIndex))
-- Both dead -> the arrows leave the card entirely rather than sit greyed.
local anyRankVerb = not (guildButtonDisabled(GuildFrameDemoteButton)
and guildButtonDisabled(GuildFramePromoteButton))
set_shown(GuildFramePromoteButton, anyRankVerb)
set_shown(GuildFrameDemoteButton, anyRankVerb)
set_enabled(GuildMemberRemoveButton,
CanGuildRemove() and (rankIndex >= 1) and (rankIndex > myRankIndex))
set_enabled(GuildMemberGroupInviteButton, online and (UnitName("player") ~= name))
end
-- The message of the day (ref l.425-437). What the pane paints is CURRENT_GUILD_MOTD, the
-- GUILD_MOTD event's cache, never the roster's copy. The reference computes an edit-label
-- placeholder here and then never paints it — that placeholder is what the SET_GUILDMOTD
-- dialog shows, and the pane shows the cache, so only the right-gating survives here.
local function paintGuildMotd()
local mayEdit = CanEditMOTD()
if mayEdit then
GuildFrameNotesText:SetTextColor(1.0, 1.0, 1.0)
else
GuildFrameNotesText:SetTextColor(0.65, 0.65, 0.65)
end
set_enabled(GuildMOTDEditButton, mayEdit)
GuildFrameNotesText:SetText(CURRENT_GUILD_MOTD)
end
function GuildStatus_Update()
-- Ref l.329-331, kept as written and worth flagging: the repaint SELECTS TAB 3 and
-- SHOWS THE WINDOW. Every caller already has the pane up (the tab arm of
-- `FriendsFrame_Update`, the GUILD_ROSTER_UPDATE arm behind an `IsVisible` gate, the
-- pane's own buttons), so in practice both are no-ops — `ShowUIPanel` returns early on
-- an already-visible frame — but they are the reference's lines, not ours to drop.
PanelTemplates_SetTab(FriendsFrame, 3)
ShowUIPanel(FriendsFrame)
local memberCount = GetNumGuildMembers()
local _, _, myRankIndex = GetGuildInfo("player")
local bottomRankIndex = GuildControlGetNumRanks() - 1
paintGuildDetail(GetGuildRosterSelection(), myRankIndex, bottomRankIndex)
paintGuildMotd()
-- One pass over the WHOLE roster for the two counters (ref l.446-456): how many are
-- online, and how many sit in the bottom rank. The second is what the rank editor's
-- Remove Rank button one window over refuses on, which is why that window's Accept
-- path comes back through here.
local onlineCount = 0
FriendsFrame.playersInBotRank = 0
for i = 1, memberCount do
local _, _, rankIndex, _, _, _, _, _, online = GetGuildRosterInfo(i)
if online then
onlineCount = onlineCount + 1
end
if rankIndex == bottomRankIndex then
FriendsFrame.playersInBotRank = FriendsFrame.playersInBotRank + 1
end
end
GuildFrameTotals:SetText(format(guildPlural("GUILD_TOTAL", memberCount), memberCount))
GuildFrameOnlineTotals:SetText(format(GUILD_TOTALONLINE, onlineCount))
-- Guild Control is the guild MASTER's alone; Add Member follows the invite right.
set_enabled(GuildFrameControlButton, IsGuildLeader())
set_enabled(GuildFrameAddMemberButton, CanGuildInvite())
local crowded = memberCount > GUILDMEMBERS_TO_DISPLAY
if FriendsFrame.playerStatusFrame then
paintPlayerView(memberCount, crowded)
else
paintStatusView(memberCount, crowded)
end
end
-- Ref l.690-712. Left-click SELECTS and toggles the detail window; clicking the row that
-- is already selected while the detail window is open closes it and clears the selection,
-- which is the only way back to "nothing selected". Right-click opens the shared FRIEND
-- menu — where the GUILD_PROMOTE / GUILD_LEAVE rows live (UnitPopup.xml), gated on this
-- pane being visible.
function FriendsFrameGuildStatusButton_OnClick(button)
if button == "RightButton" then
local guildIndex = this.guildIndex
local name, rank, rankIndex, level, class, zone, note, officernote, online =
GetGuildRosterInfo(guildIndex)
BenillaFriendsFrame_ShowDropdown(name, online)
return
end
GuildFrame.previousSelectedGuildMember = GuildFrame.selectedGuildMember
GuildFrame.selectedGuildMember = this.guildIndex
GuildFrame.selectedName = getglobal(this:GetName() .. "Name"):GetText()
SetGuildRosterSelection(GuildFrame.selectedGuildMember)
if GuildMemberDetailFrame:IsVisible() and GuildFrame.previousSelectedGuildMember
and (GuildFrame.previousSelectedGuildMember == GuildFrame.selectedGuildMember) then
GuildMemberDetailFrame:Hide()
GuildFrame.selectedGuildMember = 0
SetGuildRosterSelection(0)
else
GuildMemberDetailFrame:Show()
BenillaGuild_HideSatellitesExcept("GuildMemberDetailFrame")
end
GuildStatus_Update()
end
-- ── Rank control (ref l.800-918) ───────────────────────────────────────────────────────
-- The window is an EDIT BUFFER, not a live view: `GuildControlSetRank(i)` loads rank i,
-- the checkboxes and the name box mutate the buffer, and only Accept flushes it. That is
-- why Accept starts disabled on every open and every rank switch — it is the "buffer is
-- dirty" light — and why `GuildControlGetRankFlags` must answer 13 well-formed values
-- BEFORE any rank has been loaded, since OnLoad below calls it at load time.
-- Thirteen checkboxes, thirteen `GUILDCONTROL_OPTION*` strings, one index between them,
-- so the labels are seated in a loop rather than thirteen spelled-out lines. The bound is
-- NOT `MAX_GUILDCONTROL_OPTIONS`: that is the reference's own 12 (see its note above), and
-- reading it here would leave checkbox 13 silently blank.
local GUILD_RANK_OPTIONS = 13
function GuildControlPopupFrame_OnLoad()
GuildControlCheckboxUpdate(GuildControlGetRankFlags())
for option = 1, GUILD_RANK_OPTIONS do
getglobal("GuildControlPopupFrameCheckbox" .. option .. "Label")
:SetText(getglobal("GUILDCONTROL_OPTION" .. option))
end
end
-- Opening the editor LOADS rank 1 into the buffer and puts the dirty light out. The
-- three satellites are mutually exclusive, and the editor also clears whatever centre
-- panel is up, because it is a toplevel of its own that would otherwise sit over it.
function GuildControlPopupFrame_OnShow()
FriendsFrame.guildControlShow = 1
GuildControlPopup_LoadRank(1)
local centre = GetCenterFrame()
if centre then
HideUIPanel(centre)
end
BenillaGuild_HideSatellitesExcept("GuildControlPopupFrame")
end
function GuildControlPopupFrame_OnHide()
FriendsFrame.guildControlShow = 0
end
-- Load rank `index` into the staging buffer and re-seat everything that shows it: the
-- dropdown's selection and label, the thirteen checkboxes, and the dirty light. Every
-- path that changes which rank is being edited — open, dropdown pick, delete — is this
-- one job, so it is written once and the name says what it does.
function GuildControlPopup_LoadRank(index)
GuildControlSetRank(index)
UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown, index)
UIDropDownMenu_SetText(GuildControlGetRankName(index), GuildControlPopupFrameDropDown)
GuildControlCheckboxUpdate(GuildControlGetRankFlags())
GuildControlPopup_MarkClean()
end
-- Accept is the buffer's DIRTY LIGHT: an edit arms it, a flush or a rank switch puts it
-- out. Three edit-box handlers and thirteen checkboxes all mean the same thing by it, so
-- they say it through these two names rather than poking the button.
function GuildControlPopup_MarkDirty()
GuildControlPopupAcceptButton:Enable()
end
function GuildControlPopup_MarkClean()
GuildControlPopupAcceptButton:Disable()
end
function GuildControlPopupAcceptButton_OnClick()
local rankName = GuildControlPopupFrameEditBox:GetText()
GuildControlSaveRank(rankName)
GuildStatus_Update()
GuildControlPopup_MarkClean()
UIDropDownMenu_SetText(rankName, GuildControlPopupFrameDropDown)
GuildControlPopupFrame:Hide()
end
function GuildControlPopupFrameDropDown_OnLoad()
UIDropDownMenu_Initialize(GuildControlPopupFrameDropDown,
GuildControlPopupFrameDropDown_Initialize)
UIDropDownMenu_SetWidth(110, GuildControlPopupFrameDropDown)
UIDropDownMenu_SetButtonWidth(54, GuildControlPopupFrameDropDown)
UIDropDownMenu_JustifyText("LEFT", GuildControlPopupFrameDropDown)
end
function GuildControlPopupFrameDropDown_Initialize()
for i = 1, GuildControlGetNumRanks() do
local info = {}
info.text = GuildControlGetRankName(i)
info.func = GuildControlPopupFrameDropDownButton_OnClick
UIDropDownMenu_AddButton(info)
end
end
function GuildControlPopupFrameDropDownButton_OnClick()
local picked = this:GetID()
GuildControlPopup_LoadRank(picked)
GuildControlPopupFrameEditBox:SetText(GuildControlGetRankName(picked))
GuildControlPopupFrameAddRankButton_OnUpdate()
GuildControlPopupFrameRemoveRankButton_OnUpdate()
end
-- Ref l.874-884. The reference walks the Lua-5.0 vararg TABLE (`arg.n`, `arg[i]`); this VM
-- is 5.1, where that table does not exist. `select("#", ...)` / `select(i, ...)` is the
-- 5.1-native spelling and this tree's house style for it (WorldMapFrame.xml, TalentFrame.xml,
-- QuestTimerFrame.xml, TradeSkillFrame.xml, UIParent.xml all do the same and say so).
--
-- The `local flag` is NOT cosmetic and QuestTimerFrame.xml's header records why: in a
-- call's last-argument position `select(i, ...)` expands to EVERY remaining value, so an
-- inlined `checkbox:SetChecked(select(i, ...))` would hand checkbox 1 all thirteen flags.
-- Binding it takes the first only, which is what `arg[i]` meant.
function GuildControlCheckboxUpdate(...)
for i = 1, select("#", ...) do
local checkbox = getglobal("GuildControlPopupFrameCheckbox" .. i)
local flag = select(i, ...)
if checkbox then
checkbox:SetChecked(flag)
else
message("GuildControlPopupFrameCheckbox" .. i .. " does not exist!")
end
end
end
-- Ten ranks is the server's ceiling (the guild query answers a fixed array of 10 names).
function GuildControlPopupFrameAddRankButton_OnUpdate()
if GuildControlGetNumRanks() >= 10 then
GuildControlPopupFrameAddRankButton:Disable()
else
GuildControlPopupFrameAddRankButton:Enable()
end
end
function GuildControlPopupFrameRemoveRankButton_OnClick()
local doomed = UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown)
GuildControlDelRank(GuildControlGetRankName(doomed))
GuildStatus_Update()
GuildControlPopup_LoadRank(1)
GuildControlPopupFrameEditBox:SetText(GuildControlGetRankName(1))
CloseDropDownMenus()
end
-- Only the LAST rank can be removed, only below 5 ranks does the button hide entirely, and
-- it refuses while anyone still sits in that rank — three separate conditions, all the
-- reference's (l.907-918). `playersInBotRank` is counted by the repaint above, which is
-- why this window's Accept path calls `GuildStatus_Update`.
function GuildControlPopupFrameRemoveRankButton_OnUpdate()
local ranks = GuildControlGetNumRanks()
local onLastRank =
UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown) == ranks
if not (onLastRank and ranks > 5) then
GuildControlPopupFrameRemoveRankButton:Hide()
return
end
GuildControlPopupFrameRemoveRankButton:Show()
set_enabled(GuildControlPopupFrameRemoveRankButton,
FriendsFrame.playersInBotRank == 0)
end
-- Ref l.920-931. The guild tab's whole enabled/disabled law, in one place: greyed while we
-- are in no guild, and — the half that matters — if we were STANDING on the guild tab when
-- the guild went away (kicked, left, disbanded), the window falls back to tab 1 rather
-- than staying on a pane with no guild behind it.
function InGuildCheck()
if not IsInGuild() then
PanelTemplates_DisableTab(FriendsFrame, 3)
if FriendsFrame.selectedTab == 3 then
FriendsFrame.selectedTab = 1
FriendsFrame_Update()
end
else
PanelTemplates_EnableTab(FriendsFrame, 3)
FriendsFrame_Update()
end
end
-- The page button flips which of the two row frames the one scroll frame is showing.
function GuildFrameGuildListToggleButton_OnClick()
if FriendsFrame.playerStatusFrame then
FriendsFrame.playerStatusFrame = nil
else
FriendsFrame.playerStatusFrame = 1
end
GuildStatus_Update()
end
-- Ref l.942-955. Two jobs: keep the Guild Control button lit while its window is open, and
-- run the ref's own two-frame delay before re-asking for the roster. The delay is the
-- reference's own comment ("Janky way to make sure a change made to the guildroster will
-- reflect in the guildroster call") — a rank edit is acked before the server has the new
-- roster, so asking on the same frame answers with the old one. Nothing sets `.update`
-- today: the ref's own writer is commented out at l.902-904, so the ladder is inert there
-- too. Kept rather than dropped, because the day the ack path wants it the mechanism
-- should be the reference's and not a fresh invention.
function GuildFrameControlButton_OnUpdate()
set_highlighted(GuildFrameControlButton, FriendsFrame.guildControlShow == 1)
local pending = GuildControlPopupFrame.update
if pending == 1 then
GuildControlPopupFrame.update = 2
elseif pending == 2 then
GuildRoster()
GuildControlPopupFrame.update = nil
end
end
-- Ref l.957-978. `GetGuildRosterLastOnline` answers (years, months, days, hours) and the
-- formatter takes the COARSEST non-zero unit — "3 months", never "3 months 2 days". All
-- four zero reads "< an hour", which is also what a member who logged off minutes ago
-- gets. The ref leaks its four locals as globals (no `local` on l.958); ours are local.
function GuildFrame_GetLastOnline(guildIndex)
local year, month, day, hour = GetGuildRosterLastOnline(guildIndex)
local lastOnline
if (year == 0) or (year == nil) then
if (month == 0) or (month == nil) then
if (day == 0) or (day == nil) then
if (hour == 0) or (hour == nil) then
lastOnline = LASTONLINE_MINS
else
lastOnline = format(guildPlural("LASTONLINE_HOURS", hour), hour)
end
else
lastOnline = format(guildPlural("LASTONLINE_DAYS", day), day)
end
else
lastOnline = format(guildPlural("LASTONLINE_MONTHS", month), month)
end
else
lastOnline = format(guildPlural("LASTONLINE_YEARS", year), year)
end
return lastOnline
end
-- Ref l.980-987. The three satellites are mutually exclusive: opening any one shuts the
-- other two.
function ToggleGuildInfoFrame()
if GuildInfoFrame:IsShown() then
GuildInfoFrame:Hide()
else
GuildInfoFrame:Show()
BenillaGuild_HideSatellitesExcept("GuildInfoFrame")
end
end
-- ── The guild information board (ref l.2854-3070) ──────────────────────────────────────
-- Free prose, not rows, so it is a real scroll frame around a 500-letter multiline box.
-- ONE right decides four things at once: the text's colour, whether the box takes the
-- mouse at all, whether Save is live, and — for an editor looking at an empty board —
-- whether the invitation to write stands in place of the blank.
function GuildInfoFrame_Update()
local board = GetGuildInfoText()
if not board then
board = ""
end
local mayEdit = CanEditGuildInfo()
if mayEdit and board == "" then
GuildInfoEditBox:SetText(GUILD_INFO_EDITLABEL)
else
GuildInfoEditBox:SetText(board)
end
if mayEdit then
GuildInfoEditBox:SetTextColor(1, 1, 1)
GuildInfoEditBox:EnableMouse(1)
else
GuildInfoEditBox:SetTextColor(0.65, 0.65, 0.65)
-- `EnableMouse()` with NO argument is the DISABLE spelling — the argument arrives
-- nil. The reference's own, and it reads as a dropped `0` unless said out loud.
GuildInfoEditBox:EnableMouse()
end
set_enabled(GuildInfoSaveButton, mayEdit)
end
-- A click on the board puts the caret in the box — but only for a rank that may write to
-- it. For anyone else the click takes focus AWAY, which is what stops a read-only board
-- from swallowing the keyboard.
function GuildInfoFrame_ClaimFocus()
if CanEditGuildInfo() then
GuildInfoEditBox:SetFocus()
else
GuildInfoEditBox:ClearFocus()
end
end
function GuildInfoFrame_Save()
SetGuildInfoText(GuildInfoEditBox:GetText())
GuildRoster()
GuildInfoFrame:Hide()
end
-- Keeps the caret in view while typing past the bottom: re-measure, and if the range GREW,
-- send the bar to its new maximum. The remembered maximum is what stops this fighting a
-- hand scroll — without it every keystroke would yank the view back down.
function GuildInfoEditBox_FollowCaret(box)
local scroll = box:GetParent()
local bar = getglobal(scroll:GetName() .. "ScrollBar")
scroll:UpdateScrollChildRect()
local _, furthest = bar:GetMinMaxValues()
if furthest > 0 and box.max ~= furthest then
box.max = furthest
bar:SetValue(furthest)
end
end
-- The three panes that wear the tooltip's own backdrop colours: the info board at full
-- strength, the two note panes at part alpha so the card's art still reads through.
function BenillaGuildPane_TooltipBackdrop(pane, borderAlpha, fillAlpha)
pane:SetBackdropBorderColor(TOOLTIP_DEFAULT_COLOR.r, TOOLTIP_DEFAULT_COLOR.g,
TOOLTIP_DEFAULT_COLOR.b, borderAlpha)
pane:SetBackdropColor(TOOLTIP_DEFAULT_BACKGROUND_COLOR.r,
TOOLTIP_DEFAULT_BACKGROUND_COLOR.g, TOOLTIP_DEFAULT_BACKGROUND_COLOR.b, fillAlpha)
end
-- Both checkbox families here play the sound of the state they are LEAVING: inside OnClick
-- `GetChecked()` already reports the new one, so a box that just went ON plays the OFF
-- tack. That is the reference's, and it is easy to "correct" backwards, so it is said once.
function BenillaGuildCheckbox_PlayToggle(checked)
local leaving = "igMainMenuOptionCheckBoxOn"
if checked then
leaving = "igMainMenuOptionCheckBoxOff"
end
PlaySound(leaving)
end
-- Toggling the offline filter DROPS THE SELECTION first: the roster is about to be
-- re-ordered, so index 7 is no longer the member that index 7 was.
function BenillaGuildOfflineToggle_OnClick(checked)
SetGuildRosterSelection(0)
BenillaGuildCheckbox_PlayToggle(checked)
if checked then
SHOW_OFFLINE_GUILD_MEMBERS = 1
else
SHOW_OFFLINE_GUILD_MEMBERS = 0
end
SetGuildRosterShowOffline(SHOW_OFFLINE_GUILD_MEMBERS)
GuildStatus_Update()
end
-- A rank checkbox says exactly one thing to the engine — its own ID and its new state —
-- and arms the buffer's dirty light. The index→rights-bit map is engine-side on purpose.
function BenillaGuildRankCheckbox_OnClick(box)
BenillaGuildCheckbox_PlayToggle(box:GetChecked())
GuildControlSetRankFlag(box:GetID(), box:GetChecked())
GuildControlPopup_MarkDirty()
end
-- A guild column header sorts by its own key. Each header's `sortType` is set in its
-- OnLoad, and those eight strings ARE the `SortGuildRoster` contract.
function BenillaGuildColumnHeader_OnClick(header)
if header.sortType then
SortGuildRoster(header.sortType)
end
PlaySound("igMainMenuOptionCheckBoxOn")
end
-- ── Events (ref FriendsFrame_OnEvent l.635-662) ───────────────────────────────────────
-- A table rather than an if/elseif ladder: every event this window cares about names the
-- work it causes, and the same table is what `FriendsFrame_OnLoad` registers from — so an
-- event can never be registered with nothing to run, nor handled without being asked for.
local FRIENDS_FRAME_EVENTS = {}
FRIENDS_FRAME_EVENTS["FRIENDLIST_SHOW"] = function()
FriendsList_Update()
FriendsFrame_Update()
end
FRIENDS_FRAME_EVENTS["FRIENDLIST_UPDATE"] = function()
FriendsList_Update()
end
FRIENDS_FRAME_EVENTS["IGNORELIST_UPDATE"] = function()
IgnoreList_Update()
end
FRIENDS_FRAME_EVENTS["WHO_LIST_UPDATE"] = function()
-- A fresh answer drops the old selection: row 3 of the last query is not row 3 of
-- this one, and the ref's own Refresh button clears it for exactly that reason.
WhoFrame.selectedWho = nil
WhoList_Update()
end
-- GUILD_ROSTER_UPDATE fires for two different reasons and its argument is what tells them
-- apart. TRUTHY means the roster we hold is STALE — a member joined, left or was promoted,
-- and the server is telling us to ask again — so this re-requests before repainting.
-- Absent means the roster in hand already IS the new one and this is only a repaint, which
-- is what a column-header sort or the offline toggle fires. Re-requesting on a sort would
-- put a wire round-trip behind every click on a column header.
FRIENDS_FRAME_EVENTS["GUILD_ROSTER_UPDATE"] = function(stale)
if not GuildFrame:IsVisible() then
return
end
if stale then
GuildRoster()
end
GuildStatus_Update()
FriendsFrame_Update()
end
FRIENDS_FRAME_EVENTS["PLAYER_GUILD_UPDATE"] = function()
if FriendsFrame:IsVisible() then
InGuildCheck()
end
end
-- The MOTD arrives as its own event and is CACHED in a global rather than read back off
-- the roster: the pane paints CURRENT_GUILD_MOTD and so does the SET_GUILDMOTD dialog's
-- OnShow. The ref comments out its own `GetGuildRosterMOTD()` there in favour of this.
FRIENDS_FRAME_EVENTS["GUILD_MOTD"] = function(motd)
CURRENT_GUILD_MOTD = motd
GuildFrameNotesText:SetText(CURRENT_GUILD_MOTD)
end
function FriendsFrame_OnEvent()
local handler = FRIENDS_FRAME_EVENTS[event]
if handler then
handler(arg1)
end
end
function FriendsFrame_OnLoad()
-- THREE tabs, where the ref says four: benilla builds no RAID pane (header SCOPE), so
-- guild is tab 3 of 3 here and tab 3 of 4 there. Everything else in this function is
-- ref l.49-69.
PanelTemplates_SetNumTabs(this, 4)
this.selectedTab = 1
this.showFriendsList = 1
this.selectedFriend = 0
this.selectedIgnore = 0
this.playersInBotRank = 0
this.playerStatusFrame = 1
this.guildStatus = 0
PanelTemplates_UpdateTabs(this)
for name in pairs(FRIENDS_FRAME_EVENTS) do
this:RegisterEvent(name)
end
GuildFrame.notesToggle = 1
GuildFrame.selectedGuildMember = 0
SetGuildRosterSelection(0)
CURRENT_GUILD_MOTD = GetGuildRosterMOTD()
end
function FriendsFrame_OnShow()
FriendsFrame_Update()
-- Guarded, the house idiom (CharacterFrame/QuestLogFrame do the same): MicroMenu.xml
-- loads before this file in the real manifest, but a window must stay loadable on its
-- own for its tests.
if UpdateMicroButtons then UpdateMicroButtons() end
PlaySound("igMainMenuOpen")
-- Ref l.76-78. Opening the window always starts the guild pane with NO row selected —
-- the detail window is a click away, never a leftover — and re-checks the tab, which
-- is the reference's only path onto the guild tab's enabled state at open time.
GuildFrame.selectedGuildMember = 0
SetGuildRosterSelection(0)
InGuildCheck()
end
function FriendsFrame_OnHide()
if UpdateMicroButtons then UpdateMicroButtons() end
PlaySound("igMainMenuClose")
-- Ref l.131-135: the three guild satellites are TOPLEVEL frames of their own, not
-- children of the pane, so hiding the window does not hide them — each has to be told.
SetGuildRosterSelection(0)
GuildFrame.selectedGuildMember = 0
BenillaGuild_HideSatellitesExcept()
-- RaidInfoFrame is the ref's fourth satellite (l.135, decision 1549). It is not in
-- BENILLA_GUILD_SATELLITES because it is not a guild one — nothing may hide it just
-- because a guild window opened — but the window closing does close it, and it is a
-- child of RaidFrame rather than a toplevel, so this is belt and braces the ref also
-- wears.
if RaidInfoFrame then RaidInfoFrame:Hide() end
for i = 1, table.getn(BENILLA_FRIENDS_SUBFRAMES) do
getglobal(BENILLA_FRIENDS_SUBFRAMES[i]):Hide()
end
end
-- ── Row clicks (ref l.664-688) ─────────────────────────────────────────────────────────
function FriendsFrameFriendButton_OnClick(button)
if button == "RightButton" then
local name, _, _, _, connected = GetFriendInfo(this:GetID())
BenillaFriendsFrame_ShowDropdown(name, connected)
return
end
SetSelectedFriend(this:GetID())
FriendsList_Update()
end
function FriendsFrameIgnoreButton_OnClick()
SetSelectedIgnore(this:GetID())
IgnoreList_Update()
end
function FriendsFrameWhoButton_OnClick(button)
local name = getglobal(this:GetName() .. "Name"):GetText()
if button == "RightButton" then
-- A /who hit is online by construction, so the menu is never gated shut here.
BenillaFriendsFrame_ShowDropdown(name, 1)
return
end
WhoFrame.selectedWho = this.whoIndex
WhoFrame.selectedName = name
WhoList_Update()
end
-- ── The buttons (ref l.714-739) ────────────────────────────────────────────────────────
function FriendsFrame_UnIgnore()
local name = GetIgnoreName(FriendsFrame.selectedIgnore)
if name then
DelIgnore(name)
end
end
function FriendsFrame_RemoveFriend()
if FriendsFrame.selectedFriend and FriendsFrame.selectedFriend > 0 then
RemoveFriend(FriendsFrame.selectedFriend)
end
end
-- The ref opens the chat edit box prefilled "/w <name> " (l.726-734). benilla's chat edit
-- box is app-side, so the same intent goes through `ChatFrame_SendTell`, the whisper-target
-- queue the unit popup's WHISPER row already feeds.
function FriendsFrame_SendMessage()
local name = GetFriendInfo(FriendsFrame.selectedFriend)
if name and name ~= "" then
ChatFrame_SendTell(name)
end
end
function FriendsFrame_GroupInvite()
local name = GetFriendInfo(FriendsFrame.selectedFriend)
if name and name ~= "" then
InviteByName(name)
end
end
-- ── The window verbs (ref ToggleFriendsFrame l.741-765, ShowWhoPanel l.772-779) ────────
-- `tab` nil = plain toggle; 1 = friends, 2 = who. Clicking the tab you are already on
-- closes the window (the ref's own second branch).
function ToggleFriendsFrame(tab)
if not tab then
if FriendsFrame:IsVisible() then
HideUIPanel(FriendsFrame)
else
ShowUIPanel(FriendsFrame)
end
return
end
-- Ref l.749-752: the guild tab refuses to be selected at all while we are in no
-- guild. The greying is `InGuildCheck`'s; this is the second lock, and it is the one
-- that catches a caller reaching the tab by NUMBER rather than by clicking it.
if tab == 3 and not IsInGuild() then
return
end
if tab == PanelTemplates_GetSelectedTab(FriendsFrame)
and FriendsFrame:IsVisible() then
HideUIPanel(FriendsFrame)
return
end
PanelTemplates_SetTab(FriendsFrame, tab)
if FriendsFrame:IsVisible() then
FriendsFrame_OnShow()
else
ShowUIPanel(FriendsFrame)
end
end
function ShowWhoPanel()
PanelTemplates_SetTab(FriendsFrame, 2)
if FriendsFrame:IsVisible() then
FriendsFrame_OnShow()
else
ShowUIPanel(FriendsFrame)
end
end
function ShowIgnorePanel()
FriendsFrame.showFriendsList = nil
PanelTemplates_SetTab(FriendsFrame, 1)
if FriendsFrame:IsVisible() then
FriendsFrame_OnShow()
else
ShowUIPanel(FriendsFrame)
end
end
-- The default `/who` (ref WhoFrame_GetDefaultWhoCommand l.790-798): this zone, my level
-- ±3.
function WhoFrame_GetDefaultWhoCommand()
local level = UnitLevel("player") or 1
local minLevel = level - 3
if minLevel <= 0 then
minLevel = 1
end
return WHO_TAG_ZONE .. "\"" .. (GetRealZoneText() or "") .. "\" "
.. minLevel .. "-" .. (level + 3)
end
function WhoFrameEditBox_OnEnterPressed()
SendWho(WhoFrameEditBox:GetText())
WhoFrameEditBox:ClearFocus()
end
-- ── The slash bodies (ref ChatFrame.lua SlashCmdList l.1013-1062, verbatim) ────────────
-- benilla parses slash lines in Rust, so the app calls these rather than a SlashCmdList
-- table — but the bodies are the ref's, so the window behaviour stays in the FrameXML.
function BenillaSlashWho(msg)
if msg == "" then
msg = WhoFrame_GetDefaultWhoCommand()
ShowWhoPanel()
end
WhoFrameEditBox:SetText(msg)
SendWho(msg)
end
function BenillaSlashFriends(msg)
if msg ~= "" then
AddFriend(msg)
else
ShowFriends()
end
end
function BenillaSlashRemoveFriend(msg)
if msg ~= "" then
RemoveFriend(msg)
end
end
function BenillaSlashIgnore(msg)
if msg ~= "" then
AddOrDelIgnore(msg)
else
ShowIgnorePanel()
end
end
function BenillaSlashUnignore(msg)
if msg ~= "" then
DelIgnore(msg)
else
ShowIgnorePanel()
end
end
-- ── The two name-entry dialogs (ref StaticPopup.lua l.775-820) ─────────────────────────
-- The first customers of the popup engine's hasEditBox capability (decision 0668).
-- Every dialog in this file closes on Escape and, bar the guild invitation's own sixty
-- seconds, none of them times out. Stamped rather than spelled out per entry.
local function benillaDialog(name, entry)
if entry.timeout == nil then
entry.timeout = 0
end
entry.hideOnEscape = 1
StaticPopupDialogs[name] = entry
end
benillaDialog("ADD_FRIEND", {
text = ADD_FRIEND_LABEL,
button1 = "Accept",
button2 = "Cancel",
hasEditBox = 1,
maxLetters = 12,
OnAccept = function()
AddFriend(getglobal("StaticPopup1EditBox"):GetText())
end,
OnShow = function()
getglobal("StaticPopup1EditBox"):SetFocus()
end,
EditBoxOnEnterPressed = function()
AddFriend(getglobal("StaticPopup1EditBox"):GetText())
StaticPopup_Hide("ADD_FRIEND")
end,
})
benillaDialog("ADD_IGNORE", {
text = ADD_IGNORE_LABEL,
button1 = "Accept",
button2 = "Cancel",
hasEditBox = 1,
maxLetters = 12,
OnAccept = function()
AddIgnore(getglobal("StaticPopup1EditBox"):GetText())
end,
OnShow = function()
getglobal("StaticPopup1EditBox"):SetFocus()
end,
EditBoxOnEnterPressed = function()
AddIgnore(getglobal("StaticPopup1EditBox"):GetText())
StaticPopup_Hide("ADD_IGNORE")
end,
})
-- ── The guild dialogs (ref StaticPopup.lua) ────────────────────────────────────────────
-- They live HERE, with the guild arc, not in UiPanels.xml with the popup engine — the
-- house rule every arc follows (PartyFrame's PARTY_INVITE, DeathFrame's, DuelFrame's,
-- PetActionBar's three). The engine must stay loadable without any arc; an arc's dialogs
-- come and go with its file.
--
-- Three of them are the first customers of the engine's `hasWideEditBox` (UiPanels.xml):
-- SET_GUILDMOTD, SET_GUILDPLAYERNOTE and SET_GUILDOFFICERNOTE take a sentence, not a name,
-- so they get the 350x64 box in a 420-wide dialog.
--
-- `this` inside OnAccept / EditBoxOnEnterPressed is the clicked BUTTON or the edit box, so
-- the box is reached through `this:GetParent():GetName()` — never `StaticPopup1` by name,
-- which reads the wrong box the moment a dialog lands in the second instance. Inside
-- OnShow/OnHide `this` is the dialog itself. Both are the reference's own spellings.
--
-- The ref's OnHide bodies also clear the box; ours do not need to, because this engine
-- clears every box on SHOW (UiPanels.xml, decision 0668 — a name left over from last time
-- would be sent by a reflexive Enter). What the OnHides keep is the chat-box refocus,
-- guarded like BagFrame.xml's because ChatFrame.xml loads after this file.
-- The ten guild dialogs share a tail. A dead player may still answer one of them — you
-- can be invited, kicked or promoted while a corpse — Escape closes, and none of them
-- times out except the invitation's own sixty seconds. Ten copies of those three fields
-- is nine too many, so the shared part is stamped on rather than spelled out per entry.
-- `exclusive` stays per-dialog: only the ones that take typed text claim the screen.
local function guildDialog(name, entry)
entry.whileDead = 1
benillaDialog(name, entry)
end
-- The invite you receive. `timeout = 60` is the reference's, and it is the only guild
-- dialog with one: an invite expires.
guildDialog("GUILD_INVITE", {
text = GUILD_INVITATION,
button1 = ACCEPT,
button2 = DECLINE,
OnAccept = function()
AcceptGuild()
end,
OnCancel = function()
DeclineGuild()
end,
timeout = 60,
})
guildDialog("CONFIRM_GUILD_LEAVE", {
text = CONFIRM_GUILD_LEAVE,
button1 = ACCEPT,
button2 = CANCEL,
OnAccept = function()
GuildLeave()
end,
})
-- Handing over the guild. The name comes from `dialog.data`, stashed by the menu row that
-- raised it (UnitPopup.xml) — not from the live selection, which may have moved.
guildDialog("CONFIRM_GUILD_PROMOTE", {
text = CONFIRM_GUILD_PROMOTE,
button1 = ACCEPT,
button2 = CANCEL,
OnAccept = function(name)
GuildSetLeaderByName(name)
end,
})
-- Registered, and nothing in this house raises it yet: the reference's caller is
-- `/guilddisband` (ChatFrame.lua's SlashCmdList), and benilla parses slash lines in Rust.
-- It is here so the verb has one home when that command lands, rather than two.
guildDialog("CONFIRM_GUILD_DISBAND", {
text = CONFIRM_GUILD_DISBAND,
button1 = YES,
button2 = NO,
OnAccept = function()
GuildDisband()
end,
})
guildDialog("ADD_GUILDMEMBER", {
text = ADD_GUILDMEMBER_LABEL,
button1 = ACCEPT,
button2 = CANCEL,
hasEditBox = 1,
maxLetters = 12,
OnAccept = function()
GuildInviteByName(getglobal(this:GetParent():GetName() .. "EditBox"):GetText())
end,
OnShow = function()
getglobal(this:GetName() .. "EditBox"):SetFocus()
end,
OnHide = function()
if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
ChatFrameEditBox:SetFocus()
end
end,
EditBoxOnEnterPressed = function()
GuildInviteByName(getglobal(this:GetParent():GetName() .. "EditBox"):GetText())
this:GetParent():Hide()
end,
exclusive = 1,
})
-- The one dialog whose TEXT is rewritten on show: the registry line formats a placeholder
-- so the entry is well-formed, and OnShow splices in the real name (ref l.902-911).
guildDialog("REMOVE_GUILDMEMBER", {
text = format(REMOVE_GUILDMEMBER_LABEL, "XXX"),
button1 = YES,
button2 = NO,
OnAccept = function()
GuildUninviteByName(GuildFrame.selectedName)
GuildMemberDetailFrame:Hide()
end,
OnShow = function()
getglobal(this:GetName() .. "Text"):SetText(
format(REMOVE_GUILDMEMBER_LABEL, GuildFrame.selectedName))
end,
exclusive = 1,
})
-- Adding a rank re-loads the buffer and repaints the checkboxes, because the new rank is
-- appended below the one on screen and the dropdown's ID set just grew.
guildDialog("ADD_GUILDRANK", {
text = ADD_GUILDRANK_LABEL,
button1 = ACCEPT,
button2 = CANCEL,
hasEditBox = 1,
maxLetters = 15,
OnAccept = function()
GuildControlAddRank(getglobal(this:GetParent():GetName() .. "EditBox"):GetText())
GuildControlSetRank(UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown))
UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown,
UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown))
GuildControlPopupFrameEditBox:SetText(GuildControlGetRankName(
UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown)))
GuildControlCheckboxUpdate(GuildControlGetRankFlags())
CloseDropDownMenus()
end,
OnShow = function()
getglobal(this:GetName() .. "EditBox"):SetFocus()
end,
OnHide = function()
if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
ChatFrameEditBox:SetFocus()
end
end,
EditBoxOnEnterPressed = function()
GuildControlAddRank(getglobal(this:GetParent():GetName() .. "EditBox"):GetText())
GuildControlSetRank(UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown))
UIDropDownMenu_SetSelectedID(GuildControlPopupFrameDropDown,
UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown))
GuildControlPopupFrameEditBox:SetText(GuildControlGetRankName(
UIDropDownMenu_GetSelectedID(GuildControlPopupFrameDropDown)))
GuildControlCheckboxUpdate(GuildControlGetRankFlags())
CloseDropDownMenus()
this:GetParent():Hide()
end,
exclusive = 1,
})
-- The three WIDE-box dialogs. Note SET_GUILDMOTD shows CURRENT_GUILD_MOTD, the cached
-- event value — the ref comments out its own `GetGuildRosterMOTD()` spelling right there
-- (l.972-973) and the cache is what the pane paints too.
guildDialog("SET_GUILDMOTD", {
text = SET_GUILDMOTD_LABEL,
button1 = ACCEPT,
button2 = CANCEL,
hasEditBox = 1,
maxLetters = 128,
hasWideEditBox = 1,
OnAccept = function()
GuildSetMOTD(getglobal(this:GetParent():GetName() .. "WideEditBox"):GetText())
end,
OnShow = function()
getglobal(this:GetName() .. "WideEditBox"):SetText(CURRENT_GUILD_MOTD)
getglobal(this:GetName() .. "WideEditBox"):SetFocus()
end,
OnHide = function()
if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
ChatFrameEditBox:SetFocus()
end
end,
EditBoxOnEnterPressed = function()
GuildSetMOTD(getglobal(this:GetParent():GetName() .. "WideEditBox"):GetText())
this:GetParent():Hide()
end,
exclusive = 1,
})
-- The two note dialogs are ONE dialog twice over: same shape, same 31-letter wide box,
-- same chat refocus. They differ in three things only — the label, which of
-- `GetGuildRosterInfo`'s returns seeds the box (7th public, 8th officer), and which setter
-- takes it back — so they are built rather than spelled out twice.
--
-- The setter is held by NAME and looked up when the button is pressed, not captured here:
-- an addon that replaces `GuildRosterSetPublicNote` expects to be the one that runs.
local function guildNoteDialog(name, label, noteReturn, setterName)
guildDialog(name, {
text = label,
button1 = ACCEPT,
button2 = CANCEL,
hasEditBox = 1,
maxLetters = 31,
hasWideEditBox = 1,
OnAccept = function()
getglobal(setterName)(GetGuildRosterSelection(),
getglobal(this:GetParent():GetName() .. "WideEditBox"):GetText())
end,
OnShow = function()
local box = getglobal(this:GetName() .. "WideEditBox")
-- Bound, never inlined: in a call's last-argument position `select` expands to
-- EVERY remaining return, so the box would be handed the whole tail of the
-- roster row. Binding it takes the one we asked for.
local note = select(noteReturn,
GetGuildRosterInfo(GetGuildRosterSelection()))
box:SetText(note)
box:SetFocus()
end,
OnHide = function()
if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
ChatFrameEditBox:SetFocus()
end
end,
EditBoxOnEnterPressed = function()
getglobal(setterName)(GetGuildRosterSelection(),
getglobal(this:GetParent():GetName() .. "WideEditBox"):GetText())
this:GetParent():Hide()
end,
exclusive = 1,
})
end
guildNoteDialog("SET_GUILDPLAYERNOTE", SET_GUILDPLAYERNOTE_LABEL, 7,
"GuildRosterSetPublicNote")
guildNoteDialog("SET_GUILDOFFICERNOTE", SET_GUILDOFFICERNOTE_LABEL, 8,
"GuildRosterSetOfficerNote")
-- The guild-invite event pair. The reference handles both on UIParent's own OnEvent
-- (UIParent.lua l.83-84, l.296-301); benilla's UIParent carries none, so this is the
-- hidden-driver shape every other arc uses (PartyFrame.xml's PARTY_INVITE twin, which
-- these two lines mirror exactly).
function BenillaGuildInviteDriver_OnEvent()
if event == "GUILD_INVITE_REQUEST" then
StaticPopup_Show("GUILD_INVITE", arg1, arg2)
elseif event == "GUILD_INVITE_CANCEL" then
StaticPopup_Hide("GUILD_INVITE")
end
end
]]></Script>
<!-- The panel action button face: the ref's UI-Panel-Button three-state art, label via
`text=`.
**This comment used to say "No `UIPanelButtonTemplate` ships in this house", and that
stopped being true when UIPanelTemplates.xml landed (1203's queue) — it ships the
reference's own `UIPanelButtonTemplate`, `UIPanelCloseButton` and
`UIPanelScrollFrameTemplate`, and it loads well above this file in `benilla.toc`.** This
template is now one of the nine named copies that file's header lists as superseded but
not deleted; re-pointing the friends/ignore/who buttons at the shared name is that
mechanical pass, not this one. The GUILD frames below, being new, inherit the shared
templates directly, exactly as the reference does. -->
<Button name="BenillaFriendsPanelButtonTemplate" virtual="true">
<Size><AbsDimension x="131" y="21"/></Size>
<NormalFont inherits="GameFontNormal"/>
<HighlightFont inherits="GameFontHighlight"/>
<DisabledFont inherits="GameFontDisable"/>
<NormalTexture file="Interface\Buttons\UI-Panel-Button-Up"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></NormalTexture>
<PushedTexture file="Interface\Buttons\UI-Panel-Button-Down"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></PushedTexture>
<DisabledTexture file="Interface\Buttons\UI-Panel-Button-Disabled"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></DisabledTexture>
<HighlightTexture file="Interface\Buttons\UI-Panel-Button-Highlight" alphaMode="ADD"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></HighlightTexture>
</Button>
<!-- ── Row templates (ref FriendsFrame.xml l.4-165) ─────────────────────────────────────── -->
<Button name="BenillaFriendsFrameButtonTemplate" virtual="true">
<Size><AbsDimension x="298" y="31"/></Size>
<Layers>
<Layer level="BORDER">
<FontString name="$parentNameLocation" inherits="GameFontNormal" justifyH="LEFT">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="10" y="-3"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentInfo" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Anchors><Anchor point="TOPLEFT" relativeTo="$parentNameLocation" relativePoint="BOTTOMLEFT"/></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<!-- Both buttons, ref-verbatim (`RegisterForClicks("LeftButtonUp","RightButtonUp")`):
left selects, right opens the FRIEND menu. arg1 is the button name. -->
<OnLoad>this:RegisterForClicks("LeftButtonUp", "RightButtonUp")</OnLoad>
<OnClick>FriendsFrameFriendButton_OnClick(arg1); PlaySound("igMainMenuOptionCheckBoxOn")</OnClick>
</Scripts>
<HighlightTexture file="Interface\QuestFrame\UI-QuestTitleHighlight" alphaMode="ADD"/>
</Button>
<Button name="BenillaFriendsFrameIgnoreButtonTemplate" virtual="true">
<Size><AbsDimension x="298" y="16"/></Size>
<Layers>
<Layer level="BORDER">
<FontString name="$parentName" inherits="GameFontNormal" justifyH="LEFT">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="10" y="-3"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnClick>FriendsFrameIgnoreButton_OnClick(); PlaySound("igMainMenuOptionCheckBoxOn")</OnClick>
</Scripts>
<HighlightTexture file="Interface\QuestFrame\UI-QuestTitleHighlight" alphaMode="ADD"/>
</Button>
<!-- The who row's four columns, chained left to right off the name (ref l.74-165). -->
<Button name="BenillaFriendsFrameWhoButtonTemplate" virtual="true">
<Size><AbsDimension x="298" y="16"/></Size>
<Layers>
<Layer level="BORDER">
<FontString name="$parentName" inherits="GameFontNormalSmall" justifyH="LEFT">
<Size><AbsDimension x="88" y="14"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="10" y="-3"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentVariable" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="95" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentName" relativePoint="RIGHT"/></Anchors>
</FontString>
<FontString name="$parentLevel" inherits="GameFontHighlightSmall" justifyH="CENTER">
<Size><AbsDimension x="20" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentVariable" relativePoint="RIGHT"><Offset><AbsDimension x="2" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentClass" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="100" y="8"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentLevel" relativePoint="RIGHT"><Offset><AbsDimension x="12" y="0"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>this:RegisterForClicks("LeftButtonUp", "RightButtonUp")</OnLoad>
<OnClick>FriendsFrameWhoButton_OnClick(arg1); PlaySound("igMainMenuOptionCheckBoxOn")</OnClick>
</Scripts>
<HighlightTexture file="Interface\QuestFrame\UI-QuestTitleHighlight" alphaMode="ADD"/>
</Button>
<!-- The who column header: a three-slice tab strip, clickable to sort (ref l.166-233). -->
<Button name="BenillaWhoFrameColumnHeaderTemplate" virtual="true">
<Size><AbsDimension x="10" y="24"/></Size>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentLeft" file="Interface\FriendsFrame\WhoFrame-ColumnTabs">
<Size><AbsDimension x="5" y="24"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
<TexCoords left="0" right="0.078125" top="0" bottom="0.75"/>
</Texture>
<Texture name="$parentMiddle" file="Interface\FriendsFrame\WhoFrame-ColumnTabs">
<Size><AbsDimension x="53" y="24"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.078125" right="0.90625" top="0" bottom="0.75"/>
</Texture>
<Texture name="$parentRight" file="Interface\FriendsFrame\WhoFrame-ColumnTabs">
<Size><AbsDimension x="4" y="24"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.90625" right="0.96875" top="0" bottom="0.75"/>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnClick>
if this.sortType then
SortWho(this.sortType)
end
PlaySound("igMainMenuOptionCheckBoxOn")
</OnClick>
</Scripts>
<ButtonText>
<Anchors><Anchor point="LEFT"><Offset><AbsDimension x="8" y="0"/></Offset></Anchor></Anchors>
</ButtonText>
<NormalFont inherits="GameFontHighlightSmall"/>
<HighlightTexture name="$parentHighlightTexture" file="Interface\PaperDollInfoFrame\UI-Character-Tab-Highlight" alphaMode="ADD">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="$parentLeft"><Offset><AbsDimension x="-2" y="5"/></Offset></Anchor>
<Anchor point="BOTTOMRIGHT" relativeTo="$parentRight"><Offset><AbsDimension x="2" y="-7"/></Offset></Anchor>
</Anchors>
</HighlightTexture>
</Button>
<!-- ── The guild row/column templates (ref l.234-493) ──────────────────────────────────────
Four siblings of the three above, `Benilla`-prefixed like them (the diff test strips the
prefix, so every number below still pairs with the reference's). -->
<!-- The PLAYER-view row: name / zone / level / class / group. `Group` is the raid-group column
and it stays EMPTY here — nothing writes it in the reference's own repaint either; the
raid arc is what would (header SCOPE). Its newbie tooltip is on the row itself, which is
the only row template in this file that carries one. -->
<Button name="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" virtual="true">
<Size><AbsDimension x="298" y="16"/></Size>
<Layers>
<Layer level="BORDER">
<FontString name="$parentName" inherits="GameFontNormalSmall" justifyH="LEFT">
<Size><AbsDimension x="88" y="14"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="14" y="-3"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentZone" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="90" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentName" relativePoint="RIGHT"><Offset><AbsDimension x="-7" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentLevel" inherits="GameFontHighlightSmall" justifyH="CENTER">
<Size><AbsDimension x="20" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentZone" relativePoint="RIGHT"><Offset><AbsDimension x="4" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentClass" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="100" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentLevel" relativePoint="RIGHT"><Offset><AbsDimension x="12" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentGroup" inherits="GameFontHighlightSmall" justifyH="CENTER">
<Size><AbsDimension x="40" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentClass" relativePoint="RIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>this:RegisterForClicks("LeftButtonUp", "RightButtonUp")</OnLoad>
<OnClick>FriendsFrameGuildStatusButton_OnClick(arg1)</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, GUILD_MEMBER_OPTIONS, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILD_MEMBER_OPTIONS, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<!-- The guild rows take the FriendsFrame highlight BAR, not the quest-title highlight the
three lists above use — and it is offset (5,-2) off TOP rather than filling the row.
Both are the reference's. -->
<HighlightTexture file="Interface\FriendsFrame\UI-FriendsFrame-HighlightBar" alphaMode="ADD">
<Size><AbsDimension x="298" y="16"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="5" y="-2"/></Offset></Anchor></Anchors>
</HighlightTexture>
</Button>
<!-- The GUILD-STATUS row: name / rank / note / last-online. No newbie tooltip on this one —
the reference gives it to the player-view row only. -->
<Button name="BenillaFriendsFrameGuildStatusButtonTemplate" virtual="true">
<Size><AbsDimension x="298" y="16"/></Size>
<Layers>
<Layer level="BORDER">
<FontString name="$parentName" inherits="GameFontNormalSmall" justifyH="LEFT">
<Size><AbsDimension x="75" y="14"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="14" y="-3"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentRank" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="55" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentName" relativePoint="RIGHT"><Offset><AbsDimension x="5" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentNote" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="85" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentRank" relativePoint="RIGHT"><Offset><AbsDimension x="11" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="$parentOnline" inherits="GameFontHighlightSmall" justifyH="LEFT">
<Size><AbsDimension x="80" y="14"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentNote" relativePoint="RIGHT"><Offset><AbsDimension x="10" y="0"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>this:RegisterForClicks("LeftButtonUp", "RightButtonUp")</OnLoad>
<OnClick>FriendsFrameGuildStatusButton_OnClick(arg1)</OnClick>
</Scripts>
<HighlightTexture file="Interface\FriendsFrame\UI-FriendsFrame-HighlightBar" alphaMode="ADD">
<Size><AbsDimension x="298" y="16"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="5" y="-2"/></Offset></Anchor></Anchors>
</HighlightTexture>
</Button>
<!-- The guild column header: the who header's art and geometry exactly, sorting through
`SortGuildRoster` instead of `SortWho`. It carries NO HighlightTexture where the who one
does — the reference's difference, kept. -->
<Button name="BenillaGuildFrameColumnHeaderTemplate" virtual="true">
<Size><AbsDimension x="10" y="24"/></Size>
<Layers>
<Layer level="BACKGROUND">
<Texture name="$parentLeft" file="Interface\FriendsFrame\WhoFrame-ColumnTabs">
<Size><AbsDimension x="5" y="24"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
<TexCoords left="0" right="0.078125" top="0" bottom="0.75"/>
</Texture>
<Texture name="$parentMiddle" file="Interface\FriendsFrame\WhoFrame-ColumnTabs">
<Size><AbsDimension x="53" y="24"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentLeft" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.078125" right="0.90625" top="0" bottom="0.75"/>
</Texture>
<Texture name="$parentRight" file="Interface\FriendsFrame\WhoFrame-ColumnTabs">
<Size><AbsDimension x="4" y="24"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="$parentMiddle" relativePoint="RIGHT"/></Anchors>
<TexCoords left="0.90625" right="0.96875" top="0" bottom="0.75"/>
</Texture>
</Layer>
</Layers>
<Scripts>
<OnClick>BenillaGuildColumnHeader_OnClick(self)</OnClick>
</Scripts>
<ButtonText>
<Anchors><Anchor point="LEFT"><Offset><AbsDimension x="8" y="0"/></Offset></Anchor></Anchors>
</ButtonText>
<NormalFont inherits="GameFontHighlightSmall"/>
</Button>
<!-- One of the thirteen rank-permission checkboxes. Its ID is the OPTION INDEX, and that index
is the whole contract with the engine: `GuildControlSetRankFlag(id, checked)` is all the
Lua ever says, so the index→rights-bit map lives engine-side (and is NOT `1 << (i-1)` —
Promote/Demote are options 5/6 but sit above Invite/Remove in bit value). -->
<CheckButton name="BenillaGuildControlPopupFrameCheckboxTemplate" virtual="true">
<Size><AbsDimension x="20" y="20"/></Size>
<Layers>
<Layer level="ARTWORK">
<FontString name="$parentLabel" inherits="GameFontNormalSmall">
<Anchors><Anchor point="LEFT" relativePoint="RIGHT"><Offset><AbsDimension x="1" y="1"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<!-- The sound is INVERTED against what you would guess, and it is the reference's:
`GetChecked()` inside OnClick already reports the NEW state, so a box that just
went ON plays the OFF tack. Transcribed as written. -->
<OnClick>BenillaGuildRankCheckbox_OnClick(self)</OnClick>
</Scripts>
<NormalTexture file="Interface\Buttons\UI-CheckBox-Up"/>
<PushedTexture file="Interface\Buttons\UI-CheckBox-Down"/>
<HighlightTexture file="Interface\Buttons\UI-CheckBox-Highlight" alphaMode="ADD"/>
<CheckedTexture file="Interface\Buttons\UI-CheckBox-Check"/>
<DisabledCheckedTexture file="Interface\Buttons\UI-CheckBox-Check-Disabled"/>
</CheckButton>
<!-- ── The window (ref l.506-607) ───────────────────────────────────────────────────────── -->
<Frame name="FriendsFrame" toplevel="true" movable="true" enableMouse="true" hidden="true">
<Size><AbsDimension x="384" y="512"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="-104"/></Offset></Anchor></Anchors>
<HitRectInsets><AbsInset left="0" right="30" top="0" bottom="45"/></HitRectInsets>
<Layers>
<Layer level="BACKGROUND">
<Texture file="Interface\FriendsFrame\FriendsFrameScrollIcon">
<Size><AbsDimension x="60" y="60"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="7" y="-6"/></Offset></Anchor></Anchors>
</Texture>
</Layer>
<Layer level="ARTWORK">
<Texture name="FriendsFrameTopLeft" file="Interface\PaperDollInfoFrame\UI-Character-General-TopLeft">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
</Texture>
<Texture name="FriendsFrameTopRight" file="Interface\PaperDollInfoFrame\UI-Character-General-TopRight">
<Size><AbsDimension x="128" y="256"/></Size>
<Anchors><Anchor point="TOPRIGHT"/></Anchors>
</Texture>
<Texture name="FriendsFrameBottomLeft" file="Interface\FriendsFrame\UI-FriendsFrame-BotLeft">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="BOTTOMLEFT"/></Anchors>
</Texture>
<Texture name="FriendsFrameBottomRight" file="Interface\FriendsFrame\UI-FriendsFrame-BotRight">
<Size><AbsDimension x="128" y="256"/></Size>
<Anchors><Anchor point="BOTTOMRIGHT"/></Anchors>
</Texture>
</Layer>
<Layer level="OVERLAY">
<FontString name="FriendsFrameTitleText" inherits="GameFontNormal">
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="-18"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<!-- The row right-click menu's host (ref `<Frame name="FriendsDropDown"
inherits="UIDropDownMenuTemplate"/>`): invisible until ToggleDropDownMenu opens
it at the cursor. -->
<Frame name="BenillaFriendsDropDown" inherits="UIDropDownMenuTemplate"/>
<!-- Close: the ref's own UIPanelCloseButton seat (TOPRIGHT -30,-8) on the
minimize-button art every close button in this house uses — no UIPanelCloseButton
template ships (CharacterFrame/Gossip/Bag say the same). -->
<Button name="FriendsFrameCloseButton">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-30" y="-8"/></Offset></Anchor></Anchors>
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
<Scripts>
<OnLoad>self:SetFrameLevel(self:GetFrameLevel() + 1)</OnLoad>
<OnClick>HideUIPanel(FriendsFrame)</OnClick>
</Scripts>
</Button>
<!-- ── Tab 1a: the friends list ─────────────────────────────────────────────────── -->
<Frame name="FriendsListFrame" hidden="true" setAllPoints="true">
<Frames>
<Button name="FriendsFrameToggleTab1" inherits="TabButtonTemplate" text="Friends" id="1">
<Anchors><Anchor point="TOPLEFT" relativeTo="FriendsFrame"><Offset><AbsDimension x="70" y="-39"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>PanelTemplates_SelectTab(this)</OnLoad></Scripts>
</Button>
<Button name="FriendsFrameToggleTab2" inherits="TabButtonTemplate" text="Ignore" id="2">
<Anchors><Anchor point="LEFT" relativeTo="FriendsFrameToggleTab1" relativePoint="RIGHT"/></Anchors>
<Scripts>
<OnShow>PanelTemplates_DeselectTab(this)</OnShow>
<OnClick>
FriendsFrame.showFriendsList = nil
FriendsFrame_Update()
PlaySound("igCharacterInfoTab")
</OnClick>
</Scripts>
</Button>
<Button name="FriendsFrameAddFriendButton" inherits="BenillaFriendsPanelButtonTemplate" text="Add Friend">
<Size><AbsDimension x="131" y="21"/></Size>
<Anchors><Anchor point="BOTTOMLEFT" relativeTo="FriendsFrame"><Offset><AbsDimension x="17" y="107"/></Offset></Anchor></Anchors>
<Scripts>
<!-- Ref l.656-662: a friendly player target is befriended straight
away; otherwise the name-entry dialog opens. -->
<OnClick>
if UnitCanCooperate("player", "target") then
AddFriend(UnitName("target"))
else
StaticPopup_Show("ADD_FRIEND")
end
</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, ADD_FRIEND, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_ADDFRIEND, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Button>
<Button name="FriendsFrameRemoveFriendButton" inherits="BenillaFriendsPanelButtonTemplate" text="Remove Friend">
<Size><AbsDimension x="131" y="21"/></Size>
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameAddFriendButton" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="-5"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>FriendsFrame_RemoveFriend()</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, REMOVE_FRIEND, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_REMOVEFRIEND, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Button>
<Button name="FriendsFrameSendMessageButton" inherits="BenillaFriendsPanelButtonTemplate" text="Send Message">
<Size><AbsDimension x="131" y="21"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="FriendsFrameAddFriendButton" relativePoint="RIGHT"><Offset><AbsDimension x="66" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>FriendsFrame_SendMessage()</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, SEND_MESSAGE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_SENDMESSAGE, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Button>
<Button name="FriendsFrameGroupInviteButton" inherits="BenillaFriendsPanelButtonTemplate" text="Group Invite">
<Size><AbsDimension x="131" y="21"/></Size>
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameSendMessageButton" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="-5"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>FriendsFrame_GroupInvite()</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, GROUP_INVITE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GROUPINVITE, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
</Button>
<!-- The ten rows: the first at (23,-76) off the window, the rest chained
TOP→BOTTOM with no gap (ref l.740-829). -->
<Button name="FriendsFrameFriendButton1" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOPLEFT" relativeTo="FriendsFrame"><Offset><AbsDimension x="23" y="-76"/></Offset></Anchor></Anchors>
</Button>
<Button name="FriendsFrameFriendButton2" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton1" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton3" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton2" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton4" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton3" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton5" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton4" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton6" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton5" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton7" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton6" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton8" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton7" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton9" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton8" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameFriendButton10" inherits="BenillaFriendsFrameButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameFriendButton9" relativePoint="BOTTOM"/></Anchors>
</Button>
<Frame name="FriendsFrameFriendsScrollFrame" inherits="FauxScrollFrameTemplate">
<Size><AbsDimension x="296" y="304"/></Size>
<Anchors><Anchor point="TOPRIGHT" relativeTo="FriendsFrame"><Offset><AbsDimension x="-67" y="-75"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>self.updateFunc = FriendsList_Update</OnLoad></Scripts>
</Frame>
</Frames>
<Scripts>
<OnMouseWheel>BenillaFauxScrollFrame_OnMouseWheel(FriendsFrameFriendsScrollFrame, arg1)</OnMouseWheel>
</Scripts>
</Frame>
<!-- ── Tab 1b: the ignore list (ref l.879-1193) ─────────────────────────────────── -->
<Frame name="IgnoreListFrame" hidden="true" setAllPoints="true">
<Frames>
<Button name="IgnoreFrameToggleTab1" inherits="TabButtonTemplate" text="Friends" id="1">
<Anchors><Anchor point="TOPLEFT" relativeTo="FriendsFrame"><Offset><AbsDimension x="70" y="-39"/></Offset></Anchor></Anchors>
<Scripts>
<OnShow>PanelTemplates_DeselectTab(this)</OnShow>
<OnClick>
FriendsFrame.showFriendsList = 1
FriendsFrame_Update()
PlaySound("igCharacterInfoTab")
</OnClick>
</Scripts>
</Button>
<Button name="IgnoreFrameToggleTab2" inherits="TabButtonTemplate" text="Ignore" id="2">
<Anchors><Anchor point="LEFT" relativeTo="IgnoreFrameToggleTab1" relativePoint="RIGHT"/></Anchors>
<Scripts><OnShow>PanelTemplates_SelectTab(this)</OnShow></Scripts>
</Button>
<Button name="FriendsFrameIgnorePlayerButton" inherits="BenillaFriendsPanelButtonTemplate" text="Ignore Player">
<Size><AbsDimension x="131" y="21"/></Size>
<!-- (17,81), NOT the friends list's (17,107): the ignore pane has two
buttons where that one has four, so its row sits lower (ref l.919-925). -->
<Anchors><Anchor point="BOTTOMLEFT" relativeTo="FriendsFrame"><Offset><AbsDimension x="17" y="81"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>StaticPopup_Show("ADD_IGNORE")</OnClick>
</Scripts>
</Button>
<Button name="FriendsFrameStopIgnoreButton" inherits="BenillaFriendsPanelButtonTemplate" text="Remove Player">
<Size><AbsDimension x="131" y="21"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="FriendsFrameIgnorePlayerButton" relativePoint="RIGHT"><Offset><AbsDimension x="62" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>FriendsFrame_UnIgnore()</OnClick>
</Scripts>
</Button>
<Button name="FriendsFrameIgnoreButton1" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<!-- -80, not the friends list's -76 (ref l.965-971). -->
<Anchors><Anchor point="TOPLEFT" relativeTo="FriendsFrame"><Offset><AbsDimension x="23" y="-80"/></Offset></Anchor></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton2" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton1" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton3" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton2" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton4" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton3" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton5" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton4" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton6" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton5" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton7" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton6" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton8" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton7" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton9" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton8" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton10" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton9" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton11" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton10" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton12" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton11" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton13" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton12" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton14" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton13" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton15" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton14" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton16" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton15" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton17" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton16" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton18" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton17" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton19" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton18" relativePoint="BOTTOM"/></Anchors>
</Button>
<Button name="FriendsFrameIgnoreButton20" inherits="BenillaFriendsFrameIgnoreButtonTemplate">
<Anchors><Anchor point="TOP" relativeTo="FriendsFrameIgnoreButton19" relativePoint="BOTTOM"/></Anchors>
</Button>
<Frame name="FriendsFrameIgnoreScrollFrame" inherits="FauxScrollFrameTemplate">
<!-- 332 tall, not the friends list's 304: 20 short rows reach further
down than 10 tall ones (ref l.1146-1148). -->
<Size><AbsDimension x="296" y="332"/></Size>
<Anchors><Anchor point="TOPRIGHT" relativeTo="FriendsFrame"><Offset><AbsDimension x="-67" y="-75"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>self.updateFunc = IgnoreList_Update</OnLoad></Scripts>
</Frame>
</Frames>
<Scripts>
<OnMouseWheel>BenillaFauxScrollFrame_OnMouseWheel(FriendsFrameIgnoreScrollFrame, arg1)</OnMouseWheel>
</Scripts>
</Frame>
<!-- ── Tab 2: /who (ref l.1194-1718) ────────────────────────────────────────────── -->
<Frame name="WhoFrame" hidden="true" setAllPoints="true">
<Layers>
<Layer level="ARTWORK">
<FontString name="WhoFrameTotals" inherits="GameFontNormalSmall">
<Size><AbsDimension x="298" y="16"/></Size>
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="-10" y="127"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<Button name="WhoFrameColumnHeader1" inherits="BenillaWhoFrameColumnHeaderTemplate" text="Name">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="20" y="-70"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(83, this); this.sortType = "name"</OnLoad></Scripts>
</Button>
<Button name="WhoFrameColumnHeader2" inherits="BenillaWhoFrameColumnHeaderTemplate">
<Anchors><Anchor point="LEFT" relativeTo="WhoFrameColumnHeader1" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Frames>
<!-- The variable column IS a dropdown sitting in its own header
(ref l.1326-1375). -->
<Frame name="WhoFrameDropDown" inherits="UIDropDownMenuTemplate" id="1">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="-15" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnLoad>WhoFrameDropDown_OnLoad()</OnLoad>
<OnShow>
UIDropDownMenu_Initialize(WhoFrameDropDown, WhoFrameDropDown_Initialize)
UIDropDownMenu_SetSelectedID(WhoFrameDropDown, 1)
</OnShow>
</Scripts>
</Frame>
</Frames>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(105, this)</OnLoad></Scripts>
</Button>
<Button name="WhoFrameColumnHeader3" inherits="BenillaWhoFrameColumnHeaderTemplate" text="Lvl">
<Anchors><Anchor point="LEFT" relativeTo="WhoFrameColumnHeader2" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(32, this); this.sortType = "level"</OnLoad></Scripts>
</Button>
<Button name="WhoFrameColumnHeader4" inherits="BenillaWhoFrameColumnHeaderTemplate" text="Class">
<Anchors><Anchor point="LEFT" relativeTo="WhoFrameColumnHeader3" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(92, this); this.sortType = "class"</OnLoad></Scripts>
</Button>
<Button name="WhoFrameButton1" inherits="BenillaFriendsFrameWhoButtonTemplate" id="1">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrame"><Offset><AbsDimension x="15" y="-95"/></Offset></Anchor></Anchors>
</Button>
<Button name="WhoFrameButton2" inherits="BenillaFriendsFrameWhoButtonTemplate" id="2">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton1" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton3" inherits="BenillaFriendsFrameWhoButtonTemplate" id="3">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton2" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton4" inherits="BenillaFriendsFrameWhoButtonTemplate" id="4">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton3" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton5" inherits="BenillaFriendsFrameWhoButtonTemplate" id="5">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton4" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton6" inherits="BenillaFriendsFrameWhoButtonTemplate" id="6">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton5" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton7" inherits="BenillaFriendsFrameWhoButtonTemplate" id="7">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton6" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton8" inherits="BenillaFriendsFrameWhoButtonTemplate" id="8">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton7" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton9" inherits="BenillaFriendsFrameWhoButtonTemplate" id="9">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton8" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton10" inherits="BenillaFriendsFrameWhoButtonTemplate" id="10">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton9" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton11" inherits="BenillaFriendsFrameWhoButtonTemplate" id="11">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton10" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton12" inherits="BenillaFriendsFrameWhoButtonTemplate" id="12">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton11" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton13" inherits="BenillaFriendsFrameWhoButtonTemplate" id="13">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton12" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton14" inherits="BenillaFriendsFrameWhoButtonTemplate" id="14">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton13" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton15" inherits="BenillaFriendsFrameWhoButtonTemplate" id="15">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton14" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton16" inherits="BenillaFriendsFrameWhoButtonTemplate" id="16">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton15" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameButton17" inherits="BenillaFriendsFrameWhoButtonTemplate" id="17">
<Anchors><Anchor point="TOPLEFT" relativeTo="WhoFrameButton16" relativePoint="BOTTOMLEFT"/></Anchors>
</Button>
<Button name="WhoFrameGroupInviteButton" inherits="BenillaFriendsPanelButtonTemplate" text="Group Invite">
<Size><AbsDimension x="120" y="22"/></Size>
<Anchors><Anchor point="BOTTOMRIGHT"><Offset><AbsDimension x="-40" y="82"/></Offset></Anchor></Anchors>
<Scripts><OnClick>InviteByName(WhoFrame.selectedName)</OnClick></Scripts>
</Button>
<Button name="WhoFrameAddFriendButton" inherits="BenillaFriendsPanelButtonTemplate" text="Add Friend">
<Size><AbsDimension x="120" y="22"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="WhoFrameGroupInviteButton" relativePoint="LEFT"/></Anchors>
<Scripts><OnClick>AddFriend(WhoFrame.selectedName)</OnClick></Scripts>
</Button>
<Button name="WhoFrameWhoButton" inherits="BenillaFriendsPanelButtonTemplate" text="Refresh">
<Size><AbsDimension x="85" y="22"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="WhoFrameAddFriendButton" relativePoint="LEFT"/></Anchors>
<Scripts>
<OnClick>
WhoFrameEditBox_OnEnterPressed()
WhoFrame.selectedWho = nil
</OnClick>
</Scripts>
</Button>
<EditBox name="WhoFrameEditBox" autoFocus="false" historyLines="32">
<Size><AbsDimension x="296" y="32"/></Size>
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="-20" y="100"/></Offset></Anchor></Anchors>
<Scripts>
<OnShow>this:ClearFocus()</OnShow>
<OnEnterPressed>WhoFrameEditBox_OnEnterPressed()</OnEnterPressed>
<OnEscapePressed>this:ClearFocus()</OnEscapePressed>
</Scripts>
<FontString inherits="ChatFontNormal"/>
</EditBox>
<Frame name="WhoListScrollFrame" inherits="FauxScrollFrameTemplate">
<Size><AbsDimension x="296" y="287"/></Size>
<Anchors><Anchor point="TOPRIGHT" relativeTo="FriendsFrame" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-67" y="-96"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>self.updateFunc = WhoList_Update</OnLoad></Scripts>
</Frame>
</Frames>
<Scripts>
<!-- SetWhoToUI decides where the NEXT answer goes: this frame, or the chat
window (ref l.1707-1717). -->
<OnLoad>SetWhoToUI(0)</OnLoad>
<OnShow>SetWhoToUI(1)</OnShow>
<OnHide>SetWhoToUI(0)</OnHide>
<OnMouseWheel>BenillaFauxScrollFrame_OnMouseWheel(WhoListScrollFrame, arg1)</OnMouseWheel>
</Scripts>
</Frame>
<!-- ── Tab 3: the guild pane (ref l.1719-2450) ──────────────────────────────────────
TWO row frames over ONE scroll frame — `GuildPlayerStatusFrame` (name/zone/level/
class) and `GuildStatusFrame` (name/rank/note/last-online) — with the little page
button between the headers and the list flipping between them. Both are 13 rows,
both hidden at load; `GuildStatus_Update` shows exactly one. -->
<Frame name="GuildFrame" setAllPoints="true" hidden="true">
<Layers>
<Layer level="ARTWORK">
<FontString name="GuildFrameTotals" inherits="GameFontNormalSmall" justifyH="LEFT">
<Size><AbsDimension x="0" y="16"/></Size>
<Anchors><Anchor point="BOTTOM"><Offset><AbsDimension x="-122" y="181"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildFrameOnlineTotals" inherits="GameFontNormalSmall" justifyH="LEFT">
<Size><AbsDimension x="0" y="16"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameTotals" relativePoint="RIGHT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildFrameNotesLabel" inherits="GameFontNormalSmall" justifyH="LEFT" text="GUILD_MOTD_LABEL">
<Size><AbsDimension x="225" y="11"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="23" y="-344"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildFrameNotesText" inherits="GameFontHighlightSmall" justifyH="LEFT" justifyV="TOP">
<Size><AbsDimension x="315" y="45"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameNotesLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-3"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<!-- The filter-border box at the top right and its Show Offline Members
checkbox. Two reference oddities, both kept rather than tidied:
· the name says LFG (a leftover from a Looking-For-Group filter that this
patch no longer has) while its only content is the offline toggle;
· the CheckButton inside carries `virtual="true"` — which does NOTHING
here. `virtual` is only read by the TOP-LEVEL file loader (wow-5875-re
rf24, `0x6ede10`); a `<Frames>` child goes straight to the instantiator
`0x6ee280` via `LoadChildFrames 0x76a060` (rf26), which never looks at
the attribute. So the box is a real frame in the reference and a real
frame here — our loader has the same shape (loader/mod.rs step 7) — and
`RegisterForSave("SHOW_OFFLINE_GUILD_MEMBERS")` in its OnLoad really
does run, which is what makes that variable saved at all. -->
<Frame name="GuildFrameLFGFrame">
<Size><AbsDimension x="210" y="23"/></Size>
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-42" y="-38"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture name="GuildFrameLFGFrameRight" file="Interface\ClassTrainerFrame\UI-ClassTrainer-FilterBorder">
<Size><AbsDimension x="12" y="28"/></Size>
<Anchors><Anchor point="TOPRIGHT"/></Anchors>
<TexCoords left="0.90625" right="1.0" top="0" bottom="1.0"/>
</Texture>
<Texture name="GuildFrameLFGFrameMiddle" file="Interface\ClassTrainerFrame\UI-ClassTrainer-FilterBorder">
<Size><AbsDimension x="186" y="28"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="GuildFrameLFGFrameRight" relativePoint="LEFT"/></Anchors>
<TexCoords left="0.09375" right="0.90625" top="0" bottom="1.0"/>
</Texture>
<Texture name="GuildFrameLFGFrameLeft" file="Interface\ClassTrainerFrame\UI-ClassTrainer-FilterBorder">
<Size><AbsDimension x="12" y="28"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="GuildFrameLFGFrameMiddle" relativePoint="LEFT"/></Anchors>
<TexCoords left="0" right="0.09375" top="0" bottom="1.0"/>
</Texture>
</Layer>
</Layers>
<Frames>
<CheckButton name="GuildFrameLFGButton" virtual="true">
<Size><AbsDimension x="20" y="20"/></Size>
<Anchors><Anchor point="RIGHT"><Offset><AbsDimension x="-8" y="0"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="ARTWORK">
<FontString name="GuildFrameLFGButtonText" inherits="GameFontHighlightSmall" text="SHOW_OFFLINE_MEMBERS">
<Anchors><Anchor point="RIGHT" relativePoint="LEFT"><Offset><AbsDimension x="-10" y="1"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnLoad>
RegisterForSave("SHOW_OFFLINE_GUILD_MEMBERS")
this:RegisterEvent("VARIABLES_LOADED")
</OnLoad>
<OnEvent>
if event == "VARIABLES_LOADED" then
SetGuildRosterShowOffline(SHOW_OFFLINE_GUILD_MEMBERS)
this:SetChecked(GetGuildRosterShowOffline())
end
</OnEvent>
<!-- Toggling the filter DROPS THE SELECTION first: the roster
is about to be re-ordered, so index 7 is no longer the
member index 7 was. The sound is the reference's inverted
pair again (GetChecked already reports the new state). -->
<OnClick>BenillaGuildOfflineToggle_OnClick(self:GetChecked())</OnClick>
</Scripts>
<NormalTexture file="Interface\Buttons\UI-CheckBox-Up"/>
<PushedTexture file="Interface\Buttons\UI-CheckBox-Down"/>
<HighlightTexture file="Interface\Buttons\UI-CheckBox-Highlight" alphaMode="ADD"/>
<CheckedTexture file="Interface\Buttons\UI-CheckBox-Check"/>
<DisabledCheckedTexture file="Interface\Buttons\UI-CheckBox-Check-Disabled"/>
</CheckButton>
</Frames>
</Frame>
<!-- View A: name / zone / level / class. -->
<Frame name="GuildPlayerStatusFrame" hidden="true">
<Size><AbsDimension x="300" y="200"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
<Frames>
<!-- Each header's OnLoad calls `WhoFrameColumn_SetWidth(w)` with NO
frame, leaning on the ref's `frame = this` default. -->
<Button name="GuildFrameColumnHeader1" inherits="BenillaGuildFrameColumnHeaderTemplate" text="NAME">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="20" y="-70"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(83); this.sortType = "name"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameColumnHeader2" inherits="BenillaGuildFrameColumnHeaderTemplate" text="ZONE">
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameColumnHeader1" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(105); this.sortType = "zone"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameColumnHeader3" inherits="BenillaGuildFrameColumnHeaderTemplate" text="LEVEL_ABBR">
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameColumnHeader2" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(32); this.sortType = "level"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameColumnHeader4" inherits="BenillaGuildFrameColumnHeaderTemplate" text="CLASS">
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameColumnHeader3" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(92); this.sortType = "class"</OnLoad></Scripts>
</Button>
<!-- 13 rows, the first at (15,-95) off GuildFrame, the rest chained. -->
<Button name="GuildFrameButton1" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="1">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrame"><Offset><AbsDimension x="15" y="-95"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton2" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="2">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton3" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="3">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton4" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="4">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton5" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="5">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton6" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="6">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton7" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="7">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton8" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="8">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton9" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="9">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton8" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton10" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="10">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton11" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="11">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton10" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton12" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="12">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton11" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameButton13" inherits="BenillaFriendsFrameGuildPlayerStatusButtonTemplate" id="13">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton12" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
</Frames>
</Frame>
<!-- View B: name / rank / note / last-online.
Rows 2-13 anchor to `GuildFrameButtonN`, i.e. to the OTHER view's rows,
not to their own siblings. That is the reference's own text (l.2144-2251)
and it is kept rather than corrected: the two views' rows occupy
the identical 13 seats, so the chain lands in exactly the right place, and
"fixing" it would be an invention with no visible difference. It is only a
hazard if the two views ever stop being the same shape. -->
<Frame name="GuildStatusFrame" hidden="true">
<Size><AbsDimension x="300" y="200"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
<Frames>
<Button name="GuildFrameGuildStatusColumnHeader1" inherits="BenillaGuildFrameColumnHeaderTemplate" text="NAME">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="20" y="-70"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(83); this.sortType = "name"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameGuildStatusColumnHeader2" inherits="BenillaGuildFrameColumnHeaderTemplate" text="RANK">
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameGuildStatusColumnHeader1" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(75); this.sortType = "rank"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameGuildStatusColumnHeader3" inherits="BenillaGuildFrameColumnHeaderTemplate" text="LABEL_NOTE">
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameGuildStatusColumnHeader2" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(75); this.sortType = "note"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameGuildStatusColumnHeader4" inherits="BenillaGuildFrameColumnHeaderTemplate" text="LASTONLINE">
<Anchors><Anchor point="LEFT" relativeTo="GuildFrameGuildStatusColumnHeader3" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>WhoFrameColumn_SetWidth(75); this.sortType = "online"</OnLoad></Scripts>
</Button>
<Button name="GuildFrameGuildStatusButton1" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="1">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrame"><Offset><AbsDimension x="15" y="-95"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton2" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="2">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton3" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="3">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton4" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="4">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton5" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="5">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton6" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="6">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton7" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="7">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton8" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="8">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton9" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="9">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton8" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton10" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="10">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton11" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="11">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton10" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton12" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="12">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton11" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildFrameGuildStatusButton13" inherits="BenillaFriendsFrameGuildStatusButtonTemplate" id="13">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrameButton12" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</Button>
</Frames>
</Frame>
<!-- The shared faux scroll. A `<Frame>`, not the ref's `<ScrollFrame>`, and
driven by `updateFunc` + the pane's OnMouseWheel rather than the ref's
`<OnVerticalScroll>` — this house's FauxScrollFrameTemplate is a plain
Frame over its own scroll bar (decisions 0247/0250/0251), which is also
why the ref's two loose UI-Character-ScrollBar trough textures are omitted:
our kit draws a complete bar and they would double it. The other three
lists in this file are built exactly the same way. -->
<Frame name="GuildListScrollFrame" inherits="FauxScrollFrameTemplate">
<Size><AbsDimension x="296" y="237"/></Size>
<Anchors><Anchor point="TOPRIGHT" relativeTo="GuildFrame" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-67" y="-98"/></Offset></Anchor></Anchors>
<Scripts><OnLoad>self.updateFunc = GuildStatus_Update</OnLoad></Scripts>
</Frame>
<!-- The page button that flips the two views. Its LEFT anchor is re-set by
`GuildStatus_Update` to 284 or 307 depending on whether the scroll bar is
showing, so the (245,-67) here is only what it wears until the first
repaint. -->
<Button name="GuildFrameGuildListToggleButton">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors><Anchor point="LEFT"><Offset><AbsDimension x="245" y="-67"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>
GuildFrameGuildListToggleButton_OnClick()
PlaySound("igMainMenuOptionCheckBoxOn")
</OnClick>
</Scripts>
<NormalTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Up"/>
<PushedTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Down"/>
<DisabledTexture file="Interface\Buttons\UI-SpellbookIcon-NextPage-Disabled"/>
<HighlightTexture file="Interface\Buttons\UI-Common-MouseHilight" alphaMode="ADD"/>
<ButtonText>
<Anchors><Anchor point="RIGHT"><Offset><AbsDimension x="-32" y="0"/></Offset></Anchor></Anchors>
</ButtonText>
<NormalFont inherits="GameFontNormalSmall"/>
<PushedTextOffset><AbsDimension x="0" y="0"/></PushedTextOffset>
</Button>
<!-- The three action buttons along the bottom, right to left. -->
<Button name="GuildFrameControlButton" inherits="UIPanelButtonTemplate" text="GUILDCONTROL">
<Size><AbsDimension x="104" y="22"/></Size>
<Anchors><Anchor point="BOTTOMRIGHT"><Offset><AbsDimension x="-39" y="82"/></Offset></Anchor></Anchors>
<Scripts>
<OnUpdate>GuildFrameControlButton_OnUpdate()</OnUpdate>
<OnClick>
if GuildControlPopupFrame:IsVisible() then
GuildControlPopupFrame:Hide()
else
GuildControlPopupFrame:Show()
end
</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, GUILDCONTROL, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILDCONTROL, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
<Button name="GuildFrameAddMemberButton" inherits="UIPanelButtonTemplate" text="ADDMEMBER">
<Size><AbsDimension x="98" y="22"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="GuildFrameControlButton" relativePoint="LEFT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>StaticPopup_Show("ADD_GUILDMEMBER")</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, ADDMEMBER, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_ADDMEMBER, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
<Button name="GuildFrameGuildInformationButton" inherits="UIPanelButtonTemplate" text="GUILD_INFORMATION">
<Size><AbsDimension x="123" y="22"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="GuildFrameAddMemberButton" relativePoint="LEFT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>ToggleGuildInfoFrame()</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, GUILD_INFORMATION, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILD_INFORMATION, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
<!-- An invisible button laid exactly over the MOTD text: the message of the
day is a FontString, so this is what makes it clickable. Enabled or
disabled by the repaint off `CanEditMOTD`. -->
<Button name="GuildMOTDEditButton">
<Anchors>
<Anchor point="TOPLEFT" relativeTo="GuildFrameNotesText"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
<Anchor point="BOTTOMRIGHT" relativeTo="GuildFrameNotesText"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor>
</Anchors>
<Scripts>
<OnClick>StaticPopup_Show("SET_GUILDMOTD")</OnClick>
</Scripts>
</Button>
</Frames>
<Scripts>
<!-- Showing the pane ASKS for the roster: unlike the friend list, the guild
roster never arrives unasked. -->
<OnShow>GuildRoster()</OnShow>
<OnHide>BenillaGuild_HideSatellitesExcept("GuildInfoFrame")</OnHide>
<OnMouseWheel>BenillaFauxScrollFrame_OnMouseWheel(GuildListScrollFrame, arg1)</OnMouseWheel>
</Scripts>
</Frame>
<!-- ── Guild Control: the rank editor (ref l.2451-2853) ─────────────────────────────
`parent="UIParent"` and `toplevel`, so it floats free of the pane and outlives a
tab switch (FriendsFrame_OnHide is what closes it). Thirteen checkboxes in two
columns — ODDS down the left (1,3,5,7,9,11,13), EVENS down the right (2,4,…,12) —
which is why checkbox 2 anchors 115px right of checkbox 1 and each column chains
downward from there. -->
<Frame name="GuildControlPopupFrame" toplevel="true" parent="UIParent" movable="true" enableMouse="true" hidden="true">
<Size><AbsDimension x="297" y="298"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrame" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-35" y="-65"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture file="Interface\MacroFrame\MacroPopup-TopLeft">
<Size><AbsDimension x="256" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
</Texture>
<Texture file="Interface\MacroFrame\MacroPopup-TopRight">
<Size><AbsDimension x="64" y="256"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="256" y="0"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\MacroFrame\MacroPopup-BotLeft">
<Size><AbsDimension x="256" y="64"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="0" y="-256"/></Offset></Anchor></Anchors>
</Texture>
<Texture file="Interface\MacroFrame\MacroPopup-BotRight">
<Size><AbsDimension x="64" y="64"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="256" y="-256"/></Offset></Anchor></Anchors>
</Texture>
<FontString inherits="GameFontNormal" text="GUILDCONTROL_SELECTRANK">
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="-15"/></Offset></Anchor></Anchors>
</FontString>
<FontString inherits="GameFontHighlightSmall" text="GUILDCONTROL_ALLOWRANK">
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="-106"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Frames>
<Frame name="GuildControlPopupFrameCheckboxes">
<Size><AbsDimension x="300" y="500"/></Size>
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
<Frames>
<Frame name="GuildControlPopupFrameDropDown" inherits="UIDropDownMenuTemplate">
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="0" y="-30"/></Offset></Anchor></Anchors>
<HitRectInsets><AbsInset left="0" right="20" top="0" bottom="0"/></HitRectInsets>
<Scripts>
<OnLoad>GuildControlPopupFrameDropDown_OnLoad()</OnLoad>
</Scripts>
</Frame>
<Button name="GuildControlPopupFrameAddRankButton">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildControlPopupFrameDropDown" relativePoint="RIGHT"><Offset><AbsDimension x="-15" y="1"/></Offset></Anchor></Anchors>
<Scripts>
<OnUpdate>GuildControlPopupFrameAddRankButton_OnUpdate()</OnUpdate>
<OnClick>StaticPopup_Show("ADD_GUILDRANK")</OnClick>
<OnEnter>
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(GUILDADDRANK_BUTTON_TOOLTIP)
</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalTexture file="Interface\Buttons\UI-PlusButton-Up"/>
<PushedTexture file="Interface\Buttons\UI-PlusButton-Down"/>
<DisabledTexture file="Interface\Buttons\UI-PlusButton-Disabled"/>
<HighlightTexture file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD"/>
</Button>
<Button name="GuildControlPopupFrameRemoveRankButton">
<Size><AbsDimension x="16" y="16"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildControlPopupFrameAddRankButton" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnUpdate>GuildControlPopupFrameRemoveRankButton_OnUpdate()</OnUpdate>
<OnClick>GuildControlPopupFrameRemoveRankButton_OnClick()</OnClick>
<OnEnter>
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
GameTooltip:SetText(GUILDREMOVERANK_BUTTON_TOOLTIP)
</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<!-- The minus button's HIGHLIGHT is the PLUS button's art, in the
reference too. Not a typo of ours. -->
<NormalTexture file="Interface\Buttons\UI-MinusButton-Up"/>
<PushedTexture file="Interface\Buttons\UI-MinusButton-Down"/>
<DisabledTexture file="Interface\Buttons\UI-MinusButton-Disabled"/>
<HighlightTexture file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD"/>
</Button>
<CheckButton name="GuildControlPopupFrameCheckbox1" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="1">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="25" y="-123"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox3" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="3">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox1" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox5" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="5">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox3" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox7" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="7">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox5" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox9" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="9">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox7" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox11" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="11">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox9" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox13" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="13">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox11" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox2" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="2">
<Anchors><Anchor point="LEFT" relativeTo="GuildControlPopupFrameCheckbox1" relativePoint="RIGHT"><Offset><AbsDimension x="115" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox4" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="4">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox2" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox6" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="6">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox4" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox8" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="8">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox6" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox10" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="10">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox8" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
<CheckButton name="GuildControlPopupFrameCheckbox12" inherits="BenillaGuildControlPopupFrameCheckboxTemplate" id="12">
<Anchors><Anchor point="TOP" relativeTo="GuildControlPopupFrameCheckbox10" relativePoint="BOTTOM"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
</CheckButton>
</Frames>
</Frame>
<Button name="GuildControlPopupFrameCancelButton" inherits="UIPanelButtonTemplate" text="CANCEL">
<Size><AbsDimension x="78" y="22"/></Size>
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="GuildControlPopupFrame"><Offset><AbsDimension x="-11" y="13"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>this:GetParent():Hide()</OnClick>
</Scripts>
</Button>
<Button name="GuildControlPopupAcceptButton" inherits="UIPanelButtonTemplate" text="ACCEPT">
<Size><AbsDimension x="78" y="22"/></Size>
<Anchors><Anchor point="RIGHT" relativeTo="GuildControlPopupFrameCancelButton" relativePoint="LEFT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>GuildControlPopupAcceptButton_OnClick()</OnClick>
</Scripts>
</Button>
<!-- The rank NAME box. Typing in it enables Accept, because renaming a rank is
as much an edit as ticking a box. -->
<EditBox name="GuildControlPopupFrameEditBox" autoFocus="false" historyLines="1" letters="15">
<Size><AbsDimension x="130" y="32"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="35" y="-68"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="BACKGROUND">
<Texture file="Interface\ChatFrame\UI-ChatInputBorder-Left">
<Size><AbsDimension x="75" y="32"/></Size>
<Anchors><Anchor point="LEFT"><Offset><AbsDimension x="-10" y="0"/></Offset></Anchor></Anchors>
<TexCoords left="0" right="0.29296875" top="0" bottom="1.0"/>
</Texture>
<Texture file="Interface\ChatFrame\UI-ChatInputBorder-Right">
<Size><AbsDimension x="75" y="32"/></Size>
<Anchors><Anchor point="RIGHT"><Offset><AbsDimension x="10" y="0"/></Offset></Anchor></Anchors>
<TexCoords left="0.70703125" right="1.0" top="0" bottom="1.0"/>
</Texture>
<FontString inherits="GameFontNormal" text="GUILDCONTROL_RANKLABEL">
<Anchors><Anchor point="RIGHT" relativeTo="GuildControlPopupFrameEditBox" relativePoint="LEFT"><Offset><AbsDimension x="-12" y="1"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Scripts>
<OnShow>
this:SetText(GuildControlGetRankName(1))
this:ClearFocus()
</OnShow>
<OnEditFocusGained>GuildControlPopup_MarkDirty()</OnEditFocusGained>
<OnEnterPressed>
self:ClearFocus()
GuildControlPopup_MarkDirty()
</OnEnterPressed>
<OnEscapePressed>this:ClearFocus()</OnEscapePressed>
</Scripts>
<FontString inherits="ChatFontNormal"/>
</EditBox>
</Frames>
<Scripts>
<OnLoad>GuildControlPopupFrame_OnLoad()</OnLoad>
<OnShow>GuildControlPopupFrame_OnShow()</OnShow>
<OnHide>GuildControlPopupFrame_OnHide()</OnHide>
</Scripts>
</Frame>
<!-- ── Guild Information: the free-text notice board (ref l.2854-3070) ──────────────
A REAL scroll frame (UIPanelScrollFrameTemplate) around a 500-letter multiline
edit box, not a faux list — this is prose, not rows. Whether it is writable is
decided in the background frame's OnShow off `CanEditGuildInfo`: a rank that may
not edit gets grey text, a mouse-dead box and a disabled Accept. -->
<Frame name="GuildInfoFrame" toplevel="true" enableMouse="true" hidden="true">
<Size><AbsDimension x="297" y="298"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildControlPopupFrame"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="OVERLAY">
<Texture name="GuildInfoCorner" file="Interface\DialogFrame\UI-DialogBox-Corner">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-6" y="-7"/></Offset></Anchor></Anchors>
</Texture>
<FontString name="GuildInfoTitle" inherits="GameFontNormal" text="GUILD_INFORMATION">
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="17" y="-17"/></Offset></Anchor></Anchors>
</FontString>
<Texture file="Interface\FriendsFrame\UI-GuildMember-Patch">
<Size><AbsDimension x="375" y="32"/></Size>
<Anchors><Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="12" y="3"/></Offset></Anchor></Anchors>
</Texture>
</Layer>
</Layers>
<Frames>
<Frame name="GuildInfoTextBackground">
<Size><AbsDimension x="276" y="230"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="11" y="-32"/></Offset></Anchor></Anchors>
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
<EdgeSize><AbsValue val="16"/></EdgeSize>
<TileSize><AbsValue val="16"/></TileSize>
<BackgroundInsets><AbsInset left="5" right="5" top="5" bottom="5"/></BackgroundInsets>
</Backdrop>
<Frames>
<ScrollFrame name="GuildInfoFrameScrollFrame" inherits="UIPanelScrollFrameTemplate">
<Size><AbsDimension x="243" y="218"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="5" y="-7"/></Offset></Anchor></Anchors>
<Scripts>
<OnMouseDown>GuildInfoFrame_ClaimFocus()</OnMouseDown>
<OnMouseUp>GuildInfoFrame_ClaimFocus()</OnMouseUp>
</Scripts>
<ScrollChild>
<EditBox name="GuildInfoEditBox" letters="500" multiLine="true" autoFocus="false">
<Size><AbsDimension x="240" y="218"/></Size>
<Scripts>
<OnEscapePressed>this:ClearFocus()</OnEscapePressed>
<!-- Keeps the caret in view while typing past the
bottom: re-measure, and if the range GREW, jump
the bar to the new maximum. The `this.max ~= max`
memo is what stops it fighting a hand scroll. -->
<OnTextChanged>GuildInfoEditBox_FollowCaret(self)</OnTextChanged>
</Scripts>
<FontString inherits="GameFontHighlight"/>
</EditBox>
</ScrollChild>
</ScrollFrame>
</Frames>
<Scripts>
<OnLoad>BenillaGuildPane_TooltipBackdrop(self)</OnLoad>
<OnShow>GuildInfoFrame_Update()</OnShow>
</Scripts>
</Frame>
<Button name="GuildInfoCloseButton" inherits="UIPanelCloseButton">
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-3" y="-3"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildInfoSaveButton" inherits="UIPanelButtonTemplate" text="ACCEPT">
<Size><AbsDimension x="139" y="22"/></Size>
<Anchors><Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="10" y="12"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>GuildInfoFrame_Save()</OnClick>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
<Button name="GuildInfoCancelButton" inherits="UIPanelButtonTemplate" text="CLOSE">
<Size><AbsDimension x="139" y="22"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildInfoSaveButton" relativePoint="RIGHT"><Offset><AbsDimension x="0" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>GuildInfoFrame:Hide()</OnClick>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
</Frames>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
<TileSize><AbsValue val="32"/></TileSize>
<EdgeSize><AbsValue val="32"/></EdgeSize>
</Backdrop>
</Frame>
<!-- ── The member detail card (ref l.3071-3438) ─────────────────────────────────────
Opened by a left-click on a roster row, closed by clicking that same row again.
Its HEIGHT is not fixed: `GuildStatus_Update` swaps between 195 and 255 depending
on whether this rank may see officer notes, so the two note panes below are the
only reason the card has two sizes.
The promote/demote arrows hang OUTSIDE the card (LEFT of its RIGHT edge, -60/+50)
— deliberately, in the reference: they are rank verbs, not card fields. -->
<Frame name="GuildMemberDetailFrame" toplevel="true" enableMouse="true" hidden="true">
<Size><AbsDimension x="212" y="270"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildFrame" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-33" y="-28"/></Offset></Anchor></Anchors>
<Backdrop bgFile="Interface\DialogFrame\UI-DialogBox-Background" edgeFile="Interface\DialogFrame\UI-DialogBox-Border" tile="true">
<BackgroundInsets><AbsInset left="11" right="12" top="12" bottom="11"/></BackgroundInsets>
<TileSize><AbsValue val="32"/></TileSize>
<EdgeSize><AbsValue val="32"/></EdgeSize>
</Backdrop>
<Layers>
<Layer level="ARTWORK">
<FontString name="GuildMemberDetailName" inherits="GameFontNormal">
<Size><AbsDimension x="0" y="12"/></Size>
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="17" y="-18"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailLevel" inherits="GameFontHighlightSmall">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailName" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailZoneLabel" inherits="GameFontNormalSmall" text="ZONE_COLON">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailLevel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-11"/></Offset></Anchor></Anchors>
</FontString>
<!-- `<Size x= y=>` on the element, not a nested `<AbsDimension>` — the
reference's own spelling here and the one place in this window it
uses it. Both forms mean the same to the loader (rf24 `0x6f1eb0`). -->
<FontString name="GuildMemberDetailZoneText" inherits="GameFontHighlight">
<Size x="147" y="12"/>
<Anchors><Anchor point="LEFT" relativeTo="GuildMemberDetailZoneLabel" relativePoint="RIGHT"><Offset><AbsDimension x="2" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailRankLabel" inherits="GameFontNormalSmall" text="RANK_COLON">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailZoneLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-8"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailRankText" inherits="GameFontHighlight">
<Anchors><Anchor point="LEFT" relativeTo="GuildMemberDetailRankLabel" relativePoint="RIGHT"><Offset><AbsDimension x="2" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailOnlineLabel" inherits="GameFontNormalSmall" text="LAST_ONLINE_COLON">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailRankLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-8"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailOnlineText" inherits="GameFontHighlight">
<Anchors><Anchor point="LEFT" relativeTo="GuildMemberDetailOnlineLabel" relativePoint="RIGHT"><Offset><AbsDimension x="2" y="0"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailNoteLabel" inherits="GameFontNormalSmall" text="NOTE_COLON">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailOnlineLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-8"/></Offset></Anchor></Anchors>
</FontString>
<FontString name="GuildMemberDetailOfficerNoteLabel" inherits="GameFontNormalSmall" text="OFFICER_NOTE_COLON">
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailNoteLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-43"/></Offset></Anchor></Anchors>
</FontString>
<Texture file="Interface\FriendsFrame\UI-GuildMember-Patch">
<Size><AbsDimension x="256" y="32"/></Size>
<Anchors><Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="12" y="3"/></Offset></Anchor></Anchors>
</Texture>
</Layer>
<Layer level="OVERLAY">
<Texture name="GuildMemberDetailCorner" file="Interface\DialogFrame\UI-DialogBox-Corner">
<Size><AbsDimension x="32" y="32"/></Size>
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-6" y="-7"/></Offset></Anchor></Anchors>
</Texture>
</Layer>
</Layers>
<Frames>
<Button name="GuildMemberDetailCloseButton" inherits="UIPanelCloseButton">
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-3" y="-3"/></Offset></Anchor></Anchors>
</Button>
<Button name="GuildMemberRemoveButton" inherits="UIPanelButtonTemplate" text="REMOVE">
<Size><AbsDimension x="96" y="22"/></Size>
<Anchors><Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="10" y="12"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>StaticPopup_Show("REMOVE_GUILDMEMBER")</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, REMOVE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GUILDREMOVE, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
<Button name="GuildMemberGroupInviteButton" inherits="UIPanelButtonTemplate" text="GROUP_INVITE">
<Size><AbsDimension x="96" y="22"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildMemberRemoveButton" relativePoint="RIGHT"><Offset><AbsDimension x="1" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>InviteByName(GuildFrame.selectedName)</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, GROUP_INVITE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_GROUPINVITE, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalFont inherits="GameFontNormalSmall"/>
<HighlightFont inherits="GameFontHighlightSmall"/>
<DisabledFont inherits="GameFontDisableSmall"/>
</Button>
<!-- Both arrows DISABLE THEMSELVES on click: the promote is in flight and the
roster has not come back yet, so a second click would send a second
promote. The repaint re-enables them. `<Offset x= y=>` is the reference's
attribute spelling again. -->
<Button name="GuildFramePromoteButton">
<Size><AbsDimension x="28" y="28"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildMemberDetailFrame" relativePoint="RIGHT"><Offset x="-60" y="50"/></Anchor></Anchors>
<HitRectInsets><AbsInset left="6" right="6" top="7" bottom="7"/></HitRectInsets>
<Scripts>
<OnClick>
GuildPromoteByName(GuildFrame.selectedName)
PlaySound("UChatScrollButton")
GuildFramePromoteButton:Disable()
</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, PROMOTE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_PROMOTE, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Up"/>
<PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Down"/>
<DisabledTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Disabled"/>
<HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollUpButton-Highlight"/>
</Button>
<Button name="GuildFrameDemoteButton">
<Size><AbsDimension x="28" y="28"/></Size>
<Anchors><Anchor point="LEFT" relativeTo="GuildFramePromoteButton" relativePoint="RIGHT"><Offset><AbsDimension x="-8" y="0"/></Offset></Anchor></Anchors>
<HitRectInsets><AbsInset left="6" right="6" top="7" bottom="7"/></HitRectInsets>
<Scripts>
<OnClick>
GuildDemoteByName(GuildFrame.selectedName)
PlaySound("UChatScrollButton")
GuildFrameDemoteButton:Disable()
</OnClick>
<OnEnter>BenillaTooltip_AddNewbieTipFor(self, DEMOTE, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_DEMOTE, 1)</OnEnter>
<OnLeave>GameTooltip:Hide()</OnLeave>
</Scripts>
<NormalTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Up"/>
<PushedTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Down"/>
<DisabledTexture file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Disabled"/>
<HighlightTexture alphaMode="ADD" file="Interface\MainMenuBar\UI-MainMenu-ScrollDownButton-Highlight"/>
</Button>
<!-- The two note panes. The PUBLIC one carries `enableMouse="true"` in the XML
and the OFFICER one does not — the reference's asymmetry, and it is not an
oversight: `GuildStatus_Update` calls `EnableMouse(CanEdit…Note())` on
BOTH every repaint, so the XML value is only what they wear before the
first one. -->
<Frame name="GuildMemberNoteBackground" enableMouse="true">
<Size><AbsDimension x="181" y="40"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailNoteLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="ARTWORK">
<FontString name="PersonalNoteText" inherits="GameFontHighlight" justifyH="LEFT" justifyV="TOP">
<Size><AbsDimension x="165" y="32"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="1" y="-6"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
<EdgeSize><AbsValue val="16"/></EdgeSize>
<TileSize><AbsValue val="16"/></TileSize>
<BackgroundInsets><AbsInset left="5" right="5" top="5" bottom="5"/></BackgroundInsets>
</Backdrop>
<Scripts>
<OnLoad>BenillaGuildPane_TooltipBackdrop(self, 0.5, 0.25)</OnLoad>
<OnMouseUp>StaticPopup_Show("SET_GUILDPLAYERNOTE")</OnMouseUp>
</Scripts>
</Frame>
<Frame name="GuildMemberOfficerNoteBackground">
<Size><AbsDimension x="181" y="40"/></Size>
<Anchors><Anchor point="TOPLEFT" relativeTo="GuildMemberDetailOfficerNoteLabel" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
<Layers>
<Layer level="ARTWORK">
<FontString name="OfficerNoteText" inherits="GameFontHighlight" justifyH="LEFT" justifyV="TOP">
<Size><AbsDimension x="165" y="32"/></Size>
<Anchors><Anchor point="TOP"><Offset><AbsDimension x="1" y="-6"/></Offset></Anchor></Anchors>
</FontString>
</Layer>
</Layers>
<Backdrop bgFile="Interface\Tooltips\UI-Tooltip-Background" edgeFile="Interface\Tooltips\UI-Tooltip-Border" tile="true">
<EdgeSize><AbsValue val="16"/></EdgeSize>
<TileSize><AbsValue val="16"/></TileSize>
<BackgroundInsets><AbsInset left="5" right="5" top="5" bottom="5"/></BackgroundInsets>
</Backdrop>
<Scripts>
<OnLoad>BenillaGuildPane_TooltipBackdrop(self, 0.5, 0.25)</OnLoad>
<OnMouseUp>StaticPopup_Show("SET_GUILDOFFICERNOTE")</OnMouseUp>
</Scripts>
</Frame>
</Frames>
</Frame>
<!-- ── The tab strip (ref l.3439-3540) ──────────────────────────────────────────── -->
<Button name="FriendsFrameTab1" inherits="CharacterFrameTabButtonTemplate" id="1" text="Friends">
<Anchors><Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="11" y="47"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>
PanelTemplates_SetTab(FriendsFrame, this:GetID())
FriendsFrame_OnShow()
PlaySound("igCharacterInfoTab")
</OnClick>
</Scripts>
</Button>
<Button name="FriendsFrameTab2" inherits="CharacterFrameTabButtonTemplate" id="2" text="Who">
<Anchors><Anchor point="LEFT" relativeTo="FriendsFrameTab1" relativePoint="RIGHT"><Offset><AbsDimension x="-14" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>
PanelTemplates_SetTab(FriendsFrame, this:GetID())
FriendsFrame_OnShow()
PlaySound("igCharacterInfoTab")
</OnClick>
</Scripts>
</Button>
<!-- The GUILD tab. It had NO `<Scripts>` at all while the pane did not exist, which
was honest then and would be a dead tab now: `PanelTemplates_EnableTab` would
un-grey a button that does nothing when clicked. Same OnClick as tabs 1 and 2. -->
<Button name="FriendsFrameTab3" inherits="CharacterFrameTabButtonTemplate" id="3" text="Guild">
<Anchors><Anchor point="LEFT" relativeTo="FriendsFrameTab2" relativePoint="RIGHT"><Offset><AbsDimension x="-14" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>
PanelTemplates_SetTab(FriendsFrame, this:GetID())
FriendsFrame_OnShow()
PlaySound("igCharacterInfoTab")
</OnClick>
</Scripts>
</Button>
<!-- The RAID tab (decision 1549). Unlike Guild it carries no enable/disable rule at
all — the reference never greys it, because the pane means something in every
state: solo it explains what a raid is, in a party it offers the conversion, in a
raid it is the roster. -->
<Button name="FriendsFrameTab4" inherits="CharacterFrameTabButtonTemplate" id="4" text="Raid">
<Anchors><Anchor point="LEFT" relativeTo="FriendsFrameTab3" relativePoint="RIGHT"><Offset><AbsDimension x="-14" y="0"/></Offset></Anchor></Anchors>
<Scripts>
<OnClick>
PanelTemplates_SetTab(FriendsFrame, this:GetID())
FriendsFrame_OnShow()
PlaySound("igCharacterInfoTab")
</OnClick>
</Scripts>
</Button>
</Frames>
<Scripts>
<OnLoad>FriendsFrame_OnLoad()</OnLoad>
<OnShow>FriendsFrame_OnShow()</OnShow>
<OnHide>FriendsFrame_OnHide()</OnHide>
<OnEvent>FriendsFrame_OnEvent()</OnEvent>
</Scripts>
</Frame>
<!-- The guild-invite event driver (hidden; the DeathFrame/PartyFrame driver pattern). It
cannot live on FriendsFrame itself: the invite arrives whether or not the social window
has ever been opened, and the pane's own OnEvent arms all gate on visibility. -->
<Frame name="BenillaGuildInviteDriver" parent="UIParent" hidden="true">
<Size><AbsDimension x="1" y="1"/></Size>
<Anchors><Anchor point="TOPLEFT"/></Anchors>
<Scripts>
<OnLoad>
this:RegisterEvent("GUILD_INVITE_REQUEST")
this:RegisterEvent("GUILD_INVITE_CANCEL")
</OnLoad>
<OnEvent>BenillaGuildInviteDriver_OnEvent()</OnEvent>
</Scripts>
</Frame>
</Ui>