dcs-retribution/qt_ui/windows/QRadioFrequencyDialog.py

133 lines
4.6 KiB
Python

from typing import Optional, Iterable
from PySide2.QtCore import Qt, QLocale
from PySide2.QtGui import QIcon
from PySide2.QtWidgets import (
QDialog,
QPushButton,
QLabel,
QHBoxLayout,
QDoubleSpinBox,
QComboBox,
)
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 QFrequencySpinbox(QDoubleSpinBox):
def __init__(self, ranges: Iterable[RadioRange]) -> None:
super().__init__()
self.setLocale(QLocale(QLocale.Language.English))
self.setDecimals(3)
self.ranges = list(ranges)
first = True
for r in ranges:
if r.minimum.mhz < self.minimum():
self.setMinimum(r.minimum.mhz)
if self.maximum() < r.maximum.mhz:
self.setMaximum(r.maximum.mhz)
if first:
self.setSingleStep(r.step.mhz)
self.setValue(r.minimum.mhz)
first = False
def correct_value(self, value: float) -> None:
for r in self.ranges:
if r.maximum.mhz == value:
self.setValue(value - r.step.mhz)
return
def stepBy(self, steps: int) -> None:
new_value = self.check_value(self.value() + (steps * self.singleStep()))
self.setValue(new_value)
def check_value(self, value: float) -> float:
for r in self.ranges:
if r.minimum.mhz <= value < r.maximum.mhz:
self.setSingleStep(r.step.mhz)
return value
minimums = [m for m in set(r.minimum.mhz for r in self.ranges) if m > value]
maximums = [m for m in set(r.maximum.mhz for r in self.ranges) if m <= value]
if not minimums or not maximums:
return self.value()
smallest_min = min(minimums)
largest_max = max(maximums)
if largest_max <= value < smallest_min:
if value < self.value():
rs = [r for r in self.ranges if r.maximum.mhz == largest_max]
value = largest_max - rs[0].step.mhz
else:
rs = [r for r in self.ranges if r.minimum.mhz == smallest_min]
value = smallest_min
r = rs[0]
self.setSingleStep(r.step.mhz)
return value
raise RuntimeError()
class QFrequencyModulationBox(QComboBox):
def __init__(self, ranges: Iterable[RadioRange], freq: float) -> None:
super().__init__()
self.setMaximumWidth(60)
self.ranges = list(ranges)
self.update_modulations(freq)
def update_modulations(self, freq: float) -> None:
self.modulations = set(
r.modulation for r in self.ranges if r.minimum.mhz <= freq < r.maximum.mhz
)
self.setEnabled(len(self.modulations) > 1)
self.clear()
for i, m in enumerate(sorted(self.modulations, key=lambda x: x.name)):
self.addItem(QIcon(), m.name, m)
class QRadioFrequencyDialog(QDialog):
def __init__(
self,
parent=None,
container: Optional[RadioFrequencyContainer] = None,
ranges: Iterable[RadioRange] = tuple([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 = QFrequencySpinbox(ranges)
self.frequency_modulation = QFrequencyModulationBox(
ranges, self.frequency_input.value()
)
self.frequency_input.valueChanged.connect(
self.frequency_modulation.update_modulations
)
self.frequency_input.valueChanged.connect(self.frequency_input.correct_value)
layout.addWidget(self.frequency_label)
layout.addWidget(self.frequency_input)
layout.addWidget(self.frequency_modulation)
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)