Files
Nanami-UI/SocialUI.lua
rucky ec9e3c29d6 完成多出修改
修复拾取界面点击无效问题
修复宠物训练界面不显示训练点问题
新增天赋分享到聊天界面
修复飞行界面无法关闭问题
修复术士宠物的显示问题
为天赋界面添加默认数据库支持
框架现在也可自主选择是否启用
玩家框架和目标框架可取消显示3D头像以及透明度修改
背包和银行也添加透明度自定义支持
优化tooltip性能和背包物品显示方式
修复布局模式在ui缩放后不能正常定位的问题
添加硬核模式危险和死亡的工会通报
添加拾取和已拾取的框体
等等
2026-03-23 10:25:25 +08:00

2671 lines
96 KiB
Lua

--------------------------------------------------------------------------------
-- Nanami-UI: Social UI (SocialUI.lua)
-- Replaces FriendsFrame with modern rounded UI
-- Tabs: Friends/Ignore, Who, Guild, Raid
--------------------------------------------------------------------------------
SFrames = SFrames or {}
SFrames.SocialUI = {}
local SUI = SFrames.SocialUI
SFramesDB = SFramesDB or {}
--------------------------------------------------------------------------------
-- Theme (Pink Cat-Paw)
--------------------------------------------------------------------------------
local T = SFrames.Theme:Extend({
onlineText = { 0.30, 1.0, 0.30 },
offlineText = { 0.50, 0.45, 0.48 },
})
local CLASS_COLORS = {
["WARRIOR"] = { 0.78, 0.61, 0.43 },
["MAGE"] = { 0.41, 0.80, 0.94 },
["ROGUE"] = { 1.00, 0.96, 0.41 },
["DRUID"] = { 1.00, 0.49, 0.04 },
["HUNTER"] = { 0.67, 0.83, 0.45 },
["SHAMAN"] = { 0.14, 0.35, 1.00 },
["PRIEST"] = { 1.00, 1.00, 1.00 },
["WARLOCK"] = { 0.58, 0.51, 0.79 },
["PALADIN"] = { 0.96, 0.55, 0.73 },
}
-- Reverse lookup: localized class name -> English key
local CLASS_NAME_TO_EN = {}
local function BuildClassReverseLookup()
-- Try WoW global tables first
if LOCALIZED_CLASS_NAMES_MALE then
for en, loc in pairs(LOCALIZED_CLASS_NAMES_MALE) do
CLASS_NAME_TO_EN[loc] = en
end
end
if LOCALIZED_CLASS_NAMES_FEMALE then
for en, loc in pairs(LOCALIZED_CLASS_NAMES_FEMALE) do
CLASS_NAME_TO_EN[loc] = en
end
end
-- Hardcoded Chinese fallback
local zhMap = {
["战士"] = "WARRIOR", ["法师"] = "MAGE", ["盗贼"] = "ROGUE",
["德鲁伊"] = "DRUID", ["猎人"] = "HUNTER", ["萨满祭司"] = "SHAMAN",
["牧师"] = "PRIEST", ["术士"] = "WARLOCK", ["圣骑士"] = "PALADIN",
}
for loc, en in pairs(zhMap) do
if not CLASS_NAME_TO_EN[loc] then
CLASS_NAME_TO_EN[loc] = en
end
end
-- Also add English names themselves
for en, _ in pairs(CLASS_COLORS) do
CLASS_NAME_TO_EN[en] = en
CLASS_NAME_TO_EN[string.lower(en)] = en
end
end
--------------------------------------------------------------------------------
-- Chinese -> English search-term translation for SendWho
--------------------------------------------------------------------------------
local WHO_ZH_TO_EN = {
-- Classes
["战士"] = "Warrior", ["法师"] = "Mage", ["盗贼"] = "Rogue",
["德鲁伊"] = "Druid", ["猎人"] = "Hunter", ["萨满祭司"] = "Shaman",
["萨满"] = "Shaman", ["牧师"] = "Priest", ["术士"] = "Warlock",
["圣骑士"] = "Paladin",
-- Races
["人类"] = "Human", ["矮人"] = "Dwarf", ["暗夜精灵"] = "Night Elf",
["侏儒"] = "Gnome", ["兽人"] = "Orc", ["巨魔"] = "Troll",
["亡灵"] = "Undead", ["牛头人"] = "Tauren", ["高等精灵"] = "High Elf",
["哥布林"] = "Goblin",
-- Zones (Alliance)
["暴风城"] = "Stormwind", ["铁炉堡"] = "Ironforge", ["达纳苏斯"] = "Darnassus",
["艾尔文森林"] = "Elwynn Forest", ["西部荒野"] = "Westfall",
["丹莫罗"] = "Dun Morogh", ["洛克莫丹"] = "Loch Modan",
["湿地"] = "Wetlands", ["赤脊山"] = "Redridge Mountains",
["暮色森林"] = "Duskwood", ["荆棘谷"] = "Stranglethorn Vale",
["泰达希尔"] = "Teldrassil", ["黑海岸"] = "Darkshore",
["灰谷"] = "Ashenvale", ["石爪山脉"] = "Stonetalon Mountains",
-- Zones (Horde)
["奥格瑞玛"] = "Orgrimmar", ["雷霆崖"] = "Thunder Bluff",
["幽暗城"] = "Undercity", ["杜隆塔尔"] = "Durotar",
["莫高雷"] = "Mulgore", ["贫瘠之地"] = "The Barrens",
["银松森林"] = "Silverpine Forest", ["提瑞斯法林地"] = "Tirisfal Glades",
["希尔斯布莱德丘陵"] = "Hillsbrad Foothills",
-- Zones (Contested / High-level)
["塔纳利斯"] = "Tanaris", ["菲拉斯"] = "Feralas",
["凄凉之地"] = "Desolace", ["尘泥沼泽"] = "Dustwallow Marsh",
["千针石林"] = "Thousand Needles", ["辛特兰"] = "The Hinterlands",
["阿拉希高地"] = "Arathi Highlands", ["荒芜之地"] = "Badlands",
["灼热峡谷"] = "Searing Gorge", ["燃烧平原"] = "Burning Steppes",
["西瘟疫之地"] = "Western Plaguelands", ["东瘟疫之地"] = "Eastern Plaguelands",
["费伍德森林"] = "Felwood", ["冬泉谷"] = "Winterspring",
["安戈洛环形山"] = "Un'Goro Crater", ["希利苏斯"] = "Silithus",
["艾萨拉"] = "Azshara", ["诅咒之地"] = "Blasted Lands",
["逆风小径"] = "Deadwind Pass", ["悲伤沼泽"] = "Swamp of Sorrows",
-- Dungeons / Raids
["熔火之心"] = "Molten Core", ["黑翼之巢"] = "Blackwing Lair",
["奥妮克希亚的巢穴"] = "Onyxia's Lair", ["祖尔格拉布"] = "Zul'Gurub",
["安其拉"] = "Ahn'Qiraj", ["纳克萨玛斯"] = "Naxxramas",
["黑石深渊"] = "Blackrock Depths", ["黑石塔"] = "Blackrock Spire",
["斯坦索姆"] = "Stratholme", ["通灵学院"] = "Scholomance",
["厄运之槌"] = "Dire Maul", ["玛拉顿"] = "Maraudon",
["祖尔法拉克"] = "Zul'Farrak",
}
local function TranslateWhoQuery(text)
if not text then return "" end
for zh, en in pairs(WHO_ZH_TO_EN) do
text = string.gsub(text, zh, en)
end
return text
end
local CLASS_ICON_PATH = "Interface\\AddOns\\Nanami-UI\\img\\UI-Classes-Circles"
local CLASS_ICON_TCOORDS = {
["WARRIOR"] = { 0, 0.25, 0, 0.25 },
["MAGE"] = { 0.25, 0.49609375, 0, 0.25 },
["ROGUE"] = { 0.49609375, 0.7421875, 0, 0.25 },
["DRUID"] = { 0.7421875, 0.98828125, 0, 0.25 },
["HUNTER"] = { 0, 0.25, 0.25, 0.5 },
["SHAMAN"] = { 0.25, 0.49609375, 0.25, 0.5 },
["PRIEST"] = { 0.49609375, 0.7421875, 0.25, 0.5 },
["WARLOCK"] = { 0.7421875, 0.98828125, 0.25, 0.5 },
["PALADIN"] = { 0, 0.25, 0.5, 0.75 },
}
--------------------------------------------------------------------------------
-- Layout
--------------------------------------------------------------------------------
local FRAME_W = 380
local FRAME_H = 455
local HEADER_H = 30
local TAB_BAR_H = 26
local SIDE_PAD = 10
local CONTENT_W = FRAME_W - SIDE_PAD * 2
local ROW_H = 22
local BOTTOM_H = 30
local SCROLL_STEP = 22
--------------------------------------------------------------------------------
-- State
--------------------------------------------------------------------------------
local MainFrame = nil
local mainTabs = {}
local pages = {}
local currentMainTab = 1
local initialized = false
local friendRows = {}
local ignoreRows = {}
local whoRows = {}
local guildRows = {}
local raidSlots = {}
local selectedFriend = nil
local selectedWho = nil
local selectedGuild = nil
local friendSubTab = "friends"
local guildViewMode = "player"
local guildHideOffline = false
local guildSortField = "name"
local guildSortAsc = true
local friendSearchText = ""
local guildSearchText = ""
local origShowFriendsAPI = nil
local widgetId = 0
local function NextName(p)
widgetId = widgetId + 1
return "SFramesSocial" .. (p or "") .. tostring(widgetId)
end
--------------------------------------------------------------------------------
-- Helpers
--------------------------------------------------------------------------------
local function GetFont()
if SFrames and SFrames.GetFont then return SFrames:GetFont() end
return "Fonts\\ARIALN.TTF"
end
local function SetRoundBackdrop(frame, bgColor, borderColor)
frame:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 14,
insets = { left = 3, right = 3, top = 3, bottom = 3 },
})
local bg = bgColor or T.panelBg
local bd = borderColor or T.panelBorder
frame:SetBackdropColor(bg[1], bg[2], bg[3], bg[4] or 1)
frame:SetBackdropBorderColor(bd[1], bd[2], bd[3], bd[4] or 1)
end
local function SetPixelBackdrop(frame, bgColor, borderColor)
frame:SetBackdrop({
bgFile = "Interface\\Buttons\\WHITE8X8",
edgeFile = "Interface\\Buttons\\WHITE8X8",
tile = false, tileSize = 0, edgeSize = 1,
insets = { left = 1, right = 1, top = 1, bottom = 1 },
})
local bg = bgColor or T.slotBg
local bd = borderColor or T.slotBorder
frame:SetBackdropColor(bg[1], bg[2], bg[3], bg[4] or 1)
frame:SetBackdropBorderColor(bd[1], bd[2], bd[3], bd[4] or 1)
end
local function SetRowNormal(frame)
SetPixelBackdrop(frame, T.rowNormal, T.rowNormalBd)
end
local function AddSelHighlight(row)
local sb = row:CreateTexture(nil, "ARTWORK")
sb:SetTexture("Interface\\Buttons\\WHITE8X8")
sb:SetAllPoints(row)
sb:SetVertexColor(T.slotSelected[1], T.slotSelected[2], T.slotSelected[3], 0.35)
sb:Hide(); row._selBg = sb
local sg = row:CreateTexture(nil, "ARTWORK")
sg:SetTexture("Interface\\Buttons\\WHITE8X8")
sg:SetWidth(4)
sg:SetPoint("TOPLEFT", row, "TOPLEFT", 0, 0)
sg:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 0, 0)
sg:SetVertexColor(1, 0.65, 0.85, 1)
sg:Hide(); row._selGlow = sg
local st = row:CreateTexture(nil, "OVERLAY")
st:SetTexture("Interface\\Buttons\\WHITE8X8")
st:SetHeight(1)
st:SetPoint("TOPLEFT", row, "TOPLEFT", 0, 0)
st:SetPoint("TOPRIGHT", row, "TOPRIGHT", 0, 0)
st:SetVertexColor(T.slotSelected[1], T.slotSelected[2], T.slotSelected[3], 0.8)
st:Hide(); row._selTop = st
local sbo = row:CreateTexture(nil, "OVERLAY")
sbo:SetTexture("Interface\\Buttons\\WHITE8X8")
sbo:SetHeight(1)
sbo:SetPoint("BOTTOMLEFT", row, "BOTTOMLEFT", 0, 0)
sbo:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", 0, 0)
sbo:SetVertexColor(T.slotSelected[1], T.slotSelected[2], T.slotSelected[3], 0.8)
sbo:Hide(); row._selBot = sbo
end
local function ShowSelHighlight(row)
if row._selBg then row._selBg:Show() end
if row._selGlow then row._selGlow:Show() end
if row._selTop then row._selTop:Show() end
if row._selBot then row._selBot:Show() end
end
local function HideSelHighlight(row)
if row._selBg then row._selBg:Hide() end
if row._selGlow then row._selGlow:Hide() end
if row._selTop then row._selTop:Hide() end
if row._selBot then row._selBot:Hide() end
end
local function CreateShadow(parent)
local s = CreateFrame("Frame", nil, parent)
s:SetPoint("TOPLEFT", parent, "TOPLEFT", -4, 4)
s:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", 4, -4)
s:SetFrameLevel(math.max(parent:GetFrameLevel() - 1, 0))
s:SetBackdrop({
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
tile = true, tileSize = 16, edgeSize = 16,
insets = { left = 4, right = 4, top = 4, bottom = 4 },
})
s:SetBackdropColor(0, 0, 0, 0.6)
s:SetBackdropBorderColor(0, 0, 0, 0.45)
return s
end
local function MakeFS(parent, size, justifyH, color)
local fs = parent:CreateFontString(nil, "OVERLAY")
fs:SetFont(GetFont(), size or 11, "OUTLINE")
fs:SetJustifyH(justifyH or "LEFT")
local c = color or T.nameText
fs:SetTextColor(c[1], c[2], c[3])
return fs
end
local function MakeSep(parent, y)
local sep = parent:CreateTexture(nil, "ARTWORK")
sep:SetTexture("Interface\\Buttons\\WHITE8X8")
sep:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4])
sep:SetHeight(1)
sep:SetPoint("TOPLEFT", parent, "TOPLEFT", 0, y)
sep:SetPoint("TOPRIGHT", parent, "TOPRIGHT", 0, y)
return sep
end
local function MakeButton(parent, text, w, h)
local btn = CreateFrame("Button", NextName("Btn"), parent)
btn:SetWidth(w or 80)
btn:SetHeight(h or 22)
SetRoundBackdrop(btn, T.btnBg, T.btnBorder)
local fs = MakeFS(btn, 11, "CENTER", T.btnText)
fs:SetPoint("CENTER", 0, 0)
fs:SetText(text or "")
btn.text = fs
btn:SetScript("OnEnter", function()
SetRoundBackdrop(this, T.btnHoverBg, T.tabActiveBorder)
this.text:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3])
end)
btn:SetScript("OnLeave", function()
SetRoundBackdrop(this, T.btnBg, T.btnBorder)
this.text:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
end)
return btn
end
local function MakeEditBox(parent, w, h)
local box = CreateFrame("EditBox", NextName("Edit"), parent)
box:SetWidth(w or 200)
box:SetHeight(h or 22)
box:SetFont(GetFont(), 11, "OUTLINE")
box:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
box:SetAutoFocus(false)
box:SetMaxLetters(256)
SetPixelBackdrop(box, T.inputBg, T.inputBorder)
box:SetTextInsets(6, 6, 0, 0)
box:SetScript("OnEscapePressed", function() this:ClearFocus() end)
return box
end
local customPopup = nil
local function ShowCustomPopup(title, hasInput, onAccept, onCancel)
if not customPopup then
local f = CreateFrame("Frame", "SFramesSocialPopup", UIParent)
f:SetWidth(280)
f:SetHeight(120)
f:SetPoint("CENTER", UIParent, "CENTER", 0, 80)
f:SetFrameStrata("DIALOG")
f:SetFrameLevel(100)
SetRoundBackdrop(f, T.panelBg, T.panelBorder)
CreateShadow(f)
f:EnableMouse(true)
f:SetMovable(true)
f:RegisterForDrag("LeftButton")
f:SetScript("OnDragStart", function() this:StartMoving() end)
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
local titleFS = MakeFS(f, 12, "CENTER", T.headerText)
titleFS:SetPoint("TOP", f, "TOP", 0, -10)
f.titleFS = titleFS
local editBox = CreateFrame("EditBox", "SFramesSocialPopupEdit", f)
editBox:SetWidth(230)
editBox:SetHeight(24)
editBox:SetPoint("TOP", titleFS, "BOTTOM", 0, -10)
editBox:SetFont(GetFont(), 11, "OUTLINE")
editBox:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
editBox:SetAutoFocus(false)
editBox:SetMaxLetters(64)
SetRoundBackdrop(editBox, T.inputBg, T.inputBorder)
editBox:SetTextInsets(8, 8, 4, 4)
editBox:SetScript("OnEscapePressed", function()
this:ClearFocus()
f:Hide()
end)
f.editBox = editBox
local acceptBtn = MakeButton(f, "确定", 100, 24)
acceptBtn:SetPoint("BOTTOMRIGHT", f, "BOTTOM", -4, 10)
f.acceptBtn = acceptBtn
local cancelBtn = MakeButton(f, "取消", 100, 24)
cancelBtn:SetPoint("BOTTOMLEFT", f, "BOTTOM", 4, 10)
cancelBtn:SetScript("OnClick", function()
f:Hide()
end)
f.cancelBtn = cancelBtn
f:Hide()
customPopup = f
end
customPopup.titleFS:SetText(title or "")
customPopup.editBox:SetText("")
if hasInput then
customPopup.editBox:Show()
customPopup:SetHeight(120)
else
customPopup.editBox:Hide()
customPopup:SetHeight(80)
end
customPopup.acceptBtn:SetScript("OnClick", function()
local text = customPopup.editBox:GetText()
customPopup:Hide()
if onAccept then onAccept(text) end
end)
customPopup.editBox:SetScript("OnEnterPressed", function()
local text = customPopup.editBox:GetText()
customPopup:Hide()
if onAccept then onAccept(text) end
end)
customPopup:Show()
if hasInput then
customPopup.editBox:SetFocus()
end
end
local function GetClassEN(localizedName)
if not localizedName then return nil end
return CLASS_NAME_TO_EN[localizedName] or CLASS_NAME_TO_EN[string.upper(localizedName)]
end
local function GetClassColor(classEN)
if not classEN then return T.nameText end
local c = CLASS_COLORS[string.upper(classEN)]
if c then return c end
return T.nameText
end
local function CreateClassIcon(parent, size)
local sz = size or 16
local icon = parent:CreateTexture(nil, "OVERLAY")
icon:SetTexture(CLASS_ICON_PATH)
icon:SetWidth(sz)
icon:SetHeight(sz)
return icon
end
local function SetClassIcon(icon, classEN)
if not classEN then
icon:Hide()
return
end
local upper = string.upper(classEN)
local coords = CLASS_ICON_TCOORDS[upper]
if coords then
icon:SetTexCoord(coords[1], coords[2], coords[3], coords[4])
icon:SetVertexColor(1, 1, 1)
icon:Show()
else
icon:Hide()
end
end
--------------------------------------------------------------------------------
-- Scroll Frame Helper
--------------------------------------------------------------------------------
local function CreateScrollArea(parent, w, h)
local container = CreateFrame("Frame", nil, parent)
container:SetWidth(w)
container:SetHeight(h)
local scrollFrame = CreateFrame("ScrollFrame", NextName("Scroll"), container)
scrollFrame:SetWidth(w)
scrollFrame:SetHeight(h)
scrollFrame:SetAllPoints(container)
local child = CreateFrame("Frame", nil, scrollFrame)
child:SetWidth(w)
child:SetHeight(1)
scrollFrame:SetScrollChild(child)
local offset = 0
local maxOffset = 0
container.SetContentHeight = function(self, ch)
child:SetHeight(ch)
maxOffset = math.max(0, ch - h)
if offset > maxOffset then
offset = maxOffset
scrollFrame:SetVerticalScroll(offset)
end
end
container.Reset = function(self)
offset = 0
scrollFrame:SetVerticalScroll(0)
end
local function DoScroll(delta)
offset = offset - delta * SCROLL_STEP
if offset < 0 then offset = 0 end
if offset > maxOffset then offset = maxOffset end
scrollFrame:SetVerticalScroll(offset)
end
scrollFrame:EnableMouseWheel(true)
scrollFrame:SetScript("OnMouseWheel", function()
DoScroll(arg1 or 0)
end)
container:EnableMouseWheel(true)
container:SetScript("OnMouseWheel", function()
DoScroll(arg1 or 0)
end)
container.child = child
container.scrollFrame = scrollFrame
return container
end
local function WhoDebug(msg)
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ffcc[Who调试]|r " .. msg)
end
end
--------------------------------------------------------------------------------
-- Hide Blizzard FriendsFrame
--------------------------------------------------------------------------------
local origFriendsFrameShow
local function HideBlizzardFriends()
if not FriendsFrame then return end
origFriendsFrameShow = FriendsFrame.Show
FriendsFrame:Hide()
FriendsFrame:SetAlpha(0)
FriendsFrame:EnableMouse(false)
FriendsFrame:ClearAllPoints()
FriendsFrame:SetPoint("TOPLEFT", UIParent, "BOTTOMRIGHT", 2000, 2000)
FriendsFrame:UnregisterAllEvents()
FriendsFrame.Show = function() end
if UIPanelWindows then
UIPanelWindows["FriendsFrame"] = nil
end
for i = table.getn(UISpecialFrames), 1, -1 do
if UISpecialFrames[i] == "FriendsFrame" then
table.remove(UISpecialFrames, i)
end
end
if SetWhoToUI then
local origSetWhoToUI = SetWhoToUI
SetWhoToUI = function(flag)
if flag ~= 1 then
WhoDebug("拦截 SetWhoToUI(" .. tostring(flag) .. ") -> 强制为1")
end
origSetWhoToUI(1)
end
end
end
--------------------------------------------------------------------------------
-- Who query helper
--------------------------------------------------------------------------------
local whoQueryPending = false
local whoTimeoutFrame = nil
local function DoSendWho(query)
if whoQueryPending and whoTimeoutFrame then
WhoDebug("取消上次挂起的查询")
whoQueryPending = false
whoTimeoutFrame:SetScript("OnUpdate", nil)
end
WhoDebug("发送查询: \"" .. (query or "") .. "\"")
if SetWhoToUI then SetWhoToUI(1) end
whoQueryPending = true
SendWho(query or "")
WhoDebug("SendWho() 已调用, 等待 WHO_LIST_UPDATE...")
if not whoTimeoutFrame then
whoTimeoutFrame = CreateFrame("Frame", nil, UIParent)
end
whoTimeoutFrame.elapsed = 0
whoTimeoutFrame:SetScript("OnUpdate", function()
this.elapsed = (this.elapsed or 0) + (arg1 or 0.016)
if not whoQueryPending then
this:SetScript("OnUpdate", nil)
return
end
if this.elapsed >= 6 then
local n = GetNumWhoResults()
WhoDebug("超时! 6秒未收到事件, 强制刷新, 当前结果=" .. tostring(n))
whoQueryPending = false
this:SetScript("OnUpdate", nil)
SUI:UpdateWhoList()
end
end)
end
--------------------------------------------------------------------------------
-- Tab 1: Friends / Ignore
--------------------------------------------------------------------------------
local function BuildFriendsPage(page)
local subTabFrame = CreateFrame("Frame", nil, page)
subTabFrame:SetHeight(16)
subTabFrame:SetPoint("TOPLEFT", page, "TOPLEFT", 0, 0)
subTabFrame:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, 0)
local friendsSubBtn = CreateFrame("Button", NextName("SubTab"), subTabFrame)
friendsSubBtn:SetWidth(50)
friendsSubBtn:SetHeight(16)
friendsSubBtn:SetPoint("LEFT", subTabFrame, "LEFT", 0, 0)
local fsBtnText = MakeFS(friendsSubBtn, 10, "CENTER", T.tabActiveText)
fsBtnText:SetPoint("CENTER", 0, 0)
fsBtnText:SetText("好友")
friendsSubBtn.text = fsBtnText
friendsSubBtn:SetScript("OnEnter", function()
if friendSubTab ~= "friends" then
this.text:SetTextColor(1, 1, 1)
end
end)
friendsSubBtn:SetScript("OnLeave", function()
if friendSubTab ~= "friends" then
this.text:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
end
end)
page.friendsSubBtn = friendsSubBtn
local ignoreSubBtn = CreateFrame("Button", NextName("SubTab"), subTabFrame)
ignoreSubBtn:SetWidth(50)
ignoreSubBtn:SetHeight(16)
ignoreSubBtn:SetPoint("LEFT", friendsSubBtn, "RIGHT", 6, 0)
local igBtnText = MakeFS(ignoreSubBtn, 10, "CENTER", T.tabText)
igBtnText:SetPoint("CENTER", 0, 0)
igBtnText:SetText("屏蔽")
ignoreSubBtn.text = igBtnText
ignoreSubBtn:SetScript("OnEnter", function()
if friendSubTab ~= "ignore" then
this.text:SetTextColor(1, 1, 1)
end
end)
ignoreSubBtn:SetScript("OnLeave", function()
if friendSubTab ~= "ignore" then
this.text:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
end
end)
page.ignoreSubBtn = ignoreSubBtn
-- Underline indicator for active sub-tab
local subIndicator = friendsSubBtn:CreateTexture(nil, "OVERLAY")
subIndicator:SetHeight(2)
subIndicator:SetPoint("BOTTOMLEFT", friendsSubBtn, "BOTTOMLEFT", 4, 0)
subIndicator:SetPoint("BOTTOMRIGHT", friendsSubBtn, "BOTTOMRIGHT", -4, 0)
subIndicator:SetTexture(1, 1, 1, 1)
subIndicator:SetVertexColor(T.tabActiveBorder[1], T.tabActiveBorder[2], T.tabActiveBorder[3], 0.8)
page.subIndicator = subIndicator
-- Friend search bar
local friendSearchBar = CreateFrame("Frame", nil, page)
friendSearchBar:SetHeight(20)
friendSearchBar:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -18)
friendSearchBar:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, -18)
page.friendSearchBar = friendSearchBar
local searchLabel = MakeFS(friendSearchBar, 9, "LEFT", T.dimText)
searchLabel:SetPoint("LEFT", friendSearchBar, "LEFT", 2, 0)
searchLabel:SetText("搜索:")
local friendSearchBox = MakeEditBox(friendSearchBar, CONTENT_W - 36, 18)
friendSearchBox:SetPoint("LEFT", searchLabel, "RIGHT", 4, 0)
friendSearchBox:SetScript("OnTextChanged", function()
friendSearchText = this:GetText() or ""
SUI:UpdateFriendsList()
end)
friendSearchBox:SetScript("OnEnterPressed", function() this:ClearFocus() end)
friendSearchBox:SetScript("OnEscapePressed", function()
this:SetText("")
this:ClearFocus()
end)
page.friendSearchBox = friendSearchBox
-- Friends list
local friendsArea = CreateFrame("Frame", nil, page)
friendsArea:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -40)
friendsArea:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, BOTTOM_H)
page.friendsArea = friendsArea
local fScroll = CreateScrollArea(friendsArea, CONTENT_W, FRAME_H - HEADER_H - TAB_BAR_H - 40 - BOTTOM_H - 16)
fScroll:SetPoint("TOPLEFT", friendsArea, "TOPLEFT", 0, 0)
page.fScroll = fScroll
local MAX_FRIEND_ROWS = 50
for idx = 1, MAX_FRIEND_ROWS do
local rowIdx = idx
local row = CreateFrame("Button", NextName("FR"), fScroll.child)
row:SetWidth(CONTENT_W - 4)
row:SetHeight(ROW_H)
row:SetPoint("TOPLEFT", fScroll.child, "TOPLEFT", 2, -((rowIdx - 1) * ROW_H))
row.rowIndex = rowIdx
SetRowNormal(row)
local classIcon = CreateClassIcon(row, 16)
classIcon:SetPoint("LEFT", row, "LEFT", 4, 0)
row.classIcon = classIcon
local nameFS = MakeFS(row, 11, "LEFT", T.nameText)
nameFS:SetPoint("LEFT", classIcon, "RIGHT", 4, 0)
nameFS:SetWidth(120)
row.nameFS = nameFS
local infoFS = MakeFS(row, 9, "LEFT", T.dimText)
infoFS:SetPoint("LEFT", nameFS, "RIGHT", 4, 0)
infoFS:SetPoint("RIGHT", row, "RIGHT", -4, 0)
row.infoFS = infoFS
AddSelHighlight(row)
row:RegisterForClicks("LeftButtonUp", "RightButtonUp")
row:SetScript("OnEnter", function()
SetPixelBackdrop(this, T.slotHover, T.slotSelected)
end)
row:SetScript("OnLeave", function()
if selectedFriend and selectedFriend == this.friendDataIndex then
SetPixelBackdrop(this, T.tabActiveBg, T.tabActiveBorder)
else
SetRowNormal(this)
end
end)
row:SetScript("OnClick", function()
selectedFriend = this.friendDataIndex
if arg1 == "RightButton" and this.friendDataIndex then
SUI:ShowFriendRowMenu(this)
return
end
SUI:UpdateFriendsList()
end)
row:Hide()
friendRows[idx] = row
end
-- Ignore list
local ignoreArea = CreateFrame("Frame", nil, page)
ignoreArea:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -20)
ignoreArea:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, BOTTOM_H)
ignoreArea:Hide()
page.ignoreArea = ignoreArea
local iScroll = CreateScrollArea(ignoreArea, CONTENT_W, FRAME_H - HEADER_H - TAB_BAR_H - 20 - BOTTOM_H - 16)
iScroll:SetPoint("TOPLEFT", ignoreArea, "TOPLEFT", 0, 0)
page.iScroll = iScroll
local MAX_IGNORE_ROWS = 50
for idx = 1, MAX_IGNORE_ROWS do
local rowIdx = idx
local row = CreateFrame("Button", NextName("IR"), iScroll.child)
row:SetWidth(CONTENT_W - 4)
row:SetHeight(20)
row:SetPoint("TOPLEFT", iScroll.child, "TOPLEFT", 2, -((rowIdx - 1) * 20))
row.rowIndex = rowIdx
SetRowNormal(row)
local nameFS = MakeFS(row, 11, "LEFT", T.nameText)
nameFS:SetPoint("LEFT", row, "LEFT", 8, 0)
row.nameFS = nameFS
row:SetScript("OnEnter", function()
SetPixelBackdrop(this, T.slotHover, T.slotSelected)
end)
row:SetScript("OnLeave", function()
SetRowNormal(this)
end)
row:Hide()
ignoreRows[idx] = row
end
-- Bottom buttons
local btnBar = CreateFrame("Frame", nil, page)
btnBar:SetHeight(BOTTOM_H)
btnBar:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", 0, 0)
btnBar:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, 0)
page.btnBar = btnBar
local addBtn = MakeButton(btnBar, "添加好友", 80, 22)
addBtn:SetPoint("BOTTOMLEFT", btnBar, "BOTTOMLEFT", 0, 2)
addBtn:SetScript("OnClick", function()
if friendSubTab == "friends" then
ShowCustomPopup("添加好友", true, function(name)
if name and name ~= "" then AddFriend(name) end
end)
else
ShowCustomPopup("添加屏蔽", true, function(name)
if name and name ~= "" then AddIgnore(name) end
end)
end
end)
local removeBtn = MakeButton(btnBar, "删除好友", 80, 22)
removeBtn:SetPoint("LEFT", addBtn, "RIGHT", 4, 0)
removeBtn:SetScript("OnClick", function()
if selectedFriend then RemoveFriend(selectedFriend) end
end)
local msgBtn = MakeButton(btnBar, "发送信息", 80, 22)
msgBtn:SetPoint("LEFT", removeBtn, "RIGHT", 4, 0)
msgBtn:SetScript("OnClick", function()
if selectedFriend then
local name = GetFriendInfo(selectedFriend)
if name then ChatFrame_SendTell(name) end
end
end)
local inviteBtn = MakeButton(btnBar, "组队邀请", 80, 22)
inviteBtn:SetPoint("LEFT", msgBtn, "RIGHT", 4, 0)
inviteBtn:SetScript("OnClick", function()
if selectedFriend then
local name = GetFriendInfo(selectedFriend)
if name then InviteByName(name) end
end
end)
page.addBtn = addBtn
page.removeBtn = removeBtn
page.msgBtn = msgBtn
page.inviteBtn = inviteBtn
friendsSubBtn:SetScript("OnClick", function()
friendSubTab = "friends"
SUI:UpdateFriendsPage()
end)
ignoreSubBtn:SetScript("OnClick", function()
friendSubTab = "ignore"
SUI:UpdateFriendsPage()
end)
end
function SUI:UpdateFriendsPage()
local page = pages[1]
if not page then return end
if friendSubTab == "friends" then
page.friendsArea:Show()
page.friendSearchBar:Show()
page.ignoreArea:Hide()
page.friendsSubBtn.text:SetTextColor(T.tabActiveText[1], T.tabActiveText[2], T.tabActiveText[3])
page.ignoreSubBtn.text:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
page.subIndicator:ClearAllPoints()
page.subIndicator:SetPoint("BOTTOMLEFT", page.friendsSubBtn, "BOTTOMLEFT", 4, 0)
page.subIndicator:SetPoint("BOTTOMRIGHT", page.friendsSubBtn, "BOTTOMRIGHT", -4, 0)
page.subIndicator:Show()
page.addBtn.text:SetText("添加好友")
page.removeBtn.text:SetText("删除好友")
self:UpdateFriendsList()
else
page.friendsArea:Hide()
page.friendSearchBar:Hide()
page.ignoreArea:Show()
page.ignoreSubBtn.text:SetTextColor(T.tabActiveText[1], T.tabActiveText[2], T.tabActiveText[3])
page.friendsSubBtn.text:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
page.subIndicator:ClearAllPoints()
page.subIndicator:SetPoint("BOTTOMLEFT", page.ignoreSubBtn, "BOTTOMLEFT", 4, 0)
page.subIndicator:SetPoint("BOTTOMRIGHT", page.ignoreSubBtn, "BOTTOMRIGHT", -4, 0)
page.subIndicator:Show()
page.addBtn.text:SetText("添加屏蔽")
page.removeBtn.text:SetText("取消屏蔽")
self:UpdateIgnoreList()
end
end
function SUI:UpdateFriendsList()
local numFriends = GetNumFriends()
local totalH = 0
local rowIdx = 0
local searchLower = string.lower(friendSearchText or "")
local hasSearch = searchLower ~= ""
for i = 1, numFriends do
local name, level, class, area, connected, status = GetFriendInfo(i)
if name then
local match = true
if hasSearch then
match = string.find(string.lower(name), searchLower, 1, true)
if not match and class then
match = string.find(string.lower(class), searchLower, 1, true)
end
if not match and area then
match = string.find(string.lower(area), searchLower, 1, true)
end
end
if match then
rowIdx = rowIdx + 1
if rowIdx > 50 then break end
local row = friendRows[rowIdx]
if row then
row.nameFS:SetText(name)
row.friendDataIndex = i
local classEN = GetClassEN(class)
if connected then
local cc = classEN and GetClassColor(classEN) or T.onlineText
row.nameFS:SetTextColor(cc[1], cc[2], cc[3])
local info = ""
if level and level > 0 then info = "等级" .. level end
if class then info = info .. " " .. class end
if area then info = info .. " - " .. area end
row.infoFS:SetText(info)
row.infoFS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
else
row.nameFS:SetTextColor(T.offlineText[1], T.offlineText[2], T.offlineText[3])
row.infoFS:SetText("离线")
row.infoFS:SetTextColor(T.offlineText[1], T.offlineText[2], T.offlineText[3])
end
SetClassIcon(row.classIcon, classEN)
if selectedFriend == i then
SetPixelBackdrop(row, T.tabActiveBg, T.tabActiveBorder)
ShowSelHighlight(row)
row.nameFS:SetTextColor(1, 1, 1)
else
SetRowNormal(row)
HideSelHighlight(row)
end
row:Show()
totalH = totalH + ROW_H
end
end
end
end
for i = rowIdx + 1, 50 do
if friendRows[i] then friendRows[i]:Hide() end
end
if pages[1] and pages[1].fScroll then
pages[1].fScroll:SetContentHeight(totalH + 4)
end
end
function SUI:UpdateIgnoreList()
local numIgnores = GetNumIgnores()
local totalH = 0
for i = 1, 50 do
local row = ignoreRows[i]
if not row then break end
if i <= numIgnores then
local name = GetIgnoreName(i)
if name then
row.nameFS:SetText(name)
row:Show()
totalH = totalH + 20
else
row:Hide()
end
else
row:Hide()
end
end
if pages[1] and pages[1].iScroll then
pages[1].iScroll:SetContentHeight(totalH + 4)
end
end
function SUI:ShowFriendRowMenu(row)
local di = row.friendDataIndex
if not di then return end
local name, level, class, area, connected, status = GetFriendInfo(di)
if not name then return end
if not SUI.friendDropDown then
SUI.friendDropDown = CreateFrame("Frame", "SFramesSocialFriendDD", UIParent, "UIDropDownMenuTemplate")
SUI.friendDropDown.displayMode = "MENU"
SUI.friendDropDown.initialize = function()
local fd = SUI.friendDropDown
local fName = fd.friendName
local fOnline = fd.friendOnline
if not fName then return end
local info = {}
info.text = fName
info.isTitle = 1
info.notCheckable = 1
UIDropDownMenu_AddButton(info)
if fOnline then
info = {}
info.text = "密语"
info.notCheckable = 1
info.func = function() ChatFrame_SendTell(fName) end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "邀请组队"
info.notCheckable = 1
info.func = function() InviteByName(fName) end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "观察"
info.notCheckable = 1
info.func = function()
if TargetByName then TargetByName(fName) end
if UnitExists("target") and UnitName("target") == fName then
InspectUnit("target")
end
end
UIDropDownMenu_AddButton(info)
end
info = {}
info.text = "删除好友"
info.notCheckable = 1
info.func = function()
local idx = fd.friendIdx
if idx then RemoveFriend(idx) end
end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "取消"
info.notCheckable = 1
UIDropDownMenu_AddButton(info)
end
end
SUI.friendDropDown.friendName = name
SUI.friendDropDown.friendOnline = connected
SUI.friendDropDown.friendIdx = di
ToggleDropDownMenu(1, nil, SUI.friendDropDown, "cursor")
end
--------------------------------------------------------------------------------
-- Tab 2: Who
--------------------------------------------------------------------------------
local function BuildWhoPage(page)
local searchBar = CreateFrame("Frame", nil, page)
searchBar:SetHeight(26)
searchBar:SetPoint("TOPLEFT", page, "TOPLEFT", 0, 0)
searchBar:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, 0)
local editBox = MakeEditBox(searchBar, CONTENT_W - 110, 22)
editBox:SetPoint("LEFT", searchBar, "LEFT", 0, 0)
local placeholder = editBox:CreateFontString(nil, "ARTWORK")
placeholder:SetFont(GetFont(), 10, "OUTLINE")
placeholder:SetPoint("LEFT", editBox, "LEFT", 6, 0)
placeholder:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3], 0.6)
placeholder:SetText("名称/等级/职业/种族/区域")
editBox.placeholder = placeholder
editBox:SetScript("OnTextChanged", function()
local text = this:GetText()
if text and text ~= "" then
this.placeholder:Hide()
else
this.placeholder:Show()
end
end)
editBox:SetScript("OnEditFocusGained", function()
if this:GetText() == "" then this.placeholder:Show() end
end)
editBox:SetScript("OnEditFocusLost", function()
if this:GetText() == "" then this.placeholder:Show() end
end)
editBox:SetScript("OnEnterPressed", function()
local text = this:GetText() or ""
SUI:ClearWhoList()
DoSendWho(text)
this:ClearFocus()
end)
page.editBox = editBox
local clearBtn = MakeButton(searchBar, "X", 28, 22)
clearBtn:SetPoint("LEFT", editBox, "RIGHT", 2, 0)
clearBtn:SetScript("OnClick", function()
if page.editBox then
page.editBox:SetText("")
page.editBox:SetFocus()
end
end)
local searchBtn = MakeButton(searchBar, "搜索", 64, 22)
searchBtn:SetPoint("LEFT", clearBtn, "RIGHT", 2, 0)
searchBtn:SetScript("OnClick", function()
local text = page.editBox:GetText() or ""
SUI:ClearWhoList()
DoSendWho(text)
end)
-- Column headers
local colFrame = CreateFrame("Frame", nil, page)
colFrame:SetHeight(18)
colFrame:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -28)
colFrame:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, -28)
local cols = { { "名称", 0.30 }, { "等级", 0.12 }, { "职业", 0.18 }, { "区域", 0.40 } }
local cx = 0
for _, col in ipairs(cols) do
local fs = MakeFS(colFrame, 10, "LEFT", T.colHeader)
fs:SetPoint("TOPLEFT", colFrame, "TOPLEFT", cx, 0)
fs:SetWidth(CONTENT_W * col[2])
fs:SetText(col[1])
cx = cx + CONTENT_W * col[2]
end
MakeSep(page, -46)
-- Results scroll (leave 16px above btnBar for totalFS)
local listArea = CreateFrame("Frame", nil, page)
listArea:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -48)
listArea:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, BOTTOM_H + 18)
local scrollH = FRAME_H - HEADER_H - TAB_BAR_H - 48 - BOTTOM_H - 18
local wScroll = CreateScrollArea(listArea, CONTENT_W, scrollH)
wScroll:SetPoint("TOPLEFT", listArea, "TOPLEFT", 0, 0)
page.wScroll = wScroll
local MAX_WHO_ROWS = 50
for idx = 1, MAX_WHO_ROWS do
local rowIdx = idx
local row = CreateFrame("Button", NextName("WR"), wScroll.child)
row:SetWidth(CONTENT_W - 4)
row:SetHeight(20)
row:SetPoint("TOPLEFT", wScroll.child, "TOPLEFT", 2, -((rowIdx - 1) * 20))
row.rowIndex = rowIdx
SetRowNormal(row)
local nameFS = MakeFS(row, 10, "LEFT", T.nameText)
nameFS:SetPoint("LEFT", row, "LEFT", 4, 0)
nameFS:SetWidth(CONTENT_W * 0.30 - 8)
row.nameFS = nameFS
local lvlFS = MakeFS(row, 10, "LEFT", T.bodyText)
lvlFS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.30, 0)
lvlFS:SetWidth(CONTENT_W * 0.12)
row.lvlFS = lvlFS
local classFS = MakeFS(row, 10, "LEFT", T.bodyText)
classFS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.42, 0)
classFS:SetWidth(CONTENT_W * 0.18)
row.classFS = classFS
local zoneFS = MakeFS(row, 10, "LEFT", T.dimText)
zoneFS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.60, 0)
zoneFS:SetPoint("RIGHT", row, "RIGHT", -4, 0)
row.zoneFS = zoneFS
AddSelHighlight(row)
row:SetScript("OnEnter", function()
SetPixelBackdrop(this, T.slotHover, T.slotSelected)
end)
row:SetScript("OnLeave", function()
if selectedWho == this.rowIndex then
SetPixelBackdrop(this, T.tabActiveBg, T.tabActiveBorder)
else
SetRowNormal(this)
end
end)
row:SetScript("OnClick", function()
selectedWho = this.rowIndex
SUI:UpdateWhoList()
end)
row:Hide()
whoRows[idx] = row
end
-- Totals
local totalFS = MakeFS(page, 10, "LEFT", T.dimText)
totalFS:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", 0, BOTTOM_H + 2)
page.totalFS = totalFS
-- Bottom buttons
local btnBar = CreateFrame("Frame", nil, page)
btnBar:SetHeight(BOTTOM_H)
btnBar:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", 0, 0)
btnBar:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, 0)
local invBtn = MakeButton(btnBar, "组队邀请", 80, 22)
invBtn:SetPoint("BOTTOMLEFT", btnBar, "BOTTOMLEFT", 0, 2)
invBtn:SetScript("OnClick", function()
if selectedWho then
local name = GetWhoInfo(selectedWho)
if name then InviteByName(name) end
end
end)
local addFriendBtn = MakeButton(btnBar, "添加好友", 80, 22)
addFriendBtn:SetPoint("LEFT", invBtn, "RIGHT", 4, 0)
addFriendBtn:SetScript("OnClick", function()
if selectedWho then
local name = GetWhoInfo(selectedWho)
if name then AddFriend(name) end
end
end)
local whisperBtn = MakeButton(btnBar, "密语", 80, 22)
whisperBtn:SetPoint("LEFT", addFriendBtn, "RIGHT", 4, 0)
whisperBtn:SetScript("OnClick", function()
if selectedWho then
local name = GetWhoInfo(selectedWho)
if name then ChatFrame_SendTell(name) end
end
end)
end
function SUI:ClearWhoList()
selectedWho = nil
for i = 1, 50 do
local row = whoRows[i]
if not row then break end
row.nameFS:SetText("")
row.lvlFS:SetText("")
row.classFS:SetText("")
row.zoneFS:SetText("")
SetRowNormal(row)
HideSelHighlight(row)
row:Hide()
end
if pages[2] and pages[2].wScroll then
pages[2].wScroll:SetContentHeight(4)
end
if pages[2] and pages[2].totalFS then
pages[2].totalFS:SetText("搜索中...")
end
end
function SUI:UpdateWhoList()
local numWho, totalCount = GetNumWhoResults()
local totalH = 0
for i = 1, 50 do
local row = whoRows[i]
if not row then break end
if i <= numWho then
local name, guild, level, race, class, zone, classEN = GetWhoInfo(i)
if name then
if not classEN or classEN == "" then
classEN = GetClassEN(class)
end
local cc = GetClassColor(classEN)
row.nameFS:SetText(name)
row.nameFS:SetTextColor(cc[1], cc[2], cc[3])
row.lvlFS:SetText(level or "")
row.classFS:SetText(class or "")
row.classFS:SetTextColor(cc[1], cc[2], cc[3])
row.zoneFS:SetText(zone or "")
if selectedWho == i then
SetPixelBackdrop(row, T.tabActiveBg, T.tabActiveBorder)
ShowSelHighlight(row)
row.nameFS:SetTextColor(1, 1, 1)
else
SetRowNormal(row)
HideSelHighlight(row)
end
row:Show()
totalH = totalH + 20
else
row:Hide()
end
else
row:Hide()
end
end
if pages[2] and pages[2].wScroll then
pages[2].wScroll:SetContentHeight(totalH + 4)
end
if pages[2] and pages[2].totalFS then
pages[2].totalFS:SetText((numWho or 0) .. " 个结果 (共 " .. (totalCount or 0) .. " 人)")
end
end
--------------------------------------------------------------------------------
-- Tab 3: Guild
--------------------------------------------------------------------------------
local motdPopup = nil
local function ShowMotdPopup(motdStr)
if not motdPopup then
local f = CreateFrame("Frame", "SFramesSocialMotdPopup", UIParent)
f:SetWidth(360)
f:SetHeight(220)
f:SetPoint("CENTER", UIParent, "CENTER", 0, 60)
f:SetFrameStrata("DIALOG")
f:SetFrameLevel(120)
SetRoundBackdrop(f, T.panelBg, T.panelBorder)
CreateShadow(f)
f:EnableMouse(true)
f:SetMovable(true)
f:RegisterForDrag("LeftButton")
f:SetScript("OnDragStart", function() this:StartMoving() end)
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
local titleFS = MakeFS(f, 12, "CENTER", T.gold)
titleFS:SetPoint("TOP", f, "TOP", 0, -10)
titleFS:SetText("公会公告")
f.titleFS = titleFS
MakeSep(f, -26)
local scrollFrame = CreateFrame("ScrollFrame", NextName("MotdScroll"), f)
scrollFrame:SetPoint("TOPLEFT", f, "TOPLEFT", 12, -30)
scrollFrame:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -12, 40)
local child = CreateFrame("Frame", nil, scrollFrame)
child:SetWidth(336 - 24)
child:SetHeight(1)
scrollFrame:SetScrollChild(child)
local bodyFS = child:CreateFontString(nil, "OVERLAY")
bodyFS:SetFont(GetFont(), 11, "OUTLINE")
bodyFS:SetJustifyH("LEFT")
bodyFS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
bodyFS:SetPoint("TOPLEFT", child, "TOPLEFT", 0, 0)
bodyFS:SetWidth(336 - 24)
f.bodyFS = bodyFS
local scrollOffset = 0
local scrollMax = 0
f.UpdateScroll = function()
local textH = bodyFS:GetHeight() or 0
local viewH = scrollFrame:GetHeight() or 1
scrollMax = math.max(0, textH - viewH)
if scrollOffset > scrollMax then scrollOffset = scrollMax end
scrollFrame:SetVerticalScroll(scrollOffset)
child:SetHeight(math.max(textH, viewH))
end
scrollFrame:EnableMouseWheel(true)
scrollFrame:SetScript("OnMouseWheel", function()
scrollOffset = scrollOffset - (arg1 or 0) * 18
if scrollOffset < 0 then scrollOffset = 0 end
if scrollOffset > scrollMax then scrollOffset = scrollMax end
scrollFrame:SetVerticalScroll(scrollOffset)
end)
local closeBtn = MakeButton(f, "关闭", 100, 24)
closeBtn:SetPoint("BOTTOM", f, "BOTTOM", 0, 10)
closeBtn:SetScript("OnClick", function() f:Hide() end)
f:Hide()
motdPopup = f
end
motdPopup.bodyFS:SetText(motdStr or "无公告")
motdPopup:Show()
motdPopup.UpdateScroll()
end
local function BuildGuildPage(page)
local motdFrame = CreateFrame("Button", NextName("MotdBtn"), page)
motdFrame:SetHeight(36)
motdFrame:SetPoint("TOPLEFT", page, "TOPLEFT", 0, 0)
motdFrame:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, 0)
SetPixelBackdrop(motdFrame, { 0.08, 0.04, 0.06, 0.8 }, T.slotBorder)
local motdLabel = MakeFS(motdFrame, 9, "LEFT", T.dimText)
motdLabel:SetPoint("TOPLEFT", motdFrame, "TOPLEFT", 6, -2)
motdLabel:SetText("公会公告: (点击查看完整)")
local motdText = MakeFS(motdFrame, 10, "LEFT", T.bodyText)
motdText:SetPoint("TOPLEFT", motdLabel, "BOTTOMLEFT", 0, -2)
motdText:SetPoint("RIGHT", motdFrame, "RIGHT", -6, 0)
page.motdText = motdText
motdFrame:SetScript("OnClick", function()
local motd = GetGuildRosterMOTD and GetGuildRosterMOTD() or ""
ShowMotdPopup(motd ~= "" and motd or "无公告")
end)
motdFrame:SetScript("OnEnter", function()
SetPixelBackdrop(this, { 0.12, 0.06, 0.09, 0.9 }, T.tabActiveBorder)
end)
motdFrame:SetScript("OnLeave", function()
SetPixelBackdrop(this, { 0.08, 0.04, 0.06, 0.8 }, T.slotBorder)
end)
-- Toolbar row: search + filter buttons
local toolBar = CreateFrame("Frame", nil, page)
toolBar:SetHeight(18)
toolBar:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -38)
toolBar:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, -38)
local gSearchLabel = MakeFS(toolBar, 9, "LEFT", T.dimText)
gSearchLabel:SetPoint("LEFT", toolBar, "LEFT", 0, 0)
gSearchLabel:SetText("搜索:")
local gSearchBox = MakeEditBox(toolBar, 110, 16)
gSearchBox:SetPoint("LEFT", gSearchLabel, "RIGHT", 2, 0)
gSearchBox:SetFont(GetFont(), 9, "OUTLINE")
gSearchBox:SetScript("OnTextChanged", function()
guildSearchText = this:GetText() or ""
SUI:UpdateGuildList()
end)
gSearchBox:SetScript("OnEnterPressed", function() this:ClearFocus() end)
gSearchBox:SetScript("OnEscapePressed", function()
this:SetText("")
this:ClearFocus()
end)
page.gSearchBox = gSearchBox
local offlineToggle = MakeButton(toolBar, guildHideOffline and "显示离线" or "隐藏离线", 56, 16)
offlineToggle:SetPoint("TOPRIGHT", toolBar, "TOPRIGHT", 0, 0)
offlineToggle.text:SetFont(GetFont(), 9, "OUTLINE")
offlineToggle:SetScript("OnClick", function()
guildHideOffline = not guildHideOffline
SFramesDB.guildHideOffline = guildHideOffline
if guildHideOffline then
this.text:SetText("显示离线")
else
this.text:SetText("隐藏离线")
end
SUI:UpdateGuildList()
end)
page.offlineToggle = offlineToggle
local viewToggle = MakeButton(toolBar, "切换视图", 56, 16)
viewToggle:SetPoint("RIGHT", offlineToggle, "LEFT", -4, 0)
viewToggle.text:SetFont(GetFont(), 9, "OUTLINE")
viewToggle:SetScript("OnClick", function()
if guildViewMode == "player" then guildViewMode = "guild" else guildViewMode = "player" end
SUI:UpdateGuildList()
end)
-- Column headers
local colFrame = CreateFrame("Frame", nil, page)
colFrame:SetHeight(18)
colFrame:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -56)
colFrame:SetPoint("TOPRIGHT", page, "TOPRIGHT", 0, -56)
page.guildColFrame = colFrame
page.guildColBtns = {}
MakeSep(page, -74)
local listArea = CreateFrame("Frame", nil, page)
listArea:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -76)
listArea:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, BOTTOM_H + 14)
local gScroll = CreateScrollArea(listArea, CONTENT_W, FRAME_H - HEADER_H - TAB_BAR_H - 76 - BOTTOM_H - 14 - 16)
gScroll:SetPoint("TOPLEFT", listArea, "TOPLEFT", 0, 0)
page.gScroll = gScroll
local MAX_GUILD_ROWS = 100
for idx = 1, MAX_GUILD_ROWS do
local rowIdx = idx
local row = CreateFrame("Button", NextName("GR"), gScroll.child)
row:SetWidth(CONTENT_W - 4)
row:SetHeight(18)
row:SetPoint("TOPLEFT", gScroll.child, "TOPLEFT", 2, -((rowIdx - 1) * 18))
row.rowIndex = rowIdx
SetRowNormal(row)
local classIcon = CreateClassIcon(row, 14)
classIcon:SetPoint("LEFT", row, "LEFT", 2, 0)
row.classIcon = classIcon
local nameFS = MakeFS(row, 10, "LEFT", T.nameText)
nameFS:SetPoint("LEFT", classIcon, "RIGHT", 3, 0)
nameFS:SetWidth(CONTENT_W * 0.24 - 20)
row.nameFS = nameFS
local lvlFS = MakeFS(row, 10, "CENTER", T.bodyText)
lvlFS:SetWidth(30)
row.lvlFS = lvlFS
local col3FS = MakeFS(row, 10, "LEFT", T.dimText)
col3FS:SetWidth(100)
row.col3FS = col3FS
local col4FS = MakeFS(row, 9, "LEFT", T.dimText)
row.col4FS = col4FS
local col5FS = MakeFS(row, 9, "LEFT", T.dimText)
row.col5FS = col5FS
AddSelHighlight(row)
row:RegisterForClicks("LeftButtonUp", "RightButtonUp")
row:SetScript("OnEnter", function()
SetPixelBackdrop(this, T.slotHover, T.slotSelected)
end)
row:SetScript("OnLeave", function()
if selectedGuild and selectedGuild == this.guildDataIndex then
SetPixelBackdrop(this, T.tabActiveBg, T.tabActiveBorder)
else
SetRowNormal(this)
end
end)
row:SetScript("OnClick", function()
selectedGuild = this.guildDataIndex
if arg1 == "RightButton" and this.guildDataIndex then
SUI:ShowGuildRowMenu(this)
else
SUI:UpdateGuildList()
end
end)
row:Hide()
guildRows[idx] = row
end
local totalFS = MakeFS(page, 9, "LEFT", T.dimText)
totalFS:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", 2, BOTTOM_H + 2)
page.guildTotalFS = totalFS
local btnBar = CreateFrame("Frame", nil, page)
btnBar:SetHeight(BOTTOM_H)
btnBar:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", 0, 0)
btnBar:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, 0)
local invBtn = MakeButton(btnBar, "组队邀请", 80, 22)
invBtn:SetPoint("BOTTOMLEFT", btnBar, "BOTTOMLEFT", 0, 2)
invBtn:SetScript("OnClick", function()
if selectedGuild then
local name, rank, rankIndex, level, class, zone, note, officerNote, online = GetGuildRosterInfo(selectedGuild)
if name and online then InviteByName(name) end
end
end)
local msgBtn = MakeButton(btnBar, "发送信息", 80, 22)
msgBtn:SetPoint("LEFT", invBtn, "RIGHT", 4, 0)
msgBtn:SetScript("OnClick", function()
if selectedGuild then
local name = GetGuildRosterInfo(selectedGuild)
if name then ChatFrame_SendTell(name) end
end
end)
local gInviteBtn = MakeButton(btnBar, "邀请入会", 80, 22)
gInviteBtn:SetPoint("LEFT", msgBtn, "RIGHT", 4, 0)
gInviteBtn:SetScript("OnClick", function()
ShowCustomPopup("邀请玩家加入公会", true, function(name)
if name and name ~= "" then
if GuildInvite then
GuildInvite(name)
elseif GuildInviteByName then
GuildInviteByName(name)
else
SendChatMessage(".ginvite " .. name, "GUILD")
end
end
end)
end)
page.gInviteBtn = gInviteBtn
local gLeaveBtn = MakeButton(btnBar, "退出公会", 80, 22)
gLeaveBtn:SetPoint("LEFT", gInviteBtn, "RIGHT", 4, 0)
gLeaveBtn:SetScript("OnClick", function()
StaticPopup_Show("CONFIRM_GUILD_LEAVE", GetGuildInfo("player"))
end)
page.gLeaveBtn = gLeaveBtn
end
function SUI:ShowGuildRowMenu(row)
local di = row.guildDataIndex
if not di then return end
local name, rank, rankIndex, level, class, zone, note, officerNote, online = GetGuildRosterInfo(di)
if not name then return end
local isSelf = (name == UnitName("player"))
if not SUI.guildDropDown then
SUI.guildDropDown = CreateFrame("Frame", "SFramesSocialGuildDD", UIParent, "UIDropDownMenuTemplate")
SUI.guildDropDown.displayMode = "MENU"
SUI.guildDropDown.initialize = function()
local gd = SUI.guildDropDown
local gName = gd.memberName
local gOnline = gd.memberOnline
local gSelf = gd.memberIsSelf
if not gName then return end
local info = {}
info.text = gName
info.isTitle = 1
info.notCheckable = 1
UIDropDownMenu_AddButton(info)
if not gSelf then
if gOnline then
info = {}
info.text = "密语"
info.notCheckable = 1
info.func = function() ChatFrame_SendTell(gName) end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "邀请组队"
info.notCheckable = 1
info.func = function() InviteByName(gName) end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "观察"
info.notCheckable = 1
info.func = function()
if TargetByName then TargetByName(gName) end
if UnitExists("target") and UnitName("target") == gName then
InspectUnit("target")
end
end
UIDropDownMenu_AddButton(info)
end
if CanGuildRemove and CanGuildRemove() then
info = {}
info.text = "移出公会"
info.notCheckable = 1
info.func = function() GuildUninvite(gName) end
UIDropDownMenu_AddButton(info)
end
if CanGuildPromote and CanGuildPromote() then
info = {}
info.text = "晋升"
info.notCheckable = 1
info.func = function() GuildPromote(gName) end
UIDropDownMenu_AddButton(info)
end
if CanGuildDemote and CanGuildDemote() then
info = {}
info.text = "降级"
info.notCheckable = 1
info.func = function() GuildDemote(gName) end
UIDropDownMenu_AddButton(info)
end
else
info = {}
info.text = "退出公会"
info.notCheckable = 1
info.func = function()
StaticPopup_Show("CONFIRM_GUILD_LEAVE", GetGuildInfo("player"))
end
UIDropDownMenu_AddButton(info)
end
info = {}
info.text = "取消"
info.notCheckable = 1
UIDropDownMenu_AddButton(info)
end
end
SUI.guildDropDown.memberName = name
SUI.guildDropDown.memberOnline = online
SUI.guildDropDown.memberIsSelf = isSelf
ToggleDropDownMenu(1, nil, SUI.guildDropDown, "cursor")
end
local GUILD_COL_SORT_MAP = {
["名称"] = "name",
["等级"] = "level",
["职业"] = "class",
["职位"] = "rank",
["区域"] = "zone",
["备注"] = "note",
["状态"] = "status",
}
local function RebuildGuildColHeaders()
local colFrame = pages[3] and pages[3].guildColFrame
if not colFrame then return end
local old = pages[3].guildColBtns
if old then
for _, btn in ipairs(old) do btn:Hide() end
end
pages[3].guildColBtns = {}
local headers
if guildViewMode == "player" then
headers = { { "名称", 0, 0.24 }, { "等级", 0.24, 0.08 }, { "职业", 0.32, 0.14 }, { "职位", 0.46, 0.18 }, { "区域", 0.64, 0.36 } }
else
headers = { { "名称", 0, 0.30 }, { "职位", 0.30, 0.20 }, { "备注", 0.50, 0.30 }, { "状态", 0.80, 0.20 } }
end
for _, h in ipairs(headers) do
local sortKey = GUILD_COL_SORT_MAP[h[1]]
local btn = CreateFrame("Button", nil, colFrame)
btn:SetHeight(18)
btn:SetPoint("TOPLEFT", colFrame, "TOPLEFT", CONTENT_W * h[2], 0)
btn:SetWidth(CONTENT_W * h[3])
local fs = MakeFS(btn, 10, "LEFT", T.colHeader)
fs:SetPoint("LEFT", btn, "LEFT", 0, 0)
local arrow = ""
if sortKey and guildSortField == sortKey then
arrow = guildSortAsc and "" or ""
end
fs:SetText(h[1] .. arrow)
btn.headerFS = fs
if sortKey then
btn.sortKey = sortKey
btn:SetScript("OnClick", function()
if guildSortField == this.sortKey then
guildSortAsc = not guildSortAsc
else
guildSortField = this.sortKey
guildSortAsc = true
end
SUI:UpdateGuildList()
end)
btn:SetScript("OnEnter", function()
this.headerFS:SetTextColor(1, 1, 1)
end)
btn:SetScript("OnLeave", function()
this.headerFS:SetTextColor(T.colHeader[1], T.colHeader[2], T.colHeader[3])
end)
end
table.insert(pages[3].guildColBtns, btn)
end
end
function SUI:UpdateGuildList()
if not IsInGuild() then
for i = 1, 100 do
if guildRows[i] then guildRows[i]:Hide() end
end
if pages[3] and pages[3].motdText then
pages[3].motdText:SetText("你没有加入公会")
end
if pages[3] and pages[3].gInviteBtn then pages[3].gInviteBtn:Hide() end
if pages[3] and pages[3].gLeaveBtn then pages[3].gLeaveBtn:Hide() end
if pages[3] and pages[3].guildTotalFS then pages[3].guildTotalFS:SetText("") end
return
end
if SetGuildRosterShowOffline then
SetGuildRosterShowOffline(not guildHideOffline)
end
GuildRoster()
local motd = GetGuildRosterMOTD and GetGuildRosterMOTD() or ""
if pages[3] and pages[3].motdText then
pages[3].motdText:SetText(motd ~= "" and motd or "无公告")
end
RebuildGuildColHeaders()
local numTotal, numOnlineRet = GetNumGuildMembers()
numTotal = numTotal or 0
local totalOnline = 0
local members = {}
local searchLower = string.lower(guildSearchText or "")
local hasSearch = searchLower ~= ""
for i = 1, numTotal do
local name, rank, rankIndex, level, class, zone, note, officerNote, online, status, classEN = GetGuildRosterInfo(i)
if name then
if online then totalOnline = totalOnline + 1 end
local match = true
if hasSearch then
match = string.find(string.lower(name), searchLower, 1, true)
if not match and class then
match = string.find(string.lower(class), searchLower, 1, true)
end
if not match and rank then
match = string.find(string.lower(rank), searchLower, 1, true)
end
if not match and zone then
match = string.find(string.lower(zone), searchLower, 1, true)
end
end
if match then
if not classEN or classEN == "" then
classEN = GetClassEN(class)
end
table.insert(members, {
idx = i, name = name, rank = rank, rankIndex = rankIndex or 99,
level = level or 0, class = class or "", classEN = classEN,
zone = zone or "", note = note or "", officerNote = officerNote or "",
online = online, status = status,
})
end
end
end
local sf = guildSortField
local asc = guildSortAsc
table.sort(members, function(a, b)
local va, vb
if sf == "name" then
va, vb = (a.name or ""), (b.name or "")
elseif sf == "level" then
va, vb = (a.level or 0), (b.level or 0)
elseif sf == "class" then
va, vb = (a.class or ""), (b.class or "")
elseif sf == "rank" then
va, vb = (a.rankIndex or 99), (b.rankIndex or 99)
elseif sf == "zone" then
va, vb = (a.zone or ""), (b.zone or "")
elseif sf == "note" then
va, vb = (a.note or ""), (b.note or "")
elseif sf == "status" then
local sa = a.online and 0 or 1
local sb = b.online and 0 or 1
va, vb = sa, sb
else
va, vb = (a.name or ""), (b.name or "")
end
if va == vb then
return (a.name or "") < (b.name or "")
end
if asc then return va < vb else return va > vb end
end)
local totalH = 0
local rowIdx = 0
for mi = 1, table.getn(members) do
local m = members[mi]
rowIdx = rowIdx + 1
if rowIdx > 100 then break end
local row = guildRows[rowIdx]
if row then
local cc = GetClassColor(m.classEN)
SetClassIcon(row.classIcon, m.classEN)
row.nameFS:SetText(m.name)
row.guildDataIndex = m.idx
if m.online then
row.nameFS:SetTextColor(cc[1], cc[2], cc[3])
else
row.nameFS:SetTextColor(T.offlineText[1], T.offlineText[2], T.offlineText[3])
end
if guildViewMode == "player" then
row.lvlFS:SetText(m.level > 0 and m.level or "")
row.lvlFS:ClearAllPoints()
row.lvlFS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.24, 0)
row.col3FS:SetText(m.class)
row.col3FS:ClearAllPoints()
row.col3FS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.32, 0)
row.col3FS:SetWidth(CONTENT_W * 0.14)
row.col3FS:SetTextColor(cc[1], cc[2], cc[3])
row.col4FS:SetText(m.rank or "")
row.col4FS:ClearAllPoints()
row.col4FS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.46, 0)
row.col4FS:SetWidth(CONTENT_W * 0.18)
row.col4FS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
row.col5FS:SetText(m.online and m.zone or "离线")
row.col5FS:ClearAllPoints()
row.col5FS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.64, 0)
row.col5FS:SetPoint("RIGHT", row, "RIGHT", -4, 0)
if m.online then
row.col5FS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
else
row.col5FS:SetTextColor(T.offlineText[1], T.offlineText[2], T.offlineText[3])
end
row.col5FS:Show()
else
row.lvlFS:SetText("")
row.col3FS:SetText(m.rank or "")
row.col3FS:ClearAllPoints()
row.col3FS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.30, 0)
row.col3FS:SetWidth(CONTENT_W * 0.20)
row.col3FS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
row.col4FS:SetText(m.note)
row.col4FS:ClearAllPoints()
row.col4FS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.50, 0)
row.col4FS:SetWidth(CONTENT_W * 0.30)
row.col4FS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
row.col5FS:SetText(m.online and "在线" or "离线")
row.col5FS:ClearAllPoints()
row.col5FS:SetPoint("LEFT", row, "LEFT", CONTENT_W * 0.80, 0)
row.col5FS:SetPoint("RIGHT", row, "RIGHT", -4, 0)
if m.online then
row.col5FS:SetTextColor(T.onlineText[1], T.onlineText[2], T.onlineText[3])
else
row.col5FS:SetTextColor(T.offlineText[1], T.offlineText[2], T.offlineText[3])
end
row.col5FS:Show()
end
if selectedGuild == m.idx then
SetPixelBackdrop(row, T.tabActiveBg, T.tabActiveBorder)
ShowSelHighlight(row)
row.nameFS:SetTextColor(1, 1, 1)
else
SetRowNormal(row)
HideSelHighlight(row)
end
row:Show()
totalH = totalH + 18
end
end
for i = rowIdx + 1, 100 do
if guildRows[i] then
guildRows[i]:Hide()
end
end
if pages[3] and pages[3].gScroll then
pages[3].gScroll:SetContentHeight(totalH + 4)
end
if pages[3] and pages[3].guildTotalFS then
local shownCount = table.getn(members)
if guildHideOffline then
pages[3].guildTotalFS:SetText(totalOnline .. " 人在线 (共 " .. numTotal .. " 名成员)")
else
pages[3].guildTotalFS:SetText("" .. numTotal .. " 名成员, " .. totalOnline .. " 人在线")
end
end
-- Show/hide guild invite button based on permission
if pages[3] and pages[3].gInviteBtn then
local canInvite = CanGuildInvite and CanGuildInvite()
if canInvite then
pages[3].gInviteBtn:Show()
else
pages[3].gInviteBtn:Hide()
end
end
end
--------------------------------------------------------------------------------
-- Tab 4: Raid
--------------------------------------------------------------------------------
local RAID_COLS = 5
local RAID_GROUPS = 8
local RAID_SLOT_W = 68
local RAID_SLOT_H = 24
local RAID_GROUP_PAD = 3
local RAID_GROUP_LABEL_H = 14
local RAID_ICON_SIZE = 14
local dragSlot = nil
local dragHighlight = nil
local function BuildRaidPage(page)
local infoFS = MakeFS(page, 10, "LEFT", T.dimText)
infoFS:SetPoint("TOPLEFT", page, "TOPLEFT", 0, 0)
page.raidInfoFS = infoFS
local rScroll = CreateScrollArea(page, CONTENT_W, FRAME_H - HEADER_H - TAB_BAR_H - 20 - BOTTOM_H - 16)
rScroll:SetPoint("TOPLEFT", page, "TOPLEFT", 0, -18)
page.rScroll = rScroll
local groupH = RAID_GROUP_LABEL_H + RAID_SLOT_H
for gIdx = 1, RAID_GROUPS do
local g = gIdx
local groupFrame = CreateFrame("Frame", nil, rScroll.child)
groupFrame:SetWidth(CONTENT_W)
groupFrame:SetHeight(groupH)
local gy = -((g - 1) * (groupH + RAID_GROUP_PAD))
groupFrame:SetPoint("TOPLEFT", rScroll.child, "TOPLEFT", 0, gy)
SetRoundBackdrop(groupFrame, T.raidGroup, T.raidGroupBorder)
groupFrame.groupIndex = g
groupFrame:EnableMouse(true)
groupFrame:SetScript("OnMouseUp", function()
if not dragSlot then return end
if dragHighlight then
dragHighlight:Hide()
dragHighlight:SetScript("OnUpdate", nil)
end
local tg = this.groupIndex
if tg and dragSlot.raidIndex and tg ~= dragSlot.group then
SetRaidSubgroup(dragSlot.raidIndex, tg)
end
dragSlot = nil
end)
local groupLabel = MakeFS(groupFrame, 9, "LEFT", T.gold)
groupLabel:SetPoint("TOPLEFT", groupFrame, "TOPLEFT", 4, -1)
groupLabel:SetText("小组 " .. g)
for sIdx = 1, RAID_COLS do
local s = sIdx
local slot = CreateFrame("Button", NextName("RS"), groupFrame)
slot:SetWidth(RAID_SLOT_W)
slot:SetHeight(RAID_SLOT_H)
local sx = 2 + (s - 1) * (RAID_SLOT_W + 2)
slot:SetPoint("BOTTOMLEFT", groupFrame, "BOTTOMLEFT", sx, 1)
SetPixelBackdrop(slot, T.raidSlotEmpty, T.slotBorder)
slot.group = g
slot.slotIndex = s
local classIcon = CreateClassIcon(slot, RAID_ICON_SIZE)
classIcon:SetPoint("LEFT", slot, "LEFT", 2, 0)
slot.classIcon = classIcon
local nameFS = MakeFS(slot, 8, "LEFT", T.nameText)
nameFS:SetPoint("LEFT", classIcon, "RIGHT", 2, 0)
nameFS:SetPoint("RIGHT", slot, "RIGHT", -2, 0)
slot.nameFS = nameFS
slot.infoFS = nil
slot:RegisterForClicks("LeftButtonUp", "RightButtonUp")
slot:RegisterForDrag("LeftButton")
slot:SetScript("OnClick", function()
if not this.raidIndex then return end
if arg1 == "RightButton" then
SUI:ShowRaidSlotMenu(this)
end
end)
slot:SetScript("OnDragStart", function()
if not this.raidIndex then return end
if not (IsRaidLeader() or IsRaidOfficer()) then return end
dragSlot = this
if not dragHighlight then
dragHighlight = CreateFrame("Frame", "SFramesRaidDragHL", UIParent)
dragHighlight:SetWidth(RAID_SLOT_W)
dragHighlight:SetHeight(RAID_SLOT_H)
dragHighlight:SetFrameStrata("TOOLTIP")
SetPixelBackdrop(dragHighlight, T.tabActiveBg, T.tabActiveBorder)
local dfs = MakeFS(dragHighlight, 8, "CENTER", T.tabActiveText)
dfs:SetPoint("CENTER", 0, 0)
dragHighlight.text = dfs
end
dragHighlight.text:SetText(this.playerName or "")
local cc = GetClassColor(this.playerClass)
dragHighlight.text:SetTextColor(cc[1], cc[2], cc[3])
dragHighlight:Show()
dragHighlight:SetScript("OnUpdate", function()
local cx, cy = GetCursorPosition()
local s = UIParent:GetEffectiveScale()
dragHighlight:ClearAllPoints()
dragHighlight:SetPoint("CENTER", UIParent, "BOTTOMLEFT", cx / s, cy / s)
end)
end)
slot:SetScript("OnDragStop", function()
if not dragSlot then return end
if dragHighlight then
dragHighlight:Hide()
dragHighlight:SetScript("OnUpdate", nil)
end
local cx, cy = GetCursorPosition()
local es = UIParent:GetEffectiveScale()
cx = cx / es
cy = cy / es
local targetSlot = nil
local targetGroup = nil
for tg = 1, RAID_GROUPS do
for ts = 1, RAID_COLS do
local tSlot = raidSlots[tg] and raidSlots[tg][ts]
if tSlot and tSlot:IsVisible() then
local left = tSlot:GetLeft()
local right = tSlot:GetRight()
local top = tSlot:GetTop()
local bottom = tSlot:GetBottom()
if left and cx >= left and cx <= right and cy >= bottom and cy <= top then
targetSlot = tSlot
targetGroup = tg
break
end
end
end
if targetGroup then break end
end
if not targetGroup then
for tg = 1, RAID_GROUPS do
local gf = raidSlots[tg] and raidSlots[tg][1] and raidSlots[tg][1]:GetParent()
if gf and gf:IsVisible() then
local left = gf:GetLeft()
local right = gf:GetRight()
local top = gf:GetTop()
local bottom = gf:GetBottom()
if left and cx >= left and cx <= right and cy >= bottom and cy <= top then
targetGroup = tg
break
end
end
end
end
if targetGroup and dragSlot.raidIndex and targetGroup ~= dragSlot.group then
if targetSlot and targetSlot.raidIndex and SwapRaidMembers then
SwapRaidMembers(dragSlot.raidIndex, targetSlot.raidIndex)
else
SetRaidSubgroup(dragSlot.raidIndex, targetGroup)
end
end
dragSlot = nil
end)
slot:SetScript("OnEnter", function()
if dragSlot and dragSlot ~= this then
SetPixelBackdrop(this, { 0.30, 0.18, 0.26, 0.9 }, T.tabActiveBorder)
else
SetPixelBackdrop(this, T.slotHover, T.slotSelected)
end
if this.playerName and not dragSlot then
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:AddLine(this.playerName, 1, 1, 1)
if this.playerClass then
local cc = GetClassColor(this.playerClass)
GameTooltip:AddLine(this.playerClass, cc[1], cc[2], cc[3])
end
if this.playerLevel then
GameTooltip:AddLine("等级 " .. this.playerLevel, T.bodyText[1], T.bodyText[2], T.bodyText[3])
end
if IsRaidLeader() or IsRaidOfficer() then
GameTooltip:AddLine("左键拖拽: 移动到其他小组", T.dimText[1], T.dimText[2], T.dimText[3])
end
GameTooltip:AddLine("右键: 团队操作菜单", T.dimText[1], T.dimText[2], T.dimText[3])
GameTooltip:Show()
end
end)
slot:SetScript("OnLeave", function()
if this.raidIndex then
SetPixelBackdrop(this, T.slotBg, T.slotBorder)
else
SetPixelBackdrop(this, T.raidSlotEmpty, T.slotBorder)
end
GameTooltip:Hide()
end)
if not raidSlots[g] then raidSlots[g] = {} end
raidSlots[g][s] = slot
end
end
rScroll:SetContentHeight(RAID_GROUPS * (groupH + RAID_GROUP_PAD))
local btnBar = CreateFrame("Frame", nil, page)
btnBar:SetHeight(BOTTOM_H)
btnBar:SetPoint("BOTTOMLEFT", page, "BOTTOMLEFT", 0, 0)
btnBar:SetPoint("BOTTOMRIGHT", page, "BOTTOMRIGHT", 0, 0)
local convertBtn = MakeButton(btnBar, "转换团队", 80, 22)
convertBtn:SetPoint("BOTTOMLEFT", btnBar, "BOTTOMLEFT", 0, 2)
convertBtn:SetScript("OnClick", function()
if GetNumRaidMembers() == 0 and GetNumPartyMembers() > 0 then
ConvertToRaid()
end
end)
local leaveBtn = MakeButton(btnBar, "离开团队", 80, 22)
leaveBtn:SetPoint("LEFT", convertBtn, "RIGHT", 4, 0)
leaveBtn:SetScript("OnClick", function()
if GetNumRaidMembers() > 0 then LeaveParty() end
end)
local readyBtn = MakeButton(btnBar, "就位确认", 80, 22)
readyBtn:SetPoint("LEFT", leaveBtn, "RIGHT", 4, 0)
readyBtn:SetScript("OnClick", function()
if DoReadyCheck then DoReadyCheck() end
end)
end
function SUI:GetRaidUnitByName(targetName)
for i = 1, 40 do
local u = "raid" .. i
if UnitExists(u) and UnitName(u) == targetName then
return u
end
end
return nil
end
function SUI:ShowRaidSlotMenu(slot)
if not slot.raidIndex then return end
local pName = slot.playerName
if not pName then return end
if not SUI.raidDropDown then
SUI.raidDropDown = CreateFrame("Frame", "SFramesSocialRaidDD", UIParent, "UIDropDownMenuTemplate")
SUI.raidDropDown.displayMode = "MENU"
SUI.raidDropDown.initialize = function()
local rd = SUI.raidDropDown
local name = rd.slotName
local rIdx = rd.slotRaidIndex
local grp = rd.slotGroup
local rnk = rd.slotRank
local isSelf = rd.slotIsSelf
if not name or not rIdx then return end
local isLeader = IsRaidLeader()
local isOfficer = IsRaidOfficer()
local info
info = {}
info.text = name
info.isTitle = 1
info.notCheckable = 1
UIDropDownMenu_AddButton(info)
if not isSelf then
info = {}
info.text = "密语"
info.notCheckable = 1
info.func = function() ChatFrame_SendTell(name) end
UIDropDownMenu_AddButton(info)
info = {}
info.text = "观察"
info.notCheckable = 1
info.func = function()
local u = SUI:GetRaidUnitByName(name)
if u then InspectUnit(u) end
end
UIDropDownMenu_AddButton(info)
end
if isLeader or isOfficer then
for gIdx = 1, RAID_GROUPS do
if gIdx ~= grp then
info = {}
info.text = "移至小组 " .. gIdx
info.notCheckable = 1
local tg = gIdx
info.func = function() SetRaidSubgroup(rIdx, tg) end
UIDropDownMenu_AddButton(info)
end
end
end
if isLeader and not isSelf then
if rnk and rnk < 1 then
info = {}
info.text = "提升为助理"
info.notCheckable = 1
info.func = function() PromoteToAssistant(name) end
UIDropDownMenu_AddButton(info)
elseif rnk and rnk == 1 then
info = {}
info.text = "取消助理"
info.notCheckable = 1
info.func = function() DemoteAssistant(name) end
UIDropDownMenu_AddButton(info)
end
info = {}
info.text = "转让队长"
info.notCheckable = 1
info.func = function()
StaticPopupDialogs["SFRAMES_PROMOTE_LEADER"] = {
text = "确定要将队长转让给 " .. name .. " 吗?",
button1 = "确定",
button2 = "取消",
OnAccept = function() PromoteToLeader(name) end,
timeout = 0,
whileDead = true,
hideOnEscape = true,
}
StaticPopup_Show("SFRAMES_PROMOTE_LEADER")
end
UIDropDownMenu_AddButton(info)
end
if (isLeader or isOfficer) and not isSelf then
info = {}
info.text = "移出团队"
info.notCheckable = 1
info.func = function() UninviteByName(name) end
UIDropDownMenu_AddButton(info)
end
info = {}
info.text = "取消"
info.notCheckable = 1
UIDropDownMenu_AddButton(info)
end
end
SUI.raidDropDown.slotName = pName
SUI.raidDropDown.slotRaidIndex = slot.raidIndex
SUI.raidDropDown.slotGroup = slot.group
SUI.raidDropDown.slotRank = slot.playerRank
SUI.raidDropDown.slotIsSelf = (pName == UnitName("player"))
ToggleDropDownMenu(1, nil, SUI.raidDropDown, "cursor")
end
local function CancelRaidDrag()
if dragSlot then
dragSlot = nil
if dragHighlight then
dragHighlight:Hide()
dragHighlight:SetScript("OnUpdate", nil)
end
end
end
function SUI:UpdateRaidPage()
local page = pages[4]
if not page then return end
local numRaid = GetNumRaidMembers()
-- Clear all slots
for g = 1, RAID_GROUPS do
for s = 1, RAID_COLS do
local slot = raidSlots[g] and raidSlots[g][s]
if slot then
slot.raidIndex = nil
slot.playerName = nil
slot.playerClass = nil
slot.playerRank = nil
slot.playerLevel = nil
slot.nameFS:SetText("")
slot.classIcon:Hide()
SetPixelBackdrop(slot, T.raidSlotEmpty, T.slotBorder)
end
end
end
if numRaid == 0 then
page.raidInfoFS:SetText("你不在团队中")
return
end
page.raidInfoFS:SetText("团队成员: " .. numRaid .. "/40")
local groupCount = {}
for g = 1, RAID_GROUPS do groupCount[g] = 0 end
for i = 1, numRaid do
local name, rank, subgroup, level, class, fileName, zone, online, isDead, role, isML = GetRaidRosterInfo(i)
if name and subgroup then
local g = subgroup
groupCount[g] = (groupCount[g] or 0) + 1
local s = groupCount[g]
if s <= RAID_COLS then
local slot = raidSlots[g] and raidSlots[g][s]
if slot then
slot.raidIndex = i
slot.playerName = name
slot.playerClass = fileName
slot.playerRank = rank
slot.playerLevel = level
local shortName = name
if string.len(name) > 7 then
shortName = string.sub(name, 1, 6) .. ".."
end
local prefix = ""
if rank and rank == 2 then prefix = "*"
elseif rank and rank == 1 then prefix = "+" end
slot.nameFS:SetText(prefix .. shortName)
local cc = GetClassColor(fileName)
slot.nameFS:SetTextColor(cc[1], cc[2], cc[3])
SetClassIcon(slot.classIcon, fileName)
if online then
SetPixelBackdrop(slot, T.slotBg, T.slotBorder)
if isDead then
slot.nameFS:SetTextColor(0.5, 0.2, 0.2)
end
else
SetPixelBackdrop(slot, { 0.06, 0.03, 0.05, 0.7 }, { 0.20, 0.15, 0.18, 0.6 })
slot.nameFS:SetTextColor(T.offlineText[1], T.offlineText[2], T.offlineText[3])
end
end
end
end
end
end
--------------------------------------------------------------------------------
-- Main Tab Switching
--------------------------------------------------------------------------------
local TAB_NAMES = { "好友", "查询", "工会", "团队" }
local function ShowPage(tabIdx)
currentMainTab = tabIdx
for i = 1, 4 do
local p = pages[i]
if p then
if i == tabIdx then p:Show() else p:Hide() end
end
local btn = mainTabs[i]
if btn then
if i == tabIdx then
SetRoundBackdrop(btn, T.tabActiveBg, T.tabActiveBorder)
btn.text:SetTextColor(T.tabActiveText[1], T.tabActiveText[2], T.tabActiveText[3])
else
SetRoundBackdrop(btn, T.tabBg, T.tabBorder)
btn.text:SetTextColor(T.tabText[1], T.tabText[2], T.tabText[3])
end
end
end
if tabIdx == 1 then
if origShowFriendsAPI then origShowFriendsAPI() end
SUI:UpdateFriendsPage()
elseif tabIdx == 2 then
if SetWhoToUI then SetWhoToUI(1) end
SUI:UpdateWhoList()
elseif tabIdx == 3 then
SUI:UpdateGuildList()
elseif tabIdx == 4 then
SUI:UpdateRaidPage()
end
if MainFrame and MainFrame.titleFS then
local titles = { "好友名单", "查询玩家", "公会", "团队" }
if tabIdx == 3 and IsInGuild() then
local guildName = GetGuildInfo("player")
if guildName and guildName ~= "" then
MainFrame.titleFS:SetText("< " .. guildName .. " >")
else
MainFrame.titleFS:SetText(titles[tabIdx])
end
else
MainFrame.titleFS:SetText(titles[tabIdx] or "社交")
end
end
end
--------------------------------------------------------------------------------
-- Build Main Frame
--------------------------------------------------------------------------------
local function BuildMainFrame()
if MainFrame then return end
local f = CreateFrame("Frame", "SFramesSocialUI", UIParent)
f:SetWidth(FRAME_W)
f:SetHeight(FRAME_H)
f:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
f:SetFrameStrata("HIGH")
f:SetFrameLevel(10)
SetRoundBackdrop(f)
CreateShadow(f)
f:EnableMouse(true)
f:SetMovable(true)
f:RegisterForDrag("LeftButton")
f:SetScript("OnDragStart", function() this:StartMoving() end)
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
f:SetScript("OnHide", function() CancelRaidDrag() end)
-- Header
local header = CreateFrame("Frame", nil, f)
header:SetHeight(HEADER_H)
header:SetPoint("TOPLEFT", f, "TOPLEFT", 0, 0)
header:SetPoint("TOPRIGHT", f, "TOPRIGHT", 0, 0)
local titleIco = SFrames:CreateIcon(header, "friends", 14)
titleIco:SetDrawLayer("OVERLAY")
titleIco:SetPoint("CENTER", header, "CENTER", -40, 0)
titleIco:SetVertexColor(T.gold[1], T.gold[2], T.gold[3])
local title = MakeFS(header, 13, "CENTER", T.gold)
title:SetPoint("LEFT", titleIco, "RIGHT", 4, 0)
title:SetText("好友名单")
f.titleFS = title
local closeBtn = CreateFrame("Button", NextName("Close"), header)
closeBtn:SetWidth(20)
closeBtn:SetHeight(20)
closeBtn:SetPoint("RIGHT", header, "RIGHT", -6, 0)
closeBtn:SetScript("OnClick", function() f:Hide() end)
local closeIco = SFrames:CreateIcon(closeBtn, "close", 12)
closeIco:SetDrawLayer("OVERLAY")
closeIco:SetPoint("CENTER", closeBtn, "CENTER", 0, 0)
closeIco:SetVertexColor(1, 0.7, 0.7)
closeBtn:SetScript("OnEnter", function()
closeIco:SetVertexColor(1, 0.4, 0.5)
end)
closeBtn:SetScript("OnLeave", function()
closeIco:SetVertexColor(1, 0.7, 0.7)
end)
-- Main tabs (use this.tabIndex to avoid closure issues)
local tabContainer = CreateFrame("Frame", nil, f)
tabContainer:SetHeight(TAB_BAR_H)
tabContainer:SetPoint("TOPLEFT", f, "TOPLEFT", SIDE_PAD, -(HEADER_H + 2))
tabContainer:SetPoint("TOPRIGHT", f, "TOPRIGHT", -SIDE_PAD, -(HEADER_H + 2))
local tabW = math.floor((CONTENT_W - 6) / 4)
for idx = 1, 4 do
local tabIdx = idx
local btn = CreateFrame("Button", NextName("MTab"), tabContainer)
btn:SetWidth(tabW)
btn:SetHeight(TAB_BAR_H - 2)
btn.tabIndex = tabIdx
if tabIdx == 1 then
btn:SetPoint("LEFT", tabContainer, "LEFT", 0, 0)
else
btn:SetPoint("LEFT", mainTabs[tabIdx - 1], "RIGHT", 2, 0)
end
SetRoundBackdrop(btn, T.tabBg, T.tabBorder)
local text = MakeFS(btn, 10, "CENTER", T.tabText)
text:SetPoint("CENTER", 0, 0)
text:SetText(TAB_NAMES[tabIdx])
btn.text = text
btn:SetScript("OnClick", function()
ShowPage(this.tabIndex)
end)
mainTabs[tabIdx] = btn
end
-- Content pages
local contentTop = -(HEADER_H + TAB_BAR_H + 6)
for i = 1, 4 do
local page = CreateFrame("Frame", nil, f)
page:SetPoint("TOPLEFT", f, "TOPLEFT", SIDE_PAD, contentTop)
page:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -SIDE_PAD, SIDE_PAD)
page:Hide()
pages[i] = page
end
BuildFriendsPage(pages[1])
BuildWhoPage(pages[2])
BuildGuildPage(pages[3])
BuildRaidPage(pages[4])
table.insert(UISpecialFrames, "SFramesSocialUI")
local scale = SFramesDB.socialScale or 1
if scale ~= 1 then f:SetScale(scale) end
MainFrame = f
f:Hide()
end
--------------------------------------------------------------------------------
-- Public API
--------------------------------------------------------------------------------
function SUI:Toggle(tabIdx)
if not initialized then return end
if not MainFrame then BuildMainFrame() end
if MainFrame:IsShown() then
if tabIdx and tabIdx ~= currentMainTab then
ShowPage(tabIdx)
else
MainFrame:Hide()
end
else
MainFrame:Show()
ShowPage(tabIdx or 1)
end
end
function SUI:Show(tabIdx)
if not initialized then return end
if not MainFrame then BuildMainFrame() end
MainFrame:Show()
ShowPage(tabIdx or 1)
end
function SUI:Hide()
if MainFrame then MainFrame:Hide() end
end
function SUI:IsShown()
return MainFrame and MainFrame:IsShown()
end
--------------------------------------------------------------------------------
-- Initialize
--------------------------------------------------------------------------------
function SUI:Initialize()
if initialized then return end
initialized = true
guildHideOffline = SFramesDB.guildHideOffline or false
BuildClassReverseLookup()
HideBlizzardFriends()
BuildMainFrame()
local ef = CreateFrame("Frame", nil, UIParent)
ef:RegisterEvent("FRIENDLIST_UPDATE")
ef:RegisterEvent("IGNORELIST_UPDATE")
ef:RegisterEvent("WHO_LIST_UPDATE")
ef:RegisterEvent("GUILD_ROSTER_UPDATE")
ef:RegisterEvent("RAID_ROSTER_UPDATE")
ef:RegisterEvent("PARTY_MEMBERS_CHANGED")
ef:SetScript("OnEvent", function()
if event == "WHO_LIST_UPDATE" then
local n, t = GetNumWhoResults()
WhoDebug("收到 WHO_LIST_UPDATE! 结果=" .. tostring(n) .. " 总计=" .. tostring(t) .. " pending=" .. tostring(whoQueryPending))
local wasPending = whoQueryPending
whoQueryPending = false
if SetWhoToUI then SetWhoToUI(1) end
if FriendsFrame and FriendsFrame:IsShown() then
FriendsFrame:Hide()
end
if MainFrame and MainFrame:IsShown() and currentMainTab == 2 then
WhoDebug("更新列表显示")
SUI:UpdateWhoList()
else
WhoDebug("自动打开查询页显示结果")
if not MainFrame then BuildMainFrame() end
if MainFrame then
MainFrame:Show()
ShowPage(2)
SUI:UpdateWhoList()
end
end
return
end
if not MainFrame or not MainFrame:IsShown() then return end
if event == "FRIENDLIST_UPDATE" or event == "IGNORELIST_UPDATE" then
if currentMainTab == 1 then SUI:UpdateFriendsPage() end
elseif event == "GUILD_ROSTER_UPDATE" then
if currentMainTab == 3 then SUI:UpdateGuildList() end
elseif event == "RAID_ROSTER_UPDATE" or event == "PARTY_MEMBERS_CHANGED" then
if currentMainTab == 4 then SUI:UpdateRaidPage() end
end
end)
end
--------------------------------------------------------------------------------
-- Hook ToggleFriendsFrame
--------------------------------------------------------------------------------
local origToggleFriendsFrame = ToggleFriendsFrame
ToggleFriendsFrame = function(tab)
if SFramesDB and SFramesDB.enableSocial == false then
if origToggleFriendsFrame then
if origFriendsFrameShow and FriendsFrame then
FriendsFrame.Show = origFriendsFrameShow
end
origToggleFriendsFrame(tab)
end
return
end
SUI:Toggle(tab or 1)
end
if ShowFriends then
origShowFriendsAPI = ShowFriends
local origShowFriends = ShowFriends
ShowFriends = function()
if SFramesDB and SFramesDB.enableSocial == false then
if origShowFriends then origShowFriends() end
return
end
SUI:Show(1)
end
end
--------------------------------------------------------------------------------
-- Hook SetItemRef: shift-click player name -> WHO query in our panel
--------------------------------------------------------------------------------
do
local origSetItemRef_SUI = SetItemRef
SetItemRef = function(link, text, button)
if link and IsShiftKeyDown and IsShiftKeyDown() then
local playerName = nil
if string.sub(link, 1, 7) == "player:" then
playerName = string.sub(link, 8)
local colonPos = string.find(playerName, ":")
if colonPos then playerName = string.sub(playerName, 1, colonPos - 1) end
end
if playerName and playerName ~= "" then
if SFramesDB and SFramesDB.enableSocial ~= false and initialized then
WhoDebug("Shift点击玩家: " .. playerName .. ", 发起WHO查询")
local query = "n-\"" .. playerName .. "\""
if not MainFrame then BuildMainFrame() end
if MainFrame then
MainFrame:Show()
ShowPage(2)
end
if pages[2] and pages[2].editBox then
pages[2].editBox:SetText(playerName)
if pages[2].editBox.placeholder then
pages[2].editBox.placeholder:Hide()
end
end
SUI:ClearWhoList()
DoSendWho(query)
return
end
end
end
if origSetItemRef_SUI then
origSetItemRef_SUI(link, text, button)
end
end
end
--------------------------------------------------------------------------------
-- Bootstrap
--------------------------------------------------------------------------------
local bootstrap = CreateFrame("Frame", nil, UIParent)
bootstrap:RegisterEvent("PLAYER_LOGIN")
bootstrap:SetScript("OnEvent", function()
if event == "PLAYER_LOGIN" then
if SFramesDB.enableSocial == nil then
SFramesDB.enableSocial = true
end
if SFramesDB.enableSocial ~= false then
SUI:Initialize()
end
end
end)