mirror of
https://github.com/KeksPirates/SoftwareManager.git
synced 2026-08-04 01:49:42 +02:00
a29f58c023
Introduce _apply_layout_fast to update the image overlay quickly on window resize using the cached QImage and FastTransformation. Called from the Resize event handler before the resize timer, it handles wallpaper mode (fast scale, center-crop to parent) and non-wallpaper mode (positioning by state.image_position and state.image_offset) to provide immediate visual feedback without running the heavier _apply_layout.
251 lines
9.9 KiB
Python
251 lines
9.9 KiB
Python
from PySide6.QtWidgets import QLabel, QGraphicsOpacityEffect, QStackedWidget
|
|
from PySide6.QtCore import Qt, QSize, QEvent, QObject, QTimer
|
|
from PySide6.QtGui import QImage, QPixmap
|
|
from utils.data.state import state
|
|
import darkdetect
|
|
import os
|
|
|
|
|
|
class Image(QObject):
|
|
def __init__(self, parent):
|
|
super().__init__(parent)
|
|
self.application = parent
|
|
self.overlay_label = QLabel(parent)
|
|
self.overlay_label.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
|
|
|
|
self.opacity_effect = QGraphicsOpacityEffect()
|
|
self.overlay_label.setGraphicsEffect(self.opacity_effect)
|
|
|
|
self._current_image_path = None
|
|
self._cached_qimage = None
|
|
self._wallpaper_active = False
|
|
self._original_stylesheets = {}
|
|
|
|
self._resize_timer = QTimer(self)
|
|
self._resize_timer.setSingleShot(True)
|
|
self._resize_timer.setInterval(100)
|
|
self._resize_timer.timeout.connect(self._on_resize_finished)
|
|
|
|
parent.installEventFilter(self)
|
|
state.image_changed.connect(self.update_image_overlay)
|
|
|
|
if state.image_path and os.path.exists(state.image_path):
|
|
self._load_and_display(state.image_path)
|
|
|
|
def eventFilter(self, obj, event):
|
|
if obj == self.application and event.type() == QEvent.Type.Resize:
|
|
if self._current_image_path:
|
|
self._apply_layout_fast()
|
|
self._resize_timer.start()
|
|
return False
|
|
|
|
def _on_resize_finished(self):
|
|
if self._current_image_path:
|
|
self._apply_layout()
|
|
|
|
def _set_wallpaper_transparency(self, enabled):
|
|
if self._wallpaper_active == enabled:
|
|
return
|
|
self._wallpaper_active = enabled
|
|
parent = self.application
|
|
|
|
central = parent.centralWidget()
|
|
if central:
|
|
central.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
for attr in ['tab_wrapper', 'corner_widget', 'titlebar']:
|
|
w = getattr(parent, attr, None)
|
|
if w:
|
|
w.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
if hasattr(parent, 'tabs'):
|
|
tabs = parent.tabs
|
|
tabs.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
for i in range(tabs.count()):
|
|
page = tabs.widget(i)
|
|
if page:
|
|
page.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
stack = tabs.findChild(QStackedWidget)
|
|
if stack:
|
|
stack.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
tab_bar = tabs.tabBar()
|
|
if tab_bar:
|
|
tab_bar.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
if 'tabs' not in self._original_stylesheets:
|
|
self._original_stylesheets['tabs'] = tabs.styleSheet()
|
|
if enabled:
|
|
tabs.setStyleSheet(
|
|
self._original_stylesheets['tabs']
|
|
+ "\nQTabWidget::pane { background: transparent; }"
|
|
+ "\nQTabBar { background: transparent; }"
|
|
+ "\nQTabBar::tab { background: transparent; }"
|
|
)
|
|
else:
|
|
tabs.setStyleSheet(self._original_stylesheets['tabs'])
|
|
|
|
# Searchbar
|
|
if hasattr(parent, 'searchbar'):
|
|
if 'searchbar' not in self._original_stylesheets:
|
|
self._original_stylesheets['searchbar'] = parent.searchbar.styleSheet()
|
|
if enabled:
|
|
parent.searchbar.setStyleSheet("QLineEdit { background-color: transparent; }")
|
|
else:
|
|
parent.searchbar.setStyleSheet(self._original_stylesheets['searchbar'])
|
|
|
|
# Download button
|
|
if hasattr(parent, 'dlbutton'):
|
|
if 'dlbutton' not in self._original_stylesheets:
|
|
self._original_stylesheets['dlbutton'] = parent.dlbutton.styleSheet()
|
|
if enabled:
|
|
parent.dlbutton.setStyleSheet("QPushButton { background-color: transparent; }")
|
|
else:
|
|
parent.dlbutton.setStyleSheet(self._original_stylesheets['dlbutton'])
|
|
|
|
# Labels
|
|
for attr in ['emptyResults', 'emptyDownload']:
|
|
w = getattr(parent, attr, None)
|
|
if w:
|
|
w.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, enabled)
|
|
|
|
if hasattr(parent, 'tracker_list'):
|
|
if 'tracker_list' not in self._original_stylesheets:
|
|
self._original_stylesheets['tracker_list'] = parent.tracker_list.styleSheet()
|
|
if enabled:
|
|
popup_bg = '#1e1e1e' if darkdetect.isDark() else '#ffffff'
|
|
parent.tracker_list.setStyleSheet(
|
|
"QComboBox { background-color: transparent; }"
|
|
f" QComboBox QAbstractItemView {{ background-color: {popup_bg}; }}"
|
|
)
|
|
else:
|
|
parent.tracker_list.setStyleSheet(self._original_stylesheets['tracker_list'])
|
|
|
|
def _load_and_display(self, image_path):
|
|
if state.image_enabled is not True:
|
|
self.overlay_label.hide()
|
|
self._set_wallpaper_transparency(False)
|
|
return
|
|
self._current_image_path = image_path
|
|
|
|
# Only reload from disk when the path actually changed
|
|
if self._cached_qimage is None or image_path != getattr(self, '_cached_path', None):
|
|
image = QImage(image_path)
|
|
if image.isNull():
|
|
self.overlay_label.hide()
|
|
self._cached_qimage = None
|
|
return
|
|
self._cached_qimage = image
|
|
self._cached_path = image_path
|
|
|
|
self._apply_layout()
|
|
|
|
def _apply_layout_fast(self):
|
|
if self._cached_qimage is None or not state.image_enabled:
|
|
return
|
|
|
|
parent = self.application
|
|
image = self._cached_qimage
|
|
|
|
if getattr(state, "image_as_wallpaper", False):
|
|
scaled = image.scaled(
|
|
parent.size(),
|
|
Qt.AspectRatioMode.KeepAspectRatioByExpanding,
|
|
Qt.TransformationMode.FastTransformation
|
|
)
|
|
cx = (scaled.width() - parent.width()) // 2
|
|
cy = (scaled.height() - parent.height()) // 2
|
|
cropped = scaled.copy(cx, cy, parent.width(), parent.height())
|
|
self.overlay_label.setPixmap(QPixmap.fromImage(cropped))
|
|
self.overlay_label.setGeometry(0, 0, parent.width(), parent.height())
|
|
else:
|
|
w = self.overlay_label.width()
|
|
h = self.overlay_label.height()
|
|
pos = state.image_position
|
|
off = int(state.image_offset)
|
|
if pos == "top-left":
|
|
x, y = off, off
|
|
elif pos == "top-right":
|
|
x, y = parent.width() - w - off, off
|
|
elif pos == "bottom-left":
|
|
x, y = off, parent.height() - h - off
|
|
elif pos == "center":
|
|
x, y = (parent.width() - w) // 2, (parent.height() - h) // 2
|
|
else:
|
|
x, y = parent.width() - w - off, parent.height() - h - off
|
|
self.overlay_label.move(x, y)
|
|
|
|
def _apply_layout(self):
|
|
if self._cached_qimage is None or not state.image_enabled:
|
|
self.overlay_label.hide()
|
|
return
|
|
|
|
parent = self.application
|
|
image = self._cached_qimage
|
|
|
|
if getattr(state, "image_as_wallpaper", False):
|
|
scaled_image = image.scaled(
|
|
parent.size(),
|
|
Qt.AspectRatioMode.KeepAspectRatioByExpanding,
|
|
Qt.TransformationMode.SmoothTransformation
|
|
)
|
|
|
|
crop_x = (scaled_image.width() - parent.width()) // 2
|
|
crop_y = (scaled_image.height() - parent.height()) // 2
|
|
scaled_image = scaled_image.copy(crop_x, crop_y, parent.width(), parent.height())
|
|
|
|
pixmap = QPixmap.fromImage(scaled_image)
|
|
self.overlay_label.setPixmap(pixmap)
|
|
|
|
self.overlay_label.setGeometry(0, 0, parent.width(), parent.height())
|
|
self.overlay_label.lower()
|
|
|
|
self.opacity_effect.setOpacity(state.image_opacity / 100)
|
|
self._set_wallpaper_transparency(True)
|
|
|
|
else:
|
|
self._set_wallpaper_transparency(False)
|
|
scaled_image = image.scaledToWidth(
|
|
state.image_width, Qt.TransformationMode.SmoothTransformation
|
|
)
|
|
|
|
max_width = parent.width()
|
|
max_height = parent.height()
|
|
if scaled_image.width() > max_width or scaled_image.height() > max_height:
|
|
scaled_image = scaled_image.scaled(
|
|
QSize(max_width, max_height),
|
|
Qt.AspectRatioMode.KeepAspectRatio,
|
|
Qt.TransformationMode.SmoothTransformation,
|
|
)
|
|
|
|
pixmap = QPixmap.fromImage(scaled_image)
|
|
self.overlay_label.setPixmap(pixmap)
|
|
self.overlay_label.adjustSize()
|
|
self.overlay_label.raise_()
|
|
|
|
pos = state.image_position
|
|
off = int(state.image_offset)
|
|
w = self.overlay_label.width()
|
|
h = self.overlay_label.height()
|
|
if pos == "top-left":
|
|
x, y = off, off
|
|
elif pos == "top-right":
|
|
x, y = parent.width() - w - off, off
|
|
elif pos == "bottom-left":
|
|
x, y = off, parent.height() - h - off
|
|
elif pos == "center":
|
|
x, y = (parent.width() - w) // 2, (parent.height() - h) // 2
|
|
else: # bottom-right (default)
|
|
x, y = parent.width() - w - off, parent.height() - h - off
|
|
|
|
self.opacity_effect.setOpacity(state.image_opacity / 100)
|
|
|
|
self.overlay_label.move(x, y)
|
|
self.overlay_label.show()
|
|
|
|
def update_image_overlay(self, new_image_path):
|
|
if new_image_path != getattr(self, '_cached_path', None):
|
|
self._cached_qimage = None
|
|
self._load_and_display(new_image_path) |