diff --git a/portprotonqt/custom_widgets.py b/portprotonqt/custom_widgets.py index 2a362cc..52cf608 100644 --- a/portprotonqt/custom_widgets.py +++ b/portprotonqt/custom_widgets.py @@ -1,5 +1,5 @@ import numpy as np -from PySide6.QtWidgets import QLabel, QPushButton, QWidget, QLayout, QStyleOption, QLayoutItem +from PySide6.QtWidgets import QLabel, QPushButton, QWidget, QLayout, QLayoutItem from PySide6.QtCore import Qt, Signal, QRect, QPoint, QSize from PySide6.QtGui import QFont, QFontMetrics, QPainter @@ -133,18 +133,7 @@ class FlowLayout(QLayout): class ClickableLabel(QLabel): clicked = Signal() - def __init__(self, *args, icon=None, icon_size=16, icon_space=5, change_cursor=True, **kwargs): - """ - Поддерживаются вызовы: - - ClickableLabel("текст", parent=...) – первый аргумент строка, - - ClickableLabel(parent, text="...") – если первым аргументом передается родитель. - - Аргументы: - icon: QIcon или None – иконка, которая будет отрисована вместе с текстом. - icon_size: int – размер иконки (ширина и высота). - icon_space: int – отступ между иконкой и текстом. - change_cursor: bool – изменять ли курсор на PointingHandCursor при наведении (по умолчанию True). - """ + def __init__(self, *args, icon=None, icon_size=16, icon_space=5, change_cursor=True, font_scale_factor=0.06, **kwargs): if args and isinstance(args[0], str): text = args[0] parent = kwargs.get("parent", None) @@ -162,20 +151,38 @@ class ClickableLabel(QLabel): self._icon = icon self._icon_size = icon_size self._icon_space = icon_space + self._font_scale_factor = font_scale_factor + self._card_width = 250 # Значение по умолчанию if change_cursor: self.setCursor(Qt.CursorShape.PointingHandCursor) + self.updateFontSize() def setIcon(self, icon): - """Устанавливает иконку и перерисовывает виджет.""" self._icon = icon self.update() def icon(self): - """Возвращает текущую иконку.""" return self._icon + def setIconSize(self, icon_size: int, icon_space: int): + self._icon_size = icon_size + self._icon_space = icon_space + self.update() + + def setCardWidth(self, card_width: int): + """Обновляет ширину карточки и пересчитывает размер шрифта.""" + self._card_width = card_width + self.updateFontSize() + + def updateFontSize(self): + """Обновляет размер шрифта на основе card_width и font_scale_factor.""" + font = self.font() + font_size = int(self._card_width * self._font_scale_factor) + font.setPointSize(max(8, font_size)) # Минимальный размер шрифта 8 + self.setFont(font) + self.update() + def paintEvent(self, event): - """Переопределяем отрисовку: рисуем иконку и текст в одном лейбле.""" painter = QPainter(self) painter.setRenderHint(QPainter.RenderHint.Antialiasing) @@ -190,7 +197,6 @@ class ClickableLabel(QLabel): text = self.text() if self._icon: - # Получаем QPixmap нужного размера pixmap = self._icon.pixmap(icon_size, icon_size) icon_rect = QRect(0, 0, icon_size, icon_size) icon_rect.moveTop(rect.top() + (rect.height() - icon_size) // 2) @@ -214,13 +220,8 @@ class ClickableLabel(QLabel): if pixmap: icon_rect.moveLeft(x) text_rect = QRect(x + icon_size + spacing, y, text_width, text_height) - else: - text_rect = QRect(x, y, text_width, text_height) - - option = QStyleOption() - option.initFrom(self) - if pixmap: painter.drawPixmap(icon_rect, pixmap) + self.style().drawItemText( painter, text_rect, diff --git a/portprotonqt/game_card.py b/portprotonqt/game_card.py index ca95cfd..c498e8c 100644 --- a/portprotonqt/game_card.py +++ b/portprotonqt/game_card.py @@ -255,6 +255,42 @@ class GameCard(QFrame): nameLabel.setStyleSheet(self.theme.GAME_CARD_NAME_LABEL_STYLE) layout.addWidget(nameLabel) + def update_card_size(self, new_width: int): + self.card_width = new_width + extra_margin = 20 + self.setFixedSize(new_width + extra_margin, int(new_width * 1.6) + extra_margin) + + if self.coverLabel is None: + return + + coverWidget = self.coverLabel.parentWidget() + if coverWidget is None: + return + + coverWidget.setFixedSize(new_width, int(new_width * 1.2)) + self.coverLabel.setFixedSize(new_width, int(new_width * 1.2)) + + label_ref = weakref.ref(self.coverLabel) + def on_cover_loaded(pixmap): + label = label_ref() + if label: + scaled_pixmap = pixmap.scaled(new_width, int(new_width * 1.2), Qt.AspectRatioMode.KeepAspectRatioByExpanding, Qt.TransformationMode.SmoothTransformation) + rounded_pixmap = round_corners(scaled_pixmap, 15) + label.setPixmap(rounded_pixmap) + + load_pixmap_async(self.cover_path or "", new_width, int(new_width * 1.2), on_cover_loaded) + + badge_width = int(new_width * 2/3) + icon_size = int(new_width * 0.06) + icon_space = int(new_width * 0.012) + for label in [self.steamLabel, self.egsLabel, self.portprotonLabel, self.protondbLabel, self.anticheatLabel]: + if label is not None: + label.setFixedWidth(badge_width) + label.setIconSize(icon_size, icon_space) + label.setCardWidth(new_width) + + self.update() + def update_badge_visibility(self, display_filter: str): """Update badge visibility based on the provided display_filter.""" self.display_filter = display_filter diff --git a/portprotonqt/main_window.py b/portprotonqt/main_window.py index 2cb38fa..a040ce1 100644 --- a/portprotonqt/main_window.py +++ b/portprotonqt/main_window.py @@ -535,11 +535,13 @@ class MainWindow(QMainWindow): def startSearchDebounce(self, text): self.searchDebounceTimer.start() - def on_slider_value_changed(self, value: int): - self.card_width = value - self.sizeSlider.setToolTip(f"{value} px") - save_card_size(value) - self.updateGameGrid() + def on_slider_released(self): + self.card_width = self.sizeSlider.value() + self.sizeSlider.setToolTip(f"{self.card_width} px") + save_card_size(self.card_width) + for card in self.game_card_cache.values(): + card.update_card_size(self.card_width) + self.updateGameGrid() def filterGamesDelayed(self): """Filters games based on search text and updates the grid.""" @@ -581,7 +583,7 @@ class MainWindow(QMainWindow): self.sizeSlider.setFixedWidth(150) self.sizeSlider.setToolTip(f"{self.card_width} px") self.sizeSlider.setStyleSheet(self.theme.SLIDER_SIZE_STYLE) - self.sizeSlider.valueChanged.connect(self.on_slider_value_changed) + self.sizeSlider.sliderReleased.connect(self.on_slider_released) sliderLayout.addWidget(self.sizeSlider) layout.addLayout(sliderLayout)