Update the waypoint builder UI.

Changing targets doesn't make sense now that flights belong to a
package. Change all the "generate" dialogs to simply confirm dialogs
to make sure the user is okay with us clobbering the flight plan.
This commit is contained in:
Dan Albert 2020-09-29 23:29:30 -07:00
parent 6ce82be46b
commit b13711ddef
6 changed files with 82 additions and 433 deletions

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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("<strong>Generator :</strong>"))
rlayout.addWidget(QLabel("<small>AI compatible</small>"))
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("<strong>Advanced : </strong>"))
rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>"))
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()