From 32bbe89911057289edd5851a97c91761dbdf3d32 Mon Sep 17 00:00:00 2001 From: Boris Yumankulov Date: Tue, 17 Jun 2025 22:58:57 +0500 Subject: [PATCH] fix: enforce mutual exclusivity of hovered and focused states in GameCard Signed-off-by: Boris Yumankulov --- portprotonqt/game_card.py | 11 +++++++++- portprotonqt/main_window.py | 41 ++++++++++++++++++++++++++++++++++--- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/portprotonqt/game_card.py b/portprotonqt/game_card.py index 90668f4..24e4964 100644 --- a/portprotonqt/game_card.py +++ b/portprotonqt/game_card.py @@ -26,6 +26,7 @@ class GameCard(QFrame): removeFromSteamRequested = Signal(str, str) # name, exec_line openGameFolderRequested = Signal(str, str) # name, exec_line hoverChanged = Signal(str, bool) + focusChanged = Signal(str, bool) def __init__(self, name, description, cover_path, appid, controller_support, exec_line, last_launch, formatted_playtime, protondb_tier, anticheat_status, last_launch_ts, playtime_seconds, game_source, @@ -475,7 +476,9 @@ class GameCard(QFrame): def enterEvent(self, event): self._hovered = True + self._focused = False self.hoverChanged.emit(self.name, True) + self.thickness_anim.stop() if self._isPulseAnimationConnected: self.thickness_anim.finished.disconnect(self.startPulseAnimation) @@ -496,6 +499,7 @@ class GameCard(QFrame): self.gradient_anim.setLoopCount(-1) self.gradient_anim.start() + self.clearFocus() super().enterEvent(event) def leaveEvent(self, event): @@ -521,6 +525,10 @@ class GameCard(QFrame): def focusInEvent(self, event): self._focused = True + self._hovered = False + self.hoverChanged.emit(self.name, False) + self.focusChanged.emit(self.name, True) + self.thickness_anim.stop() if self._isPulseAnimationConnected: self.thickness_anim.finished.disconnect(self.startPulseAnimation) @@ -545,7 +553,8 @@ class GameCard(QFrame): def focusOutEvent(self, event): self._focused = False - if not self._hovered: # Сохраняем анимацию, если есть наведение + self.focusChanged.emit(self.name, False) + if not self._hovered: if self.gradient_anim: self.gradient_anim.stop() self.gradient_anim = None diff --git a/portprotonqt/main_window.py b/portprotonqt/main_window.py index 6b6ed82..a6f273e 100644 --- a/portprotonqt/main_window.py +++ b/portprotonqt/main_window.py @@ -56,6 +56,7 @@ class MainWindow(QMainWindow): self.current_exec_line = None self.currentDetailPage = None self.current_play_button = None + self.current_focused_card = None self.pending_games = [] self.game_card_cache = {} self.pending_images = {} @@ -242,10 +243,39 @@ class MainWindow(QMainWindow): self.updateGameGrid() self.progress_bar.setVisible(False) + def _on_card_focused(self, game_name: str, is_focused: bool): + """Обработчик сигнала focusChanged от GameCard.""" + card_key = None + for key, card in self.game_card_cache.items(): + if card.name == game_name: + card_key = key + break + + if not card_key: + return + + card = self.game_card_cache[card_key] + + if is_focused: + # Если карточка получила фокус + if self.current_hovered_card and self.current_hovered_card != card: + # Сбрасываем текущую hovered карточку + self.current_hovered_card._hovered = False + self.current_hovered_card.leaveEvent(None) + self.current_hovered_card = None + if self.current_focused_card and self.current_focused_card != card: + # Сбрасываем текущую focused карточку + self.current_focused_card._focused = False + self.current_focused_card.clearFocus() + self.current_focused_card = card + else: + # Если карточка потеряла фокус + if self.current_focused_card == card: + self.current_focused_card = None + def _on_card_hovered(self, game_name: str, is_hovered: bool): """Обработчик сигнала hoverChanged от GameCard.""" card_key = None - # Находим ключ карточки по имени игры for key, card in self.game_card_cache.items(): if card.name == game_name: card_key = key @@ -258,10 +288,14 @@ class MainWindow(QMainWindow): if is_hovered: # Если мышь наведена на карточку + if self.current_focused_card and self.current_focused_card != card: + # Сбрасываем текущую focused карточку + self.current_focused_card._focused = False + self.current_focused_card.clearFocus() if self.current_hovered_card and self.current_hovered_card != card: - # Сбрасываем предыдущую выделенную карточку + # Сбрасываем предыдущую hovered карточку self.current_hovered_card._hovered = False - self.current_hovered_card.leaveEvent(None) # Принудительно вызываем leaveEvent + self.current_hovered_card.leaveEvent(None) self.current_hovered_card = card else: # Если мышь покинула карточку @@ -709,6 +743,7 @@ class MainWindow(QMainWindow): context_menu_manager=self.context_menu_manager ) card.hoverChanged.connect(self._on_card_hovered) + card.focusChanged.connect(self._on_card_focused) # Подключаем сигналы контекстного меню card.editShortcutRequested.connect(self.context_menu_manager.edit_game_shortcut) card.deleteGameRequested.connect(self.context_menu_manager.delete_game)