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 1/2] 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). From 07e3998da6cb979d06b1eab833ddda5bd14068c1 Mon Sep 17 00:00:00 2001 From: justnullname <51329027+justnullname@users.noreply.github.com> Date: Tue, 31 Mar 2026 07:09:23 +0000 Subject: [PATCH 2/2] Fix: Bypass AdjustWindowToImage on Color Space switch The previous attempt restored `g_viewState` but was subsequently overridden by `AdjustWindowToImage`, which physically resizes the window based on a hardcoded `Zoom = 1.0f` scalar against the native image dimensions. By modifying `ProcessEngineEvents` to completely skip `AdjustWindowToImage` and `ApplyFullScreenZoomMode` when the `g_preserveViewStateOnNextLoad` flag is active, both the physical window size and the exact relative zoom/pan values are perfectly preserved during soft-reloads like Color Space switching and soft proofing toggles. --- QuickView/main.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/QuickView/main.cpp b/QuickView/main.cpp index 9d3e920..4058bc9 100644 --- a/QuickView/main.cpp +++ b/QuickView/main.cpp @@ -9210,20 +9210,20 @@ void ProcessEngineEvents(HWND hwnd) { // [Fix] Update Window Size AFTER RenderImageToDComp // This ensures g_lastSurfaceSize is updated with the NEW image dimensions. - AdjustWindowToImage(hwnd); - - // [Feature] Apply Fullscreen Zoom Mode if active - if (g_isFullScreen || IsZoomed(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 we are preserving view state (e.g., Color Space switch), we DO NOT resize the window + // and we bypass the Fullscreen zoom mode reset, ensuring exact visual continuity. 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 + } else { + AdjustWindowToImage(hwnd); + + // [Feature] Apply Fullscreen Zoom Mode if active + if (g_isFullScreen || IsZoomed(hwnd)) { + ApplyFullScreenZoomMode(hwnd); + } } // [Fix] Explicitly Sync DComp State immediately after Window Adjustment