mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
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
This commit is contained in:
@@ -14,6 +14,7 @@ from PySide2.QtGui import QIcon
|
||||
|
||||
from game import db
|
||||
from game.game import Game
|
||||
from game.squadrons import Squadron, Pilot
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.transfers import TransferOrder
|
||||
from gen.ato import AirTaskingOrder, Package
|
||||
@@ -366,6 +367,87 @@ class TransferModel(QAbstractListModel):
|
||||
return self.game_model.game.transfers.transfer_at_index(index.row())
|
||||
|
||||
|
||||
class AirWingModel(QAbstractListModel):
|
||||
"""The model for an air wing."""
|
||||
|
||||
SquadronRole = Qt.UserRole
|
||||
|
||||
def __init__(self, game_model: GameModel, player: bool) -> None:
|
||||
super().__init__()
|
||||
self.game_model = game_model
|
||||
self.player = player
|
||||
|
||||
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
||||
return self.game_model.game.air_wing_for(self.player).size
|
||||
|
||||
def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any:
|
||||
if not index.isValid():
|
||||
return None
|
||||
squadron = self.squadron_at_index(index)
|
||||
if role == Qt.DisplayRole:
|
||||
return self.text_for_squadron(squadron)
|
||||
if role == Qt.DecorationRole:
|
||||
return self.icon_for_squadron(squadron)
|
||||
elif role == AirWingModel.SquadronRole:
|
||||
return squadron
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def text_for_squadron(squadron: Squadron) -> str:
|
||||
"""Returns the text that should be displayed for the squadron."""
|
||||
return squadron.name
|
||||
|
||||
@staticmethod
|
||||
def icon_for_squadron(_squadron: Squadron) -> Optional[QIcon]:
|
||||
"""Returns the icon that should be displayed for the squadron."""
|
||||
return None
|
||||
|
||||
def squadron_at_index(self, index: QModelIndex) -> Squadron:
|
||||
"""Returns the squadron located at the given index."""
|
||||
return self.game_model.game.air_wing_for(self.player).squadron_at_index(
|
||||
index.row()
|
||||
)
|
||||
|
||||
|
||||
class SquadronModel(QAbstractListModel):
|
||||
"""The model for a squadron."""
|
||||
|
||||
PilotRole = Qt.UserRole
|
||||
|
||||
def __init__(self, squadron: Squadron) -> None:
|
||||
super().__init__()
|
||||
self.squadron = squadron
|
||||
|
||||
def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
|
||||
return self.squadron.size
|
||||
|
||||
def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any:
|
||||
if not index.isValid():
|
||||
return None
|
||||
pilot = self.pilot_at_index(index)
|
||||
if role == Qt.DisplayRole:
|
||||
return self.text_for_pilot(pilot)
|
||||
if role == Qt.DecorationRole:
|
||||
return self.icon_for_pilot(pilot)
|
||||
elif role == SquadronModel.PilotRole:
|
||||
return pilot
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def text_for_pilot(pilot: Pilot) -> str:
|
||||
"""Returns the text that should be displayed for the pilot."""
|
||||
return pilot.name
|
||||
|
||||
@staticmethod
|
||||
def icon_for_pilot(_pilot: Pilot) -> Optional[QIcon]:
|
||||
"""Returns the icon that should be displayed for the pilot."""
|
||||
return None
|
||||
|
||||
def pilot_at_index(self, index: QModelIndex) -> Pilot:
|
||||
"""Returns the pilot located at the given index."""
|
||||
return self.squadron.pilot_at_index(index.row())
|
||||
|
||||
|
||||
class GameModel:
|
||||
"""A model for the Game object.
|
||||
|
||||
@@ -376,6 +458,7 @@ class GameModel:
|
||||
def __init__(self, game: Optional[Game]) -> None:
|
||||
self.game: Optional[Game] = game
|
||||
self.transfer_model = TransferModel(self)
|
||||
self.blue_air_wing_model = AirWingModel(self, player=True)
|
||||
if self.game is None:
|
||||
self.ato_model = AtoModel(self, AirTaskingOrder())
|
||||
self.red_ato_model = AtoModel(self, AirTaskingOrder())
|
||||
|
||||
@@ -21,6 +21,7 @@ from qt_ui.widgets.QConditionsWidget import QConditionsWidget
|
||||
from qt_ui.widgets.QFactionsInfos import QFactionsInfos
|
||||
from qt_ui.widgets.QIntelBox import QIntelBox
|
||||
from qt_ui.widgets.clientslots import MaxPlayerCount
|
||||
from qt_ui.windows.AirWingDialog import AirWingDialog
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.PendingTransfersDialog import PendingTransfersDialog
|
||||
from qt_ui.windows.QWaitingForMissionResultWindow import QWaitingForMissionResultWindow
|
||||
@@ -63,6 +64,11 @@ class QTopPanel(QFrame):
|
||||
|
||||
self.factionsInfos = QFactionsInfos(self.game)
|
||||
|
||||
self.air_wing = QPushButton("Air Wing")
|
||||
self.air_wing.setDisabled(True)
|
||||
self.air_wing.setProperty("style", "btn-primary")
|
||||
self.air_wing.clicked.connect(self.open_air_wing)
|
||||
|
||||
self.transfers = QPushButton("Transfers")
|
||||
self.transfers.setDisabled(True)
|
||||
self.transfers.setProperty("style", "btn-primary")
|
||||
@@ -84,6 +90,7 @@ class QTopPanel(QFrame):
|
||||
|
||||
self.buttonBox = QGroupBox("Misc")
|
||||
self.buttonBoxLayout = QHBoxLayout()
|
||||
self.buttonBoxLayout.addWidget(self.air_wing)
|
||||
self.buttonBoxLayout.addWidget(self.transfers)
|
||||
self.buttonBoxLayout.addWidget(self.settings)
|
||||
self.buttonBoxLayout.addWidget(self.statistics)
|
||||
@@ -114,6 +121,7 @@ class QTopPanel(QFrame):
|
||||
if game is None:
|
||||
return
|
||||
|
||||
self.air_wing.setEnabled(True)
|
||||
self.transfers.setEnabled(True)
|
||||
self.settings.setEnabled(True)
|
||||
self.statistics.setEnabled(True)
|
||||
@@ -130,6 +138,10 @@ class QTopPanel(QFrame):
|
||||
else:
|
||||
self.proceedButton.setEnabled(True)
|
||||
|
||||
def open_air_wing(self):
|
||||
self.dialog = AirWingDialog(self.game_model, self.window())
|
||||
self.dialog.show()
|
||||
|
||||
def open_transfers(self):
|
||||
self.dialog = PendingTransfersDialog(self.game_model)
|
||||
self.dialog.show()
|
||||
|
||||
@@ -562,10 +562,17 @@ class QLiberationMap(QGraphicsView, LiberationMap):
|
||||
origin = self.game.theater.enemy_points()[0]
|
||||
|
||||
package = Package(target)
|
||||
for squadron_list in self.game.air_wing_for(player=True).squadrons.values():
|
||||
squadron = squadron_list[0]
|
||||
break
|
||||
else:
|
||||
logging.error("Player has no squadrons?")
|
||||
return
|
||||
|
||||
flight = Flight(
|
||||
package,
|
||||
self.game.player_country if player else self.game.enemy_country,
|
||||
F_16C_50,
|
||||
self.game.country_for(player),
|
||||
squadron,
|
||||
2,
|
||||
task,
|
||||
start_type="Warm",
|
||||
|
||||
154
qt_ui/windows/AirWingDialog.py
Normal file
154
qt_ui/windows/AirWingDialog.py
Normal file
@@ -0,0 +1,154 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtCore import (
|
||||
QItemSelectionModel,
|
||||
QModelIndex,
|
||||
QSize,
|
||||
Qt,
|
||||
)
|
||||
from PySide2.QtGui import QFont, QFontMetrics, QIcon, QPainter
|
||||
from PySide2.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QDialog,
|
||||
QListView,
|
||||
QStyle,
|
||||
QStyleOptionViewItem,
|
||||
QStyledItemDelegate,
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
from game.squadrons import Squadron
|
||||
from qt_ui.delegate_helpers import painter_context
|
||||
from qt_ui.models import GameModel, AirWingModel, SquadronModel
|
||||
from qt_ui.windows.SquadronDialog import SquadronDialog
|
||||
|
||||
|
||||
class SquadronDelegate(QStyledItemDelegate):
|
||||
FONT_SIZE = 10
|
||||
HMARGIN = 4
|
||||
VMARGIN = 4
|
||||
|
||||
def __init__(self, air_wing_model: AirWingModel) -> None:
|
||||
super().__init__()
|
||||
self.air_wing_model = air_wing_model
|
||||
|
||||
def get_font(self, option: QStyleOptionViewItem) -> QFont:
|
||||
font = QFont(option.font)
|
||||
font.setPointSize(self.FONT_SIZE)
|
||||
return font
|
||||
|
||||
@staticmethod
|
||||
def squadron(index: QModelIndex) -> Squadron:
|
||||
return index.data(AirWingModel.SquadronRole)
|
||||
|
||||
def first_row_text(self, index: QModelIndex) -> str:
|
||||
return self.air_wing_model.data(index, Qt.DisplayRole)
|
||||
|
||||
def second_row_text(self, index: QModelIndex) -> str:
|
||||
return self.squadron(index).nickname
|
||||
|
||||
def paint(
|
||||
self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
|
||||
) -> None:
|
||||
# Draw the list item with all the default selection styling, but with an
|
||||
# invalid index so text formatting is left to us.
|
||||
super().paint(painter, option, QModelIndex())
|
||||
|
||||
rect = option.rect.adjusted(
|
||||
self.HMARGIN, self.VMARGIN, -self.HMARGIN, -self.VMARGIN
|
||||
)
|
||||
|
||||
with painter_context(painter):
|
||||
painter.setFont(self.get_font(option))
|
||||
|
||||
icon: Optional[QIcon] = index.data(Qt.DecorationRole)
|
||||
if icon is not None:
|
||||
icon.paint(
|
||||
painter,
|
||||
rect,
|
||||
Qt.AlignLeft | Qt.AlignVCenter,
|
||||
self.icon_mode(option),
|
||||
self.icon_state(option),
|
||||
)
|
||||
|
||||
rect = rect.adjusted(self.icon_size(option).width() + self.HMARGIN, 0, 0, 0)
|
||||
painter.drawText(rect, Qt.AlignLeft, self.first_row_text(index))
|
||||
line2 = rect.adjusted(0, rect.height() / 2, 0, rect.height() / 2)
|
||||
painter.drawText(line2, Qt.AlignLeft, self.second_row_text(index))
|
||||
|
||||
@staticmethod
|
||||
def icon_mode(option: QStyleOptionViewItem) -> QIcon.Mode:
|
||||
if not (option.state & QStyle.State_Enabled):
|
||||
return QIcon.Disabled
|
||||
elif option.state & QStyle.State_Selected:
|
||||
return QIcon.Selected
|
||||
elif option.state & QStyle.State_Active:
|
||||
return QIcon.Active
|
||||
return QIcon.Normal
|
||||
|
||||
@staticmethod
|
||||
def icon_state(option: QStyleOptionViewItem) -> QIcon.State:
|
||||
return QIcon.On if option.state & QStyle.State_Open else QIcon.Off
|
||||
|
||||
@staticmethod
|
||||
def icon_size(option: QStyleOptionViewItem) -> QSize:
|
||||
icon_size: Optional[QSize] = option.decorationSize
|
||||
if icon_size is None:
|
||||
return QSize(0, 0)
|
||||
else:
|
||||
return icon_size
|
||||
|
||||
def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
|
||||
left = self.icon_size(option).width() + self.HMARGIN
|
||||
metrics = QFontMetrics(self.get_font(option))
|
||||
first = metrics.size(0, self.first_row_text(index))
|
||||
second = metrics.size(0, self.second_row_text(index))
|
||||
text_width = max(first.width(), second.width())
|
||||
return QSize(
|
||||
left + text_width + 2 * self.HMARGIN,
|
||||
first.height() + second.height() + 2 * self.VMARGIN,
|
||||
)
|
||||
|
||||
|
||||
class SquadronList(QListView):
|
||||
"""List view for displaying the air wing's squadrons."""
|
||||
|
||||
def __init__(self, air_wing_model: AirWingModel) -> None:
|
||||
super().__init__()
|
||||
self.air_wing_model = air_wing_model
|
||||
self.dialog: Optional[SquadronDialog] = None
|
||||
|
||||
self.setItemDelegate(SquadronDelegate(self.air_wing_model))
|
||||
self.setModel(self.air_wing_model)
|
||||
self.selectionModel().setCurrentIndex(
|
||||
self.air_wing_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select
|
||||
)
|
||||
|
||||
# self.setIconSize(QSize(91, 24))
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectItems)
|
||||
self.doubleClicked.connect(self.on_double_click)
|
||||
|
||||
def on_double_click(self, index: QModelIndex) -> None:
|
||||
if not index.isValid():
|
||||
return
|
||||
self.dialog = SquadronDialog(
|
||||
SquadronModel(self.air_wing_model.squadron_at_index(index)), self
|
||||
)
|
||||
self.dialog.show()
|
||||
|
||||
|
||||
class AirWingDialog(QDialog):
|
||||
"""Dialog window showing the player's air wing."""
|
||||
|
||||
def __init__(self, game_model: GameModel, parent) -> None:
|
||||
super().__init__(parent)
|
||||
self.air_wing_model = game_model.blue_air_wing_model
|
||||
|
||||
self.setMinimumSize(1000, 440)
|
||||
self.setWindowTitle(f"Air Wing")
|
||||
# TODO: self.setWindowIcon()
|
||||
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
layout.addWidget(SquadronList(self.air_wing_model))
|
||||
@@ -190,7 +190,7 @@ class PendingTransfersDialog(QDialog):
|
||||
def can_cancel(self, index: QModelIndex) -> bool:
|
||||
if not index.isValid():
|
||||
return False
|
||||
return self.transfer_model.transfer_at_index(index).player
|
||||
return self.transfer_model.pilot_at_index(index).player
|
||||
|
||||
def on_selection_changed(
|
||||
self, selected: QItemSelection, _deselected: QItemSelection
|
||||
|
||||
142
qt_ui/windows/SquadronDialog.py
Normal file
142
qt_ui/windows/SquadronDialog.py
Normal file
@@ -0,0 +1,142 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtCore import (
|
||||
QItemSelectionModel,
|
||||
QModelIndex,
|
||||
QSize,
|
||||
Qt,
|
||||
)
|
||||
from PySide2.QtGui import QFont, QFontMetrics, QIcon, QPainter
|
||||
from PySide2.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QDialog,
|
||||
QListView,
|
||||
QStyle,
|
||||
QStyleOptionViewItem,
|
||||
QStyledItemDelegate,
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
from game.squadrons import Pilot
|
||||
from qt_ui.delegate_helpers import painter_context
|
||||
from qt_ui.models import SquadronModel
|
||||
|
||||
|
||||
class PilotDelegate(QStyledItemDelegate):
|
||||
FONT_SIZE = 10
|
||||
HMARGIN = 4
|
||||
VMARGIN = 4
|
||||
|
||||
def __init__(self, squadron_model: SquadronModel) -> None:
|
||||
super().__init__()
|
||||
self.squadron_model = squadron_model
|
||||
|
||||
def get_font(self, option: QStyleOptionViewItem) -> QFont:
|
||||
font = QFont(option.font)
|
||||
font.setPointSize(self.FONT_SIZE)
|
||||
return font
|
||||
|
||||
@staticmethod
|
||||
def pilot(index: QModelIndex) -> Pilot:
|
||||
return index.data(SquadronModel.PilotRole)
|
||||
|
||||
def first_row_text(self, index: QModelIndex) -> str:
|
||||
return self.squadron_model.data(index, Qt.DisplayRole)
|
||||
|
||||
def second_row_text(self, index: QModelIndex) -> str:
|
||||
return "Alive" if self.pilot(index).alive else "Dead"
|
||||
|
||||
def paint(
|
||||
self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
|
||||
) -> None:
|
||||
# Draw the list item with all the default selection styling, but with an
|
||||
# invalid index so text formatting is left to us.
|
||||
super().paint(painter, option, QModelIndex())
|
||||
|
||||
rect = option.rect.adjusted(
|
||||
self.HMARGIN, self.VMARGIN, -self.HMARGIN, -self.VMARGIN
|
||||
)
|
||||
|
||||
with painter_context(painter):
|
||||
painter.setFont(self.get_font(option))
|
||||
|
||||
icon: Optional[QIcon] = index.data(Qt.DecorationRole)
|
||||
if icon is not None:
|
||||
icon.paint(
|
||||
painter,
|
||||
rect,
|
||||
Qt.AlignLeft | Qt.AlignVCenter,
|
||||
self.icon_mode(option),
|
||||
self.icon_state(option),
|
||||
)
|
||||
|
||||
rect = rect.adjusted(self.icon_size(option).width() + self.HMARGIN, 0, 0, 0)
|
||||
painter.drawText(rect, Qt.AlignLeft, self.first_row_text(index))
|
||||
line2 = rect.adjusted(0, rect.height() / 2, 0, rect.height() / 2)
|
||||
painter.drawText(line2, Qt.AlignLeft, self.second_row_text(index))
|
||||
|
||||
@staticmethod
|
||||
def icon_mode(option: QStyleOptionViewItem) -> QIcon.Mode:
|
||||
if not (option.state & QStyle.State_Enabled):
|
||||
return QIcon.Disabled
|
||||
elif option.state & QStyle.State_Selected:
|
||||
return QIcon.Selected
|
||||
elif option.state & QStyle.State_Active:
|
||||
return QIcon.Active
|
||||
return QIcon.Normal
|
||||
|
||||
@staticmethod
|
||||
def icon_state(option: QStyleOptionViewItem) -> QIcon.State:
|
||||
return QIcon.On if option.state & QStyle.State_Open else QIcon.Off
|
||||
|
||||
@staticmethod
|
||||
def icon_size(option: QStyleOptionViewItem) -> QSize:
|
||||
icon_size: Optional[QSize] = option.decorationSize
|
||||
if icon_size is None:
|
||||
return QSize(0, 0)
|
||||
else:
|
||||
return icon_size
|
||||
|
||||
def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
|
||||
left = self.icon_size(option).width() + self.HMARGIN
|
||||
metrics = QFontMetrics(self.get_font(option))
|
||||
first = metrics.size(0, self.first_row_text(index))
|
||||
second = metrics.size(0, self.second_row_text(index))
|
||||
text_width = max(first.width(), second.width())
|
||||
return QSize(
|
||||
left + text_width + 2 * self.HMARGIN,
|
||||
first.height() + second.height() + 2 * self.VMARGIN,
|
||||
)
|
||||
|
||||
|
||||
class PilotList(QListView):
|
||||
"""List view for displaying a squadron's pilots."""
|
||||
|
||||
def __init__(self, squadron_model: SquadronModel) -> None:
|
||||
super().__init__()
|
||||
self.squadron_model = squadron_model
|
||||
|
||||
self.setItemDelegate(PilotDelegate(self.squadron_model))
|
||||
self.setModel(self.squadron_model)
|
||||
self.selectionModel().setCurrentIndex(
|
||||
self.squadron_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select
|
||||
)
|
||||
|
||||
# self.setIconSize(QSize(91, 24))
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectItems)
|
||||
|
||||
|
||||
class SquadronDialog(QDialog):
|
||||
"""Dialog window showing a squadron."""
|
||||
|
||||
def __init__(self, squadron_model: SquadronModel, parent) -> None:
|
||||
super().__init__(parent)
|
||||
|
||||
self.setMinimumSize(1000, 440)
|
||||
self.setWindowTitle(squadron_model.squadron.name)
|
||||
# TODO: self.setWindowIcon()
|
||||
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
layout.addWidget(PilotList(squadron_model))
|
||||
@@ -175,7 +175,7 @@ class QFlightCreator(QDialog):
|
||||
flight = Flight(
|
||||
self.package,
|
||||
self.country,
|
||||
aircraft,
|
||||
self.game.air_wing_for(player=True).squadron_for(aircraft),
|
||||
size,
|
||||
task,
|
||||
self.start_type.currentText(),
|
||||
|
||||
@@ -1,17 +1,75 @@
|
||||
import logging
|
||||
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import QLabel, QGroupBox, QSpinBox, QGridLayout
|
||||
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):
|
||||
|
||||
changed = Signal()
|
||||
|
||||
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
|
||||
super().__init__("Slots")
|
||||
self.package_model = package_model
|
||||
@@ -49,33 +107,49 @@ class QFlightSlotEditor(QGroupBox):
|
||||
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)
|
||||
old_count = self.flight.count
|
||||
self.flight.count = int(self.aircraft_count_spinner.value())
|
||||
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 = self.flight.count - old_count
|
||||
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.from_cp} has only "
|
||||
f"{self.flight} because {self.flight.departure} has only "
|
||||
f"{available} {self.flight.unit_type} remaining"
|
||||
)
|
||||
self.flight.count = old_count
|
||||
self.game.aircraft_inventory.claim_for_flight(self.flight)
|
||||
self.changed.emit()
|
||||
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()
|
||||
self.changed.emit()
|
||||
|
||||
def _cap_client_count(self):
|
||||
if self.flight.client_count > self.flight.count:
|
||||
|
||||
@@ -21,9 +21,6 @@ class QFlightWaypointList(QTableView):
|
||||
|
||||
header = self.horizontalHeader()
|
||||
header.setSectionResizeMode(0, QHeaderView.ResizeToContents)
|
||||
|
||||
if len(self.flight.points) > 0:
|
||||
self.selectedPoint = self.flight.points[0]
|
||||
self.update_list()
|
||||
|
||||
self.selectionModel().setCurrentIndex(
|
||||
|
||||
Reference in New Issue
Block a user