Enhance title bar theming and refresh logic; ensure immediate updates for main and dialog windows
This commit is contained in:
@@ -2094,8 +2094,19 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
if result == 0: # S_OK
|
if result == 0: # S_OK
|
||||||
logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar ({'newer' if use_newer_api else 'legacy'} API)")
|
logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar ({'newer' if use_newer_api else 'legacy'} API)")
|
||||||
|
|
||||||
# Force window to redraw
|
# Force immediate window redraw using multiple methods
|
||||||
self.update()
|
self.update()
|
||||||
|
self.repaint()
|
||||||
|
|
||||||
|
# Force a window refresh by briefly changing and restoring window flags
|
||||||
|
try:
|
||||||
|
original_flags = self.windowFlags()
|
||||||
|
self.setWindowFlags(original_flags | QtCore.Qt.WindowType.WindowStaysOnTopHint)
|
||||||
|
self.setWindowFlags(original_flags)
|
||||||
|
self.show()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
logger.debug(f"Windows title bar API returned error code: {result}")
|
logger.debug(f"Windows title bar API returned error code: {result}")
|
||||||
@@ -2115,6 +2126,17 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
if result == 0:
|
if result == 0:
|
||||||
logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar (fallback API)")
|
logger.debug(f"Applied Windows {'dark' if enable_dark else 'light'} title bar (fallback API)")
|
||||||
self.update()
|
self.update()
|
||||||
|
self.repaint()
|
||||||
|
|
||||||
|
# Force window refresh
|
||||||
|
try:
|
||||||
|
original_flags = self.windowFlags()
|
||||||
|
self.setWindowFlags(original_flags | QtCore.Qt.WindowType.WindowStaysOnTopHint)
|
||||||
|
self.setWindowFlags(original_flags)
|
||||||
|
self.show()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
return True
|
return True
|
||||||
except Exception as fallback_e:
|
except Exception as fallback_e:
|
||||||
logger.debug(f"Windows dark title bar fallback failed: {fallback_e}")
|
logger.debug(f"Windows dark title bar fallback failed: {fallback_e}")
|
||||||
@@ -2171,17 +2193,36 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
colors = self.get_theme_styles()
|
colors = self.get_theme_styles()
|
||||||
is_dark = self.get_effective_dark_mode()
|
is_dark = self.get_effective_dark_mode()
|
||||||
|
|
||||||
# Apply title bar theming with multiple attempts to ensure it takes effect
|
# Apply title bar theming immediately
|
||||||
def apply_title_bar_theming():
|
self.apply_dark_title_bar(is_dark)
|
||||||
success = self.apply_dark_title_bar(is_dark)
|
|
||||||
if not success:
|
|
||||||
# Retry after a longer delay if first attempt failed
|
|
||||||
QtCore.QTimer.singleShot(100, lambda: self.apply_dark_title_bar(is_dark))
|
|
||||||
|
|
||||||
# Apply immediately and with delays to handle different timing scenarios
|
# Also apply to any open dialogs immediately
|
||||||
apply_title_bar_theming()
|
for dialog in QtWidgets.QApplication.allWidgets():
|
||||||
QtCore.QTimer.singleShot(50, apply_title_bar_theming)
|
if isinstance(dialog, QtWidgets.QDialog) and dialog.isVisible():
|
||||||
QtCore.QTimer.singleShot(200, apply_title_bar_theming)
|
try:
|
||||||
|
hwnd = int(dialog.winId())
|
||||||
|
if hwnd:
|
||||||
|
import ctypes
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
|
||||||
|
|
||||||
|
# Try both API versions
|
||||||
|
for attribute in [DWMWA_USE_IMMERSIVE_DARK_MODE, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1]:
|
||||||
|
try:
|
||||||
|
result = ctypes.windll.dwmapi.DwmSetWindowAttribute(
|
||||||
|
hwnd,
|
||||||
|
attribute,
|
||||||
|
ctypes.byref(ctypes.c_int(1 if is_dark else 0)),
|
||||||
|
ctypes.sizeof(ctypes.c_int)
|
||||||
|
)
|
||||||
|
if result == 0:
|
||||||
|
dialog.update()
|
||||||
|
dialog.repaint()
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
# Main window style
|
# Main window style
|
||||||
main_style = f"""
|
main_style = f"""
|
||||||
@@ -2234,13 +2275,17 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
QComboBox::drop-down {{
|
QComboBox::drop-down {{
|
||||||
border: none;
|
border: none;
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
subcontrol-origin: padding;
|
||||||
|
subcontrol-position: center right;
|
||||||
}}
|
}}
|
||||||
QComboBox::down-arrow {{
|
QComboBox::down-arrow {{
|
||||||
image: none;
|
image: none;
|
||||||
border-left: 4px solid transparent;
|
width: 0;
|
||||||
border-right: 4px solid transparent;
|
height: 0;
|
||||||
border-top: 4px solid {colors['foreground']};
|
border-left: 5px solid transparent;
|
||||||
margin: 0px 4px 0px 4px;
|
border-right: 5px solid transparent;
|
||||||
|
border-top: 6px solid {colors['foreground']};
|
||||||
|
margin: 0px;
|
||||||
}}
|
}}
|
||||||
QListWidget {{
|
QListWidget {{
|
||||||
font-size: 9pt;
|
font-size: 9pt;
|
||||||
@@ -2329,6 +2374,39 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
is_dark = self.get_effective_dark_mode()
|
is_dark = self.get_effective_dark_mode()
|
||||||
self.apply_dark_title_bar(is_dark)
|
self.apply_dark_title_bar(is_dark)
|
||||||
|
|
||||||
|
# Also apply to any open dialogs immediately
|
||||||
|
for dialog in QtWidgets.QApplication.allWidgets():
|
||||||
|
if isinstance(dialog, QtWidgets.QDialog) and dialog.isVisible():
|
||||||
|
try:
|
||||||
|
hwnd = int(dialog.winId())
|
||||||
|
if hwnd:
|
||||||
|
import ctypes
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE = 20
|
||||||
|
DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19
|
||||||
|
|
||||||
|
# Try both API versions
|
||||||
|
for attribute in [DWMWA_USE_IMMERSIVE_DARK_MODE, DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1]:
|
||||||
|
try:
|
||||||
|
result = ctypes.windll.dwmapi.DwmSetWindowAttribute(
|
||||||
|
hwnd,
|
||||||
|
attribute,
|
||||||
|
ctypes.byref(ctypes.c_int(1 if is_dark else 0)),
|
||||||
|
ctypes.sizeof(ctypes.c_int)
|
||||||
|
)
|
||||||
|
if result == 0:
|
||||||
|
dialog.update()
|
||||||
|
dialog.repaint()
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Force an immediate application repaint for instant visual feedback
|
||||||
|
QtWidgets.QApplication.processEvents()
|
||||||
|
self.update()
|
||||||
|
self.repaint()
|
||||||
|
|
||||||
# Save the theme preference immediately
|
# Save the theme preference immediately
|
||||||
self._save_window_geometry()
|
self._save_window_geometry()
|
||||||
|
|
||||||
@@ -2457,11 +2535,32 @@ class MainWindow(QtWidgets.QMainWindow):
|
|||||||
self.theme_combo.setMinimumWidth(100)
|
self.theme_combo.setMinimumWidth(100)
|
||||||
self.theme_combo.setMaximumWidth(120)
|
self.theme_combo.setMaximumWidth(120)
|
||||||
self.theme_combo.setToolTip('Select theme: System (follows OS), Light, or Dark')
|
self.theme_combo.setToolTip('Select theme: System (follows OS), Light, or Dark')
|
||||||
|
|
||||||
|
# Make the theme dropdown open upwards by setting a custom style
|
||||||
|
# This will be handled in the theme application
|
||||||
|
|
||||||
self.theme_combo.addItem('System', 'system')
|
self.theme_combo.addItem('System', 'system')
|
||||||
self.theme_combo.addItem('Light', 'light')
|
self.theme_combo.addItem('Light', 'light')
|
||||||
self.theme_combo.addItem('Dark', 'dark')
|
self.theme_combo.addItem('Dark', 'dark')
|
||||||
self.theme_combo.setCurrentText('System') # Default to system
|
self.theme_combo.setCurrentText('System') # Default to system
|
||||||
self.theme_combo.currentTextChanged.connect(self.on_theme_changed)
|
self.theme_combo.currentTextChanged.connect(self.on_theme_changed)
|
||||||
|
|
||||||
|
# Make theme dropdown open upwards
|
||||||
|
def showPopupUpwards():
|
||||||
|
# Get the combo box position and size
|
||||||
|
combo_rect = self.theme_combo.geometry()
|
||||||
|
popup = self.theme_combo.view()
|
||||||
|
popup_height = popup.sizeHint().height()
|
||||||
|
|
||||||
|
# Calculate position above the combo box
|
||||||
|
global_pos = self.theme_combo.mapToGlobal(QtCore.QPoint(0, -popup_height))
|
||||||
|
|
||||||
|
# Show the popup at the calculated position
|
||||||
|
popup.setGeometry(global_pos.x(), global_pos.y(), combo_rect.width(), popup_height)
|
||||||
|
popup.show()
|
||||||
|
|
||||||
|
# Override the showPopup method to make it open upwards
|
||||||
|
self.theme_combo.showPopup = showPopupUpwards
|
||||||
|
|
||||||
# State label
|
# State label
|
||||||
self.state_label = QtWidgets.QLabel('State: Paused')
|
self.state_label = QtWidgets.QLabel('State: Paused')
|
||||||
|
|||||||
Reference in New Issue
Block a user