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.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 game import Game
from gen.ato import Package 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 gen.flights.flightplan import FlightPlanBuilder
from qt_ui.windows.mission.flight.generator.QCAPMissionGenerator import QCAPMissionGenerator from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import \
from qt_ui.windows.mission.flight.generator.QCASMissionGenerator import QCASMissionGenerator QFlightWaypointList
from qt_ui.windows.mission.flight.generator.QSEADMissionGenerator import QSEADMissionGenerator from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import \
from qt_ui.windows.mission.flight.generator.QSTRIKEMissionGenerator import QSTRIKEMissionGenerator QPredefinedWaypointSelectionWindow
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import QFlightWaypointList from theater import ControlPoint, FrontLine
from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import QPredefinedWaypointSelectionWindow
class QFlightWaypointTab(QFrame): class QFlightWaypointTab(QFrame):
@ -23,56 +31,68 @@ class QFlightWaypointTab(QFrame):
self.package = package self.package = package
self.flight = flight self.flight = flight
self.planner = FlightPlanBuilder(self.game, package, is_player=True) 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() self.init_ui()
def init_ui(self): def init_ui(self):
layout = QGridLayout() layout = QGridLayout()
rlayout = QVBoxLayout()
self.flight_waypoint_list = QFlightWaypointList(self.flight) 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) layout.addWidget(self.flight_waypoint_list, 0, 0)
rlayout = QVBoxLayout()
layout.addLayout(rlayout, 0, 1)
rlayout.addWidget(QLabel("<strong>Generator :</strong>")) rlayout.addWidget(QLabel("<strong>Generator :</strong>"))
rlayout.addWidget(QLabel("<small>AI compatible</small>")) rlayout.addWidget(QLabel("<small>AI compatible</small>"))
rlayout.addWidget(self.cas_generator)
rlayout.addWidget(self.cap_generator) self.recreate_buttons.clear()
rlayout.addWidget(self.sead_generator) recreate_types = [
rlayout.addWidget(self.strike_generator) 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("<strong>Advanced : </strong>"))
rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>")) 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) 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) 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.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) 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() rlayout.addStretch()
layout.addLayout(rlayout, 0, 1)
self.setLayout(layout) self.setLayout(layout)
def on_delete_waypoint(self): def on_delete_waypoint(self):
@ -105,45 +125,27 @@ class QFlightWaypointTab(QFrame):
self.flight_waypoint_list.update_list() self.flight_waypoint_list.update_list()
self.on_change() self.on_change()
def on_cas_generator(self): def confirm_recreate(self, task: FlightType) -> None:
self.subwindow = QCASMissionGenerator( result = QMessageBox.question(
self.game, self,
self.package, "Regenerate flight?",
self.flight, ("Changing the flight type will reset its flight plan. Do you want "
self.flight_waypoint_list "to continue?"),
QMessageBox.No,
QMessageBox.Yes
) )
self.subwindow.finished.connect(self.on_change) if result == QMessageBox.Yes:
self.subwindow.show() # TODO: These should all be just CAP.
if task == FlightType.CAP:
def on_cap_generator(self): if isinstance(self.package.target, FrontLine):
self.subwindow = QCAPMissionGenerator( task = FlightType.TARCAP
self.game, elif isinstance(self.package.target, ControlPoint):
self.package, if self.package.target.is_fleet:
self.flight, task = FlightType.BARCAP
self.flight_waypoint_list self.flight.flight_type = task
) self.planner.populate_flight_plan(self.flight)
self.subwindow.finished.connect(self.on_change) self.flight_waypoint_list.update_list()
self.subwindow.show() self.on_change()
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()
def on_change(self): def on_change(self):
self.flight_waypoint_list.update_list() self.flight_waypoint_list.update_list()