Skip to content

Commit 9cd4b0a

Browse files
committed
fix(ui): freeze filmstrip auto-hide animation and force-finish transition when context menu is active (v6.28.1.0)
1 parent 811a89d commit 9cd4b0a

8 files changed

Lines changed: 89 additions & 13 deletions

File tree

‎QuickView/AppStrings.cpp‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const wchar_t *Settings_Tab_About = nullptr;
5959
const wchar_t *Settings_Tab_Shortcuts = nullptr;
6060
const wchar_t *Settings_Hotkey_PressKey = nullptr;
6161
const wchar_t *Settings_Hotkey_Conflict = nullptr;
62+
const wchar_t *Settings_Hotkey_ConflictPrompt = nullptr;
6263
const wchar_t *Settings_Hotkey_Restore = nullptr;
6364
const wchar_t *Settings_Hotkey_Restored = nullptr;
6465
const wchar_t *Settings_Hotkey_MouseTip = nullptr;
@@ -6140,6 +6141,7 @@ void SetLanguage(Language lang) {
61406141
Settings_Tab_Shortcuts = L"快捷键";
61416142
Settings_Hotkey_PressKey = L"请按下按键...";
61426143
Settings_Hotkey_Conflict = L"快捷键冲突";
6144+
Settings_Hotkey_ConflictPrompt = L"已由“%s”占用,继续将清除其快捷键。";
61436145
Settings_Hotkey_Restore = L"恢复快捷键默认值";
61446146
Settings_Hotkey_Restored = L"已恢复";
61456147
Settings_Hotkey_MouseTip = L"提示:支持鼠标中键、侧键等鼠标多功能按键。更多侧键请在鼠标驱动中映射为键盘按键后绑定。";
@@ -6151,6 +6153,7 @@ void SetLanguage(Language lang) {
61516153
Settings_Tab_Shortcuts = L"快捷鍵";
61526154
Settings_Hotkey_PressKey = L"請按下按鍵...";
61536155
Settings_Hotkey_Conflict = L"快捷鍵衝突";
6156+
Settings_Hotkey_ConflictPrompt = L"已由「%s」佔用,繼續將清除其快捷鍵。";
61546157
Settings_Hotkey_Restore = L"恢復快捷鍵預設值";
61556158
Settings_Hotkey_Restored = L"已恢復";
61566159
Settings_Hotkey_MouseTip = L"提示:支持滑鼠中鍵、側鍵等滑鼠多功能按鍵。更多側鍵請在滑鼠驅動中映射為鍵盤按鍵後綁定。";
@@ -6162,6 +6165,7 @@ void SetLanguage(Language lang) {
61626165
Settings_Tab_Shortcuts = L"ショートカット";
61636166
Settings_Hotkey_PressKey = L"キーを押してください...";
61646167
Settings_Hotkey_Conflict = L"キーの競合";
6168+
Settings_Hotkey_ConflictPrompt = L"「%s」で使用中。続行すると割り当てを解除します。";
61656169
Settings_Hotkey_Restore = L"既定のショートカットに戻す";
61666170
Settings_Hotkey_Restored = L"復元されました";
61676171
Settings_Hotkey_MouseTip = L"ヒント:中央ボタンやサイドボタンなどのマウス多機能ボタンに対応しています。その他のサイドボタンは、マウスのドライバーでキーボードのキーにマッピングしてからバインドしてください。";
@@ -6173,6 +6177,7 @@ void SetLanguage(Language lang) {
61736177
Settings_Tab_Shortcuts = L"Клавиши";
61746178
Settings_Hotkey_PressKey = L"Нажмите клавиши...";
61756179
Settings_Hotkey_Conflict = L"Конфликт клавиш";
6180+
Settings_Hotkey_ConflictPrompt = L"Занято «%s». Продолжение сбросит привязку.";
61766181
Settings_Hotkey_Restore = L"Сбросить горячие клавиши";
61776182
Settings_Hotkey_Restored = L"Восстановлено";
61786183
Settings_Hotkey_MouseTip = L"Подсказка: поддерживаются средняя кнопка, боковые и другие многофункциональные кнопки мыши. Для сопоставления дополнительных кнопок сначала назначьте их на клавиши клавиатуры в драйвере мыши.";
@@ -6184,6 +6189,7 @@ void SetLanguage(Language lang) {
61846189
Settings_Tab_Shortcuts = L"Kürzel";
61856190
Settings_Hotkey_PressKey = L"Tasten drücken...";
61866191
Settings_Hotkey_Conflict = L"Tastenkonflikt";
6192+
Settings_Hotkey_ConflictPrompt = L"Bereits von „%s“ belegt. Fortfahren löscht die Zuweisung.";
61876193
Settings_Hotkey_Restore = L"Standard-Tastenkombinationen wiederherstellen";
61886194
Settings_Hotkey_Restored = L"Wiederhergestellt";
61896195
Settings_Hotkey_MouseTip = L"Tipp: Unterstützt die mittlere Maustaste, Seitentasten und andere Multifunktionstasten. Ordnen Sie weitere Seitentasten im Maustreiber Tastaturtasten zu, um sie zu binden.";
@@ -6195,6 +6201,7 @@ void SetLanguage(Language lang) {
61956201
Settings_Tab_Shortcuts = L"Atajos";
61966202
Settings_Hotkey_PressKey = L"Presione teclas...";
61976203
Settings_Hotkey_Conflict = L"Conflicto de teclas";
6204+
Settings_Hotkey_ConflictPrompt = L"Usado por \"%s\". Continuar borrará su asignación.";
61986205
Settings_Hotkey_Restore = L"Restablecer atajos predeterminados";
61996206
Settings_Hotkey_Restored = L"Restablecido";
62006207
Settings_Hotkey_MouseTip = L"Consejo: Admite el botón central del mouse, los botones laterales y otros botones multifunción. Asigne botones laterales adicionales a teclas del teclado en el controlador del mouse para vincularlos.";
@@ -6206,6 +6213,7 @@ void SetLanguage(Language lang) {
62066213
Settings_Tab_Shortcuts = L"Raccourcis";
62076214
Settings_Hotkey_PressKey = L"Appuyez sur les touches...";
62086215
Settings_Hotkey_Conflict = L"Conflit de raccourcis";
6216+
Settings_Hotkey_ConflictPrompt = L"Déjà utilisé par « %s ». Continuer effacera son raccourci.";
62096217
Settings_Hotkey_Restore = L"Restaurer les raccourcis par défaut";
62106218
Settings_Hotkey_Restored = L"Restauré";
62116219
Settings_Hotkey_MouseTip = L"Conseil : Prend en charge le bouton central de la souris, les boutons latéraux et autres boutons multifonctions. Mappez les boutons latéraux supplémentaires sur les touches du clavier dans le pilote de votre souris pour les lier.";
@@ -6218,6 +6226,7 @@ void SetLanguage(Language lang) {
62186226
Settings_Tab_Shortcuts = L"Shortcuts";
62196227
Settings_Hotkey_PressKey = L"Press keys...";
62206228
Settings_Hotkey_Conflict = L"Hotkey conflict";
6229+
Settings_Hotkey_ConflictPrompt = L"Already used by \"%s\". Continuing will clear its hotkey.";
62216230
Settings_Hotkey_Restore = L"Restore Default Hotkeys";
62226231
Settings_Hotkey_Restored = L"Restored";
62236232
Settings_Hotkey_MouseTip = L"Tip: Supports middle mouse button, side buttons, and other multi-function mouse keys. Map additional buttons to keyboard keys in your mouse driver to bind them.";

‎QuickView/AppStrings.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ namespace AppStrings {
242242
extern const wchar_t* Settings_Tab_Shortcuts;
243243
extern const wchar_t* Settings_Hotkey_PressKey;
244244
extern const wchar_t* Settings_Hotkey_Conflict;
245+
extern const wchar_t* Settings_Hotkey_ConflictPrompt;
245246
extern const wchar_t* Settings_Hotkey_Restore;
246247
extern const wchar_t* Settings_Hotkey_Restored;
247248
extern const wchar_t* Settings_Hotkey_MouseTip;

‎QuickView/GalleryOverlay.cpp‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "ImageTypes.h"
77
#include "FileNavigator.h"
88
#include "EditState.h"
9+
#include "GeekContextMenu.h"
910
#include "UIRenderer.h"
1011
#include <algorithm>
1112
#include <cmath>
@@ -320,8 +321,22 @@ void GalleryOverlay::Update(float deltaTime, HWND hwnd) {
320321
}
321322
}
322323

324+
// [Fix] When a context menu popup is active, freeze auto-dismiss entirely.
325+
// Running the fade-out animation while a DComp popup is open wastes GPU frames
326+
// and destabilizes the popup's DWM Acrylic/Mica backdrop composition.
327+
const bool menuOpen = QuickView::UI::Menu::GeekContextMenu::IsMenuOpen();
328+
if (menuOpen) {
329+
m_dismissalTimer = 0.0f;
330+
// Snap any in-progress fade to its target so we stop driving repaints.
331+
if (fabsf(m_transitionProgress - m_targetProgress) > 0.001f) {
332+
m_transitionProgress = m_targetProgress;
333+
m_gridProgress = m_targetGridProgress;
334+
repaintNeeded = true;
335+
}
336+
}
337+
323338
extern bool g_isDraggingFilmstrip;
324-
if (!m_mouseInGallery && !m_isPinned && !g_isDraggingFilmstrip && !g_imagePath.empty() && m_mode != GalleryMode::FullGrid && m_targetGridProgress < 0.5f) {
339+
if (!menuOpen && !m_mouseInGallery && !m_isPinned && !g_isDraggingFilmstrip && !g_imagePath.empty() && m_mode != GalleryMode::FullGrid && m_targetGridProgress < 0.5f) {
325340
m_dismissalTimer += deltaTime;
326341
if (m_dismissalTimer >= g_config.GalleryExitDelay) {
327342
Close(true);

‎QuickView/GalleryOverlay.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,12 @@ class GalleryOverlay {
5757
}
5858
float GetRippleProgress() const { return m_hotspotRippleProgress; }
5959

60+
// Force-finish any in-progress fade transition (skip remaining animation frames)
61+
void ForceFinishTransition() {
62+
m_transitionProgress = m_targetProgress;
63+
m_gridProgress = m_targetGridProgress;
64+
}
65+
6066
// Pin (persistent filmstrip) mode
6167
void TogglePin() { m_isPinned = !m_isPinned; }
6268
void SetPinned(bool pinned) { m_isPinned = pinned; }

‎QuickView/GeekContextMenu.h‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ class GeekContextMenu {
110110
std::vector<GeekMenuItem> items,
111111
GeekContextMenu* parentMenu);
112112
static void DismissAll(UINT cmdId = 0);
113+
static bool IsMenuOpen() { return s_root != nullptr; }
113114
static void EnsureClassRegistered();
114115

115116
private:

‎QuickView/QuickView.rc‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
// Version Information - This sets the display name in Windows
1414
VS_VERSION_INFO VERSIONINFO
15-
FILEVERSION 6,28,0,0
16-
PRODUCTVERSION 6,28,0,0
15+
FILEVERSION 6,28,1,0
16+
PRODUCTVERSION 6,28,1,0
1717
FILEFLAGSMASK 0x3fL
1818
FILEFLAGS 0x0L
1919
FILEOS 0x40004L
@@ -26,12 +26,12 @@ BEGIN
2626
BEGIN
2727
VALUE "CompanyName", "QuickView"
2828
VALUE "FileDescription", "QuickView"
29-
VALUE "FileVersion", "6.28.0.0"
29+
VALUE "FileVersion", "6.28.1.0"
3030
VALUE "InternalName", "QuickView"
3131
VALUE "LegalCopyright", "Copyright (C) 2026"
3232
VALUE "OriginalFilename", "QuickView.exe"
3333
VALUE "ProductName", "QuickView"
34-
VALUE "ProductVersion", "6.28.0.0"
34+
VALUE "ProductVersion", "6.28.1.0"
3535
END
3636
END
3737
BLOCK "VarFileInfo"

‎QuickView/SettingsOverlay.cpp‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5001,11 +5001,32 @@ void SettingsOverlay::OnHotkeyCaptured(const KeyCombo& combo) {
50015001

50025002
if (conflictAction != HotkeyAction::None) {
50035003
std::wstring actionName = AppStrings::GetHotkeyActionName(conflictAction);
5004-
std::wstring warnMsg = std::wstring(AppStrings::Settings_Hotkey_Conflict) + L": " + actionName;
5005-
5006-
m_lastConflictAction = action;
5007-
m_lastConflictMsg = warnMsg;
5008-
m_lastConflictTime = GetTickCount();
5004+
wchar_t contentBuf[512] = { 0 };
5005+
swprintf_s(contentBuf, 512, AppStrings::Settings_Hotkey_ConflictPrompt, actionName.c_str());
5006+
5007+
std::vector<DialogButton> buttons = {
5008+
{ DialogResult::Yes, AppStrings::Dialog_ButtonContinue, true },
5009+
{ DialogResult::Cancel, AppStrings::Dialog_Cancel }
5010+
};
5011+
5012+
DialogResult result = AppContext::GetInstance().DialogCtrl->ShowDialog(
5013+
m_hwnd,
5014+
AppStrings::Settings_Hotkey_Conflict,
5015+
contentBuf,
5016+
D2D1::ColorF(D2D1::ColorF::DodgerBlue),
5017+
buttons
5018+
);
5019+
5020+
if (result == DialogResult::Yes) {
5021+
for (auto& binding : g_hotkeys) {
5022+
if (binding.action == conflictAction) {
5023+
binding.combo = KeyCombo{};
5024+
} else if (binding.action == action) {
5025+
binding.combo = combo;
5026+
}
5027+
}
5028+
SaveConfig();
5029+
}
50095030
} else {
50105031
// Apply new key combo
50115032
for (auto& binding : g_hotkeys) {

‎QuickView/main.cpp‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2708,8 +2708,24 @@ DialogLayout CalculateDialogLayout(D2D1_SIZE_F size) {
27082708
int titleLines = (int)(AppContext::GetInstance().Dialog.Title.length() / 20) + 1;
27092709
if (titleLines > 3) titleLines = 3; // Max 3 lines
27102710

2711-
// Message usually single line
2712-
int msgLines = 1;
2711+
// Estimate message wrapping and explicit line breaks (\n)
2712+
const std::wstring& msgStr = AppContext::GetInstance().Dialog.Message;
2713+
int msgLines = 0;
2714+
size_t startPos = 0;
2715+
while (startPos < msgStr.length()) {
2716+
size_t nextPos = msgStr.find(L'\n', startPos);
2717+
std::wstring_view line = (nextPos == std::wstring::npos) ?
2718+
std::wstring_view(msgStr.c_str() + startPos) :
2719+
std::wstring_view(msgStr.c_str() + startPos, nextPos - startPos);
2720+
2721+
int subLines = static_cast<int>(line.length() / 20) + 1;
2722+
msgLines += subLines;
2723+
2724+
if (nextPos == std::wstring::npos) break;
2725+
startPos = nextPos + 1;
2726+
}
2727+
if (msgLines < 1) msgLines = 1;
2728+
if (msgLines > 8) msgLines = 8;
27132729

27142730
float contentHeight = (titleLines * titleHeight) + (msgLines * messageHeight);
27152731
float qualityHeight = !AppContext::GetInstance().Dialog.QualityText.empty() ? 28.0f * s : 0.0f; // Add space for quality text
@@ -2720,7 +2736,7 @@ DialogLayout CalculateDialogLayout(D2D1_SIZE_F size) {
27202736

27212737
float dlgH = padding + contentHeight + qualityHeight + inputHeight + checkboxHeight + buttonsHeight + 20.0f * s;
27222738
if (dlgH < 160.0f * s) dlgH = 160.0f * s;
2723-
if (dlgH > 350.0f * s) dlgH = 350.0f * s;
2739+
if (dlgH > 480.0f * s) dlgH = 480.0f * s;
27242740

27252741
auto clamp = [](float v, float minV, float maxV) {
27262742
if (v < minV) return minV;
@@ -10492,6 +10508,13 @@ SKIP_EDGE_NAV:;
1049210508
bool menuEnableSoftProofing = contextLeft ? GetPaneContext(PaneSlot::Left).EnableSoftProofing : g_runtime.EnableSoftProofing;
1049310509
std::wstring menuSoftProofPath = contextLeft ? GetPaneContext(PaneSlot::Left).SoftProofProfilePath : g_runtime.SoftProofProfilePath;
1049410510

10511+
// [Fix] Snap any in-progress gallery fade-out before opening the popup menu.
10512+
// The fade animation drives high-frequency DComp Present() which destabilizes
10513+
// the menu's DWM Acrylic/Mica backdrop composition, causing a translucent flash.
10514+
if (g_gallery.IsVisible()) {
10515+
g_gallery.ForceFinishTransition();
10516+
}
10517+
1049510518
ShowContextMenu(hwnd, pt, hasImage, extensionFixNeeded, g_runtime.LockWindowSize, g_runtime.ShowInfoPanel, g_runtime.InfoPanelExpanded, g_config.AlwaysOnTop, renderRaw, isRaw, IsZoomed(hwnd) != 0, g_runtime.CrossMonitorMode, IsCompareModeActive(), isPixelArtMode, menuCmsMode, menuEnableSoftProofing, menuSoftProofPath);
1049610519
return 0;
1049710520
}

0 commit comments

Comments
 (0)