完成焦点等开发

This commit is contained in:
rucky
2026-03-31 18:03:23 +08:00
parent c7dd0f4848
commit 6e18269bfd
34 changed files with 6803 additions and 542 deletions

View File

@@ -70,7 +70,7 @@ local EQUIP_SLOTS_RIGHT = {
}
local EQUIP_SLOTS_BOTTOM = {
{ id = 16, name = "MainHandSlot" }, { id = 17, name = "SecondaryHandSlot" },
{ id = 18, name = "RangedSlot" }, { id = 0, name = "AmmoSlot" },
{ id = 18, name = "RangedSlot" }, { name = "AmmoSlot" },
}
local TAB_NAMES = { "装备", "声望", "技能", "荣誉" }
@@ -438,11 +438,15 @@ local TALENT_DB = {
meleeCrit = {
{ names = {"Cruelty", "残忍"}, perRank = 1 },
{ names = {"Malice", "恶意"}, perRank = 1 },
{ names = {"Lethal Shots", "致命射击"}, perRank = 1 },
{ names = {"Killer Instinct", "杀戮本能", "致命本能"}, perRank = 1 },
{ names = {"Conviction", "信念", "坚定信念"}, perRank = 1 },
{ names = {"Sharpened Claws", "利爪强化", "尖锐之爪"}, perRank = 2 },
{ names = {"Thundering Strikes", "雷霆一击", "雷霆之击"}, perRank = 1 },
},
rangedCrit = {
{ names = {"Lethal Shots", "夺命射击"}, perRank = 1 },
{ names = {"Killer Instinct", "杀戮本能", "致命本能"}, perRank = 1 },
},
spellCrit = {
{ names = {"Arcane Instability", "奥术不稳定"}, perRank = 1 },
{ names = {"Critical Mass", "临界质量"}, perRank = 2 },
@@ -458,7 +462,7 @@ local function ScanTalentBonuses()
if _talentCache and _talentCacheTime and (now - _talentCacheTime) < 5 then
return _talentCache
end
local r = { meleeHit = 0, spellHit = 0, meleeCrit = 0, spellCrit = 0,
local r = { meleeHit = 0, spellHit = 0, meleeCrit = 0, rangedCrit = 0, spellCrit = 0,
talentDetails = {} }
if not GetNumTalentTabs then _talentCache = r; _talentCacheTime = now; return r end
@@ -532,7 +536,7 @@ local function FullRangedCrit()
local _, agi = UnitStat("player", 2); agiCrit = (agi or 0) / ratio
end
local gearCrit = GetGearBonus("RANGEDCRIT") + GetGearBonus("CRIT")
local talentCrit = GetTalentBonus("meleeCrit")
local talentCrit = GetTalentBonus("rangedCrit")
return baseCrit + agiCrit + gearCrit + talentCrit,
baseCrit, agiCrit, gearCrit, talentCrit
end
@@ -1320,6 +1324,14 @@ function CP:BuildEquipmentPage()
if page.built then return end
page.built = true
-- Resolve AmmoSlot ID dynamically (may vary by client)
for _, si in ipairs(EQUIP_SLOTS_BOTTOM) do
if si.name == "AmmoSlot" and not si.id then
local slotId = GetInventorySlotInfo("AmmoSlot")
si.id = slotId or 0
end
end
local contentH = FRAME_H - (HEADER_H + TAB_BAR_H) - INNER_PAD - 4
local scrollArea = CreateScrollFrame(page, CONTENT_W, contentH)
scrollArea:SetPoint("TOPLEFT", page, "TOPLEFT", 0, 0)
@@ -1547,6 +1559,72 @@ function CP:BuildEquipmentPage()
end)
page.rotRight = rotRight
-- Gear action toolbar: small icon buttons next to model toolbar
local gearTbW = segW * 3 + 2
local gearToolbar = CreateFrame("Frame", nil, page)
gearToolbar:SetWidth(gearTbW)
gearToolbar:SetHeight(tbH)
gearToolbar:SetPoint("BOTTOM", modelBg, "BOTTOM", 0, 5 + tbH + 2)
gearToolbar:SetFrameLevel(page:GetFrameLevel() + 6)
SetPixelBackdrop(gearToolbar, { 0.04, 0.04, 0.06, 0.75 }, { 0.22, 0.22, 0.28, 0.5 })
page.gearToolbar = gearToolbar
local function MakeGearToolBtn(parent, w, text, ox, tooltip, onClick)
local btn = CreateFrame("Button", nil, parent)
btn:SetWidth(w)
btn:SetHeight(tbH - 2)
btn:SetPoint("LEFT", parent, "LEFT", ox, 0)
btn:SetFrameLevel(parent:GetFrameLevel() + 1)
btn:SetBackdrop({
bgFile = "Interface\\Buttons\\WHITE8X8",
tile = false, tileSize = 0, edgeSize = 0,
})
btn:SetBackdropColor(0, 0, 0, 0)
local fs = MakeFS(btn, 8, "CENTER", { 0.5, 0.5, 0.55 })
fs:SetPoint("CENTER", btn, "CENTER", 0, 0)
fs:SetText(text)
btn.label = fs
btn:SetScript("OnEnter", function()
this:SetBackdropColor(T.slotBg[1], T.slotBg[2], T.slotBg[3], T.slotBg[4] or 0.5)
this.label:SetTextColor(T.nameText[1], T.nameText[2], T.nameText[3])
if tooltip then
GameTooltip:SetOwner(this, "ANCHOR_BOTTOM")
GameTooltip:AddLine(tooltip, 1, 1, 1)
GameTooltip:Show()
end
end)
btn:SetScript("OnLeave", function()
this:SetBackdropColor(0, 0, 0, 0)
this.label:SetTextColor(T.dimText[1], T.dimText[2], T.dimText[3])
GameTooltip:Hide()
end)
btn:SetScript("OnClick", onClick)
return btn
end
local gStripBtn = MakeGearToolBtn(gearToolbar, segW, "", 1, "一键脱装", function() CP:StripAllGear() end)
page.gStripBtn = gStripBtn
local gSep1 = gearToolbar:CreateTexture(nil, "OVERLAY")
gSep1:SetTexture("Interface\\Buttons\\WHITE8X8")
gSep1:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4] or 0.4)
gSep1:SetWidth(1)
gSep1:SetHeight(tbH - 4)
gSep1:SetPoint("LEFT", gearToolbar, "LEFT", segW + 1, 0)
local gEquipBtn = MakeGearToolBtn(gearToolbar, segW, "穿", segW + 1, "一键穿装", function() CP:QuickEquipLastSet() end)
page.gEquipBtn = gEquipBtn
local gSep2 = gearToolbar:CreateTexture(nil, "OVERLAY")
gSep2:SetTexture("Interface\\Buttons\\WHITE8X8")
gSep2:SetVertexColor(T.sepColor[1], T.sepColor[2], T.sepColor[3], T.sepColor[4] or 0.4)
gSep2:SetWidth(1)
gSep2:SetHeight(tbH - 4)
gSep2:SetPoint("LEFT", gearToolbar, "LEFT", segW * 2 + 1, 0)
local gSetsBtn = MakeGearToolBtn(gearToolbar, segW, "", segW * 2 + 1, "装备方案管理", function() CP:ToggleGearSetPopup() end)
page.gSetsBtn = gSetsBtn
-- Equipment slots
local slotY = -6
page.equipSlots = {}
@@ -2064,7 +2142,7 @@ function CP:BuildEquipmentPage()
if gearC > 0 then CS.TipKV(" 装备暴击:", string.format("+%d%%", gearC)) end
if talC > 0 then
CS.TipKV(" 天赋暴击:", string.format("+%d%%", talC))
for _, d in ipairs(CS.GetTalentDetailsFor("meleeCrit")) do
for _, d in ipairs(CS.GetTalentDetailsFor("rangedCrit")) do
CS.TipLine(string.format(" %s (%d/%d) +%d%%",
d.name, d.rank, d.maxRank, d.bonus), 0.55,0.55,0.6)
end
@@ -2765,6 +2843,13 @@ function CP:CreateEquipSlot(parent, slotID, slotName)
ilvlText:SetText("")
frame.ilvlText = ilvlText
local durText = frame:CreateFontString(nil, "OVERLAY")
durText:SetFont(GetFont(), 7, "OUTLINE")
durText:SetPoint("TOPLEFT", frame, "TOPLEFT", 2, -2)
durText:SetTextColor(0.4, 1, 0.4)
durText:SetText("")
frame.durText = durText
local glow = frame:CreateTexture(nil, "OVERLAY")
glow:SetTexture("Interface\\Buttons\\UI-ActionButton-Border")
glow:SetBlendMode("ADD")
@@ -2822,7 +2907,7 @@ function CP:CreateEquipSlot(parent, slotID, slotName)
CP:ShowSwapPopup(this)
else
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
if GetInventoryItemLink("player", this.slotID) then
if GetInventoryItemLink("player", this.slotID) or GetInventoryItemTexture("player", this.slotID) then
GameTooltip:SetInventoryItem("player", this.slotID)
else
local label = SLOT_LABEL[this.slotName] or this.slotName
@@ -2926,6 +3011,34 @@ function CP:UpdateEquipment()
if slot then
local tex = GetInventoryItemTexture("player", si.id)
local link = GetInventoryItemLink("player", si.id)
-- Ammo slot special: try tooltip-based detection when texture/link fail
if not tex and si.name == "AmmoSlot" then
if not CP._ammoTip then
CP._ammoTip = CreateFrame("GameTooltip", "SFramesCPAmmoTip", UIParent, "GameTooltipTemplate")
CP._ammoTip:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -300, -300)
end
local tip = CP._ammoTip
tip:SetOwner(UIParent, "ANCHOR_NONE")
tip:ClearLines()
tip:SetInventoryItem("player", si.id)
local nLines = tip:NumLines() or 0
if nLines > 0 then
local txtObj = getglobal("SFramesCPAmmoTipTextLeft1")
if txtObj then
local ammoName = txtObj:GetText()
if ammoName and ammoName ~= "" then
-- Ammo is equipped but API can't return texture; use a generic icon
tex = "Interface\\Icons\\INV_Ammo_Arrow_02"
-- Try to get the real icon via GetItemInfo if available
if GetItemInfo then
local _, _, _, _, _, _, _, _, _, itemTex = GetItemInfo(ammoName)
if itemTex then tex = itemTex end
end
end
end
end
tip:Hide()
end
if tex then
slot.icon:SetTexture(tex)
slot.icon:SetVertexColor(1, 1, 1)
@@ -2939,6 +3052,54 @@ function CP:UpdateEquipment()
slot.ilvlText:SetText("")
end
end
-- Durability display (tooltip scan for 1.12 clients)
if slot.durText then
local dur, durMax
-- Try direct API first (pcall for safety)
if GetInventoryItemDurability then
local ok, c, m = pcall(GetInventoryItemDurability, si.id)
if ok then dur, durMax = c, m end
end
-- Fallback: scan tooltip
if not dur and link then
if not CP._durTip then
CP._durTip = CreateFrame("GameTooltip", "SFramesCPDurTip", UIParent, "GameTooltipTemplate")
CP._durTip:SetPoint("BOTTOMRIGHT", UIParent, "BOTTOMRIGHT", -300, -300)
end
local tip = CP._durTip
tip:SetOwner(UIParent, "ANCHOR_NONE")
tip:ClearLines()
tip:SetInventoryItem("player", si.id)
local nLines = tip:NumLines() or 0
for li = 1, nLines do
local txtObj = getglobal("SFramesCPDurTipTextLeft" .. li)
if txtObj then
local line = txtObj:GetText()
if line then
local _, _, c, m = string.find(line, "(%d+)%s*/%s*(%d+)")
if c and m then
dur, durMax = tonumber(c), tonumber(m)
break
end
end
end
end
tip:Hide()
end
if dur and durMax and durMax > 0 then
local pct = math.floor(dur / durMax * 100)
slot.durText:SetText(pct .. "%")
if pct <= 25 then
slot.durText:SetTextColor(1, 0.2, 0.2)
elseif pct <= 50 then
slot.durText:SetTextColor(1, 0.8, 0.2)
else
slot.durText:SetTextColor(0.4, 1, 0.4)
end
else
slot.durText:SetText("")
end
end
local quality = GetItemQualityFromLink(link)
if quality and quality >= 2 and QUALITY_COLORS[quality] then
local qc = QUALITY_COLORS[quality]
@@ -2960,6 +3121,7 @@ function CP:UpdateEquipment()
slot.currentBorderColor = nil
slot.qualGlow:Hide()
if slot.ilvlText then slot.ilvlText:SetText("") end
if slot.durText then slot.durText:SetText("") end
end
end
end
@@ -3848,6 +4010,430 @@ function CP:UpdatePet()
end
end
--------------------------------------------------------------------------------
-- Gear Set Management: Strip / Equip / Save / Load / Delete
--------------------------------------------------------------------------------
-- All equippable slot IDs (excluding shirt=4, tabard=19, ammo=0)
local GEAR_SLOT_IDS = { 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18 }
-- One-click strip: unequip all gear into bags
function CP:StripAllGear()
-- Save current gear as "_lastStripped" before stripping
self:SaveGearSetInternal("_lastStripped")
local count = 0
for _, sid in ipairs(GEAR_SLOT_IDS) do
if GetInventoryItemLink("player", sid) then
PickupInventoryItem(sid)
PutItemInBackpack()
count = count + 1
end
end
if count > 0 then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 已脱下 " .. count .. " 件装备")
else
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 当前没有可脱下的装备")
end
CP:ScheduleEquipUpdate()
end
-- Internal: save current gear to DB
function CP:SaveGearSetInternal(name)
if not SFramesDB then SFramesDB = {} end
if not SFramesDB.gearSets then SFramesDB.gearSets = {} end
local set = {}
for _, sid in ipairs(GEAR_SLOT_IDS) do
local link = GetInventoryItemLink("player", sid)
if link then
set[sid] = link
end
end
SFramesDB.gearSets[name] = set
end
-- Save gear set with user-provided name
function CP:SaveGearSet(name)
if not name or name == "" then return end
self:SaveGearSetInternal(name)
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 装备方案 |cffffd100" .. name .. "|r 已保存")
end
-- Load gear set by name
function CP:LoadGearSet(name)
if not SFramesDB or not SFramesDB.gearSets or not SFramesDB.gearSets[name] then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 找不到装备方案: " .. (name or "nil"))
return
end
local set = SFramesDB.gearSets[name]
local equipped = 0
-- Find item in bags by link matching (item:ID portion)
local function FindInBags(targetLink)
if not targetLink then return nil, nil end
local _, _, targetId = string.find(targetLink, "item:(%d+)")
if not targetId then return nil, nil end
for bag = 0, 4 do
local slots = GetContainerNumSlots(bag)
if slots and slots > 0 then
for slot = 1, slots do
local bagLink = GetContainerItemLink(bag, slot)
if bagLink then
local _, _, bagId = string.find(bagLink, "item:(%d+)")
if bagId == targetId then
return bag, slot
end
end
end
end
end
return nil, nil
end
for _, sid in ipairs(GEAR_SLOT_IDS) do
local targetLink = set[sid]
if targetLink then
-- Check if already wearing this item
local currentLink = GetInventoryItemLink("player", sid)
if currentLink then
local _, _, curId = string.find(currentLink, "item:(%d+)")
local _, _, tarId = string.find(targetLink, "item:(%d+)")
if curId == tarId then
-- Already wearing, skip
else
local bag, slot = FindInBags(targetLink)
if bag and slot then
PickupContainerItem(bag, slot)
PickupInventoryItem(sid)
equipped = equipped + 1
end
end
else
local bag, slot = FindInBags(targetLink)
if bag and slot then
PickupContainerItem(bag, slot)
PickupInventoryItem(sid)
equipped = equipped + 1
end
end
end
end
if equipped > 0 then
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 已装备 " .. equipped .. " 件 (方案: |cffffd100" .. name .. "|r)")
else
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 方案 |cffffd100" .. name .. "|r 中的装备已全部穿戴或不在背包中")
end
CP:ScheduleEquipUpdate()
end
-- Delete gear set
function CP:DeleteGearSet(name)
if not SFramesDB or not SFramesDB.gearSets then return end
SFramesDB.gearSets[name] = nil
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 装备方案 |cffffd100" .. name .. "|r 已删除")
end
-- Quick equip: load the "_lastStripped" auto-saved set
function CP:QuickEquipLastSet()
if SFramesDB and SFramesDB.gearSets and SFramesDB.gearSets["_lastStripped"] then
self:LoadGearSet("_lastStripped")
else
DEFAULT_CHAT_FRAME:AddMessage("|cff00ccff[Nanami-UI]|r 没有最近脱下的装备记录,请先使用一键脱装或保存方案")
end
end
-- Get sorted list of user-created gear set names
function CP:GetGearSetNames()
local names = {}
if SFramesDB and SFramesDB.gearSets then
for k, _ in pairs(SFramesDB.gearSets) do
if string.sub(k, 1, 1) ~= "_" then
table.insert(names, k)
end
end
end
table.sort(names)
return names
end
--------------------------------------------------------------------------------
-- Gear Set Popup UI
--------------------------------------------------------------------------------
local gearSetPopup
function CP:ToggleGearSetPopup()
if gearSetPopup and gearSetPopup:IsShown() then
gearSetPopup:Hide()
return
end
self:ShowGearSetPopup()
end
function CP:ShowGearSetPopup()
if not panel then return end
local POPUP_W = 200
local ROW_H = 20
local PAD = 6
if not gearSetPopup then
gearSetPopup = CreateFrame("Frame", "SFramesCPGearSetPopup", panel)
gearSetPopup:SetWidth(POPUP_W)
gearSetPopup:SetFrameStrata("TOOLTIP")
gearSetPopup:SetFrameLevel(200)
SetRoundBackdrop(gearSetPopup, T.bg, T.border)
gearSetPopup:Hide()
gearSetPopup:EnableMouse(true)
-- Title
local title = MakeFS(gearSetPopup, 10, "CENTER", T.gold)
title:SetPoint("TOP", gearSetPopup, "TOP", 0, -PAD)
title:SetText("装备方案管理")
gearSetPopup.title = title
-- Save current button
local saveBtn = CreateFrame("Button", NextName("GSave"), gearSetPopup)
saveBtn:SetWidth(POPUP_W - PAD * 2)
saveBtn:SetHeight(ROW_H)
saveBtn:SetPoint("TOP", gearSetPopup, "TOP", 0, -(PAD + 16))
SetPixelBackdrop(saveBtn, { 0.15, 0.35, 0.15, 0.8 }, T.tabBorder)
local saveTxt = MakeFS(saveBtn, 9, "CENTER", { 0.6, 1, 0.6 })
saveTxt:SetPoint("CENTER", saveBtn, "CENTER", 0, 0)
saveTxt:SetText("+ 保存当前装备为新方案")
saveBtn.label = saveTxt
saveBtn:SetScript("OnEnter", function()
this:SetBackdropColor(0.2, 0.45, 0.2, 0.9)
this.label:SetTextColor(0.8, 1, 0.8)
end)
saveBtn:SetScript("OnLeave", function()
this:SetBackdropColor(0.15, 0.35, 0.15, 0.8)
this.label:SetTextColor(0.6, 1, 0.6)
end)
saveBtn:SetScript("OnClick", function()
CP:ShowGearSetNameInput()
end)
gearSetPopup.saveBtn = saveBtn
gearSetPopup.rows = {}
end
-- Rebuild set list
local names = self:GetGearSetNames()
local numSets = table.getn(names)
-- Hide old rows
for _, row in ipairs(gearSetPopup.rows) do
row:Hide()
end
local contentTop = -(PAD + 16 + ROW_H + 4)
for i = 1, numSets do
local row = gearSetPopup.rows[i]
if not row then
row = CreateFrame("Frame", nil, gearSetPopup)
row:SetWidth(POPUP_W - PAD * 2)
row:SetHeight(ROW_H)
local bg = row:CreateTexture(nil, "BACKGROUND")
bg:SetTexture("Interface\\Buttons\\WHITE8X8")
bg:SetVertexColor(0.12, 0.12, 0.16, 0.6)
bg:SetAllPoints(row)
row.bg = bg
local nameText = MakeFS(row, 9, "LEFT", T.nameText)
nameText:SetPoint("LEFT", row, "LEFT", 6, 0)
nameText:SetWidth(POPUP_W - PAD * 2 - 60)
row.nameText = nameText
-- Load button
local loadBtn = CreateFrame("Button", nil, row)
loadBtn:SetWidth(24)
loadBtn:SetHeight(ROW_H - 4)
loadBtn:SetPoint("RIGHT", row, "RIGHT", -28, 0)
loadBtn:SetFrameLevel(row:GetFrameLevel() + 1)
SetPixelBackdrop(loadBtn, T.tabBg, T.tabBorder)
local loadTxt = MakeFS(loadBtn, 8, "CENTER", { 0.5, 0.8, 1 })
loadTxt:SetPoint("CENTER", loadBtn, "CENTER", 0, 0)
loadTxt:SetText("穿")
loadBtn.label = loadTxt
loadBtn:SetScript("OnEnter", function()
this:SetBackdropColor(T.tabActiveBg[1], T.tabActiveBg[2], T.tabActiveBg[3], 0.7)
this.label:SetTextColor(0.7, 0.95, 1)
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:AddLine("加载此方案", 1, 1, 1)
GameTooltip:Show()
end)
loadBtn:SetScript("OnLeave", function()
this:SetBackdropColor(T.tabBg[1], T.tabBg[2], T.tabBg[3], T.tabBg[4])
this.label:SetTextColor(0.5, 0.8, 1)
GameTooltip:Hide()
end)
row.loadBtn = loadBtn
-- Delete button
local delBtn = CreateFrame("Button", nil, row)
delBtn:SetWidth(24)
delBtn:SetHeight(ROW_H - 4)
delBtn:SetPoint("RIGHT", row, "RIGHT", -2, 0)
delBtn:SetFrameLevel(row:GetFrameLevel() + 1)
SetPixelBackdrop(delBtn, { 0.35, 0.12, 0.12, 0.8 }, T.tabBorder)
local delTxt = MakeFS(delBtn, 8, "CENTER", { 1, 0.5, 0.5 })
delTxt:SetPoint("CENTER", delBtn, "CENTER", 0, 0)
delTxt:SetText("X")
delBtn.label = delTxt
delBtn:SetScript("OnEnter", function()
this:SetBackdropColor(0.5, 0.15, 0.15, 0.9)
this.label:SetTextColor(1, 0.7, 0.7)
GameTooltip:SetOwner(this, "ANCHOR_RIGHT")
GameTooltip:AddLine("删除此方案", 1, 0.3, 0.3)
GameTooltip:Show()
end)
delBtn:SetScript("OnLeave", function()
this:SetBackdropColor(0.35, 0.12, 0.12, 0.8)
this.label:SetTextColor(1, 0.5, 0.5)
GameTooltip:Hide()
end)
row.delBtn = delBtn
gearSetPopup.rows[i] = row
end
row:SetPoint("TOPLEFT", gearSetPopup, "TOPLEFT", PAD, contentTop - (i - 1) * (ROW_H + 2))
row.nameText:SetText(names[i])
row.setName = names[i]
row.loadBtn:SetScript("OnClick", function()
CP:LoadGearSet(this:GetParent().setName)
gearSetPopup:Hide()
end)
row.delBtn:SetScript("OnClick", function()
CP:DeleteGearSet(this:GetParent().setName)
CP:ShowGearSetPopup()
end)
row:Show()
end
-- Hide extra rows
for i = numSets + 1, table.getn(gearSetPopup.rows) do
gearSetPopup.rows[i]:Hide()
end
local totalH = PAD + 16 + ROW_H + 4 + numSets * (ROW_H + 2) + PAD
if totalH < 70 then totalH = 70 end
gearSetPopup:SetHeight(totalH)
-- Position popup to the right of the panel
gearSetPopup:ClearAllPoints()
gearSetPopup:SetPoint("TOPLEFT", panel, "TOPRIGHT", 4, 0)
gearSetPopup:Show()
end
--------------------------------------------------------------------------------
-- Gear Set Name Input Dialog
--------------------------------------------------------------------------------
local gearSetNameInput
function CP:ShowGearSetNameInput()
if not panel then return end
if not gearSetNameInput then
local f = CreateFrame("Frame", "SFramesCPGearSetNameInput", UIParent)
f:SetWidth(240)
f:SetHeight(90)
f:SetPoint("CENTER", UIParent, "CENTER", 0, 100)
f:SetFrameStrata("DIALOG")
f:SetFrameLevel(250)
SetRoundBackdrop(f, T.bg, T.border)
f:EnableMouse(true)
f:SetMovable(true)
f:RegisterForDrag("LeftButton")
f:SetScript("OnDragStart", function() this:StartMoving() end)
f:SetScript("OnDragStop", function() this:StopMovingOrSizing() end)
f:Hide()
local title = MakeFS(f, 10, "CENTER", T.gold)
title:SetPoint("TOP", f, "TOP", 0, -8)
title:SetText("输入方案名称")
local editBox = CreateFrame("EditBox", "SFramesCPGearSetEditBox", f)
editBox:SetWidth(200)
editBox:SetHeight(22)
editBox:SetPoint("TOP", f, "TOP", 0, -28)
editBox:SetFontObject(ChatFontNormal)
editBox:SetAutoFocus(true)
editBox:SetMaxLetters(30)
SetPixelBackdrop(editBox, { 0.08, 0.08, 0.1, 0.9 }, T.tabBorder)
editBox:SetTextInsets(6, 6, 2, 2)
f.editBox = editBox
local okBtn = CreateFrame("Button", nil, f)
okBtn:SetWidth(80)
okBtn:SetHeight(20)
okBtn:SetPoint("BOTTOMLEFT", f, "BOTTOMLEFT", 20, 8)
SetPixelBackdrop(okBtn, { 0.15, 0.35, 0.15, 0.8 }, T.tabBorder)
local okTxt = MakeFS(okBtn, 9, "CENTER", { 0.6, 1, 0.6 })
okTxt:SetPoint("CENTER", okBtn, "CENTER", 0, 0)
okTxt:SetText("保存")
okBtn:SetScript("OnEnter", function()
this:SetBackdropColor(0.2, 0.45, 0.2, 0.9)
end)
okBtn:SetScript("OnLeave", function()
this:SetBackdropColor(0.15, 0.35, 0.15, 0.8)
end)
okBtn:SetScript("OnClick", function()
local name = f.editBox:GetText()
if name and name ~= "" then
CP:SaveGearSet(name)
f:Hide()
if gearSetPopup and gearSetPopup:IsShown() then
CP:ShowGearSetPopup()
end
end
end)
f.okBtn = okBtn
local cancelBtn = CreateFrame("Button", nil, f)
cancelBtn:SetWidth(80)
cancelBtn:SetHeight(20)
cancelBtn:SetPoint("BOTTOMRIGHT", f, "BOTTOMRIGHT", -20, 8)
SetPixelBackdrop(cancelBtn, { 0.35, 0.12, 0.12, 0.8 }, T.tabBorder)
local cancelTxt = MakeFS(cancelBtn, 9, "CENTER", { 1, 0.6, 0.6 })
cancelTxt:SetPoint("CENTER", cancelBtn, "CENTER", 0, 0)
cancelTxt:SetText("取消")
cancelBtn:SetScript("OnEnter", function()
this:SetBackdropColor(0.45, 0.15, 0.15, 0.9)
end)
cancelBtn:SetScript("OnLeave", function()
this:SetBackdropColor(0.35, 0.12, 0.12, 0.8)
end)
cancelBtn:SetScript("OnClick", function()
f:Hide()
end)
f.cancelBtn = cancelBtn
editBox:SetScript("OnEnterPressed", function()
local name = this:GetText()
if name and name ~= "" then
CP:SaveGearSet(name)
f:Hide()
if gearSetPopup and gearSetPopup:IsShown() then
CP:ShowGearSetPopup()
end
end
end)
editBox:SetScript("OnEscapePressed", function()
f:Hide()
end)
gearSetNameInput = f
end
gearSetNameInput.editBox:SetText("")
gearSetNameInput:Show()
gearSetNameInput.editBox:SetFocus()
end
--------------------------------------------------------------------------------
-- Events
--------------------------------------------------------------------------------