Compare commits
5 Commits
2a46cf7a2f
...
802d5a2ba1
Author | SHA1 | Date | |
---|---|---|---|
802d5a2ba1
|
|||
1d47caf4aa
|
|||
502664438c
|
|||
f4e155dade
|
|||
74400d1389
|
44
CHANGELOG.md
@@ -10,24 +10,24 @@
|
|||||||
- Бейдж PortProton
|
- Бейдж PortProton
|
||||||
- Зависимость от `xdg-utils`
|
- Зависимость от `xdg-utils`
|
||||||
- Интеграция статуса WeAntiCheatYet в карточку
|
- Интеграция статуса WeAntiCheatYet в карточку
|
||||||
- Стили в AddGameDialog
|
|
||||||
- Переключение полноэкранного режима через F11 или кнопку Select на геймпаде
|
- Переключение полноэкранного режима через F11 или кнопку Select на геймпаде
|
||||||
- Выбор QCheckBox через Enter или кнопку A на геймпаде
|
- Выбор состояния `QCheckBox` через Enter или кнопку A на геймпаде
|
||||||
- Закрытие диалога добавления игры через ESC или кнопку B на геймпаде
|
- Закрытие диалога добавления игры через ESC или кнопку B на геймпаде
|
||||||
- Закрытие окна приложения по комбинации клавиш Ctrl+Q
|
- Закрытие окна приложения по комбинации клавиш Ctrl+Q
|
||||||
- Сохранение и восстановление размера окна при перезапуске
|
- Сохранение и восстановление размера окна при перезапуске
|
||||||
- Переключатель полноэкранного режима приложения
|
- Переключатель полноэкранного режима приложения
|
||||||
- Пункт в контекстном меню «Открыть папку игры»
|
- Пункт в контекстном меню «Открыть папку игры»
|
||||||
- Пункты в контекстном меню «Добавить в Steam» и «Удалить из Steam»
|
- Пункты в контекстном меню «Добавить в Steam» и «Удалить из Steam»
|
||||||
- Пункты в контекстном меню «Добавить в Избранное» и «Удалить из Избранного» для переключения статуса избранного через геймпад
|
- Пункты в контекстном меню «Добавить в Избранное» и «Удалить из Избранного»
|
||||||
- Метод сортировки «Сначала избранное»
|
- Метод сортировки «Сначала избранное»
|
||||||
- Настройка автоматического перехода в полноэкранный режим при подключении геймпада (по умолчанию отключена)
|
- Настройка автоматического перехода в полноэкранный режим при подключении геймпада (по умолчанию отключена)
|
||||||
- Обработчики для QMenu и QComboBox при управлении геймпадом
|
- Поддержка управления геймпадом в `QMenu` и `QComboBox`
|
||||||
- Аргумент `--fullscreen` для запуска приложения в полноэкранном режиме
|
- Аргумент `--fullscreen` для запуска приложения в полноэкранном режиме
|
||||||
- Оверлей на кнопку Insert или кнопку Xbox/PS на геймпаде для закрытия приложения, выключения, перезагрузки и перехода в спящий режим или между сессиями
|
- Оверлей на кнопку Insert или кнопку Xbox/PS на геймпаде для закрытия приложения, выключения, перезагрузки и перехода в спящий режим или переключения между сессиями
|
||||||
- [Gamescope сессия](https://git.linux-gaming.ru/Boria138/gamescope-session-portprotonqt)
|
- [Gamescope сессия](https://git.linux-gaming.ru/Boria138/gamescope-session-portprotonqt)
|
||||||
- Мапинги управления для Dualshock 4 и DualSense
|
- Пресеты управления для DualShock 4 и DualSense
|
||||||
- Настройка тактильной обратной связи на геймпаде при запуске игры (по умолчанию отключена)
|
- Настройка тактильной отдачи на геймпаде при запуске игры (по умолчанию выключена)
|
||||||
|
- Переводы пунктов настроек
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
- Обновлены все иконки
|
- Обновлены все иконки
|
||||||
@@ -36,29 +36,29 @@
|
|||||||
- Логика контекстного меню вынесена в `ContextMenuManager`
|
- Логика контекстного меню вынесена в `ContextMenuManager`
|
||||||
- Бейдж Steam теперь открывает Steam Community
|
- Бейдж Steam теперь открывает Steam Community
|
||||||
- Изменена лицензия с MIT на GPL-3.0 для совместимости с кодом от legendary
|
- Изменена лицензия с MIT на GPL-3.0 для совместимости с кодом от legendary
|
||||||
- Оптимизирована генерация карточек для предотвращения задержек при поиске и изменении размера окна
|
- Оптимизирована генерация карточек для плавной работы при поиске и изменении размера окна
|
||||||
- Бейджи с карточек теперь отображаются также на странице с деталями, а не только в библиотеке
|
- Бейджи с карточек теперь отображаются также на странице с деталями, а не только в библиотеке
|
||||||
- Установлена ширина бейджа в две трети ширины карточки
|
- Установлена ширина бейджа в две трети ширины карточки
|
||||||
- Бейджи источников (`Steam`, `EGS`, `PortProton`) теперь отображаются только при активном фильтре `all` или `favorites`
|
- Бейджи источников (`Steam`, `EGS`, `PortProton`) теперь отображаются только при активном фильтре `all` или `favorites`
|
||||||
- Карточки теперь фокусируются в направлении движения стрелок или D-pad: например, при нажатии D-pad вниз фокус переходит на карточку в следующей колонке, а не по порядку
|
- Карточки теперь фокусируются в направлении движения стрелок или D-pad:
|
||||||
- Теперь D-pad можно зажимать для переключения карточек
|
- Поддерживается удержание D-pad для непрерывного переключения карточек
|
||||||
- D-pad больше не переключает вкладки, только RB и LB
|
- Объединён обработчик управления стрелками клавиатуры и D-pad для консистентности
|
||||||
|
- D-pad больше не переключает вкладки (только кнопки RB/LB)
|
||||||
- Кнопка добавления игры больше не фокусируется
|
- Кнопка добавления игры больше не фокусируется
|
||||||
- Диалог добавления игры теперь открывается только в библиотеке
|
- Диалог добавления игры теперь открывается только в библиотеке
|
||||||
- Удалены все упоминания PortProtonQT из кода и заменены на PortProtonQt
|
- Удалены все упоминания PortProtonQT из кода и заменены на PortProtonQt
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
- Обработка несуществующей темы с возвратом к «standard»
|
- Возврат к теме «standard» при выборе несуществующей темы
|
||||||
- Открытие контекстного меню
|
- Корректное открытие контекстного меню
|
||||||
- Запуск при отсутствии exiftool
|
- Запуск приложения при отсутствии `exiftool`
|
||||||
- Переводы пунктов настроек
|
- Предотвращено бесконечное обращение к `get_portproton_location`
|
||||||
- Бесконечное обращение к `get_portproton_location`
|
- Обновлены ссылки на документацию в README
|
||||||
- Ссылки на документацию в README
|
- Устранён traceback при отсутствии обложек (placeholder)
|
||||||
- Traceback при загрузке placeholder при отсутствии обложек
|
- Устранены утечки памяти при загрузке обложек
|
||||||
- Утечки памяти при загрузке обложек
|
- Исправлены ошибки при подключении геймпада
|
||||||
- Ошибки при подключении геймпада из-за работы в разных потоках
|
- Предотвращено многократное открытие диалога добавления игры через геймпад
|
||||||
- Многократное открытие диалога добавления игры при использовании геймпада
|
- Корректная обработка событий геймпада во время игры
|
||||||
- Перехват событий геймпада во время работы игры
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@@ -65,7 +65,7 @@
|
|||||||
- [X] Добавить виброотдачу на геймпаде при запуске игры
|
- [X] Добавить виброотдачу на геймпаде при запуске игры
|
||||||
- [ ] Исправить некорректную работу слайдера увеличения размера карточек([Последствия регрессии после этого коммита](https://github.com/Boria138/PortProtonQt/commit/aebdd60b5537280f06a922ff80469cd4ab27bc63)
|
- [ ] Исправить некорректную работу слайдера увеличения размера карточек([Последствия регрессии после этого коммита](https://github.com/Boria138/PortProtonQt/commit/aebdd60b5537280f06a922ff80469cd4ab27bc63)
|
||||||
- [X] Исправить баг с наложением карточек друг на друга при изменении фильтра отображения ([Последствия регрессии после этого коммита](https://github.com/Boria138/PortProtonQt/commit/aebdd60b5537280f06a922ff80469cd4ab27bc63))
|
- [X] Исправить баг с наложением карточек друг на друга при изменении фильтра отображения ([Последствия регрессии после этого коммита](https://github.com/Boria138/PortProtonQt/commit/aebdd60b5537280f06a922ff80469cd4ab27bc63))
|
||||||
- [ ] Скопировать логику управления с D-pad на стрелки с клавиатуры
|
- [X] Скопировать логику управления с D-pad на стрелки с клавиатуры
|
||||||
|
|
||||||
### Установка (devel)
|
### Установка (devel)
|
||||||
|
|
||||||
|
@@ -49,6 +49,16 @@
|
|||||||
<caption>Settings</caption>
|
<caption>Settings</caption>
|
||||||
<caption xml:lang="ru">Настройки</caption>
|
<caption xml:lang="ru">Настройки</caption>
|
||||||
</screenshot>
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<image>https://git.linux-gaming.ru/Boria138/PortProtonQt/raw/branch/main/portprotonqt/themes/standart/images/screenshots/%D0%9A%D0%BE%D0%BD%D1%82%D0%B5%D0%BA%D1%81%D1%82%D0%BD%D0%BE%D0%B5%20%D0%BC%D0%B5%D0%BD%D1%8E.png</image>
|
||||||
|
<caption>Context Menu</caption>
|
||||||
|
<caption xml:lang="ru">Контекстное меню</caption>
|
||||||
|
</screenshot>
|
||||||
|
<screenshot>
|
||||||
|
<image>https://git.linux-gaming.ru/Boria138/PortProtonQt/src/branch/main/portprotonqt/themes/standart/images/screenshots/%D0%9E%D0%B2%D0%B5%D1%80%D0%BB%D0%B5%D0%B9.png</image>
|
||||||
|
<caption>Overlay</caption>
|
||||||
|
<caption xml:lang="ru">Оверлей</caption>
|
||||||
|
</screenshot>
|
||||||
</screenshots>
|
</screenshots>
|
||||||
<keywords>
|
<keywords>
|
||||||
<keyword translate="no">wine</keyword>
|
<keyword translate="no">wine</keyword>
|
||||||
|
@@ -523,240 +523,133 @@ class InputManager(QObject):
|
|||||||
if not app:
|
if not app:
|
||||||
return super().eventFilter(obj, event)
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
# Handle only key press events
|
# Handle key press and release events
|
||||||
if not (isinstance(event, QKeyEvent) and event.type() == QEvent.Type.KeyPress):
|
if not isinstance(event, QKeyEvent):
|
||||||
return super().eventFilter(obj, event)
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
key = event.key()
|
key = event.key()
|
||||||
modifiers = event.modifiers()
|
modifiers = event.modifiers()
|
||||||
focused = QApplication.focusWidget()
|
focused = QApplication.focusWidget()
|
||||||
popup = QApplication.activePopupWidget()
|
popup = QApplication.activePopupWidget()
|
||||||
|
|
||||||
# Open system overlay with Insert
|
|
||||||
if key == Qt.Key.Key_Insert:
|
|
||||||
if not popup and not isinstance(QApplication.activeWindow(), QDialog):
|
|
||||||
self._parent.openSystemOverlay()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Close application with Ctrl+Q
|
|
||||||
if key == Qt.Key.Key_Q and modifiers & Qt.KeyboardModifier.ControlModifier:
|
|
||||||
app.quit()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Закрытие AddGameDialog на Esc
|
|
||||||
if key == Qt.Key.Key_Escape and isinstance(popup, QDialog):
|
|
||||||
popup.reject() # Закрываем диалог
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Skip navigation keys if a popup is open
|
|
||||||
if popup:
|
|
||||||
return False
|
|
||||||
|
|
||||||
# FullscreenDialog navigation
|
|
||||||
active_win = QApplication.activeWindow()
|
active_win = QApplication.activeWindow()
|
||||||
if isinstance(active_win, FullscreenDialog):
|
|
||||||
if key == Qt.Key.Key_Right:
|
|
||||||
active_win.show_next()
|
|
||||||
return True
|
|
||||||
if key == Qt.Key.Key_Left:
|
|
||||||
active_win.show_prev()
|
|
||||||
return True
|
|
||||||
if key in (Qt.Key.Key_Escape, Qt.Key.Key_Return, Qt.Key.Key_Enter, Qt.Key.Key_Backspace):
|
|
||||||
active_win.close()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Launch/stop game on detail page
|
# Handle key press events
|
||||||
if self._parent.currentDetailPage and key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
if event.type() == QEvent.Type.KeyPress:
|
||||||
if self._parent.current_exec_line:
|
# Open system overlay with Insert
|
||||||
self._parent.toggleGame(self._parent.current_exec_line, None)
|
if key == Qt.Key.Key_Insert:
|
||||||
return True
|
if not popup and not isinstance(active_win, QDialog):
|
||||||
|
self._parent.openSystemOverlay()
|
||||||
# Context menu for GameCard
|
|
||||||
if isinstance(focused, GameCard):
|
|
||||||
if key == Qt.Key.Key_F10 and Qt.KeyboardModifier.ShiftModifier:
|
|
||||||
pos = QPoint(focused.width() // 2, focused.height() // 2)
|
|
||||||
focused._show_context_menu(pos)
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Handle Up/Down keys for non-GameCard tabs
|
|
||||||
if key in (Qt.Key.Key_Up, Qt.Key.Key_Down) and not isinstance(focused, GameCard):
|
|
||||||
page = self._parent.stackedWidget.currentWidget()
|
|
||||||
if key == Qt.Key.Key_Down:
|
|
||||||
if isinstance(focused, NavLabel):
|
|
||||||
focusables = page.findChildren(QWidget, options=Qt.FindChildOption.FindChildrenRecursively)
|
|
||||||
focusables = [w for w in focusables if w.focusPolicy() & Qt.FocusPolicy.StrongFocus]
|
|
||||||
if focusables:
|
|
||||||
focusables[0].setFocus()
|
|
||||||
return True
|
|
||||||
elif focused:
|
|
||||||
focused.focusNextChild()
|
|
||||||
return True
|
|
||||||
elif key == Qt.Key.Key_Up and focused:
|
|
||||||
focused.focusPreviousChild()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Tab switching with Left/Right keys (non-GameCard focus or no focus)
|
|
||||||
idx = self._parent.stackedWidget.currentIndex()
|
|
||||||
total = len(self._parent.tabButtons)
|
|
||||||
if key == Qt.Key.Key_Left and (not isinstance(focused, GameCard) or focused is None):
|
|
||||||
new = (idx - 1) % total
|
|
||||||
self._parent.switchTab(new)
|
|
||||||
self._parent.tabButtons[new].setFocus()
|
|
||||||
return True
|
|
||||||
if key == Qt.Key.Key_Right and (not isinstance(focused, GameCard) or focused is None):
|
|
||||||
new = (idx + 1) % total
|
|
||||||
self._parent.switchTab(new)
|
|
||||||
self._parent.tabButtons[new].setFocus()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Library tab navigation
|
|
||||||
if self._parent.stackedWidget.currentIndex() == 0:
|
|
||||||
game_cards = self._parent.gamesListWidget.findChildren(GameCard)
|
|
||||||
scroll_area = self._parent.gamesListWidget.parentWidget()
|
|
||||||
while scroll_area and not isinstance(scroll_area, QScrollArea):
|
|
||||||
scroll_area = scroll_area.parentWidget()
|
|
||||||
|
|
||||||
if key in (Qt.Key.Key_Left, Qt.Key.Key_Right, Qt.Key.Key_Up, Qt.Key.Key_Down):
|
|
||||||
if not game_cards:
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# If no focused widget or not a GameCard, focus the first card
|
# Close application with Ctrl+Q
|
||||||
if not isinstance(focused, GameCard) or focused not in game_cards:
|
if key == Qt.Key.Key_Q and modifiers & Qt.KeyboardModifier.ControlModifier:
|
||||||
game_cards[0].setFocus()
|
app.quit()
|
||||||
if scroll_area:
|
return True
|
||||||
scroll_area.ensureWidgetVisible(game_cards[0], 50, 50)
|
|
||||||
|
# Close AddGameDialog with Escape
|
||||||
|
if key == Qt.Key.Key_Escape and isinstance(popup, QDialog):
|
||||||
|
popup.reject()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# FullscreenDialog navigation
|
||||||
|
if isinstance(active_win, FullscreenDialog):
|
||||||
|
if key in (Qt.Key.Key_Escape, Qt.Key.Key_Return, Qt.Key.Key_Enter, Qt.Key.Key_Backspace):
|
||||||
|
active_win.close()
|
||||||
|
return True
|
||||||
|
elif key in (Qt.Key.Key_Left, Qt.Key.Key_Right):
|
||||||
|
# Navigate screenshots in FullscreenDialog
|
||||||
|
if key == Qt.Key.Key_Left:
|
||||||
|
active_win.show_prev()
|
||||||
|
elif key == Qt.Key.Key_Right:
|
||||||
|
active_win.show_next()
|
||||||
|
return True # Consume event to prevent tab switching
|
||||||
|
|
||||||
|
# Handle tab switching with Left/Right arrow keys when not in GameCard focus
|
||||||
|
if key in (Qt.Key.Key_Left, Qt.Key.Key_Right) and (not isinstance(focused, GameCard) or focused is None):
|
||||||
|
idx = self._parent.stackedWidget.currentIndex()
|
||||||
|
total = len(self._parent.tabButtons)
|
||||||
|
if key == Qt.Key.Key_Left:
|
||||||
|
new_idx = (idx - 1) % total
|
||||||
|
self._parent.switchTab(new_idx)
|
||||||
|
self._parent.tabButtons[new_idx].setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
|
return True
|
||||||
|
elif key == Qt.Key.Key_Right:
|
||||||
|
new_idx = (idx + 1) % total
|
||||||
|
self._parent.switchTab(new_idx)
|
||||||
|
self._parent.tabButtons[new_idx].setFocus(Qt.FocusReason.OtherFocusReason)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# Group cards by rows based on y-coordinate
|
# Map arrow keys to D-pad press events for other contexts
|
||||||
rows = {}
|
if key in (Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Left, Qt.Key.Key_Right):
|
||||||
for card in game_cards:
|
now = time.time()
|
||||||
y = card.pos().y()
|
dpad_code = None
|
||||||
if y not in rows:
|
dpad_value = 0
|
||||||
rows[y] = []
|
if key == Qt.Key.Key_Up:
|
||||||
rows[y].append(card)
|
dpad_code = ecodes.ABS_HAT0Y
|
||||||
# Sort cards in each row by x-coordinate
|
dpad_value = -1
|
||||||
for y in rows:
|
|
||||||
rows[y].sort(key=lambda c: c.pos().x())
|
|
||||||
# Sort rows by y-coordinate
|
|
||||||
sorted_rows = sorted(rows.items(), key=lambda x: x[0])
|
|
||||||
|
|
||||||
# Find current row and column
|
|
||||||
current_y = focused.pos().y()
|
|
||||||
current_row_idx = next(i for i, (y, _) in enumerate(sorted_rows) if y == current_y)
|
|
||||||
current_row = sorted_rows[current_row_idx][1]
|
|
||||||
current_col_idx = current_row.index(focused)
|
|
||||||
|
|
||||||
if key == Qt.Key.Key_Right:
|
|
||||||
next_col_idx = current_col_idx + 1
|
|
||||||
if next_col_idx < len(current_row):
|
|
||||||
next_card = current_row[next_col_idx]
|
|
||||||
next_card.setFocus()
|
|
||||||
if scroll_area:
|
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
# Move to the first card of the next row if available
|
|
||||||
if current_row_idx < len(sorted_rows) - 1:
|
|
||||||
next_row = sorted_rows[current_row_idx + 1][1]
|
|
||||||
next_card = next_row[0] if next_row else None
|
|
||||||
if next_card:
|
|
||||||
next_card.setFocus()
|
|
||||||
if scroll_area:
|
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
|
||||||
return True
|
|
||||||
elif key == Qt.Key.Key_Left:
|
|
||||||
next_col_idx = current_col_idx - 1
|
|
||||||
if next_col_idx >= 0:
|
|
||||||
next_card = current_row[next_col_idx]
|
|
||||||
next_card.setFocus()
|
|
||||||
if scroll_area:
|
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
# Move to the last card of the previous row if available
|
|
||||||
if current_row_idx > 0:
|
|
||||||
prev_row = sorted_rows[current_row_idx - 1][1]
|
|
||||||
next_card = prev_row[-1] if prev_row else None
|
|
||||||
if next_card:
|
|
||||||
next_card.setFocus()
|
|
||||||
if scroll_area:
|
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
|
||||||
return True
|
|
||||||
elif key == Qt.Key.Key_Down:
|
elif key == Qt.Key.Key_Down:
|
||||||
next_row_idx = current_row_idx + 1
|
dpad_code = ecodes.ABS_HAT0Y
|
||||||
if next_row_idx < len(sorted_rows):
|
dpad_value = 1
|
||||||
next_row = sorted_rows[next_row_idx][1]
|
elif key == Qt.Key.Key_Left:
|
||||||
target_x = focused.pos().x()
|
dpad_code = ecodes.ABS_HAT0X
|
||||||
next_card = min(
|
dpad_value = -1
|
||||||
next_row,
|
elif key == Qt.Key.Key_Right:
|
||||||
key=lambda c: abs(c.pos().x() - target_x),
|
dpad_code = ecodes.ABS_HAT0X
|
||||||
default=None
|
dpad_value = 1
|
||||||
)
|
|
||||||
if next_card:
|
|
||||||
next_card.setFocus()
|
|
||||||
if scroll_area:
|
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
|
||||||
return True
|
|
||||||
elif key == Qt.Key.Key_Up:
|
|
||||||
next_row_idx = current_row_idx - 1
|
|
||||||
if next_row_idx >= 0:
|
|
||||||
next_row = sorted_rows[next_row_idx][1]
|
|
||||||
target_x = focused.pos().x()
|
|
||||||
next_card = min(
|
|
||||||
next_row,
|
|
||||||
key=lambda c: abs(c.pos().x() - target_x),
|
|
||||||
default=None
|
|
||||||
)
|
|
||||||
if next_card:
|
|
||||||
next_card.setFocus()
|
|
||||||
if scroll_area:
|
|
||||||
scroll_area.ensureWidgetVisible(next_card, 50, 50)
|
|
||||||
return True
|
|
||||||
elif current_row_idx == 0:
|
|
||||||
self._parent.tabButtons[0].setFocus()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Navigate down into tab content
|
if dpad_code is not None:
|
||||||
if key == Qt.Key.Key_Down:
|
self.dpad_moved.emit(dpad_code, dpad_value, now)
|
||||||
if isinstance(focused, NavLabel):
|
|
||||||
page = self._parent.stackedWidget.currentWidget()
|
|
||||||
focusables = page.findChildren(QWidget, options=Qt.FindChildOption.FindChildrenRecursively)
|
|
||||||
focusables = [w for w in focusables if w.focusPolicy() & Qt.FocusPolicy.StrongFocus]
|
|
||||||
if focusables:
|
|
||||||
focusables[0].setFocus()
|
|
||||||
return True
|
return True
|
||||||
elif focused:
|
|
||||||
focused.focusNextChild()
|
# Launch/stop game on detail page
|
||||||
|
if self._parent.currentDetailPage and key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
||||||
|
if self._parent.current_exec_line:
|
||||||
|
self._parent.toggleGame(self._parent.current_exec_line, None)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Context menu for GameCard
|
||||||
|
if isinstance(focused, GameCard):
|
||||||
|
if key == Qt.Key.Key_F10 and modifiers & Qt.KeyboardModifier.ShiftModifier:
|
||||||
|
pos = QPoint(focused.width() // 2, focused.height() // 2)
|
||||||
|
focused._show_context_menu(pos)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# General actions: Activate, Back, Add
|
||||||
|
if key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
||||||
|
self._parent.activateFocusedWidget()
|
||||||
return True
|
return True
|
||||||
# Navigate up through tab content
|
elif key in (Qt.Key.Key_Escape, Qt.Key.Key_Backspace):
|
||||||
if key == Qt.Key.Key_Up:
|
if isinstance(focused, QLineEdit):
|
||||||
if isinstance(focused, NavLabel):
|
return False
|
||||||
|
self._parent.goBackDetailPage(self._parent.currentDetailPage)
|
||||||
return True
|
return True
|
||||||
if focused is not None:
|
elif key == Qt.Key.Key_E:
|
||||||
focused.focusPreviousChild()
|
if isinstance(focused, QLineEdit):
|
||||||
|
return False
|
||||||
|
# Only open AddGameDialog if in library tab (index 0)
|
||||||
|
if self._parent.stackedWidget.currentIndex() == 0:
|
||||||
|
self._parent.openAddGameDialog()
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Toggle fullscreen with F11
|
||||||
|
if key == Qt.Key.Key_F11:
|
||||||
|
self.toggle_fullscreen.emit(not self._is_fullscreen)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# General actions: Activate, Back, Add
|
# Handle key release events for arrow keys
|
||||||
if key in (Qt.Key.Key_Return, Qt.Key.Key_Enter):
|
elif event.type() == QEvent.Type.KeyRelease:
|
||||||
self._parent.activateFocusedWidget()
|
if key in (Qt.Key.Key_Up, Qt.Key.Key_Down, Qt.Key.Key_Left, Qt.Key.Key_Right):
|
||||||
return True
|
now = time.time()
|
||||||
elif key in (Qt.Key.Key_Escape, Qt.Key.Key_Backspace):
|
dpad_code = None
|
||||||
if isinstance(focused, QLineEdit):
|
if key in (Qt.Key.Key_Up, Qt.Key.Key_Down):
|
||||||
return False
|
dpad_code = ecodes.ABS_HAT0Y
|
||||||
self._parent.goBackDetailPage(self._parent.currentDetailPage)
|
elif key in (Qt.Key.Key_Left, Qt.Key.Key_Right):
|
||||||
return True
|
dpad_code = ecodes.ABS_HAT0X
|
||||||
elif key == Qt.Key.Key_E:
|
|
||||||
if isinstance(focused, QLineEdit):
|
|
||||||
return False
|
|
||||||
# Only open AddGameDialog if in library tab (index 0)
|
|
||||||
if self._parent.stackedWidget.currentIndex() == 0:
|
|
||||||
self._parent.openAddGameDialog()
|
|
||||||
return True
|
|
||||||
|
|
||||||
# Toggle fullscreen with F11
|
if dpad_code is not None:
|
||||||
if key == Qt.Key.Key_F11:
|
# Emit release event with value 0 to stop continuous movement
|
||||||
self.toggle_fullscreen.emit(not self._is_fullscreen)
|
self.dpad_moved.emit(dpad_code, 0, now)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return super().eventFilter(obj, event)
|
return super().eventFilter(obj, event)
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 621 KiB After Width: | Height: | Size: 562 KiB |
After Width: | Height: | Size: 445 KiB |
After Width: | Height: | Size: 1.4 MiB |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 106 KiB |
BIN
portprotonqt/themes/standart/images/screenshots/Оверлей.png
Normal file
After Width: | Height: | Size: 1.1 MiB |