mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Clean up signal handling in pilot roster editor.
This commit is contained in:
parent
5a732acf64
commit
f6ab1aad77
@ -1,5 +1,5 @@
|
|||||||
import logging
|
import logging
|
||||||
from typing import Optional
|
from typing import Optional, Callable
|
||||||
|
|
||||||
from PySide2.QtCore import Signal, QModelIndex
|
from PySide2.QtCore import Signal, QModelIndex
|
||||||
from PySide2.QtWidgets import (
|
from PySide2.QtWidgets import (
|
||||||
@ -10,6 +10,7 @@ from PySide2.QtWidgets import (
|
|||||||
QComboBox,
|
QComboBox,
|
||||||
QHBoxLayout,
|
QHBoxLayout,
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
|
QVBoxLayout,
|
||||||
)
|
)
|
||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
@ -25,8 +26,7 @@ class PilotSelector(QComboBox):
|
|||||||
super().__init__()
|
super().__init__()
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
self.pilot_index = idx
|
self.pilot_index = idx
|
||||||
|
self.rebuild()
|
||||||
self.rebuild(initial_build=True)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def text_for(pilot: Pilot) -> str:
|
def text_for(pilot: Pilot) -> str:
|
||||||
@ -54,25 +54,17 @@ class PilotSelector(QComboBox):
|
|||||||
self.setCurrentText(self.text_for(current_pilot))
|
self.setCurrentText(self.text_for(current_pilot))
|
||||||
self.currentIndexChanged.connect(self.replace_pilot)
|
self.currentIndexChanged.connect(self.replace_pilot)
|
||||||
|
|
||||||
def rebuild(self, initial_build: bool = False) -> None:
|
def rebuild(self) -> None:
|
||||||
current_selection = self.currentData()
|
|
||||||
|
|
||||||
# The contents of the selector depend on the selection of the other selectors
|
# The contents of the selector depend on the selection of the other selectors
|
||||||
# for the flight, so changing the selection of one causes each selector to
|
# for the flight, so changing the selection of one causes each selector to
|
||||||
# rebuild. A rebuild causes a selection change, so if we don't block signals
|
# rebuild. A rebuild causes a selection change, so if we don't block signals
|
||||||
# during a rebuild we'll never stop rebuilding. Block signals during the rebuild
|
# during a rebuild we'll never stop rebuilding.
|
||||||
# and emit signals if anything actually changes afterwards.
|
|
||||||
self.blockSignals(True)
|
self.blockSignals(True)
|
||||||
try:
|
try:
|
||||||
self._do_rebuild()
|
self._do_rebuild()
|
||||||
finally:
|
finally:
|
||||||
self.blockSignals(False)
|
self.blockSignals(False)
|
||||||
|
|
||||||
new_selection = self.currentData()
|
|
||||||
if not initial_build and current_selection != new_selection:
|
|
||||||
self.currentIndexChanged.emit(self.currentIndex())
|
|
||||||
self.currentTextChanged.emit(self.currentText())
|
|
||||||
|
|
||||||
def replace_pilot(self, index: QModelIndex) -> None:
|
def replace_pilot(self, index: QModelIndex) -> None:
|
||||||
if self.itemText(index) == "No aircraft":
|
if self.itemText(index) == "No aircraft":
|
||||||
# The roster resize is handled separately, so we have no pilots to remove.
|
# The roster resize is handled separately, so we have no pilots to remove.
|
||||||
@ -91,14 +83,15 @@ class PilotControls(QHBoxLayout):
|
|||||||
self.pilot_index = idx
|
self.pilot_index = idx
|
||||||
|
|
||||||
self.selector = PilotSelector(flight, idx)
|
self.selector = PilotSelector(flight, idx)
|
||||||
|
self.selector.currentIndexChanged.connect(self.on_pilot_changed)
|
||||||
self.addWidget(self.selector)
|
self.addWidget(self.selector)
|
||||||
|
|
||||||
self.player_checkbox = QCheckBox()
|
self.player_checkbox = QCheckBox()
|
||||||
self.player_checkbox.setToolTip("Checked if this pilot is a player.")
|
self.player_checkbox.setToolTip("Checked if this pilot is a player.")
|
||||||
|
self.on_pilot_changed(self.selector.currentIndex())
|
||||||
self.addWidget(self.player_checkbox)
|
self.addWidget(self.player_checkbox)
|
||||||
|
|
||||||
self.reset()
|
self.player_checkbox.toggled.connect(self.on_player_toggled)
|
||||||
self.player_checkbox.toggled.connect(self.toggle_player_state)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pilot(self) -> Optional[Pilot]:
|
def pilot(self) -> Optional[Pilot]:
|
||||||
@ -106,27 +99,73 @@ class PilotControls(QHBoxLayout):
|
|||||||
return None
|
return None
|
||||||
return self.flight.pilots[self.pilot_index]
|
return self.flight.pilots[self.pilot_index]
|
||||||
|
|
||||||
def toggle_player_state(self, checked: bool) -> None:
|
def on_player_toggled(self, checked: bool) -> None:
|
||||||
pilot = self.pilot
|
pilot = self.pilot
|
||||||
if pilot is None:
|
if pilot is None:
|
||||||
logging.error("Cannot toggle state of a pilot when none is selected")
|
logging.error("Cannot toggle state of a pilot when none is selected")
|
||||||
return
|
return
|
||||||
pilot.player = checked
|
pilot.player = checked
|
||||||
|
|
||||||
def reset(self, initial: bool = False) -> None:
|
def on_pilot_changed(self, index: int) -> None:
|
||||||
if not initial:
|
pilot = self.selector.itemData(index)
|
||||||
self.selector.rebuild()
|
self.player_checkbox.blockSignals(True)
|
||||||
self.blockSignals(True)
|
|
||||||
try:
|
try:
|
||||||
pilot = self.pilot
|
self.player_checkbox.setChecked(pilot is not None and pilot.player)
|
||||||
if pilot is None:
|
|
||||||
self.player_checkbox.setChecked(False)
|
|
||||||
self.player_checkbox.setEnabled(False)
|
|
||||||
return
|
|
||||||
self.player_checkbox.setEnabled(True)
|
|
||||||
self.player_checkbox.setChecked(self.pilot.player)
|
|
||||||
finally:
|
finally:
|
||||||
self.blockSignals(False)
|
self.player_checkbox.blockSignals(False)
|
||||||
|
|
||||||
|
def update_available_pilots(self) -> None:
|
||||||
|
self.selector.rebuild()
|
||||||
|
|
||||||
|
def enable_and_reset(self) -> None:
|
||||||
|
self.selector.rebuild()
|
||||||
|
self.on_pilot_changed(self.selector.currentIndex())
|
||||||
|
|
||||||
|
def disable_and_clear(self) -> None:
|
||||||
|
self.selector.rebuild()
|
||||||
|
self.player_checkbox.blockSignals(True)
|
||||||
|
try:
|
||||||
|
self.player_checkbox.setEnabled(False)
|
||||||
|
self.player_checkbox.setChecked(False)
|
||||||
|
finally:
|
||||||
|
self.player_checkbox.blockSignals(False)
|
||||||
|
|
||||||
|
|
||||||
|
class FlightRosterEditor(QVBoxLayout):
|
||||||
|
MAX_PILOTS = 4
|
||||||
|
|
||||||
|
def __init__(self, flight: Flight) -> None:
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.pilot_controls = []
|
||||||
|
for pilot_idx in range(self.MAX_PILOTS):
|
||||||
|
|
||||||
|
def make_reset_callback(source_idx: int) -> Callable[[int], None]:
|
||||||
|
def callback() -> None:
|
||||||
|
self.update_available_pilots(source_idx)
|
||||||
|
|
||||||
|
return callback
|
||||||
|
|
||||||
|
controls = PilotControls(flight, pilot_idx)
|
||||||
|
controls.selector.available_pilots_changed.connect(
|
||||||
|
make_reset_callback(pilot_idx)
|
||||||
|
)
|
||||||
|
self.pilot_controls.append(controls)
|
||||||
|
self.addLayout(controls)
|
||||||
|
|
||||||
|
def update_available_pilots(self, source_idx: int) -> None:
|
||||||
|
for idx, controls in enumerate(self.pilot_controls):
|
||||||
|
# No need to reset the source of the reset, it was just manually selected.
|
||||||
|
if idx != source_idx:
|
||||||
|
controls.update_available_pilots()
|
||||||
|
|
||||||
|
def resize(self, new_size: int) -> None:
|
||||||
|
if new_size > self.MAX_PILOTS:
|
||||||
|
raise ValueError("A flight may not have more than four pilots.")
|
||||||
|
for controls in self.pilot_controls[:new_size]:
|
||||||
|
controls.enable_and_reset()
|
||||||
|
for controls in self.pilot_controls[new_size:]:
|
||||||
|
controls.disable_and_clear()
|
||||||
|
|
||||||
|
|
||||||
class QFlightSlotEditor(QGroupBox):
|
class QFlightSlotEditor(QGroupBox):
|
||||||
@ -157,21 +196,11 @@ class QFlightSlotEditor(QGroupBox):
|
|||||||
layout.addWidget(QLabel(str(self.flight.squadron)), 1, 1)
|
layout.addWidget(QLabel(str(self.flight.squadron)), 1, 1)
|
||||||
|
|
||||||
layout.addWidget(QLabel("Assigned pilots:"), 2, 0)
|
layout.addWidget(QLabel("Assigned pilots:"), 2, 0)
|
||||||
self.pilot_controls = []
|
self.roster_editor = FlightRosterEditor(flight)
|
||||||
for pilot_idx, row in enumerate(range(2, 6)):
|
layout.addLayout(self.roster_editor, 2, 1)
|
||||||
controls = PilotControls(self.flight, pilot_idx)
|
|
||||||
controls.selector.available_pilots_changed.connect(
|
|
||||||
self.reset_pilot_selectors
|
|
||||||
)
|
|
||||||
self.pilot_controls.append(controls)
|
|
||||||
layout.addLayout(controls, row, 1)
|
|
||||||
|
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def reset_pilot_selectors(self) -> None:
|
|
||||||
for controls in self.pilot_controls:
|
|
||||||
controls.reset()
|
|
||||||
|
|
||||||
def _changed_aircraft_count(self):
|
def _changed_aircraft_count(self):
|
||||||
self.game.aircraft_inventory.return_from_flight(self.flight)
|
self.game.aircraft_inventory.return_from_flight(self.flight)
|
||||||
new_count = int(self.aircraft_count_spinner.value())
|
new_count = int(self.aircraft_count_spinner.value())
|
||||||
@ -191,4 +220,4 @@ class QFlightSlotEditor(QGroupBox):
|
|||||||
return
|
return
|
||||||
|
|
||||||
self.flight.resize(new_count)
|
self.flight.resize(new_count)
|
||||||
self.reset_pilot_selectors()
|
self.roster_editor.resize(new_count)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user