修复拾取界面点击无效问题 修复宠物训练界面不显示训练点问题 新增天赋分享到聊天界面 修复飞行界面无法关闭问题 修复术士宠物的显示问题 为天赋界面添加默认数据库支持 框架现在也可自主选择是否启用 玩家框架和目标框架可取消显示3D头像以及透明度修改 背包和银行也添加透明度自定义支持 优化tooltip性能和背包物品显示方式 修复布局模式在ui缩放后不能正常定位的问题 添加硬核模式危险和死亡的工会通报 添加拾取和已拾取的框体 等等
2671 lines
96 KiB
Lua
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)
|