2247 lines
93 KiB
Lua
2247 lines
93 KiB
Lua
--------------------------------------------------------------------------------
|
||
-- Nanami-UI: Mail UI (Mail.lua)
|
||
-- Replaces MailFrame with Nanami-UI styled interface
|
||
-- Tabs: Inbox / Send
|
||
-- Inbox: select-all / per-item checkboxes, batch collect
|
||
-- Send: multi-item queue, split into individual sends
|
||
--------------------------------------------------------------------------------
|
||
|
||
SFrames = SFrames or {}
|
||
SFrames.Mail = {}
|
||
local ML = SFrames.Mail
|
||
SFramesDB = SFramesDB or {}
|
||
if SFramesDB.mailContacts == nil then
|
||
SFramesDB.mailContacts = {}
|
||
end
|
||
|
||
-- Save original Blizzard functions BEFORE other addons (TurtleMail etc.) hook them.
|
||
-- File-level locals are captured at load time, which is before later-alphabetical addons.
|
||
local _ClickSendMailItemButton = ClickSendMailItemButton
|
||
local _PickupContainerItem = PickupContainerItem
|
||
local _ClearCursor = ClearCursor
|
||
local _SendMail = SendMail
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Theme
|
||
--------------------------------------------------------------------------------
|
||
local T = SFrames.Theme:Extend({
|
||
moneyGold = { 1, 0.84, 0.0 },
|
||
moneySilver = { 0.78, 0.78, 0.78 },
|
||
moneyCopper = { 0.71, 0.43, 0.18 },
|
||
codColor = { 1.0, 0.35, 0.35 },
|
||
unreadMark = { 1.0, 0.85, 0.3 },
|
||
successText = { 0.3, 1.0, 0.4 },
|
||
errorText = { 1.0, 0.3, 0.3 },
|
||
friendColor = { 0.3, 1.0, 0.5 },
|
||
guildColor = { 0.4, 0.8, 1.0 },
|
||
whoColor = { 0.85, 0.85, 0.85 },
|
||
})
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Shared state table (avoids excessive upvalues)
|
||
--------------------------------------------------------------------------------
|
||
local S = {
|
||
frame = nil, -- MainFrame
|
||
inboxRows = {},
|
||
currentTab = 1,
|
||
inboxPage = 1,
|
||
bagPage = 1,
|
||
inboxChecked = {},
|
||
collectQueue = {},
|
||
collectTimer = nil,
|
||
isCollecting = false,
|
||
sendQueue = {},
|
||
isSending = false,
|
||
collectElapsed = 0,
|
||
multiSend = nil, -- active multi-send state table
|
||
codMode = false, -- send panel: 付款取信 mode toggle
|
||
}
|
||
|
||
local L = {
|
||
W = 360, H = 480, HEADER = 34, PAD = 12, TAB_H = 28,
|
||
BOTTOM = 46, ROWS = 8, ROW_H = 38, ICON = 30, MAX_SEND = 12,
|
||
BAG_SLOT = 38, BAG_GAP = 3, BAG_PER_ROW = 8, BAG_ROWS = 8,
|
||
}
|
||
|
||
StaticPopupDialogs["NANAMI_MAIL_COD_CONFIRM"] = {
|
||
text = "确认支付 %s 取回此物品?",
|
||
button1 = "确认",
|
||
button2 = "取消",
|
||
OnAccept = function() end,
|
||
timeout = 0,
|
||
whileDead = true,
|
||
hideOnEscape = true,
|
||
}
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Helpers
|
||
--------------------------------------------------------------------------------
|
||
local function GetFont()
|
||
if SFrames and SFrames.GetFont then return SFrames:GetFont() end
|
||
return "Fonts\\ARIALN.TTF"
|
||
end
|
||
|
||
local function SetRoundBackdrop(frame)
|
||
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 },
|
||
})
|
||
frame:SetBackdropColor(T.panelBg[1], T.panelBg[2], T.panelBg[3], T.panelBg[4])
|
||
frame:SetBackdropBorderColor(T.panelBorder[1], T.panelBorder[2], T.panelBorder[3], T.panelBorder[4])
|
||
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: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.45)
|
||
s:SetBackdropBorderColor(0, 0, 0, 0.6)
|
||
s:SetFrameLevel(math.max(0, parent:GetFrameLevel() - 1))
|
||
return s
|
||
end
|
||
|
||
local function FormatMoneyString(copper)
|
||
if not copper or copper <= 0 then return "0|cFFB87333c|r" end
|
||
local g = math.floor(copper / 10000)
|
||
local sv = math.floor(math.mod(copper, 10000) / 100)
|
||
local c = math.mod(copper, 100)
|
||
local parts = ""
|
||
if g > 0 then parts = parts .. "|cFFFFD700" .. g .. "g|r " end
|
||
if sv > 0 then parts = parts .. "|cFFC7C7CF" .. sv .. "s|r " end
|
||
if c > 0 then parts = parts .. "|cFFB87333" .. c .. "c|r" end
|
||
return parts
|
||
end
|
||
|
||
local function CreateMoneyIcons(parent, fontSize, iconSize)
|
||
fontSize = fontSize or 10
|
||
iconSize = iconSize or 11
|
||
local font = GetFont()
|
||
local mf = CreateFrame("Frame", nil, parent)
|
||
mf:SetWidth(100); mf:SetHeight(iconSize + 2)
|
||
|
||
local function MakePair(mfRef, r, g, b, tcL, tcR)
|
||
local txt = mfRef:CreateFontString(nil, "OVERLAY")
|
||
txt:SetFont(font, fontSize, "OUTLINE"); txt:SetTextColor(r, g, b)
|
||
local tex = mfRef:CreateTexture(nil, "ARTWORK")
|
||
tex:SetTexture("Interface\\MoneyFrame\\UI-MoneyIcons")
|
||
tex:SetTexCoord(tcL, tcR, 0, 1); tex:SetWidth(iconSize); tex:SetHeight(iconSize)
|
||
return txt, tex
|
||
end
|
||
mf.gTxt, mf.gTex = MakePair(mf, 1, 0.84, 0, 0, 0.25)
|
||
mf.sTxt, mf.sTex = MakePair(mf, 0.78, 0.78, 0.81, 0.25, 0.5)
|
||
mf.cTxt, mf.cTex = MakePair(mf, 0.72, 0.45, 0.2, 0.5, 0.75)
|
||
|
||
function mf:SetMoney(copper)
|
||
copper = copper or 0
|
||
local gv = math.floor(copper / 10000)
|
||
local sv = math.floor(math.mod(copper, 10000) / 100)
|
||
local cv = math.mod(copper, 100)
|
||
self.gTxt:Hide(); self.gTex:Hide(); self.gTxt:ClearAllPoints()
|
||
self.sTxt:Hide(); self.sTex:Hide(); self.sTxt:ClearAllPoints()
|
||
self.cTxt:Hide(); self.cTex:Hide(); self.cTxt:ClearAllPoints()
|
||
self.gTex:ClearAllPoints(); self.sTex:ClearAllPoints(); self.cTex:ClearAllPoints()
|
||
if copper <= 0 then return end
|
||
local anchor = nil
|
||
local function Attach(txt, tex, val)
|
||
txt:SetText(val)
|
||
txt:ClearAllPoints(); tex:ClearAllPoints()
|
||
if anchor then txt:SetPoint("LEFT", anchor, "RIGHT", 3, 0)
|
||
else txt:SetPoint("LEFT", self, "LEFT", 0, 0) end
|
||
tex:SetPoint("LEFT", txt, "RIGHT", 1, 0)
|
||
txt:Show(); tex:Show()
|
||
anchor = tex
|
||
end
|
||
if gv > 0 then Attach(self.gTxt, self.gTex, gv) end
|
||
if sv > 0 then Attach(self.sTxt, self.sTex, sv) end
|
||
if cv > 0 then Attach(self.cTxt, self.cTex, cv) end
|
||
end
|
||
return mf
|
||
end
|
||
|
||
local function FormatExpiry(daysLeft)
|
||
if not daysLeft then return "" end
|
||
local d = math.floor(daysLeft)
|
||
if d <= 0 then return "|cFFFF3333即将过期|r" end
|
||
if d == 1 then return "|cFFFF6633剩余 1 天|r" end
|
||
if d <= 3 then return "|cFFFFAA33剩余 " .. d .. " 天|r" end
|
||
return "|cFF88FF88" .. d .. " 天|r"
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Action Button Factory
|
||
--------------------------------------------------------------------------------
|
||
local function CreateActionBtn(parent, text, w)
|
||
local btn = CreateFrame("Button", nil, parent)
|
||
btn:SetWidth(w or 100)
|
||
btn:SetHeight(26)
|
||
btn: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 },
|
||
})
|
||
btn:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
|
||
btn:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
|
||
|
||
local fs = btn:CreateFontString(nil, "OVERLAY")
|
||
fs:SetFont(GetFont(), 11, "OUTLINE")
|
||
fs:SetPoint("CENTER", 0, 0)
|
||
fs:SetText(text)
|
||
fs:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
|
||
btn.label = fs
|
||
|
||
btn.disabled = false
|
||
function btn:SetDisabled(flag)
|
||
self.disabled = flag
|
||
if flag then
|
||
self.label:SetTextColor(T.btnDisabledText[1], T.btnDisabledText[2], T.btnDisabledText[3])
|
||
self:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], 0.5)
|
||
else
|
||
self.label:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
|
||
self:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
|
||
end
|
||
end
|
||
|
||
btn:SetScript("OnEnter", function()
|
||
if not this.disabled then
|
||
this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
|
||
this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
|
||
this.label:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3])
|
||
end
|
||
end)
|
||
btn:SetScript("OnLeave", function()
|
||
if not this.disabled then
|
||
this:SetBackdropColor(T.btnBg[1], T.btnBg[2], T.btnBg[3], T.btnBg[4])
|
||
this:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
|
||
this.label:SetTextColor(T.btnText[1], T.btnText[2], T.btnText[3])
|
||
end
|
||
end)
|
||
btn:SetScript("OnMouseDown", function()
|
||
if not this.disabled then
|
||
this:SetBackdropColor(T.btnDownBg[1], T.btnDownBg[2], T.btnDownBg[3], T.btnDownBg[4])
|
||
end
|
||
end)
|
||
btn:SetScript("OnMouseUp", function()
|
||
if not this.disabled then
|
||
this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
|
||
end
|
||
end)
|
||
|
||
btn:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
|
||
return btn
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Tab Button Factory
|
||
--------------------------------------------------------------------------------
|
||
local function CreateTabBtn(parent, text, w)
|
||
local btn = CreateFrame("Button", nil, parent)
|
||
btn:SetWidth(w or 70)
|
||
btn:SetHeight(22)
|
||
btn:SetBackdrop({
|
||
bgFile = "Interface\\Buttons\\WHITE8X8",
|
||
edgeFile = "Interface\\Buttons\\WHITE8X8",
|
||
tile = false, tileSize = 0, edgeSize = 1,
|
||
insets = { left = 1, right = 1, top = 1, bottom = 1 },
|
||
})
|
||
btn:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
|
||
btn:SetBackdropBorderColor(T.tabBorder[1], T.tabBorder[2], T.tabBorder[3], 0.5)
|
||
|
||
local fs = btn:CreateFontString(nil, "OVERLAY")
|
||
fs:SetFont(GetFont(), 12, "OUTLINE")
|
||
fs:SetPoint("CENTER", 0, 0)
|
||
fs:SetText(text)
|
||
fs:SetTextColor(T.tabText[1], T.tabText[2], T.tabText[3])
|
||
btn.label = fs
|
||
|
||
btn:SetScript("OnEnter", function()
|
||
if not this.active then
|
||
this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4])
|
||
this:SetBackdropBorderColor(T.btnHoverBd[1], T.btnHoverBd[2], T.btnHoverBd[3], T.btnHoverBd[4])
|
||
end
|
||
end)
|
||
btn:SetScript("OnLeave", function()
|
||
if this.active then
|
||
this:SetBackdropColor(T.tabActiveBg[1], T.tabActiveBg[2], T.tabActiveBg[3], T.tabActiveBg[4])
|
||
this:SetBackdropBorderColor(T.tabActiveBorder[1], T.tabActiveBorder[2], T.tabActiveBorder[3], T.tabActiveBorder[4])
|
||
else
|
||
this:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
|
||
this:SetBackdropBorderColor(T.tabBorder[1], T.tabBorder[2], T.tabBorder[3], 0.5)
|
||
end
|
||
end)
|
||
|
||
function btn:SetActive(flag)
|
||
self.active = flag
|
||
if flag then
|
||
self:SetBackdropColor(T.tabActiveBg[1], T.tabActiveBg[2], T.tabActiveBg[3], T.tabActiveBg[4])
|
||
self:SetBackdropBorderColor(T.tabActiveBorder[1], T.tabActiveBorder[2], T.tabActiveBorder[3], T.tabActiveBorder[4])
|
||
self.label:SetTextColor(T.tabActiveText[1], T.tabActiveText[2], T.tabActiveText[3])
|
||
else
|
||
self:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
|
||
self:SetBackdropBorderColor(T.tabBorder[1], T.tabBorder[2], T.tabBorder[3], 0.5)
|
||
self.label:SetTextColor(T.tabText[1], T.tabText[2], T.tabText[3])
|
||
end
|
||
end
|
||
|
||
return btn
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Checkbox Factory
|
||
--------------------------------------------------------------------------------
|
||
local function CreateSmallCheckbox(parent, size)
|
||
local sz = size or 16
|
||
local cb = CreateFrame("Button", nil, parent)
|
||
cb:SetWidth(sz); cb:SetHeight(sz)
|
||
cb:SetBackdrop({
|
||
bgFile = "Interface\\Buttons\\WHITE8X8", edgeFile = "Interface\\Buttons\\WHITE8X8",
|
||
tile = false, tileSize = 0, edgeSize = 1, insets = { left = 1, right = 1, top = 1, bottom = 1 },
|
||
})
|
||
cb:SetBackdropColor(T.checkBg[1], T.checkBg[2], T.checkBg[3], T.checkBg[4])
|
||
cb:SetBackdropBorderColor(T.checkBorder[1], T.checkBorder[2], T.checkBorder[3], T.checkBorder[4])
|
||
local mark = cb:CreateTexture(nil, "OVERLAY")
|
||
mark:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||
mark:SetAllPoints(cb); mark:Hide()
|
||
cb.mark = mark; cb.checked = false
|
||
function cb:SetChecked(flag)
|
||
self.checked = flag
|
||
if flag then self.mark:Show(); self:SetBackdropColor(T.checkFill[1], T.checkFill[2], T.checkFill[3], 0.3)
|
||
else self.mark:Hide(); self:SetBackdropColor(T.checkBg[1], T.checkBg[2], T.checkBg[3], T.checkBg[4]) end
|
||
end
|
||
function cb:IsChecked() return self.checked end
|
||
cb:SetScript("OnClick", function()
|
||
this:SetChecked(not this.checked)
|
||
if this.onToggle then this.onToggle(this.checked) end
|
||
end)
|
||
cb:SetScript("OnEnter", function() this:SetBackdropBorderColor(T.checkHoverBorder[1], T.checkHoverBorder[2], T.checkHoverBorder[3], T.checkHoverBorder[4]) end)
|
||
cb:SetScript("OnLeave", function() this:SetBackdropBorderColor(T.checkBorder[1], T.checkBorder[2], T.checkBorder[3], T.checkBorder[4]) end)
|
||
return cb
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Styled EditBox Factory
|
||
--------------------------------------------------------------------------------
|
||
local function CreateStyledEditBox(parent, width, height, numeric)
|
||
local eb = CreateFrame("EditBox", nil, parent)
|
||
eb:SetWidth(width or 120); eb:SetHeight(height or 22)
|
||
eb:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 },
|
||
})
|
||
eb:SetBackdropColor(T.inputBg[1], T.inputBg[2], T.inputBg[3], T.inputBg[4] or 0.95)
|
||
eb:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], 0.8)
|
||
eb:SetFont(GetFont(), 11, "OUTLINE")
|
||
eb:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
|
||
eb:SetJustifyH("LEFT"); eb:SetAutoFocus(false); eb:SetTextInsets(6, 6, 2, 2)
|
||
if numeric then eb:SetNumeric(true) end
|
||
return eb
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- INBOX: Row Factory
|
||
--------------------------------------------------------------------------------
|
||
local function CreateInboxRow(parent, index)
|
||
local row = CreateFrame("Frame", "SFramesMailInboxRow" .. index, parent)
|
||
row:SetWidth(L.W - L.PAD * 2); row:SetHeight(L.ROW_H)
|
||
local bg = row:CreateTexture(nil, "BACKGROUND")
|
||
bg:SetTexture("Interface\\Buttons\\WHITE8X8"); bg:SetAllPoints(row)
|
||
local normalR, normalG, normalB, normalA
|
||
if math.mod(index, 2) == 0 then
|
||
normalR, normalG, normalB, normalA = T.rowNormal[1], T.rowNormal[2], T.rowNormal[3], T.rowNormal[4]
|
||
else
|
||
normalR, normalG, normalB, normalA = T.panelBg[1], T.panelBg[2], T.panelBg[3], 0.3
|
||
end
|
||
bg:SetVertexColor(normalR, normalG, normalB, normalA)
|
||
row.bg = bg
|
||
|
||
local hl = row:CreateTexture(nil, "ARTWORK")
|
||
hl:SetTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||
hl:SetBlendMode("ADD"); hl:SetAllPoints(row); hl:SetAlpha(0); hl:Hide()
|
||
row.highlight = hl
|
||
|
||
row:EnableMouse(false)
|
||
|
||
local cb = CreateSmallCheckbox(row, 16)
|
||
cb:SetPoint("LEFT", row, "LEFT", 4, 0)
|
||
cb:SetFrameLevel(row:GetFrameLevel() + 10)
|
||
row.checkbox = cb
|
||
|
||
local iconFrame = CreateFrame("Frame", nil, row)
|
||
iconFrame:SetWidth(L.ICON); iconFrame:SetHeight(L.ICON)
|
||
iconFrame:SetPoint("LEFT", cb, "RIGHT", 6, 0)
|
||
iconFrame:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 },
|
||
})
|
||
iconFrame:SetBackdropColor(T.slotBg[1], T.slotBg[2], T.slotBg[3], T.slotBg[4])
|
||
iconFrame:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
iconFrame:EnableMouse(true)
|
||
iconFrame:SetScript("OnEnter", function()
|
||
if not row.mailIndex then return end
|
||
row.highlight:SetAlpha(0.1); row.highlight:Show()
|
||
GameTooltip:SetOwner(iconFrame, "ANCHOR_RIGHT")
|
||
pcall(GameTooltip.SetInboxItem, GameTooltip, row.mailIndex)
|
||
GameTooltip:Show()
|
||
end)
|
||
iconFrame:SetScript("OnLeave", function()
|
||
row.highlight:SetAlpha(0); row.highlight:Hide()
|
||
GameTooltip:Hide()
|
||
end)
|
||
iconFrame:SetScript("OnMouseUp", function()
|
||
if row.mailIndex then ML:ShowMailDetail(row.mailIndex) end
|
||
end)
|
||
row.iconFrame = iconFrame
|
||
|
||
local icon = iconFrame:CreateTexture(nil, "ARTWORK")
|
||
icon:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||
icon:SetPoint("TOPLEFT", 3, -3); icon:SetPoint("BOTTOMRIGHT", -3, 3)
|
||
row.icon = icon
|
||
|
||
local font = GetFont()
|
||
local senderFS = row:CreateFontString(nil, "OVERLAY")
|
||
senderFS:SetFont(font, 11, "OUTLINE")
|
||
senderFS:SetPoint("TOPLEFT", iconFrame, "TOPRIGHT", 6, -2)
|
||
senderFS:SetWidth(110); senderFS:SetJustifyH("LEFT")
|
||
senderFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
|
||
row.senderFS = senderFS
|
||
|
||
local subjectFS = row:CreateFontString(nil, "OVERLAY")
|
||
subjectFS:SetFont(font, 9, "OUTLINE")
|
||
subjectFS:SetPoint("TOPLEFT", senderFS, "BOTTOMLEFT", 0, -1)
|
||
subjectFS:SetWidth(110); subjectFS:SetJustifyH("LEFT")
|
||
subjectFS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
|
||
row.subjectFS = subjectFS
|
||
|
||
local moneyFrame = CreateMoneyIcons(row, 9, 10)
|
||
moneyFrame:SetPoint("RIGHT", row, "RIGHT", -52, 6)
|
||
row.moneyFrame = moneyFrame
|
||
|
||
local codFS = row:CreateFontString(nil, "OVERLAY")
|
||
codFS:SetFont(font, 9, "OUTLINE"); codFS:SetTextColor(1, 0.33, 0.33)
|
||
codFS:SetPoint("RIGHT", moneyFrame, "LEFT", -2, 0)
|
||
codFS:Hide()
|
||
row.codFS = codFS
|
||
|
||
local expiryFS = row:CreateFontString(nil, "OVERLAY")
|
||
expiryFS:SetFont(font, 9, "OUTLINE")
|
||
expiryFS:SetPoint("RIGHT", row, "RIGHT", -52, -6); expiryFS:SetJustifyH("RIGHT")
|
||
row.expiryFS = expiryFS
|
||
|
||
local takeBtn = CreateActionBtn(row, "收取", 40)
|
||
takeBtn:SetHeight(17); takeBtn:SetPoint("TOPRIGHT", row, "TOPRIGHT", -6, -3)
|
||
takeBtn:SetFrameLevel(row:GetFrameLevel() + 10)
|
||
row.takeBtn = takeBtn
|
||
|
||
local returnBtn = CreateActionBtn(row, "退回", 40)
|
||
returnBtn:SetHeight(17); returnBtn:SetPoint("BOTTOMRIGHT", row, "BOTTOMRIGHT", -6, 3)
|
||
returnBtn:SetFrameLevel(row:GetFrameLevel() + 10)
|
||
row.returnBtn = returnBtn
|
||
|
||
row.mailIndex = nil
|
||
return row
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- INBOX: Update
|
||
--------------------------------------------------------------------------------
|
||
local function UpdateInbox()
|
||
if not S.frame or not S.frame:IsVisible() or S.currentTab ~= 1 then return end
|
||
local numItems = GetInboxNumItems()
|
||
local totalPages = math.max(1, math.ceil(numItems / L.ROWS))
|
||
if S.inboxPage > totalPages then S.inboxPage = totalPages end
|
||
if S.inboxPage < 1 then S.inboxPage = 1 end
|
||
|
||
S.frame.inboxPageText:SetText(string.format("第 %d / %d 页 (%d 封)", S.inboxPage, totalPages, numItems))
|
||
S.frame.inboxPrevBtn:SetDisabled(S.inboxPage <= 1)
|
||
S.frame.inboxNextBtn:SetDisabled(S.inboxPage >= totalPages)
|
||
|
||
for i = 1, L.ROWS do
|
||
local row = S.inboxRows[i]
|
||
local mi = (S.inboxPage - 1) * L.ROWS + i
|
||
if mi <= numItems then
|
||
local _, _, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead = GetInboxHeaderInfo(mi)
|
||
row.mailIndex = mi
|
||
if hasItem then
|
||
local _, itemTex = GetInboxItem(mi)
|
||
row.icon:SetTexture(itemTex or "Interface\\Icons\\INV_Misc_Note_01")
|
||
elseif money and money > 0 then
|
||
row.icon:SetTexture("Interface\\Icons\\INV_Misc_Coin_01")
|
||
else
|
||
row.icon:SetTexture("Interface\\Icons\\INV_Misc_Note_01")
|
||
end
|
||
row.senderFS:SetText(sender or "未知")
|
||
if not wasRead then
|
||
row.senderFS:SetTextColor(T.unreadMark[1], T.unreadMark[2], T.unreadMark[3])
|
||
else
|
||
row.senderFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
|
||
end
|
||
row.subjectFS:SetText(subject or "")
|
||
row.codFS:Hide(); row.codFS:SetText("")
|
||
if money and money > 0 then
|
||
row.moneyFrame:SetMoney(money)
|
||
elseif CODAmount and CODAmount > 0 then
|
||
row.codFS:SetText("付款:"); row.codFS:Show()
|
||
row.moneyFrame:SetMoney(CODAmount)
|
||
else
|
||
row.moneyFrame:SetMoney(0)
|
||
end
|
||
row.expiryFS:SetText(FormatExpiry(daysLeft))
|
||
local canTake = hasItem or (money and money > 0)
|
||
row.takeBtn:SetDisabled(not canTake)
|
||
row.takeBtn:SetScript("OnClick", function()
|
||
if row.mailIndex then
|
||
if hasItem then
|
||
if CODAmount and CODAmount > 0 then
|
||
local codStr = FormatMoneyString(CODAmount)
|
||
local idx = row.mailIndex
|
||
StaticPopupDialogs["NANAMI_MAIL_COD_CONFIRM"].OnAccept = function()
|
||
TakeInboxItem(idx)
|
||
end
|
||
StaticPopup_Show("NANAMI_MAIL_COD_CONFIRM", codStr)
|
||
else
|
||
TakeInboxItem(row.mailIndex)
|
||
end
|
||
elseif money and money > 0 then
|
||
local idx = row.mailIndex
|
||
TakeInboxMoney(idx)
|
||
if not S.deleteTimer then S.deleteTimer = CreateFrame("Frame") end
|
||
S.deleteElapsed = 0
|
||
S.deleteTimer:SetScript("OnUpdate", function()
|
||
S.deleteElapsed = S.deleteElapsed + arg1
|
||
if S.deleteElapsed >= 0.5 then
|
||
this:SetScript("OnUpdate", nil)
|
||
if idx <= GetInboxNumItems() then DeleteInboxItem(idx) end
|
||
end
|
||
end)
|
||
end
|
||
end
|
||
end)
|
||
row.returnBtn:SetScript("OnClick", function()
|
||
if row.mailIndex then ReturnInboxItem(row.mailIndex) end
|
||
end)
|
||
row.checkbox:SetChecked(S.inboxChecked[mi] == true)
|
||
row.checkbox.onToggle = function(checked)
|
||
S.inboxChecked[mi] = checked or nil
|
||
local any = false
|
||
for _, v in pairs(S.inboxChecked) do if v then any = true; break end end
|
||
S.frame.collectSelectedBtn:SetDisabled(not any)
|
||
end
|
||
if CODAmount and CODAmount > 0 then
|
||
row.checkbox:SetChecked(false); row.checkbox.disabled = true; S.inboxChecked[mi] = nil
|
||
else
|
||
row.checkbox.disabled = false
|
||
end
|
||
row:Show()
|
||
else
|
||
row.mailIndex = nil; row:Hide()
|
||
end
|
||
end
|
||
|
||
local hasChecked = false
|
||
for _, v in pairs(S.inboxChecked) do if v then hasChecked = true; break end end
|
||
S.frame.collectSelectedBtn:SetDisabled(not hasChecked and not S.isCollecting)
|
||
S.frame.collectAllBtn:SetDisabled(numItems == 0 and not S.isCollecting)
|
||
if S.isCollecting then
|
||
S.frame.collectAllBtn.label:SetText("收取中...")
|
||
S.frame.collectSelectedBtn.label:SetText("收取中...")
|
||
else
|
||
S.frame.collectAllBtn.label:SetText("全部收取")
|
||
S.frame.collectSelectedBtn.label:SetText("收取选中")
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- INBOX: Batch Collect
|
||
--------------------------------------------------------------------------------
|
||
local function StopCollecting()
|
||
S.isCollecting = false; S.collectQueue = {}; S.collectPendingDelete = nil
|
||
if S.collectTimer then S.collectTimer:SetScript("OnUpdate", nil) end
|
||
if S.currentTab == 3 then ML:UpdateMailBag() else UpdateInbox() end
|
||
end
|
||
|
||
local function ProcessCollectQueue()
|
||
if S.collectPendingDelete then
|
||
local mi = S.collectPendingDelete
|
||
S.collectPendingDelete = nil
|
||
if mi <= GetInboxNumItems() then DeleteInboxItem(mi) end
|
||
return
|
||
end
|
||
if table.getn(S.collectQueue) == 0 then StopCollecting(); return end
|
||
local mi = table.remove(S.collectQueue, 1)
|
||
if mi > GetInboxNumItems() then ProcessCollectQueue(); return end
|
||
local _, _, _, _, money, CODAmount, _, hasItem = GetInboxHeaderInfo(mi)
|
||
if CODAmount and CODAmount > 0 then ProcessCollectQueue(); return end
|
||
if hasItem then TakeInboxItem(mi)
|
||
elseif money and money > 0 then
|
||
TakeInboxMoney(mi)
|
||
S.collectPendingDelete = mi
|
||
else DeleteInboxItem(mi) end
|
||
end
|
||
|
||
local function StartCollecting(indices)
|
||
if S.isCollecting then return end
|
||
S.collectQueue = {}
|
||
for i = table.getn(indices), 1, -1 do table.insert(S.collectQueue, indices[i]) end
|
||
if table.getn(S.collectQueue) == 0 then return end
|
||
S.isCollecting = true; S.collectElapsed = 0
|
||
if not S.collectTimer then S.collectTimer = CreateFrame("Frame") end
|
||
local nextDelay = 0
|
||
S.collectTimer:SetScript("OnUpdate", function()
|
||
if not S.isCollecting then this:SetScript("OnUpdate", nil); return end
|
||
S.collectElapsed = S.collectElapsed + arg1
|
||
if S.collectElapsed >= nextDelay then
|
||
S.collectElapsed = 0; nextDelay = 0.5; ProcessCollectQueue()
|
||
end
|
||
end)
|
||
UpdateInbox()
|
||
end
|
||
|
||
local function CollectAll()
|
||
local n = GetInboxNumItems()
|
||
if n == 0 then return end
|
||
local idx = {}
|
||
for i = 1, n do
|
||
local _, _, _, _, _, COD = GetInboxHeaderInfo(i)
|
||
if not COD or COD == 0 then table.insert(idx, i) end
|
||
end
|
||
StartCollecting(idx)
|
||
end
|
||
|
||
local function CollectSelected()
|
||
local idx = {}
|
||
for k, v in pairs(S.inboxChecked) do if v then table.insert(idx, k) end end
|
||
table.sort(idx)
|
||
if table.getn(idx) == 0 then return end
|
||
S.inboxChecked = {}
|
||
StartCollecting(idx)
|
||
end
|
||
|
||
local function SelectAllInbox()
|
||
local n = GetInboxNumItems()
|
||
for i = 1, n do
|
||
local _, _, _, _, _, COD = GetInboxHeaderInfo(i)
|
||
if not COD or COD == 0 then S.inboxChecked[i] = true end
|
||
end
|
||
UpdateInbox()
|
||
end
|
||
|
||
local function DeselectAllInbox()
|
||
S.inboxChecked = {}; UpdateInbox()
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- SEND: Item Queue
|
||
--------------------------------------------------------------------------------
|
||
local function AddSendItem(bag, slot)
|
||
if table.getn(S.sendQueue) >= L.MAX_SEND then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 发送队列已满 (" .. L.MAX_SEND .. " 件)")
|
||
return
|
||
end
|
||
local link = GetContainerItemLink(bag, slot)
|
||
if not link then return end
|
||
local texture, count = GetContainerItemInfo(bag, slot)
|
||
for i = 1, table.getn(S.sendQueue) do
|
||
if S.sendQueue[i].bag == bag and S.sendQueue[i].slot == slot then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 该物品已在发送列表中"); return
|
||
end
|
||
end
|
||
table.insert(S.sendQueue, { bag = bag, slot = slot, link = link, texture = texture, count = count or 1 })
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- SEND: Accept cursor drag (find the locked bag slot the cursor picked up)
|
||
--------------------------------------------------------------------------------
|
||
local function AcceptCursorItem()
|
||
if not CursorHasItem() then return false end
|
||
for bag = 0, 4 do
|
||
local slots = GetContainerNumSlots(bag)
|
||
for slot = 1, slots do
|
||
local _, _, locked = GetContainerItemInfo(bag, slot)
|
||
if locked then
|
||
AddSendItem(bag, slot)
|
||
ClearCursor()
|
||
ML:UpdateSendPanel()
|
||
return true
|
||
end
|
||
end
|
||
end
|
||
ClearCursor()
|
||
return false
|
||
end
|
||
|
||
local function RemoveSendItem(index)
|
||
if index >= 1 and index <= table.getn(S.sendQueue) then table.remove(S.sendQueue, index) end
|
||
end
|
||
|
||
local function ClearSendItems() S.sendQueue = {} end
|
||
|
||
local function FlashStatus(text, color, duration)
|
||
if not S.frame or not S.frame.sendStatus then return end
|
||
S.frame.sendStatus:SetText(text)
|
||
S.frame.sendStatus:SetTextColor(color[1], color[2], color[3])
|
||
S.statusFadeElapsed = 0
|
||
if not S.statusFadeTimer then S.statusFadeTimer = CreateFrame("Frame") end
|
||
S.statusFadeTimer:SetScript("OnUpdate", function()
|
||
S.statusFadeElapsed = S.statusFadeElapsed + arg1
|
||
if S.statusFadeElapsed >= (duration or 3) then
|
||
S.frame.sendStatus:SetText("")
|
||
this:SetScript("OnUpdate", nil)
|
||
end
|
||
end)
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- SEND: Multi-Send Logic
|
||
--------------------------------------------------------------------------------
|
||
local function ResetSendForm()
|
||
if not S.frame then return end
|
||
ClearSendItems()
|
||
S.codMode = false
|
||
if S.frame.UpdateMoneyToggle then S.frame.UpdateMoneyToggle() end
|
||
if S.frame.toEditBox then S.frame.toEditBox:SetText("") end
|
||
if S.frame.subjectEditBox then S.frame.subjectEditBox:SetText("") end
|
||
if S.frame.bodyEditBox then S.frame.bodyEditBox:SetText("") end
|
||
if S.frame.goldEB then S.frame.goldEB:SetText("0") end
|
||
if S.frame.silverEB then S.frame.silverEB:SetText("0") end
|
||
if S.frame.copperEB then S.frame.copperEB:SetText("0") end
|
||
ML:UpdateSendPanel()
|
||
end
|
||
|
||
local function FinishMultiSend()
|
||
local ms = S.multiSend
|
||
S.multiSend = nil
|
||
S.isSending = false
|
||
if S.updateFrame then S.updateFrame:SetScript("OnUpdate", nil) end
|
||
ResetSendForm()
|
||
if S.frame and S.frame.sendBtn then
|
||
S.frame.sendBtn.label:SetText("发送"); S.frame.sendBtn:SetDisabled(false)
|
||
end
|
||
if ms then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF88FF88[Nanami-Mail]|r 所有 " .. ms.total .. " 封邮件已发送完成")
|
||
FlashStatus("全部发送完成!", T.successText, 3)
|
||
end
|
||
end
|
||
|
||
local function AbortMultiSend(reason)
|
||
S.multiSend = nil
|
||
S.isSending = false
|
||
if S.updateFrame then S.updateFrame:SetScript("OnUpdate", nil) end
|
||
if S.frame and S.frame.sendBtn then
|
||
S.frame.sendBtn.label:SetText("发送"); S.frame.sendBtn:SetDisabled(false)
|
||
end
|
||
if S.frame and S.frame.sendStatus then S.frame.sendStatus:SetText("") end
|
||
if reason then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r " .. reason)
|
||
FlashStatus("发送失败!", T.errorText, 5)
|
||
end
|
||
end
|
||
|
||
local function DoMultiSend(recipient, subject, body, money)
|
||
if S.isSending then return end
|
||
if not recipient or recipient == "" then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 请输入收件人名字"); return
|
||
end
|
||
if not subject or subject == "" then subject = "Mail" end
|
||
if S.frame and S.frame.sendBtn then
|
||
S.frame.sendBtn.label:SetText("发送中..."); S.frame.sendBtn:SetDisabled(true)
|
||
end
|
||
local items = {}
|
||
for i = 1, table.getn(S.sendQueue) do table.insert(items, S.sendQueue[i]) end
|
||
|
||
-- No attachments: plain text / money mail (付款取信 requires attachments)
|
||
if table.getn(items) == 0 then
|
||
if S.codMode and money and money > 0 then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 付款取信模式需要添加附件物品")
|
||
if S.frame and S.frame.sendBtn then
|
||
S.frame.sendBtn.label:SetText("发送"); S.frame.sendBtn:SetDisabled(false)
|
||
end
|
||
return
|
||
end
|
||
if money and money > 0 then SetSendMailMoney(money) end
|
||
SendMail(recipient, subject, body or "")
|
||
return
|
||
end
|
||
|
||
S.multiSend = {
|
||
items = items,
|
||
recipient = recipient,
|
||
subject = subject or "",
|
||
body = body or "",
|
||
money = money,
|
||
codMode = S.codMode,
|
||
total = table.getn(items),
|
||
sentCount = 0,
|
||
phase = "attach", -- "attach" → "wait_send" → "cooldown" → "attach" ...
|
||
elapsed = 0,
|
||
}
|
||
S.isSending = true
|
||
|
||
if not S.updateFrame then S.updateFrame = CreateFrame("Frame") end
|
||
S.updateFrame:SetScript("OnUpdate", function()
|
||
local ms = S.multiSend
|
||
if not ms then this:SetScript("OnUpdate", nil); return end
|
||
ms.elapsed = ms.elapsed + arg1
|
||
|
||
---------------------------------------------------------------
|
||
-- Phase: attach — pick next item, attach to Blizzard mail slot, then send
|
||
---------------------------------------------------------------
|
||
if ms.phase == "attach" then
|
||
ms.sentCount = ms.sentCount + 1
|
||
if ms.sentCount > ms.total then
|
||
FinishMultiSend()
|
||
return
|
||
end
|
||
|
||
local item = ms.items[ms.sentCount]
|
||
if not item then FinishMultiSend(); return end
|
||
|
||
if S.frame and S.frame.sendStatus then
|
||
if S.statusFadeTimer then S.statusFadeTimer:SetScript("OnUpdate", nil) end
|
||
S.frame.sendStatus:SetText("发送中 " .. ms.sentCount .. "/" .. ms.total)
|
||
S.frame.sendStatus:SetTextColor(T.successText[1], T.successText[2], T.successText[3])
|
||
end
|
||
|
||
-- Ensure Blizzard send tab is active
|
||
if MailFrameTab_OnClick then MailFrameTab_OnClick(2) end
|
||
|
||
-- Check item still in bag
|
||
if not GetContainerItemLink(item.bag, item.slot) then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 第" .. ms.sentCount .. "件物品已不在背包,跳过")
|
||
ms.elapsed = 0
|
||
return
|
||
end
|
||
|
||
-- Attach: clear → pick up → place
|
||
_ClearCursor()
|
||
_ClickSendMailItemButton()
|
||
_ClearCursor()
|
||
_PickupContainerItem(item.bag, item.slot)
|
||
_ClickSendMailItemButton()
|
||
|
||
-- Verify
|
||
if not GetSendMailItem() then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 第" .. ms.sentCount .. "件附件挂载失败,跳过")
|
||
_ClearCursor()
|
||
ms.elapsed = 0
|
||
return
|
||
end
|
||
|
||
-- Money or 付款取信
|
||
if ms.money and ms.money > 0 then
|
||
if ms.codMode then
|
||
SetSendMailCOD(ms.money)
|
||
elseif ms.sentCount == 1 then
|
||
SetSendMailMoney(ms.money)
|
||
end
|
||
end
|
||
|
||
-- Send this single-attachment mail
|
||
ms.sendOk = false
|
||
ms.phase = "wait_send"
|
||
ms.elapsed = 0
|
||
SendMail(ms.recipient, ms.subject, ms.body)
|
||
|
||
---------------------------------------------------------------
|
||
-- Phase: wait_send — waiting for MAIL_SEND_SUCCESS
|
||
---------------------------------------------------------------
|
||
elseif ms.phase == "wait_send" then
|
||
if ms.sendOk then
|
||
ms.phase = "cooldown"
|
||
ms.elapsed = 0
|
||
elseif ms.elapsed >= 15 then
|
||
AbortMultiSend("发送超时,已停止")
|
||
end
|
||
|
||
---------------------------------------------------------------
|
||
-- Phase: cooldown — let server & Blizzard UI fully reset
|
||
---------------------------------------------------------------
|
||
elseif ms.phase == "cooldown" then
|
||
if ms.elapsed >= 0.6 then
|
||
ms.phase = "attach"
|
||
ms.elapsed = 0
|
||
end
|
||
end
|
||
end)
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- SEND: Panel Update
|
||
--------------------------------------------------------------------------------
|
||
function ML:UpdateSendPanel()
|
||
if not S.frame or S.currentTab ~= 2 then return end
|
||
if not S.frame.sendItemSlots then return end
|
||
for i = 1, L.MAX_SEND do
|
||
local slot = S.frame.sendItemSlots[i]
|
||
if not slot then break end
|
||
local entry = S.sendQueue[i]
|
||
if entry then
|
||
slot.icon:SetTexture(entry.texture); slot.icon:Show()
|
||
slot.countFS:SetText(entry.count > 1 and entry.count or "")
|
||
slot.removeBtn:Show(); slot.hasItem = true
|
||
else
|
||
slot.icon:SetTexture(nil); slot.icon:Hide()
|
||
slot.countFS:SetText(""); slot.removeBtn:Hide(); slot.hasItem = false
|
||
end
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Main frame + header + tabs
|
||
--------------------------------------------------------------------------------
|
||
local function BuildMainFrame()
|
||
local f = CreateFrame("Frame", "SFramesMailFrame", UIParent)
|
||
f:SetWidth(L.W); f:SetHeight(L.H)
|
||
f:SetPoint("TOPLEFT", UIParent, "TOPLEFT", 16, -104)
|
||
f:SetFrameStrata("HIGH"); f:SetToplevel(true)
|
||
f:EnableMouse(true); f:SetMovable(true); f:RegisterForDrag("LeftButton")
|
||
f:SetScript("OnDragStart", function() this:StartMoving() end)
|
||
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
||
SetRoundBackdrop(f); CreateShadow(f)
|
||
S.frame = f
|
||
|
||
local font = GetFont()
|
||
local header = CreateFrame("Frame", nil, f)
|
||
header:SetPoint("TOPLEFT", 0, 0); header:SetPoint("TOPRIGHT", 0, 0); header:SetHeight(L.HEADER)
|
||
header:SetBackdrop({ bgFile = "Interface\\Buttons\\WHITE8X8" })
|
||
header:SetBackdropColor(T.headerBg[1], T.headerBg[2], T.headerBg[3], T.headerBg[4])
|
||
|
||
local titleIco = SFrames:CreateIcon(header, "mail", 16)
|
||
titleIco:SetDrawLayer("OVERLAY")
|
||
titleIco:SetPoint("LEFT", header, "LEFT", L.PAD, 0)
|
||
titleIco:SetVertexColor(T.gold[1], T.gold[2], T.gold[3])
|
||
|
||
local titleFS = header:CreateFontString(nil, "OVERLAY")
|
||
titleFS:SetFont(font, 14, "OUTLINE"); titleFS:SetPoint("LEFT", titleIco, "RIGHT", 5, 0)
|
||
titleFS:SetTextColor(T.gold[1], T.gold[2], T.gold[3]); titleFS:SetText("邮箱")
|
||
|
||
local closeBtn = CreateFrame("Button", nil, header)
|
||
closeBtn:SetWidth(20); closeBtn:SetHeight(20); closeBtn:SetPoint("RIGHT", header, "RIGHT", -8, 0)
|
||
local closeTex = closeBtn:CreateTexture(nil, "ARTWORK")
|
||
closeTex:SetTexture("Interface\\AddOns\\Nanami-UI\\img\\icon")
|
||
closeTex:SetTexCoord(0.25, 0.375, 0, 0.125); closeTex:SetAllPoints()
|
||
closeTex:SetVertexColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
closeBtn:SetScript("OnClick", function() S.frame:Hide() end)
|
||
closeBtn:SetScript("OnEnter", function() closeTex:SetVertexColor(1, 0.6, 0.7) end)
|
||
closeBtn:SetScript("OnLeave", function() closeTex:SetVertexColor(T.dimText[1], T.dimText[2], T.dimText[3]) end)
|
||
|
||
local sep = f:CreateTexture(nil, "ARTWORK")
|
||
sep:SetTexture("Interface\\Buttons\\WHITE8X8"); sep:SetHeight(1)
|
||
sep:SetPoint("TOPLEFT", f, "TOPLEFT", 6, -L.HEADER)
|
||
sep:SetPoint("TOPRIGHT", f, "TOPRIGHT", -6, -L.HEADER)
|
||
sep:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])
|
||
|
||
local tabInbox = CreateTabBtn(f, "收件箱", 62)
|
||
tabInbox:SetPoint("TOPLEFT", f, "TOPLEFT", L.PAD, -(L.HEADER + 6))
|
||
tabInbox:SetScript("OnClick", function() S.currentTab = 1; ML:ShowInboxPanel() end)
|
||
f.tabInbox = tabInbox
|
||
|
||
local tabBag = CreateTabBtn(f, "邮包", 50)
|
||
tabBag:SetPoint("LEFT", tabInbox, "RIGHT", 4, 0)
|
||
tabBag:SetScript("OnClick", function() S.currentTab = 3; ML:ShowMailBagPanel() end)
|
||
f.tabBag = tabBag
|
||
|
||
local tabSend = CreateTabBtn(f, "发送", 62)
|
||
tabSend:SetPoint("LEFT", tabBag, "RIGHT", 4, 0)
|
||
tabSend:SetScript("OnClick", function() S.currentTab = 2; ML:ShowSendPanel() end)
|
||
f.tabSend = tabSend
|
||
|
||
f:Hide()
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Inbox panel
|
||
--------------------------------------------------------------------------------
|
||
local function BuildInboxPanel()
|
||
local f = S.frame
|
||
local panelTop = L.HEADER + 6 + L.TAB_H + 4
|
||
local ip = CreateFrame("Frame", nil, f)
|
||
ip:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -panelTop)
|
||
ip:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||
f.inboxPanel = ip
|
||
|
||
local font = GetFont()
|
||
|
||
local selAll = CreateActionBtn(ip, "全选", 50)
|
||
selAll:SetHeight(20); selAll:SetPoint("TOPLEFT", ip, "TOPLEFT", L.PAD, 0)
|
||
selAll:SetScript("OnClick", function() SelectAllInbox() end)
|
||
|
||
local desel = CreateActionBtn(ip, "取消全选", 66)
|
||
desel:SetHeight(20); desel:SetPoint("LEFT", selAll, "RIGHT", 4, 0)
|
||
desel:SetScript("OnClick", function() DeselectAllInbox() end)
|
||
|
||
local pageFS = ip:CreateFontString(nil, "OVERLAY")
|
||
pageFS:SetFont(font, 10, "OUTLINE"); pageFS:SetPoint("LEFT", desel, "RIGHT", 12, 0)
|
||
pageFS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
f.inboxPageText = pageFS
|
||
|
||
for i = 1, L.ROWS do
|
||
local row = CreateInboxRow(ip, i)
|
||
row:SetPoint("TOPLEFT", ip, "TOPLEFT", L.PAD, -(26 + (i - 1) * L.ROW_H))
|
||
S.inboxRows[i] = row
|
||
end
|
||
|
||
local bsep = ip:CreateTexture(nil, "ARTWORK")
|
||
bsep:SetTexture("Interface\\Buttons\\WHITE8X8"); bsep:SetHeight(1)
|
||
bsep:SetPoint("BOTTOMLEFT", ip, "BOTTOMLEFT", 6, L.BOTTOM)
|
||
bsep:SetPoint("BOTTOMRIGHT", ip, "BOTTOMRIGHT", -6, L.BOTTOM)
|
||
bsep:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])
|
||
|
||
local prev = CreateActionBtn(ip, "<", 28)
|
||
prev:SetHeight(22); prev:SetPoint("BOTTOMLEFT", ip, "BOTTOMLEFT", L.PAD, 12)
|
||
prev:SetScript("OnClick", function() S.inboxPage = S.inboxPage - 1; UpdateInbox() end)
|
||
f.inboxPrevBtn = prev
|
||
|
||
local nxt = CreateActionBtn(ip, ">", 28)
|
||
nxt:SetHeight(22); nxt:SetPoint("LEFT", prev, "RIGHT", 4, 0)
|
||
nxt:SetScript("OnClick", function() S.inboxPage = S.inboxPage + 1; UpdateInbox() end)
|
||
f.inboxNextBtn = nxt
|
||
|
||
local colSel = CreateActionBtn(ip, "收取选中", 80)
|
||
colSel:SetHeight(24); colSel:SetPoint("BOTTOMRIGHT", ip, "BOTTOMRIGHT", -L.PAD, 10)
|
||
colSel:SetScript("OnClick", function()
|
||
if S.isCollecting then StopCollecting() else CollectSelected() end
|
||
end)
|
||
f.collectSelectedBtn = colSel
|
||
|
||
local colAll = CreateActionBtn(ip, "全部收取", 80)
|
||
colAll:SetHeight(24); colAll:SetPoint("RIGHT", colSel, "LEFT", -6, 0)
|
||
colAll:SetScript("OnClick", function()
|
||
if S.isCollecting then StopCollecting() else CollectAll() end
|
||
end)
|
||
f.collectAllBtn = colAll
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Mail detail panel (overlays inbox when a mail is clicked)
|
||
--------------------------------------------------------------------------------
|
||
local function BuildDetailPanel()
|
||
local f = S.frame
|
||
local panelTop = L.HEADER + 6 + L.TAB_H + 4
|
||
local dp = CreateFrame("Frame", nil, f)
|
||
dp:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -panelTop)
|
||
dp:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||
dp:Hide()
|
||
f.detailPanel = dp
|
||
|
||
local font = GetFont()
|
||
local pad = L.PAD
|
||
|
||
local backBtn = CreateActionBtn(dp, "< 返回", 60)
|
||
backBtn:SetHeight(20); backBtn:SetPoint("TOPLEFT", dp, "TOPLEFT", pad, 0)
|
||
backBtn:SetScript("OnClick", function() ML:HideMailDetail() end)
|
||
|
||
local senderFS = dp:CreateFontString(nil, "OVERLAY")
|
||
senderFS:SetFont(font, 11, "OUTLINE"); senderFS:SetJustifyH("LEFT")
|
||
senderFS:SetPoint("TOPLEFT", dp, "TOPLEFT", pad, -26)
|
||
senderFS:SetWidth(L.W - pad * 2)
|
||
senderFS:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
|
||
dp.senderFS = senderFS
|
||
|
||
local subjectFS = dp:CreateFontString(nil, "OVERLAY")
|
||
subjectFS:SetFont(font, 11, "OUTLINE"); subjectFS:SetJustifyH("LEFT")
|
||
subjectFS:SetPoint("TOPLEFT", senderFS, "BOTTOMLEFT", 0, -4)
|
||
subjectFS:SetWidth(L.W - pad * 2)
|
||
subjectFS:SetTextColor(T.bodyText[1], T.bodyText[2], T.bodyText[3])
|
||
dp.subjectFS = subjectFS
|
||
|
||
local sep1 = dp:CreateTexture(nil, "ARTWORK")
|
||
sep1:SetTexture("Interface\\Buttons\\WHITE8X8"); sep1:SetHeight(1)
|
||
sep1:SetPoint("TOPLEFT", subjectFS, "BOTTOMLEFT", 0, -6)
|
||
sep1:SetPoint("RIGHT", dp, "RIGHT", -pad, 0)
|
||
sep1:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])
|
||
|
||
-- Body scroll frame
|
||
local bsf = CreateFrame("ScrollFrame", "SFramesMailDetailScroll", dp, "UIPanelScrollFrameTemplate")
|
||
bsf:SetPoint("TOPLEFT", sep1, "BOTTOMLEFT", 0, -4)
|
||
bsf:SetWidth(L.W - pad * 2 - 24); bsf:SetHeight(180)
|
||
|
||
local bodyFS = CreateFrame("Frame", nil, bsf)
|
||
bodyFS:SetWidth(L.W - pad * 2 - 36); bodyFS:SetHeight(400)
|
||
local bodyText = bodyFS:CreateFontString(nil, "OVERLAY")
|
||
bodyText:SetFont(font, 11, "OUTLINE")
|
||
bodyText:SetPoint("TOPLEFT", 0, 0)
|
||
bodyText:SetWidth(L.W - pad * 2 - 36); bodyText:SetJustifyH("LEFT"); bodyText:SetJustifyV("TOP")
|
||
bodyText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
|
||
bsf:SetScrollChild(bodyFS)
|
||
dp.bodyText = bodyText
|
||
dp.bodyFrame = bodyFS
|
||
|
||
local sep2 = dp:CreateTexture(nil, "ARTWORK")
|
||
sep2:SetTexture("Interface\\Buttons\\WHITE8X8"); sep2:SetHeight(1)
|
||
sep2:SetPoint("TOPLEFT", bsf, "BOTTOMLEFT", 0, -4)
|
||
sep2:SetPoint("RIGHT", dp, "RIGHT", -pad, 0)
|
||
sep2:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])
|
||
|
||
-- Item + money info line
|
||
local infoFS = dp:CreateFontString(nil, "OVERLAY")
|
||
infoFS:SetFont(font, 10, "OUTLINE"); infoFS:SetJustifyH("LEFT")
|
||
infoFS:SetPoint("TOPLEFT", sep2, "BOTTOMLEFT", 0, -6)
|
||
infoFS:SetWidth(L.W - pad * 2)
|
||
infoFS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
dp.infoFS = infoFS
|
||
|
||
local moneyLabel = dp:CreateFontString(nil, "OVERLAY")
|
||
moneyLabel:SetFont(font, 10, "OUTLINE"); moneyLabel:SetTextColor(1, 0.84, 0)
|
||
moneyLabel:SetPoint("TOPLEFT", infoFS, "BOTTOMLEFT", 0, -3)
|
||
moneyLabel:Hide()
|
||
dp.detailMoneyLabel = moneyLabel
|
||
|
||
local detailMoney = CreateMoneyIcons(dp, 10, 11)
|
||
detailMoney:SetPoint("LEFT", moneyLabel, "RIGHT", 4, 0)
|
||
detailMoney:Hide()
|
||
dp.detailMoney = detailMoney
|
||
|
||
local codLabel = dp:CreateFontString(nil, "OVERLAY")
|
||
codLabel:SetFont(font, 10, "OUTLINE"); codLabel:SetTextColor(1, 0.33, 0.33)
|
||
codLabel:SetPoint("LEFT", detailMoney, "RIGHT", 8, 0)
|
||
codLabel:Hide()
|
||
dp.detailCodLabel = codLabel
|
||
|
||
local detailCod = CreateMoneyIcons(dp, 10, 11)
|
||
detailCod:SetPoint("LEFT", codLabel, "RIGHT", 4, 0)
|
||
detailCod:Hide()
|
||
dp.detailCod = detailCod
|
||
|
||
-- Action buttons at bottom
|
||
local takeItemBtn = CreateActionBtn(dp, "收取物品", 72)
|
||
takeItemBtn:SetHeight(24); takeItemBtn:SetPoint("BOTTOMLEFT", dp, "BOTTOMLEFT", pad, 10)
|
||
dp.takeItemBtn = takeItemBtn
|
||
|
||
local takeMoneyBtn = CreateActionBtn(dp, "收取金币", 72)
|
||
takeMoneyBtn:SetHeight(24); takeMoneyBtn:SetPoint("LEFT", takeItemBtn, "RIGHT", 4, 0)
|
||
dp.takeMoneyBtn = takeMoneyBtn
|
||
|
||
local returnBtn = CreateActionBtn(dp, "退回", 50)
|
||
returnBtn:SetHeight(24); returnBtn:SetPoint("LEFT", takeMoneyBtn, "RIGHT", 4, 0)
|
||
dp.returnBtn = returnBtn
|
||
|
||
local deleteBtn = CreateActionBtn(dp, "删除", 50)
|
||
deleteBtn:SetHeight(24); deleteBtn:SetPoint("LEFT", returnBtn, "RIGHT", 4, 0)
|
||
dp.deleteBtn = deleteBtn
|
||
|
||
local replyBtn = CreateActionBtn(dp, "回复", 50)
|
||
replyBtn:SetHeight(24); replyBtn:SetPoint("BOTTOMRIGHT", dp, "BOTTOMRIGHT", -pad, 10)
|
||
dp.replyBtn = replyBtn
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Show / Hide mail detail
|
||
--------------------------------------------------------------------------------
|
||
function ML:ShowMailDetail(mailIndex)
|
||
if not S.frame or not S.frame.detailPanel then return end
|
||
local dp = S.frame.detailPanel
|
||
S.detailMailIndex = mailIndex
|
||
|
||
local _, _, sender, subject, money, CODAmount, daysLeft, hasItem, wasRead = GetInboxHeaderInfo(mailIndex)
|
||
local bodyText = GetInboxText(mailIndex)
|
||
|
||
dp.senderFS:SetText("发件人: |cFFFFFFFF" .. (sender or "未知") .. "|r " .. FormatExpiry(daysLeft))
|
||
dp.subjectFS:SetText("主题: |cFFFFFFFF" .. (subject or "(无主题)") .. "|r")
|
||
|
||
dp.bodyText:SetText(bodyText or "(无正文)")
|
||
local ok, textH = pcall(function() return dp.bodyText:GetStringHeight() end)
|
||
if not ok or not textH then textH = 40 end
|
||
dp.bodyFrame:SetHeight(math.max(textH + 10, 40))
|
||
|
||
local info = ""
|
||
if hasItem then
|
||
local itemName, itemTex = GetInboxItem(mailIndex)
|
||
if itemName then info = info .. "|cFFFFD700附件:|r " .. itemName end
|
||
end
|
||
if info == "" and (not money or money <= 0) and (not CODAmount or CODAmount <= 0) then
|
||
info = "无附件,无金币"
|
||
end
|
||
dp.infoFS:SetText(info)
|
||
|
||
dp.detailMoneyLabel:Hide(); dp.detailMoney:Hide()
|
||
dp.detailCodLabel:Hide(); dp.detailCod:Hide()
|
||
if money and money > 0 then
|
||
dp.detailMoneyLabel:SetText("金额:"); dp.detailMoneyLabel:Show()
|
||
dp.detailMoney:SetMoney(money); dp.detailMoney:Show()
|
||
end
|
||
if CODAmount and CODAmount > 0 then
|
||
dp.detailCodLabel:SetText("付款取信:"); dp.detailCodLabel:Show()
|
||
dp.detailCod:SetMoney(CODAmount); dp.detailCod:Show()
|
||
end
|
||
|
||
-- Take items button
|
||
local canTakeItem = hasItem
|
||
dp.takeItemBtn:SetDisabled(not canTakeItem)
|
||
dp.takeItemBtn:SetScript("OnClick", function()
|
||
if S.detailMailIndex then
|
||
if CODAmount and CODAmount > 0 then
|
||
local codStr = FormatMoneyString(CODAmount)
|
||
local idx = S.detailMailIndex
|
||
StaticPopupDialogs["NANAMI_MAIL_COD_CONFIRM"].OnAccept = function()
|
||
TakeInboxItem(idx)
|
||
end
|
||
StaticPopup_Show("NANAMI_MAIL_COD_CONFIRM", codStr)
|
||
else
|
||
TakeInboxItem(S.detailMailIndex)
|
||
end
|
||
end
|
||
end)
|
||
|
||
-- Take money button
|
||
local canTakeMoney = money and money > 0 and (not CODAmount or CODAmount == 0)
|
||
dp.takeMoneyBtn:SetDisabled(not canTakeMoney)
|
||
dp.takeMoneyBtn:SetScript("OnClick", function()
|
||
if S.detailMailIndex then
|
||
local idx = S.detailMailIndex
|
||
local _, _, _, _, _, _, _, hi = GetInboxHeaderInfo(idx)
|
||
TakeInboxMoney(idx)
|
||
if not hi then
|
||
if not S.deleteTimer then S.deleteTimer = CreateFrame("Frame") end
|
||
S.deleteElapsed = 0
|
||
S.deleteTimer:SetScript("OnUpdate", function()
|
||
S.deleteElapsed = S.deleteElapsed + arg1
|
||
if S.deleteElapsed >= 0.5 then
|
||
this:SetScript("OnUpdate", nil)
|
||
if idx <= GetInboxNumItems() then DeleteInboxItem(idx) end
|
||
end
|
||
end)
|
||
end
|
||
ML:HideMailDetail()
|
||
end
|
||
end)
|
||
|
||
-- Return button
|
||
dp.returnBtn:SetScript("OnClick", function()
|
||
if S.detailMailIndex then
|
||
ReturnInboxItem(S.detailMailIndex)
|
||
ML:HideMailDetail()
|
||
end
|
||
end)
|
||
|
||
-- Delete button
|
||
dp.deleteBtn:SetScript("OnClick", function()
|
||
if S.detailMailIndex then
|
||
DeleteInboxItem(S.detailMailIndex)
|
||
ML:HideMailDetail()
|
||
end
|
||
end)
|
||
|
||
-- Reply button
|
||
dp.replyBtn:SetScript("OnClick", function()
|
||
if sender then
|
||
S.currentTab = 2; ML:ShowSendPanel()
|
||
if S.frame.toEditBox then S.frame.toEditBox:SetText(sender) end
|
||
if S.frame.subjectEditBox then
|
||
local re = subject or ""
|
||
if string.sub(re, 1, 4) ~= "Re: " then re = "Re: " .. re end
|
||
S.frame.subjectEditBox:SetText(re)
|
||
end
|
||
end
|
||
end)
|
||
|
||
S.frame.inboxPanel:Hide()
|
||
dp:Show()
|
||
end
|
||
|
||
function ML:HideMailDetail()
|
||
if not S.frame then return end
|
||
S.detailMailIndex = nil
|
||
if S.frame.detailPanel then S.frame.detailPanel:Hide() end
|
||
S.frame.inboxPanel:Show()
|
||
UpdateInbox()
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Mail Bag panel (grid view of all inbox items)
|
||
--------------------------------------------------------------------------------
|
||
local function BuildMailBagPanel()
|
||
local f = S.frame
|
||
local panelTop = L.HEADER + 6 + L.TAB_H + 4
|
||
local bp = CreateFrame("Frame", nil, f)
|
||
bp:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -panelTop)
|
||
bp:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||
bp:Hide()
|
||
f.bagPanel = bp
|
||
|
||
local font = GetFont()
|
||
local slotsPerPage = L.BAG_PER_ROW * L.BAG_ROWS
|
||
|
||
local infoFS = bp:CreateFontString(nil, "OVERLAY")
|
||
infoFS:SetFont(font, 10, "OUTLINE")
|
||
infoFS:SetPoint("TOPLEFT", bp, "TOPLEFT", L.PAD, -2)
|
||
infoFS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
f.bagInfoFS = infoFS
|
||
|
||
local codLegend = bp:CreateFontString(nil, "OVERLAY")
|
||
codLegend:SetFont(font, 9, "OUTLINE")
|
||
codLegend:SetPoint("TOPRIGHT", bp, "TOPRIGHT", -L.PAD, -2)
|
||
codLegend:SetText("|cFFFF5555■|r 付款取信")
|
||
codLegend:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
|
||
f.bagSlots = {}
|
||
local gridTop = 16
|
||
for i = 1, slotsPerPage do
|
||
local row = math.floor((i - 1) / L.BAG_PER_ROW)
|
||
local col = math.mod((i - 1), L.BAG_PER_ROW)
|
||
local sf = CreateFrame("Button", "SFramesMailBagSlot" .. i, bp)
|
||
sf:SetWidth(L.BAG_SLOT); sf:SetHeight(L.BAG_SLOT)
|
||
sf:SetPoint("TOPLEFT", bp, "TOPLEFT",
|
||
L.PAD + col * (L.BAG_SLOT + L.BAG_GAP),
|
||
-(gridTop + row * (L.BAG_SLOT + L.BAG_GAP)))
|
||
sf:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12,
|
||
insets = { left = 2, right = 2, top = 2, bottom = 2 },
|
||
})
|
||
sf:SetBackdropColor(T.slotBg[1], T.slotBg[2], T.slotBg[3], T.slotBg[4])
|
||
sf:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
|
||
local ico = sf:CreateTexture(nil, "ARTWORK")
|
||
ico:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||
ico:SetPoint("TOPLEFT", 3, -3); ico:SetPoint("BOTTOMRIGHT", -3, 3)
|
||
ico:Hide()
|
||
sf.icon = ico
|
||
|
||
local cnt = sf:CreateFontString(nil, "OVERLAY")
|
||
cnt:SetFont(font, 11, "OUTLINE")
|
||
cnt:SetPoint("BOTTOMRIGHT", sf, "BOTTOMRIGHT", -2, 2)
|
||
cnt:SetJustifyH("RIGHT")
|
||
sf.countFS = cnt
|
||
|
||
local moneyFS = sf:CreateFontString(nil, "OVERLAY")
|
||
moneyFS:SetFont(font, 8, "OUTLINE")
|
||
moneyFS:SetPoint("BOTTOM", sf, "BOTTOM", 0, 2)
|
||
moneyFS:SetWidth(L.BAG_SLOT)
|
||
moneyFS:SetJustifyH("CENTER")
|
||
moneyFS:Hide()
|
||
sf.moneyFS = moneyFS
|
||
|
||
local codFS = sf:CreateFontString(nil, "OVERLAY")
|
||
codFS:SetFont(font, 7, "OUTLINE")
|
||
codFS:SetPoint("TOP", sf, "TOP", 0, -1)
|
||
codFS:SetText("|cFFFF3333付款|r")
|
||
codFS:Hide()
|
||
sf.codFS = codFS
|
||
|
||
sf.mailData = nil
|
||
sf:RegisterForClicks("LeftButtonUp")
|
||
sf:SetScript("OnClick", function()
|
||
local data = this.mailData
|
||
if not data then return end
|
||
if data.codAmount and data.codAmount > 0 then
|
||
local codStr = FormatMoneyString(data.codAmount)
|
||
local idx = data.mailIndex
|
||
StaticPopupDialogs["NANAMI_MAIL_COD_CONFIRM"].OnAccept = function()
|
||
TakeInboxItem(idx)
|
||
end
|
||
StaticPopup_Show("NANAMI_MAIL_COD_CONFIRM", codStr)
|
||
elseif data.hasItem then
|
||
TakeInboxItem(data.mailIndex)
|
||
elseif data.money and data.money > 0 then
|
||
local idx = data.mailIndex
|
||
TakeInboxMoney(idx)
|
||
if not S.deleteTimer then S.deleteTimer = CreateFrame("Frame") end
|
||
S.deleteElapsed = 0
|
||
S.deleteTimer:SetScript("OnUpdate", function()
|
||
S.deleteElapsed = S.deleteElapsed + arg1
|
||
if S.deleteElapsed >= 0.5 then
|
||
this:SetScript("OnUpdate", nil)
|
||
if idx <= GetInboxNumItems() then DeleteInboxItem(idx) end
|
||
end
|
||
end)
|
||
end
|
||
end)
|
||
sf:SetScript("OnEnter", function()
|
||
this:SetBackdropBorderColor(T.slotHover[1], T.slotHover[2], T.slotHover[3], T.slotHover[4])
|
||
local data = this.mailData
|
||
if not data then return end
|
||
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
|
||
if data.hasItem then
|
||
pcall(GameTooltip.SetInboxItem, GameTooltip, data.mailIndex)
|
||
else
|
||
GameTooltip:AddLine("金币邮件", 1, 0.84, 0)
|
||
end
|
||
GameTooltip:AddLine(" ")
|
||
if data.sender then
|
||
GameTooltip:AddLine("发件人: " .. data.sender, 0.7, 0.7, 0.7)
|
||
end
|
||
if data.subject and data.subject ~= "" then
|
||
GameTooltip:AddLine(data.subject, 0.5, 0.5, 0.5)
|
||
end
|
||
if data.codAmount and data.codAmount > 0 then
|
||
GameTooltip:AddLine(" ")
|
||
GameTooltip:AddLine("付款取信: " .. FormatMoneyString(data.codAmount), 1, 0.3, 0.3)
|
||
GameTooltip:AddLine("|cFFFFCC00点击支付并取回|r")
|
||
elseif data.money and data.money > 0 and not data.hasItem then
|
||
GameTooltip:AddLine(" ")
|
||
GameTooltip:AddLine("金额: " .. FormatMoneyString(data.money), 1, 0.84, 0)
|
||
GameTooltip:AddLine("|cFFFFCC00点击收取金币|r")
|
||
elseif data.hasItem then
|
||
GameTooltip:AddLine(" ")
|
||
GameTooltip:AddLine("|cFFFFCC00点击收取物品|r")
|
||
end
|
||
GameTooltip:Show()
|
||
end)
|
||
sf:SetScript("OnLeave", function()
|
||
local data = this.mailData
|
||
if data and data.codAmount and data.codAmount > 0 then
|
||
this:SetBackdropBorderColor(1, 0.3, 0.3, 0.8)
|
||
else
|
||
this:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
end
|
||
GameTooltip:Hide()
|
||
end)
|
||
|
||
f.bagSlots[i] = sf
|
||
end
|
||
|
||
local bsep = bp:CreateTexture(nil, "ARTWORK")
|
||
bsep:SetTexture("Interface\\Buttons\\WHITE8X8"); bsep:SetHeight(1)
|
||
bsep:SetPoint("BOTTOMLEFT", bp, "BOTTOMLEFT", 6, L.BOTTOM)
|
||
bsep:SetPoint("BOTTOMRIGHT", bp, "BOTTOMRIGHT", -6, L.BOTTOM)
|
||
bsep:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4])
|
||
|
||
local prev = CreateActionBtn(bp, "<", 28)
|
||
prev:SetHeight(22); prev:SetPoint("BOTTOMLEFT", bp, "BOTTOMLEFT", L.PAD, 12)
|
||
prev:SetScript("OnClick", function() S.bagPage = S.bagPage - 1; ML:UpdateMailBag() end)
|
||
f.bagPrevBtn = prev
|
||
|
||
local nxt = CreateActionBtn(bp, ">", 28)
|
||
nxt:SetHeight(22); nxt:SetPoint("LEFT", prev, "RIGHT", 4, 0)
|
||
nxt:SetScript("OnClick", function() S.bagPage = S.bagPage + 1; ML:UpdateMailBag() end)
|
||
f.bagNextBtn = nxt
|
||
|
||
local pageFS = bp:CreateFontString(nil, "OVERLAY")
|
||
pageFS:SetFont(font, 10, "OUTLINE")
|
||
pageFS:SetPoint("LEFT", nxt, "RIGHT", 8, 0)
|
||
pageFS:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
f.bagPageFS = pageFS
|
||
|
||
local colAll = CreateActionBtn(bp, "全部收取", 80)
|
||
colAll:SetHeight(24); colAll:SetPoint("BOTTOMRIGHT", bp, "BOTTOMRIGHT", -L.PAD, 10)
|
||
colAll:SetScript("OnClick", function()
|
||
if S.isCollecting then StopCollecting() else CollectAll() end
|
||
end)
|
||
f.bagCollectAllBtn = colAll
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Mail Bag: Update
|
||
--------------------------------------------------------------------------------
|
||
function ML:UpdateMailBag()
|
||
if not S.frame or not S.frame:IsVisible() or S.currentTab ~= 3 then return end
|
||
local slotsPerPage = L.BAG_PER_ROW * L.BAG_ROWS
|
||
local numMails = GetInboxNumItems()
|
||
|
||
local entries = {}
|
||
for mi = 1, numMails do
|
||
local _, _, sender, subject, money, CODAmount, daysLeft, hasItem = GetInboxHeaderInfo(mi)
|
||
if hasItem or (money and money > 0) or (CODAmount and CODAmount > 0) then
|
||
local itemName, itemTex
|
||
if hasItem then itemName, itemTex = GetInboxItem(mi) end
|
||
table.insert(entries, {
|
||
mailIndex = mi,
|
||
hasItem = hasItem,
|
||
itemName = itemName,
|
||
itemTexture = itemTex,
|
||
money = money or 0,
|
||
codAmount = CODAmount or 0,
|
||
sender = sender or "未知",
|
||
subject = subject or "",
|
||
daysLeft = daysLeft,
|
||
})
|
||
end
|
||
end
|
||
|
||
local totalEntries = table.getn(entries)
|
||
local totalPages = math.max(1, math.ceil(totalEntries / slotsPerPage))
|
||
if S.bagPage > totalPages then S.bagPage = totalPages end
|
||
if S.bagPage < 1 then S.bagPage = 1 end
|
||
|
||
S.frame.bagInfoFS:SetText(string.format("共 %d 件可收取 (%d 封邮件)", totalEntries, numMails))
|
||
S.frame.bagPageFS:SetText(string.format("第 %d/%d 页", S.bagPage, totalPages))
|
||
S.frame.bagPrevBtn:SetDisabled(S.bagPage <= 1)
|
||
S.frame.bagNextBtn:SetDisabled(S.bagPage >= totalPages)
|
||
S.frame.bagCollectAllBtn:SetDisabled(numMails == 0 and not S.isCollecting)
|
||
if S.isCollecting then
|
||
S.frame.bagCollectAllBtn.label:SetText("收取中...")
|
||
else
|
||
S.frame.bagCollectAllBtn.label:SetText("全部收取")
|
||
end
|
||
|
||
for i = 1, slotsPerPage do
|
||
local slot = S.frame.bagSlots[i]
|
||
local ei = (S.bagPage - 1) * slotsPerPage + i
|
||
local entry = entries[ei]
|
||
if entry then
|
||
slot.mailData = entry
|
||
if entry.hasItem and entry.itemTexture then
|
||
slot.icon:SetTexture(entry.itemTexture)
|
||
elseif entry.money > 0 then
|
||
slot.icon:SetTexture("Interface\\Icons\\INV_Misc_Coin_01")
|
||
else
|
||
slot.icon:SetTexture("Interface\\Icons\\INV_Misc_Note_01")
|
||
end
|
||
slot.icon:Show()
|
||
slot.countFS:SetText("")
|
||
slot.moneyFS:Hide()
|
||
|
||
if entry.money > 0 and not entry.hasItem then
|
||
local g = math.floor(entry.money / 10000)
|
||
if g > 0 then
|
||
slot.moneyFS:SetText("|cFFFFD700" .. g .. "g|r")
|
||
else
|
||
local sv = math.floor(math.mod(entry.money, 10000) / 100)
|
||
if sv > 0 then
|
||
slot.moneyFS:SetText("|cFFC7C7CF" .. sv .. "s|r")
|
||
else
|
||
local cv = math.mod(entry.money, 100)
|
||
slot.moneyFS:SetText("|cFFB87333" .. cv .. "c|r")
|
||
end
|
||
end
|
||
slot.moneyFS:Show()
|
||
end
|
||
|
||
if entry.codAmount > 0 then
|
||
slot.codFS:Show()
|
||
slot:SetBackdropBorderColor(1, 0.3, 0.3, 0.8)
|
||
else
|
||
slot.codFS:Hide()
|
||
slot:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
end
|
||
slot:Show()
|
||
else
|
||
slot.mailData = nil
|
||
slot.icon:Hide()
|
||
slot.countFS:SetText("")
|
||
slot.moneyFS:Hide()
|
||
slot.codFS:Hide()
|
||
slot:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
slot:Show()
|
||
end
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Mail Bag: Panel Switching
|
||
--------------------------------------------------------------------------------
|
||
function ML:ShowMailBagPanel()
|
||
if not S.frame then return end
|
||
S.frame.tabInbox:SetActive(false)
|
||
S.frame.tabBag:SetActive(true)
|
||
S.frame.tabSend:SetActive(false)
|
||
if S.frame.detailPanel then S.frame.detailPanel:Hide() end
|
||
S.detailMailIndex = nil
|
||
S.frame.inboxPanel:Hide()
|
||
S.frame.sendPanel:Hide()
|
||
S.frame.bagPanel:Show()
|
||
ML:UpdateMailBag()
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Send panel
|
||
--------------------------------------------------------------------------------
|
||
local function BuildSendPanel()
|
||
local f = S.frame
|
||
local panelTop = L.HEADER + 6 + L.TAB_H + 4
|
||
local sp = CreateFrame("Frame", "SFramesMailSendPanel", f)
|
||
sp:SetPoint("TOPLEFT", f, "TOPLEFT", 0, -panelTop)
|
||
sp:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", 0, 0)
|
||
sp:EnableMouse(true)
|
||
sp:SetScript("OnReceiveDrag", function() AcceptCursorItem() end)
|
||
sp:SetScript("OnMouseUp", function()
|
||
if CursorHasItem() then AcceptCursorItem() end
|
||
end)
|
||
sp:Hide()
|
||
f.sendPanel = sp
|
||
|
||
local font = GetFont()
|
||
|
||
-- Recipient
|
||
local labelW = 50
|
||
local ebW = L.W - L.PAD * 2 - labelW - 6
|
||
local toLabel = sp:CreateFontString(nil, "OVERLAY")
|
||
toLabel:SetFont(font, 11, "OUTLINE"); toLabel:SetPoint("TOPLEFT", sp, "TOPLEFT", L.PAD, -32)
|
||
toLabel:SetWidth(labelW); toLabel:SetJustifyH("RIGHT")
|
||
toLabel:SetText("收件人:"); toLabel:SetTextColor(T.labelText[1], T.labelText[2], T.labelText[3])
|
||
local toEB = CreateStyledEditBox(sp, ebW, 22)
|
||
toEB:SetPoint("LEFT", toLabel, "RIGHT", 6, 0)
|
||
f.toEditBox = toEB
|
||
|
||
-- Contact buttons
|
||
local addContactBtn = CreateActionBtn(sp, "添加", 30)
|
||
addContactBtn:SetHeight(22); addContactBtn:SetPoint("TOPRIGHT", sp, "TOPRIGHT", -L.PAD, -6)
|
||
addContactBtn:SetScript("OnClick", function()
|
||
local name = f.toEditBox:GetText()
|
||
if name and name ~= "" then
|
||
if not SFramesDB then
|
||
SFramesDB = {}
|
||
end
|
||
if not SFramesDB.mailContacts then
|
||
SFramesDB.mailContacts = {}
|
||
end
|
||
SFramesDB.mailContacts[name] = true
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88[Nanami-Mail]|r 已添加常用联系人: " .. name)
|
||
end
|
||
end)
|
||
|
||
-- Contact management frame
|
||
local contactFrame
|
||
local function CreateContactFrame()
|
||
if contactFrame then return end
|
||
|
||
contactFrame = CreateFrame("Frame", "SFramesMailContactFrame", UIParent)
|
||
if not contactFrame then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 创建联系人管理窗口失败")
|
||
return
|
||
end
|
||
contactFrame:SetWidth(250)
|
||
contactFrame:SetHeight(300)
|
||
contactFrame:SetPoint("CENTER", UIParent, "CENTER", 0, 0)
|
||
contactFrame:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12,
|
||
insets = { left = 3, right = 3, top = 3, bottom = 3 }
|
||
})
|
||
contactFrame:SetBackdropColor(0.1, 0.1, 0.1, 0.95)
|
||
contactFrame:SetBackdropBorderColor(0.5, 0.5, 0.5, 1)
|
||
contactFrame:SetFrameStrata("DIALOG")
|
||
contactFrame:SetMovable(true)
|
||
contactFrame:EnableMouse(true)
|
||
contactFrame:RegisterForDrag("LeftButton")
|
||
contactFrame:SetScript("OnDragStart", function() this:StartMoving() end)
|
||
contactFrame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
|
||
contactFrame:Hide()
|
||
|
||
-- Title
|
||
local title = contactFrame:CreateFontString(nil, "OVERLAY")
|
||
title:SetFont(GetFont(), 12, "OUTLINE")
|
||
title:SetPoint("TOP", contactFrame, "TOP", 0, -10)
|
||
title:SetText("|cFFFFCC00常用联系人管理|r")
|
||
|
||
-- Close button
|
||
local closeBtn = CreateActionBtn(contactFrame, "X", 20)
|
||
closeBtn:SetHeight(20)
|
||
closeBtn:SetPoint("TOPRIGHT", contactFrame, "TOPRIGHT", -5, -5)
|
||
closeBtn:SetScript("OnClick", function() contactFrame:Hide() end)
|
||
|
||
-- Scroll frame
|
||
local scrollFrame = CreateFrame("ScrollFrame", nil, contactFrame)
|
||
if not scrollFrame then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 创建滚动框架失败")
|
||
return
|
||
end
|
||
scrollFrame:SetWidth(230)
|
||
scrollFrame:SetHeight(240)
|
||
scrollFrame:SetPoint("TOPLEFT", contactFrame, "TOPLEFT", 10, -30)
|
||
|
||
local scrollChild = CreateFrame("Frame", nil, scrollFrame)
|
||
if not scrollChild then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 创建滚动子框架失败")
|
||
return
|
||
end
|
||
scrollChild:SetWidth(210)
|
||
scrollChild:SetHeight(1)
|
||
scrollFrame:SetScrollChild(scrollChild)
|
||
|
||
-- Refresh function
|
||
contactFrame.Refresh = function()
|
||
if not SFramesDB then SFramesDB = {} end
|
||
if not SFramesDB.mailContacts then SFramesDB.mailContacts = {} end
|
||
|
||
-- Clear existing buttons
|
||
for _, child in ipairs({scrollChild:GetChildren()}) do
|
||
child:Hide()
|
||
child:SetParent(nil)
|
||
child = nil
|
||
end
|
||
|
||
-- Create contact buttons
|
||
local contacts = SFramesDB.mailContacts
|
||
local y = 0
|
||
for name in pairs(contacts) do
|
||
local contactBtn = CreateActionBtn(scrollChild, name, 180)
|
||
contactBtn:SetHeight(20)
|
||
contactBtn:SetPoint("TOPLEFT", scrollChild, "TOPLEFT", 0, -y)
|
||
contactBtn.contactName = name
|
||
contactBtn:SetScript("OnClick", function()
|
||
if this.contactName and f.toEditBox then
|
||
f.toEditBox:SetText(this.contactName)
|
||
contactFrame:Hide()
|
||
end
|
||
end)
|
||
|
||
local deleteBtn = CreateActionBtn(scrollChild, "×", 20)
|
||
deleteBtn:SetHeight(20)
|
||
deleteBtn:SetPoint("LEFT", contactBtn, "RIGHT", 5, 0)
|
||
deleteBtn.contactName = name
|
||
deleteBtn:SetScript("OnClick", function()
|
||
if this.contactName then
|
||
SFramesDB.mailContacts[this.contactName] = nil
|
||
contactFrame:Refresh()
|
||
end
|
||
end)
|
||
|
||
y = y + 25
|
||
end
|
||
|
||
scrollChild:SetHeight(math.max(1, y))
|
||
|
||
-- No contacts message
|
||
if not next(contacts) then
|
||
local noContacts = scrollChild:CreateFontString(nil, "OVERLAY")
|
||
noContacts:SetFont(GetFont(), 11, "OUTLINE")
|
||
noContacts:SetPoint("TOP", scrollChild, "TOP", 0, -10)
|
||
noContacts:SetText("|cFF999999常用联系人列表为空|r")
|
||
end
|
||
end
|
||
|
||
-- Add contact section
|
||
local addLabel = contactFrame:CreateFontString(nil, "OVERLAY")
|
||
addLabel:SetFont(GetFont(), 11, "OUTLINE")
|
||
addLabel:SetPoint("BOTTOMLEFT", contactFrame, "BOTTOMLEFT", 10, 40)
|
||
addLabel:SetText("添加新联系人:")
|
||
|
||
local addEditBox = CreateStyledEditBox(contactFrame, 150, 20)
|
||
addEditBox:SetPoint("BOTTOMLEFT", contactFrame, "BOTTOMLEFT", 10, 15)
|
||
|
||
local addBtn = CreateActionBtn(contactFrame, "添加", 60)
|
||
addBtn:SetHeight(20)
|
||
addBtn:SetPoint("BOTTOMRIGHT", contactFrame, "BOTTOMRIGHT", -10, 15)
|
||
addBtn:SetScript("OnClick", function()
|
||
local name = addEditBox:GetText()
|
||
if name and name ~= "" then
|
||
if not SFramesDB then SFramesDB = {} end
|
||
if not SFramesDB.mailContacts then SFramesDB.mailContacts = {} end
|
||
SFramesDB.mailContacts[name] = true
|
||
addEditBox:SetText("")
|
||
contactFrame:Refresh()
|
||
end
|
||
end)
|
||
end
|
||
|
||
local manageContactBtn = CreateActionBtn(sp, "管理", 30)
|
||
manageContactBtn:SetHeight(22); manageContactBtn:SetPoint("RIGHT", addContactBtn, "LEFT", -4, 0)
|
||
manageContactBtn:SetScript("OnClick", function()
|
||
CreateContactFrame()
|
||
if contactFrame then
|
||
contactFrame:Refresh()
|
||
contactFrame:Show()
|
||
else
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 无法创建联系人管理窗口")
|
||
end
|
||
end)
|
||
|
||
-- Autocomplete dropdown for recipient
|
||
local AC_MAX = 8
|
||
local acBox = CreateFrame("Frame", "SFramesMailAutoComplete", f)
|
||
acBox:SetWidth(ebW); acBox:SetFrameStrata("TOOLTIP")
|
||
acBox:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background",
|
||
edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12,
|
||
insets = { left = 2, right = 2, top = 2, bottom = 2 },
|
||
})
|
||
acBox:SetBackdropColor(0.05, 0.05, 0.1, 0.95)
|
||
acBox:SetBackdropBorderColor(T.panelBorder[1], T.panelBorder[2], T.panelBorder[3], 0.9)
|
||
acBox:SetPoint("TOPLEFT", toEB, "BOTTOMLEFT", 0, -2)
|
||
acBox:Hide()
|
||
acBox:EnableMouse(true)
|
||
f.acBox = acBox
|
||
|
||
local acButtons = {}
|
||
for ai = 1, AC_MAX do
|
||
local btn = CreateFrame("Button", nil, acBox)
|
||
btn:SetHeight(18); btn:SetPoint("TOPLEFT", acBox, "TOPLEFT", 4, -4 - (ai - 1) * 18)
|
||
btn:SetPoint("RIGHT", acBox, "RIGHT", -4, 0)
|
||
btn:SetHighlightTexture("Interface\\QuestFrame\\UI-QuestTitleHighlight")
|
||
local bfs = btn:CreateFontString(nil, "OVERLAY")
|
||
bfs:SetFont(font, 11, "OUTLINE"); bfs:SetAllPoints(btn)
|
||
bfs:SetJustifyH("LEFT")
|
||
btn.label = bfs
|
||
btn.sourceName = nil
|
||
btn:SetScript("OnClick", function()
|
||
if btn.sourceName then
|
||
toEB:SetText(btn.sourceName)
|
||
end
|
||
acBox:Hide()
|
||
f.subjectEditBox:SetFocus()
|
||
end)
|
||
btn:Hide()
|
||
acButtons[ai] = btn
|
||
end
|
||
f.acButtons = acButtons
|
||
|
||
local friendCache = {}
|
||
local function BuildFriendCache()
|
||
friendCache = {}
|
||
for fi = 1, GetNumFriends() do
|
||
local name = GetFriendInfo(fi)
|
||
if name then friendCache[name] = true end
|
||
end
|
||
end
|
||
|
||
local function ShowSuggestions()
|
||
local input = toEB:GetText()
|
||
if not input or input == "" then acBox:Hide(); return end
|
||
local upper = string.upper(input)
|
||
|
||
BuildFriendCache()
|
||
|
||
local seen = { [UnitName("player")] = true }
|
||
local results = {}
|
||
|
||
local function addName(name, source)
|
||
if not name or name == "" or seen[name] then return end
|
||
if string.find(string.upper(name), upper, 1, true) == 1 then
|
||
table.insert(results, { name = name, source = source })
|
||
end
|
||
seen[name] = true
|
||
end
|
||
|
||
-- Add mail contacts first
|
||
if SFramesDB and SFramesDB.mailContacts then
|
||
for name in pairs(SFramesDB.mailContacts) do
|
||
addName(name, "contact")
|
||
end
|
||
end
|
||
|
||
for fi = 1, GetNumFriends() do
|
||
local name = GetFriendInfo(fi)
|
||
addName(name, "friend")
|
||
end
|
||
if GetNumGuildMembers then
|
||
for gi = 1, GetNumGuildMembers(true) do
|
||
local name = GetGuildRosterInfo(gi)
|
||
addName(name, "guild")
|
||
end
|
||
end
|
||
|
||
local count = math.min(table.getn(results), AC_MAX)
|
||
if count == 0 then acBox:Hide(); return end
|
||
if count == 1 and results[1].name == input then acBox:Hide(); return end
|
||
|
||
for ai = 1, AC_MAX do
|
||
local btn = acButtons[ai]
|
||
if ai <= count then
|
||
local r = results[ai]
|
||
local col = T.whoColor
|
||
local tag = ""
|
||
if r.source == "contact" then
|
||
col = { 1, 1, 0.3 }; tag = " |cFFFFCC00[常用]|r"
|
||
elseif r.source == "friend" then
|
||
col = T.friendColor; tag = " |cFF66FF88[好友]|r"
|
||
elseif r.source == "guild" then
|
||
col = T.guildColor; tag = " |cFF66CCFF[公会]|r"
|
||
end
|
||
btn.label:SetText("|cFF" .. string.format("%02x%02x%02x",
|
||
col[1] * 255, col[2] * 255, col[3] * 255) .. r.name .. "|r" .. tag)
|
||
btn.sourceName = r.name
|
||
btn:Show()
|
||
else
|
||
btn:Hide()
|
||
end
|
||
end
|
||
acBox:SetHeight(count * 18 + 8)
|
||
acBox:Show()
|
||
end
|
||
|
||
toEB:SetScript("OnTextChanged", function() ShowSuggestions() end)
|
||
toEB:SetScript("OnEscapePressed", function() acBox:Hide(); this:ClearFocus() end)
|
||
toEB:SetScript("OnEnterPressed", function()
|
||
acBox:Hide(); f.subjectEditBox:SetFocus()
|
||
end)
|
||
|
||
-- Subject (second line, aligned with recipient)
|
||
local subLabel = sp:CreateFontString(nil, "OVERLAY")
|
||
subLabel:SetFont(font, 11, "OUTLINE"); subLabel:SetPoint("TOPLEFT", sp, "TOPLEFT", L.PAD, -60)
|
||
subLabel:SetWidth(labelW); subLabel:SetJustifyH("RIGHT")
|
||
subLabel:SetText("主题:"); subLabel:SetTextColor(T.labelText[1], T.labelText[2], T.labelText[3])
|
||
local subEB = CreateStyledEditBox(sp, ebW, 22)
|
||
subEB:SetPoint("LEFT", subLabel, "RIGHT", 6, 0)
|
||
f.subjectEditBox = subEB
|
||
|
||
toEB:SetScript("OnTabPressed", function() acBox:Hide(); f.subjectEditBox:SetFocus() end)
|
||
subEB:SetScript("OnTabPressed", function() f.toEditBox:SetFocus() end)
|
||
|
||
-- Body
|
||
local bodyLabel = sp:CreateFontString(nil, "OVERLAY")
|
||
bodyLabel:SetFont(font, 11, "OUTLINE"); bodyLabel:SetPoint("TOPLEFT", sp, "TOPLEFT", L.PAD, -88)
|
||
bodyLabel:SetText("正文:"); bodyLabel:SetTextColor(T.labelText[1], T.labelText[2], T.labelText[3])
|
||
|
||
local bsf = CreateFrame("ScrollFrame", "SFramesMailBodyScroll", sp, "UIPanelScrollFrameTemplate")
|
||
bsf:SetPoint("TOPLEFT", bodyLabel, "BOTTOMLEFT", 0, -4)
|
||
bsf:SetWidth(L.W - L.PAD * 2 - 28); bsf:SetHeight(100)
|
||
bsf:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 },
|
||
})
|
||
bsf:SetBackdropColor(T.inputBg[1], T.inputBg[2], T.inputBg[3], T.inputBg[4] or 0.95)
|
||
bsf:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], 0.8)
|
||
|
||
local bodyEB = CreateFrame("EditBox", "SFramesMailBodyEditBox", bsf)
|
||
bodyEB:SetWidth(L.W - L.PAD * 2 - 40); bodyEB:SetHeight(200)
|
||
bodyEB:SetFont(font, 11, "OUTLINE"); bodyEB:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
|
||
bodyEB:SetAutoFocus(false); bodyEB:SetMultiLine(true); bodyEB:SetMaxLetters(500)
|
||
bodyEB:SetTextInsets(6, 6, 4, 4)
|
||
bsf:SetScrollChild(bodyEB)
|
||
f.bodyEditBox = bodyEB
|
||
|
||
-- Money mode toggle (附加金币 / 付款取信)
|
||
local mToggle = CreateActionBtn(sp, "附加金币", 72)
|
||
mToggle:SetHeight(20); mToggle:SetPoint("TOPLEFT", bsf, "BOTTOMLEFT", 0, -10)
|
||
f.moneyToggle = mToggle
|
||
local function UpdateMoneyToggle()
|
||
if S.codMode then
|
||
mToggle.label:SetText("|cFFFF5555付款取信|r")
|
||
mToggle:SetBackdropBorderColor(1, 0.3, 0.3, 0.8)
|
||
else
|
||
mToggle.label:SetText("附加金币")
|
||
mToggle:SetBackdropBorderColor(T.btnBorder[1], T.btnBorder[2], T.btnBorder[3], T.btnBorder[4])
|
||
end
|
||
end
|
||
f.UpdateMoneyToggle = UpdateMoneyToggle
|
||
mToggle:SetScript("OnClick", function()
|
||
S.codMode = not S.codMode; UpdateMoneyToggle()
|
||
end)
|
||
mToggle:SetScript("OnEnter", function()
|
||
GameTooltip:SetOwner(this, "ANCHOR_TOPRIGHT")
|
||
if S.codMode then
|
||
GameTooltip:AddLine("付款取信模式", 1, 0.5, 0.5)
|
||
GameTooltip:AddLine("收件人需支付指定金额才能取回附件", 0.8, 0.8, 0.8)
|
||
else
|
||
GameTooltip:AddLine("附加金币模式", 1, 0.84, 0)
|
||
GameTooltip:AddLine("随邮件附送金币给收件人", 0.8, 0.8, 0.8)
|
||
end
|
||
GameTooltip:AddLine("|cFFFFCC00点击切换模式|r")
|
||
GameTooltip:Show()
|
||
end)
|
||
mToggle:SetScript("OnLeave", function() GameTooltip:Hide() end)
|
||
UpdateMoneyToggle()
|
||
|
||
local gL = sp:CreateFontString(nil, "OVERLAY")
|
||
gL:SetFont(font, 10, "OUTLINE"); gL:SetPoint("LEFT", mToggle, "RIGHT", 6, 0)
|
||
gL:SetText("金"); gL:SetTextColor(T.moneyGold[1], T.moneyGold[2], T.moneyGold[3])
|
||
local gEB = CreateStyledEditBox(sp, 50, 20, true); gEB:SetPoint("LEFT", gL, "RIGHT", 4, 0); gEB:SetText("0"); f.goldEB = gEB
|
||
|
||
local sL = sp:CreateFontString(nil, "OVERLAY")
|
||
sL:SetFont(font, 10, "OUTLINE"); sL:SetPoint("LEFT", gEB, "RIGHT", 6, 0)
|
||
sL:SetText("银"); sL:SetTextColor(T.moneySilver[1], T.moneySilver[2], T.moneySilver[3])
|
||
local sEB = CreateStyledEditBox(sp, 36, 20, true); sEB:SetPoint("LEFT", sL, "RIGHT", 4, 0); sEB:SetText("0"); f.silverEB = sEB
|
||
|
||
local cL = sp:CreateFontString(nil, "OVERLAY")
|
||
cL:SetFont(font, 10, "OUTLINE"); cL:SetPoint("LEFT", sEB, "RIGHT", 6, 0)
|
||
cL:SetText("铜"); cL:SetTextColor(T.moneyCopper[1], T.moneyCopper[2], T.moneyCopper[3])
|
||
local cEB = CreateStyledEditBox(sp, 36, 20, true); cEB:SetPoint("LEFT", cL, "RIGHT", 4, 0); cEB:SetText("0"); f.copperEB = cEB
|
||
|
||
-- Attachments
|
||
local aLabel = sp:CreateFontString(nil, "OVERLAY")
|
||
aLabel:SetFont(font, 11, "OUTLINE"); aLabel:SetPoint("TOPLEFT", mToggle, "TOPLEFT", 0, -28)
|
||
aLabel:SetText("附件 (右击/拖放背包物品添加):"); aLabel:SetTextColor(T.labelText[1], T.labelText[2], T.labelText[3])
|
||
|
||
local clrBtn = CreateActionBtn(sp, "清空", 50)
|
||
clrBtn:SetHeight(20); clrBtn:SetPoint("LEFT", aLabel, "RIGHT", 8, 0)
|
||
clrBtn:SetScript("OnClick", function() ClearSendItems(); ML:UpdateSendPanel() end)
|
||
|
||
-- Item slot grid
|
||
f.sendItemSlots = {}
|
||
BuildSendSlots(sp, aLabel, f)
|
||
|
||
-- Send button & status
|
||
local status = sp:CreateFontString(nil, "OVERLAY")
|
||
status:SetFont(font, 11, "OUTLINE"); status:SetPoint("BOTTOMLEFT", sp, "BOTTOMLEFT", L.PAD, 14)
|
||
status:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
|
||
f.sendStatus = status
|
||
|
||
local sendBtn = CreateActionBtn(sp, "发送", 80)
|
||
sendBtn:SetHeight(26); sendBtn:SetPoint("BOTTOMRIGHT", sp, "BOTTOMRIGHT", -L.PAD, 10)
|
||
sendBtn:SetScript("OnClick", function()
|
||
local r = f.toEditBox:GetText()
|
||
local sub = f.subjectEditBox:GetText()
|
||
local bd = f.bodyEditBox:GetText()
|
||
local g = tonumber(f.goldEB:GetText()) or 0
|
||
local sv = tonumber(f.silverEB:GetText()) or 0
|
||
local c = tonumber(f.copperEB:GetText()) or 0
|
||
DoMultiSend(r, sub, bd, g * 10000 + sv * 100 + c)
|
||
end)
|
||
f.sendBtn = sendBtn
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Send item slots (separate function to stay under upvalue limit)
|
||
--------------------------------------------------------------------------------
|
||
function BuildSendSlots(parent, anchor, f)
|
||
local slotSize, slotGap, perRow = 34, 4, 6
|
||
for i = 1, L.MAX_SEND do
|
||
local row = math.floor((i - 1) / perRow)
|
||
local col = math.mod((i - 1), perRow)
|
||
local sf = CreateFrame("Button", "SFramesMailSendSlot" .. i, parent)
|
||
sf:SetWidth(slotSize); sf:SetHeight(slotSize)
|
||
sf:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", col * (slotSize + slotGap), -(4 + row * (slotSize + slotGap)))
|
||
sf:SetBackdrop({
|
||
bgFile = "Interface\\Tooltips\\UI-Tooltip-Background", edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
|
||
tile = true, tileSize = 16, edgeSize = 12, insets = { left = 2, right = 2, top = 2, bottom = 2 },
|
||
})
|
||
sf:SetBackdropColor(T.slotBg[1], T.slotBg[2], T.slotBg[3], T.slotBg[4])
|
||
sf:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
|
||
local ico = sf:CreateTexture(nil, "ARTWORK")
|
||
ico:SetTexCoord(0.08, 0.92, 0.08, 0.92)
|
||
ico:SetPoint("TOPLEFT", 3, -3); ico:SetPoint("BOTTOMRIGHT", -3, 3); ico:Hide()
|
||
sf.icon = ico
|
||
|
||
local cnt = sf:CreateFontString(nil, "OVERLAY")
|
||
cnt:SetFont("Fonts\\ARIALN.TTF", 11, "OUTLINE")
|
||
cnt:SetPoint("BOTTOMRIGHT", sf, "BOTTOMRIGHT", -2, 2); cnt:SetJustifyH("RIGHT")
|
||
sf.countFS = cnt
|
||
|
||
local rb = CreateFrame("Button", nil, sf)
|
||
rb:SetWidth(14); rb:SetHeight(14); rb:SetPoint("TOPRIGHT", sf, "TOPRIGHT", 2, 2)
|
||
local rtx = rb:CreateTexture(nil, "OVERLAY")
|
||
rtx:SetTexture("Interface\\AddOns\\Nanami-UI\\img\\icon")
|
||
rtx:SetTexCoord(0.25, 0.375, 0, 0.125); rtx:SetAllPoints(); rtx:SetVertexColor(1, 0.4, 0.4)
|
||
rb:Hide(); sf.removeBtn = rb; sf.hasItem = false
|
||
|
||
local si = i
|
||
rb:SetScript("OnClick", function() RemoveSendItem(si); ML:UpdateSendPanel() end)
|
||
sf:SetScript("OnReceiveDrag", function() AcceptCursorItem() end)
|
||
sf:SetScript("OnClick", function()
|
||
if CursorHasItem() then AcceptCursorItem(); return end
|
||
if arg1 == "RightButton" and sf.hasItem then RemoveSendItem(si); ML:UpdateSendPanel() end
|
||
end)
|
||
sf:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
sf:SetScript("OnEnter", function()
|
||
this:SetBackdropBorderColor(T.slotHover[1], T.slotHover[2], T.slotHover[3], T.slotHover[4])
|
||
local e = S.sendQueue[si]
|
||
if e and e.link then
|
||
GameTooltip:SetOwner(this, "ANCHOR_RIGHT"); pcall(GameTooltip.SetHyperlink, GameTooltip, e.link); GameTooltip:Show()
|
||
end
|
||
end)
|
||
sf:SetScript("OnLeave", function()
|
||
this:SetBackdropBorderColor(T.slotBorder[1], T.slotBorder[2], T.slotBorder[3], T.slotBorder[4])
|
||
GameTooltip:Hide()
|
||
end)
|
||
f.sendItemSlots[i] = sf
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- BUILD: Events & hooks
|
||
--------------------------------------------------------------------------------
|
||
local function SetupEvents()
|
||
local f = S.frame
|
||
|
||
f:SetScript("OnHide", function()
|
||
StopCollecting(); if S.multiSend then AbortMultiSend() end; pcall(CloseMail)
|
||
end)
|
||
|
||
f:SetScript("OnEvent", function()
|
||
if event == "MAIL_SHOW" then
|
||
if SFramesDB and SFramesDB.enableMail == false then return end
|
||
S.currentTab = 1; S.inboxPage = 1; S.bagPage = 1; S.inboxChecked = {}
|
||
CheckInbox(); f:Show(); ML:ShowInboxPanel()
|
||
elseif event == "MAIL_INBOX_UPDATE" then
|
||
if f:IsVisible() then
|
||
if S.detailMailIndex and f.detailPanel and f.detailPanel:IsVisible() then
|
||
if S.detailMailIndex <= GetInboxNumItems() then
|
||
ML:ShowMailDetail(S.detailMailIndex)
|
||
else
|
||
ML:HideMailDetail()
|
||
end
|
||
elseif S.currentTab == 3 then
|
||
ML:UpdateMailBag()
|
||
else
|
||
UpdateInbox()
|
||
end
|
||
end
|
||
-- 收件箱清空后同步小地图信件图标状态
|
||
if MiniMapMailFrame then
|
||
if HasNewMail and HasNewMail() then
|
||
MiniMapMailFrame:Show()
|
||
elseif GetInboxNumItems() == 0 then
|
||
MiniMapMailFrame:Hide()
|
||
end
|
||
end
|
||
elseif event == "UPDATE_PENDING_MAIL" then
|
||
if MiniMapMailFrame then
|
||
if HasNewMail and HasNewMail() then
|
||
MiniMapMailFrame:Show()
|
||
else
|
||
MiniMapMailFrame:Hide()
|
||
end
|
||
end
|
||
elseif event == "MAIL_CLOSED" then
|
||
if S.multiSend then AbortMultiSend("邮箱已关闭") end
|
||
f:Hide()
|
||
elseif event == "MAIL_SEND_SUCCESS" then
|
||
if S.multiSend then
|
||
S.multiSend.sendOk = true
|
||
S.multiSend.phase = "cooldown"
|
||
S.multiSend.elapsed = 0
|
||
else
|
||
FlashStatus("发送成功!", T.successText, 3)
|
||
ResetSendForm()
|
||
if f.sendBtn then f.sendBtn.label:SetText("发送"); f.sendBtn:SetDisabled(false) end
|
||
end
|
||
elseif event == "MAIL_SEND_INFO_UPDATE" then
|
||
-- noop
|
||
elseif event == "MAIL_FAILED" then
|
||
if S.multiSend and S.multiSend.phase == "wait_send" and not S.multiSend.sendOk then
|
||
AbortMultiSend("发送失败")
|
||
elseif not S.multiSend then
|
||
if f.sendBtn then f.sendBtn.label:SetText("发送"); f.sendBtn:SetDisabled(false) end
|
||
FlashStatus("发送失败!", T.errorText, 5)
|
||
end
|
||
end
|
||
end)
|
||
|
||
f:RegisterEvent("MAIL_SHOW"); f:RegisterEvent("MAIL_INBOX_UPDATE")
|
||
f:RegisterEvent("MAIL_CLOSED"); f:RegisterEvent("MAIL_SEND_SUCCESS")
|
||
f:RegisterEvent("MAIL_SEND_INFO_UPDATE"); f:RegisterEvent("MAIL_FAILED")
|
||
f:RegisterEvent("UPDATE_PENDING_MAIL")
|
||
|
||
if MailFrame then
|
||
local origMailOnShow = MailFrame:GetScript("OnShow")
|
||
MailFrame:SetScript("OnShow", function()
|
||
if origMailOnShow then origMailOnShow() end
|
||
this:ClearAllPoints()
|
||
this:SetPoint("TOPLEFT", UIParent, "TOPLEFT", -10000, 10000)
|
||
this:SetAlpha(0)
|
||
this:EnableMouse(false)
|
||
end)
|
||
for i = table.getn(UISpecialFrames), 1, -1 do
|
||
if UISpecialFrames[i] == "MailFrame" then
|
||
table.remove(UISpecialFrames, i)
|
||
end
|
||
end
|
||
end
|
||
if OpenMailFrame then
|
||
OpenMailFrame:UnregisterAllEvents(); OpenMailFrame:Hide()
|
||
end
|
||
|
||
tinsert(UISpecialFrames, "SFramesMailFrame")
|
||
|
||
SFrames.Mail.TryAddItemFromBag = function(bag, slot)
|
||
if S.frame and S.frame:IsVisible() and not S.isSending then
|
||
if bag and slot then
|
||
if S.currentTab ~= 2 then S.currentTab = 2; ML:ShowSendPanel() end
|
||
AddSendItem(bag, slot); ML:UpdateSendPanel()
|
||
return true
|
||
end
|
||
end
|
||
return false
|
||
end
|
||
|
||
if ContainerFrameItemButton_OnClick then
|
||
local orig = ContainerFrameItemButton_OnClick
|
||
ContainerFrameItemButton_OnClick = function(button, ignoreShift)
|
||
if arg1 == "RightButton" then
|
||
if SFrames.Mail.TryAddItemFromBag(this:GetParent():GetID(), this:GetID()) then return end
|
||
end
|
||
orig(button, ignoreShift)
|
||
end
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Initialize (calls sub-builders)
|
||
--------------------------------------------------------------------------------
|
||
function ML:Initialize()
|
||
if S.frame then return end
|
||
BuildMainFrame()
|
||
BuildInboxPanel()
|
||
BuildDetailPanel()
|
||
BuildMailBagPanel()
|
||
BuildSendPanel()
|
||
SetupEvents()
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Panel Switching
|
||
--------------------------------------------------------------------------------
|
||
function ML:ShowInboxPanel()
|
||
if not S.frame then return end
|
||
S.frame.tabInbox:SetActive(true); S.frame.tabBag:SetActive(false); S.frame.tabSend:SetActive(false)
|
||
if S.frame.detailPanel then S.frame.detailPanel:Hide() end
|
||
S.frame.inboxPanel:Show(); S.frame.sendPanel:Hide(); S.frame.bagPanel:Hide()
|
||
S.detailMailIndex = nil
|
||
UpdateInbox()
|
||
end
|
||
|
||
function ML:ShowSendPanel()
|
||
if not S.frame then return end
|
||
S.frame.tabInbox:SetActive(false); S.frame.tabBag:SetActive(false); S.frame.tabSend:SetActive(true)
|
||
if S.frame.detailPanel then S.frame.detailPanel:Hide() end
|
||
S.detailMailIndex = nil
|
||
S.frame.inboxPanel:Hide(); S.frame.sendPanel:Show(); S.frame.bagPanel:Hide()
|
||
if S.frame.sendStatus then S.frame.sendStatus:SetText("") end
|
||
if S.statusFadeTimer then S.statusFadeTimer:SetScript("OnUpdate", nil) end
|
||
ML:UpdateSendPanel()
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Slash commands for mail contacts
|
||
--------------------------------------------------------------------------------
|
||
SLASH_MAILCONTACT1 = "/mailcontact"
|
||
SLASH_MAILCONTACT2 = "/mailcontacts"
|
||
SlashCmdList["MAILCONTACT"] = function(msg)
|
||
if not SFramesDB then
|
||
SFramesDB = {}
|
||
end
|
||
if not SFramesDB.mailContacts then
|
||
SFramesDB.mailContacts = {}
|
||
end
|
||
|
||
local cmd, arg = string.match(msg, "^(%S*)%s*(.-)$")
|
||
cmd = string.lower(cmd)
|
||
|
||
if cmd == "add" and arg ~= "" then
|
||
SFramesDB.mailContacts[arg] = true
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88[Nanami-Mail]|r 已添加常用联系人: " .. arg)
|
||
elseif cmd == "remove" and arg ~= "" then
|
||
if SFramesDB.mailContacts[arg] then
|
||
SFramesDB.mailContacts[arg] = nil
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88[Nanami-Mail]|r 已删除常用联系人: " .. arg)
|
||
else
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFF6666[Nanami-Mail]|r 常用联系人中不存在: " .. arg)
|
||
end
|
||
elseif cmd == "list" then
|
||
local contacts = SFramesDB.mailContacts
|
||
if next(contacts) then
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFCC00[Nanami-Mail]|r 常用联系人列表:")
|
||
for name in pairs(contacts) do
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88- |r" .. name)
|
||
end
|
||
else
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFCC00[Nanami-Mail]|r 常用联系人列表为空")
|
||
end
|
||
elseif cmd == "clear" then
|
||
SFramesDB.mailContacts = {}
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88[Nanami-Mail]|r 已清空常用联系人列表")
|
||
else
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFFFFCC00[Nanami-Mail]|r 常用联系人命令:")
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88/mailcontact add <name>|r - 添加常用联系人")
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88/mailcontact remove <name>|r - 删除常用联系人")
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88/mailcontact list|r - 查看常用联系人列表")
|
||
DEFAULT_CHAT_FRAME:AddMessage("|cFF66FF88/mailcontact clear|r - 清空常用联系人列表")
|
||
end
|
||
end
|
||
|
||
--------------------------------------------------------------------------------
|
||
-- Bootstrap
|
||
--------------------------------------------------------------------------------
|
||
local bootstrap = CreateFrame("Frame")
|
||
bootstrap:RegisterEvent("PLAYER_LOGIN")
|
||
bootstrap:SetScript("OnEvent", function()
|
||
if event == "PLAYER_LOGIN" then
|
||
if SFramesDB.enableMail == nil then SFramesDB.enableMail = true end
|
||
if SFramesDB.enableMail ~= false then ML:Initialize() end
|
||
end
|
||
end)
|