mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Configurable RF/TCN/ICLS/LINK4 with UI feedback
Resolves #70 Freq/Channel will turn orange when double booked. Freq will turn red if GUARD freq was assigned.
This commit is contained in:
@@ -17,9 +17,13 @@ from game.ato.flight import Flight
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.ato.package import Package
|
||||
from game.game import Game
|
||||
from game.radio.RadioFrequencyContainer import RadioFrequencyContainer
|
||||
from game.radio.radios import RadioFrequency
|
||||
from game.radio.tacan import TacanChannel
|
||||
from game.server import EventStream
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.squadrons.squadron import Pilot, Squadron
|
||||
from game.theater import NavalControlPoint
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.transfers import PendingTransfers, TransferOrder
|
||||
from qt_ui.simcontroller import SimController
|
||||
@@ -179,6 +183,8 @@ class PackageModel(QAbstractListModel):
|
||||
self.package.remove_flight(flight)
|
||||
self.endRemoveRows()
|
||||
self.update_tot()
|
||||
self.game_model.release_freq(flight.frequency)
|
||||
self.game_model.release_tacan(flight.tacan)
|
||||
|
||||
def flight_at_index(self, index: QModelIndex) -> Flight:
|
||||
"""Returns the flight located at the given index."""
|
||||
@@ -294,6 +300,7 @@ class AtoModel(QAbstractListModel):
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.client_slots_changed.emit()
|
||||
self.on_packages_changed()
|
||||
self.release_comms_for_package(package)
|
||||
|
||||
def on_packages_changed(self) -> None:
|
||||
if self.game is not None:
|
||||
@@ -342,6 +349,12 @@ class AtoModel(QAbstractListModel):
|
||||
def on_sim_update(self, _events: GameUpdateEvents) -> None:
|
||||
self.dataChanged.emit(self.index(0), self.index(self.rowCount()))
|
||||
|
||||
def release_comms_for_package(self, package: Package):
|
||||
self.game_model.release_freq(package.frequency)
|
||||
for f in package.flights:
|
||||
self.game_model.release_freq(f.frequency)
|
||||
self.game_model.release_tacan(f.tacan)
|
||||
|
||||
|
||||
class TransferModel(QAbstractListModel):
|
||||
"""The model for a ground unit transfer."""
|
||||
@@ -532,6 +545,12 @@ class GameModel:
|
||||
self.ato_model = AtoModel(self, self.game.blue.ato)
|
||||
self.red_ato_model = AtoModel(self, self.game.red.ato)
|
||||
|
||||
# For UI purposes
|
||||
self.allocated_freqs: list[RadioFrequency] = list()
|
||||
self.allocated_tacan: list[TacanChannel] = list()
|
||||
self.allocated_icls: list[int] = list()
|
||||
self.init_comms_registry()
|
||||
|
||||
def ato_model_for(self, player: bool) -> AtoModel:
|
||||
if player:
|
||||
return self.ato_model
|
||||
@@ -553,3 +572,43 @@ class GameModel:
|
||||
if self.game is None:
|
||||
raise RuntimeError("GameModel has no Game set")
|
||||
return self.game
|
||||
|
||||
def init_comms_registry(self) -> None:
|
||||
if self.game is None:
|
||||
return
|
||||
allocated_freqs = {None}
|
||||
allocated_tacan = {None}
|
||||
allocated_icls = {None}
|
||||
for p in self.ato_model.ato.packages:
|
||||
allocated_freqs.add(p.frequency)
|
||||
for f in p.flights:
|
||||
allocated_freqs.add(f.frequency)
|
||||
allocated_tacan.add(f.tacan)
|
||||
for cp in self.game.theater.control_points_for(True):
|
||||
if isinstance(cp, NavalControlPoint):
|
||||
allocated_freqs.add(cp.frequency)
|
||||
allocated_freqs.add(cp.link4)
|
||||
allocated_tacan.add(cp.tacan)
|
||||
allocated_icls.add(cp.icls_channel)
|
||||
elif isinstance(cp, RadioFrequencyContainer):
|
||||
allocated_freqs.add(cp.frequency)
|
||||
allocated_freqs.remove(None)
|
||||
allocated_tacan.remove(None)
|
||||
allocated_icls.remove(None)
|
||||
self.allocated_freqs = list(allocated_freqs)
|
||||
self.allocated_tacan = list(allocated_tacan)
|
||||
self.allocated_icls = list(allocated_icls)
|
||||
|
||||
def release_freq(self, freq: RadioFrequency):
|
||||
if freq:
|
||||
try:
|
||||
self.allocated_freqs.remove(freq)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def release_tacan(self, tacan: TacanChannel):
|
||||
if tacan:
|
||||
try:
|
||||
self.allocated_tacan.remove(tacan)
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
101
qt_ui/widgets/QFrequencyWidget.py
Normal file
101
qt_ui/widgets/QFrequencyWidget.py
Normal file
@@ -0,0 +1,101 @@
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import (
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game.ato import Flight
|
||||
from game.radio.RadioFrequencyContainer import RadioFrequencyContainer
|
||||
from game.radio.radios import RadioFrequency, RadioRange, MHz, kHz
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.QRadioFrequencyDialog import QRadioFrequencyDialog
|
||||
|
||||
|
||||
class QFrequencyWidget(QWidget):
|
||||
|
||||
freq_changed = Signal(QWidget)
|
||||
|
||||
def __init__(
|
||||
self, container: RadioFrequencyContainer, game_model: GameModel
|
||||
) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.ct = container
|
||||
self.gm = game_model
|
||||
|
||||
columns = QHBoxLayout()
|
||||
self.setLayout(columns)
|
||||
|
||||
self.freq = QLabel(self._get_label_text())
|
||||
self.check_freq()
|
||||
columns.addWidget(self.freq)
|
||||
columns.addStretch()
|
||||
|
||||
self.set_freq_btn = QPushButton("Set FREQ")
|
||||
self.set_freq_btn.setProperty("class", "comms")
|
||||
self.set_freq_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.set_freq_btn)
|
||||
self.set_freq_btn.clicked.connect(self.open_freq_dialog)
|
||||
|
||||
self.reset_freq_btn = QPushButton("Reset FREQ")
|
||||
self.reset_freq_btn.setProperty("class", "btn-danger comms")
|
||||
self.reset_freq_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.reset_freq_btn)
|
||||
self.reset_freq_btn.clicked.connect(self.reset_freq)
|
||||
|
||||
def _get_label_text(self) -> str:
|
||||
freq = "AUTO" if self.ct.frequency is None else self.ct.frequency
|
||||
return f"<b>FREQ: {freq}</b>"
|
||||
|
||||
def open_freq_dialog(self) -> None:
|
||||
range = RadioRange(MHz(30), MHz(400), kHz(25))
|
||||
if isinstance(self.ct, Flight):
|
||||
if self.ct.unit_type.intra_flight_radio is not None:
|
||||
range = self.ct.unit_type.intra_flight_radio.ranges[0]
|
||||
self.frequency_dialog = QRadioFrequencyDialog(self, self.ct, range)
|
||||
self.frequency_dialog.accepted.connect(self.assign_frequency)
|
||||
self.frequency_dialog.show()
|
||||
|
||||
def assign_frequency(self) -> None:
|
||||
hz = round(self.frequency_dialog.frequency_input.value() * 10**6)
|
||||
self._try_remove()
|
||||
self.ct.frequency = RadioFrequency(hertz=hz)
|
||||
self.gm.allocated_freqs.append(self.ct.frequency)
|
||||
self.freq.setText(self._get_label_text())
|
||||
self.check_freq()
|
||||
self.freq_changed.emit(self)
|
||||
|
||||
def reset_freq(self) -> None:
|
||||
self._try_remove()
|
||||
self.ct.frequency = None
|
||||
self.freq.setText(self._get_label_text())
|
||||
self._reset_color_and_tooltip()
|
||||
self.freq_changed.emit(self)
|
||||
|
||||
def check_freq(self) -> None:
|
||||
if self.ct.frequency is None:
|
||||
return
|
||||
if self.gm.allocated_freqs.count(self.ct.frequency) > 1:
|
||||
self.freq.setStyleSheet("color: orange")
|
||||
self.freq.setToolTip(
|
||||
"Double booked frequency, verify that this was your intention."
|
||||
)
|
||||
elif self.gm.allocated_freqs.count(self.ct.frequency) == 1:
|
||||
self._reset_color_and_tooltip()
|
||||
if self.ct.frequency == MHz(243) or self.ct.frequency == MHz(121, 500):
|
||||
self.freq.setStyleSheet("color: red")
|
||||
self.freq.setToolTip(
|
||||
"GUARD Freq. was assigned, verify that this was your intention."
|
||||
)
|
||||
|
||||
def _reset_color_and_tooltip(self):
|
||||
self.freq.setStyleSheet("color: white")
|
||||
self.freq.setToolTip(None)
|
||||
|
||||
def _try_remove(self) -> None:
|
||||
try:
|
||||
self.gm.allocated_freqs.remove(self.ct.frequency)
|
||||
except ValueError:
|
||||
pass
|
||||
86
qt_ui/widgets/QICLSWidget.py
Normal file
86
qt_ui/widgets/QICLSWidget.py
Normal file
@@ -0,0 +1,86 @@
|
||||
from PySide2.QtWidgets import (
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game.radio.ICLSContainer import ICLSContainer
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.QICLSDialog import QICLSDialog
|
||||
|
||||
|
||||
class QICLSWidget(QWidget):
|
||||
def __init__(self, container: ICLSContainer, game_model: GameModel) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.ct = container
|
||||
self.gm = game_model
|
||||
|
||||
columns = QHBoxLayout()
|
||||
self.setLayout(columns)
|
||||
|
||||
self.channel = QLabel(self._get_label_text())
|
||||
self.check_channel()
|
||||
columns.addWidget(self.channel)
|
||||
columns.addStretch()
|
||||
|
||||
self.set_icls_btn = QPushButton("Set ICLS")
|
||||
self.set_icls_btn.setProperty("class", "comms")
|
||||
self.set_icls_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.set_icls_btn)
|
||||
self.set_icls_btn.clicked.connect(self.open_icls_dialog)
|
||||
|
||||
self.reset_icls_btn = QPushButton("Reset ICLS")
|
||||
self.reset_icls_btn.setProperty("class", "btn-danger comms")
|
||||
self.reset_icls_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.reset_icls_btn)
|
||||
self.reset_icls_btn.clicked.connect(self.reset_icls)
|
||||
|
||||
def _get_label_text(self) -> str:
|
||||
c = "AUTO" if self.ct.icls_channel is None else self.ct.icls_channel
|
||||
cs = self.ct.icls_name
|
||||
cs = "" if cs is None else f" ({cs})"
|
||||
return f"<b>ICLS: {c}{cs}</b>"
|
||||
|
||||
def open_icls_dialog(self) -> None:
|
||||
self.icls_dialog = QICLSDialog(self, self.ct)
|
||||
self.icls_dialog.accepted.connect(self.assign_icls)
|
||||
self.icls_dialog.show()
|
||||
|
||||
def assign_icls(self) -> None:
|
||||
self._try_remove()
|
||||
self.ct.icls_channel = self.icls_dialog.icls_input.value()
|
||||
self.gm.allocated_icls.append(self.ct.icls_channel)
|
||||
if cs := self.icls_dialog.callsign_input.text():
|
||||
self.ct.icls_name = cs.upper()
|
||||
self.channel.setText(self._get_label_text())
|
||||
self.check_channel()
|
||||
|
||||
def reset_icls(self) -> None:
|
||||
self._try_remove()
|
||||
self.ct.icls_channel = None
|
||||
self.ct.icls_name = None
|
||||
self.channel.setText(self._get_label_text())
|
||||
self._reset_color_and_tooltip()
|
||||
|
||||
def check_channel(self) -> None:
|
||||
if self.ct.icls_channel is None:
|
||||
return
|
||||
if self.gm.allocated_icls.count(self.ct.icls_channel) > 1:
|
||||
self.channel.setStyleSheet("color: orange")
|
||||
self.channel.setToolTip(
|
||||
"Double booked ICLS channel, verify that this was your intention."
|
||||
)
|
||||
elif self.gm.allocated_icls.count(self.ct.icls_channel) == 1:
|
||||
self._reset_color_and_tooltip()
|
||||
|
||||
def _reset_color_and_tooltip(self):
|
||||
self.channel.setStyleSheet("color: white")
|
||||
self.channel.setToolTip(None)
|
||||
|
||||
def _try_remove(self) -> None:
|
||||
try:
|
||||
self.gm.allocated_icls.remove(self.ct.icls_channel)
|
||||
except ValueError:
|
||||
pass
|
||||
95
qt_ui/widgets/QLink4Widget.py
Normal file
95
qt_ui/widgets/QLink4Widget.py
Normal file
@@ -0,0 +1,95 @@
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import (
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game.radio.radios import RadioFrequency, RadioRange, MHz, kHz
|
||||
from game.theater import NavalControlPoint
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.QRadioFrequencyDialog import QRadioFrequencyDialog
|
||||
|
||||
|
||||
class QLink4Widget(QWidget):
|
||||
|
||||
freq_changed = Signal(QWidget)
|
||||
|
||||
def __init__(self, cp: NavalControlPoint, game_model: GameModel) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.cp = cp
|
||||
self.gm = game_model
|
||||
|
||||
columns = QHBoxLayout()
|
||||
self.setLayout(columns)
|
||||
|
||||
self.freq = QLabel(self._get_label_text())
|
||||
self.check_freq()
|
||||
columns.addWidget(self.freq)
|
||||
columns.addStretch()
|
||||
|
||||
self.set_freq_btn = QPushButton("Set LINK4")
|
||||
self.set_freq_btn.setProperty("class", "comms")
|
||||
self.set_freq_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.set_freq_btn)
|
||||
self.set_freq_btn.clicked.connect(self.open_freq_dialog)
|
||||
|
||||
self.reset_freq_btn = QPushButton("Reset LINK4")
|
||||
self.reset_freq_btn.setProperty("class", "btn-danger comms")
|
||||
self.reset_freq_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.reset_freq_btn)
|
||||
self.reset_freq_btn.clicked.connect(self.reset_freq)
|
||||
|
||||
def _get_label_text(self) -> str:
|
||||
freq = "AUTO" if self.cp.link4 is None else self.cp.link4
|
||||
return f"<b>LINK4: {freq}</b>"
|
||||
|
||||
def open_freq_dialog(self) -> None:
|
||||
range = RadioRange(MHz(225), MHz(400), kHz(25))
|
||||
self.frequency_dialog = QRadioFrequencyDialog(self, self.cp, range, link4=True)
|
||||
self.frequency_dialog.accepted.connect(self.assign_frequency)
|
||||
self.frequency_dialog.show()
|
||||
|
||||
def assign_frequency(self) -> None:
|
||||
hz = round(self.frequency_dialog.frequency_input.value() * 10**6)
|
||||
self._try_remove()
|
||||
self.cp.link4 = RadioFrequency(hertz=hz)
|
||||
self.gm.allocated_freqs.append(self.cp.link4)
|
||||
self.freq.setText(self._get_label_text())
|
||||
self.check_freq()
|
||||
self.freq_changed.emit(self)
|
||||
|
||||
def reset_freq(self):
|
||||
self._try_remove()
|
||||
self.cp.link4 = None
|
||||
self.freq.setText(self._get_label_text())
|
||||
self._reset_color_and_tooltip()
|
||||
self.freq_changed.emit(self)
|
||||
|
||||
def check_freq(self):
|
||||
if self.cp.link4 is None:
|
||||
return
|
||||
if self.gm.allocated_freqs.count(self.cp.link4) > 1:
|
||||
self.freq.setStyleSheet("color: orange")
|
||||
self.freq.setToolTip(
|
||||
"Double booked frequency, verify that this was your intention."
|
||||
)
|
||||
elif self.gm.allocated_freqs.count(self.cp.link4) == 1:
|
||||
self._reset_color_and_tooltip()
|
||||
if self.cp.link4 == MHz(243) or self.cp.link4 == MHz(121, 500):
|
||||
self.freq.setStyleSheet("color: red")
|
||||
self.freq.setToolTip(
|
||||
"GUARD Freq. was assigned, verify that this was your intention."
|
||||
)
|
||||
|
||||
def _reset_color_and_tooltip(self):
|
||||
self.freq.setStyleSheet("color: white")
|
||||
self.freq.setToolTip(None)
|
||||
|
||||
def _try_remove(self):
|
||||
try:
|
||||
self.gm.allocated_freqs.remove(self.cp.link4)
|
||||
except ValueError:
|
||||
pass
|
||||
90
qt_ui/widgets/QTacanWidget.py
Normal file
90
qt_ui/widgets/QTacanWidget.py
Normal file
@@ -0,0 +1,90 @@
|
||||
from PySide2.QtWidgets import (
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game.radio.TacanContainer import TacanContainer
|
||||
from game.radio.tacan import TacanChannel, TacanBand
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.windows.QTacanDialog import QTacanDialog
|
||||
|
||||
|
||||
class QTacanWidget(QWidget):
|
||||
def __init__(self, container: TacanContainer, game_model: GameModel) -> None:
|
||||
super().__init__()
|
||||
|
||||
self.ct = container
|
||||
self.gm = game_model
|
||||
|
||||
columns = QHBoxLayout()
|
||||
self.setLayout(columns)
|
||||
|
||||
self.channel = QLabel(self._get_label_text())
|
||||
self.check_channel()
|
||||
columns.addWidget(self.channel)
|
||||
columns.addStretch()
|
||||
|
||||
self.set_tacan_btn = QPushButton("Set TACAN")
|
||||
self.set_tacan_btn.setProperty("class", "comms")
|
||||
self.set_tacan_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.set_tacan_btn)
|
||||
self.set_tacan_btn.clicked.connect(self.open_tacan_dialog)
|
||||
|
||||
self.reset_tacan_btn = QPushButton("Reset TACAN")
|
||||
self.reset_tacan_btn.setProperty("class", "btn-danger comms")
|
||||
self.reset_tacan_btn.setFixedWidth(100)
|
||||
columns.addWidget(self.reset_tacan_btn)
|
||||
self.reset_tacan_btn.clicked.connect(self.reset_tacan)
|
||||
|
||||
def _get_label_text(self) -> str:
|
||||
c = "AUTO" if self.ct.tacan is None else self.ct.tacan
|
||||
cs = self.ct.tcn_name
|
||||
cs = "" if cs is None else f" ({cs})"
|
||||
return f"<b>TACAN: {c}{cs}</b>"
|
||||
|
||||
def open_tacan_dialog(self) -> None:
|
||||
self.tacan_dialog = QTacanDialog(self, self.ct)
|
||||
self.tacan_dialog.accepted.connect(self.assign_tacan)
|
||||
self.tacan_dialog.show()
|
||||
|
||||
def assign_tacan(self) -> None:
|
||||
channel = self.tacan_dialog.tacan_input.value()
|
||||
band = self.tacan_dialog.band_input.currentText()
|
||||
band = TacanBand.X if band == "X" else TacanBand.Y
|
||||
self._try_remove()
|
||||
self.ct.tacan = TacanChannel(number=channel, band=band)
|
||||
self.gm.allocated_tacan.append(self.ct.tacan)
|
||||
if cs := self.tacan_dialog.callsign_input.text():
|
||||
self.ct.tcn_name = cs.upper()
|
||||
self.channel.setText(self._get_label_text())
|
||||
self.check_channel()
|
||||
|
||||
def reset_tacan(self) -> None:
|
||||
self._try_remove()
|
||||
self.ct.tacan = None
|
||||
self.ct.tcn_name = None
|
||||
self.channel.setText(self._get_label_text())
|
||||
self._reset_color_and_tooltip()
|
||||
|
||||
def check_channel(self) -> None:
|
||||
if self.ct.tacan is None:
|
||||
return
|
||||
if self.gm.allocated_tacan.count(self.ct.tacan) > 1:
|
||||
self.channel.setStyleSheet("color: orange")
|
||||
self.channel.setToolTip(
|
||||
"Double booked TACAN channel, verify that this was your intention."
|
||||
)
|
||||
elif self.gm.allocated_tacan.count(self.ct.tacan) == 1:
|
||||
self._reset_color_and_tooltip()
|
||||
|
||||
def _reset_color_and_tooltip(self):
|
||||
self.channel.setStyleSheet("color: white")
|
||||
self.channel.setToolTip(None)
|
||||
|
||||
def _try_remove(self) -> None:
|
||||
try:
|
||||
self.gm.allocated_tacan.remove(self.ct.tacan)
|
||||
except ValueError:
|
||||
pass
|
||||
54
qt_ui/windows/QICLSDialog.py
Normal file
54
qt_ui/windows/QICLSDialog.py
Normal file
@@ -0,0 +1,54 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtWidgets import (
|
||||
QDialog,
|
||||
QPushButton,
|
||||
QLabel,
|
||||
QHBoxLayout,
|
||||
QSpinBox,
|
||||
QLineEdit,
|
||||
)
|
||||
|
||||
from game.radio.ICLSContainer import ICLSContainer
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
|
||||
|
||||
class QICLSDialog(QDialog):
|
||||
def __init__(self, parent=None, container: Optional[ICLSContainer] = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.container = container
|
||||
self.setMinimumWidth(400)
|
||||
|
||||
# Make dialog modal to prevent background windows to close unexpectedly.
|
||||
self.setModal(True)
|
||||
|
||||
self.setWindowTitle("Assign ICLS")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
|
||||
layout = QHBoxLayout()
|
||||
|
||||
self.icls_label = QLabel("ICLS:")
|
||||
self.icls_input = QSpinBox()
|
||||
self.icls_input.setRange(1, 20)
|
||||
self.icls_input.setSingleStep(1)
|
||||
layout.addWidget(self.icls_label)
|
||||
layout.addStretch()
|
||||
layout.addWidget(self.icls_input)
|
||||
self.callsign_input = QLineEdit()
|
||||
self.callsign_input.setMaxLength(3)
|
||||
self.callsign_input.setMaximumWidth(50)
|
||||
layout.addWidget(self.callsign_input)
|
||||
layout.addStretch()
|
||||
|
||||
self.create_button = QPushButton("Save")
|
||||
self.create_button.clicked.connect(self.accept)
|
||||
layout.addWidget(self.create_button, alignment=Qt.AlignRight)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
if container is not None:
|
||||
if container.icls_name is not None:
|
||||
self.callsign_input.setText(container.icls_name)
|
||||
if container.icls_channel is not None:
|
||||
self.icls_input.setValue(container.icls_channel)
|
||||
@@ -404,6 +404,7 @@ class QLiberationWindow(QMainWindow):
|
||||
self.info_panel.setGame(game)
|
||||
self.sim_controller.set_game(game)
|
||||
self.game_model.set(self.game)
|
||||
self.game_model.init_comms_registry()
|
||||
except AttributeError:
|
||||
logging.exception("Incompatible save game")
|
||||
QMessageBox.critical(
|
||||
@@ -530,6 +531,7 @@ class QLiberationWindow(QMainWindow):
|
||||
logging.info("On Debriefing")
|
||||
self.debriefing = QDebriefingWindow(debrief)
|
||||
self.debriefing.show()
|
||||
self.game_model.init_comms_registry()
|
||||
|
||||
def open_tgo_info_dialog(self, tgo: TheaterGroundObject) -> None:
|
||||
QGroundObjectMenu(self, tgo, tgo.control_point, self.game).show()
|
||||
|
||||
60
qt_ui/windows/QRadioFrequencyDialog.py
Normal file
60
qt_ui/windows/QRadioFrequencyDialog.py
Normal file
@@ -0,0 +1,60 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtCore import Qt, QLocale
|
||||
from PySide2.QtWidgets import (
|
||||
QDialog,
|
||||
QPushButton,
|
||||
QLabel,
|
||||
QHBoxLayout,
|
||||
QDoubleSpinBox,
|
||||
)
|
||||
|
||||
from game.radio.Link4Container import Link4Container
|
||||
from game.radio.RadioFrequencyContainer import RadioFrequencyContainer
|
||||
from game.radio.radios import RadioRange, kHz, MHz
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
|
||||
|
||||
class QRadioFrequencyDialog(QDialog):
|
||||
def __init__(
|
||||
self,
|
||||
parent=None,
|
||||
container: Optional[RadioFrequencyContainer] = None,
|
||||
range: RadioRange = RadioRange(MHz(225), MHz(400), kHz(25)),
|
||||
link4: bool = False,
|
||||
) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.container = container
|
||||
self.setMinimumWidth(400)
|
||||
|
||||
# Make dialog modal to prevent background windows to close unexpectedly.
|
||||
self.setModal(True)
|
||||
|
||||
self.setWindowTitle("Assign frequency")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
|
||||
layout = QHBoxLayout()
|
||||
|
||||
self.frequency_label = QLabel("FREQ (MHz):")
|
||||
self.frequency_input = QDoubleSpinBox()
|
||||
self.frequency_input.setRange(
|
||||
range.minimum.mhz, range.maximum.mhz - range.step.mhz
|
||||
)
|
||||
self.frequency_input.setSingleStep(range.step.mhz)
|
||||
self.frequency_input.setDecimals(3)
|
||||
self.frequency_input.setLocale(QLocale(QLocale.Language.English))
|
||||
self.frequency_input.setValue(225.0)
|
||||
layout.addWidget(self.frequency_label)
|
||||
layout.addWidget(self.frequency_input)
|
||||
|
||||
self.create_button = QPushButton("Save")
|
||||
self.create_button.clicked.connect(self.accept)
|
||||
layout.addWidget(self.create_button, alignment=Qt.AlignRight)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
if link4 and isinstance(container, Link4Container):
|
||||
if container.link4:
|
||||
self.frequency_input.setValue(container.link4.mhz)
|
||||
elif container.frequency:
|
||||
self.frequency_input.setValue(container.frequency.mhz)
|
||||
59
qt_ui/windows/QTacanDialog.py
Normal file
59
qt_ui/windows/QTacanDialog.py
Normal file
@@ -0,0 +1,59 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtWidgets import (
|
||||
QDialog,
|
||||
QPushButton,
|
||||
QLabel,
|
||||
QHBoxLayout,
|
||||
QSpinBox,
|
||||
QComboBox,
|
||||
QLineEdit,
|
||||
)
|
||||
|
||||
from game.radio.TacanContainer import TacanContainer
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
|
||||
|
||||
class QTacanDialog(QDialog):
|
||||
def __init__(self, parent=None, container: Optional[TacanContainer] = None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.container = container
|
||||
self.setMinimumWidth(400)
|
||||
|
||||
# Make dialog modal to prevent background windows to close unexpectedly.
|
||||
self.setModal(True)
|
||||
|
||||
self.setWindowTitle("Assign TACAN")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
|
||||
layout = QHBoxLayout()
|
||||
|
||||
self.tacan_label = QLabel("TACAN:")
|
||||
self.tacan_input = QSpinBox()
|
||||
self.tacan_input.setRange(1, 126)
|
||||
self.tacan_input.setSingleStep(1)
|
||||
layout.addWidget(self.tacan_label)
|
||||
layout.addStretch()
|
||||
layout.addWidget(self.tacan_input)
|
||||
self.band_input = QComboBox()
|
||||
self.band_input.addItems(["X", "Y"])
|
||||
layout.addWidget(self.band_input)
|
||||
self.callsign_input = QLineEdit()
|
||||
self.callsign_input.setMaxLength(3)
|
||||
self.callsign_input.setMaximumWidth(50)
|
||||
layout.addWidget(self.callsign_input)
|
||||
layout.addStretch()
|
||||
|
||||
self.create_button = QPushButton("Save")
|
||||
self.create_button.clicked.connect(self.accept)
|
||||
layout.addWidget(self.create_button, alignment=Qt.AlignRight)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
if container is not None:
|
||||
if container.tcn_name is not None:
|
||||
self.callsign_input.setText(container.tcn_name)
|
||||
if container.tacan is not None:
|
||||
self.tacan_input.setValue(container.tacan.number)
|
||||
self.band_input.setCurrentText(container.tacan.band.value)
|
||||
@@ -8,11 +8,15 @@ from PySide2.QtWidgets import (
|
||||
QPushButton,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
QGridLayout,
|
||||
)
|
||||
|
||||
from game import Game
|
||||
from game.ato.flighttype import FlightType
|
||||
from game.config import RUNWAY_REPAIR_COST
|
||||
from game.radio.ICLSContainer import ICLSContainer
|
||||
from game.radio.RadioFrequencyContainer import RadioFrequencyContainer
|
||||
from game.radio.TacanContainer import TacanContainer
|
||||
from game.server import EventStream
|
||||
from game.sim import GameUpdateEvents
|
||||
from game.theater import (
|
||||
@@ -20,10 +24,15 @@ from game.theater import (
|
||||
ControlPoint,
|
||||
ControlPointType,
|
||||
FREE_FRONTLINE_UNIT_SUPPLY,
|
||||
NavalControlPoint,
|
||||
)
|
||||
from qt_ui.dialogs import Dialog
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.QFrequencyWidget import QFrequencyWidget
|
||||
from qt_ui.widgets.QICLSWidget import QICLSWidget
|
||||
from qt_ui.widgets.QLink4Widget import QLink4Widget
|
||||
from qt_ui.widgets.QTacanWidget import QTacanWidget
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.basemenu.NewUnitTransferDialog import NewUnitTransferDialog
|
||||
from qt_ui.windows.basemenu.QBaseMenuTabs import QBaseMenuTabs
|
||||
@@ -60,13 +69,49 @@ class QBaseMenu2(QDialog):
|
||||
pixmap = QPixmap(self.get_base_image())
|
||||
header.setPixmap(pixmap)
|
||||
|
||||
cp_settings = QGridLayout()
|
||||
top_layout.addLayout(cp_settings)
|
||||
|
||||
title = QLabel("<b>" + self.cp.name + "</b>")
|
||||
title.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||
title.setProperty("style", "base-title")
|
||||
cp_settings.addWidget(title, 0, 0, 1, 2)
|
||||
cp_settings.setHorizontalSpacing(20)
|
||||
|
||||
counter = 2
|
||||
|
||||
self.freq_widget = None
|
||||
self.link4_widget = None
|
||||
|
||||
is_friendly = cp.is_friendly(True)
|
||||
if is_friendly and isinstance(cp, RadioFrequencyContainer):
|
||||
self.freq_widget = QFrequencyWidget(cp, self.game_model)
|
||||
cp_settings.addWidget(self.freq_widget, counter // 2, counter % 2)
|
||||
counter += 1
|
||||
|
||||
if is_friendly and isinstance(cp, TacanContainer):
|
||||
self.tacan_widget = QTacanWidget(cp, self.game_model)
|
||||
cp_settings.addWidget(self.tacan_widget, counter // 2, counter % 2)
|
||||
counter += 1
|
||||
|
||||
if is_friendly and isinstance(cp, ICLSContainer):
|
||||
self.icls_widget = QICLSWidget(cp, self.game_model)
|
||||
cp_settings.addWidget(self.icls_widget, counter // 2, counter % 2)
|
||||
counter += 1
|
||||
|
||||
if is_friendly and isinstance(cp, NavalControlPoint):
|
||||
self.link4_widget = QLink4Widget(cp, self.game_model)
|
||||
cp_settings.addWidget(self.link4_widget, counter // 2, counter % 2)
|
||||
counter += 1
|
||||
|
||||
if self.freq_widget and self.link4_widget:
|
||||
# link them so on change they check freq
|
||||
self.freq_widget.freq_changed.connect(self.link4_widget.check_freq)
|
||||
self.link4_widget.freq_changed.connect(self.freq_widget.check_freq)
|
||||
|
||||
self.intel_summary = QLabel()
|
||||
self.intel_summary.setToolTip(self.generate_intel_tooltip())
|
||||
self.update_intel_summary()
|
||||
top_layout.addWidget(title)
|
||||
top_layout.addWidget(self.intel_summary)
|
||||
top_layout.setAlignment(Qt.AlignTop)
|
||||
|
||||
@@ -127,6 +172,7 @@ class QBaseMenu2(QDialog):
|
||||
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
|
||||
state = self.game_model.game.check_win_loss()
|
||||
GameUpdateSignal.get_instance().gameStateChanged(state)
|
||||
self.close()
|
||||
|
||||
@property
|
||||
def has_transfer_destinations(self) -> bool:
|
||||
|
||||
@@ -32,7 +32,7 @@ class QEditFlightDialog(QDialog):
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
self.flight_planner = QFlightPlanner(package_model, flight, game_model.game)
|
||||
self.flight_planner = QFlightPlanner(package_model, flight, game_model)
|
||||
layout.addWidget(self.flight_planner)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
@@ -26,9 +26,10 @@ from game.sim import GameUpdateEvents
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from qt_ui.models import AtoModel, GameModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.QFrequencyWidget import QFrequencyWidget
|
||||
from qt_ui.widgets.ato import QFlightList
|
||||
from qt_ui.windows.QRadioFrequencyDialog import QRadioFrequencyDialog
|
||||
from qt_ui.windows.mission.flight.QFlightCreator import QFlightCreator
|
||||
from qt_ui.windows.mission.package.QPackageFrequency import QPackageFrequency
|
||||
|
||||
|
||||
class QPackageDialog(QDialog):
|
||||
@@ -70,22 +71,9 @@ class QPackageDialog(QDialog):
|
||||
package_type_row.addWidget(self.package_type_text)
|
||||
self.package_type_column.addLayout(package_type_row)
|
||||
|
||||
# TODO: make freq red if used by another package
|
||||
package_freq_row = QHBoxLayout()
|
||||
self.package_freq_label = QLabel("Package FREQ:")
|
||||
freq = (
|
||||
self.package_model.package.frequency.mhz
|
||||
if self.package_model.package.frequency is not None
|
||||
else ""
|
||||
)
|
||||
self.package_freq_text = QLabel(f"{freq}")
|
||||
package_freq_row.addWidget(self.package_freq_label)
|
||||
package_freq_row.addWidget(self.package_freq_text)
|
||||
self.package_type_column.addLayout(package_freq_row)
|
||||
|
||||
self.summary_row.addStretch(1)
|
||||
|
||||
self.package_name_column = QVBoxLayout()
|
||||
self.package_name_column = QHBoxLayout()
|
||||
self.summary_row.addLayout(self.package_name_column)
|
||||
self.package_name_label = QLabel("Package Name:")
|
||||
self.package_name_label.setAlignment(Qt.AlignCenter)
|
||||
@@ -145,16 +133,17 @@ class QPackageDialog(QDialog):
|
||||
self.delete_flight_button.setEnabled(model.rowCount() > 0)
|
||||
self.button_layout.addWidget(self.delete_flight_button)
|
||||
|
||||
self.open_radio_button = QPushButton("Set Package FREQ")
|
||||
self.open_radio_button.clicked.connect(self.on_open_radio)
|
||||
self.button_layout.addWidget(self.open_radio_button)
|
||||
self.button_layout.addStretch()
|
||||
|
||||
self.package_model.tot_changed.connect(self.update_tot)
|
||||
self.freq_widget = QFrequencyWidget(self.package_model.package, game_model)
|
||||
self.button_layout.addWidget(self.freq_widget)
|
||||
|
||||
self.button_layout.addStretch()
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.package_model.tot_changed.connect(self.update_tot)
|
||||
|
||||
self.accepted.connect(self.on_save)
|
||||
self.finished.connect(self.on_close)
|
||||
self.rejected.connect(self.on_cancel)
|
||||
@@ -238,8 +227,8 @@ class QPackageDialog(QDialog):
|
||||
self.package_model.package.custom_name = self.package_name_text.text()
|
||||
|
||||
def on_open_radio(self) -> None:
|
||||
self.package_frequency_dialog = QPackageFrequency(
|
||||
self.game, self.package_model.package, parent=self.window()
|
||||
self.package_frequency_dialog = QRadioFrequencyDialog(
|
||||
parent=self.window(), container=self.package_model.package
|
||||
)
|
||||
self.package_frequency_dialog.accepted.connect(self.assign_frequency)
|
||||
self.package_frequency_dialog.show()
|
||||
@@ -251,8 +240,11 @@ class QPackageDialog(QDialog):
|
||||
|
||||
def on_package_changed(self):
|
||||
self.package_type_text.setText(self.package_model.description)
|
||||
if (freq := self.package_model.package.frequency) is not None:
|
||||
self.package_freq_text.setText(f"{freq.mhz} MHz")
|
||||
self.freq_widget.check_freq()
|
||||
|
||||
def on_reset_radio(self):
|
||||
self.package_model.package.frequency = None
|
||||
self.package_freq_text.setText("AUTO")
|
||||
|
||||
|
||||
class QNewPackageDialog(QPackageDialog):
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
from PySide2.QtWidgets import QTabWidget
|
||||
|
||||
from game import Game
|
||||
from game.ato.flight import Flight
|
||||
from qt_ui.models import PackageModel
|
||||
from qt_ui.models import PackageModel, GameModel
|
||||
from qt_ui.windows.mission.flight.payload.QFlightPayloadTab import QFlightPayloadTab
|
||||
from qt_ui.windows.mission.flight.settings.QGeneralFlightSettingsTab import (
|
||||
QGeneralFlightSettingsTab,
|
||||
@@ -11,14 +10,12 @@ from qt_ui.windows.mission.flight.waypoints.QFlightWaypointTab import QFlightWay
|
||||
|
||||
|
||||
class QFlightPlanner(QTabWidget):
|
||||
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
|
||||
def __init__(self, package_model: PackageModel, flight: Flight, gm: GameModel):
|
||||
super().__init__()
|
||||
|
||||
self.general_settings_tab = QGeneralFlightSettingsTab(
|
||||
game, package_model, flight
|
||||
)
|
||||
self.payload_tab = QFlightPayloadTab(flight, game)
|
||||
self.waypoint_tab = QFlightWaypointTab(game, package_model.package, flight)
|
||||
self.general_settings_tab = QGeneralFlightSettingsTab(gm, package_model, flight)
|
||||
self.payload_tab = QFlightPayloadTab(flight, gm.game)
|
||||
self.waypoint_tab = QFlightWaypointTab(gm.game, package_model.package, flight)
|
||||
self.waypoint_tab.loadout_changed.connect(self.payload_tab.reload_from_flight)
|
||||
self.addTab(self.general_settings_tab, "General Flight settings")
|
||||
self.addTab(self.payload_tab, "Payload")
|
||||
|
||||
@@ -4,6 +4,8 @@ from PySide2.QtWidgets import (
|
||||
QFrame,
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
QScrollArea,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
from game import Game
|
||||
@@ -42,7 +44,12 @@ class QFlightPayloadTab(QFrame):
|
||||
docsText.setAlignment(Qt.AlignCenter)
|
||||
docsText.setOpenExternalLinks(True)
|
||||
|
||||
layout.addLayout(PropertyEditor(self.flight))
|
||||
self.scroll_area = QScrollArea()
|
||||
self.property_editor = QWidget()
|
||||
self.property_editor.setLayout(PropertyEditor(self.flight))
|
||||
self.scroll_area.setWidget(self.property_editor)
|
||||
|
||||
layout.addWidget(self.scroll_area)
|
||||
self.loadout_selector = DcsLoadoutSelector(flight)
|
||||
self.loadout_selector.currentIndexChanged.connect(self.on_new_loadout)
|
||||
layout.addWidget(self.loadout_selector)
|
||||
|
||||
@@ -30,7 +30,6 @@ class QLoadoutEditor(QGroupBox):
|
||||
layout.addWidget(QPylonEditor(game, flight, pylon), i, 1)
|
||||
|
||||
vbox.addLayout(layout)
|
||||
vbox.addStretch()
|
||||
self.setLayout(vbox)
|
||||
|
||||
for i in self.findChildren(QPylonEditor):
|
||||
|
||||
25
qt_ui/windows/mission/flight/settings/QCommsEditor.py
Normal file
25
qt_ui/windows/mission/flight/settings/QCommsEditor.py
Normal file
@@ -0,0 +1,25 @@
|
||||
from PySide2.QtWidgets import QGroupBox, QVBoxLayout
|
||||
|
||||
from game.ato import Flight, FlightType
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.widgets.QFrequencyWidget import QFrequencyWidget
|
||||
from qt_ui.widgets.QTacanWidget import QTacanWidget
|
||||
|
||||
|
||||
class QCommsEditor(QGroupBox):
|
||||
def __init__(self, flight: Flight, game: GameModel):
|
||||
title = "Intra-Flight Frequency"
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
is_refuel = flight.flight_type == FlightType.REFUELING
|
||||
has_tacan = flight.unit_type.dcs_unit_type.tacan
|
||||
|
||||
layout.addWidget(QFrequencyWidget(flight, game))
|
||||
if is_refuel and has_tacan:
|
||||
layout.addWidget(QTacanWidget(flight, game))
|
||||
title = title + " / TACAN"
|
||||
super(QCommsEditor, self).__init__(title)
|
||||
self.flight = flight
|
||||
|
||||
self.setLayout(layout)
|
||||
@@ -1,6 +1,6 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtWidgets import QGroupBox, QVBoxLayout, QLineEdit, QLabel, QMessageBox
|
||||
from PySide2.QtWidgets import QGroupBox, QHBoxLayout, QLineEdit, QLabel, QMessageBox
|
||||
from game.ato.flight import Flight
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class QFlightCustomName(QGroupBox):
|
||||
|
||||
self.flight = flight
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
self.layout = QHBoxLayout()
|
||||
self.custom_name_label = QLabel(f"Custom Name:")
|
||||
self.custom_name_input = QLineEdit(flight.custom_name)
|
||||
self.custom_name_input.textChanged.connect(self.on_change)
|
||||
|
||||
@@ -3,10 +3,11 @@ from PySide2.QtWidgets import QFrame, QGridLayout, QVBoxLayout
|
||||
|
||||
from game import Game
|
||||
from game.ato.flight import Flight
|
||||
from qt_ui.models import PackageModel
|
||||
from qt_ui.models import PackageModel, GameModel
|
||||
from qt_ui.windows.mission.flight.settings.FlightAirfieldDisplay import (
|
||||
FlightAirfieldDisplay,
|
||||
)
|
||||
from qt_ui.windows.mission.flight.settings.QCommsEditor import QCommsEditor
|
||||
from qt_ui.windows.mission.flight.settings.QCustomName import QFlightCustomName
|
||||
from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import QFlightSlotEditor
|
||||
from qt_ui.windows.mission.flight.settings.QFlightStartType import QFlightStartType
|
||||
@@ -18,16 +19,23 @@ from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import (
|
||||
class QGeneralFlightSettingsTab(QFrame):
|
||||
on_flight_settings_changed = Signal()
|
||||
|
||||
def __init__(self, game: Game, package_model: PackageModel, flight: Flight):
|
||||
def __init__(self, game: GameModel, package_model: PackageModel, flight: Flight):
|
||||
super().__init__()
|
||||
|
||||
widgets = [
|
||||
QFlightTypeTaskInfo(flight),
|
||||
QCommsEditor(flight, game),
|
||||
FlightAirfieldDisplay(game.game, package_model, flight),
|
||||
QFlightSlotEditor(package_model, flight, game.game),
|
||||
QFlightStartType(package_model, flight),
|
||||
QFlightCustomName(flight),
|
||||
]
|
||||
layout = QGridLayout()
|
||||
layout.addWidget(QFlightTypeTaskInfo(flight), 0, 0)
|
||||
layout.addWidget(FlightAirfieldDisplay(game, package_model, flight), 1, 0)
|
||||
layout.addWidget(QFlightSlotEditor(package_model, flight, game), 2, 0)
|
||||
layout.addWidget(QFlightStartType(package_model, flight), 3, 0)
|
||||
layout.addWidget(QFlightCustomName(flight), 4, 0)
|
||||
row = 0
|
||||
for w in widgets:
|
||||
layout.addWidget(w, row, 0)
|
||||
row += 1
|
||||
vstretch = QVBoxLayout()
|
||||
vstretch.addStretch()
|
||||
layout.addLayout(vstretch, 5, 0)
|
||||
layout.addLayout(vstretch, row, 0)
|
||||
self.setLayout(layout)
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
from typing import Optional, Type
|
||||
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtWidgets import (
|
||||
QDialog,
|
||||
QPushButton,
|
||||
QVBoxLayout,
|
||||
QLabel,
|
||||
QHBoxLayout,
|
||||
QDoubleSpinBox,
|
||||
)
|
||||
|
||||
from game import Game
|
||||
from game.ato.package import Package
|
||||
from game.radio.radios import RadioRegistry
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
|
||||
|
||||
class QPackageFrequency(QDialog):
|
||||
def __init__(self, game: Game, package: Package, parent=None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
self.setMinimumWidth(400)
|
||||
|
||||
self.game = game
|
||||
self.package = package
|
||||
|
||||
# Make dialog modal to prevent background windows to close unexpectedly.
|
||||
self.setModal(True)
|
||||
|
||||
self.setWindowTitle("Assign frequency")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
|
||||
layout = QHBoxLayout()
|
||||
|
||||
self.frequency_label = QLabel("FREQ (Mhz):")
|
||||
self.frequency_input = QDoubleSpinBox()
|
||||
self.frequency_input.setRange(225, 399.975)
|
||||
self.frequency_input.setSingleStep(0.025)
|
||||
self.frequency_input.setDecimals(3)
|
||||
layout.addWidget(self.frequency_label)
|
||||
layout.addWidget(self.frequency_input)
|
||||
|
||||
self.create_button = QPushButton("Save")
|
||||
self.create_button.clicked.connect(self.accept)
|
||||
layout.addWidget(self.create_button, alignment=Qt.AlignRight)
|
||||
|
||||
self.setLayout(layout)
|
||||
Reference in New Issue
Block a user