mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
313 lines
13 KiB
Python
313 lines
13 KiB
Python
from __future__ import unicode_literals, annotations
|
|
|
|
from datetime import datetime
|
|
from typing import List, Optional
|
|
|
|
from PySide6 import QtWidgets, QtGui
|
|
from PySide6.QtCore import Signal, QDate, QPoint, QItemSelectionModel, Qt, QModelIndex
|
|
from PySide6.QtGui import QStandardItem, QPixmap, QStandardItemModel
|
|
from PySide6.QtWidgets import (
|
|
QCheckBox,
|
|
QTextBrowser,
|
|
QTextEdit,
|
|
QLabel,
|
|
QListView,
|
|
QAbstractItemView,
|
|
)
|
|
|
|
from game.campaignloader import Campaign
|
|
from qt_ui.liberation_install import get_dcs_install_directory
|
|
from qt_ui.widgets.QLiberationCalendar import QLiberationCalendar
|
|
from qt_ui.windows.newgame.WizardPages.QFactionSelection import FactionSelection
|
|
from qt_ui.windows.newgame.jinja_env import jinja_env
|
|
|
|
"""
|
|
Possible time periods for new games
|
|
|
|
`Name`: daytime(day, month, year),
|
|
|
|
`Identifier` is the name that will appear in the menu
|
|
The object is a python datetime object
|
|
"""
|
|
TIME_PERIODS = {
|
|
"WW2 - Winter [1944]": datetime(1944, 1, 1),
|
|
"WW2 - Spring [1944]": datetime(1944, 4, 1),
|
|
"WW2 - Summer [1944]": datetime(1944, 6, 1),
|
|
"WW2 - Fall [1944]": datetime(1944, 10, 1),
|
|
"Early Cold War - Winter [1952]": datetime(1952, 1, 1),
|
|
"Early Cold War - Spring [1952]": datetime(1952, 4, 1),
|
|
"Early Cold War - Summer [1952]": datetime(1952, 6, 1),
|
|
"Early Cold War - Fall [1952]": datetime(1952, 10, 1),
|
|
"Cold War - Winter [1970]": datetime(1970, 1, 1),
|
|
"Cold War - Spring [1970]": datetime(1970, 4, 1),
|
|
"Cold War - Summer [1970]": datetime(1970, 6, 1),
|
|
"Cold War - Fall [1970]": datetime(1970, 10, 1),
|
|
"Late Cold War - Winter [1985]": datetime(1985, 1, 1),
|
|
"Late Cold War - Spring [1985]": datetime(1985, 4, 1),
|
|
"Late Cold War - Summer [1985]": datetime(1985, 6, 1),
|
|
"Late Cold War - Fall [1985]": datetime(1985, 10, 1),
|
|
"Gulf War - Winter [1990]": datetime(1990, 1, 1),
|
|
"Gulf War - Spring [1990]": datetime(1990, 4, 1),
|
|
"Gulf War - Summer [1990]": datetime(1990, 6, 1),
|
|
"Mid-90s - Winter [1995]": datetime(1995, 1, 1),
|
|
"Mid-90s - Spring [1995]": datetime(1995, 4, 1),
|
|
"Mid-90s - Summer [1995]": datetime(1995, 6, 1),
|
|
"Mid-90s - Fall [1995]": datetime(1995, 10, 1),
|
|
"Gulf War - Fall [1990]": datetime(1990, 10, 1),
|
|
"Modern - Winter [2010]": datetime(2010, 1, 1),
|
|
"Modern - Spring [2010]": datetime(2010, 4, 1),
|
|
"Modern - Summer [2010]": datetime(2010, 6, 1),
|
|
"Modern - Fall [2010]": datetime(2010, 10, 1),
|
|
"Georgian War [2008]": datetime(2008, 8, 7),
|
|
"Syrian War [2011]": datetime(2011, 3, 15),
|
|
"6 days war [1967]": datetime(1967, 6, 5),
|
|
"Yom Kippour War [1973]": datetime(1973, 10, 6),
|
|
"First Lebanon War [1982]": datetime(1982, 6, 6),
|
|
"Arab-Israeli War [1948]": datetime(1948, 5, 15),
|
|
}
|
|
|
|
|
|
class TheaterConfiguration(QtWidgets.QWizardPage):
|
|
campaign_selected = Signal(Campaign)
|
|
|
|
def __init__(
|
|
self,
|
|
campaigns: List[Campaign],
|
|
faction_selection: FactionSelection,
|
|
parent=None,
|
|
) -> None:
|
|
super().__init__(parent)
|
|
|
|
self.faction_selection = faction_selection
|
|
|
|
self.setTitle("Theater configuration")
|
|
self.setSubTitle("\nChoose a terrain and time period for this game.")
|
|
self.setPixmap(
|
|
QtWidgets.QWizard.WizardPixmap.LogoPixmap,
|
|
QtGui.QPixmap("./resources/ui/wizard/logo1.png"),
|
|
)
|
|
|
|
self.setPixmap(
|
|
QtWidgets.QWizard.WizardPixmap.WatermarkPixmap,
|
|
QtGui.QPixmap("./resources/ui/wizard/watermark3.png"),
|
|
)
|
|
|
|
# List of campaigns
|
|
show_incompatible_campaigns_checkbox = QCheckBox(
|
|
text="Show incompatible campaigns"
|
|
)
|
|
show_incompatible_campaigns_checkbox.setChecked(False)
|
|
self.campaignList = QCampaignList(
|
|
campaigns, show_incompatible_campaigns_checkbox.isChecked()
|
|
)
|
|
show_incompatible_campaigns_checkbox.toggled.connect(
|
|
lambda checked: self.campaignList.setup_content(show_incompatible=checked)
|
|
)
|
|
self.registerField("selectedCampaign", self.campaignList)
|
|
|
|
# Faction description
|
|
self.campaignMapDescription = QTextBrowser()
|
|
self.campaignMapDescription.setReadOnly(True)
|
|
self.campaignMapDescription.setOpenExternalLinks(True)
|
|
self.campaignMapDescription.setMaximumHeight(200)
|
|
|
|
self.performanceText = QTextEdit("")
|
|
self.performanceText.setReadOnly(True)
|
|
self.performanceText.setMaximumHeight(90)
|
|
|
|
# Campaign settings
|
|
mapSettingsGroup = QtWidgets.QGroupBox("Map Settings")
|
|
mapSettingsLayout = QtWidgets.QGridLayout()
|
|
self.invertMap = QtWidgets.QCheckBox()
|
|
self.invertMap.stateChanged.connect(self.on_invert_map)
|
|
self.registerField("invertMap", self.invertMap)
|
|
mapSettingsLayout.addWidget(QtWidgets.QLabel("Invert Map"), 0, 0)
|
|
mapSettingsLayout.addWidget(self.invertMap, 0, 1)
|
|
self.advanced_iads = QtWidgets.QCheckBox()
|
|
self.registerField("advanced_iads", self.advanced_iads)
|
|
self.iads_label = QtWidgets.QLabel("Advanced IADS (WIP)")
|
|
mapSettingsLayout.addWidget(self.iads_label, 1, 0)
|
|
mapSettingsLayout.addWidget(self.advanced_iads, 1, 1)
|
|
mapSettingsGroup.setLayout(mapSettingsLayout)
|
|
|
|
# Time Period
|
|
timeGroup = QtWidgets.QGroupBox("Time Period")
|
|
timePeriod = QtWidgets.QLabel("Start date :")
|
|
timePeriodSelect = QtWidgets.QComboBox()
|
|
timePeriodPresetLabel = QLabel("Use preset :")
|
|
timePeriodPreset = QtWidgets.QCheckBox()
|
|
timePeriodPreset.setChecked(True)
|
|
self.calendar = QLiberationCalendar()
|
|
self.calendar.setSelectedDate(QDate())
|
|
self.calendar.setDisabled(True)
|
|
|
|
def onTimePeriodChanged():
|
|
self.calendar.setSelectedDate(
|
|
list(TIME_PERIODS.values())[timePeriodSelect.currentIndex()]
|
|
)
|
|
|
|
timePeriodSelect.currentTextChanged.connect(onTimePeriodChanged)
|
|
|
|
for r in TIME_PERIODS:
|
|
timePeriodSelect.addItem(r)
|
|
timePeriod.setBuddy(timePeriodSelect)
|
|
timePeriodSelect.setCurrentIndex(21)
|
|
|
|
def onTimePeriodCheckboxChanged():
|
|
if timePeriodPreset.isChecked():
|
|
self.calendar.setDisabled(True)
|
|
timePeriodSelect.setDisabled(False)
|
|
onTimePeriodChanged()
|
|
else:
|
|
self.calendar.setDisabled(False)
|
|
timePeriodSelect.setDisabled(True)
|
|
|
|
timePeriodPreset.stateChanged.connect(onTimePeriodCheckboxChanged)
|
|
|
|
# Bind selection method for campaign selection
|
|
def on_campaign_selected():
|
|
template = jinja_env.get_template("campaigntemplate_EN.j2")
|
|
template_perf = jinja_env.get_template(
|
|
"campaign_performance_template_EN.j2"
|
|
)
|
|
campaign = self.campaignList.selected_campaign
|
|
self.setField("selectedCampaign", campaign)
|
|
if campaign is None:
|
|
self.campaignMapDescription.setText("No campaign selected")
|
|
self.performanceText.setText("No campaign selected")
|
|
return
|
|
|
|
self.campaignMapDescription.setText(template.render({"campaign": campaign}))
|
|
self.faction_selection.setDefaultFactions(campaign)
|
|
if self.invertMap.isChecked():
|
|
self.on_invert_map()
|
|
self.performanceText.setText(
|
|
template_perf.render({"performance": campaign.performance})
|
|
)
|
|
|
|
if (start_date := campaign.recommended_start_date) is not None:
|
|
self.calendar.setSelectedDate(
|
|
QDate(start_date.year, start_date.month, start_date.day)
|
|
)
|
|
timePeriodPreset.setChecked(False)
|
|
else:
|
|
timePeriodPreset.setChecked(True)
|
|
self.advanced_iads.setEnabled(campaign.advanced_iads)
|
|
self.iads_label.setEnabled(campaign.advanced_iads)
|
|
self.advanced_iads.setChecked(campaign.advanced_iads)
|
|
if not campaign.advanced_iads:
|
|
self.advanced_iads.setToolTip(
|
|
"Advanced IADS is not supported by this campaign"
|
|
)
|
|
else:
|
|
self.advanced_iads.setToolTip("Enable Advanced IADS")
|
|
|
|
self.campaign_selected.emit(campaign)
|
|
|
|
self.campaignList.selectionModel().setCurrentIndex(
|
|
self.campaignList.indexAt(QPoint(1, 1)),
|
|
QItemSelectionModel.SelectionFlag.Rows,
|
|
)
|
|
|
|
self.campaignList.selectionModel().selectionChanged.connect(
|
|
on_campaign_selected
|
|
)
|
|
on_campaign_selected()
|
|
|
|
docsText = QtWidgets.QLabel(
|
|
"<p>Want more campaigns? You can "
|
|
'<a href="https://github.com/dcs-retribution/dcs-retribution/wiki/Campaign-maintenance"><span style="color:#FFFFFF;">offer to help</span></a>, '
|
|
'<a href="https://github.com/dcs-retribution/dcs-retribution/wiki/Community-campaigns"><span style="color:#FFFFFF;">play a community campaign</span></a>, '
|
|
'or <a href="https://github.com/dcs-retribution/dcs-retribution/wiki/Custom-Campaigns"><span style="color:#FFFFFF;">create your own</span></a>.'
|
|
"</p>"
|
|
)
|
|
docsText.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
docsText.setOpenExternalLinks(True)
|
|
|
|
# Register fields
|
|
self.registerField("timePeriod", timePeriodSelect)
|
|
self.registerField("usePreset", timePeriodPreset)
|
|
|
|
timeGroupLayout = QtWidgets.QGridLayout()
|
|
timeGroupLayout.addWidget(timePeriodPresetLabel, 0, 0)
|
|
timeGroupLayout.addWidget(timePeriodPreset, 0, 1)
|
|
timeGroupLayout.addWidget(timePeriod, 1, 0)
|
|
timeGroupLayout.addWidget(timePeriodSelect, 1, 1)
|
|
timeGroupLayout.addWidget(self.calendar, 0, 2, 3, 1)
|
|
timeGroup.setLayout(timeGroupLayout)
|
|
|
|
layout = QtWidgets.QGridLayout()
|
|
layout.setColumnMinimumWidth(0, 20)
|
|
layout.addWidget(self.campaignList, 0, 0, 5, 1)
|
|
layout.addWidget(show_incompatible_campaigns_checkbox, 5, 0, 1, 1)
|
|
layout.addWidget(docsText, 6, 0, 1, 1)
|
|
layout.addWidget(self.campaignMapDescription, 0, 1, 1, 1)
|
|
layout.addWidget(self.performanceText, 1, 1, 1, 1)
|
|
layout.addWidget(mapSettingsGroup, 2, 1, 1, 1)
|
|
layout.addWidget(timeGroup, 3, 1, 3, 1)
|
|
self.setLayout(layout)
|
|
|
|
def on_invert_map(self) -> None:
|
|
blue = self.faction_selection.blueFactionSelect.currentIndex()
|
|
red = self.faction_selection.redFactionSelect.currentIndex()
|
|
self.faction_selection.blueFactionSelect.setCurrentIndex(red)
|
|
self.faction_selection.redFactionSelect.setCurrentIndex(blue)
|
|
self.faction_selection.updateUnitRecap()
|
|
|
|
|
|
class QCampaignItem(QStandardItem):
|
|
def __init__(self, campaign: Campaign) -> None:
|
|
super(QCampaignItem, self).__init__()
|
|
self.setData(campaign, QCampaignList.CampaignRole)
|
|
|
|
# Define terrain icon path from the DCS installation directory by default
|
|
dcs_path = get_dcs_install_directory()
|
|
icon_path = dcs_path / campaign.menu_thumbnail_dcs_relative_path
|
|
|
|
# If the path does not exist (user does not have the terrain installed),
|
|
# use the old icons as fallback to avoid an ugly campaign list with missing icons
|
|
if not icon_path.exists():
|
|
icon_path = campaign.fallback_icon_path
|
|
|
|
self.setIcon(QtGui.QIcon(QPixmap(str(icon_path))))
|
|
self.setEditable(False)
|
|
if campaign.is_compatible:
|
|
name = campaign.name
|
|
else:
|
|
name = f"[INCOMPATIBLE] {campaign.name}"
|
|
self.setText(name)
|
|
|
|
|
|
class QCampaignList(QListView):
|
|
CampaignRole = Qt.ItemDataRole.UserRole
|
|
|
|
def __init__(self, campaigns: list[Campaign], show_incompatible: bool) -> None:
|
|
super(QCampaignList, self).__init__()
|
|
self.campaign_model = QStandardItemModel(self)
|
|
self.setModel(self.campaign_model)
|
|
self.setMinimumWidth(250)
|
|
self.setMinimumHeight(350)
|
|
self.campaigns = campaigns
|
|
self.setSelectionBehavior(QAbstractItemView.SelectionBehavior.SelectItems)
|
|
self.setup_content(show_incompatible)
|
|
|
|
@property
|
|
def selected_campaign(self) -> Optional[Campaign]:
|
|
return self.currentIndex().data(QCampaignList.CampaignRole)
|
|
|
|
def setup_content(self, show_incompatible: bool) -> None:
|
|
self.selectionModel().blockSignals(True)
|
|
try:
|
|
self.campaign_model.clear()
|
|
for campaign in self.campaigns:
|
|
if show_incompatible or campaign.is_compatible:
|
|
item = QCampaignItem(campaign)
|
|
self.campaign_model.appendRow(item)
|
|
finally:
|
|
self.selectionModel().blockSignals(False)
|
|
|
|
self.selectionModel().setCurrentIndex(
|
|
self.campaign_model.index(0, 0, QModelIndex()),
|
|
QItemSelectionModel.SelectionFlag.Select,
|
|
)
|