Dan Albert 4147d2f684 Initial squadrons implementation.
Doesn't actually do anything yet, but squadrons are created for each
aircraft type and pilots will be created as needed to fill flights.

https://github.com/dcs-liberation/dcs_liberation/issues/276
2021-05-26 17:49:53 -07:00

158 lines
6.2 KiB
Python

import logging
from PySide2.QtCore import Signal, QModelIndex
from PySide2.QtWidgets import QLabel, QGroupBox, QSpinBox, QGridLayout, QComboBox
from game import Game
from gen.flights.flight import Flight
from qt_ui.models import PackageModel
class PilotSelector(QComboBox):
available_pilots_changed = Signal()
def __init__(self, flight: Flight, idx: int) -> None:
super().__init__()
self.flight = flight
self.pilot_index = idx
self.rebuild(initial_build=True)
def _do_rebuild(self) -> None:
self.clear()
if self.pilot_index >= self.flight.count:
self.addItem("No aircraft", None)
self.setDisabled(True)
return
self.setEnabled(True)
self.addItem("Unassigned", None)
choices = list(self.flight.squadron.available_pilots)
current_pilot = self.flight.pilots[self.pilot_index]
if current_pilot is not None:
choices.append(current_pilot)
for pilot in sorted(choices, key=lambda p: p.name):
self.addItem(pilot.name, pilot)
if current_pilot is None:
self.setCurrentText("Unassigned")
return
self.setCurrentText(current_pilot.name)
self.currentIndexChanged.connect(self.replace_pilot)
def rebuild(self, initial_build: bool = False) -> None:
current_selection = self.currentData()
# 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
# 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
# and emit signals if anything actually changes afterwards.
self.blockSignals(True)
try:
self._do_rebuild()
finally:
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:
if self.itemText(index) == "No aircraft":
# The roster resize is handled separately, so we have no pilots to remove.
return
pilot = self.itemData(index)
if pilot == self.flight.pilots[self.pilot_index]:
return
self.flight.set_pilot(self.pilot_index, pilot)
self.available_pilots_changed.emit()
class QFlightSlotEditor(QGroupBox):
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
super().__init__("Slots")
self.package_model = package_model
self.flight = flight
self.game = game
self.inventory = self.game.aircraft_inventory.for_control_point(flight.from_cp)
available = self.inventory.available(self.flight.unit_type)
max_count = self.flight.count + available
if max_count > 4:
max_count = 4
layout = QGridLayout()
self.aircraft_count = QLabel("Aircraft count:")
self.aircraft_count_spinner = QSpinBox()
self.aircraft_count_spinner.setMinimum(1)
self.aircraft_count_spinner.setMaximum(max_count)
self.aircraft_count_spinner.setValue(flight.count)
self.aircraft_count_spinner.valueChanged.connect(self._changed_aircraft_count)
self.client_count = QLabel("Client slots count:")
self.client_count_spinner = QSpinBox()
self.client_count_spinner.setMinimum(0)
self.client_count_spinner.setMaximum(max_count)
self.client_count_spinner.setValue(flight.client_count)
self.client_count_spinner.valueChanged.connect(self._changed_client_count)
if not self.flight.unit_type.flyable:
self.client_count_spinner.setValue(0)
self.client_count_spinner.setEnabled(False)
layout.addWidget(self.aircraft_count, 0, 0)
layout.addWidget(self.aircraft_count_spinner, 0, 1)
layout.addWidget(self.client_count, 1, 0)
layout.addWidget(self.client_count_spinner, 1, 1)
layout.addWidget(QLabel("Squadron:"), 2, 0)
layout.addWidget(QLabel(self.flight.squadron.name), 2, 1)
layout.addWidget(QLabel("Assigned pilots:"), 3, 0)
self.pilot_selectors = []
for pilot_idx, row in enumerate(range(3, 7)):
selector = PilotSelector(self.flight, pilot_idx)
selector.available_pilots_changed.connect(self.reset_pilot_selectors)
self.pilot_selectors.append(selector)
layout.addWidget(selector, row, 1)
self.setLayout(layout)
def reset_pilot_selectors(self) -> None:
for selector in self.pilot_selectors:
selector.rebuild()
def _changed_aircraft_count(self):
self.game.aircraft_inventory.return_from_flight(self.flight)
new_count = int(self.aircraft_count_spinner.value())
try:
self.game.aircraft_inventory.claim_for_flight(self.flight)
except ValueError:
# The UI should have prevented this, but if we ran out of aircraft
# then roll back the inventory change.
difference = new_count - self.flight.count
available = self.inventory.available(self.flight.unit_type)
logging.error(
f"Could not add {difference} additional aircraft to "
f"{self.flight} because {self.flight.departure} has only "
f"{available} {self.flight.unit_type} remaining"
)
self.game.aircraft_inventory.claim_for_flight(self.flight)
return
self.flight.resize(new_count)
self._cap_client_count()
self.reset_pilot_selectors()
def _changed_client_count(self):
self.flight.client_count = int(self.client_count_spinner.value())
self._cap_client_count()
self.package_model.update_tot()
def _cap_client_count(self):
if self.flight.client_count > self.flight.count:
self.flight.client_count = self.flight.count
self.client_count_spinner.setValue(self.flight.client_count)