From 67dae80b76247502464bcb7e8bec5129e64f338c Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Sun, 19 Feb 2023 11:59:45 -0800 Subject: [PATCH] Rework the speed controls for 1080p friendliness. Fixes https://github.com/dcs-liberation/dcs_liberation/issues/2396. --- qt_ui/simcontroller.py | 6 ++- qt_ui/widgets/simspeedcontrols.py | 74 +++++++++++++++++++++++-------- 2 files changed, 60 insertions(+), 20 deletions(-) diff --git a/qt_ui/simcontroller.py b/qt_ui/simcontroller.py index 4bf9be05..18675139 100644 --- a/qt_ui/simcontroller.py +++ b/qt_ui/simcontroller.py @@ -22,7 +22,7 @@ if TYPE_CHECKING: class SimController(QObject): sim_update = Signal(GameUpdateEvents) - sim_speed_reset = Signal(SimSpeedSetting) + sim_speed_changed = Signal(SimSpeedSetting) simulation_complete = Signal() def __init__(self, game: Optional[Game]) -> None: @@ -55,8 +55,8 @@ class SimController(QObject): return self.game_loop.elapsed_time def set_game(self, game: Optional[Game]) -> None: + self.sim_speed_changed.emit(SimSpeedSetting.PAUSED) self.recreate_game_loop(game) - self.sim_speed_reset.emit(SimSpeedSetting.PAUSED) def recreate_game_loop(self, game: Optional[Game]) -> None: if self.game_loop is not None: @@ -76,6 +76,7 @@ class SimController(QObject): if not self.started and simulation_speed is not SimSpeedSetting.PAUSED: self.game_loop.start() self.started = True + self.sim_speed_changed.emit(simulation_speed) self.game_loop.set_simulation_speed(simulation_speed) @contextmanager @@ -106,4 +107,5 @@ class SimController(QObject): def on_simulation_complete(self) -> None: logging.debug("Simulation complete") + self.sim_speed_changed.emit(SimSpeedSetting.PAUSED) self.simulation_complete.emit() diff --git a/qt_ui/widgets/simspeedcontrols.py b/qt_ui/widgets/simspeedcontrols.py index daa3eea0..cc6308b0 100644 --- a/qt_ui/widgets/simspeedcontrols.py +++ b/qt_ui/widgets/simspeedcontrols.py @@ -2,34 +2,72 @@ from __future__ import annotations from typing import Optional -from PySide6.QtWidgets import QButtonGroup, QHBoxLayout, QPushButton, QWidget +from PySide6.QtCore import QSize +from PySide6.QtWidgets import QHBoxLayout, QPushButton, QSpinBox, QWidget from game.sim.simspeedsetting import SimSpeedSetting from qt_ui.simcontroller import SimController +class SimSpeedSpinner(QSpinBox): + def __init__(self, sim_controller: SimController, parent: QWidget | None) -> None: + super().__init__(parent) + self.sim_controller = sim_controller + + # Disable text editing, which wouldn't work in the first place, but also + # obnoxiously selects the text on change (highlighting it) and leaves a flashing + # cursor in the middle of the element when clicked. + self.lineEdit().setEnabled(False) + + # The value stored by the spinner is the index of the speed setting in the enum. + # SimSpeedSetting is ordered, so the minimum value is paused, and increasing the + # value will speed up the game by one speed). + self.setMinimum(0) + self.setMaximum(len(SimSpeedSetting) - 1) + self.setValue(0) + + self.valueChanged.connect(self.on_change) + self.sim_controller.sim_speed_changed.connect(self.on_sim_speed_reset) + + @staticmethod + def speed_for_value(value: int) -> SimSpeedSetting: + return list(SimSpeedSetting)[value] + + def sizeHint(self) -> QSize: + # The default size hinting fails to deal with label width, and will truncate + # "Paused". + size = super().sizeHint() + size.setWidth(86) + return size + + def textFromValue(self, value: int) -> str: + return self.speed_for_value(value).text + + def valueFromText(self, text: str) -> int: + for idx, speed in enumerate(SimSpeedSetting): + if speed.text == text: + return idx + raise ValueError(f"Unknown SimSpeedSetting: {text}") + + def on_change(self, value: int) -> None: + self.sim_controller.set_simulation_speed(self.speed_for_value(value)) + + def on_sim_speed_reset(self, speed_setting: SimSpeedSetting) -> None: + self.setValue(list(SimSpeedSetting).index(speed_setting)) + + class SimSpeedControls(QHBoxLayout): def __init__( self, sim_controller: SimController, parent: Optional[QWidget] = None ) -> None: super().__init__(parent) self.sim_controller = sim_controller - self.button_group = QButtonGroup(self) - self.buttons: dict[SimSpeedSetting, QPushButton] = {} - for speed_setting in SimSpeedSetting: - button = QPushButton(speed_setting.text) - button.setCheckable(True) # TODO: CSS - self.button_group.addButton(button, id=speed_setting.speed_factor) - self.addWidget(button) - self.buttons[speed_setting] = button + self.pause_button = QPushButton(text="Pause") + self.pause_button.clicked.connect( + lambda: self.sim_controller.set_simulation_speed(SimSpeedSetting.PAUSED) + ) + self.addWidget(self.pause_button) - self.button_group.idPressed.connect(self.speed_changed) - self.sim_controller.sim_speed_reset.connect(self.on_sim_speed_reset) - - def speed_changed(self, speed_factor: int) -> None: - setting = SimSpeedSetting.from_factor(speed_factor) - self.sim_controller.set_simulation_speed(setting) - - def on_sim_speed_reset(self, speed_setting: SimSpeedSetting) -> None: - self.buttons[speed_setting].setChecked(True) + self.speed_spinner = SimSpeedSpinner(sim_controller, parent) + self.addWidget(self.speed_spinner)