diff --git a/qt_ui/windows/mission/flight/QFlightPlanner.py b/qt_ui/windows/mission/flight/QFlightPlanner.py index 55a53a9c..59c2e406 100644 --- a/qt_ui/windows/mission/flight/QFlightPlanner.py +++ b/qt_ui/windows/mission/flight/QFlightPlanner.py @@ -14,7 +14,7 @@ class QFlightPlanner(QTabWidget): if flight: self.general_settings_tab = QGeneralFlightSettingsTab(flight, game) self.payload_tab = QFlightPayloadTab(flight, game) - self.waypoint_tab = QFlightWaypointTab(flight) + self.waypoint_tab = QFlightWaypointTab(game, flight) self.addTab(self.general_settings_tab, "General Flight settings") self.addTab(self.payload_tab, "Payload") self.addTab(self.waypoint_tab, "Waypoints") diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py new file mode 100644 index 00000000..b28d082a --- /dev/null +++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointInfoBox.py @@ -0,0 +1,66 @@ +from PySide2.QtWidgets import QGroupBox, QGridLayout, QLabel, QHBoxLayout, QVBoxLayout + +from gen.flights.flight import FlightWaypoint + + +class QFlightWaypointInfoBox(QGroupBox): + + def __init__(self, flight_wpt:FlightWaypoint): + super(QFlightWaypointInfoBox, self).__init__("Waypoint") + self.flight_wpt = flight_wpt + if flight_wpt is None: + self.flight_wpt = FlightWaypoint(0,0,0) + self.x_position_label = QLabel(str(self.flight_wpt.x)) + self.y_position_label = QLabel(str(self.flight_wpt.y)) + self.alt_label = QLabel(str(self.flight_wpt.alt)) + self.name_label = QLabel(str(self.flight_wpt.name)) + self.desc_label = QLabel(str(self.flight_wpt.description)) + self.init_ui() + + def init_ui(self): + + layout = QVBoxLayout() + + x_pos_layout = QHBoxLayout() + x_pos_layout.addWidget(QLabel("X : ")) + x_pos_layout.addWidget(self.x_position_label) + x_pos_layout.addStretch() + + y_pos_layout = QHBoxLayout() + y_pos_layout.addWidget(QLabel("Y : ")) + y_pos_layout.addWidget(self.y_position_label) + y_pos_layout.addStretch() + + alt_layout = QHBoxLayout() + alt_layout.addWidget(QLabel("Alt : ")) + alt_layout.addWidget(self.alt_label) + alt_layout.addStretch() + + name_layout = QHBoxLayout() + name_layout.addWidget(QLabel("Name : ")) + name_layout.addWidget(self.name_label) + name_layout.addStretch() + + desc_layout = QHBoxLayout() + desc_layout.addWidget(QLabel("Description : ")) + desc_layout.addWidget(self.desc_label) + desc_layout.addStretch() + + layout.addLayout(name_layout) + layout.addLayout(x_pos_layout) + layout.addLayout(y_pos_layout) + layout.addLayout(alt_layout) + layout.addLayout(desc_layout) + + self.setLayout(layout) + + def set_flight_waypoint(self, flight_wpt:FlightWaypoint): + self.flight_wpt = flight_wpt + if flight_wpt is None: + self.flight_wpt = FlightWaypoint(0,0,0) + self.x_position_label.setText(str(self.flight_wpt.x)) + self.y_position_label.setText(str(self.flight_wpt.y)) + self.alt_label.setText(str(self.flight_wpt.alt)) + self.name_label.setText(str(self.flight_wpt.name)) + self.desc_label.setText(str(self.flight_wpt.description)) + self.setTitle(self.flight_wpt.name) diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py index dff7849d..64777d49 100644 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py +++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointList.py @@ -1,3 +1,4 @@ +from PySide2.QtCore import QItemSelectionModel, QPoint from PySide2.QtGui import QStandardItemModel from PySide2.QtWidgets import QListView @@ -13,8 +14,21 @@ class QFlightWaypointList(QListView): self.setModel(self.model) self.flight = flight - takeoff = FlightWaypoint(flight.from_cp.position.x, flight.from_cp.position.y, 0) + if len(self.flight.points) > 0: + self.selectedPoint = self.flight.points[0] + self.update_list() + + self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select) + self.selectionModel().selectionChanged.connect(self.on_waypoint_selected_changed) + + def on_waypoint_selected_changed(self): + index = self.selectionModel().currentIndex().row() + + def update_list(self): + self.model.clear() + takeoff = FlightWaypoint(self.flight.from_cp.position.x, self.flight.from_cp.position.y, 0) takeoff.description = "Take Off" self.model.appendRow(QWaypointItem(takeoff)) for i, point in enumerate(self.flight.points): - self.model.appendRow(QWaypointItem(point)) \ No newline at end of file + self.model.appendRow(QWaypointItem(point)) + self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select) \ No newline at end of file diff --git a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py index 42498c9a..06fc85a6 100644 --- a/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py +++ b/qt_ui/windows/mission/flight/waypoints/QFlightWaypointTab.py @@ -1,18 +1,41 @@ -from PySide2.QtWidgets import QFrame, QGridLayout, QLabel +from PySide2.QtWidgets import QFrame, QGridLayout, QLabel, QPushButton, QVBoxLayout from gen.flights.flight import Flight from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import QFlightWaypointList - +from qt_ui.windows.mission.flight.waypoints.QWaypointSelectionWindow import QWaypointSelectionWindow +from game import Game class QFlightWaypointTab(QFrame): - def __init__(self, flight: Flight): + def __init__(self, game: Game, flight: Flight): super(QFlightWaypointTab, self).__init__() self.flight = flight + self.game = game self.init_ui() def init_ui(self): layout = QGridLayout() + rlayout = QVBoxLayout() self.flight_waypoint_list = QFlightWaypointList(self.flight) - layout.addWidget(self.flight_waypoint_list) + self.open_fast_waypoint_button = QPushButton("Add Waypoint") + self.open_fast_waypoint_button.clicked.connect(self.on_fast_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.addWidget(self.open_fast_waypoint_button) + rlayout.addWidget(self.delete_selected) + rlayout.addStretch() + layout.addLayout(rlayout, 0, 1) self.setLayout(layout) + + def on_delete_waypoint(self): + wpt = self.flight_waypoint_list.selectionModel().currentIndex().row() + if wpt > 0: + del self.flight.points[wpt-1] + self.flight_waypoint_list.update_list() + + def on_fast_waypoint(self): + self.subwindow = QWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list) + self.subwindow.show() \ No newline at end of file diff --git a/qt_ui/windows/mission/flight/waypoints/QWaypointSelectionWindow.py b/qt_ui/windows/mission/flight/waypoints/QWaypointSelectionWindow.py new file mode 100644 index 00000000..c6ab2ab6 --- /dev/null +++ b/qt_ui/windows/mission/flight/waypoints/QWaypointSelectionWindow.py @@ -0,0 +1,150 @@ +from PySide2.QtCore import Qt +from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QComboBox, QHBoxLayout, QVBoxLayout, QPushButton +from dcs import Point + +from game import Game +from gen.flights.flight import Flight, FlightWaypoint +from qt_ui.uiconstants import EVENT_ICONS +from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox + +PREDEFINED_WAYPOINT_CATEGORIES = [ + "Frontline (CAS AREA)", + "Building", + "Units", + "Airbase" +] + + +class QWaypointSelectionWindow(QDialog): + + + def __init__(self, game: Game, flight: Flight, flight_waypoint_list): + super(QWaypointSelectionWindow, self).__init__() + self.game = game + self.flight = flight + self.setWindowFlags(Qt.WindowStaysOnTopHint) + self.setMinimumSize(450, 350) + self.setModal(True) + self.setWindowTitle("Add Predefined Waypoint") + self.setWindowIcon(EVENT_ICONS["strike"]) + self.flight_waypoint_list = flight_waypoint_list + + self.selected_cp = self.game.theater.controlpoints[0] + self.cp_selection_box = QComboBox() + for cp in self.game.theater.controlpoints: + self.cp_selection_box.addItem(cp.name) + + self.wpt_type_selection_box = QComboBox() + for cat in PREDEFINED_WAYPOINT_CATEGORIES: + self.wpt_type_selection_box.addItem(cat) + + self.cp_selection_box.currentTextChanged.connect(self.on_parameters_changed) + self.wpt_type_selection_box.currentTextChanged.connect(self.on_parameters_changed) + + self.wpt_selection_box = QComboBox() + self.wpt_selection_box.setMinimumWidth(200) + self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed) + + self.selected_waypoint = None + self.wpt_info = QFlightWaypointInfoBox(self.selected_waypoint) + + self.add_button = QPushButton("Add") + self.add_button.clicked.connect(self.add_waypoint) + + self.init_ui() + self.on_parameters_changed() + print("DONE") + + + def init_ui(self): + layout = QVBoxLayout() + + near_layout = QHBoxLayout() + near_layout.addWidget(QLabel("Near : ")) + near_layout.addWidget(self.cp_selection_box) + near_layout.addStretch() + + type_layout = QHBoxLayout() + type_layout.addWidget(QLabel("Type : ")) + type_layout.addWidget(self.wpt_type_selection_box) + type_layout.addStretch() + + wpt_layout = QHBoxLayout() + wpt_layout.addWidget(QLabel("Waypoint : ")) + wpt_layout.addWidget(self.wpt_selection_box) + wpt_layout.addStretch() + + layout.addLayout(near_layout) + layout.addLayout(type_layout) + layout.addLayout(wpt_layout) + layout.addWidget(self.wpt_info) + layout.addStretch() + layout.addWidget(self.add_button) + + self.setLayout(layout) + + def on_select_wpt_changed(self): + self.selected_waypoint = self.wpt_selection_box.currentData() + self.wpt_info.set_flight_waypoint(self.selected_waypoint) + if self.selected_waypoint is None: + self.add_button.setDisabled(True) + else: + self.add_button.setDisabled(False) + + def on_parameters_changed(self): + self.wpt_selection_box.clear() + + select_cp_text = self.cp_selection_box.currentText() + select_cp = None + for cp in self.game.theater.controlpoints: + if cp.name == select_cp_text: + select_cp = cp + break + if select_cp is not None: + selected_wpt_type = self.wpt_type_selection_box.currentText() + + if selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[0]: # CAS + enemy_cp = [cp for cp in select_cp.connected_points if cp.captured != select_cp.captured] + for ecp in enemy_cp: + wpt = FlightWaypoint((select_cp.position.x + ecp.position.x)/2, (select_cp.position.y + ecp.position.y)/2, 800) + wpt.name = "Frontline with " + ecp.name + " [CAS]" + wpt.description = "Provide CAS" + self.wpt_selection_box.addItem(wpt.name, userData=wpt) + if len(enemy_cp) == 0: + self.wpt_selection_box.addItem("None", userData=None) + elif selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[1]: # Building + for ground_object in select_cp.ground_objects: + if not ground_object.is_dead and not ground_object.dcs_identifier == "AA": + wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0) + wpt.name = ground_object.category + " #" + str(ground_object.object_id) + " @ site #" + str(ground_object.group_id) + wpt.description = "Ennemy Building" + self.wpt_selection_box.addItem(wpt.name, userData=wpt) + elif selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[2]: # Known units position + for ground_object in select_cp.ground_objects: + if not ground_object.is_dead and ground_object.dcs_identifier == "AA": + for g in ground_object.groups: + for u in g.units: + wpt = FlightWaypoint(ground_object.position.x, ground_object.position.y, 0) + wpt.name = u.type + " @ site #" + str(ground_object.group_id) + wpt.description = "Ennemy unit to be destroyed" + self.wpt_selection_box.addItem(wpt.name, userData=wpt) + elif selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[3]: # CAS + wpt = FlightWaypoint(select_cp.position.x, select_cp.position.y, 0) + wpt.name = select_cp.name + wpt.description = "Position of " + select_cp.name + self.wpt_selection_box.addItem("Airbase", userData=wpt) + else: + self.wpt_selection_box.addItem("None", userData=None) + else: + self.wpt_selection_box.addItem("None", userData=None) + + self.wpt_selection_box.setCurrentIndex(0) + + def add_waypoint(self): + if not self.selected_waypoint is None: + self.flight.points.append(self.selected_waypoint) + self.flight_waypoint_list.update_list() + self.close() + + +