From c2ba6b0e331a7f8283a515e21366f44a8b9eb736 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Thu, 26 Mar 2026 15:51:37 +0100 Subject: [PATCH] Update the canvas detail view only when drawing is done And remove the canvas from the view once it's destroyed. --- web/internal/canvas_context_details_view.js | 32 +++++++++++++++++---- web/internal/page_view.js | 13 +++++++-- 2 files changed, 37 insertions(+), 8 deletions(-) diff --git a/web/internal/canvas_context_details_view.js b/web/internal/canvas_context_details_view.js index 5ec4f59cc..4f1ddd725 100644 --- a/web/internal/canvas_context_details_view.js +++ b/web/internal/canvas_context_details_view.js @@ -110,10 +110,12 @@ class CanvasContextDetailsView { this.#ctxStates.set(label, state); this.#ctxStateStacks.set(label, []); this.#ctxStackViewIdx.set(label, null); - // If the panel is already visible (stepping in progress), rebuild it so - // the new context section is added and its live-update entries are - // registered. - if (this.#gfxStateValueElements.size > 0) { + // If the panel is already visible and we're at a pause point, rebuild it + // so the new context section is added and its live-update entries are + // registered. Skip the rebuild while frozen (execution is in progress + // between pauses) — the next build() call from #onStepped() will pick it + // up. + if (!this.#frozen && this.#gfxStateValueElements.size > 0) { this.build(); } @@ -303,9 +305,29 @@ class CanvasContextDetailsView { } } - /** Hide the panel. */ + /** + * Remove the section for a single context from the panel and all internal + * state maps. Called when a temporary canvas is destroyed. + */ + removeContext(label) { + this.#ctxStates.delete(label); + this.#ctxStateStacks.delete(label); + this.#ctxStackViewIdx.delete(label); + this.#gfxStateValueElements.delete(label); + this.#gfxStateNavElements.delete(label); + this.#panel + .querySelector( + `.gfx-state-section[data-ctx-label="${CSS.escape(label)}"]` + ) + ?.remove(); + } + + /** Hide the panel and discard all DOM state so no live updates occur. */ hide() { this.#panel.hidden = true; + this.#gfxStateValueElements.clear(); + this.#gfxStateNavElements.clear(); + this.#panel.replaceChildren(); } /** diff --git a/web/internal/page_view.js b/web/internal/page_view.js index e840cd213..397dad8c4 100644 --- a/web/internal/page_view.js +++ b/web/internal/page_view.js @@ -355,7 +355,9 @@ class PageView { destroy(canvasAndCtx) { const idx = this.#alive.findIndex(e => e.canvasAndCtx === canvasAndCtx); if (idx !== -1) { - this.#alive[idx].wrapper.remove(); + const { wrapper, ctxLabel } = this.#alive[idx]; + wrapper.remove(); + gfxStateComp.removeContext(ctxLabel); this.#alive.splice(idx, 1); } super.destroy(canvasAndCtx); @@ -393,7 +395,7 @@ class PageView { checker.className = "canvas-checker"; checker.append(canvasAndCtx.canvas); wrapper.append(labelEl, checker); - const entry = { canvasAndCtx, wrapper, labelEl }; + const entry = { canvasAndCtx, wrapper, labelEl, ctxLabel }; this.#alive.push(entry); this.#attachWrapper(entry); } @@ -482,7 +484,10 @@ class PageView { }); this.#stepButton.addEventListener("click", () => { - globalThis.StepperManager._active?.stepNext(); + if (globalThis.StepperManager._active) { + this.#gfxStateComp.freeze(); + globalThis.StepperManager._active.stepNext(); + } }); this.#continueButton.addEventListener("click", () => { @@ -580,9 +585,11 @@ class PageView { } if (e.key === "s") { e.preventDefault(); + this.#gfxStateComp.freeze(); stepper.stepNext(); } else if (e.key === "c") { e.preventDefault(); + this.#gfxStateComp.freeze(); stepper.continueToBreakpoint(); } });