fix(layout): strip stale dockspace IDs from bundled INI; force live-session apply

Bundled layouts/default.ini (relocated from tests/artifacts/ in Phase 1)
contained a [Docking] data block with a hardcoded DockSpace ID 0xAFBEEF01
plus per-window DockId references to nodes 0x10 and 0x11. Those IDs were
captured at the time the layout was first generated; on any fresh session
HelloImgui computes dockspace IDs dynamically (typically a hash of the
dockspace name + creation order) so the hardcoded literal is stale by the
first render and the orphan docking instructions are silently dropped.

Result: window positions stored in the INI render the windows as
floating at their absolute Pos coordinates, but the auto-created
dockspace captures the full window body, hiding them all. User observed
empty dockspace with only the menu ribbon rendering.

Two-part fix:

1. layouts/default.ini: remove [Docking] data block and per-window DockId
   lines. Comment rewritten to explain why the auto-dock strategy is the
   only session-stable option. Each [Window] entry now has only Pos + Size
   + Collapsed=0, so HelloImgui's auto-dock layer places the panels as
   tabs in the central dockspace on first render.

2. _install_default_layout_if_empty: after writing the bundled INI to
   disk, also call imgui.load_ini_settings_from_memory(src_text) to force
   the live HelloImgui session to apply the new INI. Without this, the
   install only takes effect on the NEXT launch (since HelloImgui reads
   cwd/manualslop_layout.ini BEFORE the post_init callback fires). With it,
   first-launch panels appear immediately.

Tests:
- tests/test_default_layout_install.py assertions updated: instead of
  checking for a per-window DockId line, the install now verifies (a)
  [Window][Project Settings] entry exists, (b) the INI has at least one
  [Window] entry, (c) the INI has no [Docking] data block.
- New _assert_live_session_apply() on tests 1 and 2 verifies the
  "(and applied to live session)" log line appears in stderr, confirming
  imgui.load_ini_settings_from_memory was invoked.

17/17 tests pass (3 install + 2 reset_layout + 8 adjacent gui/commands).
This commit is contained in:
ed
2026-06-29 19:08:49 -04:00
parent 15cd12624f
commit e965451842
3 changed files with 95 additions and 77 deletions
+33 -8
View File
@@ -38,6 +38,25 @@ def _spawn_sloppy_for(workspace: Path, log_suffix: str) -> subprocess.Popen:
return proc
def _read_launch_log(log_suffix: str) -> str:
log_path: Path = _SCRIPTS_DIR / f"test_{log_suffix}.log"
if not log_path.exists():
return ""
try:
return log_path.read_text(encoding="utf-8", errors="replace")
except OSError:
return ""
def _assert_live_session_apply(log_suffix: str) -> None:
text: str = _read_launch_log(log_suffix)
assert "and applied to live session" in text, (
f"install write succeeded but live-session apply did not happen; "
f"expected the live-apply confirmation line in stderr, got: "
f"{[l for l in text.splitlines() if 'installed' in l]!r}"
)
def _terminate(process: subprocess.Popen) -> None:
if process.poll() is not None:
return
@@ -72,16 +91,17 @@ def _read_ini(workspace: Path) -> str:
return ""
def _has_dockid_after_window_header(text: str) -> bool:
lines: list[str] = text.splitlines()
for idx, line in enumerate(lines):
def _has_window_with_collapsed_zero(text: str) -> bool:
for line in text.splitlines():
if line.startswith("[Window][") and line.rstrip().endswith("]"):
tail: str = "\n".join(lines[idx + 1:])
if "DockId=" in tail:
return True
return True
return False
def _has_no_docking_block(text: str) -> bool:
return "[Docking][Data]" not in text
def _workspace_for(tmp_path: Path, test_name: str) -> Path:
return tmp_path / f"_default_layout_install_{os.getpid()}_{test_name}"
@@ -99,8 +119,11 @@ def _assert_installed_default(workspace: Path) -> None:
assert "[Window][Project Settings]" in text, (
f"installed INI missing [Window][Project Settings]; got first 400 chars: {text[:400]!r}"
)
assert _has_dockid_after_window_header(text), (
f"installed INI has no DockId= following a [Window][...] header; got first 400 chars: {text[:400]!r}"
assert _has_window_with_collapsed_zero(text), (
f"installed INI has no [Window][...] entry; got first 400 chars: {text[:400]!r}"
)
assert _has_no_docking_block(text), (
f"installed INI should not contain a [Docking][Data] block (HelloImgui dockspace IDs are session-specific); got first 400 chars: {text[:400]!r}"
)
@@ -113,6 +136,7 @@ def test_default_layout_installed_when_ini_missing(tmp_path: Path) -> None:
proc: subprocess.Popen = _start_subprocess_in(workspace, "ini_missing")
try:
_assert_installed_default(workspace)
_assert_live_session_apply("ini_missing")
finally:
_terminate(proc)
shutil.rmtree(workspace, ignore_errors=True)
@@ -126,6 +150,7 @@ def test_default_layout_installed_when_ini_empty(tmp_path: Path) -> None:
proc: subprocess.Popen = _start_subprocess_in(workspace, "ini_empty")
try:
_assert_installed_default(workspace)
_assert_live_session_apply("ini_empty")
finally:
_terminate(proc)
shutil.rmtree(workspace, ignore_errors=True)