Source code for pyvisor.GUI.tab_buttons.assign_button_box

import pygame
from PyQt5.QtGui import QPixmap, QCloseEvent
from PyQt5.QtWidgets import QHBoxLayout, QLabel, QPushButton, QMessageBox, QWidget, QInputDialog

from ..model.behaviour import Behaviour
from ..model.gui_data_interface import GUIDataInterface
from ..model.scorer_action import ScorerAction


[docs] class AssignButtonBox(QWidget): """Widget for a single button-to-action assignment. Shows the action name, current binding, and an "assign button" control. For gamepads, opens a dialog that polls for input; for keyboards, opens a text entry dialog. """ def __init__(self, parent_widget: QWidget, gui_data_interface: GUIDataInterface, action: ScorerAction, color: str, is_behaviour: bool): super().__init__(parent_widget) self.parent_widget = parent_widget self.gui_data_interface = gui_data_interface self.action = action self.color = color self._init_callbacks(gui_data_interface) self.is_behaviour = is_behaviour self._init_UI() def _init_callbacks(self, gui_data_interface): self._callback_id_binding = gui_data_interface.register_callback_key_binding_changed( self.button_assignment_changed) self._callback_id_color = gui_data_interface.callbacks_behaviour_color_changed.register( self.set_color ) self._callback_id_icon = gui_data_interface.callbacks_update_icon.register( self._set_icon ) self._callback_id_name = gui_data_interface.callbacks_behaviour_name_changed.register( self._set_name ) self._callback_id_removed = gui_data_interface.callbacks_behaviour_removed.register( self.remove )
[docs] def remove(self, behaviour: Behaviour): if behaviour is self.action: self.close()
def _set_name(self, action: ScorerAction): if action is not self.action: return self.behav_label.setText(action.name)
[docs] def set_color(self, action: ScorerAction): if action is not self.action: return assert self.is_behaviour self.color = action.color self.behav_label.setStyleSheet('color: ' + self.color)
[docs] def closeEvent(self, a0: QCloseEvent) -> None: self.gui_data_interface.callbacks_key_binding_changed.pop(self._callback_id_binding) self.gui_data_interface.callbacks_update_icon.pop(self._callback_id_icon) self.gui_data_interface.callbacks_behaviour_color_changed.pop(self._callback_id_color) self.gui_data_interface.callbacks_behaviour_name_changed.pop(self._callback_id_name) self.gui_data_interface.callbacks_behaviour_removed.pop(self._callback_id_removed)
def _init_UI(self): self.box = QHBoxLayout() self.behav_label = QLabel(self.action.name) self.behav_label.setStyleSheet('color: ' + self.color) btn_set_uic = QPushButton('assign button') btn_set_uic.clicked.connect(self.assign_button) self._create_button_label() if self.is_behaviour: self._create_icon() self.box.addWidget(self.imageLabel) self.box.addWidget(self.behav_label) self.box.addWidget(btn_set_uic) self.box.addWidget(self.button_label) self.setLayout(self.box) def _set_icon(self, behaviour: Behaviour): if behaviour is not self.action: return pixmap = QPixmap(self.action.icon_path) pixmap = pixmap.scaledToWidth(20) self.imageLabel.setPixmap(pixmap) def _create_icon(self): self.imageLabel = QLabel() if self.action.icon_path is None: return pixmap = QPixmap(self.action.icon_path) pixmap = pixmap.scaledToWidth(20) self.imageLabel.setStyleSheet('color: ' + self.color) self.imageLabel.setPixmap(pixmap) def _create_button_label(self): key = self.action.key_bindings[self.gui_data_interface.selected_device] label = 'no button\nassigned' if key is None else key self.button_label = QLabel(self) if key is None: self.button_label.setStyleSheet('color: #C0C0C0') else: self.button_label.setStyleSheet('color: #ffffff') self.button_label.setText(label)
[docs] def assign_button(self): if self.gui_data_interface.selected_device is None: QMessageBox.warning(self.parent_widget, 'Set device first!', "You need to choose an input device first", QMessageBox.Ok) return if self.gui_data_interface.selected_device == "Keyboard": text, ok = QInputDialog.getText(self.parent(), 'Press', 'Key Entry:') if not ok: return button_identifier = str(text) else: button_identifier = self.waitOnUICpress() if button_identifier is None: return assigned_action, is_behaviour = self.gui_data_interface.get_action_assigned_to( button_identifier) # Clear this button from ALL old assignments (behaviours + movie actions) self.gui_data_interface.steal_button(button_identifier) # Assign to the new action self.gui_data_interface.change_button_binding(self.action, button_identifier, self.is_behaviour)
[docs] def button_assignment_changed(self, action: ScorerAction, is_behaviour: bool): if action is not self.action: return binding = action.key_bindings[self.gui_data_interface.selected_device] if binding is None: self.button_label.setText("no button\nassigned") self.button_label.setStyleSheet('color: #C0C0C0') else: self.button_label.setText(binding) self.button_label.setStyleSheet('color: #ffffff')
[docs] @staticmethod def waitOnUICpress(): """Wait for a gamepad button/axis/hat press with a visible dialog.""" from PyQt5.QtWidgets import QDialog, QVBoxLayout, QLabel as _QLabel from PyQt5.QtCore import QTimer, Qt as _Qt dlg = QDialog() dlg.setWindowTitle("Waiting for gamepad input…") dlg.setMinimumSize(320, 100) layout = QVBoxLayout(dlg) lbl = _QLabel("Press a button, trigger, or move a stick\n" "on your gamepad to assign it.\n\n" "Close this window to cancel.") lbl.setAlignment(_Qt.AlignCenter) layout.addWidget(lbl) dlg.setLayout(layout) result = [None] def poll(): for event in pygame.event.get(): if event.type == pygame.JOYBUTTONDOWN: result[0] = 'B' + str(event.button) dlg.accept() return if event.type == pygame.JOYAXISMOTION: value = event.dict['value'] axis = event.dict['axis'] if abs(value) > 0.75: code = 'A' + str(axis) code += '+' if value > 0 else '-' result[0] = code dlg.accept() return if event.type == pygame.JOYHATMOTION: value = event.dict['value'] code = 'H' + str(value[0]) + str(value[1]) if code != 'H00': result[0] = code dlg.accept() return timer = QTimer(dlg) timer.timeout.connect(poll) timer.start(50) # poll every 50 ms pygame.event.clear() dlg.exec_() timer.stop() return result[0]