mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
parent
06960db5e5
commit
824312e19d
@ -19,6 +19,7 @@
|
||||
* **[UI]** Zoom level retained when switching campaigns
|
||||
* **[UX]** Allow changing squadrons in flight's edit dialog
|
||||
* **[Cheats]** Sink/Resurrect carriers instead of showing an error during cheat-capture (use AWCD-cheat to add squadrons upon resurrection)
|
||||
* **[UI/UX]** Allow changing conditions such as Time, Date & Weather
|
||||
|
||||
## Fixes
|
||||
* **[UI/UX]** A-10A flights can be edited again
|
||||
|
||||
85
qt_ui/widgets/QConditionsDialog.py
Normal file
85
qt_ui/widgets/QConditionsDialog.py
Normal file
@ -0,0 +1,85 @@
|
||||
from copy import deepcopy
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QPushButton
|
||||
|
||||
from game.sim import GameUpdateEvents
|
||||
from game.weather.clouds import Clouds
|
||||
from qt_ui.widgets.conditions.QTimeAdjustmentWidget import QTimeAdjustmentWidget
|
||||
from qt_ui.widgets.conditions.QTimeTurnWidget import QTimeTurnWidget
|
||||
from qt_ui.widgets.conditions.QWeatherAdjustmentWidget import QWeatherAdjustmentWidget
|
||||
from qt_ui.widgets.conditions.QWeatherWidget import QWeatherWidget
|
||||
|
||||
|
||||
class QConditionsDialog(QDialog):
|
||||
def __init__(self, time_turn: QTimeTurnWidget, weather: QWeatherWidget):
|
||||
super().__init__()
|
||||
self.time_turn = time_turn
|
||||
self.weather = weather
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
self.setWindowTitle("Time & Weather Conditions")
|
||||
self.setMinimumSize(360, 380)
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
|
||||
self.time_adjuster = QTimeAdjustmentWidget(self.time_turn)
|
||||
vbox.addWidget(self.time_adjuster, 1)
|
||||
self.weather_adjuster = QWeatherAdjustmentWidget(self.weather)
|
||||
vbox.addWidget(self.weather_adjuster, 8)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
reject_btn = QPushButton("REJECT")
|
||||
reject_btn.setProperty("style", "btn-danger")
|
||||
reject_btn.clicked.connect(self.close)
|
||||
hbox.addWidget(reject_btn)
|
||||
accept_btn = QPushButton("ACCEPT")
|
||||
accept_btn.setProperty("style", "btn-success")
|
||||
accept_btn.clicked.connect(self.apply_conditions)
|
||||
hbox.addWidget(accept_btn)
|
||||
vbox.addLayout(hbox, 1)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
def apply_conditions(self) -> None:
|
||||
qdt: datetime = self.time_adjuster.datetime_edit.dateTime().toPython()
|
||||
|
||||
sim = self.time_turn.sim_controller
|
||||
current_time = sim.current_time_in_sim_if_game_loaded
|
||||
if current_time:
|
||||
current_time = deepcopy(current_time)
|
||||
sim.game_loop.sim.time = qdt
|
||||
|
||||
game = sim.game_loop.game
|
||||
game.date = qdt.date() - timedelta(days=game.turn // 4)
|
||||
game.conditions.start_time = qdt
|
||||
self.time_turn.set_current_turn(game.turn, game.conditions)
|
||||
|
||||
# TODO: create new weather object
|
||||
|
||||
new_weather_type = self.weather_adjuster.type_selector.currentData()
|
||||
new_weather = new_weather_type(
|
||||
seasonal_conditions=game.theater.seasonal_conditions,
|
||||
day=qdt.date(),
|
||||
time_of_day=game.current_turn_time_of_day,
|
||||
)
|
||||
|
||||
# self.weather.conditions.weather = WeatherType()
|
||||
preset = self.weather_adjuster.preset_selector.currentData()
|
||||
new_weather.clouds = Clouds(
|
||||
base=self.weather_adjuster.cloud_base.base.value(),
|
||||
density=self.weather_adjuster.cloud_density.density.value(),
|
||||
thickness=self.weather_adjuster.cloud_thickness.thickness.value(),
|
||||
precipitation=self.weather_adjuster.precipitation.selector.currentData(),
|
||||
preset=preset,
|
||||
)
|
||||
|
||||
self.weather.conditions.weather = new_weather
|
||||
|
||||
self.weather.update_forecast()
|
||||
if game.turn > 0 and current_time != qdt:
|
||||
events = GameUpdateEvents()
|
||||
game.initialize_turn(events, for_blue=True, for_red=True)
|
||||
sim.sim_update.emit(events)
|
||||
self.accept()
|
||||
@ -1,282 +1,15 @@
|
||||
from datetime import datetime
|
||||
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6 import QtCore, QtGui
|
||||
from PySide6.QtGui import QCursor
|
||||
from PySide6.QtWidgets import (
|
||||
QFrame,
|
||||
QGridLayout,
|
||||
QGroupBox,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
)
|
||||
from dcs.weather import CloudPreset, Weather as PydcsWeather
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.timeofday import TimeOfDay
|
||||
from game.utils import mps
|
||||
from game.weather.conditions import Conditions
|
||||
from qt_ui.simcontroller import SimController
|
||||
|
||||
|
||||
class QTimeTurnWidget(QGroupBox):
|
||||
"""
|
||||
UI Component to display current turn and time info
|
||||
"""
|
||||
|
||||
def __init__(self, sim_controller: SimController) -> None:
|
||||
super(QTimeTurnWidget, self).__init__("Turn")
|
||||
self.sim_controller = sim_controller
|
||||
self.setStyleSheet(
|
||||
"padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px"
|
||||
)
|
||||
|
||||
self.icons = {
|
||||
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
|
||||
TimeOfDay.Day: CONST.ICONS["Day"],
|
||||
TimeOfDay.Dusk: CONST.ICONS["Dusk"],
|
||||
TimeOfDay.Night: CONST.ICONS["Night"],
|
||||
}
|
||||
|
||||
# self.setProperty('style', 'conditions__widget--turn')
|
||||
self.layout = QHBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.daytime_icon = QLabel()
|
||||
self.daytime_icon.setPixmap(self.icons[TimeOfDay.Dawn])
|
||||
self.layout.addWidget(self.daytime_icon)
|
||||
|
||||
self.time_column = QVBoxLayout()
|
||||
self.layout.addLayout(self.time_column)
|
||||
|
||||
self.date_display = QLabel()
|
||||
self.time_column.addWidget(self.date_display)
|
||||
|
||||
self.time_display = QLabel()
|
||||
self.time_column.addWidget(self.time_display)
|
||||
|
||||
sim_controller.sim_update.connect(self.on_sim_update)
|
||||
|
||||
def on_sim_update(self, _events: GameUpdateEvents) -> None:
|
||||
time = self.sim_controller.current_time_in_sim_if_game_loaded
|
||||
if time is None:
|
||||
self.date_display.setText("")
|
||||
self.time_display.setText("")
|
||||
else:
|
||||
self.set_date_and_time(time)
|
||||
|
||||
def set_current_turn(self, turn: int, conditions: Conditions) -> None:
|
||||
"""Sets the turn information display.
|
||||
|
||||
:arg turn Current turn number.
|
||||
:arg conditions Current time and weather conditions.
|
||||
"""
|
||||
self.daytime_icon.setPixmap(self.icons[conditions.time_of_day])
|
||||
self.set_date_and_time(conditions.start_time)
|
||||
self.setTitle(f"Turn {turn}")
|
||||
|
||||
def set_date_and_time(self, time: datetime) -> None:
|
||||
self.date_display.setText(time.strftime("%d %b %Y"))
|
||||
self.time_display.setText(time.strftime("%H:%M:%S Local"))
|
||||
|
||||
|
||||
class QWeatherWidget(QGroupBox):
|
||||
"""
|
||||
UI Component to display current weather forecast
|
||||
"""
|
||||
|
||||
turn = None
|
||||
conditions = None
|
||||
|
||||
def __init__(self):
|
||||
super(QWeatherWidget, self).__init__("")
|
||||
self.setProperty("style", "QWeatherWidget")
|
||||
|
||||
self.icons = {
|
||||
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
|
||||
TimeOfDay.Day: CONST.ICONS["Day"],
|
||||
TimeOfDay.Dusk: CONST.ICONS["Dusk"],
|
||||
TimeOfDay.Night: CONST.ICONS["Night"],
|
||||
}
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.makeWeatherIcon()
|
||||
self.makeCloudRainFogWidget()
|
||||
self.makeWindsWidget()
|
||||
|
||||
def makeWeatherIcon(self):
|
||||
"""Makes the Weather Icon Widget"""
|
||||
self.weather_icon = QLabel()
|
||||
self.weather_icon.setPixmap(self.icons[TimeOfDay.Dawn])
|
||||
self.layout.addWidget(self.weather_icon)
|
||||
|
||||
def makeCloudRainFogWidget(self):
|
||||
"""Makes the Cloud, Rain, Fog Widget"""
|
||||
self.textLayout = QVBoxLayout()
|
||||
self.layout.addLayout(self.textLayout)
|
||||
|
||||
self.forecastClouds = self.makeLabel()
|
||||
self.textLayout.addWidget(self.forecastClouds)
|
||||
|
||||
self.forecastRain = self.makeLabel()
|
||||
self.textLayout.addWidget(self.forecastRain)
|
||||
|
||||
self.forecastFog = self.makeLabel()
|
||||
self.textLayout.addWidget(self.forecastFog)
|
||||
|
||||
def makeWindsWidget(self):
|
||||
"""Factory for the winds widget."""
|
||||
windsLayout = QGridLayout()
|
||||
self.layout.addLayout(windsLayout)
|
||||
|
||||
windsLayout.addWidget(self.makeIcon(CONST.ICONS["Weather_winds"]), 0, 0, 3, 1)
|
||||
|
||||
windsLayout.addWidget(self.makeLabel("At GL"), 0, 1)
|
||||
windsLayout.addWidget(self.makeLabel("At FL08"), 1, 1)
|
||||
windsLayout.addWidget(self.makeLabel("At FL26"), 2, 1)
|
||||
|
||||
self.windGLSpeedLabel = self.makeLabel("0kts")
|
||||
self.windGLDirLabel = self.makeLabel("0º")
|
||||
windsLayout.addWidget(self.windGLSpeedLabel, 0, 2)
|
||||
windsLayout.addWidget(self.windGLDirLabel, 0, 3)
|
||||
|
||||
self.windFL08SpeedLabel = self.makeLabel("0kts")
|
||||
self.windFL08DirLabel = self.makeLabel("0º")
|
||||
windsLayout.addWidget(self.windFL08SpeedLabel, 1, 2)
|
||||
windsLayout.addWidget(self.windFL08DirLabel, 1, 3)
|
||||
|
||||
self.windFL26SpeedLabel = self.makeLabel("0kts")
|
||||
self.windFL26DirLabel = self.makeLabel("0º")
|
||||
windsLayout.addWidget(self.windFL26SpeedLabel, 2, 2)
|
||||
windsLayout.addWidget(self.windFL26DirLabel, 2, 3)
|
||||
|
||||
def makeLabel(self, text: str = "") -> QLabel:
|
||||
"""Shorthand to generate a QLabel with widget standard style
|
||||
|
||||
:arg pixmap QPixmap for the icon.
|
||||
"""
|
||||
label = QLabel(text)
|
||||
label.setProperty("style", "text-sm")
|
||||
|
||||
return label
|
||||
|
||||
def makeIcon(self, pixmap: QPixmap) -> QLabel:
|
||||
"""Shorthand to generate a QIcon with pixmap.
|
||||
|
||||
:arg pixmap QPixmap for the icon.
|
||||
"""
|
||||
icon = QLabel()
|
||||
icon.setPixmap(pixmap)
|
||||
|
||||
return icon
|
||||
|
||||
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
|
||||
"""Sets the turn information display.
|
||||
|
||||
:arg turn Current turn number.
|
||||
:arg conditions Current time and weather conditions.
|
||||
"""
|
||||
self.turn = turn
|
||||
self.conditions = conditions
|
||||
|
||||
self.update_forecast()
|
||||
self.updateWinds()
|
||||
|
||||
def updateWinds(self):
|
||||
"""Updates the UI with the current conditions wind info."""
|
||||
windGlSpeed = mps(self.conditions.weather.wind.at_0m.speed or 0)
|
||||
windGlDir = str(self.conditions.weather.wind.at_0m.direction or 0).rjust(3, "0")
|
||||
self.windGLSpeedLabel.setText(f"{int(windGlSpeed.knots)}kts")
|
||||
self.windGLDirLabel.setText(f"{windGlDir}º")
|
||||
|
||||
windFL08Speed = mps(self.conditions.weather.wind.at_2000m.speed or 0)
|
||||
windFL08Dir = str(self.conditions.weather.wind.at_2000m.direction or 0).rjust(
|
||||
3, "0"
|
||||
)
|
||||
self.windFL08SpeedLabel.setText(f"{int(windFL08Speed.knots)}kts")
|
||||
self.windFL08DirLabel.setText(f"{windFL08Dir}º")
|
||||
|
||||
windFL26Speed = mps(self.conditions.weather.wind.at_8000m.speed or 0)
|
||||
windFL26Dir = str(self.conditions.weather.wind.at_8000m.direction or 0).rjust(
|
||||
3, "0"
|
||||
)
|
||||
self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts")
|
||||
self.windFL26DirLabel.setText(f"{windFL26Dir}º")
|
||||
|
||||
def update_forecast_from_preset(self, preset: CloudPreset) -> None:
|
||||
self.forecastFog.setText("No fog")
|
||||
if "Rain" in preset.name:
|
||||
self.forecastRain.setText("Rain")
|
||||
self.update_forecast_icons("rain")
|
||||
else:
|
||||
self.forecastRain.setText("No rain")
|
||||
self.update_forecast_icons("partly-cloudy")
|
||||
|
||||
# We get a description like the following for the cloud preset.
|
||||
#
|
||||
# 09 ##Two Layer Broken/Scattered \nMETAR:BKN 7.5/10 SCT 20/22 FEW41
|
||||
#
|
||||
# The second line is probably interesting but doesn't fit into the widget
|
||||
# currently, so for now just extract the first line.
|
||||
self.forecastClouds.setText(preset.description.splitlines()[0].split("##")[1])
|
||||
|
||||
def update_forecast(self):
|
||||
"""Updates the Forecast Text and icon with the current conditions wind info."""
|
||||
if (
|
||||
self.conditions.weather.clouds
|
||||
and self.conditions.weather.clouds.preset is not None
|
||||
):
|
||||
self.update_forecast_from_preset(self.conditions.weather.clouds.preset)
|
||||
return
|
||||
|
||||
if self.conditions.weather.clouds is None:
|
||||
cloud_density = 0
|
||||
precipitation = None
|
||||
else:
|
||||
cloud_density = self.conditions.weather.clouds.density
|
||||
precipitation = self.conditions.weather.clouds.precipitation
|
||||
|
||||
if not cloud_density:
|
||||
self.forecastClouds.setText("Clear")
|
||||
weather_type = "clear"
|
||||
elif cloud_density < 3:
|
||||
self.forecastClouds.setText("Partly Cloudy")
|
||||
weather_type = "partly-cloudy"
|
||||
elif cloud_density < 5:
|
||||
self.forecastClouds.setText("Mostly Cloudy")
|
||||
weather_type = "partly-cloudy"
|
||||
else:
|
||||
self.forecastClouds.setText("Totally Cloudy")
|
||||
weather_type = "partly-cloudy"
|
||||
|
||||
if precipitation == PydcsWeather.Preceptions.Rain:
|
||||
self.forecastRain.setText("Rain")
|
||||
weather_type = "rain"
|
||||
elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
|
||||
self.forecastRain.setText("Thunderstorm")
|
||||
weather_type = "thunderstorm"
|
||||
else:
|
||||
self.forecastRain.setText("No rain")
|
||||
|
||||
if not self.conditions.weather.fog is not None:
|
||||
self.forecastFog.setText("No fog")
|
||||
else:
|
||||
visibility = round(self.conditions.weather.fog.visibility.nautical_miles, 1)
|
||||
self.forecastFog.setText(f"Fog vis: {visibility}nm")
|
||||
if cloud_density > 1:
|
||||
weather_type = "cloudy-fog"
|
||||
else:
|
||||
weather_type = "fog"
|
||||
|
||||
self.update_forecast_icons(weather_type)
|
||||
|
||||
def update_forecast_icons(self, weather_type: str) -> None:
|
||||
time = "night" if self.conditions.time_of_day == TimeOfDay.Night else "day"
|
||||
icon_key = f"Weather_{time}-{weather_type}"
|
||||
icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"]
|
||||
self.weather_icon.setPixmap(icon)
|
||||
from qt_ui.widgets.QConditionsDialog import QConditionsDialog
|
||||
from qt_ui.widgets.conditions.QTimeTurnWidget import QTimeTurnWidget
|
||||
from qt_ui.widgets.conditions.QWeatherWidget import QWeatherWidget
|
||||
|
||||
|
||||
class QConditionsWidget(QFrame):
|
||||
@ -287,6 +20,7 @@ class QConditionsWidget(QFrame):
|
||||
def __init__(self, sim_controller: SimController) -> None:
|
||||
super(QConditionsWidget, self).__init__()
|
||||
self.setProperty("style", "QConditionsWidget")
|
||||
self.setCursor(QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
|
||||
|
||||
self.layout = QGridLayout()
|
||||
self.layout.setContentsMargins(0, 0, 0, 0)
|
||||
@ -305,6 +39,9 @@ class QConditionsWidget(QFrame):
|
||||
self.weather_widget.hide()
|
||||
self.layout.addWidget(self.weather_widget, 0, 1)
|
||||
|
||||
def mouseDoubleClickEvent(self, event: QtGui.QMouseEvent) -> None:
|
||||
QConditionsDialog(self.time_turn_widget, self.weather_widget).exec()
|
||||
|
||||
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
|
||||
"""Sets the turn information display.
|
||||
|
||||
|
||||
89
qt_ui/widgets/conditions/DcsCloudBaseSelector.py
Normal file
89
qt_ui/widgets/conditions/DcsCloudBaseSelector.py
Normal file
@ -0,0 +1,89 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QSlider, QSpinBox, QComboBox
|
||||
from dcs.weather import CloudPreset
|
||||
|
||||
|
||||
class DcsCloudBaseSelector(QHBoxLayout):
|
||||
M2FT_FACTOR = 3.2808399
|
||||
|
||||
def __init__(self, preset: Optional[CloudPreset]) -> None:
|
||||
super().__init__()
|
||||
self.preset = preset
|
||||
self.unit_changing = False
|
||||
|
||||
self.label = QLabel("Cloud Base: ")
|
||||
self.addWidget(self.label)
|
||||
|
||||
self.base = QSlider(Qt.Orientation.Horizontal)
|
||||
self.base.setValue(round(self.max_base - (self.max_base - self.min_base) / 2))
|
||||
self.base.valueChanged.connect(self.on_slider_change)
|
||||
self.addWidget(self.base, 1)
|
||||
|
||||
self.base_spinner = QSpinBox()
|
||||
self.base_spinner.setValue(self.base.value())
|
||||
self.base_spinner.setFixedWidth(75)
|
||||
self.base_spinner.setSingleStep(100)
|
||||
self.base_spinner.valueChanged.connect(self.update_slider)
|
||||
self.addWidget(self.base_spinner, 1)
|
||||
|
||||
self.unit = QComboBox()
|
||||
self.unit.insertItems(0, ["m", "ft"])
|
||||
self.unit.currentIndexChanged.connect(self.on_unit_change)
|
||||
self.unit.setCurrentIndex(1)
|
||||
self.addWidget(self.unit)
|
||||
|
||||
self.update_bounds()
|
||||
|
||||
@property
|
||||
def min_base(self) -> int:
|
||||
return self.preset.min_base if self.preset else 300
|
||||
|
||||
@property
|
||||
def max_base(self) -> int:
|
||||
return self.preset.max_base if self.preset else 5000
|
||||
|
||||
def update_bounds(self) -> None:
|
||||
self.base.setRange(self.min_base, self.max_base)
|
||||
index = self.unit.currentIndex()
|
||||
if index == 0:
|
||||
self.base_spinner.setRange(self.min_base, self.max_base)
|
||||
elif index == 1:
|
||||
self.base_spinner.setRange(
|
||||
self.m2ft(self.min_base), self.m2ft(self.max_base)
|
||||
)
|
||||
|
||||
def on_slider_change(self, value: int) -> None:
|
||||
if self.unit.currentIndex() == 0:
|
||||
self.base_spinner.setValue(value)
|
||||
elif self.unit.currentIndex() == 1 and not self.unit_changing:
|
||||
self.base_spinner.setValue(self.m2ft(value))
|
||||
|
||||
def update_slider(self, value: int) -> None:
|
||||
if self.unit_changing:
|
||||
return
|
||||
if self.unit.currentIndex() == 0:
|
||||
self.base.setValue(value)
|
||||
elif self.unit.currentIndex() == 1:
|
||||
self.unit_changing = True
|
||||
self.base.setValue(self.ft2m(value))
|
||||
self.unit_changing = False
|
||||
|
||||
def on_unit_change(self, index: int) -> None:
|
||||
self.unit_changing = True
|
||||
if index == 0:
|
||||
self.base_spinner.setRange(self.min_base, self.max_base)
|
||||
self.base_spinner.setValue(self.base.value())
|
||||
elif index == 1:
|
||||
self.base_spinner.setRange(
|
||||
self.m2ft(self.min_base), self.m2ft(self.max_base)
|
||||
)
|
||||
self.base_spinner.setValue(self.m2ft(self.base.value()))
|
||||
self.unit_changing = False
|
||||
|
||||
def m2ft(self, value: int) -> int:
|
||||
return round(value * self.M2FT_FACTOR)
|
||||
|
||||
def ft2m(self, value: int) -> int:
|
||||
return round(value / self.M2FT_FACTOR)
|
||||
42
qt_ui/widgets/conditions/DcsCloudDensitySelector.py
Normal file
42
qt_ui/widgets/conditions/DcsCloudDensitySelector.py
Normal file
@ -0,0 +1,42 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QSlider, QSpinBox
|
||||
from dcs.weather import CloudPreset
|
||||
|
||||
from game.weather.clouds import Clouds
|
||||
|
||||
|
||||
class DcsCloudDensitySelector(QHBoxLayout):
|
||||
def __init__(self, clouds: Clouds) -> None:
|
||||
super().__init__()
|
||||
self.unit_changing = False
|
||||
|
||||
self.label = QLabel("Density : ")
|
||||
self.addWidget(self.label)
|
||||
|
||||
self.density = QSlider(Qt.Orientation.Horizontal)
|
||||
self.density.setRange(0, 10)
|
||||
self.density.setValue(clouds.density)
|
||||
self.density.valueChanged.connect(self.on_slider_change)
|
||||
self.addWidget(self.density, 1)
|
||||
|
||||
self.density_spinner = QSpinBox()
|
||||
self.density_spinner.setValue(self.density.value())
|
||||
self.density_spinner.setFixedWidth(75)
|
||||
self.density_spinner.valueChanged.connect(self.update_slider)
|
||||
self.addWidget(self.density_spinner, 1)
|
||||
|
||||
def on_slider_change(self, value: int) -> None:
|
||||
self.density_spinner.setValue(value)
|
||||
|
||||
def update_slider(self, value: int) -> None:
|
||||
self.density.setValue(value)
|
||||
|
||||
def update_ui(self, preset: Optional[CloudPreset]) -> None:
|
||||
self.label.setVisible(preset is None)
|
||||
self.density.setVisible(preset is None)
|
||||
self.density_spinner.setVisible(preset is None)
|
||||
|
||||
if preset:
|
||||
self.density.setValue(0)
|
||||
87
qt_ui/widgets/conditions/DcsCloudThicknessSelector.py
Normal file
87
qt_ui/widgets/conditions/DcsCloudThicknessSelector.py
Normal file
@ -0,0 +1,87 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QSlider, QSpinBox, QComboBox
|
||||
from dcs.weather import CloudPreset
|
||||
|
||||
from game.weather.clouds import Clouds
|
||||
|
||||
|
||||
class DcsCloudThicknessSelector(QHBoxLayout):
|
||||
M2FT_FACTOR = 3.2808399
|
||||
|
||||
def __init__(self, clouds: Clouds) -> None:
|
||||
super().__init__()
|
||||
self.unit_changing = False
|
||||
|
||||
self.label = QLabel("Thickness : ")
|
||||
self.addWidget(self.label)
|
||||
|
||||
self.thickness = QSlider(Qt.Orientation.Horizontal)
|
||||
self.thickness.setRange(200, 2000)
|
||||
self.thickness.setValue(clouds.thickness)
|
||||
self.thickness.valueChanged.connect(self.on_slider_change)
|
||||
self.addWidget(self.thickness, 1)
|
||||
|
||||
self.thickness_spinner = QSpinBox()
|
||||
self.thickness_spinner.setValue(self.thickness.value())
|
||||
self.thickness_spinner.setFixedWidth(75)
|
||||
self.thickness_spinner.setSingleStep(100)
|
||||
self.thickness_spinner.valueChanged.connect(self.update_slider)
|
||||
self.addWidget(self.thickness_spinner, 1)
|
||||
|
||||
self.unit = QComboBox()
|
||||
self.unit.insertItems(0, ["m", "ft"])
|
||||
self.unit.currentIndexChanged.connect(self.on_unit_change)
|
||||
self.unit.setCurrentIndex(1)
|
||||
self.addWidget(self.unit)
|
||||
|
||||
def update_ui(self, preset: Optional[CloudPreset]) -> None:
|
||||
self.label.setVisible(preset is None)
|
||||
self.thickness.setVisible(preset is None)
|
||||
self.thickness_spinner.setVisible(preset is None)
|
||||
self.unit.setVisible(preset is None)
|
||||
|
||||
if preset:
|
||||
self.thickness.setValue(0)
|
||||
|
||||
def on_slider_change(self, value: int) -> None:
|
||||
if self.unit.currentIndex() == 0:
|
||||
self.thickness_spinner.setValue(value)
|
||||
elif self.unit.currentIndex() == 1 and not self.unit_changing:
|
||||
self.thickness_spinner.setValue(self.m2ft(value))
|
||||
|
||||
def update_slider(self, value: int) -> None:
|
||||
if self.unit_changing:
|
||||
return
|
||||
if self.unit.currentIndex() == 0:
|
||||
self.thickness.setValue(value)
|
||||
elif self.unit.currentIndex() == 1:
|
||||
self.unit_changing = True
|
||||
self.thickness.setValue(self.ft2m(value))
|
||||
self.unit_changing = False
|
||||
|
||||
def on_unit_change(self, index: int) -> None:
|
||||
self.unit_changing = True
|
||||
mini = (
|
||||
self.thickness.minimum()
|
||||
if index == 0
|
||||
else self.m2ft(self.thickness.minimum())
|
||||
)
|
||||
maxi = (
|
||||
self.thickness.maximum()
|
||||
if index == 0
|
||||
else self.m2ft(self.thickness.maximum())
|
||||
)
|
||||
value = (
|
||||
self.thickness.value() if index == 0 else self.m2ft(self.thickness.value())
|
||||
)
|
||||
self.thickness_spinner.setRange(mini, maxi)
|
||||
self.thickness_spinner.setValue(value)
|
||||
self.unit_changing = False
|
||||
|
||||
def m2ft(self, value: int) -> int:
|
||||
return round(value * self.M2FT_FACTOR)
|
||||
|
||||
def ft2m(self, value: int) -> int:
|
||||
return round(value / self.M2FT_FACTOR)
|
||||
28
qt_ui/widgets/conditions/DcsPrecipitationSelector.py
Normal file
28
qt_ui/widgets/conditions/DcsPrecipitationSelector.py
Normal file
@ -0,0 +1,28 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QComboBox
|
||||
from dcs.weather import Weather as PydcsWeather, CloudPreset
|
||||
|
||||
from game.weather.clouds import Clouds
|
||||
|
||||
|
||||
class DcsPrecipitationSelector(QHBoxLayout):
|
||||
def __init__(self, clouds: Clouds) -> None:
|
||||
super().__init__()
|
||||
self.unit_changing = False
|
||||
|
||||
self.label = QLabel("Precipitation : ")
|
||||
self.addWidget(self.label)
|
||||
|
||||
self.selector = QComboBox()
|
||||
for p in PydcsWeather.Preceptions:
|
||||
self.selector.addItem(p.name.replace("_", ""), p)
|
||||
|
||||
self.selector.setCurrentText(clouds.precipitation.name.replace("_", ""))
|
||||
self.addWidget(self.selector, 1)
|
||||
|
||||
def update_ui(self, preset: Optional[CloudPreset]) -> None:
|
||||
self.selector.setEnabled(preset is None)
|
||||
|
||||
if preset:
|
||||
self.selector.setCurrentText("None")
|
||||
38
qt_ui/widgets/conditions/QTimeAdjustmentWidget.py
Normal file
38
qt_ui/widgets/conditions/QTimeAdjustmentWidget.py
Normal file
@ -0,0 +1,38 @@
|
||||
from typing import Optional
|
||||
|
||||
from PySide6.QtCore import QDateTime
|
||||
from PySide6.QtWidgets import QVBoxLayout, QWidget, QLabel, QHBoxLayout, QDateTimeEdit
|
||||
|
||||
from qt_ui.widgets.conditions.QTimeTurnWidget import QTimeTurnWidget
|
||||
|
||||
|
||||
class QTimeAdjustmentWidget(QWidget):
|
||||
def __init__(
|
||||
self, time_turn: QTimeTurnWidget, parent: Optional[QWidget] = None
|
||||
) -> None:
|
||||
super().__init__(parent)
|
||||
self.current_datetime = time_turn.sim_controller.current_time_in_sim
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self) -> None:
|
||||
vbox = QVBoxLayout()
|
||||
|
||||
vbox.addWidget(QLabel("<h2><b>Time & Date:</b></h2>"))
|
||||
vbox.addWidget(
|
||||
QLabel(
|
||||
'<h4 style="color:orange"><b>WARNING: CHANGING TIME/DATE WILL RE-INITIALIZE THE TURN</b></h4>'
|
||||
)
|
||||
)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
|
||||
t = self.current_datetime.time()
|
||||
d = self.current_datetime.date()
|
||||
self.datetime_edit = QDateTimeEdit(
|
||||
QDateTime(d.year, d.month, d.day, t.hour, t.minute, t.second)
|
||||
)
|
||||
hbox.addWidget(self.datetime_edit)
|
||||
|
||||
vbox.addLayout(hbox)
|
||||
|
||||
self.setLayout(vbox)
|
||||
70
qt_ui/widgets/conditions/QTimeTurnWidget.py
Normal file
70
qt_ui/widgets/conditions/QTimeTurnWidget.py
Normal file
@ -0,0 +1,70 @@
|
||||
from datetime import datetime
|
||||
|
||||
from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QVBoxLayout
|
||||
|
||||
from game.sim import GameUpdateEvents
|
||||
from game.timeofday import TimeOfDay
|
||||
from game.weather.conditions import Conditions
|
||||
from qt_ui import uiconstants as CONST
|
||||
from qt_ui.simcontroller import SimController
|
||||
|
||||
|
||||
class QTimeTurnWidget(QGroupBox):
|
||||
"""
|
||||
UI Component to display current turn and time info
|
||||
"""
|
||||
|
||||
def __init__(self, sim_controller: SimController) -> None:
|
||||
super(QTimeTurnWidget, self).__init__("Turn")
|
||||
self.sim_controller = sim_controller
|
||||
self.setStyleSheet(
|
||||
"padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px"
|
||||
)
|
||||
|
||||
self.icons = {
|
||||
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
|
||||
TimeOfDay.Day: CONST.ICONS["Day"],
|
||||
TimeOfDay.Dusk: CONST.ICONS["Dusk"],
|
||||
TimeOfDay.Night: CONST.ICONS["Night"],
|
||||
}
|
||||
|
||||
# self.setProperty('style', 'conditions__widget--turn')
|
||||
self.layout = QHBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.daytime_icon = QLabel()
|
||||
self.daytime_icon.setPixmap(self.icons[TimeOfDay.Dawn])
|
||||
self.layout.addWidget(self.daytime_icon)
|
||||
|
||||
self.time_column = QVBoxLayout()
|
||||
self.layout.addLayout(self.time_column)
|
||||
|
||||
self.date_display = QLabel()
|
||||
self.time_column.addWidget(self.date_display)
|
||||
|
||||
self.time_display = QLabel()
|
||||
self.time_column.addWidget(self.time_display)
|
||||
|
||||
sim_controller.sim_update.connect(self.on_sim_update)
|
||||
|
||||
def on_sim_update(self, _events: GameUpdateEvents) -> None:
|
||||
time = self.sim_controller.current_time_in_sim_if_game_loaded
|
||||
if time is None:
|
||||
self.date_display.setText("")
|
||||
self.time_display.setText("")
|
||||
else:
|
||||
self.set_date_and_time(time)
|
||||
|
||||
def set_current_turn(self, turn: int, conditions: Conditions) -> None:
|
||||
"""Sets the turn information display.
|
||||
|
||||
:arg turn Current turn number.
|
||||
:arg conditions Current time and weather conditions.
|
||||
"""
|
||||
self.daytime_icon.setPixmap(self.icons[conditions.time_of_day])
|
||||
self.set_date_and_time(conditions.start_time)
|
||||
self.setTitle(f"Turn {turn}")
|
||||
|
||||
def set_date_and_time(self, time: datetime) -> None:
|
||||
self.date_display.setText(time.strftime("%d %b %Y"))
|
||||
self.time_display.setText(time.strftime("%H:%M:%S Local"))
|
||||
94
qt_ui/widgets/conditions/QWeatherAdjustmentWidget.py
Normal file
94
qt_ui/widgets/conditions/QWeatherAdjustmentWidget.py
Normal file
@ -0,0 +1,94 @@
|
||||
from PySide6.QtWidgets import QLabel, QHBoxLayout, QComboBox, QWidget, QVBoxLayout
|
||||
from dcs.cloud_presets import CLOUD_PRESETS
|
||||
|
||||
from game.weather.weather import ClearSkies, Cloudy, Raining, Thunderstorm
|
||||
from qt_ui.widgets.conditions.DcsCloudBaseSelector import DcsCloudBaseSelector
|
||||
from qt_ui.widgets.conditions.DcsCloudDensitySelector import DcsCloudDensitySelector
|
||||
from qt_ui.widgets.conditions.DcsCloudThicknessSelector import DcsCloudThicknessSelector
|
||||
from qt_ui.widgets.conditions.DcsPrecipitationSelector import DcsPrecipitationSelector
|
||||
from qt_ui.widgets.conditions.QWeatherWidget import QWeatherWidget
|
||||
|
||||
|
||||
class QWeatherAdjustmentWidget(QWidget):
|
||||
def __init__(self, weather: QWeatherWidget) -> None:
|
||||
super().__init__()
|
||||
self.weather = weather
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self) -> None:
|
||||
weather = self.weather.conditions.weather
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
label = QLabel("<h2><b>Weather:</b></h2>")
|
||||
label.setMaximumHeight(75)
|
||||
vbox.addWidget(label)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addWidget(QLabel("Type"))
|
||||
self.type_selector = QComboBox()
|
||||
for text, w_type in [
|
||||
("Clear", ClearSkies),
|
||||
("Clouds", Cloudy),
|
||||
("Rain", Raining),
|
||||
("Thunderstorm", Thunderstorm),
|
||||
]:
|
||||
self.type_selector.addItem(text, w_type)
|
||||
if isinstance(weather, w_type):
|
||||
self.type_selector.setCurrentText(text)
|
||||
self.type_selector.currentIndexChanged.connect(self.update_ui_for_type)
|
||||
hbox.addWidget(self.type_selector)
|
||||
vbox.addLayout(hbox)
|
||||
|
||||
label = QLabel("<h3><b>Clouds:</b></h3>")
|
||||
label.setMaximumHeight(50)
|
||||
vbox.addWidget(label)
|
||||
|
||||
hbox = QHBoxLayout()
|
||||
hbox.addWidget(QLabel("Preset"))
|
||||
self.preset_selector = QComboBox()
|
||||
for _, preset in CLOUD_PRESETS.items():
|
||||
self.preset_selector.addItem(preset.value.ui_name, preset.value)
|
||||
self.preset_selector.addItem("Custom", None)
|
||||
self.preset_selector.setCurrentText(
|
||||
weather.clouds.preset.ui_name
|
||||
if weather.clouds and weather.clouds.preset
|
||||
else "Custom"
|
||||
)
|
||||
self.preset_selector.currentIndexChanged.connect(self.update_ui)
|
||||
hbox.addWidget(self.preset_selector)
|
||||
vbox.addLayout(hbox)
|
||||
|
||||
self.cloud_base = DcsCloudBaseSelector(self.preset_selector.currentData())
|
||||
vbox.addLayout(self.cloud_base)
|
||||
|
||||
clouds = self.weather.conditions.weather.clouds
|
||||
|
||||
self.cloud_thickness = DcsCloudThicknessSelector(clouds)
|
||||
vbox.addLayout(self.cloud_thickness)
|
||||
|
||||
self.cloud_density = DcsCloudDensitySelector(clouds)
|
||||
vbox.addLayout(self.cloud_density)
|
||||
|
||||
self.precipitation = DcsPrecipitationSelector(clouds)
|
||||
vbox.addLayout(self.precipitation)
|
||||
|
||||
self.setLayout(vbox)
|
||||
|
||||
self.update_ui_for_type()
|
||||
|
||||
def update_ui_for_type(self) -> None:
|
||||
if self.type_selector.currentData() in [ClearSkies, Thunderstorm]:
|
||||
self.preset_selector.setCurrentText("Custom")
|
||||
self.preset_selector.setDisabled(True)
|
||||
else:
|
||||
self.preset_selector.setDisabled(False)
|
||||
|
||||
self.update_ui()
|
||||
|
||||
def update_ui(self) -> None:
|
||||
preset = self.preset_selector.currentData()
|
||||
self.cloud_base.preset = preset
|
||||
self.cloud_base.update_bounds()
|
||||
self.cloud_thickness.update_ui(preset)
|
||||
self.cloud_density.update_ui(preset)
|
||||
self.precipitation.update_ui(preset)
|
||||
207
qt_ui/widgets/conditions/QWeatherWidget.py
Normal file
207
qt_ui/widgets/conditions/QWeatherWidget.py
Normal file
@ -0,0 +1,207 @@
|
||||
from PySide6.QtGui import QPixmap
|
||||
from PySide6.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QVBoxLayout, QGridLayout
|
||||
from dcs.weather import CloudPreset, Weather as PydcsWeather
|
||||
|
||||
from game.timeofday import TimeOfDay
|
||||
from game.utils import mps
|
||||
from game.weather.conditions import Conditions
|
||||
from qt_ui import uiconstants as CONST
|
||||
|
||||
|
||||
class QWeatherWidget(QGroupBox):
|
||||
"""
|
||||
UI Component to display current weather forecast
|
||||
"""
|
||||
|
||||
turn = None
|
||||
conditions = None
|
||||
|
||||
def __init__(self):
|
||||
super(QWeatherWidget, self).__init__("")
|
||||
self.setProperty("style", "QWeatherWidget")
|
||||
|
||||
self.icons = {
|
||||
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
|
||||
TimeOfDay.Day: CONST.ICONS["Day"],
|
||||
TimeOfDay.Dusk: CONST.ICONS["Dusk"],
|
||||
TimeOfDay.Night: CONST.ICONS["Night"],
|
||||
}
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.makeWeatherIcon()
|
||||
self.makeCloudRainFogWidget()
|
||||
self.makeWindsWidget()
|
||||
|
||||
def makeWeatherIcon(self):
|
||||
"""Makes the Weather Icon Widget"""
|
||||
self.weather_icon = QLabel()
|
||||
self.weather_icon.setPixmap(self.icons[TimeOfDay.Dawn])
|
||||
self.layout.addWidget(self.weather_icon)
|
||||
|
||||
def makeCloudRainFogWidget(self):
|
||||
"""Makes the Cloud, Rain, Fog Widget"""
|
||||
self.textLayout = QVBoxLayout()
|
||||
self.layout.addLayout(self.textLayout)
|
||||
|
||||
self.forecastClouds = self.makeLabel()
|
||||
self.textLayout.addWidget(self.forecastClouds)
|
||||
|
||||
self.forecastRain = self.makeLabel()
|
||||
self.textLayout.addWidget(self.forecastRain)
|
||||
|
||||
self.forecastFog = self.makeLabel()
|
||||
self.textLayout.addWidget(self.forecastFog)
|
||||
|
||||
def makeWindsWidget(self):
|
||||
"""Factory for the winds widget."""
|
||||
windsLayout = QGridLayout()
|
||||
self.layout.addLayout(windsLayout)
|
||||
|
||||
windsLayout.addWidget(self.makeIcon(CONST.ICONS["Weather_winds"]), 0, 0, 3, 1)
|
||||
|
||||
windsLayout.addWidget(self.makeLabel("At GL"), 0, 1)
|
||||
windsLayout.addWidget(self.makeLabel("At FL08"), 1, 1)
|
||||
windsLayout.addWidget(self.makeLabel("At FL26"), 2, 1)
|
||||
|
||||
self.windGLSpeedLabel = self.makeLabel("0kts")
|
||||
self.windGLDirLabel = self.makeLabel("0º")
|
||||
windsLayout.addWidget(self.windGLSpeedLabel, 0, 2)
|
||||
windsLayout.addWidget(self.windGLDirLabel, 0, 3)
|
||||
|
||||
self.windFL08SpeedLabel = self.makeLabel("0kts")
|
||||
self.windFL08DirLabel = self.makeLabel("0º")
|
||||
windsLayout.addWidget(self.windFL08SpeedLabel, 1, 2)
|
||||
windsLayout.addWidget(self.windFL08DirLabel, 1, 3)
|
||||
|
||||
self.windFL26SpeedLabel = self.makeLabel("0kts")
|
||||
self.windFL26DirLabel = self.makeLabel("0º")
|
||||
windsLayout.addWidget(self.windFL26SpeedLabel, 2, 2)
|
||||
windsLayout.addWidget(self.windFL26DirLabel, 2, 3)
|
||||
|
||||
def makeLabel(self, text: str = "") -> QLabel:
|
||||
"""Shorthand to generate a QLabel with widget standard style
|
||||
|
||||
:arg pixmap QPixmap for the icon.
|
||||
"""
|
||||
label = QLabel(text)
|
||||
label.setProperty("style", "text-sm")
|
||||
|
||||
return label
|
||||
|
||||
def makeIcon(self, pixmap: QPixmap) -> QLabel:
|
||||
"""Shorthand to generate a QIcon with pixmap.
|
||||
|
||||
:arg pixmap QPixmap for the icon.
|
||||
"""
|
||||
icon = QLabel()
|
||||
icon.setPixmap(pixmap)
|
||||
|
||||
return icon
|
||||
|
||||
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
|
||||
"""Sets the turn information display.
|
||||
|
||||
:arg turn Current turn number.
|
||||
:arg conditions Current time and weather conditions.
|
||||
"""
|
||||
self.turn = turn
|
||||
self.conditions = conditions
|
||||
|
||||
self.update_forecast()
|
||||
self.updateWinds()
|
||||
|
||||
def updateWinds(self):
|
||||
"""Updates the UI with the current conditions wind info."""
|
||||
windGlSpeed = mps(self.conditions.weather.wind.at_0m.speed or 0)
|
||||
windGlDir = str(self.conditions.weather.wind.at_0m.direction or 0).rjust(3, "0")
|
||||
self.windGLSpeedLabel.setText(f"{int(windGlSpeed.knots)}kts")
|
||||
self.windGLDirLabel.setText(f"{windGlDir}º")
|
||||
|
||||
windFL08Speed = mps(self.conditions.weather.wind.at_2000m.speed or 0)
|
||||
windFL08Dir = str(self.conditions.weather.wind.at_2000m.direction or 0).rjust(
|
||||
3, "0"
|
||||
)
|
||||
self.windFL08SpeedLabel.setText(f"{int(windFL08Speed.knots)}kts")
|
||||
self.windFL08DirLabel.setText(f"{windFL08Dir}º")
|
||||
|
||||
windFL26Speed = mps(self.conditions.weather.wind.at_8000m.speed or 0)
|
||||
windFL26Dir = str(self.conditions.weather.wind.at_8000m.direction or 0).rjust(
|
||||
3, "0"
|
||||
)
|
||||
self.windFL26SpeedLabel.setText(f"{int(windFL26Speed.knots)}kts")
|
||||
self.windFL26DirLabel.setText(f"{windFL26Dir}º")
|
||||
|
||||
def update_forecast_from_preset(self, preset: CloudPreset) -> None:
|
||||
self.forecastFog.setText("No fog")
|
||||
if "Rain" in preset.name:
|
||||
self.forecastRain.setText("Rain")
|
||||
self.update_forecast_icons("rain")
|
||||
else:
|
||||
self.forecastRain.setText("No rain")
|
||||
self.update_forecast_icons("partly-cloudy")
|
||||
|
||||
# We get a description like the following for the cloud preset.
|
||||
#
|
||||
# 09 ##Two Layer Broken/Scattered \nMETAR:BKN 7.5/10 SCT 20/22 FEW41
|
||||
#
|
||||
# The second line is probably interesting but doesn't fit into the widget
|
||||
# currently, so for now just extract the first line.
|
||||
self.forecastClouds.setText(preset.description.splitlines()[0].split("##")[1])
|
||||
|
||||
def update_forecast(self):
|
||||
"""Updates the Forecast Text and icon with the current conditions wind info."""
|
||||
if (
|
||||
self.conditions.weather.clouds
|
||||
and self.conditions.weather.clouds.preset is not None
|
||||
):
|
||||
self.update_forecast_from_preset(self.conditions.weather.clouds.preset)
|
||||
return
|
||||
|
||||
if self.conditions.weather.clouds is None:
|
||||
cloud_density = 0
|
||||
precipitation = None
|
||||
else:
|
||||
cloud_density = self.conditions.weather.clouds.density
|
||||
precipitation = self.conditions.weather.clouds.precipitation
|
||||
|
||||
if not cloud_density:
|
||||
self.forecastClouds.setText("Clear")
|
||||
weather_type = "clear"
|
||||
elif cloud_density < 3:
|
||||
self.forecastClouds.setText("Partly Cloudy")
|
||||
weather_type = "partly-cloudy"
|
||||
elif cloud_density < 5:
|
||||
self.forecastClouds.setText("Mostly Cloudy")
|
||||
weather_type = "partly-cloudy"
|
||||
else:
|
||||
self.forecastClouds.setText("Totally Cloudy")
|
||||
weather_type = "partly-cloudy"
|
||||
|
||||
if precipitation == PydcsWeather.Preceptions.Rain:
|
||||
self.forecastRain.setText("Rain")
|
||||
weather_type = "rain"
|
||||
elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
|
||||
self.forecastRain.setText("Thunderstorm")
|
||||
weather_type = "thunderstorm"
|
||||
else:
|
||||
self.forecastRain.setText("No rain")
|
||||
|
||||
if not self.conditions.weather.fog is not None:
|
||||
self.forecastFog.setText("No fog")
|
||||
else:
|
||||
visibility = round(self.conditions.weather.fog.visibility.nautical_miles, 1)
|
||||
self.forecastFog.setText(f"Fog vis: {visibility}nm")
|
||||
if cloud_density > 1:
|
||||
weather_type = "cloudy-fog"
|
||||
else:
|
||||
weather_type = "fog"
|
||||
|
||||
self.update_forecast_icons(weather_type)
|
||||
|
||||
def update_forecast_icons(self, weather_type: str) -> None:
|
||||
time = "night" if self.conditions.time_of_day == TimeOfDay.Night else "day"
|
||||
icon_key = f"Weather_{time}-{weather_type}"
|
||||
icon = CONST.ICONS.get(icon_key) or CONST.ICONS["Weather_night-partly-cloudy"]
|
||||
self.weather_icon.setPixmap(icon)
|
||||
@ -590,6 +590,11 @@ QFrame[style="QConditionsWidget"] {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
QFrame[style="QConditionsWidget"]:hover {
|
||||
cursor: pointer;
|
||||
background: #43A6C6;
|
||||
}
|
||||
|
||||
QGroupBox[style="QWeatherWidget"] {
|
||||
padding: 0px;
|
||||
margin-left: 0px;
|
||||
@ -664,3 +669,7 @@ QCalendarWidget QTableView{
|
||||
.comms {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user