Compare commits
3 Commits
c037af4314
...
9c4ad0b7ba
Author | SHA1 | Date | |
---|---|---|---|
9c4ad0b7ba
|
|||
0f59c46d36
|
|||
364e1dd02a
|
@@ -24,6 +24,7 @@
|
|||||||
- Пункт в контекстное меню "Удалить из Steam”
|
- Пункт в контекстное меню "Удалить из Steam”
|
||||||
- Метод сортировки сначала избранное
|
- Метод сортировки сначала избранное
|
||||||
- Настройка автоматического перехода в режим полноэкранного отображения приложения при подключении геймпада (по умолчанию отключено)
|
- Настройка автоматического перехода в режим полноэкранного отображения приложения при подключении геймпада (по умолчанию отключено)
|
||||||
|
- Обработчики для QMenu и QComboBox на геймпаде
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Обновлены все иконки
|
- Обновлены все иконки
|
||||||
@@ -39,6 +40,7 @@
|
|||||||
- Карточки теперь фокусируются в направлении движения стрелок или D-pad, например если нажать D-pad вниз то перейдёшь на карточку со следующей колонки, а не по порядку
|
- Карточки теперь фокусируются в направлении движения стрелок или D-pad, например если нажать D-pad вниз то перейдёшь на карточку со следующей колонки, а не по порядку
|
||||||
- D-pad больше не переключает вкладки только RB и LB
|
- D-pad больше не переключает вкладки только RB и LB
|
||||||
- Кнопка добавления игры больше не фокусируется
|
- Кнопка добавления игры больше не фокусируется
|
||||||
|
- Диалог добавления игры теперь открывается только в библиотеке
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Обработка несуществующей темы с возвратом к “standart”
|
- Обработка несуществующей темы с возвратом к “standart”
|
||||||
|
@@ -9,6 +9,7 @@ from PySide6.QtGui import QDesktopServices
|
|||||||
from portprotonqt.config_utils import parse_desktop_entry
|
from portprotonqt.config_utils import parse_desktop_entry
|
||||||
from portprotonqt.localization import _
|
from portprotonqt.localization import _
|
||||||
from portprotonqt.steam_api import is_game_in_steam, add_to_steam, remove_from_steam
|
from portprotonqt.steam_api import is_game_in_steam, add_to_steam, remove_from_steam
|
||||||
|
from portprotonqt.dialogs import AddGameDialog
|
||||||
|
|
||||||
class ContextMenuManager:
|
class ContextMenuManager:
|
||||||
"""Manages context menu actions for game management in PortProtonQT."""
|
"""Manages context menu actions for game management in PortProtonQT."""
|
||||||
@@ -321,7 +322,6 @@ class ContextMenuManager:
|
|||||||
|
|
||||||
def edit_game_shortcut(self, game_name, exec_line, cover_path):
|
def edit_game_shortcut(self, game_name, exec_line, cover_path):
|
||||||
"""Opens the AddGameDialog in edit mode to modify an existing .desktop file."""
|
"""Opens the AddGameDialog in edit mode to modify an existing .desktop file."""
|
||||||
from portprotonqt.dialogs import AddGameDialog # Local import to avoid circular dependency
|
|
||||||
|
|
||||||
if not self._check_portproton():
|
if not self._check_portproton():
|
||||||
return
|
return
|
||||||
|
@@ -3,7 +3,7 @@ import threading
|
|||||||
from typing import Protocol, cast
|
from typing import Protocol, cast
|
||||||
from evdev import InputDevice, ecodes, list_devices
|
from evdev import InputDevice, ecodes, list_devices
|
||||||
import pyudev
|
import pyudev
|
||||||
from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog, QMenu
|
from PySide6.QtWidgets import QWidget, QStackedWidget, QApplication, QScrollArea, QLineEdit, QDialog, QMenu, QComboBox, QListView
|
||||||
from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot
|
from PySide6.QtCore import Qt, QObject, QEvent, QPoint, Signal, Slot
|
||||||
from PySide6.QtGui import QKeyEvent
|
from PySide6.QtGui import QKeyEvent
|
||||||
from portprotonqt.logger import get_logger
|
from portprotonqt.logger import get_logger
|
||||||
@@ -134,20 +134,55 @@ class InputManager(QObject):
|
|||||||
# Handle QMenu (context menu)
|
# Handle QMenu (context menu)
|
||||||
if isinstance(popup, QMenu):
|
if isinstance(popup, QMenu):
|
||||||
if button_code in BUTTONS['confirm'] or button_code in BUTTONS['confirm_stick']:
|
if button_code in BUTTONS['confirm'] or button_code in BUTTONS['confirm_stick']:
|
||||||
# Trigger the currently highlighted menu action and close the menu
|
|
||||||
if popup.activeAction():
|
if popup.activeAction():
|
||||||
popup.activeAction().trigger()
|
popup.activeAction().trigger()
|
||||||
popup.close()
|
popup.close()
|
||||||
return
|
return
|
||||||
elif button_code in BUTTONS['back'] or button_code in BUTTONS['menu']:
|
elif button_code in BUTTONS['back'] or button_code in BUTTONS['menu']:
|
||||||
# Close the menu
|
|
||||||
popup.close()
|
popup.close()
|
||||||
return
|
return
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Handle QComboBox
|
||||||
|
if isinstance(focused, QComboBox):
|
||||||
|
if button_code in BUTTONS['confirm'] or button_code in BUTTONS['confirm_stick']:
|
||||||
|
focused.showPopup()
|
||||||
|
return
|
||||||
|
|
||||||
|
# Handle QListView
|
||||||
|
if isinstance(focused, QListView):
|
||||||
|
combo = None
|
||||||
|
parent = focused.parentWidget()
|
||||||
|
while parent:
|
||||||
|
if isinstance(parent, QComboBox):
|
||||||
|
combo = parent
|
||||||
|
break
|
||||||
|
parent = parent.parentWidget()
|
||||||
|
|
||||||
|
if button_code in BUTTONS['confirm'] or button_code in BUTTONS['confirm_stick']:
|
||||||
|
idx = focused.currentIndex()
|
||||||
|
if idx.isValid():
|
||||||
|
if combo:
|
||||||
|
combo.setCurrentIndex(idx.row())
|
||||||
|
combo.hidePopup()
|
||||||
|
combo.setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
|
else:
|
||||||
|
focused.activated.emit(idx)
|
||||||
|
focused.clicked.emit(idx)
|
||||||
|
focused.hide()
|
||||||
|
return
|
||||||
|
|
||||||
|
if button_code in BUTTONS['back']:
|
||||||
|
if combo:
|
||||||
|
combo.hidePopup()
|
||||||
|
combo.setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
|
else:
|
||||||
|
focused.clearSelection()
|
||||||
|
focused.hide()
|
||||||
|
|
||||||
# Закрытие AddGameDialog на кнопку B
|
# Закрытие AddGameDialog на кнопку B
|
||||||
if button_code in BUTTONS['back'] and isinstance(active, QDialog):
|
if button_code in BUTTONS['back'] and isinstance(active, QDialog):
|
||||||
active.reject() # Закрываем диалог
|
active.reject()
|
||||||
return
|
return
|
||||||
|
|
||||||
# FullscreenDialog
|
# FullscreenDialog
|
||||||
@@ -181,6 +216,8 @@ class InputManager(QObject):
|
|||||||
elif button_code in BUTTONS['back'] or button_code in BUTTONS['menu']:
|
elif button_code in BUTTONS['back'] or button_code in BUTTONS['menu']:
|
||||||
self._parent.goBackDetailPage(getattr(self._parent, 'currentDetailPage', None))
|
self._parent.goBackDetailPage(getattr(self._parent, 'currentDetailPage', None))
|
||||||
elif button_code in BUTTONS['add_game']:
|
elif button_code in BUTTONS['add_game']:
|
||||||
|
# Only open AddGameDialog if in library tab (index 0)
|
||||||
|
if self._parent.stackedWidget.currentIndex() == 0:
|
||||||
self._parent.openAddGameDialog()
|
self._parent.openAddGameDialog()
|
||||||
elif button_code in BUTTONS['prev_tab']:
|
elif button_code in BUTTONS['prev_tab']:
|
||||||
idx = (self._parent.stackedWidget.currentIndex() - 1) % len(self._parent.tabButtons)
|
idx = (self._parent.stackedWidget.currentIndex() - 1) % len(self._parent.tabButtons)
|
||||||
@@ -193,7 +230,6 @@ class InputManager(QObject):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error in handle_button_slot: {e}", exc_info=True)
|
logger.error(f"Error in handle_button_slot: {e}", exc_info=True)
|
||||||
|
|
||||||
|
|
||||||
@Slot(int, int, float)
|
@Slot(int, int, float)
|
||||||
def handle_dpad_slot(self, code: int, value: int, current_time: float) -> None:
|
def handle_dpad_slot(self, code: int, value: int, current_time: float) -> None:
|
||||||
try:
|
try:
|
||||||
@@ -205,8 +241,24 @@ class InputManager(QObject):
|
|||||||
if not app:
|
if not app:
|
||||||
return
|
return
|
||||||
active = QApplication.activeWindow()
|
active = QApplication.activeWindow()
|
||||||
|
focused = QApplication.focusWidget()
|
||||||
popup = QApplication.activePopupWidget()
|
popup = QApplication.activePopupWidget()
|
||||||
|
|
||||||
|
# Handle AddGameDialog navigation with D-pad
|
||||||
|
if isinstance(active, QDialog) and code == ecodes.ABS_HAT0Y and value != 0:
|
||||||
|
if not focused or not active.focusWidget():
|
||||||
|
# If no widget is focused, focus the first focusable widget
|
||||||
|
focusables = active.findChildren(QWidget, options=Qt.FindChildOption.FindChildrenRecursively)
|
||||||
|
focusables = [w for w in focusables if w.focusPolicy() & Qt.FocusPolicy.StrongFocus]
|
||||||
|
if focusables:
|
||||||
|
focusables[0].setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
|
return
|
||||||
|
if value > 0: # Down
|
||||||
|
active.focusNextChild()
|
||||||
|
elif value < 0: # Up
|
||||||
|
active.focusPreviousChild()
|
||||||
|
return
|
||||||
|
|
||||||
# Handle QMenu navigation with D-pad
|
# Handle QMenu navigation with D-pad
|
||||||
if isinstance(popup, QMenu):
|
if isinstance(popup, QMenu):
|
||||||
if code == ecodes.ABS_HAT0Y and value != 0:
|
if code == ecodes.ABS_HAT0Y and value != 0:
|
||||||
@@ -222,6 +274,22 @@ class InputManager(QObject):
|
|||||||
return
|
return
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Handle QListView navigation with D-pad
|
||||||
|
if isinstance(focused, QListView) and code == ecodes.ABS_HAT0Y and value != 0:
|
||||||
|
model = focused.model()
|
||||||
|
current_index = focused.currentIndex()
|
||||||
|
if model and current_index.isValid():
|
||||||
|
row_count = model.rowCount()
|
||||||
|
current_row = current_index.row()
|
||||||
|
if value > 0: # Down
|
||||||
|
next_row = min(current_row + 1, row_count - 1)
|
||||||
|
focused.setCurrentIndex(model.index(next_row, current_index.column()))
|
||||||
|
elif value < 0: # Up
|
||||||
|
prev_row = max(current_row - 1, 0)
|
||||||
|
focused.setCurrentIndex(model.index(prev_row, current_index.column()))
|
||||||
|
focused.scrollTo(focused.currentIndex(), QListView.ScrollHint.PositionAtCenter)
|
||||||
|
return
|
||||||
|
|
||||||
# Fullscreen horizontal navigation
|
# Fullscreen horizontal navigation
|
||||||
if isinstance(active, FullscreenDialog) and code == ecodes.ABS_HAT0X:
|
if isinstance(active, FullscreenDialog) and code == ecodes.ABS_HAT0X:
|
||||||
if value < 0:
|
if value < 0:
|
||||||
@@ -313,7 +381,6 @@ class InputManager(QObject):
|
|||||||
next_card.setFocus()
|
next_card.setFocus()
|
||||||
if scroll_area:
|
if scroll_area:
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
||||||
|
|
||||||
elif code == ecodes.ABS_HAT0Y and value != 0: # Up/Down
|
elif code == ecodes.ABS_HAT0Y and value != 0: # Up/Down
|
||||||
if value > 0: # Down
|
if value > 0: # Down
|
||||||
next_row_idx = current_row_idx + 1
|
next_row_idx = current_row_idx + 1
|
||||||
@@ -570,6 +637,9 @@ class InputManager(QObject):
|
|||||||
if focusables:
|
if focusables:
|
||||||
focusables[0].setFocus()
|
focusables[0].setFocus()
|
||||||
return True
|
return True
|
||||||
|
elif focused:
|
||||||
|
focused.focusNextChild()
|
||||||
|
return True
|
||||||
# Navigate up through tab content
|
# Navigate up through tab content
|
||||||
if key == Qt.Key.Key_Up:
|
if key == Qt.Key.Key_Up:
|
||||||
if isinstance(focused, NavLabel):
|
if isinstance(focused, NavLabel):
|
||||||
@@ -590,6 +660,8 @@ class InputManager(QObject):
|
|||||||
elif key == Qt.Key.Key_E:
|
elif key == Qt.Key.Key_E:
|
||||||
if isinstance(focused, QLineEdit):
|
if isinstance(focused, QLineEdit):
|
||||||
return False
|
return False
|
||||||
|
# Only open AddGameDialog if in library tab (index 0)
|
||||||
|
if self._parent.stackedWidget.currentIndex() == 0:
|
||||||
self._parent.openAddGameDialog()
|
self._parent.openAddGameDialog()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@@ -742,6 +742,7 @@ class MainWindow(QMainWindow):
|
|||||||
return
|
return
|
||||||
|
|
||||||
dialog = AddGameDialog(self, self.theme)
|
dialog = AddGameDialog(self, self.theme)
|
||||||
|
dialog.setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
self.current_add_game_dialog = dialog # Сохраняем ссылку на диалог
|
self.current_add_game_dialog = dialog # Сохраняем ссылку на диалог
|
||||||
|
|
||||||
# Предзаполняем путь к .exe при drag-and-drop
|
# Предзаполняем путь к .exe при drag-and-drop
|
||||||
|
Reference in New Issue
Block a user