the map opens full screen again after an addon windowed it
- the world map opens full screen again on a character that once ran Cartographer's windowed map: a saved frame position or size outlives the addon only while the frame is movable or resizable (2193) - the layout cache gates both the write and the apply on `userPlaced AND (movable|resizable)`, the reference's four sites, where benilla had only the setter's (2193) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -987,6 +987,9 @@ fn a_repeating_error_is_one_row_with_a_count_not_a_flood() {
|
||||
/// userPlaced bit (`SetUserPlaced` refuses a frame that is neither movable nor resizable).
|
||||
/// Parentless, so its anchor is the screen root — the file's `-` target — which is what lets this
|
||||
/// need no FrameXML and no install.
|
||||
/// **Both flags, deliberately**: the layout cache's apply is gated per arm — position behind
|
||||
/// `movable`, size behind `resizable` (decision 2193) — so a probe standing in for a window the
|
||||
/// player both moved and resized has to carry both, or half its geometry is correctly left behind.
|
||||
fn place_a_window(world: &mut World) {
|
||||
world
|
||||
.get_non_send_resource_mut::<benilla_ui::script::UiScript>()
|
||||
@@ -995,7 +998,7 @@ fn place_a_window(world: &mut World) {
|
||||
"local f = CreateFrame(\"Frame\", \"B353Probe\") \
|
||||
f:SetWidth(413) f:SetHeight(147) \
|
||||
f:SetPoint(\"BOTTOMLEFT\", 61, 29) \
|
||||
f:SetMovable(true) f:SetUserPlaced(true)",
|
||||
f:SetMovable(true) f:SetResizable(true) f:SetUserPlaced(true)",
|
||||
)
|
||||
.expect("place the probe window");
|
||||
}
|
||||
@@ -1099,6 +1102,10 @@ fn each_character_gets_its_own_layout_cache() {
|
||||
/// A window as FrameXML would author it — the shape the restore has to overwrite. Same name as
|
||||
/// [`place_a_window`]'s, different geometry, and **not** user-placed: this is the fresh tree a
|
||||
/// relog meets.
|
||||
///
|
||||
/// It carries the same `movable`/`resizable` pair, because those are the window's **authored**
|
||||
/// state — XML attributes on a real resizable window, rebuilt with it — and the layout cache's
|
||||
/// apply reads them off the live frame to decide which arm runs (decision 2193).
|
||||
fn author_a_window(world: &mut World) {
|
||||
world
|
||||
.get_non_send_resource_mut::<benilla_ui::script::UiScript>()
|
||||
@@ -1107,7 +1114,7 @@ fn author_a_window(world: &mut World) {
|
||||
"local f = CreateFrame(\"Frame\", \"B353Probe\") \
|
||||
f:SetWidth(100) f:SetHeight(100) \
|
||||
f:SetPoint(\"BOTTOMLEFT\", 0, 0) \
|
||||
f:SetMovable(true)",
|
||||
f:SetMovable(true) f:SetResizable(true)",
|
||||
)
|
||||
.expect("author the probe window");
|
||||
}
|
||||
|
||||
@@ -814,3 +814,104 @@ fn the_real_feralas_catalog_names_dire_maul_under_the_cursor() {
|
||||
"the stock OnUpdate puts the hovered sub-area's name in the label"
|
||||
);
|
||||
}
|
||||
|
||||
/// **A layout row an addon stamped does not outlive the addon** — director report: the world map
|
||||
/// stopped opening full screen, "leaving the left and bottom open", on a character whose addons
|
||||
/// were all disabled.
|
||||
///
|
||||
/// `Cartographer/Modules/LookNFeel.lua` windows the map on enable — `SetMovable(true)`,
|
||||
/// `SetResizable(true)`, `SetWidth(1024)`, `SetHeight(768)`, `StartMoving(); StopMovingOrSizing()`,
|
||||
/// then `SetPoint("CENTER", UIParent, "CENTER", db.x, db.y)` — and the drag entry stamps the
|
||||
/// userPlaced bit on the way through (`0x7652b0` @`0x7652e5`, unconditionally). benilla's layout
|
||||
/// cache was gated on that bit **alone**, so it persisted the row and re-seated it at every login
|
||||
/// on every character, replacing the stock `setAllPoints="true"` forever; the blackout, which
|
||||
/// `WorldMapFrame_OnLoad` sizes to the screen and anchors BOTTOMLEFT of the map, slid up-and-right
|
||||
/// with it and left the world showing at the left and the bottom.
|
||||
///
|
||||
/// The reference gates both ends on `movable|resizable` as well (`0x490e97 test ah,0x3` at the
|
||||
/// writer; `0x490600 test ah,0x1` / `0x490689 test ah,0x2` at the two arms of the apply), and
|
||||
/// stock `WorldMapFrame` carries neither flag — so the stale row is inert the first session the
|
||||
/// addon does not load, and falls out of the file at that logout. Decision 2193.
|
||||
#[test]
|
||||
fn a_stale_layout_row_cannot_seat_a_stock_frame() {
|
||||
let _data = benilla_formats::wow_data_or_skip!();
|
||||
let mut s = UiScript::new().unwrap();
|
||||
s.set_screen_size(1600.0, 900.0);
|
||||
s.set_unit(
|
||||
"player",
|
||||
Some(benilla_ui::script::UnitState {
|
||||
exists: true,
|
||||
name: Some("Probefour".into()),
|
||||
level: 60,
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
let failures = super::load_default_ui(&s);
|
||||
assert!(failures.is_empty(), "manifest load errors: {failures:#?}");
|
||||
s.resolve();
|
||||
|
||||
// The row verbatim as an affected `benilla-config/layout/<realm>-<character>.txt` carries it:
|
||||
// Cartographer's own saved `LookNFeel` profile offsets, and the size it forces.
|
||||
let row = || benilla_ui::script::FrameLayout {
|
||||
name: "WorldMapFrame".into(),
|
||||
width: 1024.0,
|
||||
height: 768.0,
|
||||
points: vec![benilla_ui::script::LayoutPoint {
|
||||
point: "CENTER".into(),
|
||||
relative_to: Some("UIParent".into()),
|
||||
relative_point: "CENTER".into(),
|
||||
x: -0.6369222,
|
||||
y: 53.861614,
|
||||
}],
|
||||
};
|
||||
|
||||
s.restore_user_placed_layouts([row()]);
|
||||
s.resolve();
|
||||
s.run("ShowUIPanel(WorldMapFrame)").unwrap();
|
||||
s.resolve();
|
||||
|
||||
let (w, h, sw, sh) = s
|
||||
.eval::<(f64, f64, f64, f64)>(
|
||||
"return WorldMapFrame:GetWidth(), WorldMapFrame:GetHeight(), \
|
||||
GetScreenWidth(), GetScreenHeight()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
(w, h),
|
||||
(sw, sh),
|
||||
"the stale row seated nothing — the map is still the screen, as its setAllPoints authored it"
|
||||
);
|
||||
assert!(
|
||||
!s.eval::<bool>("return WorldMapFrame:IsUserPlaced()")
|
||||
.unwrap(),
|
||||
"and the apply's userPlaced stamp lives inside the position arm it never took"
|
||||
);
|
||||
assert!(
|
||||
s.user_placed_layouts().is_empty(),
|
||||
"so the row falls out of the file at this logout instead of being written again"
|
||||
);
|
||||
|
||||
// The positive control: the gate is the frame's own flags, not a special case for this frame.
|
||||
// With the addon's `SetMovable`/`SetResizable` in place the same row seats exactly as before.
|
||||
s.run("WorldMapFrame:SetMovable(true) WorldMapFrame:SetResizable(true)")
|
||||
.unwrap();
|
||||
s.restore_user_placed_layouts([row()]);
|
||||
s.resolve();
|
||||
let (w, h) = s
|
||||
.eval::<(f64, f64)>("return WorldMapFrame:GetWidth(), WorldMapFrame:GetHeight()")
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
(w, h),
|
||||
(1024.0, 768.0),
|
||||
"a movable+resizable frame takes it"
|
||||
);
|
||||
assert!(
|
||||
s.eval::<bool>("return WorldMapFrame:IsUserPlaced()")
|
||||
.unwrap(),
|
||||
"and the position arm stamps the bit it was written under"
|
||||
);
|
||||
let saved = s.user_placed_layouts();
|
||||
assert_eq!(saved.len(), 1, "which is what puts the row back: {saved:?}");
|
||||
assert_eq!(saved[0], row(), "unchanged through the round trip");
|
||||
assert!(s.errors().is_empty(), "script errors: {:?}", s.errors());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user