From a1f40e8463a4a4fadbef0b2b55b36f87d3dee177 Mon Sep 17 00:00:00 2001 From: justnullname <51329027+justnullname@users.noreply.github.com> Date: Fri, 27 Mar 2026 11:38:14 +0000 Subject: [PATCH] Fix: Preserve zoom and pan states when switching color spaces or RAW mode When right-clicking to switch color spaces, toggle soft proofing, or enable/disable RAW rendering, the image is re-decoded and re-uploaded to the GPU, causing the `AdjustWindowToImage` system to reset the user's current zoom scale and pan offsets to default (Fit Window). This patch introduces a dedicated global flag (`g_preserveViewStateOnNextLoad`) and a storage struct (`g_preservedViewState`) to seamlessly persist the `g_viewState` across these specific user-initiated asynchronous image reloads. Once the new image resource completes decoding and reaches `ProcessEngineEvents`, the original zoom and pan are cleanly restored to the hardware composition engine matrix immediately before the `SyncDCompState` update. --- QuickView/main.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/QuickView/main.cpp b/QuickView/main.cpp index ad60691..9d3e920 100644 --- a/QuickView/main.cpp +++ b/QuickView/main.cpp @@ -236,6 +236,8 @@ static EditState g_editState; AppConfig g_config; RuntimeConfig g_runtime; ViewState g_viewState; // Non-static for extern access from UIRenderer +bool g_preserveViewStateOnNextLoad = false; +ViewState g_preservedViewState; static int g_renderExifOrientation = 1; // Exif orientation baked into the bitmap surface FileNavigator g_navigator; // New Navigator (Non-static for extern access from SettingsOverlay) static ThumbnailManager g_thumbMgr; @@ -8586,6 +8588,8 @@ SKIP_EDGE_NAV:; g_imageEngine->UpdateConfig(g_runtime); // [Fix] Push config to engine g_imageEngine->SetForceRefresh(true); } + g_preservedViewState = g_viewState; + g_preserveViewStateOnNextLoad = true; ReleaseImageResources(); LoadImageAsync(hwnd, contextPath.c_str()); } @@ -8613,6 +8617,8 @@ SKIP_EDGE_NAV:; g_imageEngine->UpdateConfig(g_runtime); g_imageEngine->SetForceRefresh(true); } + g_preservedViewState = g_viewState; + g_preserveViewStateOnNextLoad = true; ReleaseImageResources(); LoadImageAsync(hwnd, g_imagePath, false, QuickView::BrowseDirection::IDLE); } @@ -9211,6 +9217,15 @@ void ProcessEngineEvents(HWND hwnd) { ApplyFullScreenZoomMode(hwnd); } + // [Fix] Restore View State if it was saved prior to reloading (e.g. Color Space switch) + // Do this before SyncDCompState so it receives the correct zoom and pan + if (g_preserveViewStateOnNextLoad) { + g_viewState.Zoom = g_preservedViewState.Zoom; + g_viewState.PanX = g_preservedViewState.PanX; + g_viewState.PanY = g_preservedViewState.PanY; + g_preserveViewStateOnNextLoad = false; // Consume it + } + // [Fix] Explicitly Sync DComp State immediately after Window Adjustment // This covers the case where the Window Size DOES NOT CHANGE (e.g. Locked or Maximized), // so WM_SIZE is never fired, leaving the DComp Transform Matrix stale (using old image AR).