- a 40-man raid cost +5 to +8 ms of CPU per frame — a population, not a hot function — and three cuts landed where it was measured: the rig palette upload sends one `write_buffer` per run, bridging the gaps parked bodies leave between live rigs (calls 93 → 3); a built material becomes an asset when something visible binds it, not when a spawner builds it — 9.9k material assets were alive for 36 drawn batches, so a material is realized only once bound and visible, readers that clone before binding doing it themselves through one new function in the engine's wall (172 → 173): a 17× cut in live GPU objects; and a body's batches spawn as material groups — a geared body stood as 12–27 mesh parts, its skin composite drawn as five separate batches, and two visible batches now join when nothing downstream can tell them apart: parts per body 17 → 12, the Stormwind raid leg 17.0–21.0 → 15.65–15.82 `cpu_ms` (1929, 1940) - the instruments that priced it, all on the probe line: wgpu's own resource census, because a sampled profile put roughly half of the pass encoder in usage trackers sized to the device's live buffer and texture counts — a term that scales with residency, not with what is drawn, and nothing printed the number; the active camera count, since every view is its own pass set; the UI's live texture-identity runs, one 2D draw each, which is the number a UI change moves, not the quad count; and parts and materials per dressed body on the dress census, the ceiling on merging a body's batches read off a real body instead of guessed from a model's batch table (1940) - the coin kit retires: every remaining money display — quest progress, the mail purse and postage, the trade recipient, the tooltip, the quest log, the trainer's purse and cost — moves onto the reference's `MoneyFrameTemplate`, each seat already matching ours; the progress panel's required-money flow is ported in full — `QuestFrame.lua:168-190` colours the FRAME red/white AND the LABEL black/dark-grey when the quest costs more than you hold, where ours had neither colour; the mail postage takes the reference's name and label, trade and mail issue no explicit update because the frames repaint on their own events, and the trainer's cost label is shown or hidden with its `local COSTS_LABEL` shadow deleted; with the trainer converted the hand-built coin trios have no consumer, so their templates and the `BenillaMoney_*` helpers are deleted and `MoneyFrame.xml` is the only money kit (1937) - the crowd-control ladder's aura exemption exists, and it is a join between two `Spell.dbc` records — each arm asks whether the spell being cast is itself an immunity covering the aura that blocks it (Ice Block cast while stunned), the school arm shifting because `School` is an index and `EffectMiscValue` a mask; what the scan mostly decides is WHICH message a refusal carries — a blocking aura the cast does not counter renames the reason to "Can't do that while %s" (1941); bevy_audio leaves the build — its plugin had been disabled since 0530, but disabling a plugin does not remove a crate, and rodio, a second cpal and an Ogg/Vorbis decoder were still linked into a client that mixes through kira (1932); and cpal has four stream errors, not two — a routine ALSA underrun was treated as "the device is gone", tearing the stream down on every hiccup; now only a lost or invalidated device rebuilds (1939) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2000 lines
146 KiB
XML
2000 lines
146 KiB
XML
<Ui>
|
||
<!--
|
||
benilla's quest log window (decision 0088 arc, the quest-log slice — the sibling of
|
||
`QuestFrame.xml`'s questgiver window, dressed from the real 1.12 `QuestLogFrame.xml`/
|
||
`QuestLogFrame.lua` (scratchpad `ref-framexml/QUESTLOG-PIN.md`; section cites below are into
|
||
that pin, `file:line` cites are into the pin's own extracted `QuestLogFrame.xml`/`.lua`). One
|
||
`QuestLogFrame` carries BOTH the list page and the detail page — FLAT layout (decision
|
||
0088 §2, quoted in `QuestFrame.xml`'s header): a child frame shown at runtime does not render
|
||
its own `<Layers>` FontStrings in this engine, so every FontString/Button here lives directly
|
||
on the one always-visible window, never on a nested sub-frame. `enableMouse`/`toplevel`/
|
||
`movable` are LoadXML no-ops in this engine (`loader.rs` warn-once gaps) — omitted here exactly
|
||
as `QuestFrame.xml` omits them; they cost nothing since Buttons are mouse-enabled by
|
||
construction regardless (`widget/mod.rs`'s ctor comment).
|
||
|
||
Docks the left UIPanel slot exactly like Gossip/Merchant/Quest (`UiPanels.xml`
|
||
`UIPanelWindows["QuestLogFrame"] = { area = "left", pushable = 0, whileDead = 1 }`
|
||
(whileDead carried since 1507), pin §8's
|
||
`UIParent.lua l.25` quote) — so it competes for/replaces those windows, never stacks with
|
||
them. UNLIKE those windows this is not an NPC session: no `CloseX()` on hide, no range guard;
|
||
it is durable player state the app can push at any time (`benilla-ui`'s `quest_log.rs` module
|
||
doc). `ToggleQuestLog()` (pin §8, `QuestLogFrame.lua:24-30`) is the show/hide entry point the
|
||
app's 'L' binding already calls (`ui_script/mod.rs`).
|
||
|
||
Faux-scroll (pin §2): 6 title rows (`QUESTS_DISPLAYED`) under a REAL
|
||
`QuestLogListScrollFrame` (a `FauxScrollFrameTemplate` instance, ref l.291-307) driven by
|
||
`FauxScrollFrame_Update`/`_GetOffset`. This paragraph used to say the offset was "a Lua-side
|
||
`questLogOffset` upvalue standing in for [them] (no real ScrollFrame/FauxScrollFrame engine
|
||
exists yet)" — false since the faux kit landed; six other windows ride it. The
|
||
wheel handler lives on the window Frame itself: the engine bubbles a spin UP the parent chain
|
||
(`script/pointer.rs` `mouse_wheel`), so a spin over a title row (no handler of its own) rises to
|
||
this window and scrolls. (A bare `<Frame>` is not mouse-enabled by its ctor — that set is
|
||
Button/CheckButton/Slider/ColorSelect/EditBox, decision 1795 — but `enableMouse` and the
|
||
auto-arming `<Scripts>` names both reach it, and it is a valid bubble ANCESTOR either way:
|
||
bubbling checks for the handler, not mouse-enablement.) There is no wheel-catcher frame: a
|
||
full-area mouse-enabled `<Button>` declared FIRST would win every tie in its bucket, not lose
|
||
it — among equal `(strata, level)` the EARLIER-linked frame takes the point (decision 1816),
|
||
so such a catcher eats the whole window's clicks. The list's empty tail is covered by
|
||
`QuestLogListScrollFrame`, which is wheel-interactive by construction, and its spin bubbles here.
|
||
|
||
v1 scope/deviations from the pin (each cited again at its own widget below):
|
||
- Both pages sit on real scroll frames now: the LIST on a `FauxScrollFrameTemplate`
|
||
(`QuestLogListScrollFrame`) and the DETAIL on a `UIPanelScrollFrameTemplate`
|
||
(`QuestLogDetailScrollFrame`, decision 0112's mechanism)
|
||
— a quest with many objectives/a long description/many rewards scrolls and clips at the
|
||
pane's own edge instead of running past the window's bottom (pin §3's doNotScroll
|
||
asymmetry is implemented — see `BenillaQuestLogDetail_Update`'s own comment).
|
||
- Difficulty coloring wears the reference's names and bands (`QuestDifficultyColor` +
|
||
`GetDifficultyColor`, specified at l.14-20 + l.584-599) over the real
|
||
`GetQuestGreenRange()` binding — see the function's own comment. (The old
|
||
`BenillaQuestDifficultyColor` INTERIM and its approximated thresholds are retired.)
|
||
- No headers ship (`benilla-ui`'s `quest_log.rs`: flat entries only, headers need the
|
||
QuestSort/AreaTable DBC join) — the header branch below is dead code today, kept for when
|
||
that join lands rather than re-derived then.
|
||
- No party share/push, no timed-quest countdown, no reward-spell row — still-named v1 stubs
|
||
in `benilla-ui`'s `quest_log.rs`. Quest-watch tracking (this comment's own arc) IS wired.
|
||
- `GetQuestLogRequiredMoney()` exists on the Lua surface (pin §3/§6) but is not wired to a
|
||
detail-pane line — rare in vanilla (ferry-style quests), a documented v1 gap.
|
||
- `EmptyQuestLogFrame` (pin §2, a whole separate book-art frame) is simplified to one
|
||
centered FontString + hidden rows on this same window.
|
||
- The abandon confirm is the ref's `ABANDON_QUEST` entry on the shared StaticPopup
|
||
engine (UiPanels.xml, decision 0308 §3).
|
||
- Quest-watch toggle is SHIFT+left-click, the ref's own fork (pin §5,
|
||
`QuestLogTitleButton_OnClick`, `QuestLogFrame.lua:469-505`). The modifier plumbing this
|
||
note once named as the missing engine slice (`IsShiftKeyDown` + the app's per-frame
|
||
mirror) landed with the cursor arc; the interim right-click substitute is retired.
|
||
- The two ref watch errors (`QUEST_WATCH_NO_OBJECTIVES`/`QUEST_WATCH_TOO_MANY`) go out
|
||
through the reference's own `UIErrorsFrame:AddMessage`. That was once impossible here —
|
||
`UIErrorsFrame` was a hand-rolled `<Frame>` reachable only by firing `UI_ERROR_MESSAGE`
|
||
from Rust — and the guards no-opped silently in the interim; the MessageFrame widget
|
||
(`script::messageframe::plain`) closed it, and the seam this note asked for turned out
|
||
to be the real widget method rather than a benilla global.
|
||
-->
|
||
<Script><![CDATA[
|
||
-- **`MAX_QUESTS` belongs to the quest LOG in 1.12** — `QuestLogFrame.lua:2`, the file this
|
||
-- one is our counterpart to — and it is here since 1751's sixteenth window. It was
|
||
-- declared in our QuestTimerFrame.xml as `MAX_QUESTS = MAX_QUESTS or 20`, which was the
|
||
-- honest shape while both files were ours; the timer window is the reference's own now and
|
||
-- its `QuestTimerFrame_Update` walks `for i = arg.n + 1, MAX_QUESTS` with no fallback, so
|
||
-- a nil there is `'for' limit must be a number` on the first repaint.
|
||
--
|
||
-- Distinct from `MAX_QUESTLOG_QUESTS` below, which the reference also has: this is the
|
||
-- quest-log CAPACITY (how many a character may carry), that is the display cap.
|
||
MAX_QUESTS = 20 -- MAX_QUESTS (QuestLogFrame.lua:2)
|
||
QUESTS_DISPLAYED = 6 -- QUESTS_DISPLAYED (pin §2, QuestLogFrame.lua:1)
|
||
QUESTLOG_QUEST_HEIGHT = 16 -- the row pitch the faux kit scrolls by (ref l.4)
|
||
MAX_QUESTLOG_QUESTS = 20 -- MAX_QUESTLOG_QUESTS (pin §2, :6) — display cap only
|
||
MAX_OBJECTIVES = 10 -- MAX_OBJECTIVES (pin §3, QuestLogFrame.lua:3)
|
||
-- Reward/choice row cap: the SAME v1 cap `QuestFrame.xml`'s BENILLA_QUEST_MAX_ITEMS uses (the
|
||
-- ref's own MAX_NUM_ITEMS is 10, QuestFrame.lua:2 — we halve it there too).
|
||
MAX_NUM_ITEMS = 6
|
||
-- MAX_WATCHABLE_QUESTS (pin §2/§5, QuestLogFrame.lua:8) — the SAME cap `quest_log.rs`'s
|
||
-- AddQuestWatch already enforces engine-side; this is just this file's own guard so the
|
||
-- right-click handler can skip the AddQuestWatch call (and its error) locally.
|
||
BENILLA_QUESTLOG_MAX_WATCHES = 5
|
||
-- The tracker HUD's flat line pool (ref MAX_QUESTWATCH_LINES, QuestLogFrame.lua:7):
|
||
-- one rolling pool across every watch, dynamically re-chained each paint — the ref's own
|
||
-- model (the old fixed 5×(1+4) per-slot grid predated region Show/Hide/SetPoint).
|
||
BENILLA_QUESTWATCH_LINES = 30
|
||
-- The timed-quest countdown row (decision 1150). UPDATE_DELAY is the ref's own
|
||
-- (QuestLogFrame.lua:5) — the throttle on the "Time Remaining:" repaint, not a benilla
|
||
-- dial. TIME_REMAINING is the shipped enUS GlobalString (GlobalStrings.lua:4248), inlined
|
||
-- like every other string in these files (we load no GlobalStrings.lua).
|
||
BENILLA_QUESTLOG_UPDATE_DELAY = 0.1
|
||
BENILLA_TIME_REMAINING = "Time Remaining:"
|
||
|
||
-- The detail pane's ScrollFrame child-resize sum (`BenillaQuestLogDetail_ResizeChild`'s own
|
||
-- comment) — fixed offsets/row heights transcribed from this chain's own FontString/SetPoint
|
||
-- comments below, gathered here with the file's other constants.
|
||
BENILLA_QUESTLOG_DETAIL_TOP = 5 -- child TOPLEFT -> QuestTitle (ref :624-635, offset 5,-5)
|
||
BENILLA_QUESTLOG_DETAIL_OBJ_GAP = 10 -- ObjectivesText->Objective1 AND last objective/
|
||
-- ObjectivesText->DescriptionTitle (both -10, XML/Lua)
|
||
BENILLA_QUESTLOG_DETAIL_OBJ_ROW = 12 -- one objective line (Objective1's own comment)
|
||
BENILLA_QUESTLOG_DETAIL_OBJ_STEP = 2 -- gap between objective lines
|
||
BENILLA_QUESTLOG_DETAIL_BOTTOM_PAD = 10 -- v1: a little breathing room past the last row
|
||
|
||
-- The list's scroll offset lives on the REAL `QuestLogListScrollFrame` now (a
|
||
-- FauxScrollFrameTemplate instance, ref l.291-307), read with `FauxScrollFrame_GetOffset`.
|
||
-- What stood here was `local questLogOffset = 0`, a chunk-local upvalue standing in for it
|
||
-- "because no real ScrollFrame/FauxScrollFrame engine exists yet" — which stopped being
|
||
-- true when the faux kit landed (SkillFrame.xml, TrainerFrame.xml and four more ride it).
|
||
-- The stand-in also meant this window published no `QuestLogListScrollFrame` at all, which
|
||
-- pfUI's `skins/blizzard/questlog.lua` indexes at l.135-136, l.149-153, l.163-164 and l.181.
|
||
|
||
-- The detail pane's last-computed resize inputs (`BenillaQuestLogDetail_ResizeChild`'s own
|
||
-- comment on WHY a re-check is needed at all: `GetHeight()` on the auto-height FontStrings
|
||
-- is one tick stale on the FIRST populate of brand-new text — the host measures it only on
|
||
-- the NEXT `resolve()`/measure round-trip, which lands after this Lua tick already returned.
|
||
-- Detail_Update has no reason to run again once the quest log's data stops changing, so
|
||
-- nothing would ever ask for the now-correct height — these upvalues let the ScrollFrame's
|
||
-- own `<OnUpdate>` re-ask every frame (cheaply — see that handler's own comment) using the
|
||
-- SAME inputs the last full populate computed, until the measured heights catch up and the
|
||
-- resize stops changing.
|
||
local detailObjAnchorIndex = 0
|
||
local detailRewardHeight = 18
|
||
-- The last height actually applied via SetHeight — lets the OnUpdate re-check below skip
|
||
-- SetHeight/UpdateScrollChildRect (and the OnScrollRangeChanged repaint it fires) entirely
|
||
-- once the resize has converged and stopped changing, rather than redoing that work every
|
||
-- single frame forever while the window sits open.
|
||
local detailLastAppliedHeight = nil
|
||
|
||
-- ── Difficulty coloring ──────────────────────────────────────────────────────────────────
|
||
-- The six bands and their exact colors are the reference's contract, not a palette of ours:
|
||
-- ref-QuestLogFrame.lua's table (l.14-20) and GetDifficultyColor (l.584-599, "Used for
|
||
-- quests and enemy coloration" — the ref's own comment; the TARGET FRAME's level number
|
||
-- colors through this same function, TargetFrame_CheckLevel l.130), and `QuestDifficultyColor`
|
||
-- is a name addons read, so both the global and its six keys are fixed. The green→grey
|
||
-- boundary is the real GetQuestGreenRange() binding (benilla-ui unit.rs — the byte-verified
|
||
-- grey band the plate/tooltip share; the binding's own byte read is under the 2026-07-17
|
||
-- wow-re §5). This retires the BenillaQuestDifficultyColor INTERIM and its approximated
|
||
-- -2/-10 thresholds.
|
||
QuestDifficultyColor = {
|
||
impossible = { r = 1.00, g = 0.10, b = 0.10 },
|
||
verydifficult = { r = 1.00, g = 0.50, b = 0.25 },
|
||
difficult = { r = 1.00, g = 1.00, b = 0.00 },
|
||
standard = { r = 0.25, g = 0.75, b = 0.25 },
|
||
trivial = { r = 0.50, g = 0.50, b = 0.50 },
|
||
header = { r = 0.70, g = 0.70, b = 0.70 },
|
||
}
|
||
|
||
-- How far ABOVE the player the quest sits picks the band. Note the shape of the last two
|
||
-- tests: the three hard bands are fixed offsets, but the green/grey boundary is not a
|
||
-- constant at all — GetQuestGreenRange() widens as the player levels — which is why it is
|
||
-- asked rather than compared against a number, and why "trivial" is what is left over
|
||
-- rather than a band with an edge of its own.
|
||
function GetDifficultyColor(level)
|
||
local levelDiff = level - UnitLevel("player")
|
||
if levelDiff >= 5 then
|
||
return QuestDifficultyColor.impossible
|
||
elseif levelDiff >= 3 then
|
||
return QuestDifficultyColor.verydifficult
|
||
elseif levelDiff >= -2 then
|
||
return QuestDifficultyColor.difficult
|
||
elseif -levelDiff <= GetQuestGreenRange() then
|
||
return QuestDifficultyColor.standard
|
||
end
|
||
return QuestDifficultyColor.trivial
|
||
end
|
||
|
||
-- ── The list page ────────────────────────────────────────────────────────────────────────
|
||
-- `mouseButton` is arg1 off RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
-- (QuestLogTitleButtonTemplate's OnLoad). The watch toggle is SHIFT+left-click, the ref's
|
||
-- own fork (QuestLogFrame.lua:469-505) — the modifier plumbing this file's header once
|
||
-- named as the missing engine slice landed with the cursor arc (0216/0218 follow-up), so
|
||
-- the documented right-click substitute is retired.
|
||
function BenillaQuestLogTitle_OnClick(button, mouseButton)
|
||
local index = button.questIndex
|
||
if not index then return end
|
||
local _, _, _, isHeader, isCollapsed = GetQuestLogTitle(index)
|
||
if isHeader then
|
||
-- pin §5, QuestLog_SetSelection (QuestLogFrame.lua:321-329): a header never becomes
|
||
-- the selection, it only (un)collapses. No header ever ships in v1 (module doc,
|
||
-- `benilla-ui/src/script/quest_log.rs`) so Expand/CollapseQuestHeader don't exist yet
|
||
-- — guarded rather than assumed absent forever.
|
||
if isCollapsed and type(ExpandQuestHeader) == "function" then
|
||
ExpandQuestHeader(index)
|
||
elseif type(CollapseQuestHeader) == "function" then
|
||
CollapseQuestHeader(index)
|
||
end
|
||
return
|
||
end
|
||
-- pin §5, QuestLogTitleButton_OnClick (QuestLogFrame.lua:469-501): shift-click either
|
||
-- posts the quest's NAME into an open chat edit box (l.478-480) or, with chat closed,
|
||
-- toggles the watch (l.481-500 — the ref's own `else`). Chat wins; the watch is the
|
||
-- fallback, not the other way round (decision 1059).
|
||
--
|
||
-- The insert (l.480) is `gsub(this:GetText(), " *(.*)", "%1")` — the row LABEL with its
|
||
-- leading indent trimmed, i.e. the bare quest name; note it is plain text, NOT a
|
||
-- hyperlink (1.12 has no |Hquest: link). We read `GetQuestLogTitle(index)` rather than
|
||
-- gsub'ing the label: the API title IS the string the ref's trim yields (our label is
|
||
-- that title behind the same two-space indent, and in both windows the tag lives on its
|
||
-- own FontString, not on the label) — same result, one fewer expression. `ChatFrameEditBox
|
||
-- and` guards a window test that hasn't loaded ChatFrame.xml (BenillaPaperDollSlot_OnClick's
|
||
-- precedent).
|
||
--
|
||
-- Guard order inside the watch arm matches the ref exactly: already watched → unwatch,
|
||
-- unconditionally; else zero objectives (QUEST_WATCH_NO_OBJECTIVES) or the watch list
|
||
-- full (QUEST_WATCH_TOO_MANY) put the ref's red line on the errors frame
|
||
-- (UIErrorsFrame:AddMessage, the ref's own call — lua:490/495), else watch it. The ref calls QuestWatch_Update() itself
|
||
-- right after each Add/RemoveQuestWatch (same two call sites) — it does NOT lean on
|
||
-- the QUEST_LOG_UPDATE/QUEST_WATCH_UPDATE events alone for this, since neither engine
|
||
-- fires an event off a plain Add/RemoveQuestWatch call; we mirror that exactly.
|
||
if mouseButton == "LeftButton" and IsShiftKeyDown() then
|
||
local title = GetQuestLogTitle(index)
|
||
if ChatFrameEditBox and ChatFrameEditBox:IsVisible() then
|
||
-- The visibility test stays HERE, not in the helper: it is the ref's own fork
|
||
-- (l.474/478) — with chat open this click never watches, and the helper's
|
||
-- return would conflate "chat closed" with "nothing to post".
|
||
BenillaChatEdit_InsertLink(title)
|
||
elseif IsQuestWatched(index) then
|
||
-- Clearing the timer too: a lingering timed entry would later expire and
|
||
-- silently unwatch a re-added MANUAL watch.
|
||
if title then BENILLA_QUEST_WATCH_TIMERS[title] = nil end
|
||
RemoveQuestWatch(index)
|
||
QuestWatch_Update()
|
||
elseif GetNumQuestLeaderBoards(index) == 0 then
|
||
-- ref QUEST_WATCH_NO_OBJECTIVES, red, straight onto the errors frame.
|
||
UIErrorsFrame:AddMessage("This quest has no objectives to track", 1.0, 0.1, 0.1)
|
||
elseif GetNumQuestWatches() >= BENILLA_QUESTLOG_MAX_WATCHES then
|
||
-- ref QUEST_WATCH_TOO_MANY, red.
|
||
UIErrorsFrame:AddMessage("You may only watch " .. BENILLA_QUESTLOG_MAX_WATCHES .. " quests at a time", 1.0, 0.1, 0.1)
|
||
else
|
||
-- A manual watch is PERMANENT (ref: QUEST_WATCH_NO_EXPIRE) — drop any timed
|
||
-- entry the auto-watch may have armed for it.
|
||
if title then BENILLA_QUEST_WATCH_TIMERS[title] = nil end
|
||
AddQuestWatch(index)
|
||
QuestWatch_Update()
|
||
end
|
||
end
|
||
-- pin §5: every click (shifted/right-clicked or not) ends in select + a full repaint.
|
||
SelectQuestLogEntry(index)
|
||
BenillaQuestLogFrame_Update()
|
||
end
|
||
|
||
-- The fold-all tab (ref QuestLogCollapseAllButton_OnClick, QuestLogFrame.lua:554-563):
|
||
-- index 0 = every header; the tab's own +/- icon tracks the all-state.
|
||
function QuestLogCollapseAllButton_OnClick()
|
||
local b = getglobal("QuestLogCollapseAllButton")
|
||
if b.allCollapsed then
|
||
b.allCollapsed = nil
|
||
b:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
|
||
ExpandQuestHeader(0)
|
||
else
|
||
b.allCollapsed = 1
|
||
b:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
|
||
CollapseQuestHeader(0)
|
||
end
|
||
end
|
||
|
||
-- pin §2's QuestLog_SetFirstValidSelection/QuestLog_GetFirstSelectableQuest
|
||
-- (QuestLogFrame.lua:293-296, :565-582): if nothing is selected, pick the first non-header row.
|
||
function QuestLog_SetFirstValidSelection()
|
||
if GetQuestLogSelection() ~= 0 then return end
|
||
local numEntries = GetNumQuestLogEntries()
|
||
for i = 1, numEntries do
|
||
local _, _, _, isHeader = GetQuestLogTitle(i)
|
||
if not isHeader then
|
||
SelectQuestLogEntry(i)
|
||
return
|
||
end
|
||
end
|
||
end
|
||
|
||
function BenillaQuestLogList_Update()
|
||
local numEntries, numQuests = GetNumQuestLogEntries()
|
||
-- Ref QuestLogFrame.lua:123-124 with QUEST_LOG_COUNT_TEMPLATE inlined verbatim
|
||
-- (GlobalStrings.lua:3236): gold "Quests:" label, white count via the |cff markup; the
|
||
-- pill's middle piece then shrinks to the text (ref sizes it every update). The >10
|
||
-- guard skips the first-ever paint, where the host hasn't measured the string yet
|
||
-- (GetWidth 0 would collapse the pill; the next update — and every one after — sizes it).
|
||
getglobal("QuestLogQuestCount"):SetText(string.format("Quests: |cffffffff%d/%d|r", numQuests, MAX_QUESTLOG_QUESTS))
|
||
local countWidth = getglobal("QuestLogQuestCount"):GetWidth()
|
||
if countWidth and countWidth > 10 then
|
||
getglobal("QuestLogCountMiddle"):SetWidth(countWidth)
|
||
end
|
||
|
||
-- v1 empty state (pin §2 drives a whole separate EmptyQuestLogFrame; simplified here to
|
||
-- one message string + hidden rows, see this file's header comment). NOTE: throughout
|
||
-- this file "hiding" text is a blank SetText(""), never a Show/Hide call — exactly how
|
||
-- `QuestFrame.xml`'s BenillaQuest_HideAll blanks its texts instead of hiding them. That
|
||
-- convention predates region Show/Hide (`region.rs` has the real pair now, and the
|
||
-- loader honours hidden= on regions); an empty string draws nothing, so it is equivalent
|
||
-- either way and the idiom stays for consistency with the sibling windows.
|
||
-- ref QuestLogFrame.lua l.108-119, its own two arms: the empty page is a FRAME that
|
||
-- shows or hides, not a string that is written or blanked. (The blank-text convention
|
||
-- above still holds for this window's other text; it is the EmptyQuestLogFrame case
|
||
-- that the reference does differently, because its page carries art as well as a line.)
|
||
local abandonButton = getglobal("QuestLogFrameAbandonButton")
|
||
if numEntries == 0 then
|
||
getglobal("EmptyQuestLogFrame"):Show()
|
||
abandonButton:Disable()
|
||
else
|
||
getglobal("EmptyQuestLogFrame"):Hide()
|
||
abandonButton:Enable()
|
||
end
|
||
|
||
-- Share Quest (ref QuestLog_Update's tail, QuestLogFrame.lua:299-305) — the predicate
|
||
-- verbatim, in the ref's own guard order: an EMPTY log disables outright, otherwise the
|
||
-- quest must be sharable AND we must be in a party. Both halves matter and neither is
|
||
-- redundant. GetQuestLogPushable() reads the SELECTION's QUEST_FLAGS_SHARABLE bit off
|
||
-- the template cache, which is the client's own test and the server's only reliance:
|
||
-- vmangos never re-checks the bit on the push, only on the receiver's accept, so a
|
||
-- button we wrongly lit would push a quest the party is then refused (decision 1733).
|
||
BenillaQuestLogPushButton_Update(numEntries)
|
||
|
||
-- ref QuestLogFrame.lua l.127, its own call: the kit owns the clamp, the bar range
|
||
-- and the arrows. (The ref passes QuestLogHighlightFrame + two offsets as the
|
||
-- highlight-repositioning tail; ours repositions its own highlight below, so those
|
||
-- trailing arguments stay off.)
|
||
local listScroll = getglobal("QuestLogListScrollFrame")
|
||
FauxScrollFrame_Update(listScroll, numEntries, QUESTS_DISPLAYED, QUESTLOG_QUEST_HEIGHT)
|
||
BenillaScrollTrough_Follow("QuestLogListScrollFrame")
|
||
local questLogOffset = FauxScrollFrame_GetOffset(listScroll)
|
||
|
||
local selection = GetQuestLogSelection()
|
||
|
||
for i = 1, QUESTS_DISPLAYED do
|
||
local button = getglobal("QuestLogTitle" .. i)
|
||
local index = i + questLogOffset
|
||
if index <= numEntries then
|
||
local title, level, tag, isHeader, isCollapsed, isComplete = GetQuestLogTitle(index)
|
||
local text = title or ""
|
||
if isHeader then
|
||
-- Ref QuestLogFrame.lua:146-159: a header shows the plus/minus fold icon
|
||
-- (its NormalTexture — the row template declares the 16x16 LEFT+3 slot),
|
||
-- the plus-glow hover art, no indent, no tag, no watch check.
|
||
if isCollapsed then
|
||
button:SetNormalTexture("Interface\\Buttons\\UI-PlusButton-Up")
|
||
else
|
||
button:SetNormalTexture("Interface\\Buttons\\UI-MinusButton-Up")
|
||
end
|
||
button.foldHighlight:SetTexture("Interface\\Buttons\\UI-PlusButton-Hilight")
|
||
else
|
||
-- Ref l.161-166: quest rows clear both state slots and indent two spaces.
|
||
text = " " .. text
|
||
button:SetNormalTexture("")
|
||
button.foldHighlight:SetTexture("")
|
||
end
|
||
-- The TAG, ref l.187-195 verbatim, INCLUDING the precedence: a finished quest's
|
||
-- Failed/Complete word OVERWRITES the engine's tag — one row never shows both,
|
||
-- and the state word wins. `questTag` is the bare word from the engine
|
||
-- (`Elite`, `Dungeon`, `Raid`, `PvP`, `Life`, `World Event`, `Legendary` —
|
||
-- QuestInfo.dbc keyed by the quest template's Type); the parentheses are the
|
||
-- ref's, added here. Headers arrive with a nil tag and a nil isComplete, so
|
||
-- this clears their string without a branch of its own (ref l.187 is likewise
|
||
-- outside the isHeader arm).
|
||
--
|
||
-- KNOWN DEVIATION, and the only one left on this row: the ref also SHRINKS the
|
||
-- title to keep it out from under the tag (l.196-203, `275 - 15 - tagWidth`,
|
||
-- re-seating the watch check off the capped width at l.205-213). We don't cap:
|
||
-- an explicit width on a FontString is a WRAP width here
|
||
-- (`RegionData::measure_key`), so capping a 33+ character title would wrap it
|
||
-- onto a second line inside a 16px row — worse than the overlap it prevents.
|
||
-- Our check needs no reseat either: it anchors off the title's own ink
|
||
-- (template comment), which is what the ref's dummy-measure arithmetic
|
||
-- reconstructs.
|
||
if isComplete and isComplete < 0 then
|
||
tag = FAILED
|
||
elseif isComplete and isComplete > 0 then
|
||
tag = COMPLETE
|
||
end
|
||
if tag then
|
||
button.tag:SetText("(" .. tag .. ")")
|
||
else
|
||
button.tag:SetText("")
|
||
end
|
||
button.text:SetText(text)
|
||
button.questIndex = index
|
||
-- Ref l.239-246: the tag takes the SAME difficulty colour as the title (the
|
||
-- ref colours title, tag and the group-mate count together). What we don't do
|
||
-- is the ref's SELECTED-row recolour (l.253-256/l.336: highlight-white on both
|
||
-- title and tag) — our title can't take it either, since the ref gets it from
|
||
-- LockHighlight on a ButtonText and ours is a plain FontString. Whole-row, not
|
||
-- tag-only, so the two stay in step; the selection already reads off
|
||
-- QuestLogHighlightFrame.
|
||
local c
|
||
if isHeader then
|
||
c = QuestDifficultyColor["header"]
|
||
else
|
||
c = GetDifficultyColor(level)
|
||
end
|
||
button.text:SetTextColor(c.r, c.g, c.b)
|
||
button.tag:SetTextColor(c.r, c.g, c.b)
|
||
-- pin §2's $parentCheck: the per-row watch checkbox. SetTexture(path)/
|
||
-- SetTexture(nil) as the show/hide toggle — the icon-slot blanking pattern
|
||
-- (the icon-clearing every slot repaint does). (Regions DO have Show/Hide these days —
|
||
-- region.rs; this site just predates it and the pattern is equivalent.)
|
||
if not isHeader and IsQuestWatched(index) then
|
||
button.check:SetTexture("Interface\\Buttons\\UI-CheckBox-Check")
|
||
else
|
||
button.check:SetTexture(nil)
|
||
end
|
||
button:Show()
|
||
else
|
||
button.questIndex = nil
|
||
button:Hide()
|
||
end
|
||
end
|
||
|
||
-- The selection highlight follows the row only while it is inside the visible scroll
|
||
-- window (pin §5, QuestLog_SetSelection QuestLogFrame.lua:330-340) — a selection scrolled
|
||
-- off-screen still holds state, but the highlight itself doesn't show until the list
|
||
-- scrolls back to it. Ref l.337-339 verbatim: the glow rides at (5,0) on the row and is
|
||
-- vertex-colored to the row's own difficulty color (that green bar in the ref shot IS
|
||
-- this vertex color on the white ADD gradient).
|
||
local hl = getglobal("QuestLogHighlightFrame")
|
||
if selection > questLogOffset and selection <= questLogOffset + QUESTS_DISPLAYED
|
||
and selection <= numEntries then
|
||
local selButton = getglobal("QuestLogTitle" .. (selection - questLogOffset))
|
||
local _, selLevel, _, selIsHeader = GetQuestLogTitle(selection)
|
||
if selIsHeader then
|
||
local c = QuestDifficultyColor["header"]
|
||
getglobal("QuestLogSkillHighlight"):SetVertexColor(c.r, c.g, c.b)
|
||
else
|
||
local c = GetDifficultyColor(selLevel)
|
||
getglobal("QuestLogSkillHighlight"):SetVertexColor(c.r, c.g, c.b)
|
||
end
|
||
hl:SetPoint("TOPLEFT", selButton, "TOPLEFT", 5, 0)
|
||
hl:Show()
|
||
else
|
||
hl:Hide()
|
||
end
|
||
end
|
||
|
||
function BenillaQuestLogFrame_OnMouseWheel(delta)
|
||
-- WoW wheel convention: +1 per notch up, -1 down (ChatFrame.xml's own handler quotes the
|
||
-- same convention). Up = earlier entries (offset toward 0); down = later entries. The
|
||
-- shared kit's own wheel step, off the real frame — the same call SkillFrame.xml makes.
|
||
BenillaFauxScrollFrame_OnMouseWheel(getglobal("QuestLogListScrollFrame"), delta)
|
||
end
|
||
|
||
-- ── The detail page ──────────────────────────────────────────────────────────────────────
|
||
-- The detail pane's real ScrollFrame (decision 0112's mechanism, landed this session — this
|
||
-- window used to be a fixed layout that simply clipped past the window's bottom edge, this
|
||
-- file's header comment). `QuestLogDetailScrollFrame`'s ScrollChild is
|
||
-- `QuestLogDetailScrollChildFrame`: every FontString/Button below that used to live flat on
|
||
-- `QuestLogFrame` now lives on that child instead (the 0088 §2 flat-frame constraint
|
||
-- this file's header comment quoted DIED with the 0112 resolver fixpoint — child frames
|
||
-- render their own `<Layers>` regions again), so its subtree clips at the ScrollFrame's own
|
||
-- rect and scrolls independent of the rest of the window.
|
||
--
|
||
-- The child has no *reported* height from the engine (a Frame's height is its own SetSize —
|
||
-- the resolver never grows a frame to fit content that overflows it, `script/mod.rs`'s
|
||
-- region-resolution comment), so `BenillaQuestLogDetail_ResizeChild` below sums one by hand
|
||
-- from the same fixed offsets/row heights this chain's own comments already cite, plus each
|
||
-- auto-height FontString's OWN `GetHeight()` (region.rs: measured from the host font atlas
|
||
-- once text is set — confirmed live, not a guess). That measurement is a FRAME LATE relative
|
||
-- to *this* call (Lua runs before `resolve()`/the measure round-trip each tick, `ui_script/
|
||
-- mod.rs`'s drive loop) — a BRAND-NEW selection's text sizes off zero (never yet measured)
|
||
-- on this very populate, understating the true height. Nothing guarantees a SECOND populate
|
||
-- ever runs for the same stable selection (`QUEST_LOG_UPDATE` only fires on an actual data
|
||
-- change — `ui_quest_log.rs`'s diffed feed — not every tick), so relying on "the next
|
||
-- update self-heals it" silently under-sizes the child forever once the log goes quiet
|
||
-- (caught on the ui-questlog capture: the reward text visibly clipped with the scrollbar
|
||
-- never appearing). The honest fix is `BenillaQuestLogDetail_OnUpdate` below: it re-sums
|
||
-- every frame the window is open (cheap — its own comment) until the measurement lands and
|
||
-- the sum stops changing, which converges within a couple of frames of any repaint. A
|
||
-- same-frame exact answer isn't available without an engine-side "resize to fit" primitive;
|
||
-- this converges honestly instead of asserting a fiction.
|
||
|
||
-- A FontString's content height for the resize sum: blank text is a TRUE 0 regardless of
|
||
-- what GetHeight() answers. Needed because `measured` (region.rs) is a one-way cache keyed
|
||
-- off the LAST non-blank text — SetText("") never clears it (this engine has no live "0,0"
|
||
-- the instant a string blanks, unlike the real client's font engine), so a freshly-blanked
|
||
-- FontString would otherwise still report its previous text's height. A NON-blank string
|
||
-- still reports last tick's measurement (this function's own header comment on the lag).
|
||
function BenillaQuestLogDetail_TextHeight(fontString)
|
||
local text = fontString:GetText()
|
||
if not text or text == "" then return 0 end
|
||
return fontString:GetHeight()
|
||
end
|
||
|
||
-- Sums the child's needed height from this ONE chain's own fixed offsets (cited per term,
|
||
-- each already documented at its own FontString/SetPoint above) + every auto-height
|
||
-- FontString's measured `GetHeight()` + `rewardSectionHeight` (BenillaQuestLogRewards_Update's
|
||
-- own return — its header-through-money layout has its own conditional branches, cheaper to
|
||
-- total right where those branches already live than to re-derive them here). Then
|
||
-- `UpdateScrollChildRect()` so the scrollbar (the template's OnScrollRangeChanged) hears the
|
||
-- new range.
|
||
function BenillaQuestLogDetail_ResizeChild(objAnchorIndex, rewardSectionHeight)
|
||
detailObjAnchorIndex = objAnchorIndex
|
||
detailRewardHeight = rewardSectionHeight
|
||
local title = getglobal("QuestLogQuestTitle")
|
||
local objectivesText = getglobal("QuestLogObjectivesText")
|
||
local description = getglobal("QuestLogQuestDescription")
|
||
|
||
local objSpan
|
||
if objAnchorIndex > 0 then
|
||
objSpan = BENILLA_QUESTLOG_DETAIL_OBJ_GAP
|
||
+ objAnchorIndex * BENILLA_QUESTLOG_DETAIL_OBJ_ROW
|
||
+ (objAnchorIndex - 1) * BENILLA_QUESTLOG_DETAIL_OBJ_STEP
|
||
+ BENILLA_QUESTLOG_DETAIL_OBJ_GAP
|
||
else
|
||
objSpan = BENILLA_QUESTLOG_DETAIL_OBJ_GAP
|
||
end
|
||
-- The countdown row, when the selection has one (decision 1150): one more -10 hop and
|
||
-- one more fixed 12px row ahead of the objectives, whether or not any objective follows
|
||
-- it — both branches above start at the same ObjectivesText→next -10, so the delta is
|
||
-- the same either way. Read off the ref's own hasTimer flag rather than a second
|
||
-- parameter, so the OnUpdate re-check below re-sums it without threading state.
|
||
if BenillaQuestLogHasTimer then
|
||
objSpan = objSpan + BENILLA_QUESTLOG_DETAIL_OBJ_GAP + BENILLA_QUESTLOG_DETAIL_OBJ_ROW
|
||
end
|
||
|
||
local height = BENILLA_QUESTLOG_DETAIL_TOP
|
||
+ BenillaQuestLogDetail_TextHeight(title)
|
||
+ 5 -- QuestTitle -> ObjectivesText
|
||
+ BenillaQuestLogDetail_TextHeight(objectivesText)
|
||
+ objSpan
|
||
+ 18 -- DescriptionTitle: fixed span regardless of text (its own comment)
|
||
+ 5 -- DescriptionTitle -> Description
|
||
+ BenillaQuestLogDetail_TextHeight(description)
|
||
+ 15 -- Description -> RewardTitleText
|
||
+ rewardSectionHeight
|
||
+ BENILLA_QUESTLOG_DETAIL_BOTTOM_PAD
|
||
|
||
if height ~= detailLastAppliedHeight then
|
||
detailLastAppliedHeight = height
|
||
getglobal("QuestLogDetailScrollChildFrame"):SetHeight(height)
|
||
getglobal("QuestLogDetailScrollFrame"):UpdateScrollChildRect()
|
||
end
|
||
end
|
||
|
||
-- The re-check `QuestLogDetailScrollFrame`'s own `<OnUpdate>` calls every frame the log
|
||
-- window is open (`UiScript::tick`'s OnUpdate gate gates it on effective-visibility, so this
|
||
-- costs nothing while the window is closed): re-sums the SAME inputs the last full populate
|
||
-- computed (`BenillaQuestLogDetail_ResizeChild`'s own header comment on why a single populate
|
||
-- isn't enough — the auto-height FontStrings' `GetHeight()` only reflects a NEW text's real
|
||
-- measurement one tick after this function first set it). `ResizeChild`'s own
|
||
-- detailLastAppliedHeight guard makes every one of these calls a no-op once the resize has
|
||
-- converged (no host measurement changed since the last check).
|
||
function BenillaQuestLogDetail_OnUpdate()
|
||
BenillaQuestLogDetail_ResizeChild(detailObjAnchorIndex, detailRewardHeight)
|
||
end
|
||
|
||
-- ref QuestLog_OnUpdate (QuestLogFrame.lua:96-105), re-expressed here including its
|
||
-- UPDATE_DELAY throttle: the countdown is repainted ten times a second, not every frame —
|
||
-- SecondsToTime's output only changes once a second, so anything faster is a re-measure of
|
||
-- an identical string. The flag/accumulator pair is the ref's own (its two fields on
|
||
-- QuestLogFrame; ours are file globals because our detail state already lives that way).
|
||
function QuestLog_OnUpdate(elapsed)
|
||
if not BenillaQuestLogHasTimer then
|
||
return
|
||
end
|
||
BenillaQuestLogTimePassed = (BenillaQuestLogTimePassed or 0) + (elapsed or 0)
|
||
if BenillaQuestLogTimePassed > BENILLA_QUESTLOG_UPDATE_DELAY then
|
||
local left = GetQuestLogTimeLeft()
|
||
getglobal("QuestLogTimerText"):SetText(
|
||
BENILLA_TIME_REMAINING .. " " .. SecondsToTime(left or 0))
|
||
BenillaQuestLogTimePassed = 0
|
||
end
|
||
end
|
||
|
||
-- The detail pane's scrollbar is the ref's own `UIPanelScrollFrameTemplate` Slider now
|
||
-- (ref l.276-289): the wheel, the arrows, the draggable thumb and the range bookkeeping all
|
||
-- come from the template. What stood here was `BenillaQuestLogDetailScroll_Step`/`_SyncBar`
|
||
-- over a hand-rolled, no-drag `QuestLogDetailScrollBar` — a private name pfUI's
|
||
-- `skins/blizzard/questlog.lua` l.199 falls through, since it skins
|
||
-- `QuestLogDetailScrollFrameScrollBar`.
|
||
|
||
function BenillaQuestLogDetail_Clear()
|
||
getglobal("QuestLogQuestTitle"):SetText("")
|
||
getglobal("QuestLogObjectivesText"):SetText("")
|
||
-- The ref clears hasTimer on the empty-log path too (QuestLog_Update, :108) — without
|
||
-- it the per-tick repaint keeps writing a countdown into a pane with no selection, and
|
||
-- the child height keeps paying for a row that isn't there.
|
||
BenillaQuestLogHasTimer = nil
|
||
getglobal("QuestLogTimerText"):SetText("")
|
||
getglobal("QuestLogDescriptionTitle"):SetText("")
|
||
getglobal("QuestLogQuestDescription"):SetText("")
|
||
for i = 1, MAX_OBJECTIVES do
|
||
getglobal("QuestLogObjective" .. i):SetText("")
|
||
end
|
||
getglobal("QuestLogRewardTitleText"):SetText("")
|
||
getglobal("QuestLogItemChooseText"):SetText("")
|
||
getglobal("QuestLogItemReceiveText"):SetText("")
|
||
for i = 1, MAX_NUM_ITEMS do
|
||
getglobal("QuestLogItem" .. i):Hide()
|
||
end
|
||
getglobal("QuestLogMoneyFrame"):Hide()
|
||
-- Nothing selected: the header-only span (BenillaQuestLogRewards_Update's own
|
||
-- haveAnyReward==false case, 18px) is the right resize input here too.
|
||
BenillaQuestLogDetail_ResizeChild(0, 18)
|
||
end
|
||
|
||
-- Fill + show one reward/choice row. `getter` is GetQuestLogChoiceInfo or
|
||
-- GetQuestLogRewardInfo (pin §6): both answer the shared 5-tuple `name, texture, count,
|
||
-- quality, usable` — the same shape QuestFrame.xml's GetQuestItemInfo(kind, index) answers
|
||
-- for the questgiver panels, just under quest-log-specific getter names instead of one
|
||
-- kind-dispatched function. `kind` ("choice"/"reward") rides alongside because the LINK
|
||
-- getter IS kind-dispatched — GetQuestLogItemLink(this.type, this:GetID()), ref
|
||
-- QuestLogFrame.lua:545/549 — and because it is the ref's own `questItem.type`
|
||
-- (QuestFrame.lua:369/476, the shared layout routine both windows run).
|
||
function BenillaQuestLogItem_Set(button, getter, index, kind)
|
||
local name, texture, count, quality, usable, itemId = getter(index)
|
||
button.index = index
|
||
button.kind = kind
|
||
button.itemId = itemId
|
||
-- ref QuestFrame.lua:388/490 ("-- For the tooltip"), the same stamp the giver window's
|
||
-- BenillaQuestItem_Set makes: only the reward-SPELL row ever reads "spell" (l.445), and
|
||
-- v1 builds none (GetQuestLogRewardSpell is nil — this file's header). The click arms
|
||
-- below guard on it exactly as the ref does, so the guard is live when that row lands.
|
||
button.rewardType = "item"
|
||
button.quality = quality
|
||
button.icon:SetTexture(texture or BENILLA_FALLBACK_ICON)
|
||
button.name:SetText(name or "...")
|
||
if (count or 1) > 1 then button.count:SetText(count) else button.count:SetText("") end
|
||
local r, g, b = 1, 1, 1
|
||
if quality and BenillaTooltip_QualityColor then r, g, b = BenillaTooltip_QualityColor(quality) end
|
||
button.name:SetTextColor(r, g, b)
|
||
button:Show()
|
||
end
|
||
|
||
-- ref QuestLogRewardItem_OnClick (QuestLogFrame.lua:542-552), the OnClick
|
||
-- QuestLogRewardItemTemplate carries (ref QuestLogFrame.xml:118-120): CTRL previews the
|
||
-- reward in the dressing room (decision 1060), SHIFT posts its link into an open chat edit
|
||
-- box (decision 1059). There is no third arm here — a quest-log reward row is never
|
||
-- selectable, so a plain click is inert, which is why these rows carried no OnClick before
|
||
-- this arc.
|
||
--
|
||
-- Guard-for-guard with the ref: ctrl is gated on `this.rewardType ~= "spell"` (l.544), and
|
||
-- so is shift — but on the ELSEIF line itself (l.547), where the giver window's twin puts it
|
||
-- inside (QuestFrame.lua:121). Same outcome, and kept where the ref puts it. Ours
|
||
-- adds `ChatFrameEditBox and` (ChatFrame.xml is a separate file a window test need not
|
||
-- load — BenillaPaperDollSlot_OnClick's precedent) and a nil-link guard: `link` is nil until
|
||
-- the ask-once item template lands, a state the reference's synchronous item cache never
|
||
-- has, and EditBox:Insert takes a string (DressUpItemLink carries the same guard itself —
|
||
-- ref DressUpFrame.lua:11-13).
|
||
function QuestLogRewardItem_OnClick()
|
||
local button = this
|
||
if IsControlKeyDown() then
|
||
if button.rewardType ~= "spell" then
|
||
DressUpItemLink(GetQuestLogItemLink(button.kind, button.index))
|
||
end
|
||
elseif IsShiftKeyDown() and button.rewardType ~= "spell" then
|
||
-- The visible/non-nil pair is the shared helper's (UIParent.xml).
|
||
BenillaChatEdit_InsertLink(GetQuestLogItemLink(button.kind, button.index))
|
||
end
|
||
end
|
||
|
||
-- The reward-panel layout, ported from the ref's shared `QuestFrameItems_Update`
|
||
-- (QuestFrame.lua:311-522, the same routine the live QuestFrame reward panel uses) — this
|
||
-- window's v1 subset of it: no spell-reward row (GetQuestLogRewardSpell has no v1 caller,
|
||
-- QuestLogFrame.xml's header comment), capped at MAX_NUM_ITEMS (6, half the ref's
|
||
-- MAX_NUM_ITEMS=10, same halving QuestFrame.xml's own BENILLA_QUEST_MAX_ITEMS does). Every
|
||
-- SetPoint below mirrors the ref's own line-for-line (cited per block) — this is the mechanism
|
||
-- the ref itself uses; a static XML band was never right, and now that a runtime SetPoint
|
||
-- re-propagates to dependents (commit d0c23c5) we don't need to fake it with fixed offsets.
|
||
--
|
||
-- RETURNS the section's own total height (RewardTitleText's top to the lowest visible row's
|
||
-- bottom) for `BenillaQuestLogDetail_ResizeChild` to add onto the rest of the chain — this is
|
||
-- the one place that already knows every conditional branch (choices-only / fixed-only /
|
||
-- money-only / any combination), cheaper to total right here than to re-derive elsewhere.
|
||
function BenillaQuestLogRewards_Update()
|
||
local numChoices = GetNumQuestLogChoices()
|
||
local numRewards = GetNumQuestLogRewards()
|
||
local money = GetQuestLogRewardMoney()
|
||
|
||
-- pin §3 / QuestFrame.lua:343-349: QuestLogRewardTitleText shown only if
|
||
-- numRewards+numChoices+money > 0. Text is toggled rather than Show/Hide — see
|
||
-- BenillaQuestLogList_Update's comment on this file's blank-text convention.
|
||
local header = getglobal("QuestLogRewardTitleText")
|
||
local haveAnyReward = numChoices > 0 or numRewards > 0 or (money and money > 0)
|
||
if haveAnyReward then
|
||
header:SetText("Rewards")
|
||
else
|
||
header:SetText("")
|
||
end
|
||
|
||
-- ── Choosable rewards (QuestFrame.lua:367-413): 2-per-row under ItemChooseText. Row 1
|
||
-- anchors below the header text (-3,-5); each following ODD index anchors BOTTOMLEFT of
|
||
-- the row two back (0,-2) — starts a new row; each EVEN index anchors TOPRIGHT of the
|
||
-- previous (1,0) — sits beside it. ──
|
||
local chooseText = getglobal("QuestLogItemChooseText")
|
||
local lastChoice = math.min(numChoices, MAX_NUM_ITEMS)
|
||
if numChoices > 0 then
|
||
chooseText:SetText("You may choose one of these rewards:")
|
||
else
|
||
chooseText:SetText("")
|
||
end
|
||
-- ref l.358-361: hide the tail of the pool BEFORE laying any of it out.
|
||
local totalRewards = numChoices + numRewards
|
||
for i = totalRewards + 1, MAX_NUM_ITEMS do
|
||
getglobal("QuestLogItem" .. i):Hide()
|
||
end
|
||
for i = 1, lastChoice do
|
||
local choice = getglobal("QuestLogItem" .. i)
|
||
BenillaQuestLogItem_Set(choice, GetQuestLogChoiceInfo, i, "choice")
|
||
if i == 1 then
|
||
choice:SetPoint("TOPLEFT", chooseText, "BOTTOMLEFT", -3, -5)
|
||
elseif i % 2 == 1 then
|
||
choice:SetPoint("TOPLEFT", getglobal("QuestLogItem" .. (i - 2)), "BOTTOMLEFT", 0, -2)
|
||
else
|
||
choice:SetPoint("TOPLEFT", getglobal("QuestLogItem" .. (i - 1)), "TOPRIGHT", 1, 0)
|
||
end
|
||
end
|
||
|
||
-- ── "You will receive:" / "You will also receive:" (QuestFrame.lua:454-473): shown
|
||
-- whenever there's a fixed reward OR money, even with zero fixed-reward rows (money-only).
|
||
-- Anchored below the LAST CHOICE ROW'S LEFT COLUMN (the shorter of the two columns) when
|
||
-- choices exist, else below the Rewards header directly. ──
|
||
local receiveText = getglobal("QuestLogItemReceiveText")
|
||
local haveFixed = numRewards > 0 or (money and money > 0)
|
||
if haveFixed then
|
||
if numChoices > 0 then
|
||
receiveText:SetText("You will also receive:")
|
||
local anchorIndex = lastChoice
|
||
if anchorIndex % 2 == 0 then anchorIndex = anchorIndex - 1 end
|
||
receiveText:SetPoint("TOPLEFT", getglobal("QuestLogItem" .. anchorIndex), "BOTTOMLEFT", 3, -5)
|
||
else
|
||
receiveText:SetText("You will receive:")
|
||
receiveText:SetPoint("TOPLEFT", header, "BOTTOMLEFT", 3, -5)
|
||
end
|
||
else
|
||
receiveText:SetText("")
|
||
end
|
||
|
||
-- ── Fixed rewards (QuestFrame.lua:474-513): row 1 anchors below ItemReceiveText (-3,-5);
|
||
-- the same odd/even 2-per-row pattern as the choice rows above, chained off each other. ──
|
||
-- The fixed rows CONTINUE the pool after the choices (ref's own running `rewardsCount`).
|
||
local lastReward = math.min(numRewards, MAX_NUM_ITEMS - lastChoice)
|
||
for i = 1, lastReward do
|
||
local index = i + lastChoice
|
||
local reward = getglobal("QuestLogItem" .. index)
|
||
BenillaQuestLogItem_Set(reward, GetQuestLogRewardInfo, i, "reward")
|
||
if i == 1 then
|
||
reward:SetPoint("TOPLEFT", receiveText, "BOTTOMLEFT", -3, -5)
|
||
elseif i % 2 == 1 then
|
||
reward:SetPoint("TOPLEFT", getglobal("QuestLogItem" .. (index - 2)), "BOTTOMLEFT", 0, -2)
|
||
else
|
||
reward:SetPoint("TOPLEFT", getglobal("QuestLogItem" .. (index - 1)), "TOPRIGHT", 1, 0)
|
||
end
|
||
end
|
||
|
||
-- Money: a STATIC XML anchor (LEFT of ItemReceiveText's RIGHT, +15,0 — ref
|
||
-- QuestLogFrame.xml:896-903) tracks receiveText's runtime SetPoint above via the resolver's
|
||
-- fixpoint re-propagation; only the coin fill/clear is Lua's job here.
|
||
-- ref QuestFrame.lua:350-356's tail, on the reference's own widget (1937).
|
||
local moneyFrame = getglobal("QuestLogMoneyFrame")
|
||
if money and money > 0 then
|
||
moneyFrame:Show()
|
||
MoneyFrame_Update("QuestLogMoneyFrame", money)
|
||
else
|
||
moneyFrame:Hide()
|
||
end
|
||
|
||
-- The section's total height, mirroring the branches above term-for-term (a money-only
|
||
-- coin row adds no height of its own — it rides receiveText's own row, LEFT of it, not
|
||
-- a new one — this window's own coin-anchor comment just above).
|
||
local height = 18 -- RewardTitleText: fixed span regardless of text (its own comment)
|
||
if haveAnyReward then
|
||
if numChoices > 0 then
|
||
local numChoiceRows = math.ceil(lastChoice / 2)
|
||
height = height
|
||
+ 5 -- header -> chooseText
|
||
+ BenillaQuestLogDetail_TextHeight(chooseText)
|
||
+ 5 -- chooseText -> choice row 1
|
||
+ numChoiceRows * 41 + (numChoiceRows - 1) * 2
|
||
end
|
||
if haveFixed then
|
||
height = height + 5 -- (last choice row, or the header) -> receiveText
|
||
+ BenillaQuestLogDetail_TextHeight(receiveText)
|
||
if numRewards > 0 then
|
||
local numRewardRows = math.ceil(lastReward / 2)
|
||
height = height + 5 -- receiveText -> reward row 1
|
||
+ numRewardRows * 41 + (numRewardRows - 1) * 2
|
||
end
|
||
end
|
||
end
|
||
return height
|
||
end
|
||
|
||
-- pin §3/§5's doNotScroll asymmetry (QuestLogFrame.lua:348/455-457, QUESTLOG-PIN.md's own
|
||
-- section on it): a MANUAL reselect (`BenillaQuestLogTitle_OnClick`, no arg here) always
|
||
-- snaps the detail pane's scroll back to the top; the QUEST_LOG_UPDATE data-refresh path
|
||
-- (`BenillaQuestLogFrame_OnEvent` below) passes `doNotScroll=true` so a quest updating while
|
||
-- already being read doesn't yank the player's scroll position out from under them.
|
||
function BenillaQuestLogDetail_Update(doNotScroll)
|
||
local selection = GetQuestLogSelection()
|
||
if selection == 0 or selection > GetNumQuestLogEntries() then
|
||
BenillaQuestLogDetail_Clear()
|
||
if not doNotScroll then
|
||
getglobal("QuestLogDetailScrollFrame"):SetVerticalScroll(0)
|
||
end
|
||
return
|
||
end
|
||
|
||
-- pin §3, QuestLog_UpdateQuestDetails (QuestLogFrame.lua:349-356): title from
|
||
-- GetQuestLogTitle's FIRST return only; " - (Failed)" appended when failed.
|
||
local title = GetQuestLogTitle(selection)
|
||
if IsCurrentQuestFailed() then
|
||
title = (title or "") .. " - (Failed)"
|
||
end
|
||
getglobal("QuestLogQuestTitle"):SetText(title or "")
|
||
|
||
-- pin §3: description is GetQuestLogQuestText()'s FIRST return, the objectives FLAVOR
|
||
-- paragraph (not the leaderboard lines) is the second.
|
||
local description, objectivesText = GetQuestLogQuestText()
|
||
getglobal("QuestLogObjectivesText"):SetText(objectivesText or "")
|
||
|
||
-- pin §3, QuestLog_UpdateQuestDetails (QuestLogFrame.lua:364-374) followed, minus the
|
||
-- Show/Hide our region model has no verb for: a timed quest gets the "Time Remaining:"
|
||
-- row and pushes Objective1 below it; an untimed one blanks the row (our stand-in for
|
||
-- the ref's :Hide()) and anchors Objective1 straight onto ObjectivesText, so the row
|
||
-- costs an untimed quest no space at all. `hasTimer` is the ref's own flag and drives
|
||
-- both the per-tick repaint (QuestLog_OnUpdate) and the child-height sum.
|
||
local questTimer = GetQuestLogTimeLeft()
|
||
local timerText = getglobal("QuestLogTimerText")
|
||
local objective1 = getglobal("QuestLogObjective1")
|
||
if questTimer then
|
||
BenillaQuestLogHasTimer = 1
|
||
BenillaQuestLogTimePassed = 0
|
||
timerText:SetText(BENILLA_TIME_REMAINING .. " " .. SecondsToTime(questTimer))
|
||
objective1:SetPoint("TOPLEFT", timerText, "BOTTOMLEFT", 0, -10)
|
||
else
|
||
BenillaQuestLogHasTimer = nil
|
||
timerText:SetText("")
|
||
objective1:SetPoint("TOPLEFT", getglobal("QuestLogObjectivesText"), "BOTTOMLEFT", 0, -10)
|
||
end
|
||
getglobal("QuestLogQuestDescription"):SetText(description or "")
|
||
-- Lua-managed header (ref text=QUEST_DESCRIPTION is static since the ref always has a real
|
||
-- selection whenever this pane is even visible; our flat window keeps the same FontString
|
||
-- alive with no selection, so THIS function — not a static `text=` — owns "Description",
|
||
-- blanked by BenillaQuestLogDetail_Clear on the empty-log path).
|
||
getglobal("QuestLogDescriptionTitle"):SetText("Description")
|
||
|
||
local numObjectives = GetNumQuestLeaderBoards()
|
||
for i = 1, MAX_OBJECTIVES do
|
||
local line = getglobal("QuestLogObjective" .. i)
|
||
if i <= numObjectives then
|
||
local text, kind, finished = GetQuestLogLeaderBoard(i)
|
||
local display = text
|
||
if not display or display == "" then display = kind or "" end
|
||
-- Ref QuestLogFrame.lua:389-394 verbatim: finished objectives go (0.2,0.2,0.2)
|
||
-- with the "(Complete)" suffix, unfinished stay (0,0,0) — both on the parchment.
|
||
if finished then
|
||
display = display .. " (Complete)"
|
||
line:SetTextColor(0.2, 0.2, 0.2)
|
||
else
|
||
line:SetTextColor(0, 0, 0)
|
||
end
|
||
line:SetText(display)
|
||
else
|
||
line:SetText("")
|
||
end
|
||
end
|
||
|
||
-- pin §3, QuestLog_UpdateQuestDetails (QuestLogFrame.lua:414-424): DescriptionTitle is
|
||
-- runtime-SetPoint'd off the LAST actually-used objective slot, not a static chain off
|
||
-- Objective10 — a quest with fewer than 10 objectives would otherwise drag this header
|
||
-- down by however much dead space the unused tail slots add (this window's own comment
|
||
-- on the FontString). No RequiredMoney branch here (this file's documented v1 gap: no
|
||
-- widget backs GetQuestLogRequiredMoney yet) — that ref branch collapses into the rest.
|
||
-- The objective-less TIMED branch (ref :432-437) is kept: a timed quest with no
|
||
-- leaderboard lines hangs the header off the countdown row, not off ObjectivesText.
|
||
local objAnchorIndex = math.min(numObjectives, MAX_OBJECTIVES)
|
||
local descTitle = getglobal("QuestLogDescriptionTitle")
|
||
if objAnchorIndex > 0 then
|
||
descTitle:SetPoint("TOPLEFT", getglobal("QuestLogObjective" .. objAnchorIndex), "BOTTOMLEFT", 0, -10)
|
||
elseif questTimer then
|
||
descTitle:SetPoint("TOPLEFT", getglobal("QuestLogTimerText"), "BOTTOMLEFT", 0, -10)
|
||
else
|
||
descTitle:SetPoint("TOPLEFT", getglobal("QuestLogObjectivesText"), "BOTTOMLEFT", 0, -10)
|
||
end
|
||
|
||
local rewardHeight = BenillaQuestLogRewards_Update()
|
||
BenillaQuestLogDetail_ResizeChild(objAnchorIndex, rewardHeight)
|
||
if not doNotScroll then
|
||
getglobal("QuestLogDetailScrollFrame"):SetVerticalScroll(0)
|
||
end
|
||
end
|
||
|
||
-- ── The always-visible quest-watch tracker (QuestWatchFrame) ─────────────────────────
|
||
-- Ref QuestWatch_Update (QuestLogFrame.lua:602-663), re-expressed onto the flat 30-line pool
|
||
-- (the frame's own XML comment): every paint re-anchors each used line — a quest TITLE drops
|
||
-- -5 below the previous line (ref -4 under its 13px boxes; ours are measured 12s, same
|
||
-- pitch), an OBJECTIVE drops -1 (ref 0) — writes " - "-prefixed objective rows colored by
|
||
-- the ref law (finished WHITE, unfinished 0.8-gray; the title dark-gold 0.75/0.61/0 until
|
||
-- every objective completes, then full gold), sizes the frame to the content (width
|
||
-- maxW+10 growing LEFT off the TOPRIGHT anchor, height lines×13), recolors the log
|
||
-- window's Track dot, and hides the pool's trailing lines. `GetQuestIndexForWatch(w)`
|
||
-- answers each watch's CURRENT log index (it follows the quest across a log shuffle —
|
||
-- `quest_log.rs`'s id-keyed watch set), exactly like the ref.
|
||
function QuestWatch_Update()
|
||
local watchTextIndex = 1
|
||
local maxWidth = 0
|
||
for i = 1, GetNumQuestWatches() do
|
||
local questIndex = GetQuestIndexForWatch(i)
|
||
if questIndex then
|
||
local numObjectives = GetNumQuestLeaderBoards(questIndex)
|
||
if numObjectives > 0 then
|
||
local titleLine = getglobal("QuestWatchLine" .. watchTextIndex)
|
||
titleLine:SetText(GetQuestLogTitle(questIndex) or "")
|
||
if watchTextIndex > 1 then
|
||
titleLine:ClearAllPoints()
|
||
titleLine:SetPoint("TOPLEFT", getglobal("QuestWatchLine" .. (watchTextIndex - 1)), "BOTTOMLEFT", 0, -5)
|
||
end
|
||
titleLine:Show()
|
||
if titleLine:GetStringWidth() > maxWidth then maxWidth = titleLine:GetStringWidth() end
|
||
watchTextIndex = watchTextIndex + 1
|
||
local objectivesCompleted = 0
|
||
for j = 1, numObjectives do
|
||
local text, kind, finished = GetQuestLogLeaderBoard(j, questIndex)
|
||
if not text or text == "" then text = kind or "" end
|
||
local line = getglobal("QuestWatchLine" .. watchTextIndex)
|
||
line:SetText(" - " .. text)
|
||
if finished then
|
||
line:SetTextColor(1, 1, 1)
|
||
objectivesCompleted = objectivesCompleted + 1
|
||
else
|
||
line:SetTextColor(0.8, 0.8, 0.8)
|
||
end
|
||
line:ClearAllPoints()
|
||
line:SetPoint("TOPLEFT", getglobal("QuestWatchLine" .. (watchTextIndex - 1)), "BOTTOMLEFT", 0, -1)
|
||
line:Show()
|
||
if line:GetStringWidth() > maxWidth then maxWidth = line:GetStringWidth() end
|
||
watchTextIndex = watchTextIndex + 1
|
||
end
|
||
if objectivesCompleted == numObjectives then
|
||
titleLine:SetTextColor(1, 0.82, 0)
|
||
else
|
||
titleLine:SetTextColor(0.75, 0.61, 0)
|
||
end
|
||
end
|
||
end
|
||
end
|
||
-- The log window's Track dot (the ref's tracking-indicator tail): green with ≥1
|
||
-- watch, red with none.
|
||
if GetNumQuestWatches() > 0 then
|
||
getglobal("QuestLogTrackTracking"):SetVertexColor(0, 1.0, 0)
|
||
else
|
||
getglobal("QuestLogTrackTracking"):SetVertexColor(1.0, 0, 0)
|
||
end
|
||
local frame = getglobal("QuestWatchFrame")
|
||
if watchTextIndex == 1 then
|
||
frame:Hide()
|
||
return
|
||
end
|
||
frame:Show()
|
||
frame:SetHeight(watchTextIndex * 13)
|
||
if maxWidth > 0 then frame:SetWidth(maxWidth + 10) end
|
||
-- The GetStringWidth reads above are extract-measured — a frame stale after a text
|
||
-- change — so the OnUpdate sizing tail re-reads them for two frames and converges.
|
||
frame.used_lines = watchTextIndex - 1
|
||
frame.resize_pending = 2
|
||
for i = watchTextIndex, BENILLA_QUESTWATCH_LINES do
|
||
getglobal("QuestWatchLine" .. i):Hide()
|
||
end
|
||
end
|
||
|
||
-- ── Auto quest watching (ref QuestLogFrame.lua:702-786; AUTO_QUEST_WATCH defaults "1" —
|
||
-- "Quests are automatically watched for 5 minutes when you achieve a quest objective.").
|
||
-- BENILLA_QUEST_PROGRESS(questLogIndex) — our own engine event — arms a 300 s timed
|
||
-- watch: a manual shift-click watch is permanent (no timer entry) and never downgraded,
|
||
-- fresh progress re-arms a timed one, expiry unwatches, and a full watch list evicts the
|
||
-- timed entry nearest expiry (never a manual one). Timers key by quest TITLE (stable
|
||
-- across log shuffles; the engine's watch set is id-keyed — the ref's index-keyed
|
||
-- QUEST_WATCH_LIST bookkeeping is transcribed to its observable law, not its
|
||
-- iterate-while-mutating quirks).
|
||
--
|
||
-- Why NOT the native QUEST_WATCH_UPDATE the ref Lua consumes: the §5-verified engine
|
||
-- (wow-re quest-update-ui-feedback-law.md, handler 0x5e5ad0) fires that event with the
|
||
-- quest's 1-based WATCH-LIST position — 0 when unwatched — while the ref's
|
||
-- AutoQuestWatch_Update(arg1) treats arg1 as a quest-LOG index: the shipped 1.12 chain
|
||
-- is broken at exactly that seam (an unwatched quest's progress arrives as 0, and
|
||
-- AddQuestWatch(0) no-ops), so the advertised auto-watch never actually adds a quest.
|
||
-- We keep the advertised behavior — the feature the option tooltip documents — off the
|
||
-- benilla event that carries what the Lua needed; a deliberate intent-over-letter
|
||
-- divergence (the fold-back decision record).
|
||
--
|
||
-- The FLAG is the ref's own uvar, under the ref's own name since decision 1136 — it was
|
||
-- BENILLA_AUTO_QUEST_WATCH (a boolean) while nothing could change it. It is a "1"/"0"
|
||
-- string now because that is what an options row writes and what the reference's own
|
||
-- consumers compare against; the Interface page's "Automatic Quest Tracking" row drives it.
|
||
--
|
||
-- Which is the SECOND break in this feature, independent of the event seam above and just
|
||
-- as fatal: 1.12 assigns `AUTO_QUEST_WATCH = 1` — the NUMBER — at UIOptionsFrame.lua:122,
|
||
-- while every consumer tests `AUTO_QUEST_WATCH == "1"` (QuestLogFrame.lua:64/68) and the
|
||
-- checkbox loads on the same string compare. In Lua 5.0 `1 ~= "1"`, so on a fresh install
|
||
-- the option paints UNCHECKED and the auto-watch is dead, despite the table declaring
|
||
-- `default = "1"`; it only comes alive once the player clicks the box, which writes the
|
||
-- string. We ship the string, so the advertised default is the real one.
|
||
AUTO_QUEST_WATCH = "1"
|
||
RegisterForSave("AUTO_QUEST_WATCH")
|
||
BENILLA_QUEST_WATCH_TIMER = 300
|
||
BENILLA_QUEST_WATCH_TIMERS = {}
|
||
|
||
function BenillaQuestWatch_RemoveByTitle(title)
|
||
for w = 1, GetNumQuestWatches() do
|
||
local questIndex = GetQuestIndexForWatch(w)
|
||
if questIndex and GetQuestLogTitle(questIndex) == title then
|
||
RemoveQuestWatch(questIndex)
|
||
return
|
||
end
|
||
end
|
||
end
|
||
|
||
function AutoQuestWatch_Update(questIndex)
|
||
if AUTO_QUEST_WATCH ~= "1" or not questIndex then return end
|
||
local title = GetQuestLogTitle(questIndex)
|
||
if not title then return end
|
||
if IsQuestWatched(questIndex) then
|
||
if BENILLA_QUEST_WATCH_TIMERS[title] then
|
||
BENILLA_QUEST_WATCH_TIMERS[title] = BENILLA_QUEST_WATCH_TIMER
|
||
end
|
||
return
|
||
end
|
||
if GetNumQuestLeaderBoards(questIndex) == 0 then return end
|
||
if GetNumQuestWatches() >= BENILLA_QUESTLOG_MAX_WATCHES then
|
||
local lowestTitle, lowestTimer = nil, BENILLA_QUEST_WATCH_TIMER + 1
|
||
for t, timer in pairs(BENILLA_QUEST_WATCH_TIMERS) do
|
||
if timer < lowestTimer then lowestTitle, lowestTimer = t, timer end
|
||
end
|
||
if not lowestTitle then return end -- every slot is a manual watch: no eviction
|
||
BENILLA_QUEST_WATCH_TIMERS[lowestTitle] = nil
|
||
BenillaQuestWatch_RemoveByTitle(lowestTitle)
|
||
end
|
||
AddQuestWatch(questIndex)
|
||
BENILLA_QUEST_WATCH_TIMERS[title] = BENILLA_QUEST_WATCH_TIMER
|
||
end
|
||
|
||
function AutoQuestWatch_OnUpdate(elapsed)
|
||
local expired = nil
|
||
for title, timer in pairs(BENILLA_QUEST_WATCH_TIMERS) do
|
||
if timer - elapsed <= 0 then
|
||
expired = expired or {}
|
||
table.insert(expired, title)
|
||
else
|
||
BENILLA_QUEST_WATCH_TIMERS[title] = timer - elapsed
|
||
end
|
||
end
|
||
if expired then
|
||
for _, title in ipairs(expired) do
|
||
BENILLA_QUEST_WATCH_TIMERS[title] = nil
|
||
BenillaQuestWatch_RemoveByTitle(title)
|
||
end
|
||
QuestWatch_Update()
|
||
BenillaQuestLogList_Update() -- the log's row ticks follow (ref: QuestLog_Update)
|
||
end
|
||
end
|
||
|
||
function BenillaQuestWatchFrame_OnLoad(frame)
|
||
-- Repaints on all three: QUEST_LOG_UPDATE (every log change — the ref's own
|
||
-- QuestLog_OnEvent repaints QuestWatch_Update() off it too, QuestLogFrame.lua:57-70),
|
||
-- the native QUEST_WATCH_UPDATE (arg1 = the WATCH-LIST index, 0 if unwatched — kept
|
||
-- for repaint + any future addon, never for auto-watch: the divergence comment
|
||
-- above), and BENILLA_QUEST_PROGRESS (arg1 = the quest-LOG index) which feeds the
|
||
-- auto-watch.
|
||
frame:RegisterEvent("QUEST_LOG_UPDATE")
|
||
frame:RegisterEvent("QUEST_WATCH_UPDATE")
|
||
frame:RegisterEvent("BENILLA_QUEST_PROGRESS")
|
||
QuestWatch_Update()
|
||
end
|
||
|
||
function BenillaQuestWatchFrame_OnEvent(frame)
|
||
if event == "BENILLA_QUEST_PROGRESS" then
|
||
AutoQuestWatch_Update(arg1)
|
||
QuestWatch_Update()
|
||
elseif event == "QUEST_WATCH_UPDATE" or event == "QUEST_LOG_UPDATE" then
|
||
QuestWatch_Update()
|
||
end
|
||
end
|
||
|
||
-- The watch frame's OnUpdate carries the ref's auto-watch timer decay (ref
|
||
-- QuestLogFrame.xml:1140-1144 — the ALWAYS-VISIBLE frame hosts it, so timers tick with
|
||
-- the log closed; hidden-with-no-watches is safe, an empty watch set has no timers) plus
|
||
-- our sizing-convergence tail (QuestWatch_Update's own comment).
|
||
function BenillaQuestWatchFrame_OnUpdate(frame, elapsed)
|
||
AutoQuestWatch_OnUpdate(elapsed or 0)
|
||
if frame.resize_pending and frame.resize_pending > 0 then
|
||
frame.resize_pending = frame.resize_pending - 1
|
||
local maxw = 0
|
||
for i = 1, (frame.used_lines or 0) do
|
||
local w = getglobal("QuestWatchLine" .. i):GetStringWidth()
|
||
if w > maxw then maxw = w end
|
||
end
|
||
if maxw > 0 then frame:SetWidth(maxw + 10) end
|
||
end
|
||
end
|
||
|
||
-- ── Window lifecycle ─────────────────────────────────────────────────────────────────────
|
||
-- `doNotScroll` (pin §5's asymmetry, threaded through to `BenillaQuestLogDetail_Update`):
|
||
-- absent/falsy for a manual call (a row click, the window's own OnShow); `true` from the
|
||
-- QUEST_LOG_UPDATE event handler below.
|
||
-- ── The reference's own two names for what this window already does ─────────────────
|
||
--
|
||
-- `QuestTimerFrame.xml` is the reference's own file, on the chain since 1751, and its
|
||
-- `QuestTimerButton_OnClick` (QuestTimerFrame.lua:41-45) does exactly three things:
|
||
-- ShowUIPanel, `QuestLog_SetSelection(...)`, `QuestLog_Update()`. Neither of the last two
|
||
-- existed anywhere in this tree, so clicking a quest timer raised. Defining them here is
|
||
-- not a stub of an engine verb (1203) — both are FrameXML functions, and this file is our
|
||
-- stand-in for `QuestLogFrame.lua`, which is where the reference defines them. Every other
|
||
-- function in this window has the same relationship to its stock twin; these two were
|
||
-- simply missed because nothing of ours called them.
|
||
--
|
||
-- `QuestLog_SetSelection`'s stock body (QuestLogFrame.lua:317-345) is mostly frame work
|
||
-- that only the stock window has — `QuestLogTitle`..id, `QuestLogHighlightFrame`,
|
||
-- `QuestLogSkillHighlight`. What survives the re-expression is its LAW: a header never
|
||
-- becomes the selection (it folds instead), and a real quest is selected and repainted.
|
||
-- That is the same fork `BenillaQuestLogTitle_OnClick` above already implements, so this
|
||
-- is the shared body rather than a second copy of it.
|
||
function QuestLog_SetSelection(index)
|
||
if not index or index == 0 then return end
|
||
local _, _, _, isHeader, isCollapsed = GetQuestLogTitle(index)
|
||
if isHeader then
|
||
if isCollapsed and type(ExpandQuestHeader) == "function" then
|
||
ExpandQuestHeader(index)
|
||
elseif type(CollapseQuestHeader) == "function" then
|
||
CollapseQuestHeader(index)
|
||
end
|
||
return
|
||
end
|
||
SelectQuestLogEntry(index)
|
||
end
|
||
|
||
-- The reference's `QuestLog_Update` (QuestLogFrame.lua:107). Ours has carried this body
|
||
-- under a `Benilla` prefix; the stock name is the one the chain calls, and having it here
|
||
-- also shrinks the delta when this window itself migrates.
|
||
function QuestLog_Update(doNotScroll)
|
||
BenillaQuestLogFrame_Update(doNotScroll)
|
||
end
|
||
|
||
function BenillaQuestLogFrame_Update(doNotScroll)
|
||
QuestLog_SetFirstValidSelection()
|
||
BenillaQuestLogList_Update()
|
||
-- pin §5, QuestLog_OnEvent (QuestLogFrame.lua:57-63): the detail pane only repaints while
|
||
-- the window is visible — the list rebuild above runs unconditionally either way.
|
||
if getglobal("QuestLogFrame"):IsVisible() then
|
||
BenillaQuestLogDetail_Update(doNotScroll)
|
||
end
|
||
end
|
||
|
||
-- The Share Quest button's enable state (ref QuestLogFrame.lua:299-305 and :74-79, which
|
||
-- are the same three lines twice: the full update runs it with the entry count to hand,
|
||
-- and PARTY_MEMBERS_CHANGED runs it alone because a party you just joined or left changes
|
||
-- the answer without changing the log). `numEntries` is optional — omitted, it is read
|
||
-- here, which is what the event path wants.
|
||
function BenillaQuestLogPushButton_Update(numEntries)
|
||
if not numEntries then
|
||
numEntries = GetNumQuestLogEntries()
|
||
end
|
||
local pushButton = getglobal("QuestFramePushQuestButton")
|
||
if numEntries == 0 then
|
||
pushButton:Disable()
|
||
elseif GetQuestLogPushable() and GetNumPartyMembers() > 0 then
|
||
pushButton:Enable()
|
||
else
|
||
pushButton:Disable()
|
||
end
|
||
end
|
||
|
||
function BenillaQuestLogFrame_OnLoad(frame)
|
||
frame:RegisterEvent("QUEST_LOG_UPDATE")
|
||
-- ref QuestLog_OnLoad (QuestLogFrame.lua:44-54) registers this for exactly one reason:
|
||
-- the Share Quest button's second conjunct. Joining or leaving a party changes whether
|
||
-- the selected quest can be shared without changing the quest log at all, so
|
||
-- QUEST_LOG_UPDATE alone would leave the button stale (decision 1733).
|
||
frame:RegisterEvent("PARTY_MEMBERS_CHANGED")
|
||
-- The faux kit's owner hook (ScrollTemplates.xml l.37): a bar drag or arrow click sets
|
||
-- the frame's offset and then calls this to repaint the rows. SkillFrame.xml wires its
|
||
-- own the same way.
|
||
end
|
||
|
||
function BenillaQuestLogFrame_OnEvent(frame)
|
||
if event == "QUEST_LOG_UPDATE" then
|
||
-- pin §5: the event-driven refresh path passes doNotScroll=true (QuestLogFrame.lua:62
|
||
-- passes `1`) — a quest updating while already being read must not yank the reader's
|
||
-- scroll position back to the top.
|
||
BenillaQuestLogFrame_Update(true)
|
||
elseif event == "PARTY_MEMBERS_CHANGED" then
|
||
-- The ref runs a whole QuestLog_Update here (its else-branch, QuestLogFrame.lua:71-81)
|
||
-- and then re-tests the button; the list cannot have changed, so only the button is
|
||
-- repainted. Same observable state, no scroll or selection churn.
|
||
BenillaQuestLogPushButton_Update()
|
||
end
|
||
end
|
||
|
||
-- pin §8, QuestLogFrame.lua:24-30 — the app's 'L' binding already calls this
|
||
-- (ui_script/mod.rs).
|
||
function ToggleQuestLog()
|
||
local frame = getglobal("QuestLogFrame")
|
||
if frame:IsVisible() then
|
||
HideUIPanel(frame)
|
||
else
|
||
ShowUIPanel(frame)
|
||
end
|
||
end
|
||
|
||
function BenillaQuestLogCloseButton_OnClick()
|
||
HideUIPanel(getglobal("QuestLogFrame"))
|
||
end
|
||
|
||
-- ── The abandon two-step (mark on click → confirm on Yes) — our `ABANDON_QUEST` entry on
|
||
-- the shared StaticPopup engine (UiPanels.xml, decision 0308 §3). Every field below is
|
||
-- StaticPopup's own vocabulary and every value is specified by StaticPopup.lua:749-761:
|
||
-- the ABANDON_QUEST_CONFIRM wording 'Abandon "%s"?' (GlobalStrings.lua:5), abandoning on
|
||
-- accept, and the igQuestLogAbandonQuest kit. There is no expression left to choose here,
|
||
-- which is why this reads the way the specification does. exclusive is v1-inert (engine
|
||
-- header note). ─────────────────────────────────────────────────────────────────────────
|
||
StaticPopupDialogs["ABANDON_QUEST"] = {
|
||
text = "Abandon \"%s\"?", -- ABANDON_QUEST_CONFIRM
|
||
button1 = "Yes", -- YES
|
||
button2 = "No", -- NO
|
||
OnAccept = function()
|
||
AbandonQuest()
|
||
PlaySound("igQuestLogAbandonQuest")
|
||
end,
|
||
timeout = 0,
|
||
whileDead = 1,
|
||
exclusive = 1,
|
||
hideOnEscape = 1,
|
||
}
|
||
|
||
-- ── ABANDON_QUEST_WITH_ITEMS — DECLARED, never shown ────────────────────────────────────
|
||
-- `GetAbandonQuestItems()` is always nil here (`quest_log.rs`), so nothing in this client
|
||
-- reaches `StaticPopup_Show("ABANDON_QUEST_WITH_ITEMS", …)`, and the click handler below
|
||
-- says so. That was taken as a reason to omit the *entry*, and it is not one: the
|
||
-- reference's StaticPopup.lua declares this table unconditionally at load
|
||
-- (StaticPopup.lua:762-775), whatever the client later shows, and an addon reading `_G`
|
||
-- reads declarations, not behaviour.
|
||
--
|
||
-- Questie is the measurement: `QuestieQuest.lua:55` is
|
||
-- `StaticPopupDialogs["ABANDON_QUEST_WITH_ITEMS"].OnAccept` at file scope, with no guard —
|
||
-- it wraps BOTH abandon dialogs to clear its own quest cache. Absent, that is
|
||
-- `attempt to index field 'ABANDON_QUEST_WITH_ITEMS' (a nil value)` and the addon's whole
|
||
-- quest module never loads. (#3 of the top-20 corpus; the same shape as `ChatFrame3..7`'s
|
||
-- "declared because addons read them", 1497.)
|
||
--
|
||
-- Byte-identical to ABANDON_QUEST above but for `text` — the reference's two entries differ
|
||
-- in exactly that one field. `%s` twice: the quest name, then the item list.
|
||
StaticPopupDialogs["ABANDON_QUEST_WITH_ITEMS"] = {
|
||
text = "Abandon \"%s\", destroying %s?", -- ABANDON_QUEST_CONFIRM_WITH_ITEMS
|
||
button1 = "Yes", -- YES
|
||
button2 = "No", -- NO
|
||
OnAccept = function()
|
||
AbandonQuest()
|
||
PlaySound("igQuestLogAbandonQuest")
|
||
end,
|
||
timeout = 0,
|
||
whileDead = 1,
|
||
exclusive = 1,
|
||
hideOnEscape = 1,
|
||
}
|
||
|
||
function BenillaQuestLogAbandonButton_OnClick()
|
||
if GetQuestLogSelection() == 0 then return end
|
||
-- pin §4, QuestLogFrame.xml:463-472: SetAbandonQuest() pins the click-time selection;
|
||
-- GetAbandonQuestItems() is always nil in v1 (`quest_log.rs`), so only the plain
|
||
-- ABANDON_QUEST popup path exists — never ABANDON_QUEST_WITH_ITEMS. (Ref
|
||
-- QuestLogFrame.lua's own click handler shows the same dialog with the name arg.)
|
||
SetAbandonQuest()
|
||
StaticPopup_Show("ABANDON_QUEST", GetAbandonQuestName() or "")
|
||
end
|
||
]]></Script>
|
||
|
||
<!--
|
||
One reward/choice item row — a byte-for-byte copy of `QuestFrame.xml`'s
|
||
`QuestItemTemplate` (ref `QuestItemTemplate`, QuestFrameTemplates.xml l.85-166),
|
||
DUPLICATED rather than inherited across files: this window's own tests load only its own
|
||
dependency list (Fonts/UiPanels/MerchantFrame — the money helpers), the same per-window
|
||
isolation this repo's other `*_tests.rs` already keep (e.g. `bag_tests.rs` loads
|
||
`MerchantFrame.xml` for its money helper only, never `QuestFrame.xml`). The real client also
|
||
keeps a SEPARATE `QuestLogRewardItemTemplate` from the live `QuestItemTemplate` (pin §3) — so
|
||
this mirrors the ref's own duplication, not just an engine workaround. Keep the two shapes in
|
||
sync by hand if either is revisited.
|
||
-->
|
||
<Button name="QuestLogRewardItemTemplate" virtual="true" hidden="true">
|
||
<!-- Ref-verbatim geometry (QuestFrameTemplates.xml:85-138): a bare 39×39 icon at TOPLEFT
|
||
(no slot-well texture behind it — the earlier `UI-EmptySlot` here was our own addition
|
||
and read as a heavy black box on the parchment), the name plate overlapping the icon's
|
||
right edge by 10, and the name in GameFontHighlight (12px — not the Small variant). -->
|
||
<Size><AbsDimension x="147" y="41"/></Size>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="$parentIconTexture">
|
||
<Size><AbsDimension x="39" y="39"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
</Texture>
|
||
<Texture name="$parentNameFrame" file="Interface\QuestFrame\UI-QuestItemNameFrame">
|
||
<Size><AbsDimension x="128" y="64"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentIconTexture" relativePoint="RIGHT"><Offset><AbsDimension x="-10" y="0"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<FontString name="$parentName" inherits="GameFontHighlight" justifyH="LEFT">
|
||
<Size><AbsDimension x="90" y="36"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentNameFrame"><Offset><AbsDimension x="15" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
<Layer level="ARTWORK">
|
||
<FontString name="$parentCount" inherits="NumberFontNormal" justifyH="RIGHT">
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativeTo="$parentIconTexture"><Offset><AbsDimension x="-4" y="1"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<!-- No HighlightTexture: the ref QuestLogRewardItemTemplate (QuestLogFrame.xml:108-123)
|
||
adds only tooltip/click scripts to QuestItemTemplate — reward rows never glow on
|
||
hover, exactly like the giver window's twin template. -->
|
||
<Scripts>
|
||
<OnLoad>
|
||
local n = self:GetName()
|
||
self.icon = getglobal(n .. "IconTexture")
|
||
self.name = getglobal(n .. "Name")
|
||
self.count = getglobal(n .. "Count")
|
||
</OnLoad>
|
||
<!-- The shared id-keyed item tooltip (ref QuestLogRewardItemTemplate OnEnter →
|
||
GameTooltip:SetQuestLogItem — the same C++ renderer every item hover uses). -->
|
||
<OnEnter>
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetItemById(self.itemId, self.name:GetText(), self.quality)
|
||
GameTooltip:Show()
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
<!-- ref QuestLogRewardItemTemplate's own OnClick (ref QuestLogFrame.xml:118-120): the
|
||
CTRL dressing-room preview + the SHIFT chat-link post, and nothing else — a plain
|
||
click on a quest-log reward row is inert (decisions 1059/1060). -->
|
||
<OnClick>QuestLogRewardItem_OnClick()</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<!--
|
||
One list row (pin §2's QuestLogTitleButtonTemplate, QuestLogFrame.xml:4-107, ~300×16). Text
|
||
lives on a NAMED `$parentText` FontString (not the auto ButtonText slot — same convention
|
||
`GossipFrame.xml`'s `GossipTitleButtonTemplate` uses for its `$parentLabel`), so it can carry
|
||
an explicit LEFT justify. The tag rides its own right-flush `$parentTag` string, as the
|
||
ref's does — see that FontString's own comment, and `BenillaQuestLogList_Update` for the
|
||
one thing the ref does with it that we don't (the title width cap).
|
||
State art is now ref-verbatim (QuestLogTitleButtonTemplate, ref QuestLogFrame.xml:68-107):
|
||
the 16x16 plus/minus fold icon slot at LEFT+3 is the button's NormalTexture (the Lua swaps
|
||
Plus/Minus per header fold state and CLEARS it on quest rows — SetNormalTexture("")), the
|
||
16x16 UI-PlusButton-Hilight at the same spot is the ONLY hover art (quest rows clear it
|
||
too — the ref has NO row-wide hover glow), and the text starts at LEFT+20 (the real
|
||
indent; quest rows add the ref's own two-space prefix on top). The PERSISTENT selection bar
|
||
is the separate `QuestLogHighlightFrame` frame `BenillaQuestLogList_Update` moves.
|
||
|
||
`$parentCheck` (pin §2, ref `QuestLogFrame.xml:34-45`) is the per-row watch checkbox — a 16×16
|
||
`UI-CheckBox-Check`, no `file=` here (where the ref uses `hidden="true"`): it starts with
|
||
NO texture bound and is entirely SetTexture-driven from first paint. That shape dates from
|
||
before Texture regions had Show/Hide; `region.rs` has the real pair now and the loader
|
||
honours `hidden=` on regions, so the ref's exact shape is available here if this ever wants
|
||
it — the bind-driven form works and is left alone. SEAT (the director's
|
||
ref A/B — the first build parked it in a left gutter): the ref places the check just past
|
||
the TITLE'S INK — `QuestLog.lua:211/224` computes `LEFT of the row + dummyTextWidth + 24`,
|
||
and with the ref's text inset of 20 that nets to `ink end + 4`. We get the same geometry
|
||
from the anchor graph instead of the Lua dummy-measure hack: the title FontString is
|
||
width-less (its resolved rect hugs its host-measured ink — the measure round-trip), and
|
||
the check anchors LEFT → the title's RIGHT at +4. That IS the ref's seat: its
|
||
`textWidth+24` off the row's left, with `textWidth` the un-capped title ink, is ink-end + 4
|
||
given the 20-unit text inset — the ref only computes it because its own `GetWidth` returns
|
||
whatever width it last capped the title to.
|
||
-->
|
||
<Button name="QuestLogTitleButtonTemplate" virtual="true" hidden="true">
|
||
<Size><AbsDimension x="300" y="16"/></Size>
|
||
<Layers>
|
||
<Layer level="ARTWORK">
|
||
<FontString name="$parentText" inherits="GameFontNormal" justifyH="LEFT">
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="20" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- The quest TAG (ref QuestLogFrame.xml:10-21, verbatim geometry): a right-flush
|
||
GameFontNormal string at RIGHT-2, height 16, width 0 so it hugs its own ink.
|
||
It carries "(Elite)"/"(Dungeon)"/"(Raid)"/"(PvP)" — and the Complete/Failed
|
||
state, which in the reference rides this same string, not the title. Sits in
|
||
ARTWORK beside the title (the ref parks it in BACKGROUND, where its own title
|
||
is the Button's ButtonText slot rather than a layer region — ours is a named
|
||
FontString, so the two live in one layer). -->
|
||
<FontString name="$parentTag" inherits="GameFontNormal" justifyH="RIGHT">
|
||
<Size><AbsDimension x="0" y="16"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativePoint="RIGHT"><Offset><AbsDimension x="-2" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<Texture name="$parentCheck">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="$parentText" relativePoint="RIGHT"><Offset><AbsDimension x="4" y="0"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<NormalTexture file="Interface\Buttons\UI-MinusButton-UP">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</NormalTexture>
|
||
<HighlightTexture name="$parentHighlight" file="Interface\Buttons\UI-PlusButton-Hilight" alphaMode="ADD">
|
||
<Size><AbsDimension x="16" y="16"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="3" y="0"/></Offset></Anchor></Anchors>
|
||
</HighlightTexture>
|
||
<Scripts>
|
||
<OnLoad>
|
||
self.text = getglobal(self:GetName() .. "Text")
|
||
self.tag = getglobal(self:GetName() .. "Tag")
|
||
self.check = getglobal(self:GetName() .. "Check")
|
||
-- Via the state-texture getter (era API), not getglobal: the loader doesn't yet
|
||
-- publish a named state texture's `name=` as a global (known gap — Layers regions
|
||
-- publish, state slots don't).
|
||
self.foldHighlight = self:GetHighlightTexture()
|
||
-- Both buttons must reach OnClick (the default set is LeftButtonUp only) — the same
|
||
-- convention the reference's own `BankFrameBaseButton_OnLoad` uses for its left/right split.
|
||
self:RegisterForClicks("LeftButtonUp", "RightButtonUp")
|
||
</OnLoad>
|
||
<OnClick>BenillaQuestLogTitle_OnClick(self, arg1)</OnClick>
|
||
</Scripts>
|
||
</Button>
|
||
|
||
<!-- A panel action button (Abandon/Exit/Yes/No) — the UIPanelButtonTemplate face from
|
||
`QuestFrame.xml`'s `BenillaQuestPanelButtonTemplate`, duplicated for the same per-window
|
||
test-isolation reason as `QuestLogRewardItemTemplate` above. UNLIKE the giver window's
|
||
template this one is NOT hidden="true": the giver's panel-switch Lua re-Show()s each
|
||
panel's pair every switch, but this window's Abandon/Exit are always-visible chrome (ref
|
||
QuestLogFrame.xml:451/482) with no code path that would ever Show() them — inheriting
|
||
hidden left them invisible (0109 look fix; caught on the ui-questlog capture). -->
|
||
<Button name="BenillaQuestLogPanelButtonTemplate" virtual="true">
|
||
<Size><AbsDimension x="80" y="22"/></Size>
|
||
<NormalFont inherits="GameFontNormal"/>
|
||
<HighlightFont inherits="GameFontHighlight"/>
|
||
<DisabledFont inherits="GameFontDisable"/>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-Button-Up"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></NormalTexture>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-Button-Down"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></PushedTexture>
|
||
<DisabledTexture file="Interface\Buttons\UI-Panel-Button-Disabled"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></DisabledTexture>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-Button-Highlight" alphaMode="ADD"><TexCoords left="0" right="0.625" top="0" bottom="0.6875"/></HighlightTexture>
|
||
</Button>
|
||
|
||
<Frame name="QuestLogFrame" enableMouse="true" toplevel="true" parent="UIParent" hidden="true">
|
||
<!-- The real 384×512 window (pin §1). No <Anchors> — ShowUIPanel/SetLeftFrame SetPoints this
|
||
to the left slot on open, exactly like Gossip/Merchant/Quest. -->
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<!-- pin §1: 64×64 book icon, TOPLEFT (4,-4). -->
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-BookIcon">
|
||
<Size><AbsDimension x="64" y="64"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="4" y="-4"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
<Layer level="ARTWORK">
|
||
<!-- pin §1: the four book-panel quadrants, each pinned to its corner, whole-texture. -->
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-TopLeft"><Size><AbsDimension x="256" y="256"/></Size><Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors></Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-TopRight"><Size><AbsDimension x="128" y="256"/></Size><Anchors><Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"/></Anchors></Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-BotLeft"><Size><AbsDimension x="256" y="256"/></Size><Anchors><Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT"/></Anchors></Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-BotRight"><Size><AbsDimension x="128" y="256"/></Size><Anchors><Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"/></Anchors></Texture>
|
||
|
||
<!-- pin §1: title, TOP (0,-15), GameFontHighlight, text token QUEST_LOG → "Quest Log". -->
|
||
<FontString name="QuestLogTitleText" inherits="GameFontHighlight" justifyH="CENTER" text="Quest Log">
|
||
<Anchors><Anchor point="TOP" relativePoint="TOP"><Offset><AbsDimension x="0" y="-15"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- pin §1, geometry/art byte-for-byte (ref QuestLogFrame.xml:204-243): the quest-count
|
||
pill is the Common-Input-Border 3-texture trio + a FontString RIGHT of the right
|
||
piece — REPLACING this window's old bare text at (-30,-16), which sat inside the
|
||
close X's hit area and visually collided with it. -->
|
||
<Texture name="QuestLogCountRight" file="Interface\Common\Common-Input-Border">
|
||
<Size><AbsDimension x="8" y="20"/></Size>
|
||
<Anchors><Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-47" y="-41"/></Offset></Anchor></Anchors>
|
||
<TexCoords left="0.9375" right="1.0" top="0" bottom="0.625"/>
|
||
</Texture>
|
||
<Texture name="QuestLogCountMiddle" file="Interface\Common\Common-Input-Border">
|
||
<Size><AbsDimension x="100" y="20"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativeTo="QuestLogCountRight" relativePoint="LEFT"/></Anchors>
|
||
<TexCoords left="0.0625" right="0.9375" top="0" bottom="0.625"/>
|
||
</Texture>
|
||
<Texture name="QuestLogCountLeft" file="Interface\Common\Common-Input-Border">
|
||
<Size><AbsDimension x="8" y="20"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativeTo="QuestLogCountMiddle" relativePoint="LEFT"/></Anchors>
|
||
<TexCoords left="0" right="0.0625" top="0" bottom="0.625"/>
|
||
</Texture>
|
||
<FontString name="QuestLogQuestCount" inherits="GameFontNormalSmall" justifyH="RIGHT">
|
||
<Anchors><Anchor point="RIGHT" relativeTo="QuestLogCountRight" relativePoint="RIGHT"><Offset><AbsDimension x="-6" y="0"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- Detail page (pin §3): NOW lives on `QuestLogDetailScrollChildFrame`, a real
|
||
ScrollFrame's scroll child (`QuestLogDetailScrollFrame`, below in this window's
|
||
own `<Frames>`) — the 0088 §2 flat-frame constraint this file used to quote here
|
||
DIED with the 0112 resolver fixpoint (child frames render their own `<Layers>`
|
||
regions again), so the whole chain (QuestTitle → ItemReceiveText, the choice/
|
||
reward Buttons, the money coins) moved there verbatim; only the FIRST element's
|
||
anchor changed (the child's own TOPLEFT, ref :624-635's offset 5,-5 — see the
|
||
child's own comment). Nothing detail-page-shaped remains in this window's own
|
||
`<Layers>`. -->
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- pin §1: the top-right close X (UIPanelCloseButton in the ref; our engine ships no such
|
||
template — QuestFrame.xml/BagFrame.xml already draw it by hand on the same art). -->
|
||
<Button name="QuestLogFrameCloseButton">
|
||
<Size><AbsDimension x="32" y="32"/></Size>
|
||
<Anchors><Anchor point="TOPRIGHT" relativePoint="TOPRIGHT"><Offset><AbsDimension x="-30" y="-8"/></Offset></Anchor></Anchors>
|
||
<NormalTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Up"/>
|
||
<PushedTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Down"/>
|
||
<HighlightTexture file="Interface\Buttons\UI-Panel-MinimizeButton-Highlight" alphaMode="ADD"/>
|
||
<Scripts><OnClick>BenillaQuestLogCloseButton_OnClick()</OnClick></Scripts>
|
||
</Button>
|
||
|
||
<!-- The "All" fold-all tab (ref QuestLogExpandButtonFrame/QuestLogCollapseAllButton,
|
||
QuestLogFrame.xml:247-323): the sort-tab art trio behind a row-template button at
|
||
(70,-48) — its own +/- NormalTexture slot doubles as the all-state icon. The ref's
|
||
sibling "Track Quest" checkbox (QuestLogTrack) is a named deferral: our watch
|
||
toggle is the row right-click until the track-checkbox arc lands. -->
|
||
<Frame name="QuestLogExpandButtonFrame">
|
||
<Size><AbsDimension x="54" y="32"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="70" y="-48"/></Offset></Anchor></Anchors>
|
||
<Frames>
|
||
<Button name="QuestLogCollapseAllButton" inherits="QuestLogTitleButtonTemplate" hidden="false" text="All">
|
||
<Size><AbsDimension x="40" y="22"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture name="QuestLogExpandTabLeft" file="Interface\QuestFrame\UI-QuestLogSortTab-Left">
|
||
<Size><AbsDimension x="8" y="32"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="-6" y="8"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture name="QuestLogExpandTabMiddle" file="Interface\QuestFrame\UI-QuestLogSortTab-Middle">
|
||
<Size><AbsDimension x="38" y="32"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="QuestLogExpandTabLeft" relativePoint="RIGHT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLogSortTab-Right">
|
||
<Size><AbsDimension x="8" y="32"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativeTo="QuestLogExpandTabMiddle" relativePoint="RIGHT"/></Anchors>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnClick>QuestLogCollapseAllButton_OnClick()</OnClick>
|
||
</Scripts>
|
||
<!-- The tab label sits beside its own +/- icon slot (the ref row template's
|
||
ButtonText geometry: LEFT+20 next to the 16px icon at LEFT+3), gold —
|
||
the engine's default label centered "All" OVER the icon (director's
|
||
img-12 misalignment). -->
|
||
<ButtonText>
|
||
<Size><AbsDimension x="0" y="10"/></Size>
|
||
<Anchors><Anchor point="LEFT" relativePoint="LEFT"><Offset><AbsDimension x="20" y="0"/></Offset></Anchor></Anchors>
|
||
</ButtonText>
|
||
<NormalFont inherits="GameFontNormal" justifyH="LEFT"/>
|
||
<HighlightFont inherits="GameFontHighlight" justifyH="LEFT"/>
|
||
</Button>
|
||
</Frames>
|
||
</Frame>
|
||
|
||
<!-- The "Track Quest" watch indicator (ref QuestLogTrack, QuestLogFrame.xml:324-369):
|
||
an INDICATOR, not a button — the 20×20 UI-RadioButton pair (base = the left
|
||
quarter, the dot = the second quarter) with the dot vertex-colored by
|
||
`QuestWatch_Update`: red when nothing is watched, green when ≥1 is (ref
|
||
`QuestWatch_Update`'s tracking-indicator tail). Watching itself stays the row
|
||
shift-click (`QUEST_WATCH_TOOLTIP`, served on hover). Ref HitRectInsets
|
||
(right −80, stretching the hover over the label) is an engine gap — the hover
|
||
rect is the 20×20 dot only. -->
|
||
<Frame name="QuestLogTrack" enableMouse="true">
|
||
<Size><AbsDimension x="20" y="20"/></Size>
|
||
<Anchors>
|
||
<Anchor point="LEFT" relativeTo="QuestLogExpandButtonFrame" relativePoint="RIGHT">
|
||
<Offset><AbsDimension x="5" y="10"/></Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<FontString name="$parentTitle" inherits="GameFontHighlightSmall" text="Track Quest">
|
||
<Anchors><Anchor point="LEFT" relativePoint="RIGHT"/></Anchors>
|
||
</FontString>
|
||
<Texture file="Interface\Buttons\UI-RadioButton">
|
||
<TexCoords left="0" right="0.25" top="0" bottom="1"/>
|
||
</Texture>
|
||
<Texture name="QuestLogTrackTracking" file="Interface\Buttons\UI-RadioButton">
|
||
<TexCoords left="0.25" right="0.5" top="0" bottom="1"/>
|
||
</Texture>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>
|
||
getglobal("QuestLogTrackTracking"):SetVertexColor(1.0, 0, 0)
|
||
</OnLoad>
|
||
<OnEnter>
|
||
GameTooltip:SetOwner(self, "ANCHOR_RIGHT")
|
||
GameTooltip:SetText("Shift-click a quest to add or remove a quest from your quest watch list.", nil, nil, nil, nil, 1)
|
||
</OnEnter>
|
||
<OnLeave>
|
||
GameTooltip:Hide()
|
||
</OnLeave>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
<!-- The persistent selection highlight (ref QuestLogHighlightFrame, QuestLogFrame.xml:
|
||
522-534): 293×16, ARTWORK-layer ADD `UI-QuestLogTitleHighlight`, declared BEFORE the
|
||
title rows so the row text paints OVER the glow (same parent + same frameLevel ⇒
|
||
declaration order is the z-tiebreak; the old `frameLevel="8"` put the glow ON TOP of
|
||
the title text and washed it out — 0112's capture gate caught the wash, this scrub
|
||
found the cause). Moved onto the selected row (at the ref's (5,0)) and vertex-colored
|
||
to the row's difficulty color by `BenillaQuestLogList_Update` (ref lua l.337-339). -->
|
||
<Frame name="QuestLogHighlightFrame" hidden="true">
|
||
<Size><AbsDimension x="293" y="16"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
<Layers><Layer level="ARTWORK">
|
||
<Texture name="QuestLogSkillHighlight" file="Interface\QuestFrame\UI-QuestLogTitleHighlight" alphaMode="ADD">
|
||
<Anchors><Anchor point="TOPLEFT"/><Anchor point="BOTTOMRIGHT"/></Anchors>
|
||
</Texture>
|
||
</Layer></Layers>
|
||
</Frame>
|
||
|
||
<!-- pin §2, geometry byte-for-byte (ref QuestLogFrame.xml:535-588): 6 title rows,
|
||
300×16, row1 TOPLEFT of the frame at (19,-75); rows 2-6 chain TOPLEFT→prior BOTTOMLEFT
|
||
at (0,+1) — a TIGHT 1px OVERLAP, not a gap (the ref's own offset is positive). -->
|
||
<!-- ref l.291-307. The list's real faux-scroll frame: an invisible container over the
|
||
6 title rows whose right-hand Slider is the only part that draws, sized to the row
|
||
span and anchored where row 1 starts (SkillFrame.xml's own convention). It replaces
|
||
a `questLogOffset` upvalue this file kept "because no real ScrollFrame/
|
||
FauxScrollFrame engine exists yet" — long false, and the reason this window
|
||
published no QuestLogListScrollFrame for addons to find. -->
|
||
<ScrollFrame name="QuestLogListScrollFrame" inherits="FauxScrollFrameTemplate">
|
||
<Size><AbsDimension x="300" y="93"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="19" y="-75"/></Offset></Anchor></Anchors>
|
||
<Scripts>
|
||
<OnVerticalScroll>
|
||
FauxScrollFrame_OnVerticalScroll(QUESTLOG_QUEST_HEIGHT, BenillaQuestLogList_Update)
|
||
</OnVerticalScroll>
|
||
</Scripts>
|
||
</ScrollFrame>
|
||
|
||
<Button name="QuestLogTitle1" inherits="QuestLogTitleButtonTemplate" id="1">
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="19" y="-75"/></Offset></Anchor></Anchors>
|
||
</Button>
|
||
<Button name="QuestLogTitle2" inherits="QuestLogTitleButtonTemplate" id="2"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogTitle1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="QuestLogTitle3" inherits="QuestLogTitleButtonTemplate" id="3"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogTitle2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="QuestLogTitle4" inherits="QuestLogTitleButtonTemplate" id="4"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogTitle3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="QuestLogTitle5" inherits="QuestLogTitleButtonTemplate" id="5"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogTitle4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors></Button>
|
||
<Button name="QuestLogTitle6" inherits="QuestLogTitleButtonTemplate" id="6"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogTitle5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="1"/></Offset></Anchor></Anchors></Button>
|
||
|
||
<!-- The detail pane's real ScrollFrame (decision 0112's mechanism): 300×261, TOPLEFT of
|
||
this window at (19,-175) — the ref's own `QuestLogDetailScrollFrame` position, this
|
||
file's "Detail chain start" arithmetic that used to live above (list bottom-left
|
||
(19,-168) - 7 = (19,-175)). Mouse-wheel-interactive by construction
|
||
(`widget/mod.rs`'s ScrollFrame ctor comment), so a spin inside its own rect is taken
|
||
here and scrolling the detail text no longer scrolls the LIST underneath it — a
|
||
latent mix-up the flat layout had no way to avoid. It needs no declaration-order
|
||
trick to win that: nothing else in this window's bucket covers the detail rect. -->
|
||
<ScrollFrame name="QuestLogDetailScrollFrame" inherits="UIPanelScrollFrameTemplate">
|
||
<Size><AbsDimension x="300" y="261"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="19" y="-175"/></Offset></Anchor></Anchors>
|
||
<ScrollChild>
|
||
<!-- The scroll child (`SetScrollChild`'d in this ScrollFrame's own OnLoad below):
|
||
300 wide, matching the ref's `QuestLogDetailScrollChildFrame`; HEIGHT is
|
||
runtime-set by `BenillaQuestLogDetail_ResizeChild` (a Frame's height is only
|
||
ever its own SetSize — the resolver never grows one to fit overflowing
|
||
content, that function's own comment) — 261 here is just a sane starting size
|
||
before the first Detail_Update ever runs. Every widget below is the SAME
|
||
detail chain this window used to carry flat on itself (this window's own
|
||
"Detail page" comment) — only QuestTitle's own anchor changed, to the CHILD's
|
||
TOPLEFT (ref :624-635's offset 5,-5) now that it's the origin of its own
|
||
subtree; everything downstream still chains by NAME exactly as before (anchor
|
||
resolution is name-keyed, not parent-scoped — unaffected by which frame owns
|
||
which region). -->
|
||
<Frame name="QuestLogDetailScrollChildFrame">
|
||
<Size><AbsDimension x="300" y="261"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"/></Anchors>
|
||
<Layers>
|
||
<Layer level="ARTWORK">
|
||
<FontString name="QuestLogQuestTitle" inherits="QuestTitleFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="285" y="0"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativePoint="TOPLEFT"><Offset><AbsDimension x="5" y="-5"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<FontString name="QuestLogObjectivesText" inherits="QuestFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="275" y="0"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogQuestTitle" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-5"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- The timed-quest countdown row (decision 1150) — the ref's QuestLogTimerText,
|
||
QuestLogFrame.xml:648-659, at its own anchor and offset. Untimed quests are the
|
||
overwhelming majority, so the row must cost them NOTHING: the ref hides it and
|
||
re-SetPoints Objective1 straight onto ObjectivesText (QuestLogFrame.lua:370/374),
|
||
and `BenillaQuestLogDetail_Update` keeps exactly that pair of branches. Our
|
||
region model has no Show/Hide for a bare FontString (the recurring comment
|
||
below), so the untimed case leaves this string EMPTY — it draws nothing, and
|
||
nothing anchors through it, so its 12px sits harmlessly behind Objective1's row
|
||
rather than displacing anything. -->
|
||
<FontString name="QuestLogTimerText" inherits="QuestFontNormalSmall" justifyH="LEFT">
|
||
<Size><AbsDimension x="285" y="12"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjectivesText" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-10"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- No `hidden=` on these 10 (a no-op on a region anyway — same reasoning as the
|
||
empty-state text above): each starts textless (no `text=` attribute) and stays
|
||
that way until `BenillaQuestLogDetail_Update` fills the ones in use.
|
||
Objective1's XML anchor is the UNTIMED one (straight onto ObjectivesText) rather
|
||
than the ref's static hop through the timer row, because in this engine that
|
||
row cannot be hidden — the timed branch re-SetPoints it through
|
||
QuestLogTimerText, which is the ref's own runtime behaviour either way
|
||
(QuestLogFrame.lua:370/374; only the XML seed differs, and the ref re-points it
|
||
on every populate before anything is drawn).
|
||
|
||
Height is EXPLICIT 12 (GameFontNormalSmall is 10px, `Fonts.xml`), NOT the ref's
|
||
auto "y=0" — a deliberate v1 deviation: a FontString anchored by a single point
|
||
with an explicit height of exactly 0 and no text ever measured (this engine only
|
||
host-measures a FontString with non-empty text — `UiScript::fontstrings_needing_
|
||
measure`'s own doc) resolves its far edge to `combine_edge`'s span==0 branch,
|
||
which is UNSET, so `resolve()`'s region pass falls the WHOLE unconstrained edge
|
||
back to the OWNER FRAME's edge (`script/mod.rs`'s region-resolution comment) —
|
||
not "zero height", the owner's own far edge. The ref's own equivalent never sees
|
||
this: it :Hide()s unused objective strings entirely (pin §3, QuestLogFrame.lua:
|
||
400-402) — Show/Hide aside — and presumably never lets an anchored-through
|
||
FontString sit at a true zero measured height. This engine's region model has no
|
||
Show/Hide for a bare FontString (this file's own recurring comment on
|
||
`region.rs`), so hiding isn't an option; a fixed nonzero height is the narrowest
|
||
fix that keeps the WHOLE ref chain verbatim. Blank slots now occupy a small
|
||
fixed 12px instead of true 0 — an accepted, minor v1 footprint difference from
|
||
the ref, not a fidelity claim (and exactly why `BenillaQuestLogDetail_ResizeChild`
|
||
sums this fixed 12px per row rather than measuring these ten). -->
|
||
<FontString name="QuestLogObjective1" inherits="QuestFontNormalSmall" justifyH="LEFT">
|
||
<Size><AbsDimension x="285" y="12"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjectivesText" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-10"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<FontString name="QuestLogObjective2" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective3" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective4" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective5" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective6" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective7" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective8" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective9" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective8" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestLogObjective10" inherits="QuestFontNormalSmall" justifyH="LEFT"><Size><AbsDimension x="285" y="12"/></Size><Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjective9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-2"/></Offset></Anchor></Anchors></FontString>
|
||
|
||
<!-- Verbatim ref chain continues (QuestLogFrame.xml:785-833), EXCEPT
|
||
`QuestLogDescriptionTitle` itself: the ref does NOT anchor its
|
||
`QuestLogDescriptionTitle` to a static `QuestLogObjective10` — it re-`SetPoint`s
|
||
it at RUNTIME in `QuestLog_UpdateQuestDetails` off the LAST *actually used*
|
||
objective slot (`QuestLogFrame.lua:414-424`: `QuestLogObjective`..numObjectives,
|
||
or `QuestLogObjectivesText` when numObjectives is 0 — there's also a
|
||
RequiredMoney branch we don't model, this file's documented v1 gap).
|
||
`BenillaQuestLogDetail_Update` ports the ref's runtime SetPoint; the anchor
|
||
below is a load-bearing-free PLACEHOLDER (immediately overwritten whenever a
|
||
selection exists) — same convention the reward/choice Buttons use. Height
|
||
stays EXPLICIT 18 (QuestTitleFont, `Fonts.xml` — matching `RewardTitleText`'s
|
||
own explicit 18 below, which the ref ITSELF gives a nonzero height): the same
|
||
zero-height-owner-fallback rationale as the Objective slots above applies
|
||
whenever the log has zero rewards+choices+money (`RewardTitleText` blanks to ""
|
||
too) — this header must resolve a real span regardless of its own text (and is
|
||
why `BenillaQuestLogDetail_ResizeChild` sums a fixed 18 for it too, never
|
||
`GetHeight()`). -->
|
||
<FontString name="QuestLogDescriptionTitle" inherits="QuestTitleFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="285" y="18"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogObjectivesText" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-10"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<FontString name="QuestLogQuestDescription" inherits="QuestFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="270" y="0"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogDescriptionTitle" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-5"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- No `text=`/`hidden=` — `BenillaQuestLogRewards_Update` owns this text entirely
|
||
(toggles "Rewards" / "" — this file's blank-text convention). -->
|
||
<FontString name="QuestLogRewardTitleText" inherits="QuestTitleFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="300" y="18"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogQuestDescription" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-15"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- REWARD_CHOICES (ref QuestLogFrame.xml:821-832) — our literal transcription of the
|
||
token's string. Lua-managed (`BenillaQuestLogRewards_Update` toggles the text). -->
|
||
<FontString name="QuestLogItemChooseText" inherits="QuestFont" justifyH="LEFT">
|
||
<Size><AbsDimension x="295" y="0"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogRewardTitleText" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-5"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
<!-- QuestLogItemReceiveText (ref :833-837) — unlike the ref's own bare `<Anchor
|
||
point="TOPLEFT"/>` (it's entirely SetPoint-driven at runtime, QuestFrame.lua:
|
||
460/467/470), `BenillaQuestLogRewards_Update` re-SetPoints this one too — see that
|
||
function. No static `relativeTo` here is load-bearing, only a safe placeholder. -->
|
||
<FontString name="QuestLogItemReceiveText" inherits="QuestFont" justifyH="LEFT">
|
||
<Anchors><Anchor point="TOPLEFT" relativeTo="QuestLogRewardTitleText" relativePoint="BOTTOMLEFT"/></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Frames>
|
||
<!-- Choice + fixed reward rows (pin §3/§6). Static XML anchors below are placeholders
|
||
ONLY (bare TOPLEFT-of-parent-ish, never read while hidden) —
|
||
`BenillaQuestLogRewards_Update` SetPoints every shown row every repaint, porting
|
||
`QuestFrameItems_Update`'s own SetPoint math verbatim (QuestFrame.lua:311-522,
|
||
cited per-line in that function). -->
|
||
<!-- ONE pool of 10, the ref's own (ref l.837-887): the detail page packs CHOICES,
|
||
then the reward-spell row, then FIXED rewards into a single numbered run and
|
||
positions each at runtime, so every row carries a bare TOPLEFT anchor. This was
|
||
two static 6-deep pools (QuestLogChoice*/QuestLogReward*), names the reference
|
||
does not have; pfUI's skins/blizzard/questlog.lua l.219-224 walks QuestLogItem
|
||
1..6 and indexes :GetWidth() unguarded. -->
|
||
<Button name="QuestLogItem1" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem2" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem3" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem4" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem5" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem6" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem7" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem8" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem9" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
<Button name="QuestLogItem10" inherits="QuestLogRewardItemTemplate"><Anchors><Anchor point="TOPLEFT"/></Anchors></Button>
|
||
|
||
<!-- Reward money (pin §3, GetQuestLogRewardMoney) — ref QuestLogMoneyFrame anchors LEFT
|
||
to QuestLogItemReceiveText's RIGHT, offset (15,0) (QuestLogFrame.xml:896-903). -->
|
||
<!-- ref QuestLogFrame.xml:896-906, and the reference's own NAME: one MoneyFrameTemplate at the
|
||
same LEFT->QuestLogItemReceiveText RIGHT (15,0) seat our Coin1 used. Its OnLoad is the
|
||
reference's QuestMoneyFrame_OnLoad (QuestFrame.lua:306, in our QuestFrame.xml — manifest 960,
|
||
above this file at 987). Retires QuestLogMoneyCoin1..3 (1937). -->
|
||
<Frame name="QuestLogMoneyFrame" inherits="MoneyFrameTemplate">
|
||
<Anchors><Anchor point="LEFT" relativeTo="QuestLogItemReceiveText" relativePoint="RIGHT"><Offset><AbsDimension x="15" y="0"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnLoad>QuestMoneyFrame_OnLoad()</OnLoad></Scripts>
|
||
</Frame>
|
||
</Frames>
|
||
</Frame>
|
||
</ScrollChild>
|
||
</ScrollFrame>
|
||
|
||
<!-- ref l.370-440. The empty-log page: four `UI-QuestLog-Empty-*` slabs and the
|
||
"no quests" line, shown as ONE frame when the log is empty and hidden otherwise
|
||
(ref QuestLogFrame.lua l.108-119). This window used to carry only the FontString,
|
||
loose on its own Layers and blanked with SetText("") — the simplification the
|
||
header called "pin §2's EmptyQuestLogFrame, simplified". pfUI's
|
||
`skins/blizzard/questlog.lua` l.118-131 strips it, hooks its OnShow/OnHide, and
|
||
drives its own expand button off them, so the FRAME is the contract, not the text. -->
|
||
<Frame name="EmptyQuestLogFrame" hidden="true">
|
||
<Size><AbsDimension x="384" y="512"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"><Offset><AbsDimension x="19" y="-73"/></Offset></Anchor></Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-Empty-TopLeft">
|
||
<Size><AbsDimension x="256" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-Empty-TopRight">
|
||
<Size><AbsDimension x="64" y="256"/></Size>
|
||
<Anchors><Anchor point="TOPRIGHT"><Offset><AbsDimension x="-64" y="0"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-Empty-BotLeft">
|
||
<Size><AbsDimension x="256" y="128"/></Size>
|
||
<Anchors><Anchor point="BOTTOMLEFT"><Offset><AbsDimension x="0" y="128"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<Texture file="Interface\QuestFrame\UI-QuestLog-Empty-BotRight">
|
||
<Size><AbsDimension x="64" y="128"/></Size>
|
||
<Anchors><Anchor point="BOTTOMRIGHT"><Offset><AbsDimension x="-64" y="128"/></Offset></Anchor></Anchors>
|
||
</Texture>
|
||
<FontString name="QuestLogNoQuestsText" inherits="GameFontHighlight" text="Your quest log is empty.">
|
||
<Size><AbsDimension x="200" y="16"/></Size>
|
||
<Anchors><Anchor point="TOP" relativeTo="QuestLogTitleText"><Offset><AbsDimension x="-20" y="-90"/></Offset></Anchor></Anchors>
|
||
</FontString>
|
||
</Layer>
|
||
</Layers>
|
||
</Frame>
|
||
|
||
<!-- pin §4, geometry byte-for-byte (ref QuestLogFrame.xml:451-498): Abandon 125×21 at
|
||
(17,54), Exit 77×21 at (-43,54). numEntries==0 disables Abandon. -->
|
||
<Button name="QuestLogFrameAbandonButton" inherits="BenillaQuestLogPanelButtonTemplate" text="Abandon Quest">
|
||
<Size><AbsDimension x="125" y="21"/></Size>
|
||
<Anchors><Anchor point="BOTTOMLEFT" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="17" y="54"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>BenillaQuestLogAbandonButton_OnClick()</OnClick></Scripts>
|
||
</Button>
|
||
<Button name="QuestFrameExitButton" inherits="BenillaQuestLogPanelButtonTemplate" text="Exit">
|
||
<Size><AbsDimension x="77" y="21"/></Size>
|
||
<Anchors><Anchor point="BOTTOMRIGHT" relativePoint="BOTTOMRIGHT"><Offset><AbsDimension x="-43" y="54"/></Offset></Anchor></Anchors>
|
||
<Scripts><OnClick>HideUIPanel(getglobal("QuestLogFrame"))</OnClick></Scripts>
|
||
</Button>
|
||
<!-- Share Quest (ref QuestFramePushQuestButton, QuestLogFrame.xml:499-521): 123×21 flush
|
||
LEFT of Exit. Live since decision 1733; it starts DISABLED because that is the
|
||
solo/no-selection state the ref's own predicate produces, and
|
||
BenillaQuestLogPushButton_Update re-tests it on every list update and every
|
||
PARTY_MEMBERS_CHANGED. The newbie tooltip is the ref's (NEWBIE_TOOLTIP_SHAREQUEST,
|
||
GlobalStrings.lua:2764), through the same GameTooltip_AddNewbieTip the ref calls. -->
|
||
<Button name="QuestFramePushQuestButton" inherits="BenillaQuestLogPanelButtonTemplate" text="Share Quest">
|
||
<Size><AbsDimension x="123" y="21"/></Size>
|
||
<Anchors><Anchor point="RIGHT" relativeTo="QuestFrameExitButton" relativePoint="LEFT"/></Anchors>
|
||
<Scripts>
|
||
<OnLoad>self:Disable()</OnLoad>
|
||
<OnClick>QuestLogPushQuest()</OnClick>
|
||
<OnEnter>
|
||
if GameTooltip_AddNewbieTip then
|
||
GameTooltip_AddNewbieTip(SHARE_QUEST, 1.0, 1.0, 1.0, NEWBIE_TOOLTIP_SHAREQUEST, 1)
|
||
end
|
||
</OnEnter>
|
||
<OnLeave>GameTooltip:Hide()</OnLeave>
|
||
</Scripts>
|
||
</Button>
|
||
</Frames>
|
||
<Scripts>
|
||
<OnLoad>BenillaQuestLogFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaQuestLogFrame_OnEvent(self)</OnEvent>
|
||
<!-- The countdown's own repaint (ref QuestLog_OnUpdate, QuestLogFrame.lua:96-105) —
|
||
the ONLY thing the ref's window OnUpdate does. Gated on hasTimer, so it costs an
|
||
untimed selection nothing, and gated on the window being effectively visible by
|
||
`UiScript::tick`'s own OnUpdate gate, so it costs a closed window nothing. -->
|
||
<OnUpdate>QuestLog_OnUpdate(arg1)</OnUpdate>
|
||
<!-- The list wheel lives on the WINDOW: the engine bubbles a spin up the PARENT chain
|
||
(script/pointer.rs mouse_wheel), so a spin over a quest-title row (no OnMouseWheel of
|
||
its own) reaches this window and scrolls. That is the whole mechanism — a sibling
|
||
frame could never serve it anyway, since bubbling reaches ancestors, not siblings.
|
||
(The detail ScrollFrame keeps its own OnMouseWheel and is unaffected.) -->
|
||
<OnMouseWheel>BenillaQuestLogFrame_OnMouseWheel(arg1)</OnMouseWheel>
|
||
<!-- pin §1, QuestLog_OnShow/OnHide (QuestLogFrame.lua:85-95), wired via the frame's
|
||
OnShow/OnHide (QuestLogFrame.xml:949-954) — the window-sound convention (decision
|
||
0090). Note the SoundKit-name vs on-disk-filename trap the pin calls out (§1): the
|
||
kit names below are `igQuestLog*`, the shipped waves are `iQuestLogOpenA`/
|
||
`iQuestLogCloseA` (no "g") — PlaySound takes the KIT name, so this is correct as
|
||
written, flagged only so a future filename-based lookup doesn't "fix" it wrongly.
|
||
Never fires at load (hidden="true"). UpdateMicroButtons leads both, as in the ref
|
||
(QuestLogFrame.lua:85-95's own first line) — live since the micro-menu slice
|
||
(MicroMenu.xml). -->
|
||
<OnShow>if UpdateMicroButtons then UpdateMicroButtons() end PlaySound("igQuestLogOpen") BenillaQuestLogFrame_Update()</OnShow>
|
||
<OnHide>if UpdateMicroButtons then UpdateMicroButtons() end PlaySound("igQuestLogClose")</OnHide>
|
||
</Scripts>
|
||
</Frame>
|
||
|
||
|
||
<!--
|
||
The quest-watch tracker HUD (pin's `QuestWatchFrame`, ref `QuestLogFrame.xml:968-1146`) — a
|
||
SEPARATE always-on-screen frame, not part of `QuestLogFrame` (this file's "The
|
||
always-visible quest-watch tracker" script comment): it's screen-anchored, never docks a
|
||
UIPanel slot, has no close button/ESC handling, and repaints off its own events whether or
|
||
not the log window is even open — a HUD element, exactly like the ref's. Kept in THIS file
|
||
rather than a separate `QuestWatchFrame.xml`: the ref itself defines it in `QuestLogFrame.xml`
|
||
too (it's the log's own on-screen echo, driven by the same Lua functions/getters as the log
|
||
window above), and this file's tests already load nothing else — a second file would need its
|
||
own duplicate test-harness load list for zero isolation benefit (contrast the
|
||
`QuestLogRewardItemTemplate`/`BenillaQuestLogPanelButtonTemplate` duplication above, which
|
||
buys real per-window test isolation).
|
||
|
||
v1 placement: TOPRIGHT of the screen, offset (-10,-170) — no minimap frame exists in benilla
|
||
yet (the ref anchors 10px below `MinimapCluster`'s bottom edge), so this is a plain guess at
|
||
clearing where one would land (a classic-sized minimap runs roughly 140px tall from the
|
||
corner). FOR THE DIRECTOR'S EYE: revisit once a minimap ships, or sooner if this reads wrong
|
||
on screen.
|
||
|
||
280 wide (the ref's own `QuestWatchFrame` width) with NO Backdrop (the ref's tracker floats
|
||
bare text over the world, no border/background) — matches `UIErrorsFrame`'s bare-text
|
||
convention, not `BenillaQuestLogAbandonConfirm`'s dialog chrome. `BENILLA_QUESTLOG_MAX_WATCHES`
|
||
(5, `quest_log.rs`'s own `AddQuestWatch` cap) × `BENILLA_QUESTWATCH_MAX_OBJECTIVES` (4, this
|
||
file's v1 cap — see that constant's own comment) pre-declares a FIXED 5×(1+4) grid of
|
||
FontStrings — the flat-frame constraint (no dynamic creation at runtime), so every slot exists
|
||
up front and `QuestWatch_Update` only ever SetTexts/colors them, never creates one.
|
||
-->
|
||
<!-- The always-on quest-watch tracker HUD (ref QuestWatchFrame, QuestLogFrame.xml:963-1146
|
||
+ QuestWatch_Update, QuestLogFrame.lua:602-663), re-expressed: TOPRIGHT hangs off the
|
||
MinimapCluster's BOTTOMRIGHT (+10 up — the cluster art overhangs), an empty 13px
|
||
GameFontNormal spacer (the ref's never-written QuestWatchQuestName) seats the first line,
|
||
and ONE FLAT POOL of 30 lines (MAX_QUESTWATCH_LINES) carries titles and objectives alike —
|
||
the Lua re-anchors each line every paint (titles drop -4 extra; the pool squeezes, no
|
||
fixed per-quest slots). Lines are the ref's GameFontHighlight; the XML chain offset is -1
|
||
because our lines are measured (y=0 -> ink height 12) where the ref pins 13px boxes:
|
||
12 + 1 = the ref pitch. Width/height follow the content (SetWidth maxW+10 / SetHeight
|
||
lines*13) so the left-aligned column hugs the minimap's right edge like the ref; the
|
||
GetWidth reads are extract-measured (one frame stale), so the sizing tail re-runs from
|
||
OnUpdate for two frames after each repaint (`resize_pending`) and converges next frame. -->
|
||
<Frame name="QuestWatchFrame" toplevel="true" parent="UIParent">
|
||
<Size><AbsDimension x="280" y="20"/></Size>
|
||
<Anchors>
|
||
<Anchor point="TOPRIGHT" relativeTo="MinimapCluster" relativePoint="BOTTOMRIGHT">
|
||
<Offset><AbsDimension x="0" y="10"/></Offset>
|
||
</Anchor>
|
||
</Anchors>
|
||
<Layers>
|
||
<Layer level="BACKGROUND">
|
||
<FontString name="QuestWatchQuestName" inherits="GameFontNormal" justifyH="LEFT">
|
||
<Size><AbsDimension x="0" y="13"/></Size>
|
||
<Anchors><Anchor point="TOPLEFT"/></Anchors>
|
||
</FontString>
|
||
<FontString name="QuestWatchLine1" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchQuestName" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine2" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine1" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine3" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine2" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine4" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine3" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine5" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine4" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine6" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine5" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine7" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine6" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine8" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine7" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine9" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine8" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine10" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine9" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine11" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine10" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine12" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine11" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine13" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine12" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine14" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine13" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine15" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine14" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine16" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine15" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine17" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine16" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine18" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine17" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine19" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine18" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine20" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine19" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine21" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine20" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine22" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine21" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine23" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine22" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine24" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine23" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine25" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine24" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine26" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine25" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine27" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine26" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine28" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine27" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine29" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine28" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
<FontString name="QuestWatchLine30" inherits="GameFontHighlight" justifyH="LEFT"><Anchors><Anchor point="TOPLEFT" relativeTo="QuestWatchLine29" relativePoint="BOTTOMLEFT"><Offset><AbsDimension x="0" y="-1"/></Offset></Anchor></Anchors></FontString>
|
||
</Layer>
|
||
</Layers>
|
||
<Scripts>
|
||
<OnLoad>BenillaQuestWatchFrame_OnLoad(self)</OnLoad>
|
||
<OnEvent>BenillaQuestWatchFrame_OnEvent(self)</OnEvent>
|
||
<OnUpdate>BenillaQuestWatchFrame_OnUpdate(self, arg1)</OnUpdate>
|
||
</Scripts>
|
||
</Frame>
|
||
</Ui>
|