feat(settings): added initial gamepad navigation
All checks were successful
Code check / Check code (push) Successful in 1m20s

Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
2025-11-21 00:08:02 +05:00
parent b2a1046f9d
commit 836e6cdd36
2 changed files with 502 additions and 2 deletions

View File

@@ -125,6 +125,15 @@ def create_dialog_hints_widget(theme, main_window, input_manager, context='defau
("prev_tab", _("Prev Tab")), # LB / L1
("next_tab", _("Next Tab")), # RB / R1
]
elif context == 'settings':
dialog_actions = [
("confirm", _("Toggle")), # A / Cross
("add_game", _("Save")), # X / Triangle
("prev_dir", _("Search")), # Y / Square
("back", _("Cancel")), # B / Circle
("prev_tab", _("Prev Tab")), # LB / L1
("next_tab", _("Next Tab")), # RB / R1
]
hints_labels = [] # Store for updates (returned for class storage)
@@ -1723,6 +1732,8 @@ class ExeSettingsDialog(QDialog):
self.setModal(True)
self.resize(1100, 720)
self.setStyleSheet(self.theme.MAIN_WINDOW_STYLE + self.theme.MESSAGE_BOX_STYLE)
# Set focus policy to handle focus changes properly
self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
# Load toggle settings from config module
self.toggle_settings = get_toggle_settings()
@@ -1741,6 +1752,27 @@ class ExeSettingsDialog(QDialog):
self.current_theme_name = read_theme_from_config()
# Enable settings dialog-specific mode
if self.input_manager:
self.input_manager.enable_settings_mode(self)
# Create hints widget using common function
self.hints_widget, self.hints_labels = create_dialog_hints_widget(self.theme, self.main_window, self.input_manager, context='settings')
self.main_layout.addWidget(self.hints_widget)
# Connect signals
if self.input_manager:
self.input_manager.button_event.connect(
lambda *args: update_dialog_hints(self.hints_labels, self.main_window, self.input_manager, theme_manager, self.current_theme_name)
)
self.input_manager.dpad_moved.connect(
lambda *args: update_dialog_hints(self.hints_labels, self.main_window, self.input_manager, theme_manager, self.current_theme_name)
)
update_dialog_hints(self.hints_labels, self.main_window, self.input_manager, theme_manager, self.current_theme_name)
# Initialize virtual keyboard
self.init_virtual_keyboard()
# Load current settings (includes list-db)
self.load_current_settings()
@@ -1757,6 +1789,19 @@ class ExeSettingsDialog(QDialog):
self.main_layout.setContentsMargins(10, 10, 10, 10)
self.main_layout.setSpacing(10)
# Search bar
search_layout = QHBoxLayout()
self.search_label = QLabel(_("Search:"))
self.search_label.setStyleSheet(self.theme.PARAMS_TITLE_STYLE)
self.search_edit = QLineEdit()
self.search_edit.setStyleSheet(self.theme.ADDGAME_INPUT_STYLE)
self.search_edit.setPlaceholderText(_("Search settings..."))
self.search_edit.textChanged.connect(self.filter_settings)
self.search_edit.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
search_layout.addWidget(self.search_label)
search_layout.addWidget(self.search_edit)
self.main_layout.addLayout(search_layout)
# Tab widget
self.tab_widget = QTabWidget()
self.tab_widget.setStyleSheet(self.theme.WINETRICKS_TAB_STYLE)
@@ -2009,6 +2054,9 @@ class ExeSettingsDialog(QDialog):
if len(setting['options']) == 1:
combo.setEnabled(False)
# Set focus policy for combo box
combo.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
self.advanced_table.setCellWidget(row, 1, combo)
self.advanced_widgets[setting['key']] = combo
self.original_display_values[setting['key']] = current_val
@@ -2029,6 +2077,75 @@ class ExeSettingsDialog(QDialog):
desc_item.setTextAlignment(Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter)
self.advanced_table.setItem(row, 2, desc_item)
def init_virtual_keyboard(self):
"""Initialize virtual keyboard"""
self.keyboard = VirtualKeyboard(self, theme=self.theme, button_width=40)
self.keyboard.hide()
self.keyboard.current_input_widget = None
def show_virtual_keyboard(self, widget=None):
"""Show virtual keyboard for search or text input"""
if not widget:
# Default to search edit
widget = self.search_edit
if not widget or not widget.isVisible():
return
# Set the current input widget
self.keyboard.current_input_widget = widget
# Position the keyboard
keyboard_height = 220
self.keyboard.setFixedWidth(self.width())
self.keyboard.setFixedHeight(keyboard_height)
self.keyboard.move(0, self.height() - keyboard_height)
# Show and raise keyboard
self.keyboard.setParent(self)
self.keyboard.show()
self.keyboard.raise_()
# Focus on first button of keyboard
first_button = self.keyboard.findFirstFocusableButton()
if first_button:
# First hide the current focus to prevent conflicts
focused_widget = QApplication.focusWidget()
if focused_widget and focused_widget != self.keyboard:
focused_widget.clearFocus()
# Then focus the keyboard button
QTimer.singleShot(50, lambda: first_button.setFocus())
def filter_settings(self, text):
"""Filter settings based on search text."""
# Filter main settings table
search_text = text.lower()
for row in range(self.settings_table.rowCount()):
name_item = self.settings_table.item(row, 0) # Setting name
desc_item = self.settings_table.item(row, 2) # Description
should_show = False
if name_item and search_text in name_item.text().lower():
should_show = True
elif desc_item and search_text in desc_item.text().lower():
should_show = True
self.settings_table.setRowHidden(row, not should_show)
# Filter advanced settings table
for row in range(self.advanced_table.rowCount()):
name_item = self.advanced_table.item(row, 0) # Setting name
desc_item = self.advanced_table.item(row, 2) # Description
should_show = False
if name_item and search_text in name_item.text().lower():
should_show = True
elif desc_item and search_text in desc_item.text().lower():
should_show = True
self.advanced_table.setRowHidden(row, not should_show)
def apply_changes(self):
"""Apply changes by collecting diffs from both main and advanced tabs."""
changes = []
@@ -2089,8 +2206,40 @@ class ExeSettingsDialog(QDialog):
self.load_current_settings()
QMessageBox.information(self, _("Success"), _("Settings updated successfully."))
def keyPressEvent(self, event):
"""Override key press event to handle combo box interaction properly."""
# If a combo box in the advanced table is active and has an open dropdown,
# we need to handle Escape key specially to prevent dialog closure
focused_widget = QApplication.focusWidget()
if (event.key() == Qt.Key.Key_Escape and
isinstance(focused_widget, QComboBox) and
focused_widget.view().isVisible()):
# If a combo box dropdown is open, just close the dropdown instead of the dialog
focused_widget.hidePopup()
self.advanced_table.setFocus()
return
super().keyPressEvent(event)
def closeEvent(self, event):
# Hide virtual keyboard if visible
if hasattr(self, 'keyboard') and self.keyboard.isVisible():
self.keyboard.hide()
if self.input_manager:
self.input_manager.disable_settings_mode()
super().closeEvent(event)
def reject(self):
# Hide virtual keyboard if visible
if hasattr(self, 'keyboard') and self.keyboard.isVisible():
self.keyboard.hide()
if self.input_manager:
self.input_manager.disable_settings_mode()
super().reject()
def accept(self):
# Hide virtual keyboard if visible
if hasattr(self, 'keyboard') and self.keyboard.isVisible():
self.keyboard.hide()
if self.input_manager:
self.input_manager.disable_settings_mode()
super().accept()