mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Improve UI for flight properties.
Use the new data from pydcs to improve the properties UI: * Use human readable names * Use appropriate control types * Limit min and max values as appropriate for each property * Show labels Fixes https://github.com/dcs-liberation/dcs_liberation/issues/3090.
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
class MissingPropertyDataError(RuntimeError):
|
||||
...
|
||||
21
qt_ui/windows/mission/flight/payload/propertycheckbox.py
Normal file
21
qt_ui/windows/mission/flight/payload/propertycheckbox.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from PySide6.QtWidgets import QCheckBox
|
||||
from dcs.unitpropertydescription import UnitPropertyDescription
|
||||
|
||||
from game.ato import Flight
|
||||
from .missingpropertydataerror import MissingPropertyDataError
|
||||
|
||||
|
||||
class PropertyCheckBox(QCheckBox):
|
||||
def __init__(self, flight: Flight, prop: UnitPropertyDescription) -> None:
|
||||
super().__init__()
|
||||
self.flight = flight
|
||||
self.prop = prop
|
||||
|
||||
if prop.default is None:
|
||||
raise MissingPropertyDataError("default cannot be None")
|
||||
|
||||
self.setChecked(self.flight.props.get(self.prop.identifier, self.prop.default))
|
||||
self.toggled.connect(self.on_toggle)
|
||||
|
||||
def on_toggle(self, checked: bool) -> None:
|
||||
self.flight.props[self.prop.identifier] = checked
|
||||
29
qt_ui/windows/mission/flight/payload/propertycombobox.py
Normal file
29
qt_ui/windows/mission/flight/payload/propertycombobox.py
Normal file
@@ -0,0 +1,29 @@
|
||||
from PySide6.QtWidgets import QComboBox
|
||||
from dcs.unitpropertydescription import UnitPropertyDescription
|
||||
|
||||
from game.ato import Flight
|
||||
from .missingpropertydataerror import MissingPropertyDataError
|
||||
|
||||
|
||||
class PropertyComboBox(QComboBox):
|
||||
def __init__(self, flight: Flight, prop: UnitPropertyDescription) -> None:
|
||||
super().__init__()
|
||||
self.flight = flight
|
||||
self.prop = prop
|
||||
|
||||
if prop.values is None:
|
||||
raise MissingPropertyDataError("values cannot be None")
|
||||
if prop.default is None:
|
||||
raise MissingPropertyDataError("default cannot be None")
|
||||
|
||||
current_value = self.flight.props.get(self.prop.identifier, self.prop.default)
|
||||
|
||||
for ident, text in self.prop.values.items():
|
||||
self.addItem(text, ident)
|
||||
if ident == current_value:
|
||||
self.setCurrentText(text)
|
||||
|
||||
self.currentIndexChanged.connect(self.on_selection_changed)
|
||||
|
||||
def on_selection_changed(self, _index: int) -> None:
|
||||
self.flight.props[self.prop.identifier] = self.currentData()
|
||||
@@ -1,7 +1,18 @@
|
||||
import logging
|
||||
|
||||
from PySide2.QtWidgets import QGridLayout, QLabel
|
||||
from dcs.unitpropertydescription import UnitPropertyDescription
|
||||
|
||||
from game.ato import Flight
|
||||
from .propertyselector import PropertySelector
|
||||
from .missingpropertydataerror import MissingPropertyDataError
|
||||
from .propertycheckbox import PropertyCheckBox
|
||||
from .propertycombobox import PropertyComboBox
|
||||
from .propertyspinbox import PropertySpinBox
|
||||
|
||||
|
||||
class UnhandledControlTypeError(RuntimeError):
|
||||
def __init__(self, control: str) -> None:
|
||||
super().__init__(f"Unhandled control type {control}")
|
||||
|
||||
|
||||
class PropertyEditor(QGridLayout):
|
||||
@@ -10,5 +21,47 @@ class PropertyEditor(QGridLayout):
|
||||
self.flight = flight
|
||||
|
||||
for row, prop in enumerate(flight.unit_type.iter_props()):
|
||||
self.addWidget(QLabel(prop.id), row, 0)
|
||||
self.addWidget(PropertySelector(self.flight, prop), row, 1)
|
||||
if prop.label is None:
|
||||
if prop.control != "label":
|
||||
logging.error(
|
||||
"Found non-label aircraft property with no display name."
|
||||
)
|
||||
continue
|
||||
|
||||
if prop.player_only and not flight.client_count:
|
||||
continue
|
||||
|
||||
try:
|
||||
widget = self.control_for_property(prop)
|
||||
except (MissingPropertyDataError, UnhandledControlTypeError):
|
||||
logging.exception(
|
||||
f"Cannot create property control for property %s of %s",
|
||||
prop.identifier,
|
||||
flight.unit_type,
|
||||
)
|
||||
continue
|
||||
|
||||
label = prop.label
|
||||
if widget is None:
|
||||
label = f"<strong>{label}</label>"
|
||||
self.addWidget(QLabel(label), row, 0)
|
||||
|
||||
# If prop.control is "label", widget will be None. We only need to add the
|
||||
# label, not the control.
|
||||
if widget is not None:
|
||||
self.addWidget(widget, row, 1)
|
||||
|
||||
def control_for_property(self, prop: UnitPropertyDescription) -> QWidget | None:
|
||||
# Valid values are:
|
||||
# "checkbox", "comboList", "groupbox", "label", "slider", "spinbox"
|
||||
match prop.control:
|
||||
case "checkbox":
|
||||
return PropertyCheckBox(self.flight, prop)
|
||||
case "comboList":
|
||||
return PropertyComboBox(self.flight, prop)
|
||||
case "groupbox" | "label":
|
||||
return None
|
||||
case "slider" | "spinbox":
|
||||
return PropertySpinBox(self.flight, prop)
|
||||
case _:
|
||||
raise UnhandledControlTypeError(prop.control)
|
||||
|
||||
28
qt_ui/windows/mission/flight/payload/propertyspinbox.py
Normal file
28
qt_ui/windows/mission/flight/payload/propertyspinbox.py
Normal file
@@ -0,0 +1,28 @@
|
||||
from PySide6.QtWidgets import QSpinBox
|
||||
from dcs.unitpropertydescription import UnitPropertyDescription
|
||||
|
||||
from game.ato import Flight
|
||||
from .missingpropertydataerror import MissingPropertyDataError
|
||||
|
||||
|
||||
class PropertySpinBox(QSpinBox):
|
||||
def __init__(self, flight: Flight, prop: UnitPropertyDescription) -> None:
|
||||
super().__init__()
|
||||
self.flight = flight
|
||||
self.prop = prop
|
||||
|
||||
if prop.minimum is None:
|
||||
raise MissingPropertyDataError("minimum cannot be None")
|
||||
if prop.maximum is None:
|
||||
raise MissingPropertyDataError("maximum cannot be None")
|
||||
if prop.default is None:
|
||||
raise MissingPropertyDataError("default cannot be None")
|
||||
|
||||
self.setMinimum(prop.minimum)
|
||||
self.setMaximum(prop.maximum)
|
||||
self.setValue(self.flight.props.get(self.prop.identifier, self.prop.default))
|
||||
|
||||
self.valueChanged.connect(self.on_value_changed)
|
||||
|
||||
def on_value_changed(self, value: int) -> None:
|
||||
self.flight.props[self.prop.identifier] = value
|
||||
Reference in New Issue
Block a user