806 lines
34 KiB
Lua
806 lines
34 KiB
Lua
-- Freewood-OctoWoW-Codex: Namen von Hand eintragen (Deutsch / Englisch)
|
|
-- Zwei Fenster im Tab "Datenbank":
|
|
-- "Name bearbeiten" fuer den gewaehlten Eintrag (Kreatur, Objekt, Quest, Item), mit Vorschlaegen aus dem Kampflog
|
|
-- "Namen einfuegen" mehrere Zeilen "ID Name" auf einmal fuer die aktuelle Liste
|
|
|
|
local ADDON, NS = ...
|
|
|
|
local FW = _G.Freewood
|
|
local Codex = NS and NS.Codex
|
|
if not FW or not Codex or not FW.UI then
|
|
return
|
|
end
|
|
|
|
local UI = FW.UI
|
|
local Util = FW.Util
|
|
|
|
local NameUI = {}
|
|
NS.NameUI = NameUI
|
|
Codex.NameUI = NameUI
|
|
|
|
local EDITABLE = { units = true, objects = true, quests = true, items = true }
|
|
local KIND_LABEL = { units = "CODEX_KIND_UNITS", objects = "CODEX_KIND_OBJECTS", quests = "CODEX_KIND_QUESTS", items = "CODEX_KIND_ITEMS" }
|
|
local MAX_SUGGEST = 6
|
|
|
|
local function MakeInput(parent, width)
|
|
local box = UI.CreatePanel(parent, "bgDeep", "bronze")
|
|
box:SetSize(width, 26)
|
|
local edit = CreateFrame("EditBox", nil, box)
|
|
edit:SetAutoFocus(false)
|
|
edit:SetPoint("TOPLEFT", box, "TOPLEFT", 8, -2)
|
|
edit:SetPoint("BOTTOMRIGHT", box, "BOTTOMRIGHT", -8, 2)
|
|
edit:SetMaxLetters(100)
|
|
if not edit:SetFont(UI.GetFontPath("body"), 12, "") then
|
|
edit:SetFont("Fonts\\FRIZQT__.TTF", 12, "")
|
|
end
|
|
edit:SetTextColor(UI.Color("text"))
|
|
edit:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
|
|
box.edit = edit
|
|
return box
|
|
end
|
|
|
|
-- Wowhead-Adresse fuer Nachschlagen (an einer Stelle, falls sich die Domain aendert)
|
|
local WOWHEAD_BASE = "https://www.wowhead.com/forever/"
|
|
local WOWHEAD_PATH = { units = "npc", objects = "object", quests = "quest", items = "item" }
|
|
function NameUI.LookupURL(kind, id, lang)
|
|
local path = WOWHEAD_PATH[kind]
|
|
if not path or not id then return nil end
|
|
return WOWHEAD_BASE .. (lang == "de" and "de/" or "") .. path .. "=" .. tostring(id)
|
|
end
|
|
|
|
-- Schreibgeschuetztes Feld: Klick markiert alles, dann Strg+C
|
|
local function MakeLink(parent, width)
|
|
local box = MakeInput(parent, width)
|
|
box:SetHeight(22)
|
|
local edit = box.edit
|
|
edit:SetMaxLetters(0)
|
|
edit:SetTextColor(UI.Color("goldLight"))
|
|
local function Select(self) self:HighlightText() end
|
|
edit:SetScript("OnEditFocusGained", Select)
|
|
edit:SetScript("OnMouseUp", function(self) self:SetFocus(); self:HighlightText() end)
|
|
edit:SetScript("OnTextChanged", function(self, user)
|
|
if user and box.fwUrl and self:GetText() ~= box.fwUrl then
|
|
self:SetText(box.fwUrl)
|
|
self:HighlightText()
|
|
end
|
|
end)
|
|
function box.SetURL(url)
|
|
box.fwUrl = url or ""
|
|
edit:SetText(url or "")
|
|
edit:SetCursorPosition(0)
|
|
end
|
|
return box
|
|
end
|
|
|
|
local function MakeWindow(parent, width, height)
|
|
local w = UI.CreatePanel(parent, "bg", "gold")
|
|
w:SetSize(width, height)
|
|
w:SetPoint("CENTER", parent, "CENTER", 0, 0)
|
|
w:SetFrameStrata("DIALOG")
|
|
w:EnableMouse(true)
|
|
w:Hide()
|
|
return w
|
|
end
|
|
|
|
local function GameName(kind, id)
|
|
local v = Codex.V()
|
|
if kind == "units" then
|
|
local e = v.units[id]
|
|
return e and e.n
|
|
elseif kind == "objects" then
|
|
local e = v.objects[id]
|
|
return e and e.n
|
|
elseif kind == "quests" then
|
|
local q = v.quests[id]
|
|
return q and q.t
|
|
end
|
|
local info = Util.GetItem and Util.GetItem(id)
|
|
return (info and info.name) or Codex.db.names[id]
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Fenster "Name bearbeiten"
|
|
------------------------------------------------------------------------
|
|
|
|
local function BuildEdit(parent, onChanged)
|
|
local L = FW.L
|
|
local win = MakeWindow(parent, 480, 520)
|
|
local state = {}
|
|
|
|
local title = UI.CreateLabel(win, "", { font = "heading", size = 14, color = "goldLight" })
|
|
title:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -14)
|
|
local game = UI.CreateLabel(win, "", { size = 11, color = "textDim" })
|
|
game:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -40)
|
|
game:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -40)
|
|
game:SetWordWrap(false)
|
|
|
|
local deLabel = UI.CreateLabel(win, L.CODEX_NAME_DE, { size = 12 })
|
|
deLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -68)
|
|
local deBox = MakeInput(win, 448)
|
|
deBox:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -86)
|
|
local deLink = MakeLink(win, 448)
|
|
deLink:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -114)
|
|
local enLabel = UI.CreateLabel(win, L.CODEX_NAME_EN, { size = 12 })
|
|
enLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -146)
|
|
local enBox = MakeInput(win, 448)
|
|
enBox:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -164)
|
|
local enLink = MakeLink(win, 448)
|
|
enLink:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -192)
|
|
|
|
local hint = UI.CreateLabel(win, "", { size = 11, color = "textDim", justifyV = "TOP" })
|
|
hint:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -222)
|
|
hint:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -222)
|
|
hint:SetHeight(32)
|
|
hint:SetWordWrap(true)
|
|
|
|
local sugTitle = UI.CreateLabel(win, L.CODEX_NAME_KILLS, { size = 12, color = "goldLight" })
|
|
sugTitle:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -260)
|
|
local sugNone = UI.CreateLabel(win, L.CODEX_NAME_NOKILLS, { size = 11, color = "textDim", justifyV = "TOP" })
|
|
sugNone:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -284)
|
|
sugNone:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -284)
|
|
sugNone:SetHeight(32)
|
|
sugNone:SetWordWrap(true)
|
|
|
|
local function Fill(text)
|
|
local box = Codex.Lang() == "en" and enBox or deBox
|
|
box.edit:SetText(text or "")
|
|
box.edit:SetFocus()
|
|
end
|
|
local sugButtons = {}
|
|
for i = 1, MAX_SUGGEST do
|
|
local b = UI.CreateButton(win, "", 448, 24, function(self)
|
|
if self.fwText then Fill(self.fwText) end
|
|
end, "default")
|
|
b:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -284 - (i - 1) * 28)
|
|
b:Hide()
|
|
sugButtons[i] = b
|
|
end
|
|
|
|
local function Save()
|
|
if state.kind and state.id then
|
|
Codex:SetCustom(state.kind, state.id, deBox.edit:GetText(), enBox.edit:GetText())
|
|
if onChanged then onChanged() end
|
|
end
|
|
win:Hide()
|
|
end
|
|
local save = UI.CreateButton(win, L.CODEX_NAME_SAVE, 140, 28, Save, "primary")
|
|
save:SetPoint("BOTTOMLEFT", win, "BOTTOMLEFT", 16, 14)
|
|
local clear = UI.CreateButton(win, L.CODEX_NAME_CLEAR, 140, 28, function()
|
|
deBox.edit:SetText("")
|
|
enBox.edit:SetText("")
|
|
Save()
|
|
end, "default")
|
|
clear:SetPoint("LEFT", save, "RIGHT", 8, 0)
|
|
local cancel = UI.CreateButton(win, L.CODEX_NAME_CANCEL, 140, 28, function() win:Hide() end, "default")
|
|
cancel:SetPoint("LEFT", clear, "RIGHT", 8, 0)
|
|
|
|
function win.Open(kind, id)
|
|
state.kind, state.id = kind, id
|
|
local label = L[KIND_LABEL[kind]] or kind
|
|
title:SetText(string.format("%s #%s", label, tostring(id)))
|
|
local gn = GameName(kind, id)
|
|
game:SetText(gn and string.format(L.CODEX_NAME_GAME, gn) or "")
|
|
local de, en = Codex:GetCustom(kind, id)
|
|
deBox.edit:SetText(de or "")
|
|
enBox.edit:SetText(en or "")
|
|
hint:SetText((kind == "items" and L.CODEX_NAME_HINT_LOCAL or L.CODEX_NAME_HINT) .. "\n" .. (L.CODEX_NAME_LINK or ""))
|
|
deLink.SetURL(NameUI.LookupURL(kind, id, "de"))
|
|
enLink.SetURL(NameUI.LookupURL(kind, id, "en"))
|
|
local names = {}
|
|
if kind == "units" and Codex.Names and Codex.Names.RecentKills then
|
|
for _, k in ipairs(Codex.Names:RecentKills(900, MAX_SUGGEST)) do
|
|
names[#names + 1] = k.name
|
|
if k.alt then names[#names + 1] = k.alt end
|
|
end
|
|
end
|
|
local showSug = kind == "units"
|
|
if showSug then sugTitle:Show() else sugTitle:Hide() end
|
|
if showSug and #names == 0 then sugNone:Show() else sugNone:Hide() end
|
|
for i, b in ipairs(sugButtons) do
|
|
local text = names[i]
|
|
if text then
|
|
b.fwText = text
|
|
b:SetLabel(text)
|
|
b:Show()
|
|
else
|
|
b.fwText = nil
|
|
b:Hide()
|
|
end
|
|
end
|
|
win.fwKey = kind .. ":" .. tostring(id)
|
|
win:Show()
|
|
win:Raise()
|
|
end
|
|
return win
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Fenster "Eigenschaften bearbeiten": Zone(n), Dungeon, Klasse, Stufen
|
|
-- (Blizzard liefert aus Instanzen keine Orte und oft keine Klasse; hier koennen Berechtigte sie nachtragen)
|
|
------------------------------------------------------------------------
|
|
|
|
local mapIndex
|
|
|
|
-- Alle Karten des Spiels (Name -> ID), einmal gelesen
|
|
local function MapIndex()
|
|
if mapIndex then return mapIndex end
|
|
mapIndex = {}
|
|
if C_Map and C_Map.GetMapInfo then
|
|
for id = 1, 3000 do
|
|
local ok, info = pcall(C_Map.GetMapInfo, id)
|
|
if ok and type(info) == "table" and type(info.name) == "string" and info.name ~= "" then
|
|
mapIndex[#mapIndex + 1] = { id = id, name = info.name, lower = info.name:lower() }
|
|
end
|
|
end
|
|
end
|
|
return mapIndex
|
|
end
|
|
|
|
-- Karten, deren Name den Text enthaelt (oder deren ID passt). Rueckgabe: Liste { id, name }
|
|
function NameUI.FindMaps(text, limit)
|
|
local out = {}
|
|
text = type(text) == "string" and text:lower():gsub("^%s+", ""):gsub("%s+$", "") or ""
|
|
if text == "" then return out end
|
|
local num = tonumber(text)
|
|
if num and num >= 1 and num == math.floor(num) then
|
|
out[1] = { id = num, name = Codex.MapName(num) }
|
|
end
|
|
-- eingebaute Instanzen (Dungeons, Schlachtfelder): negative ID
|
|
local ids = {}
|
|
for id in pairs(Codex.INSTANCES) do ids[#ids + 1] = id end
|
|
table.sort(ids)
|
|
for _, id in ipairs(ids) do
|
|
if #out >= (limit or 6) then break end
|
|
local b = Codex.INSTANCES[id]
|
|
if b[1]:lower():find(text, 1, true) or b[2]:lower():find(text, 1, true) then
|
|
out[#out + 1] = { id = -id, name = Codex.InstanceName(id) }
|
|
end
|
|
end
|
|
for _, m in ipairs(MapIndex()) do
|
|
if #out >= (limit or 6) then break end
|
|
if m.lower:find(text, 1, true) and m.id ~= num then
|
|
out[#out + 1] = { id = m.id, name = m.name }
|
|
end
|
|
end
|
|
return out
|
|
end
|
|
|
|
local CLASS_CYCLE = { false, "normal", "elite", "rare", "rareelite", "worldboss" }
|
|
|
|
local function ClassLabel(cl)
|
|
local L = FW.L
|
|
if not cl then return L.CODEX_PROPS_AUTO end
|
|
return L["CODEX_PROPS_CLASS_" .. cl] or cl
|
|
end
|
|
|
|
local function BuildProps(parent, onChanged)
|
|
local L = FW.L
|
|
local win = MakeWindow(parent, 520, 650)
|
|
local state = { z = {} }
|
|
local MAXZ = Codex.MAX_ED_ZONES
|
|
|
|
local title = UI.CreateLabel(win, "", { font = "heading", size = 14, color = "goldLight" })
|
|
title:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -14)
|
|
local game = UI.CreateLabel(win, "", { size = 11, color = "textDim" })
|
|
game:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -40)
|
|
game:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -40)
|
|
game:SetWordWrap(false)
|
|
|
|
-- Zonen
|
|
local zoneTitle = UI.CreateLabel(win, L.CODEX_PROPS_ZONES, { size = 12, color = "goldLight" })
|
|
zoneTitle:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -68)
|
|
local zoneRows = {}
|
|
for i = 1, MAXZ do local i = i
|
|
local lbl = UI.CreateLabel(win, "", { size = 12 })
|
|
lbl:SetPoint("TOPLEFT", win, "TOPLEFT", 24, -92 - (i - 1) * 24)
|
|
lbl:SetWidth(400)
|
|
lbl:SetWordWrap(false)
|
|
local rm = UI.CreateButton(win, "x", 24, 20, function()
|
|
table.remove(state.z, i)
|
|
win.Refresh()
|
|
end, "default")
|
|
rm:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -90 - (i - 1) * 24)
|
|
zoneRows[i] = { lbl = lbl, rm = rm }
|
|
end
|
|
local zoneNone = UI.CreateLabel(win, L.CODEX_PROPS_ZONES_NONE, { size = 11, color = "textDim" })
|
|
zoneNone:SetPoint("TOPLEFT", win, "TOPLEFT", 24, -92)
|
|
|
|
local zoneInput = MakeInput(win, 300)
|
|
zoneInput:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -92 - MAXZ * 24 - 8)
|
|
local sugBtns = {}
|
|
local function AddZone(id)
|
|
if id and #state.z < MAXZ then
|
|
for _, z in ipairs(state.z) do if z == id then return end end
|
|
state.z[#state.z + 1] = id
|
|
end
|
|
zoneInput.edit:SetText("")
|
|
win.Refresh()
|
|
end
|
|
local function Suggest()
|
|
local found = NameUI.FindMaps(zoneInput.edit:GetText(), #sugBtns)
|
|
for i, b in ipairs(sugBtns) do
|
|
local m = found[i]
|
|
if m then
|
|
b.fwId = m.id
|
|
b:SetLabel(string.format("%s (#%d)", m.name, m.id < 0 and -m.id or m.id))
|
|
b:Show()
|
|
else
|
|
b.fwId = nil
|
|
b:Hide()
|
|
end
|
|
end
|
|
end
|
|
zoneInput.edit:SetScript("OnTextChanged", function(_, user) if user then Suggest() end end)
|
|
local here = UI.CreateButton(win, L.CODEX_PROPS_HERE, 170, 26, function()
|
|
local inst = Codex.CurrentInstance and Codex.CurrentInstance()
|
|
if inst then
|
|
AddZone(-inst)
|
|
return
|
|
end
|
|
local m = C_Map and C_Map.GetBestMapForUnit and C_Map.GetBestMapForUnit("player")
|
|
if m then AddZone(m) end
|
|
end, "default")
|
|
here:SetPoint("LEFT", zoneInput, "RIGHT", 8, 0)
|
|
for i = 1, 5 do
|
|
local b = UI.CreateButton(win, "", 488, 22, function(self)
|
|
if self.fwId then AddZone(self.fwId) end
|
|
end, "default")
|
|
b:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -92 - MAXZ * 24 - 40 - (i - 1) * 24)
|
|
b:Hide()
|
|
sugBtns[i] = b
|
|
end
|
|
local zoneHint = UI.CreateLabel(win, L.CODEX_PROPS_ZONE_HINT, { size = 11, color = "textDim", justifyV = "TOP" })
|
|
zoneHint:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -92 - MAXZ * 24 - 40 - 5 * 24 - 2)
|
|
zoneHint:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -92 - MAXZ * 24 - 40 - 5 * 24 - 2)
|
|
zoneHint:SetHeight(30)
|
|
zoneHint:SetWordWrap(true)
|
|
|
|
-- Dungeon / Klasse / Stufen
|
|
local baseY = 92 + MAXZ * 24 + 40 + 5 * 24 + 36
|
|
local dgLabel = UI.CreateLabel(win, L.CODEX_PROPS_DUNGEON, { size = 12 })
|
|
dgLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - 4)
|
|
local dgBtn = UI.CreateButton(win, "", 200, 24, function()
|
|
if state.dg == nil then state.dg = true elseif state.dg == true then state.dg = false else state.dg = nil end
|
|
win.Refresh()
|
|
end, "default")
|
|
dgBtn:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY)
|
|
local clLabel = UI.CreateLabel(win, L.CODEX_PROPS_CLASS, { size = 12 })
|
|
clLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - 36)
|
|
local clBtn = UI.CreateButton(win, "", 200, 24, function()
|
|
local idx = 1
|
|
for i, c in ipairs(CLASS_CYCLE) do if c == (state.cl or false) then idx = i end end
|
|
state.cl = CLASS_CYCLE[idx % #CLASS_CYCLE + 1] or nil
|
|
if state.cl == false then state.cl = nil end
|
|
win.Refresh()
|
|
end, "default")
|
|
clBtn:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY - 32)
|
|
local lvLabel = UI.CreateLabel(win, L.CODEX_PROPS_LEVELS, { size = 12 })
|
|
lvLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - 72)
|
|
local l1Box = MakeInput(win, 70)
|
|
l1Box:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY - 68)
|
|
l1Box.edit:SetMaxLetters(3)
|
|
local lvDash = UI.CreateLabel(win, "-", { size = 12 })
|
|
lvDash:SetPoint("LEFT", l1Box, "RIGHT", 6, 0)
|
|
local l2Box = MakeInput(win, 70)
|
|
l2Box:SetPoint("LEFT", l1Box, "RIGHT", 20, 0)
|
|
l2Box.edit:SetMaxLetters(3)
|
|
-- Quests: Vorquests (an der Stelle der Stufen)
|
|
local preLabel = UI.CreateLabel(win, L.CODEX_PROPS_PRE, { size = 12 })
|
|
preLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - 72)
|
|
local preBox = MakeInput(win, 300)
|
|
preBox:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY - 68)
|
|
preBox.edit:SetMaxLetters(60)
|
|
|
|
-- Quests: Folgequests, davor, danach, Stufe, Questtext (Dev)
|
|
local QROW = { nx = 36, bf = 108, af = 140, ql = 172, tx = 204, si = 236 }
|
|
local qLabels, qBoxes = {}, {}
|
|
local function QField(key, label, width, letters, y)
|
|
local lbl = UI.CreateLabel(win, label, { size = 12 })
|
|
lbl:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - y - 4)
|
|
local box = MakeInput(win, width)
|
|
box:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY - y)
|
|
box.edit:SetMaxLetters(letters)
|
|
qLabels[key], qBoxes[key] = lbl, box
|
|
end
|
|
QField("nx", L.CODEX_PROPS_NEXT, 300, 60, QROW.nx)
|
|
QField("bf", L.CODEX_PROPS_BEFORE, 300, 60, QROW.bf)
|
|
QField("af", L.CODEX_PROPS_AFTER, 300, 60, QROW.af)
|
|
QField("ql", L.CODEX_PROPS_QLEVEL, 70, 3, QROW.ql)
|
|
QField("tx", L.CODEX_PROPS_TEXT, 300, 600, QROW.tx)
|
|
QField("si", L.CODEX_PROPS_STARTITEM, 120, 9, QROW.si)
|
|
|
|
-- Kreaturen und Objekte: Quest-Zuordnung von Hand (Ziel von Quests, laesst Quest-Items fallen)
|
|
local uLabels, uBoxes = {}, {}
|
|
local function UField(key, label, width, letters, y)
|
|
local lbl = UI.CreateLabel(win, label, { size = 12 })
|
|
lbl:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - y - 4)
|
|
local box = MakeInput(win, width)
|
|
box:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY - y)
|
|
box.edit:SetMaxLetters(letters)
|
|
uLabels[key], uBoxes[key] = lbl, box
|
|
end
|
|
UField("qk", L.CODEX_PROPS_QK, 300, 80, 108)
|
|
UField("qd", L.CODEX_PROPS_QD, 300, 120, 140)
|
|
UField("qb", L.CODEX_PROPS_QB, 300, 80, 172)
|
|
QField("qr", L.CODEX_PROPS_QR, 300, 200, 268)
|
|
|
|
local hint = UI.CreateLabel(win, L.CODEX_PROPS_HINT, { size = 11, color = "textDim", justifyV = "TOP" })
|
|
hint:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - 104)
|
|
hint:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -baseY - 104)
|
|
hint:SetHeight(58)
|
|
hint:SetWordWrap(true)
|
|
|
|
function win.Refresh()
|
|
for i = 1, MAXZ do
|
|
local row = zoneRows[i]
|
|
local id = state.z[i]
|
|
if id then
|
|
row.lbl:SetText(string.format("%s |cff9a978c#%d|r", Codex.MapName(id), id < 0 and -id or id))
|
|
row.lbl:Show()
|
|
row.rm:Show()
|
|
else
|
|
row.lbl:Hide()
|
|
row.rm:Hide()
|
|
end
|
|
end
|
|
if #state.z == 0 then zoneNone:Show() else zoneNone:Hide() end
|
|
dgBtn:SetLabel(state.dg == nil and L.CODEX_PROPS_UNKNOWN or (state.dg and L.CODEX_PROPS_YES or L.CODEX_PROPS_NO))
|
|
local isUnit = state.kind == "units"
|
|
local hasDungeon = state.kind ~= nil
|
|
if hasDungeon then dgLabel:Show(); dgBtn:Show() end
|
|
if isUnit then
|
|
clLabel:Show(); clBtn:Show(); lvLabel:Show(); l1Box:Show(); l2Box:Show(); lvDash:Show()
|
|
clBtn:SetLabel(ClassLabel(state.cl))
|
|
else
|
|
clLabel:Hide(); clBtn:Hide(); lvLabel:Hide(); l1Box:Hide(); l2Box:Hide(); lvDash:Hide()
|
|
end
|
|
if state.kind == "quests" or state.kind == "items" then
|
|
preLabel:SetText(state.kind == "items" and L.CODEX_PROPS_KEY or L.CODEX_PROPS_PRE)
|
|
preLabel:Show(); preBox:Show()
|
|
else
|
|
preLabel:Hide(); preBox:Hide()
|
|
end
|
|
local isQuest = state.kind == "quests"
|
|
for key, lbl in pairs(qLabels) do
|
|
if isQuest then lbl:Show(); qBoxes[key]:Show() else lbl:Hide(); qBoxes[key]:Hide() end
|
|
end
|
|
local isEnt = state.kind == "units" or state.kind == "objects"
|
|
local isItem = state.kind == "items"
|
|
for key, lbl in pairs(uLabels) do
|
|
local show = isEnt or (isItem and key == "qb")
|
|
if show then lbl:Show(); uBoxes[key]:Show() else lbl:Hide(); uBoxes[key]:Hide() end
|
|
end
|
|
-- bei Items steht "Gehoert zu Quest" direkt unter dem Schluessel-Feld
|
|
local qbY = isItem and 108 or 172
|
|
uLabels.qb:ClearAllPoints()
|
|
uLabels.qb:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - qbY - 4)
|
|
uBoxes.qb:ClearAllPoints()
|
|
uBoxes.qb:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -baseY - qbY)
|
|
-- fuer Quests (und Kreaturen/Objekte mit Quest-Zeilen) ist das Fenster hoeher, der Hinweis rutscht nach unten
|
|
win:SetHeight(isQuest and (baseY + 430) or (isEnt and (baseY + 340) or (isItem and 700 or 650)))
|
|
hint:ClearAllPoints()
|
|
local hy = isQuest and (268 + 40) or (isEnt and 212 or (isItem and 148 or 104))
|
|
hint:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -baseY - hy)
|
|
hint:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -baseY - hy)
|
|
end
|
|
|
|
local function Collect()
|
|
local ed = { z = {}, dg = state.dg, cl = state.cl }
|
|
for i, z in ipairs(state.z) do ed.z[i] = z end
|
|
if state.kind == "units" then
|
|
ed.l1, ed.l2 = tonumber(l1Box.edit:GetText()), tonumber(l2Box.edit:GetText())
|
|
elseif state.kind == "quests" then
|
|
local pre = {}
|
|
for n in (preBox.edit:GetText() or ""):gmatch("%d+") do pre[#pre + 1] = tonumber(n) end
|
|
if #pre > 0 then ed.pre = pre end
|
|
for _, key in ipairs({ "nx", "bf", "af" }) do
|
|
local list = {}
|
|
for n in (qBoxes[key].edit:GetText() or ""):gmatch("%d+") do list[#list + 1] = tonumber(n) end
|
|
if #list > 0 then ed[key] = list end
|
|
end
|
|
ed.ql = tonumber(qBoxes.ql.edit:GetText())
|
|
local tx = qBoxes.tx.edit:GetText()
|
|
if tx and tx:find("%S") then ed.tx = tx end
|
|
ed.si = tonumber((qBoxes.si.edit:GetText() or ""):match("%d+"))
|
|
elseif state.kind == "items" then
|
|
ed.key = tonumber((preBox.edit:GetText() or ""):match("%d+"))
|
|
end
|
|
if state.kind == "units" or state.kind == "objects" then
|
|
local qk, qd = {}, {}
|
|
for n in (uBoxes.qk.edit:GetText() or ""):gmatch("%d+") do qk[#qk + 1] = tonumber(n) end
|
|
for q, it in (uBoxes.qd.edit:GetText() or ""):gmatch("(%d+)%s*[:/]%s*(%d+)") do qd[#qd + 1] = q .. ":" .. it end
|
|
if #qk > 0 then ed.qk = qk end
|
|
if #qd > 0 then ed.qd = qd end
|
|
end
|
|
if state.kind == "units" or state.kind == "objects" or state.kind == "items" then
|
|
local qb = {}
|
|
for n in (uBoxes.qb.edit:GetText() or ""):gmatch("%d+") do qb[#qb + 1] = tonumber(n) end
|
|
if #qb > 0 then ed.qb = qb end
|
|
end
|
|
if state.kind == "quests" then
|
|
local qr = {}
|
|
for k, n in (qBoxes.qr.edit:GetText() or ""):gmatch("([iuoIUO])%s*[:#]?%s*(%d+)") do qr[#qr + 1] = k:lower() .. ":" .. n end
|
|
if #qr > 0 then ed.qr = qr end
|
|
end
|
|
return ed
|
|
end
|
|
local function Save()
|
|
if state.kind and state.id then
|
|
Codex:SetEd(state.kind, state.id, Collect())
|
|
if onChanged then onChanged() end
|
|
end
|
|
win:Hide()
|
|
end
|
|
local save = UI.CreateButton(win, L.CODEX_NAME_SAVE, 140, 28, Save, "primary")
|
|
save:SetPoint("BOTTOMLEFT", win, "BOTTOMLEFT", 16, 14)
|
|
local clear = UI.CreateButton(win, L.CODEX_NAME_CLEAR, 140, 28, function()
|
|
state.z, state.dg, state.cl = {}, nil, nil
|
|
l1Box.edit:SetText("")
|
|
l2Box.edit:SetText("")
|
|
preBox.edit:SetText("")
|
|
for _, b in pairs(qBoxes) do b.edit:SetText("") end
|
|
for _, b in pairs(uBoxes) do b.edit:SetText("") end
|
|
Save()
|
|
end, "default")
|
|
clear:SetPoint("LEFT", save, "RIGHT", 8, 0)
|
|
local cancel = UI.CreateButton(win, L.CODEX_NAME_CANCEL, 140, 28, function() win:Hide() end, "default")
|
|
cancel:SetPoint("LEFT", clear, "RIGHT", 8, 0)
|
|
|
|
function win.Open(kind, id)
|
|
state.kind, state.id = kind, id
|
|
local ed = Codex:GetEd(kind, id) or {}
|
|
state.z = {}
|
|
for i, z in ipairs(ed.z or {}) do state.z[i] = z end
|
|
state.dg, state.cl = ed.dg, ed.cl
|
|
l1Box.edit:SetText(ed.l1 and tostring(ed.l1) or "")
|
|
l2Box.edit:SetText(ed.l2 and tostring(ed.l2) or "")
|
|
preBox.edit:SetText(kind == "items" and (ed.key and tostring(ed.key) or "") or (ed.pre and table.concat(ed.pre, ", ") or ""))
|
|
hint:SetText(kind == "quests" and (L.CODEX_PROPS_PRE_HINT .. "\n" .. L.CODEX_PROPS_HINT)
|
|
or (kind == "items" and (L.CODEX_PROPS_KEY_HINT .. "\n" .. L.CODEX_PROPS_HINT))
|
|
or ((kind == "units" or kind == "objects") and (L.CODEX_PROPS_Q_HINT .. "\n" .. L.CODEX_PROPS_HINT)) or L.CODEX_PROPS_HINT)
|
|
if kind == "quests" then hint:SetText(L.CODEX_PROPS_QR_HINT .. "\n" .. L.CODEX_PROPS_PRE_HINT .. "\n" .. L.CODEX_PROPS_HINT) end
|
|
for _, key in ipairs({ "nx", "bf", "af" }) do
|
|
qBoxes[key].edit:SetText(ed[key] and table.concat(ed[key], ", ") or "")
|
|
end
|
|
qBoxes.ql.edit:SetText(ed.ql and tostring(ed.ql) or "")
|
|
qBoxes.tx.edit:SetText(ed.tx or "")
|
|
qBoxes.si.edit:SetText(ed.si and tostring(ed.si) or "")
|
|
uBoxes.qk.edit:SetText(ed.qk and table.concat(ed.qk, ", ") or "")
|
|
uBoxes.qd.edit:SetText(ed.qd and table.concat(ed.qd, ", ") or "")
|
|
uBoxes.qb.edit:SetText(ed.qb and table.concat(ed.qb, ", ") or "")
|
|
qBoxes.qr.edit:SetText(ed.qr and table.concat(ed.qr, ", ") or "")
|
|
zoneInput.edit:SetText("")
|
|
Suggest()
|
|
title:SetText(string.format("%s #%s", L[KIND_LABEL[kind]] or kind, tostring(id)))
|
|
local gn = GameName(kind, id)
|
|
game:SetText(gn and string.format(L.CODEX_NAME_GAME, gn) or "")
|
|
win.fwKey = kind .. ":" .. tostring(id)
|
|
win.Refresh()
|
|
win:Show()
|
|
win:Raise()
|
|
end
|
|
return win
|
|
end
|
|
|
|
-- Stufenspanne eines Gebiets von Hand setzen (nur Berechtigte): geht wie alle Eigenschaften ueber die Vorschau im Dev-Reiter
|
|
local function BuildZoneProps(parent, onChanged)
|
|
local L = FW.L
|
|
local win = MakeWindow(parent, 420, 210)
|
|
local state = {}
|
|
local title = UI.CreateLabel(win, "", { font = "heading", size = 14, color = "goldLight" })
|
|
title:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -14)
|
|
local lvLabel = UI.CreateLabel(win, L.CODEX_PROPS_LEVELS, { size = 12 })
|
|
lvLabel:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -52)
|
|
local l1Box = MakeInput(win, 70)
|
|
l1Box:SetPoint("TOPLEFT", win, "TOPLEFT", 190, -48)
|
|
l1Box.edit:SetMaxLetters(3)
|
|
local dash = UI.CreateLabel(win, "-", { size = 12 })
|
|
dash:SetPoint("LEFT", l1Box, "RIGHT", 6, 0)
|
|
local l2Box = MakeInput(win, 70)
|
|
l2Box:SetPoint("LEFT", l1Box, "RIGHT", 20, 0)
|
|
l2Box.edit:SetMaxLetters(3)
|
|
local hint = UI.CreateLabel(win, L.CODEX_ZONE_EDIT_HINT, { size = 11, color = "textDim", justifyV = "TOP" })
|
|
hint:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -86)
|
|
hint:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -86)
|
|
hint:SetHeight(60)
|
|
hint:SetWordWrap(true)
|
|
local function Save(clear)
|
|
if state.key then
|
|
local ed
|
|
if not clear then ed = { l1 = tonumber(l1Box.edit:GetText()), l2 = tonumber(l2Box.edit:GetText()) } end
|
|
Codex:SetEd("zones", Codex.ZoneEdID(state.key), ed)
|
|
if onChanged then onChanged() end
|
|
end
|
|
win:Hide()
|
|
end
|
|
local save = UI.CreateButton(win, L.CODEX_NAME_SAVE, 120, 28, function() Save(false) end, "primary")
|
|
save:SetPoint("BOTTOMLEFT", win, "BOTTOMLEFT", 16, 14)
|
|
local clear = UI.CreateButton(win, L.CODEX_NAME_CLEAR, 120, 28, function() Save(true) end, "default")
|
|
clear:SetPoint("LEFT", save, "RIGHT", 8, 0)
|
|
local cancel = UI.CreateButton(win, L.CODEX_NAME_CANCEL, 120, 28, function() win:Hide() end, "default")
|
|
cancel:SetPoint("LEFT", clear, "RIGHT", 8, 0)
|
|
function win.Open(key)
|
|
state.key = key
|
|
local ed = Codex:GetEd("zones", Codex.ZoneEdID(key)) or {}
|
|
l1Box.edit:SetText(ed.l1 and tostring(ed.l1) or "")
|
|
l2Box.edit:SetText(ed.l2 and tostring(ed.l2) or "")
|
|
title:SetText(string.format("%s: %s", L.CODEX_KIND_ZONES, Codex.MapName(key)))
|
|
win.fwKey = "zones:" .. tostring(key)
|
|
win:Show()
|
|
win:Raise()
|
|
end
|
|
return win
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Fenster "Namen einfuegen"
|
|
------------------------------------------------------------------------
|
|
|
|
local function BuildImport(parent, onChanged)
|
|
local L = FW.L
|
|
local win = MakeWindow(parent, 560, 440)
|
|
local state = { lang = Codex.Lang() }
|
|
|
|
local title = UI.CreateLabel(win, L.CODEX_NAME_IMPORT, { font = "heading", size = 14, color = "goldLight" })
|
|
title:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -14)
|
|
local help = UI.CreateLabel(win, "", { size = 11, color = "textDim", justifyV = "TOP" })
|
|
help:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -40)
|
|
help:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -40)
|
|
help:SetHeight(32)
|
|
help:SetWordWrap(true)
|
|
|
|
local deButton, enButton
|
|
local function Sync()
|
|
deButton:SetStyle(state.lang == "de" and "primary" or "default")
|
|
enButton:SetStyle(state.lang == "en" and "primary" or "default")
|
|
end
|
|
deButton = UI.CreateButton(win, L.CODEX_NAME_DE, 140, 26, function() state.lang = "de"; Sync() end, "default")
|
|
deButton:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -78)
|
|
enButton = UI.CreateButton(win, L.CODEX_NAME_EN, 140, 26, function() state.lang = "en"; Sync() end, "default")
|
|
enButton:SetPoint("LEFT", deButton, "RIGHT", 8, 0)
|
|
|
|
local area = UI.CreateTextArea(win, 528, 220)
|
|
area:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -112)
|
|
|
|
local result = UI.CreateLabel(win, "", { size = 12, color = "goldLight" })
|
|
result:SetPoint("TOPLEFT", win, "TOPLEFT", 16, -344)
|
|
result:SetPoint("TOPRIGHT", win, "TOPRIGHT", -16, -344)
|
|
|
|
local go = UI.CreateButton(win, L.CODEX_NAME_IMPORT_GO, 140, 28, function()
|
|
local done, skipped = Codex:ImportNames(state.kind, state.lang, area:GetText())
|
|
result:SetText(string.format(L.CODEX_NAME_IMPORT_RESULT, done, skipped))
|
|
if onChanged then onChanged() end
|
|
end, "primary")
|
|
go:SetPoint("BOTTOMLEFT", win, "BOTTOMLEFT", 16, 14)
|
|
local close = UI.CreateButton(win, L.CODEX_NAME_CLOSE, 140, 28, function() win:Hide() end, "default")
|
|
close:SetPoint("LEFT", go, "RIGHT", 8, 0)
|
|
|
|
function win.Open(kind)
|
|
state.kind = kind
|
|
state.lang = Codex.Lang()
|
|
Sync()
|
|
help:SetText(string.format(L.CODEX_NAME_IMPORT_HELP, L[KIND_LABEL[kind]] or kind))
|
|
result:SetText("")
|
|
area:SetText("")
|
|
win:Show()
|
|
win:Raise()
|
|
end
|
|
return win
|
|
end
|
|
|
|
------------------------------------------------------------------------
|
|
-- Knoepfe im Tab
|
|
-- getSel() gibt art, auswahl zurueck; onChanged() aktualisiert Liste und Detail
|
|
------------------------------------------------------------------------
|
|
|
|
function NameUI.Attach(f, getSel, onChanged, origin)
|
|
local L = FW.L
|
|
local ctl = { height = 0 }
|
|
origin = origin or { x = 0, y = 0 }
|
|
local editWin, importWin, propsWin, zoneWin
|
|
function NameUI.OpenZone(key)
|
|
if not (Codex.Trust and Codex.Trust.CanEdit()) then return end
|
|
zoneWin = zoneWin or BuildZoneProps(f, onChanged)
|
|
zoneWin.Open(key)
|
|
end
|
|
|
|
local editButton = UI.CreateButton(f, L.CODEX_NAME_EDIT, 150, 26, function()
|
|
local kind, id = getSel()
|
|
if EDITABLE[kind] and id then
|
|
editWin = editWin or BuildEdit(f, onChanged)
|
|
editWin.Open(kind, id)
|
|
end
|
|
end, "default")
|
|
editButton:Hide()
|
|
|
|
local importButton = UI.CreateButton(f, L.CODEX_NAME_IMPORT, 150, 26, function()
|
|
local kind = getSel()
|
|
if EDITABLE[kind] then
|
|
importWin = importWin or BuildImport(f, onChanged)
|
|
importWin.Open(kind)
|
|
end
|
|
end, "default")
|
|
importButton:Hide()
|
|
|
|
local propsButton = UI.CreateButton(f, L.CODEX_PROPS_BTN, 150, 26, function()
|
|
local kind, id = getSel()
|
|
if EDITABLE[kind] and id then
|
|
propsWin = propsWin or BuildProps(f, onChanged)
|
|
propsWin.Open(kind, id)
|
|
end
|
|
end, "default")
|
|
propsButton:Hide()
|
|
|
|
-- "Fehlerhaft markieren" (nur Berechtigte): blendet den Datensatz bei allen Spielern aus
|
|
local function BadNow(kind, id)
|
|
local hook = Codex.DevHook
|
|
local staged = hook and hook.StagedBad and hook.StagedBad(kind, id)
|
|
if staged ~= nil then return staged end
|
|
return Codex:IsBad(kind, id)
|
|
end
|
|
local badButton = UI.CreateButton(f, L.CODEX_BAD_MARK, 170, 26, function()
|
|
local kind, id = getSel()
|
|
if kind and id and kind ~= "items" then
|
|
Codex:SetBad(kind, id, not BadNow(kind, id))
|
|
if onChanged then onChanged() end
|
|
ctl.Update()
|
|
end
|
|
end, "default")
|
|
badButton:Hide()
|
|
|
|
-- Die Knoepfe stehen in einer eigenen Reihe unter "Zurueck/Favorit", von links nach rechts;
|
|
-- ist der Platz zu knapp, laufen sie in die naechste Reihe. ctl.height ist die belegte Hoehe.
|
|
local strip = { propsButton, badButton, importButton, editButton }
|
|
function ctl.Layout()
|
|
local avail = (f:GetWidth() or 0) - origin.x
|
|
if avail < 240 then avail = 640 end
|
|
local x, y, any = 0, 0, false
|
|
for _, b in ipairs(strip) do
|
|
if b:IsShown() then
|
|
local w = b:GetWidth() or 150
|
|
if x > 0 and x + w > avail then
|
|
x = 0
|
|
y = y + 32
|
|
end
|
|
b:ClearAllPoints()
|
|
b:SetPoint("TOPLEFT", f, "TOPLEFT", origin.x + x, -(origin.y + y))
|
|
x = x + w + 8
|
|
any = true
|
|
end
|
|
end
|
|
local h = any and (y + 32) or 0
|
|
if h ~= ctl.height then
|
|
ctl.height = h
|
|
if origin.relayout then origin.relayout() end
|
|
end
|
|
end
|
|
ctl.strip = strip
|
|
|
|
function ctl.Update()
|
|
local kind, id = getSel()
|
|
if EDITABLE[kind] and kind ~= "items" and id and Codex.Trust then
|
|
local bad = BadNow(kind, id)
|
|
if Codex.Trust.Can(bad and "unbad" or "bad") then
|
|
badButton:SetLabel(bad and L.CODEX_BAD_UNMARK or L.CODEX_BAD_MARK)
|
|
badButton:SetStyle(bad and "primary" or "default")
|
|
badButton:Show()
|
|
else
|
|
badButton:Hide()
|
|
end
|
|
else
|
|
badButton:Hide()
|
|
end
|
|
-- Namen bearbeiten: nur berechtigte Charaktere mit dem Modul Freewood-OctoWoW-Dev
|
|
local can = Codex.Trust ~= nil and Codex.Trust.CanEdit()
|
|
if can and EDITABLE[kind] and id then editButton:Show() else editButton:Hide() end
|
|
if can and EDITABLE[kind] then importButton:Show() else importButton:Hide() end
|
|
if can and EDITABLE[kind] and id then propsButton:Show() else propsButton:Hide() end
|
|
if propsWin and propsWin:IsShown() and propsWin.fwKey ~= (tostring(kind) .. ":" .. tostring(id)) then propsWin:Hide() end
|
|
if editWin and editWin:IsShown() and editWin.fwKey ~= (tostring(kind) .. ":" .. tostring(id)) then editWin:Hide() end
|
|
if importWin and importWin:IsShown() and not EDITABLE[kind] then importWin:Hide() end
|
|
ctl.Layout()
|
|
end
|
|
ctl.editButton, ctl.importButton, ctl.propsButton = editButton, importButton, propsButton
|
|
return ctl
|
|
end
|