map: the art was scaled by the canvas while living in the detail frame

Grom's report was "textures are not where they should be", and still wrong with OpenMapClassic
switched off — which is what made it ours rather than the addon's. His own session log had both
states 1.4 s apart, same map, same frame: detail 1431x954 with tiles 366x366 (correct, 1431/1002 =
1.428), then the same frame with tiles back at the XML's raw 256x256.

`ScaleDetailArt` was being handed the CANVAS's size by `OnCanvasSizeChanged`, on the assumption
that the detail frame is `SetAllPoints` to the canvas. 1.12's own windowed mode breaks that:
`WorldMapFrame_Minimize` puts `WORLDMAP_WINDOWED_SCALE` (0.7) on `WorldMapDetailFrame` and
`WorldMapButton` and insets the frame to TOPLEFT 15,-33, so the same screen area is a different
number of units in each — his trace reads `detail 1431x954 scale 0.56` inside `WorldMapCanvas
1002x668 scale 0.80`. Scaled by the canvas's number every tile came out 1.43x too small: the art
covered 1024x768 of a 1431x954 frame, the rest bare parchment, and the exploration overlays scaled
to match landed nowhere near their terrain.

The detail frame's own size is the authority, since the tiles are its children. `GetLeft()` first
to settle the layout, because that size is derived and an unforced read answers the size from
before the last change; the caller's w,h stay as the fallback for what cannot be measured.

Reproduced and controlled in the harness with the windowed scale applied as the stock code applies
it: tile 362 where 362 is wanted, against the control's 256 — the number his log recorded. Two
earlier attempts are written up in docs/ADDON_COMPAT.md as dead ends, because both looked right:
caching the canvas size prefers the wrong quantity, and converting it by the effective-scale ratio
gives 366 against a true 362, since Minimize also insets the frame.

`$WOW_CAPTURE_SAVED` now reaches the enable-state file too, so a capture reproduces which addons
the player has turned off — without which "I turned it off and it is still wrong" cannot be
answered offline at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SgstFWtn1RxEJ5kVrpgYwn
This commit is contained in:
2026-11-03 10:54:54 -07:00
co-authored by Claude Opus 5
parent 5e2f1f3ac8
commit d11b9ac3ae
3 changed files with 80 additions and 9 deletions
+21 -8
View File
@@ -737,19 +737,32 @@ local DETAIL_TILE, DETAIL_TILES = 256, 12
-- Base geometry per overlay texture, as `WorldMapFrame_Update` wrote it: [texture] = {x,y,w,h}.
local overlayBase = {}
-- `w`,`h` are the size the detail frame is ABOUT to have, passed by the caller that just set it.
-- Reading the frame instead would answer the old size: the detail frame is `SetAllPoints` to the
-- canvas, so its own size is derived, and a derived size does not resolve until the layout pass
-- — measured, a child answered `0x0` immediately after its parent was resized. Without them the
-- frame's current size is read, which is right for a caller that is not resizing it (the overlay
-- capture after a repaint).
-- Scale the stock map art to whatever size the detail frame currently has. `w`,`h` are a
-- fallback only, for the one caller that has just set a size the layout cannot answer yet.
local function ScaleDetailArt(w, h)
local d = WorldMapDetailFrame
if not d then
return
end
w = w or d:GetWidth()
h = h or d:GetHeight()
-- The detail frame's OWN size is the authority, because the tiles are its children and it is
-- not always the canvas's shape: 1.12's windowed mode re-anchors AND rescales it out from
-- under the canvas (`WorldMapFrame_Minimize` sets `WORLDMAP_WINDOWED_SCALE` on it and insets
-- it to TOPLEFT 15,-33), so the canvas's own size stops describing the frame the art lives
-- in. Measured in grom's session: `detail 1431x954 scale 0.56` inside `WorldMapCanvas
-- 1002x668 scale 0.80` — the same screen area, a different number of units.
--
-- Scaled by the canvas's number instead, every tile came out 1.43x too small: the art
-- covered 1024x768 of a 1431x954 frame and the rest was bare parchment. His own art trace
-- caught both states 1.4 s apart, tiles 366 then 256, with the detail frame unchanged.
--
-- `GetLeft` first: the size is derived, and without forcing the layout to settle a read taken
-- straight after a resize answers the size from before it. The caller's `w`,`h` remain the
-- fallback for the one case that cannot be measured at all.
d:GetLeft()
local dw, dh = d:GetWidth(), d:GetHeight()
if dw and dh and dw > 0 and dh > 0 then
w, h = dw, dh
end
if not w or not h or w <= 0 or h <= 0 then
return
end
+5 -1
View File
@@ -116,7 +116,11 @@ pub(crate) fn saved_variables_path() -> Option<PathBuf> {
/// of its UI shutdown (`0x490bd0`). An addon absent from the file is enabled.
pub(crate) fn addons_state_path(realm: &str, character: &str) -> Option<PathBuf> {
let key = format!("{}-{}", file_token(realm), file_token(character));
home().map(|h| h.join("addons").join(format!("{key}.txt")))
// Through `saved_home`, so `$WOW_CAPTURE_SAVED` reproduces which addons the player has turned
// OFF as well as how the rest are configured. Without it a capture of their interface loads
// every addon in the folder, which is a different interface again — and the difference is
// exactly what a "I turned it off and it is still wrong" report turns on.
saved_home().map(|h| h.join("addons").join(format!("{key}.txt")))
}
/// [`home`] for the saved-variable readers, opened back up for a capture by
+54
View File
@@ -2484,3 +2484,57 @@ The four info panels moved onto the same page at the same time, the bottom-right
(`pfUI.panel.right`, over the right chat frame) included. Those have had a fixed two-second
autohide on pfUI's Panel page for years; the Auto Fade page drives the same frames on the user's
own timeout, and hands one back rather than switching it off when the Panel page still wants it.
## The map art was scaled by the canvas while living in the detail frame
"Textures are not where they should be", and still wrong with the map addon switched off — which
is what made it ours. His own session log had both states, 1.4 seconds apart, same map, same frame:
```
251.4s detail 1431x954 tiles 366x366 at 387, 752, 1118, 1484 (1431/1002 = 1.428, correct)
252.8s detail 1431x954 tiles 256x256 at 387, 643, 899, 1155 (the XML's raw size)
```
The stock art is twelve 256x256 tiles laid 4x3 in a `WorldMapDetailFrame` the realm's XML declares
as 1002x668 — they overflow it by 22x100 on purpose, and that is faithful. `MapCanvas.lua`'s
`ScaleDetailArt` rescales them whenever the frame is not that size.
It was being told the **canvas's** size, by the one caller that knew a size at all
(`OnCanvasSizeChanged`), on the assumption that the detail frame is `SetAllPoints` to the canvas.
1.12's own windowed mode breaks that assumption: `WorldMapFrame_Minimize` sets
`WORLDMAP_WINDOWED_SCALE` (0.7) on `WorldMapDetailFrame` and on `WorldMapButton`, and insets the
frame to `TOPLEFT 15,-33`. The same screen area is then a different number of units in each —
grom's trace reads `detail 1431x954 scale 0.56` inside `WorldMapCanvas 1002x668 scale 0.80`.
Scaled by the canvas's number, every tile came out 1.43x too small: the art covered 1024x768 of a
1431x954 frame and the rest showed bare parchment, with the exploration overlays scaled to match
and landing nowhere near their terrain.
**The detail frame's own size is the authority** — the tiles are its children — so that is what is
read now, with `GetLeft()` first to settle the layout, because the size is derived and an unforced
read answers the size from before the last change. The caller's `w`,`h` stay as the fallback for
the case that cannot be measured at all.
Reproduced and controlled in the harness, with the windowed scale applied as the stock code
applies it:
```
fix: detail 1416x921 scale 0.49 | canvas 1002 scale 0.70 | tile 362, should be 362 -> OK
control: detail 1416x921 scale 0.49 | canvas 1002 scale 0.70 | tile 256, should be 362 -> WRONG
```
The control's 256 is the number his log recorded.
**A dead end worth recording**, because it looked right twice: the first fix cached the last size
the canvas passed and preferred it over reading the frame. That is backwards — the cached canvas
size is the wrong quantity, not a stale copy of the right one. The second tried converting canvas
units to detail units by the effective-scale ratio; it came out 366 against a true 362, because
`Minimize` also insets the frame, so the two are not related by scale alone. Only the frame's own
measured size is right.
## A capture now honours which addons the player turned OFF
`$WOW_CAPTURE_SAVED` reaches the enable-state file as well as the saved variables, so a capture
reproduces the addon set the player actually has. The report that needed it was "I turned the map
addon off to test and it is still wrong" — without it a capture loads every addon in the folder,
which cannot answer that at all.