Dateien nach "/" hochladen
This commit is contained in:
+805
@@ -0,0 +1,805 @@
|
||||
-- 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
|
||||
Reference in New Issue
Block a user