diff --git a/qt_ui/windows/mission/flight/generator/QAbstractMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QAbstractMissionGenerator.py
deleted file mode 100644
index 4811da1d..00000000
--- a/qt_ui/windows/mission/flight/generator/QAbstractMissionGenerator.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from PySide2.QtCore import Qt
-from PySide2.QtWidgets import QDialog, QPushButton
-
-from game import Game
-from gen.ato import Package
-from gen.flights.flight import Flight
-from gen.flights.flightplan import FlightPlanBuilder
-from qt_ui.uiconstants import EVENT_ICONS
-from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox
-
-
-class QAbstractMissionGenerator(QDialog):
-
- def __init__(self, game: Game, package: Package, flight: Flight,
- flight_waypoint_list, title) -> None:
- super(QAbstractMissionGenerator, self).__init__()
- self.game = game
- self.package = package
- self.flight = flight
- self.setWindowFlags(Qt.WindowStaysOnTopHint)
- self.setMinimumSize(400, 250)
- self.setModal(True)
- self.setWindowTitle(title)
- self.setWindowIcon(EVENT_ICONS["strike"])
- self.flight_waypoint_list = flight_waypoint_list
- self.planner = FlightPlanBuilder(self.game, package, is_player=True)
-
- self.selected_waypoints = []
- self.wpt_info = QFlightWaypointInfoBox()
-
- self.ok_button = QPushButton("Ok")
- self.ok_button.clicked.connect(self.apply)
-
- def on_select_wpt_changed(self):
- self.selected_waypoints = self.wpt_selection_box.get_selected_waypoints(False)
- if self.selected_waypoints is None or len(self.selected_waypoints) <= 0:
- self.ok_button.setDisabled(True)
- else:
- self.wpt_info.set_flight_waypoint(self.selected_waypoints[0])
- self.ok_button.setDisabled(False)
-
- def apply(self):
- raise NotImplementedError()
-
-
-
-
diff --git a/qt_ui/windows/mission/flight/generator/QCAPMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QCAPMissionGenerator.py
deleted file mode 100644
index b376851d..00000000
--- a/qt_ui/windows/mission/flight/generator/QCAPMissionGenerator.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import logging
-
-from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
-
-from game import Game
-from gen.ato import Package
-from gen.flights.flight import Flight, FlightType
-from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
-from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
-from theater import ControlPoint, FrontLine
-
-
-class QCAPMissionGenerator(QAbstractMissionGenerator):
-
- def __init__(self, game: Game, package: Package, flight: Flight,
- flight_waypoint_list) -> None:
- super(QCAPMissionGenerator, self).__init__(
- game,
- package,
- flight,
- flight_waypoint_list,
- "CAP Generator"
- )
-
- self.wpt_selection_box = QPredefinedWaypointSelectionComboBox(self.game, self, False, True, True, False, False, True)
- self.wpt_selection_box.setMinimumWidth(200)
- self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed)
-
- self.init_ui()
- self.on_select_wpt_changed()
-
- def init_ui(self):
- layout = QVBoxLayout()
-
- wpt_layout = QHBoxLayout()
- wpt_layout.addWidget(QLabel("CAP mission on : "))
- wpt_layout.addWidget(self.wpt_selection_box)
- wpt_layout.addStretch()
-
- layout.addLayout(wpt_layout)
- layout.addWidget(self.wpt_info)
- layout.addStretch()
- layout.addWidget(self.ok_button)
-
- self.setLayout(layout)
-
- def apply(self):
- location = self.package.target
- if isinstance(location, FrontLine):
- self.flight.flight_type = FlightType.TARCAP
- self.planner.populate_flight_plan(self.flight)
- elif isinstance(location, ControlPoint):
- if location.is_fleet:
- self.flight.flight_type = FlightType.BARCAP
- else:
- self.flight.flight_type = FlightType.CAP
- else:
- name = location.__class__.__name__
- logging.error(f"Unexpected objective type for CAP: {name}")
- return
-
- self.planner.generate_barcap(self.flight)
-
- self.flight_waypoint_list.update_list()
- self.close()
-
-
-
-
diff --git a/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py
deleted file mode 100644
index 76177772..00000000
--- a/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from PySide2.QtGui import Qt
-from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QGroupBox
-from dcs import Point
-
-from game import Game
-from game.utils import meter_to_nm
-from gen.ato import Package
-from gen.flights.flight import Flight, FlightType
-from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
-from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
-
-
-class QCASMissionGenerator(QAbstractMissionGenerator):
-
- def __init__(self, game: Game, package: Package, flight: Flight,
- flight_waypoint_list) -> None:
- super(QCASMissionGenerator, self).__init__(
- game,
- package,
- flight,
- flight_waypoint_list,
- "CAS Generator"
- )
-
- self.wpt_selection_box = QPredefinedWaypointSelectionComboBox(self.game, self, False, False, True, False, False)
- self.wpt_selection_box.setMinimumWidth(200)
- self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed)
-
- self.distanceToTargetLabel = QLabel("0 nm")
- self.init_ui()
- self.on_select_wpt_changed()
-
- def on_select_wpt_changed(self):
- super(QCASMissionGenerator, self).on_select_wpt_changed()
- wpts = self.wpt_selection_box.get_selected_waypoints()
-
- if len(wpts) > 0:
- self.distanceToTargetLabel.setText("~" + str(meter_to_nm(self.flight.from_cp.position.distance_to_point(Point(wpts[0].x, wpts[0].y)))) + " nm")
- else:
- self.distanceToTargetLabel.setText("??? nm")
-
- def init_ui(self):
- layout = QVBoxLayout()
-
- wpt_layout = QHBoxLayout()
- wpt_layout.addWidget(QLabel("CAS : "))
- wpt_layout.addWidget(self.wpt_selection_box)
- wpt_layout.addStretch()
-
- distToTargetBox = QGroupBox("Infos :")
- distToTarget = QHBoxLayout()
- distToTarget.addWidget(QLabel("Distance to target : "))
- distToTarget.addStretch()
- distToTarget.addWidget(self.distanceToTargetLabel, alignment=Qt.AlignRight)
- distToTargetBox.setLayout(distToTarget)
-
- layout.addLayout(wpt_layout)
- layout.addWidget(self.wpt_info)
- layout.addWidget(distToTargetBox)
- layout.addStretch()
- layout.addWidget(self.ok_button)
-
- self.setLayout(layout)
-
- def apply(self):
- self.flight.flight_type = FlightType.CAS
- self.planner.populate_flight_plan(self.flight)
- self.flight_waypoint_list.update_list()
- self.close()
-
-
-
-
diff --git a/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py
deleted file mode 100644
index dd3a31f8..00000000
--- a/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py
+++ /dev/null
@@ -1,92 +0,0 @@
-from PySide2.QtGui import Qt
-from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QGroupBox
-
-from game import Game
-from game.utils import meter_to_nm
-from gen.ato import Package
-from gen.flights.flight import Flight, FlightType
-from qt_ui.widgets.combos.QSEADTargetSelectionComboBox import QSEADTargetSelectionComboBox
-from qt_ui.widgets.views.QSeadTargetInfoView import QSeadTargetInfoView
-from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
-
-
-class QSEADMissionGenerator(QAbstractMissionGenerator):
-
- def __init__(self, game: Game, package: Package, flight: Flight,
- flight_waypoint_list) -> None:
- super(QSEADMissionGenerator, self).__init__(
- game,
- package,
- flight,
- flight_waypoint_list,
- "SEAD/DEAD Generator"
- )
-
- self.tgt_selection_box = QSEADTargetSelectionComboBox(self.game)
- self.tgt_selection_box.setMinimumWidth(200)
- self.tgt_selection_box.currentTextChanged.connect(self.on_selected_target_changed)
-
- self.distanceToTargetLabel = QLabel("0 nm")
- self.threatRangeLabel = QLabel("0 nm")
- self.detectionRangeLabel = QLabel("0 nm")
- self.seadTargetInfoView = QSeadTargetInfoView(None)
- self.init_ui()
- self.on_selected_target_changed()
-
- def on_selected_target_changed(self):
- target = self.tgt_selection_box.get_selected_target()
- if target is not None:
- self.distanceToTargetLabel.setText("~" + str(meter_to_nm(self.flight.from_cp.position.distance_to_point(target.location.position))) + " nm")
- self.threatRangeLabel.setText(str(meter_to_nm(target.threat_range)) + " nm")
- self.detectionRangeLabel.setText(str(meter_to_nm(target.detection_range)) + " nm")
- self.seadTargetInfoView.setTarget(target)
-
- def init_ui(self):
- layout = QVBoxLayout()
-
- wpt_layout = QHBoxLayout()
- wpt_layout.addWidget(QLabel("SEAD/DEAD target : "))
- wpt_layout.addStretch()
- wpt_layout.addWidget(self.tgt_selection_box, alignment=Qt.AlignRight)
-
- distThreatBox = QGroupBox("Infos :")
- threatLayout = QVBoxLayout()
-
- distToTarget = QHBoxLayout()
- distToTarget.addWidget(QLabel("Distance to site : "))
- distToTarget.addStretch()
- distToTarget.addWidget(self.distanceToTargetLabel, alignment=Qt.AlignRight)
-
- threatRangeLayout = QHBoxLayout()
- threatRangeLayout.addWidget(QLabel("Site threat range : "))
- threatRangeLayout.addStretch()
- threatRangeLayout.addWidget(self.threatRangeLabel, alignment=Qt.AlignRight)
-
- detectionRangeLayout = QHBoxLayout()
- detectionRangeLayout.addWidget(QLabel("Site radar detection range: "))
- detectionRangeLayout.addStretch()
- detectionRangeLayout.addWidget(self.detectionRangeLabel, alignment=Qt.AlignRight)
-
- threatLayout.addLayout(distToTarget)
- threatLayout.addLayout(threatRangeLayout)
- threatLayout.addLayout(detectionRangeLayout)
- distThreatBox.setLayout(threatLayout)
-
- layout.addLayout(wpt_layout)
- layout.addWidget(self.seadTargetInfoView)
- layout.addWidget(distThreatBox)
- layout.addStretch()
- layout.addWidget(self.ok_button)
-
- self.setLayout(layout)
-
- def apply(self):
- target = self.tgt_selection_box.get_selected_target()
- self.flight.flight_type = FlightType.SEAD
- self.planner.populate_flight_plan(self.flight, target.radars)
- self.flight_waypoint_list.update_list()
- self.close()
-
-
-
-
diff --git a/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py
deleted file mode 100644
index c210208c..00000000
--- a/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py
+++ /dev/null
@@ -1,72 +0,0 @@
-from PySide2.QtGui import Qt
-from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QGroupBox
-
-from game import Game
-from game.utils import meter_to_nm
-from gen.ato import Package
-from gen.flights.flight import Flight, FlightType
-from qt_ui.widgets.combos.QStrikeTargetSelectionComboBox import QStrikeTargetSelectionComboBox
-from qt_ui.widgets.views.QStrikeTargetInfoView import QStrikeTargetInfoView
-from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
-
-
-class QSTRIKEMissionGenerator(QAbstractMissionGenerator):
-
- def __init__(self, game: Game, package: Package, flight: Flight,
- flight_waypoint_list) -> None:
- super(QSTRIKEMissionGenerator, self).__init__(
- game,
- package,
- flight,
- flight_waypoint_list,
- "Strike Generator"
- )
-
- self.tgt_selection_box = QStrikeTargetSelectionComboBox(self.game)
- self.tgt_selection_box.setMinimumWidth(200)
- self.tgt_selection_box.currentTextChanged.connect(self.on_selected_target_changed)
-
-
- self.distanceToTargetLabel = QLabel("0 nm")
- self.strike_infos = QStrikeTargetInfoView(None)
- self.init_ui()
- self.on_selected_target_changed()
-
- def on_selected_target_changed(self):
- target = self.tgt_selection_box.get_selected_target()
- self.distanceToTargetLabel.setText("~" + str(meter_to_nm(self.flight.from_cp.position.distance_to_point(target.location.position))) + " nm")
- self.strike_infos.setTarget(target)
-
- def init_ui(self):
- layout = QVBoxLayout()
-
- wpt_layout = QHBoxLayout()
- wpt_layout.addWidget(QLabel("Target : "))
- wpt_layout.addStretch()
- wpt_layout.addWidget(self.tgt_selection_box, alignment=Qt.AlignRight)
-
- distToTargetBox = QGroupBox("Infos :")
- distToTarget = QHBoxLayout()
- distToTarget.addWidget(QLabel("Distance to target : "))
- distToTarget.addStretch()
- distToTarget.addWidget(self.distanceToTargetLabel, alignment=Qt.AlignRight)
- distToTargetBox.setLayout(distToTarget)
-
- layout.addLayout(wpt_layout)
- layout.addWidget(self.strike_infos)
- layout.addWidget(distToTargetBox)
- layout.addStretch()
- layout.addWidget(self.ok_button)
-
- self.setLayout(layout)
-
- def apply(self):
- target = self.tgt_selection_box.get_selected_target()
- self.flight.flight_type = FlightType.STRIKE
- self.planner.populate_flight_plan(self.flight, target.location)
- self.flight_waypoint_list.update_list()
- self.close()
-
-
-
-
diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py
index 7561d639..2879c356 100644
--- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py
+++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py
@@ -1,16 +1,24 @@
+from typing import List, Optional
+
from PySide2.QtCore import Signal
-from PySide2.QtWidgets import QFrame, QGridLayout, QLabel, QPushButton, QVBoxLayout
+from PySide2.QtWidgets import (
+ QFrame,
+ QGridLayout,
+ QLabel,
+ QMessageBox,
+ QPushButton,
+ QVBoxLayout,
+)
from game import Game
from gen.ato import Package
-from gen.flights.flight import Flight
+from gen.flights.flight import Flight, FlightType
from gen.flights.flightplan import FlightPlanBuilder
-from qt_ui.windows.mission.flight.generator.QCAPMissionGenerator import QCAPMissionGenerator
-from qt_ui.windows.mission.flight.generator.QCASMissionGenerator import QCASMissionGenerator
-from qt_ui.windows.mission.flight.generator.QSEADMissionGenerator import QSEADMissionGenerator
-from qt_ui.windows.mission.flight.generator.QSTRIKEMissionGenerator import QSTRIKEMissionGenerator
-from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import QFlightWaypointList
-from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import QPredefinedWaypointSelectionWindow
+from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \
+ QFlightWaypointList
+from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import \
+ QPredefinedWaypointSelectionWindow
+from theater import ControlPoint, FrontLine
class QFlightWaypointTab(QFrame):
@@ -23,56 +31,68 @@ class QFlightWaypointTab(QFrame):
self.package = package
self.flight = flight
self.planner = FlightPlanBuilder(self.game, package, is_player=True)
+
+ self.flight_waypoint_list: Optional[QFlightWaypointList] = None
+ self.ascend_waypoint: Optional[QPushButton] = None
+ self.descend_waypoint: Optional[QPushButton] = None
+ self.rtb_waypoint: Optional[QPushButton] = None
+ self.delete_selected: Optional[QPushButton] = None
+ self.open_fast_waypoint_button: Optional[QPushButton] = None
+ self.recreate_buttons: List[QPushButton] = []
self.init_ui()
def init_ui(self):
layout = QGridLayout()
- rlayout = QVBoxLayout()
+
self.flight_waypoint_list = QFlightWaypointList(self.flight)
- self.open_fast_waypoint_button = QPushButton("Add Waypoint")
- self.open_fast_waypoint_button.clicked.connect(self.on_fast_waypoint)
-
- self.cas_generator = QPushButton("Gen. CAS")
- self.cas_generator.clicked.connect(self.on_cas_generator)
-
- self.cap_generator = QPushButton("Gen. CAP")
- self.cap_generator.clicked.connect(self.on_cap_generator)
-
- self.sead_generator = QPushButton("Gen. SEAD/DEAD")
- self.sead_generator.clicked.connect(self.on_sead_generator)
-
- self.strike_generator = QPushButton("Gen. STRIKE")
- self.strike_generator.clicked.connect(self.on_strike_generator)
-
- self.rtb_waypoint = QPushButton("Add RTB Waypoint")
- self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint)
-
- self.ascend_waypoint = QPushButton("Add Ascend Waypoint")
- self.ascend_waypoint.clicked.connect(self.on_ascend_waypoint)
-
- self.descend_waypoint = QPushButton("Add Descend Waypoint")
- self.descend_waypoint.clicked.connect(self.on_descend_waypoint)
-
- self.delete_selected = QPushButton("Delete Selected")
- self.delete_selected.clicked.connect(self.on_delete_waypoint)
-
layout.addWidget(self.flight_waypoint_list, 0, 0)
+ rlayout = QVBoxLayout()
+ layout.addLayout(rlayout, 0, 1)
+
rlayout.addWidget(QLabel("Generator :"))
rlayout.addWidget(QLabel("AI compatible"))
- rlayout.addWidget(self.cas_generator)
- rlayout.addWidget(self.cap_generator)
- rlayout.addWidget(self.sead_generator)
- rlayout.addWidget(self.strike_generator)
+
+ self.recreate_buttons.clear()
+ recreate_types = [
+ FlightType.CAS,
+ FlightType.CAP,
+ FlightType.SEAD,
+ FlightType.STRIKE
+ ]
+ for task in recreate_types:
+ def make_closure(arg):
+ def closure():
+ return self.confirm_recreate(arg)
+ return closure
+ button = QPushButton(f"Recreate as {task.name}")
+ button.clicked.connect(make_closure(task))
+ rlayout.addWidget(button)
+ self.recreate_buttons.append(button)
+
rlayout.addWidget(QLabel("Advanced : "))
rlayout.addWidget(QLabel("Do not use for AI flights"))
+
+ self.ascend_waypoint = QPushButton("Add Ascend Waypoint")
+ self.ascend_waypoint.clicked.connect(self.on_ascend_waypoint)
rlayout.addWidget(self.ascend_waypoint)
+
+ self.descend_waypoint = QPushButton("Add Descend Waypoint")
+ self.descend_waypoint.clicked.connect(self.on_descend_waypoint)
rlayout.addWidget(self.descend_waypoint)
+
+ self.rtb_waypoint = QPushButton("Add RTB Waypoint")
+ self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint)
rlayout.addWidget(self.rtb_waypoint)
- rlayout.addWidget(self.open_fast_waypoint_button)
+
+ self.delete_selected = QPushButton("Delete Selected")
+ self.delete_selected.clicked.connect(self.on_delete_waypoint)
rlayout.addWidget(self.delete_selected)
+
+ self.open_fast_waypoint_button = QPushButton("Add Waypoint")
+ self.open_fast_waypoint_button.clicked.connect(self.on_fast_waypoint)
+ rlayout.addWidget(self.open_fast_waypoint_button)
rlayout.addStretch()
- layout.addLayout(rlayout, 0, 1)
self.setLayout(layout)
def on_delete_waypoint(self):
@@ -105,45 +125,27 @@ class QFlightWaypointTab(QFrame):
self.flight_waypoint_list.update_list()
self.on_change()
- def on_cas_generator(self):
- self.subwindow = QCASMissionGenerator(
- self.game,
- self.package,
- self.flight,
- self.flight_waypoint_list
+ def confirm_recreate(self, task: FlightType) -> None:
+ result = QMessageBox.question(
+ self,
+ "Regenerate flight?",
+ ("Changing the flight type will reset its flight plan. Do you want "
+ "to continue?"),
+ QMessageBox.No,
+ QMessageBox.Yes
)
- self.subwindow.finished.connect(self.on_change)
- self.subwindow.show()
-
- def on_cap_generator(self):
- self.subwindow = QCAPMissionGenerator(
- self.game,
- self.package,
- self.flight,
- self.flight_waypoint_list
- )
- self.subwindow.finished.connect(self.on_change)
- self.subwindow.show()
-
- def on_sead_generator(self):
- self.subwindow = QSEADMissionGenerator(
- self.game,
- self.package,
- self.flight,
- self.flight_waypoint_list
- )
- self.subwindow.finished.connect(self.on_change)
- self.subwindow.show()
-
- def on_strike_generator(self):
- self.subwindow = QSTRIKEMissionGenerator(
- self.game,
- self.package,
- self.flight,
- self.flight_waypoint_list
- )
- self.subwindow.finished.connect(self.on_change)
- self.subwindow.show()
+ if result == QMessageBox.Yes:
+ # TODO: These should all be just CAP.
+ if task == FlightType.CAP:
+ if isinstance(self.package.target, FrontLine):
+ task = FlightType.TARCAP
+ elif isinstance(self.package.target, ControlPoint):
+ if self.package.target.is_fleet:
+ task = FlightType.BARCAP
+ self.flight.flight_type = task
+ self.planner.populate_flight_plan(self.flight)
+ self.flight_waypoint_list.update_list()
+ self.on_change()
def on_change(self):
self.flight_waypoint_list.update_list()