local AddOnName = "Nanami-UI" SFrames = SFrames or {} local TradeUI = CreateFrame("Frame", "SFramesTradeUI", UIParent) TradeUI:RegisterEvent("TRADE_SHOW") TradeUI:RegisterEvent("TRADE_CLOSED") TradeUI:RegisterEvent("TRADE_UPDATE") TradeUI:RegisterEvent("TRADE_PLAYER_ITEM_CHANGED") TradeUI:RegisterEvent("TRADE_TARGET_ITEM_CHANGED") TradeUI:RegisterEvent("TRADE_ACCEPT_UPDATE") TradeUI:RegisterEvent("TRADE_MONEY_CHANGED") TradeUI:RegisterEvent("PLAYER_TRADE_MONEY") TradeUI:RegisterEvent("UI_INFO_MESSAGE") TradeUI:RegisterEvent("CHAT_MSG_SYSTEM") local L = { NOT_TRADED = "不会被交易", WHISPER_CHECK = "发送清单", CONFIRMED = "已确认", WAITING = "等待中...", } local TRADE_DATA = { active = false, playerItems = {}, targetItems = {}, playerMoney = 0, targetMoney = 0, targetName = "", playerAccepted = false, targetAccepted = false, } SFramesDB = SFramesDB or {} -------------------------------------------------------------------------------- -- Theme: Pink Cat-Paw (matching GameMenu / Nanami-UI) -------------------------------------------------------------------------------- local T = SFrames.Theme:Extend({ labelDim = { 0.7, 0.5, 0.6 }, tradeBg = { 0.10, 0.22, 0.12, 0.95 }, tradeBorder = { 0.30, 0.70, 0.35, 0.90 }, tradeText = { 0.7, 1, 0.75 }, moneyBg = { 0.08, 0.04, 0.06, 0.85 }, moneyBorder = { 0.40, 0.25, 0.35, 0.6 }, confirmOverlay = { 0.15, 0.85, 0.25, 0.55 }, confirmBorder = { 0.30, 1.0, 0.40, 0.95 }, confirmText = { 0.3, 1, 0.4 }, statusConfirmBg = { 0.08, 0.35, 0.12, 0.92 }, statusConfirmBd = { 0.25, 0.95, 0.35, 0.95 }, statusWaitBg = { 0.15, 0.08, 0.12, 0.8 }, statusWaitBd = { 0.45, 0.28, 0.38, 0.6 }, statusWaitText = { 0.6, 0.45, 0.55 }, }) local FRAME_W = 440 local SLOT_W = 188 local SLOT_H = 42 local SLOT_GAP = 2 local SIDE_PAD = 16 local HEADER_H = 46 local BOTTOM_H = 54 local NOT_TRADED_GAP = 38 local STATUS_BAR_H = 22 -- FRAME_H computed: HEADER_H+8 + 6*SLOT_H+5*GAP + NOT_TRADED_GAP + SLOT_H + 6 + STATUS_BAR_H + 6 + BOTTOM_H local FRAME_H = HEADER_H + 8 + 6 * SLOT_H + 5 * SLOT_GAP + NOT_TRADED_GAP + SLOT_H + 6 + STATUS_BAR_H + 6 + BOTTOM_H local DEFAULT_SLOT_BORDER = { 0.25, 0.25, 0.3, 0.8 } local function GetFont() if SFrames and SFrames.GetFont then return SFrames:GetFont() end return "Fonts\\ARIALN.TTF" end -------------------------------------------------------------------------------- -- Data logic -------------------------------------------------------------------------------- local function SaveTradeState() if not TradeFrame or not TradeFrame:IsVisible() then return end local pItems = {} for i = 1, 6 do local link = nil if GetTradePlayerItemLink then link = GetTradePlayerItemLink(i) end if not link and GetTradePlayerItemInfo then local name, texture, numItems = GetTradePlayerItemInfo(i) if name and name ~= "" then link = name end end if link then local _, _, numItems = GetTradePlayerItemInfo(i) table.insert(pItems, { link = link, count = numItems or 1 }) end end if table.getn(pItems) > 0 then TRADE_DATA.playerItems = pItems end local tItems = {} for i = 1, 6 do local link = nil if GetTradeTargetItemLink then link = GetTradeTargetItemLink(i) end if not link and GetTradeTargetItemInfo then local name, texture, numItems = GetTradeTargetItemInfo(i) if name and name ~= "" then link = name end end if link then local _, _, numItems = GetTradeTargetItemInfo(i) table.insert(tItems, { link = link, count = numItems or 1 }) end end if table.getn(tItems) > 0 then TRADE_DATA.targetItems = tItems end local pm = GetPlayerTradeMoney and GetPlayerTradeMoney() or 0 local tm = GetTargetTradeMoney and GetTargetTradeMoney() or 0 if pm >= 0 and pm > TRADE_DATA.playerMoney then TRADE_DATA.playerMoney = pm end if tm >= 0 and tm > TRADE_DATA.targetMoney then TRADE_DATA.targetMoney = tm end local name = UnitName("NPC") if name and name ~= "" then TRADE_DATA.targetName = name end end local function FormatMoneyZH(copper) if not copper or copper == 0 then return nil end local g = math.floor(copper / 10000) local s = math.floor((copper - (g * 10000)) / 100) local c = math.mod(copper, 100) local text = "" if g > 0 then text = text .. g .. "g " end if s > 0 then text = text .. s .. "s " end if c > 0 then text = text .. c .. "c " end return text end local function SendLine(msg, channel, target) if channel == "WHISPER" then if target and target ~= "" and target ~= "Unknown" then SendChatMessage(msg, "WHISPER", nil, target) end else SendChatMessage(msg, channel) end end local function SendTradeWhisper() if not SFramesDB.TradeWhisperEnable then return end local target = TRADE_DATA.targetName local channel = SFramesDB.TradeWhisperChannel or "WHISPER" local outLines = {} local playerMoneyStr = FormatMoneyZH(TRADE_DATA.playerMoney) local targetMoneyStr = FormatMoneyZH(TRADE_DATA.targetMoney) local giveItems = "" for _, item in ipairs(TRADE_DATA.playerItems) do giveItems = giveItems .. item.link .. (item.count > 1 and ("x" .. item.count) or "") .. " " end local getItems = "" for _, item in ipairs(TRADE_DATA.targetItems) do getItems = getItems .. item.link .. (item.count > 1 and ("x" .. item.count) or "") .. " " end if not playerMoneyStr and giveItems == "" and not targetMoneyStr and getItems == "" then return end local useCN = (SFramesDB.TradeWhisperLang == "ZH") local header = useCN and "=== 交易完成清单 ===" or "=== Trade Summary ===" local lblGiveG = useCN and "我方金币: " or "I gave gold: " local lblGiveI = useCN and "我方物品: " or "I gave items: " local lblGotG = useCN and "对方金币: " or "I got gold: " local lblGotI = useCN and "对方物品: " or "I got items: " table.insert(outLines, header) if playerMoneyStr then table.insert(outLines, lblGiveG .. playerMoneyStr) end if giveItems ~= "" then table.insert(outLines, lblGiveI .. giveItems) end if targetMoneyStr then table.insert(outLines, lblGotG .. targetMoneyStr) end if getItems ~= "" then table.insert(outLines, lblGotI .. getItems) end for _, line in ipairs(outLines) do SendLine(line, channel, target) end end local function ClearTradeData() TRADE_DATA.playerItems = {} TRADE_DATA.targetItems = {} TRADE_DATA.playerMoney = 0 TRADE_DATA.targetMoney = 0 end local tradeWhisperSent = false local function IsTradeCompleteMsg(msg) if not msg then return false end if string.find(msg, "Trade successful") then return true end if string.find(msg, "Trade complete") then return true end if string.find(msg, "交易完成") then return true end if string.find(msg, "交易成功") then return true end return false end local sfTradeRefreshing = false local function ForceRefreshTradeVisuals() if not TradeFrame or not TradeFrame:IsVisible() then return end if sfTradeRefreshing then return end if TradeFrame_Update then sfTradeRefreshing = true pcall(function() TradeFrame_Update() end) sfTradeRefreshing = false end end TradeUI:SetScript("OnEvent", function() if event == "TRADE_SHOW" then tradeWhisperSent = false TRADE_DATA.active = true TRADE_DATA.targetName = UnitName("NPC") or "" TRADE_DATA.playerItems = {} TRADE_DATA.targetItems = {} TRADE_DATA.playerMoney = 0 TRADE_DATA.targetMoney = 0 TRADE_DATA.playerAccepted = false TRADE_DATA.targetAccepted = false SaveTradeState() ForceRefreshTradeVisuals() elseif event == "TRADE_PLAYER_ITEM_CHANGED" or event == "TRADE_TARGET_ITEM_CHANGED" then TRADE_DATA.playerAccepted = false TRADE_DATA.targetAccepted = false SaveTradeState() ForceRefreshTradeVisuals() elseif event == "TRADE_UPDATE" then SaveTradeState() ForceRefreshTradeVisuals() elseif event == "TRADE_ACCEPT_UPDATE" then TRADE_DATA.playerAccepted = (arg1 and arg1 == 1) TRADE_DATA.targetAccepted = (arg2 and arg2 == 1) SaveTradeState() ForceRefreshTradeVisuals() elseif event == "TRADE_MONEY_CHANGED" or event == "PLAYER_TRADE_MONEY" then SaveTradeState() ForceRefreshTradeVisuals() elseif event == "TRADE_CLOSED" then if TRADE_DATA.playerAccepted and TRADE_DATA.targetAccepted and not tradeWhisperSent then tradeWhisperSent = true SendTradeWhisper() ClearTradeData() end TRADE_DATA.active = false TRADE_DATA.playerAccepted = false TRADE_DATA.targetAccepted = false elseif event == "UI_INFO_MESSAGE" then if IsTradeCompleteMsg(arg1) and not tradeWhisperSent then tradeWhisperSent = true SendTradeWhisper() ClearTradeData() end elseif event == "CHAT_MSG_SYSTEM" then if IsTradeCompleteMsg(arg1) and not tradeWhisperSent then tradeWhisperSent = true SendTradeWhisper() ClearTradeData() end end end) -------------------------------------------------------------------------------- -- UI Helpers (matching GameMenu / Nanami-UI style) -------------------------------------------------------------------------------- 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 CreateShadow(parent, size) local s = CreateFrame("Frame", nil, parent) local sz = size or 4 s:SetPoint("TOPLEFT", parent, "TOPLEFT", -sz, sz) s:SetPoint("BOTTOMRIGHT", parent, "BOTTOMRIGHT", sz, -sz) 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.55) s:SetBackdropBorderColor(0, 0, 0, 0.4) return s end -------------------------------------------------------------------------------- -- Tooltip scanner for item level -------------------------------------------------------------------------------- local tooltipScanner = CreateFrame("GameTooltip", "SFramesTradeTooltipScan", nil, "GameTooltipTemplate") tooltipScanner:SetOwner(UIParent, "ANCHOR_NONE") local function ScanItemLevelFromTooltip() for i = 2, tooltipScanner:NumLines() do local line = _G["SFramesTradeTooltipScanTextLeft" .. i] if line then local text = line:GetText() if text then local _, _, ilvl = string.find(text, "(%d+)") if string.find(text, "Item Level") or string.find(text, "iLvl") or string.find(text, "ilvl") or string.find(text, "物品等级") then if ilvl then return tonumber(ilvl) end end end end end return nil end local function GetTradePlayerItemLevel(slot) tooltipScanner:SetOwner(UIParent, "ANCHOR_NONE") tooltipScanner:ClearLines() local ok = pcall(function() tooltipScanner:SetTradePlayerItem(slot) end) if ok then return ScanItemLevelFromTooltip() end local link = GetTradePlayerItemLink and GetTradePlayerItemLink(slot) if link then tooltipScanner:SetOwner(UIParent, "ANCHOR_NONE") tooltipScanner:ClearLines() ok = pcall(function() tooltipScanner:SetHyperlink(link) end) if ok then return ScanItemLevelFromTooltip() end end return nil end local function GetTradeTargetItemLevel(slot) tooltipScanner:SetOwner(UIParent, "ANCHOR_NONE") tooltipScanner:ClearLines() local ok = pcall(function() tooltipScanner:SetTradeTargetItem(slot) end) if ok then return ScanItemLevelFromTooltip() end local link = GetTradeTargetItemLink and GetTradeTargetItemLink(slot) if link then tooltipScanner:SetOwner(UIParent, "ANCHOR_NONE") tooltipScanner:ClearLines() ok = pcall(function() tooltipScanner:SetHyperlink(link) end) if ok then return ScanItemLevelFromTooltip() end end return nil end -------------------------------------------------------------------------------- -- Quality color from item link -------------------------------------------------------------------------------- local function GetQualityColorFromLink(link) if not link then return nil, nil, nil end local _, _, hex = string.find(link, "|c(%x+)|H") if hex and string.len(hex) == 8 then local r = tonumber(string.sub(hex, 3, 4), 16) / 255 local g = tonumber(string.sub(hex, 5, 6), 16) / 255 local b = tonumber(string.sub(hex, 7, 8), 16) / 255 return r, g, b end return nil, nil, nil end local function GetQualityColorFromRarity(rarity) if type(rarity) ~= "number" then return nil, nil, nil end if not GetItemQualityColor then return nil, nil, nil end local ok, r, g, b = pcall(function() return GetItemQualityColor(rarity) end) if ok and r and g and b then return r, g, b end return nil, nil, nil end local function ResolveTradeItemQuality(link, quality, name) if type(quality) == "number" then return quality end if GetItemInfo then if link then local _, _, q = GetItemInfo(link) if type(q) == "number" then return q end end if name then local _, _, q = GetItemInfo(name) if type(q) == "number" then return q end end end return nil end local function IsCommonOrPoor(link) if not link then return true end local _, _, hex = string.find(link, "|c(%x+)|H") if hex then local hexLower = string.lower(hex) return hexLower == "ffffffff" or hexLower == "ff9d9d9d" end return true end -------------------------------------------------------------------------------- -- Right-click to remove player trade items -------------------------------------------------------------------------------- local function HookSingleTradeSlot(slotIndex) local itemBtn = _G["TradePlayerItem" .. slotIndex .. "ItemButton"] if not itemBtn or itemBtn.sfRightClickHooked then return end itemBtn.sfRightClickHooked = true itemBtn:RegisterForClicks("LeftButtonUp", "RightButtonUp") local origScript = itemBtn:GetScript("OnClick") itemBtn:SetScript("OnClick", function() if arg1 == "RightButton" then local hasItem = false if GetTradePlayerItemLink then local link = GetTradePlayerItemLink(slotIndex) if link then hasItem = true end end if not hasItem then local name = GetTradePlayerItemInfo(slotIndex) if name and name ~= "" then hasItem = true end end if hasItem then ClearCursor() ClickTradeButton(slotIndex) return end end if origScript then origScript() end end) end local function HookTradeItemRightClick() for i = 1, 6 do HookSingleTradeSlot(i) end end -------------------------------------------------------------------------------- -- Re-hide Blizzard visuals (called every TradeFrame_Update) -------------------------------------------------------------------------------- local function ReHideBlizzardSlot(itemPrefix, index) local btnName = itemPrefix .. index .. "ItemButton" local icon = _G[btnName .. "IconTexture"] if icon then icon:SetAlpha(0); icon:Hide() end local nt = _G[btnName .. "NormalTexture"] if nt then nt:SetAlpha(0); nt:Hide() end local slot = _G[btnName .. "SlotTexture"] if slot then slot:SetAlpha(0); slot:Hide() end local cnt = _G[btnName .. "Count"] if cnt then cnt:SetAlpha(0) end local bgSlot = _G[itemPrefix .. index .. "ItemButtonSlotTexture"] if bgSlot then bgSlot:SetAlpha(0); bgSlot:Hide() end local bgSlot2 = _G[itemPrefix .. index .. "SlotTexture"] if bgSlot2 then bgSlot2:SetAlpha(0); bgSlot2:Hide() end local bgSlot3 = _G[itemPrefix .. index .. "ItemButtonBackground"] if bgSlot3 then bgSlot3:SetAlpha(0); bgSlot3:Hide() end local nf = _G[itemPrefix .. index .. "NameFrame"] if nf then nf:SetAlpha(0); nf:Hide() end end -------------------------------------------------------------------------------- -- Skin Trade Frame -------------------------------------------------------------------------------- local function SkinTradeFrame() if TradeFrame.sfSkinned then return end TradeFrame.sfSkinned = true TradeFrame:SetMovable(true) TradeFrame:EnableMouse(true) TradeFrame:RegisterForDrag("LeftButton") TradeFrame:SetScript("OnDragStart", function() this:StartMoving() end) TradeFrame:SetScript("OnDragStop", function() this:StopMovingOrSizing() end) -- Hide ALL default textures local regions = { TradeFrame:GetRegions() } local bottomTexts = {} for _, r in ipairs(regions) do if r:IsObjectType("Texture") then r:SetTexture(nil) r:SetAlpha(0) elseif r:IsObjectType("FontString") then local text = r:GetText() if text and (string.find(text, "不会被交易") or string.find(text, "Will not be traded") or text == L.NOT_TRADED) then table.insert(bottomTexts, r) end end end TradeFrame.sfBottomTexts = bottomTexts TradeFrame:SetWidth(FRAME_W) TradeFrame:SetHeight(FRAME_H) -- Main backdrop - Nanami-UI rounded style (matching GameMenu) SetRoundBackdrop(TradeFrame, T.panelBg, T.panelBorder) CreateShadow(TradeFrame, 5) -- Header separator local headerSep = TradeFrame:CreateTexture(nil, "ARTWORK") headerSep:SetTexture("Interface\\Buttons\\WHITE8X8") headerSep:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4]) headerSep:SetHeight(1) headerSep:SetPoint("TOPLEFT", TradeFrame, "TOPLEFT", 4, -HEADER_H) headerSep:SetPoint("TOPRIGHT", TradeFrame, "TOPRIGHT", -4, -HEADER_H) -- Center vertical divider (pink tinted) local divLine = TradeFrame:CreateTexture(nil, "ARTWORK") divLine:SetTexture("Interface\\Buttons\\WHITE8X8") divLine:SetVertexColor(T.divider[1], T.divider[2], T.divider[3], T.divider[4]) divLine:SetWidth(1) divLine:SetPoint("TOP", TradeFrame, "TOP", 0, -(HEADER_H + 2)) divLine:SetPoint("BOTTOM", TradeFrame, "BOTTOM", 0, BOTTOM_H + 2) -- Bottom separator local bottomSep = TradeFrame:CreateTexture(nil, "ARTWORK") bottomSep:SetTexture("Interface\\Buttons\\WHITE8X8") bottomSep:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4]) bottomSep:SetHeight(1) bottomSep:SetPoint("BOTTOMLEFT", TradeFrame, "BOTTOMLEFT", 4, BOTTOM_H) bottomSep:SetPoint("BOTTOMRIGHT", TradeFrame, "BOTTOMRIGHT", -4, BOTTOM_H) -- Player name (pink/gold tint) TradeFramePlayerNameText:ClearAllPoints() TradeFramePlayerNameText:SetPoint("TOPLEFT", TradeFrame, "TOPLEFT", SIDE_PAD, -8) TradeFramePlayerNameText:SetFont(GetFont(), 12, "OUTLINE") TradeFramePlayerNameText:SetTextColor(T.gold[1], T.gold[2], T.gold[3]) -- Target name TradeFrameRecipientNameText:ClearAllPoints() TradeFrameRecipientNameText:SetPoint("TOPRIGHT", TradeFrame, "TOPRIGHT", -SIDE_PAD, -8) TradeFrameRecipientNameText:SetFont(GetFont(), 12, "OUTLINE") TradeFrameRecipientNameText:SetTextColor(T.gold[1], T.gold[2], T.gold[3]) if TradeFrameRecipientPortrait then TradeFrameRecipientPortrait:Hide() end if TradeFramePlayerPortrait then TradeFramePlayerPortrait:Hide() end -- Confirmation status bars (created here, positioned after item layout) local function CreateStatusBar(parent, anchorSide) local bar = CreateFrame("Frame", nil, parent) bar:SetWidth(SLOT_W) bar:SetHeight(STATUS_BAR_H) bar:SetFrameLevel(parent:GetFrameLevel() + 5) SetRoundBackdrop(bar, T.statusWaitBg, T.statusWaitBd) local icon = bar:CreateFontString(nil, "OVERLAY") icon:SetFont(GetFont(), 13, "OUTLINE") icon:SetPoint("LEFT", bar, "LEFT", 8, 0) bar.sfIcon = icon local label = bar:CreateFontString(nil, "OVERLAY") label:SetFont(GetFont(), 12, "OUTLINE") label:SetPoint("LEFT", icon, "RIGHT", 4, 0) label:SetPoint("RIGHT", bar, "RIGHT", -6, 0) label:SetJustifyH(anchorSide) bar.sfLabel = label local glow = bar:CreateTexture(nil, "BACKGROUND") glow:SetTexture("Interface\\Buttons\\WHITE8X8") glow:SetAllPoints(bar) glow:SetAlpha(0) bar.sfGlow = glow bar.sfElapsed = 0 bar:SetScript("OnUpdate", function() if not this.sfConfirmed then return end this.sfElapsed = (this.sfElapsed or 0) + arg1 local a = 0.35 + 0.2 * math.sin(this.sfElapsed * 3.5) if this.sfGlow then this.sfGlow:SetAlpha(a) end end) bar:Hide() return bar end local playerStatusBar = CreateStatusBar(TradeFrame, "LEFT") TradeFrame.sfPlayerStatusBar = playerStatusBar local targetStatusBar = CreateStatusBar(TradeFrame, "LEFT") TradeFrame.sfTargetStatusBar = targetStatusBar -- Money frames TradePlayerInputMoneyFrame:ClearAllPoints() TradePlayerInputMoneyFrame:SetPoint("TOPLEFT", TradeFrame, "TOPLEFT", SIDE_PAD, -24) local pMoneyBg = CreateFrame("Frame", nil, TradeFrame) pMoneyBg:SetPoint("TOPLEFT", TradePlayerInputMoneyFrame, "TOPLEFT", -3, 3) pMoneyBg:SetPoint("BOTTOMRIGHT", TradePlayerInputMoneyFrame, "BOTTOMRIGHT", 3, -3) pMoneyBg:SetFrameLevel(math.max(TradePlayerInputMoneyFrame:GetFrameLevel() - 1, 0)) SetRoundBackdrop(pMoneyBg, T.moneyBg, T.moneyBorder) TradeRecipientMoneyFrame:ClearAllPoints() TradeRecipientMoneyFrame:SetPoint("TOPRIGHT", TradeFrame, "TOPRIGHT", -SIDE_PAD, -24) local rMoneyBg = CreateFrame("Frame", nil, TradeFrame) rMoneyBg:SetPoint("TOPLEFT", TradeRecipientMoneyFrame, "TOPLEFT", -3, 3) rMoneyBg:SetPoint("BOTTOMRIGHT", TradeRecipientMoneyFrame, "BOTTOMRIGHT", 3, -3) rMoneyBg:SetFrameLevel(math.max(TradeRecipientMoneyFrame:GetFrameLevel() - 1, 0)) SetRoundBackdrop(rMoneyBg, T.moneyBg, T.moneyBorder) -- Style money input text local moneyEditNames = { "Gold", "Silver", "Copper" } for _, suffix in ipairs(moneyEditNames) do local eb = _G["TradePlayerInputMoneyFrame" .. suffix] if eb and eb.SetFont then eb:SetFont(GetFont(), 12, "OUTLINE") eb:SetTextColor(1, 1, 1, 1) end local btn = _G["TradePlayerInputMoneyFrame" .. suffix .. "Button"] if btn then local icon = btn:GetNormalTexture() if icon then icon:SetVertexColor(1, 1, 1, 1) end end local rBtn = _G["TradeRecipientMoneyFrame" .. suffix .. "Button"] if rBtn then local rText = _G["TradeRecipientMoneyFrame" .. suffix .. "ButtonText"] if rText and rText.SetFont then rText:SetFont(GetFont(), 11, "OUTLINE") rText:SetTextColor(1, 1, 1, 1) end end end ---------------------------------------------------------------------------- -- Item slots - fully custom, Blizzard button is invisible click receiver ---------------------------------------------------------------------------- local function HideBlizzardButton(itemBtn) local btnName = itemBtn:GetName() -- Kill every known named child texture by explicit name local suffixes = { "IconTexture", "NormalTexture", "SlotTexture", "Count" } for _, suf in ipairs(suffixes) do local obj = _G[btnName .. suf] if obj then if obj.SetTexture then obj:SetTexture(nil) end if obj.SetAlpha then obj:SetAlpha(0) end if obj.SetTextColor then obj:SetTextColor(0,0,0,0) end if obj.Hide then obj:Hide() end end end -- Kill template textures via API if itemBtn.GetNormalTexture then local nt = itemBtn:GetNormalTexture() if nt then nt:SetTexture(nil); nt:SetAlpha(0) end end if itemBtn.GetPushedTexture then local pt = itemBtn:GetPushedTexture() if pt then pt:SetTexture(nil); pt:SetAlpha(0) end end if itemBtn.GetHighlightTexture then local ht = itemBtn:GetHighlightTexture() if ht then ht:SetTexture(nil); ht:SetAlpha(0) end end -- Kill all remaining child regions local regions = { itemBtn:GetRegions() } for _, r in ipairs(regions) do if r then if r.SetTexture then r:SetTexture(nil) end if r.SetAlpha then r:SetAlpha(0) end if r.SetTextColor then r:SetTextColor(0,0,0,0) end if r.Hide then r:Hide() end end end itemBtn:SetBackdrop(nil) end local function CreateSfSlot(parent) local slot = CreateFrame("Frame", nil, parent) slot:SetWidth(SLOT_H) slot:SetHeight(SLOT_H) slot: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 } }) slot:SetBackdropColor(T.slotBg[1], T.slotBg[2], T.slotBg[3], T.slotBg[4]) slot:SetBackdropBorderColor(DEFAULT_SLOT_BORDER[1], DEFAULT_SLOT_BORDER[2], DEFAULT_SLOT_BORDER[3], DEFAULT_SLOT_BORDER[4]) local icon = slot:CreateTexture(nil, "ARTWORK") icon:SetWidth(SLOT_H - 4) icon:SetHeight(SLOT_H - 4) icon:SetPoint("CENTER", slot, "CENTER", 0, 0) icon:SetTexCoord(0.08, 0.92, 0.08, 0.92) icon:Hide() slot.icon = icon local highlight = slot:CreateTexture(nil, "OVERLAY") highlight:SetTexture("Interface\\Buttons\\ButtonHilight-Square") highlight:SetBlendMode("ADD") highlight:SetWidth(SLOT_H - 4) highlight:SetHeight(SLOT_H - 4) highlight:SetPoint("CENTER", slot, "CENTER", 0, 0) highlight:SetAlpha(0) slot.highlight = highlight local ilvl = slot:CreateFontString(nil, "OVERLAY") ilvl:SetFont(GetFont(), 9, "OUTLINE") ilvl:SetPoint("BOTTOMRIGHT", slot, "BOTTOMRIGHT", -2, 2) ilvl:SetTextColor(1, 0.82, 0) ilvl:SetJustifyH("RIGHT") ilvl:Hide() slot.ilvl = ilvl local count = slot:CreateFontString(nil, "OVERLAY") count:SetFont(GetFont(), 11, "OUTLINE") count:SetPoint("BOTTOMRIGHT", slot, "BOTTOMRIGHT", -2, 2) count:SetTextColor(1, 1, 1) count:SetJustifyH("RIGHT") count:Hide() slot.count = count local qualGlow = slot:CreateTexture(nil, "OVERLAY") qualGlow:SetTexture("Interface\\Buttons\\UI-ActionButton-Border") qualGlow:SetBlendMode("ADD") qualGlow:SetAlpha(0.8) qualGlow:SetWidth(SLOT_H * 1.8) qualGlow:SetHeight(SLOT_H * 1.8) qualGlow:SetPoint("CENTER", slot, "CENTER", 0, 0) qualGlow:Hide() slot.qualGlow = qualGlow return slot end local function StyleTradeItem(itemPrefix, index) local itemFrame = _G[itemPrefix .. index] local itemBtn = _G[itemPrefix .. index .. "ItemButton"] local itemName = _G[itemPrefix .. index .. "Name"] local bgSlot = _G[itemPrefix .. index .. "ItemButtonSlotTexture"] local bgSlot2 = _G[itemPrefix .. index .. "SlotTexture"] local bgSlot3 = _G[itemPrefix .. index .. "ItemButtonBackground"] local nameFrame = _G[itemPrefix .. index .. "NameFrame"] if bgSlot then bgSlot:SetTexture(nil); bgSlot:Hide() bgSlot.Show = function() end end if bgSlot2 then bgSlot2:SetTexture(nil); bgSlot2:Hide() bgSlot2.Show = function() end end if bgSlot3 then bgSlot3:SetTexture(nil); bgSlot3:Hide() bgSlot3.Show = function() end end if nameFrame then nameFrame:SetTexture(nil); nameFrame:Hide() nameFrame.Show = function() end end itemFrame:SetWidth(SLOT_W) itemFrame:SetHeight(SLOT_H) -- Row background (create once) if not itemFrame.sfRowBg then local slotBg = itemFrame:CreateTexture(nil, "BACKGROUND") slotBg:SetTexture("Interface\\Tooltips\\UI-Tooltip-Background") slotBg:SetVertexColor(0.08, 0.04, 0.06, 0.4) slotBg:SetAllPoints(itemFrame) itemFrame.sfRowBg = slotBg end -- Create our pure custom slot (once) if not itemFrame.sfSlot then itemFrame.sfSlot = CreateSfSlot(itemFrame) end local sfSlot = itemFrame.sfSlot sfSlot:ClearAllPoints() sfSlot:SetPoint("LEFT", itemFrame, "LEFT", 1, 0) sfSlot:SetFrameLevel(itemFrame:GetFrameLevel() + 1) sfSlot:Show() -- Make Blizzard button completely invisible HideBlizzardButton(itemBtn) -- Position invisible Blizzard button exactly over sfSlot for click/drag itemBtn:ClearAllPoints() itemBtn:SetWidth(SLOT_H) itemBtn:SetHeight(SLOT_H) itemBtn:SetPoint("CENTER", sfSlot, "CENTER", 0, 0) itemBtn:SetFrameLevel(sfSlot:GetFrameLevel() + 2) -- Hover glow: show/hide highlight on sfSlot when mouse enters Blizzard button if not itemBtn.sfHoverHooked then itemBtn.sfHoverHooked = true local origEnter = itemBtn:GetScript("OnEnter") local origLeave = itemBtn:GetScript("OnLeave") itemBtn:SetScript("OnEnter", function() if origEnter then origEnter() end local sf = this:GetParent() and this:GetParent().sfSlot if sf and sf.highlight then sf.highlight:SetAlpha(0.35) end end) itemBtn:SetScript("OnLeave", function() if origLeave then origLeave() end local sf = this:GetParent() and this:GetParent().sfSlot if sf and sf.highlight then sf.highlight:SetAlpha(0) end end) end -- Name text anchored to sfSlot itemName:ClearAllPoints() itemName:SetPoint("LEFT", sfSlot, "RIGHT", 6, 0) itemName:SetPoint("RIGHT", itemFrame, "RIGHT", -4, 0) itemName:SetJustifyH("LEFT") itemName:SetFont(GetFont(), 11, "OUTLINE") end -- Layout items in two columns for i = 1, 7 do StyleTradeItem("TradePlayerItem", i) StyleTradeItem("TradeRecipientItem", i) local pf = _G["TradePlayerItem" .. i] local rf = _G["TradeRecipientItem" .. i] pf:ClearAllPoints() rf:ClearAllPoints() if i == 1 then pf:SetPoint("TOPLEFT", TradeFrame, "TOPLEFT", SIDE_PAD, -(HEADER_H + 8)) rf:SetPoint("TOPRIGHT", TradeFrame, "TOPRIGHT", -SIDE_PAD, -(HEADER_H + 8)) elseif i == 7 then pf:SetPoint("TOPLEFT", _G["TradePlayerItem6"], "BOTTOMLEFT", 0, -NOT_TRADED_GAP) rf:SetPoint("TOPLEFT", _G["TradeRecipientItem6"], "BOTTOMLEFT", 0, -NOT_TRADED_GAP) if TradeFrame.sfBottomTexts then for idx, lbl in ipairs(TradeFrame.sfBottomTexts) do lbl:ClearAllPoints() lbl:SetFont(GetFont(), 10, "OUTLINE") lbl:SetTextColor(T.labelDim[1], T.labelDim[2], T.labelDim[3]) if idx == 1 then lbl:SetPoint("BOTTOMLEFT", pf, "TOPLEFT", 0, 5) else lbl:SetPoint("BOTTOMLEFT", rf, "TOPLEFT", 0, 5) end end end else pf:SetPoint("TOPLEFT", _G["TradePlayerItem" .. (i - 1)], "BOTTOMLEFT", 0, -SLOT_GAP) rf:SetPoint("TOPLEFT", _G["TradeRecipientItem" .. (i - 1)], "BOTTOMLEFT", 0, -SLOT_GAP) end end -- Position status bars below item 7 if TradeFrame.sfPlayerStatusBar then TradeFrame.sfPlayerStatusBar:ClearAllPoints() TradeFrame.sfPlayerStatusBar:SetPoint("TOPLEFT", _G["TradePlayerItem7"], "BOTTOMLEFT", 0, -4) end if TradeFrame.sfTargetStatusBar then TradeFrame.sfTargetStatusBar:ClearAllPoints() TradeFrame.sfTargetStatusBar:SetPoint("TOPLEFT", _G["TradeRecipientItem7"], "BOTTOMLEFT", 0, -4) end -- Thin separator in the gap between slot 6 and not-traded label local function MakeThinSep(anchor, w) local sep = TradeFrame: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:SetWidth(w) sep:SetPoint("BOTTOMLEFT", anchor, "BOTTOMLEFT", 0, -(NOT_TRADED_GAP / 2.5)) end MakeThinSep(_G["TradePlayerItem6"], SLOT_W) MakeThinSep(_G["TradeRecipientItem6"], SLOT_W) ---------------------------------------------------------------------------- -- Hide Blizzard confirm highlights (we handle this ourselves) ---------------------------------------------------------------------------- local function KillBlizzardHighlight(name) local obj = _G[name] if not obj then return end if obj:IsObjectType("Texture") then obj:SetTexture(nil); obj:SetAlpha(0); obj:Hide() obj.Show = function() end elseif obj:IsObjectType("Frame") then local regs = { obj:GetRegions() } for _, r in ipairs(regs) do if r:IsObjectType("Texture") then r:SetTexture(nil); r:Hide() end end obj:SetAlpha(0); obj:Hide() obj.Show = function() end end end KillBlizzardHighlight("TradeHighlightPlayer") KillBlizzardHighlight("TradeHighlightRecipient") KillBlizzardHighlight("TradeHighlightPlayerEnchant") KillBlizzardHighlight("TradeHighlightRecipientEnchant") ---------------------------------------------------------------------------- -- Custom confirm overlay (our own, with proper FrameLevel + pulse) ---------------------------------------------------------------------------- local function CreateConfirmOverlay(parent, item1, item2) local overlay = CreateFrame("Frame", nil, parent) overlay:SetFrameLevel(parent:GetFrameLevel() + 8) overlay:SetPoint("TOPLEFT", item1, "TOPLEFT", -4, 4) overlay:SetPoint("BOTTOMRIGHT", item2, "BOTTOMRIGHT", 4, -4) SetRoundBackdrop(overlay, { 0, 0, 0, 0 }, T.confirmBorder) overlay.sfElapsed = 0 overlay:SetScript("OnUpdate", function() this.sfElapsed = (this.sfElapsed or 0) + arg1 local pulse = 0.6 + 0.4 * math.sin(this.sfElapsed * 3) this:SetBackdropBorderColor( T.confirmBorder[1], T.confirmBorder[2], T.confirmBorder[3], pulse) end) overlay:EnableMouse(false) overlay:Hide() return overlay end TradeFrame.sfPlayerOverlay = CreateConfirmOverlay(TradeFrame, _G["TradePlayerItem1"], _G["TradePlayerItem6"]) TradeFrame.sfPlayerOverlayEnchant = CreateConfirmOverlay(TradeFrame, _G["TradePlayerItem7"], _G["TradePlayerItem7"]) TradeFrame.sfTargetOverlay = CreateConfirmOverlay(TradeFrame, _G["TradeRecipientItem1"], _G["TradeRecipientItem6"]) TradeFrame.sfTargetOverlayEnchant = CreateConfirmOverlay(TradeFrame, _G["TradeRecipientItem7"], _G["TradeRecipientItem7"]) ---------------------------------------------------------------------------- -- Buttons - Nanami-UI GameMenu style ---------------------------------------------------------------------------- local function SkinBtn(btn, bgCol, borderCol, textCol, label) if not btn then return end btn:SetWidth(72) btn:SetHeight(26) local nt = btn:GetNormalTexture() if nt then nt:SetTexture(nil) end local pt = btn:GetPushedTexture() if pt then pt:SetTexture(nil) end local ht = btn:GetHighlightTexture() if ht then ht:SetTexture(nil) end local dt = btn:GetDisabledTexture() if dt then dt:SetTexture(nil) end SetRoundBackdrop(btn, bgCol, borderCol) local origEnter = btn:GetScript("OnEnter") local origLeave = btn:GetScript("OnLeave") if not btn.sfHoverHooked then btn.sfHoverHooked = true btn.sfBgCol = bgCol btn.sfBorderCol = borderCol btn:SetScript("OnEnter", function() if origEnter then origEnter() end this:SetBackdropColor(T.btnHoverBg[1], T.btnHoverBg[2], T.btnHoverBg[3], T.btnHoverBg[4]) this:SetBackdropBorderColor(T.btnHoverBorder[1], T.btnHoverBorder[2], T.btnHoverBorder[3], T.btnHoverBorder[4]) local fs = this:GetFontString() if fs then fs:SetTextColor(T.btnActiveText[1], T.btnActiveText[2], T.btnActiveText[3]) end end) btn:SetScript("OnLeave", function() if origLeave then origLeave() end local bg = this.sfBgCol or T.btnBg local bd = this.sfBorderCol or T.btnBorder this:SetBackdropColor(bg[1], bg[2], bg[3], bg[4] or 1) this:SetBackdropBorderColor(bd[1], bd[2], bd[3], bd[4] or 1) local fs = this:GetFontString() if fs and this.sfTextCol then fs:SetTextColor(unpack(this.sfTextCol)) end end) end local fs = btn:GetFontString() if fs then fs:SetFont(GetFont(), 11, "OUTLINE") fs:SetTextColor(unpack(textCol or T.btnText)) if label then fs:SetText(label) end end btn.sfTextCol = textCol or T.btnText end SkinBtn(TradeFrameTradeButton, T.tradeBg, T.tradeBorder, T.tradeText, "交易") SkinBtn(TradeFrameCancelButton, T.btnBg, T.btnBorder, T.btnText, "取消") TradeFrameTradeButton:ClearAllPoints() TradeFrameCancelButton:ClearAllPoints() TradeFrameCancelButton:SetPoint("BOTTOMRIGHT", TradeFrame, "BOTTOMRIGHT", -SIDE_PAD, 14) TradeFrameTradeButton:SetPoint("RIGHT", TradeFrameCancelButton, "LEFT", -6, 0) ---------------------------------------------------------------------------- -- Whisper checkbox + channel dropdown ---------------------------------------------------------------------------- local cbObj = _G["SFramesTradeWhisperObj"] if not cbObj then cbObj = CreateFrame("CheckButton", "SFramesTradeWhisperObj", TradeFrame, "UICheckButtonTemplate") cbObj:SetWidth(20) cbObj:SetHeight(20) cbObj:SetPoint("BOTTOMLEFT", TradeFrame, "BOTTOMLEFT", SIDE_PAD, 14) local cbText = _G[cbObj:GetName() .. "Text"] if cbText then cbText:SetFont(GetFont(), 11, "OUTLINE") cbText:SetText(L.WHISPER_CHECK) cbText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3]) end if SFramesDB.TradeWhisperEnable == nil then SFramesDB.TradeWhisperEnable = false end cbObj:SetChecked(SFramesDB.TradeWhisperEnable and 1 or 0) cbObj:SetScript("OnClick", function() SFramesDB = SFramesDB or {} SFramesDB.TradeWhisperEnable = (this:GetChecked() == 1) end) local drop = CreateFrame("Frame", "SFramesTradeChannelObj", TradeFrame, "UIDropDownMenuTemplate") drop:SetPoint("LEFT", cbText or cbObj, "RIGHT", -8, -1) UIDropDownMenu_SetWidth(60, drop) local dropText = _G[drop:GetName() .. "Text"] if dropText then dropText:SetFont(GetFont(), 10, "OUTLINE") dropText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3]) end local channels = { { text = "密语", value = "WHISPER" }, { text = "小队", value = "PARTY" }, { text = "当前", value = "SAY" }, } local function TradeDropDownInit() SFramesDB = SFramesDB or {} local selected = SFramesDB.TradeWhisperChannel or "WHISPER" for _, info in ipairs(channels) do local capturedText = info.text local capturedValue = info.value local d = {} d.text = capturedText d.value = capturedValue d.func = function() SFramesDB = SFramesDB or {} SFramesDB.TradeWhisperChannel = capturedValue UIDropDownMenu_SetSelectedValue(drop, capturedValue) local txt = _G[drop:GetName() .. "Text"] if txt then txt:SetText(capturedText) end end d.checked = (capturedValue == selected) UIDropDownMenu_AddButton(d) end end UIDropDownMenu_Initialize(drop, TradeDropDownInit) SFramesDB = SFramesDB or {} UIDropDownMenu_SetSelectedValue(drop, SFramesDB.TradeWhisperChannel or "WHISPER") if dropText then for _, info in ipairs(channels) do if info.value == (SFramesDB.TradeWhisperChannel or "WHISPER") then dropText:SetText(info.text) break end end end -- Language dropdown (EN / ZH) local langDrop = CreateFrame("Frame", "SFramesTradeLangObj", TradeFrame, "UIDropDownMenuTemplate") langDrop:SetPoint("LEFT", drop, "RIGHT", -16, 0) UIDropDownMenu_SetWidth(50, langDrop) local langDropText = _G[langDrop:GetName() .. "Text"] if langDropText then langDropText:SetFont(GetFont(), 10, "OUTLINE") langDropText:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3]) end local langs = { { text = "EN", value = "EN" }, { text = "中文", value = "ZH" }, } local function TradeLangDropInit() SFramesDB = SFramesDB or {} local selected = SFramesDB.TradeWhisperLang or "EN" for _, info in ipairs(langs) do local capText = info.text local capValue = info.value local d = {} d.text = capText d.value = capValue d.func = function() SFramesDB = SFramesDB or {} SFramesDB.TradeWhisperLang = capValue UIDropDownMenu_SetSelectedValue(langDrop, capValue) local txt = _G[langDrop:GetName() .. "Text"] if txt then txt:SetText(capText) end end d.checked = (capValue == selected) UIDropDownMenu_AddButton(d) end end UIDropDownMenu_Initialize(langDrop, TradeLangDropInit) SFramesDB = SFramesDB or {} UIDropDownMenu_SetSelectedValue(langDrop, SFramesDB.TradeWhisperLang or "EN") if langDropText then for _, info in ipairs(langs) do if info.value == (SFramesDB.TradeWhisperLang or "EN") then langDropText:SetText(info.text) break end end end end -- Close button local closeBtn = _G["TradeFrameCloseButton"] if closeBtn then closeBtn:ClearAllPoints() closeBtn:SetPoint("TOPRIGHT", TradeFrame, "TOPRIGHT", -2, -2) end HookTradeItemRightClick() end -------------------------------------------------------------------------------- -- Hooks -------------------------------------------------------------------------------- local Hook_TradeFrame_OnShow = TradeFrame_OnShow function TradeFrame_OnShow() if Hook_TradeFrame_OnShow then Hook_TradeFrame_OnShow() end SkinTradeFrame() ForceRefreshTradeVisuals() end local function UpdateSfSlot(sfSlot, texture, numItems, link, ilvl, quality) if not sfSlot then return end -- Icon texture if texture then sfSlot.icon:SetTexture(texture) sfSlot.icon:Show() else sfSlot.icon:SetTexture(nil) sfSlot.icon:Hide() end -- Stack count if numItems and numItems > 1 then sfSlot.count:SetText(numItems) sfSlot.count:Show() sfSlot.ilvl:Hide() else sfSlot.count:Hide() -- Item level (only show if no stack count) if ilvl and ilvl > 0 and texture then sfSlot.ilvl:SetText(ilvl) sfSlot.ilvl:Show() else sfSlot.ilvl:Hide() end end -- Quality border local r, g, b = nil, nil, nil if link and not IsCommonOrPoor(link) then r, g, b = GetQualityColorFromLink(link) end if (not r) and type(quality) == "number" and quality ~= 1 then r, g, b = GetQualityColorFromRarity(quality) end if r then if sfSlot.qualGlow then sfSlot.qualGlow:SetVertexColor(r, g, b) sfSlot.qualGlow:Show() end else if sfSlot.qualGlow then sfSlot.qualGlow:Hide() end end end local function UpdateSlotNameColor(nameObj, link, quality) if not nameObj then return end local r, g, b = nil, nil, nil if link then r, g, b = GetQualityColorFromLink(link) end if (not r) and type(quality) == "number" and quality ~= 1 then r, g, b = GetQualityColorFromRarity(quality) end if r then nameObj:SetTextColor(r, g, b) return end nameObj:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3]) end local function SetStatusBarState(bar, confirmed) if not bar then return end if confirmed then bar.sfConfirmed = true bar.sfElapsed = 0 SetRoundBackdrop(bar, T.statusConfirmBg, T.statusConfirmBd) if bar.sfGlow then bar.sfGlow:SetVertexColor(T.confirmOverlay[1], T.confirmOverlay[2], T.confirmOverlay[3], 1) bar.sfGlow:SetAlpha(0.35) end if bar.sfIcon then bar.sfIcon:SetText("|cff33ff55>>|r") bar.sfIcon:SetTextColor(0.3, 1, 0.4) end if bar.sfLabel then bar.sfLabel:SetText(L.CONFIRMED) bar.sfLabel:SetTextColor(T.confirmText[1], T.confirmText[2], T.confirmText[3]) end else bar.sfConfirmed = false SetRoundBackdrop(bar, T.statusWaitBg, T.statusWaitBd) if bar.sfGlow then bar.sfGlow:SetAlpha(0) end if bar.sfIcon then bar.sfIcon:SetText("...") bar.sfIcon:SetTextColor(T.statusWaitText[1], T.statusWaitText[2], T.statusWaitText[3]) end if bar.sfLabel then bar.sfLabel:SetText(L.WAITING) bar.sfLabel:SetTextColor(T.statusWaitText[1], T.statusWaitText[2], T.statusWaitText[3]) end end bar:Show() end local function UpdateConfirmStatus() if not TradeFrame then return end local playerConfirmed = TRADE_DATA.playerAccepted local targetConfirmed = TRADE_DATA.targetAccepted -- Status bars SetStatusBarState(TradeFrame.sfPlayerStatusBar, playerConfirmed) SetStatusBarState(TradeFrame.sfTargetStatusBar, targetConfirmed) -- Green overlays on item columns if TradeFrame.sfPlayerOverlay then if playerConfirmed then TradeFrame.sfPlayerOverlay:Show() else TradeFrame.sfPlayerOverlay:Hide() end end if TradeFrame.sfPlayerOverlayEnchant then if playerConfirmed then TradeFrame.sfPlayerOverlayEnchant:Show() else TradeFrame.sfPlayerOverlayEnchant:Hide() end end if TradeFrame.sfTargetOverlay then if targetConfirmed then TradeFrame.sfTargetOverlay:Show() else TradeFrame.sfTargetOverlay:Hide() end end if TradeFrame.sfTargetOverlayEnchant then if targetConfirmed then TradeFrame.sfTargetOverlayEnchant:Show() else TradeFrame.sfTargetOverlayEnchant:Hide() end end end local Hook_TradeFrame_Update = TradeFrame_Update function TradeFrame_Update() if Hook_TradeFrame_Update then Hook_TradeFrame_Update() end for i = 1, 7 do -- Re-hide Blizzard visuals (Blizzard code re-shows them every update) ReHideBlizzardSlot("TradePlayerItem", i) ReHideBlizzardSlot("TradeRecipientItem", i) -- Read from Blizzard API local pName, pTex, pNum, pQuality = GetTradePlayerItemInfo(i) local rName, rTex, rNum, rQuality = GetTradeTargetItemInfo(i) local pLink = GetTradePlayerItemLink(i) local rLink = GetTradeTargetItemLink and GetTradeTargetItemLink(i) if (not pTex or pTex == "") then local pIconObj = _G["TradePlayerItem" .. i .. "ItemButtonIconTexture"] if pIconObj and pIconObj.GetTexture then pTex = pIconObj:GetTexture() end end if (not rTex or rTex == "") then local rIconObj = _G["TradeRecipientItem" .. i .. "ItemButtonIconTexture"] if rIconObj and rIconObj.GetTexture then rTex = rIconObj:GetTexture() end end if (not pTex or pTex == "") and pLink and GetItemIcon then pTex = GetItemIcon(pLink) end if (not rTex or rTex == "") and rLink and GetItemIcon then rTex = GetItemIcon(rLink) end if (not pTex or pTex == "") and pName and GetItemInfo then local _, _, _, _, _, _, _, _, pInfoTex = GetItemInfo(pName) pTex = pInfoTex or pTex end if (not rTex or rTex == "") and rName and GetItemInfo then local _, _, _, _, _, _, _, _, rInfoTex = GetItemInfo(rName) rTex = rInfoTex or rTex end pQuality = ResolveTradeItemQuality(pLink, pQuality, pName) rQuality = ResolveTradeItemQuality(rLink, rQuality, rName) local pIlvl = (pTex or pName or pLink) and GetTradePlayerItemLevel(i) or nil local rIlvl = (rTex or rName or rLink) and GetTradeTargetItemLevel(i) or nil -- Write to custom sfSlot local pFrame = _G["TradePlayerItem" .. i] local rFrame = _G["TradeRecipientItem" .. i] if pFrame then UpdateSfSlot(pFrame.sfSlot, pTex, pNum, pLink, pIlvl, pQuality) end if rFrame then UpdateSfSlot(rFrame.sfSlot, rTex, rNum, rLink, rIlvl, rQuality) end UpdateSlotNameColor(_G["TradePlayerItem" .. i .. "Name"], pLink, pQuality) UpdateSlotNameColor(_G["TradeRecipientItem" .. i .. "Name"], rLink, rQuality) end UpdateConfirmStatus() end local Hook_MoneyFrame_Update = MoneyFrame_Update function MoneyFrame_Update(frameName, money) if Hook_MoneyFrame_Update then Hook_MoneyFrame_Update(frameName, money) end end