Fix None dereferences in weather UI.

Also normalizes line endings.
This commit is contained in:
Dan Albert 2020-11-25 14:35:27 -08:00
parent afabf6fd00
commit 75ea5cc462
2 changed files with 285 additions and 280 deletions

View File

@ -1,265 +1,270 @@
from PySide2.QtCore import Qt from PySide2.QtCore import Qt
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QVBoxLayout, QFrame, QGridLayout from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QVBoxLayout, QFrame, QGridLayout
from PySide2.QtGui import QPixmap from PySide2.QtGui import QPixmap
from game.weather import Conditions, TimeOfDay, Weather from game.weather import Conditions, TimeOfDay, Weather
from game.utils import meter_to_nm, mps_to_knots from game.utils import meter_to_nm, mps_to_knots
from dcs.weather import Weather as PydcsWeather from dcs.weather import Weather as PydcsWeather
from qt_ui.windows.weather.QWeatherInfoWindow import QWeatherInfoWindow from qt_ui.windows.weather.QWeatherInfoWindow import QWeatherInfoWindow
import qt_ui.uiconstants as CONST import qt_ui.uiconstants as CONST
class QTimeTurnWidget(QGroupBox): class QTimeTurnWidget(QGroupBox):
""" """
UI Component to display current turn and time info UI Component to display current turn and time info
""" """
def __init__(self): def __init__(self):
super(QTimeTurnWidget, self).__init__("Turn") super(QTimeTurnWidget, self).__init__("Turn")
self.setStyleSheet('padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px') self.setStyleSheet('padding: 0px; margin-left: 5px; margin-right: 0px; margin-top: 1ex; margin-bottom: 5px; border-right: 0px')
self.icons = { self.icons = {
TimeOfDay.Dawn: CONST.ICONS["Dawn"], TimeOfDay.Dawn: CONST.ICONS["Dawn"],
TimeOfDay.Day: CONST.ICONS["Day"], TimeOfDay.Day: CONST.ICONS["Day"],
TimeOfDay.Dusk: CONST.ICONS["Dusk"], TimeOfDay.Dusk: CONST.ICONS["Dusk"],
TimeOfDay.Night: CONST.ICONS["Night"], TimeOfDay.Night: CONST.ICONS["Night"],
} }
# self.setProperty('style', 'conditions__widget--turn') # self.setProperty('style', 'conditions__widget--turn')
self.layout = QHBoxLayout() self.layout = QHBoxLayout()
self.setLayout(self.layout) self.setLayout(self.layout)
self.daytime_icon = QLabel() self.daytime_icon = QLabel()
self.daytime_icon.setPixmap(self.icons[TimeOfDay.Dawn]) self.daytime_icon.setPixmap(self.icons[TimeOfDay.Dawn])
self.layout.addWidget(self.daytime_icon) self.layout.addWidget(self.daytime_icon)
self.time_column = QVBoxLayout() self.time_column = QVBoxLayout()
self.layout.addLayout(self.time_column) self.layout.addLayout(self.time_column)
self.date_display = QLabel() self.date_display = QLabel()
self.time_column.addWidget(self.date_display) self.time_column.addWidget(self.date_display)
self.time_display = QLabel() self.time_display = QLabel()
self.time_column.addWidget(self.time_display) self.time_column.addWidget(self.time_display)
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None: def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
"""Sets the turn information display. """Sets the turn information display.
:arg turn Current turn number. :arg turn Current turn number.
:arg conditions Current time and weather conditions. :arg conditions Current time and weather conditions.
""" """
self.daytime_icon.setPixmap(self.icons[conditions.time_of_day]) self.daytime_icon.setPixmap(self.icons[conditions.time_of_day])
self.date_display.setText(conditions.start_time.strftime("%d %b %Y")) self.date_display.setText(conditions.start_time.strftime("%d %b %Y"))
self.time_display.setText( self.time_display.setText(
conditions.start_time.strftime("%H:%M:%S Local")) conditions.start_time.strftime("%H:%M:%S Local"))
self.setTitle("Turn " + str(turn + 1)) self.setTitle("Turn " + str(turn + 1))
class QWeatherWidget(QGroupBox): class QWeatherWidget(QGroupBox):
""" """
UI Component to display current weather forecast UI Component to display current weather forecast
""" """
turn = None turn = None
conditions = None conditions = None
def __init__(self): def __init__(self):
super(QWeatherWidget, self).__init__("") super(QWeatherWidget, self).__init__("")
self.setProperty('style', 'QWeatherWidget') self.setProperty('style', 'QWeatherWidget')
self.icons = { self.icons = {
TimeOfDay.Dawn: CONST.ICONS["Dawn"], TimeOfDay.Dawn: CONST.ICONS["Dawn"],
TimeOfDay.Day: CONST.ICONS["Day"], TimeOfDay.Day: CONST.ICONS["Day"],
TimeOfDay.Dusk: CONST.ICONS["Dusk"], TimeOfDay.Dusk: CONST.ICONS["Dusk"],
TimeOfDay.Night: CONST.ICONS["Night"], TimeOfDay.Night: CONST.ICONS["Night"],
} }
self.layout = QHBoxLayout() self.layout = QHBoxLayout()
self.setLayout(self.layout) self.setLayout(self.layout)
self.makeWeatherIcon() self.makeWeatherIcon()
self.makeCloudRainFogWidget() self.makeCloudRainFogWidget()
self.makeWindsWidget() self.makeWindsWidget()
def makeWeatherIcon(self): def makeWeatherIcon(self):
"""Makes the Weather Icon Widget """Makes the Weather Icon Widget
""" """
self.weather_icon = QLabel() self.weather_icon = QLabel()
self.weather_icon.setPixmap(self.icons[TimeOfDay.Dawn]) self.weather_icon.setPixmap(self.icons[TimeOfDay.Dawn])
self.layout.addWidget(self.weather_icon) self.layout.addWidget(self.weather_icon)
def makeCloudRainFogWidget(self): def makeCloudRainFogWidget(self):
"""Makes the Cloud, Rain, Fog Widget """Makes the Cloud, Rain, Fog Widget
""" """
self.textLayout = QVBoxLayout() self.textLayout = QVBoxLayout()
self.layout.addLayout(self.textLayout) self.layout.addLayout(self.textLayout)
self.forecastClouds = self.makeLabel() self.forecastClouds = self.makeLabel()
self.textLayout.addWidget(self.forecastClouds) self.textLayout.addWidget(self.forecastClouds)
self.forecastRain = self.makeLabel() self.forecastRain = self.makeLabel()
self.textLayout.addWidget(self.forecastRain) self.textLayout.addWidget(self.forecastRain)
self.forecastFog = self.makeLabel() self.forecastFog = self.makeLabel()
self.textLayout.addWidget(self.forecastFog) self.textLayout.addWidget(self.forecastFog)
def makeWindsWidget(self): def makeWindsWidget(self):
"""Factory for the winds widget. """Factory for the winds widget.
""" """
windsLayout = QGridLayout() windsLayout = QGridLayout()
self.layout.addLayout(windsLayout) self.layout.addLayout(windsLayout)
windsLayout.addWidget(self.makeIcon(CONST.ICONS['Weather_winds']), 0, 0, 3, 1) 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 GL'), 0, 1)
windsLayout.addWidget(self.makeLabel('At FL08'), 1, 1) windsLayout.addWidget(self.makeLabel('At FL08'), 1, 1)
windsLayout.addWidget(self.makeLabel('At FL26'), 2, 1) windsLayout.addWidget(self.makeLabel('At FL26'), 2, 1)
self.windGLSpeedLabel = self.makeLabel('0kts') self.windGLSpeedLabel = self.makeLabel('0kts')
self.windGLDirLabel = self.makeLabel('') self.windGLDirLabel = self.makeLabel('')
windsLayout.addWidget(self.windGLSpeedLabel, 0, 2) windsLayout.addWidget(self.windGLSpeedLabel, 0, 2)
windsLayout.addWidget(self.windGLDirLabel, 0, 3) windsLayout.addWidget(self.windGLDirLabel, 0, 3)
self.windFL08SpeedLabel = self.makeLabel('0kts') self.windFL08SpeedLabel = self.makeLabel('0kts')
self.windFL08DirLabel = self.makeLabel('') self.windFL08DirLabel = self.makeLabel('')
windsLayout.addWidget(self.windFL08SpeedLabel, 1, 2) windsLayout.addWidget(self.windFL08SpeedLabel, 1, 2)
windsLayout.addWidget(self.windFL08DirLabel, 1, 3) windsLayout.addWidget(self.windFL08DirLabel, 1, 3)
self.windFL26SpeedLabel = self.makeLabel('0kts') self.windFL26SpeedLabel = self.makeLabel('0kts')
self.windFL26DirLabel = self.makeLabel('') self.windFL26DirLabel = self.makeLabel('')
windsLayout.addWidget(self.windFL26SpeedLabel, 2, 2) windsLayout.addWidget(self.windFL26SpeedLabel, 2, 2)
windsLayout.addWidget(self.windFL26DirLabel, 2, 3) windsLayout.addWidget(self.windFL26DirLabel, 2, 3)
def makeLabel(self, text: str = '') -> QLabel: def makeLabel(self, text: str = '') -> QLabel:
"""Shorthand to generate a QLabel with widget standard style """Shorthand to generate a QLabel with widget standard style
:arg pixmap QPixmap for the icon. :arg pixmap QPixmap for the icon.
""" """
label = QLabel(text) label = QLabel(text)
label.setProperty('style', 'text-sm') label.setProperty('style', 'text-sm')
return label return label
def makeIcon(self, pixmap: QPixmap) -> QLabel: def makeIcon(self, pixmap: QPixmap) -> QLabel:
"""Shorthand to generate a QIcon with pixmap. """Shorthand to generate a QIcon with pixmap.
:arg pixmap QPixmap for the icon. :arg pixmap QPixmap for the icon.
""" """
icon = QLabel() icon = QLabel()
icon.setPixmap(pixmap) icon.setPixmap(pixmap)
return icon return icon
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None: def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
"""Sets the turn information display. """Sets the turn information display.
:arg turn Current turn number. :arg turn Current turn number.
:arg conditions Current time and weather conditions. :arg conditions Current time and weather conditions.
""" """
self.turn = turn self.turn = turn
self.conditions = conditions self.conditions = conditions
self.updateForecast() self.updateForecast()
self.updateWinds() self.updateWinds()
def updateWinds(self): def updateWinds(self):
"""Updates the UI with the current conditions wind info. """Updates the UI with the current conditions wind info.
""" """
windGlSpeed = mps_to_knots(self.conditions.weather.wind.at_0m.speed or 0) windGlSpeed = mps_to_knots(self.conditions.weather.wind.at_0m.speed or 0)
windGlDir = self.conditions.weather.wind.at_0m.direction or 0 windGlDir = self.conditions.weather.wind.at_0m.direction or 0
self.windGLSpeedLabel.setText('{}kts'.format(windGlSpeed)) self.windGLSpeedLabel.setText('{}kts'.format(windGlSpeed))
self.windGLDirLabel.setText('{}º'.format(windGlDir)) self.windGLDirLabel.setText('{}º'.format(windGlDir))
windFL08Speed = mps_to_knots(self.conditions.weather.wind.at_2000m.speed or 0) windFL08Speed = mps_to_knots(self.conditions.weather.wind.at_2000m.speed or 0)
windFL08Dir = self.conditions.weather.wind.at_2000m.direction or 0 windFL08Dir = self.conditions.weather.wind.at_2000m.direction or 0
self.windFL08SpeedLabel.setText('{}kts'.format(windFL08Speed)) self.windFL08SpeedLabel.setText('{}kts'.format(windFL08Speed))
self.windFL08DirLabel.setText('{}º'.format(windFL08Dir)) self.windFL08DirLabel.setText('{}º'.format(windFL08Dir))
windFL26Speed = mps_to_knots(self.conditions.weather.wind.at_8000m.speed or 0) windFL26Speed = mps_to_knots(self.conditions.weather.wind.at_8000m.speed or 0)
windFL26Dir = self.conditions.weather.wind.at_8000m.direction or 0 windFL26Dir = self.conditions.weather.wind.at_8000m.direction or 0
self.windFL26SpeedLabel.setText('{}kts'.format(windFL26Speed)) self.windFL26SpeedLabel.setText('{}kts'.format(windFL26Speed))
self.windFL26DirLabel.setText('{}º'.format(windFL26Dir)) self.windFL26DirLabel.setText('{}º'.format(windFL26Dir))
def updateForecast(self): def updateForecast(self):
"""Updates the Forecast Text and icon with the current conditions wind info. """Updates the Forecast Text and icon with the current conditions wind info.
""" """
icon = [] icon = []
cloudDensity = self.conditions.weather.clouds.density or 0 if self.conditions.weather.clouds is None:
precipitation = self.conditions.weather.clouds.precipitation or None cloudDensity = 0
fog = self.conditions.weather.fog or None precipitation = None
is_night = self.conditions.time_of_day == TimeOfDay.Night else:
time = 'night' if is_night else 'day' cloudDensity = self.conditions.weather.clouds.density
precipitation = self.conditions.weather.clouds.precipitation
if cloudDensity <= 0:
self.forecastClouds.setText('Sunny') fog = self.conditions.weather.fog or None
icon = [time, 'clear'] is_night = self.conditions.time_of_day == TimeOfDay.Night
time = 'night' if is_night else 'day'
if cloudDensity > 0 and cloudDensity < 3:
self.forecastClouds.setText('Partly Cloudy') if cloudDensity <= 0:
icon = [time, 'partly-cloudy'] self.forecastClouds.setText('Sunny')
icon = [time, 'clear']
if cloudDensity >= 3 and cloudDensity < 5:
self.forecastClouds.setText('Mostly Cloudy') if cloudDensity > 0 and cloudDensity < 3:
icon = [time, 'partly-cloudy'] self.forecastClouds.setText('Partly Cloudy')
icon = [time, 'partly-cloudy']
if cloudDensity >= 5:
self.forecastClouds.setText('Totally Cloudy') if cloudDensity >= 3 and cloudDensity < 5:
icon = [time, 'partly-cloudy'] self.forecastClouds.setText('Mostly Cloudy')
icon = [time, 'partly-cloudy']
if precipitation == PydcsWeather.Preceptions.Rain:
self.forecastRain.setText('Rain') if cloudDensity >= 5:
icon = [time, 'rain'] self.forecastClouds.setText('Totally Cloudy')
icon = [time, 'partly-cloudy']
elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
self.forecastRain.setText('Thunderstorm') if precipitation == PydcsWeather.Preceptions.Rain:
icon = [time, 'thunderstorm'] self.forecastRain.setText('Rain')
icon = [time, 'rain']
else:
self.forecastRain.setText('No Rain') elif precipitation == PydcsWeather.Preceptions.Thunderstorm:
self.forecastRain.setText('Thunderstorm')
if not fog: icon = [time, 'thunderstorm']
self.forecastFog.setText('No fog')
else: else:
visvibilityNm = round(meter_to_nm(fog.visibility), 1) self.forecastRain.setText('No Rain')
self.forecastFog.setText('Fog vis: {}nm'.format(visvibilityNm))
icon = [time, ('cloudy' if cloudDensity > 1 else None), 'fog'] if not fog:
self.forecastFog.setText('No fog')
else:
icon_key = "Weather_{}".format('-'.join(filter(None.__ne__, icon))) visvibilityNm = round(meter_to_nm(fog.visibility), 1)
icon = CONST.ICONS.get(icon_key) or CONST.ICONS['Weather_night-partly-cloudy'] self.forecastFog.setText('Fog vis: {}nm'.format(visvibilityNm))
self.weather_icon.setPixmap(icon) icon = [time, ('cloudy' if cloudDensity > 1 else None), 'fog']
class QConditionsWidget(QFrame): icon_key = "Weather_{}".format('-'.join(filter(None.__ne__, icon)))
""" icon = CONST.ICONS.get(icon_key) or CONST.ICONS['Weather_night-partly-cloudy']
UI Component to display Turn Number, Day Time & Hour and weather combined. self.weather_icon.setPixmap(icon)
"""
def __init__(self): class QConditionsWidget(QFrame):
super(QConditionsWidget, self).__init__() """
self.setProperty('style', 'QConditionsWidget') UI Component to display Turn Number, Day Time & Hour and weather combined.
"""
self.layout = QGridLayout()
self.layout.setContentsMargins(0, 0, 0, 0) def __init__(self):
self.layout.setHorizontalSpacing(0) super(QConditionsWidget, self).__init__()
self.layout.setVerticalSpacing(0) self.setProperty('style', 'QConditionsWidget')
self.setLayout(self.layout)
self.layout = QGridLayout()
self.time_turn_widget = QTimeTurnWidget() self.layout.setContentsMargins(0, 0, 0, 0)
self.time_turn_widget.setStyleSheet('QGroupBox { margin-right: 0px; }') self.layout.setHorizontalSpacing(0)
self.layout.addWidget(self.time_turn_widget, 0, 0) self.layout.setVerticalSpacing(0)
self.setLayout(self.layout)
self.weather_widget = QWeatherWidget()
self.weather_widget.setStyleSheet('QGroupBox { margin-top: 5px; margin-left: 0px; border-left: 0px; }') self.time_turn_widget = QTimeTurnWidget()
self.weather_widget.hide() self.time_turn_widget.setStyleSheet('QGroupBox { margin-right: 0px; }')
self.layout.addWidget(self.weather_widget, 0, 1) self.layout.addWidget(self.time_turn_widget, 0, 0)
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None: self.weather_widget = QWeatherWidget()
"""Sets the turn information display. self.weather_widget.setStyleSheet('QGroupBox { margin-top: 5px; margin-left: 0px; border-left: 0px; }')
self.weather_widget.hide()
:arg turn Current turn number. self.layout.addWidget(self.weather_widget, 0, 1)
:arg conditions Current time and weather conditions.
""" def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
self.time_turn_widget.setCurrentTurn(turn, conditions) """Sets the turn information display.
self.weather_widget.setCurrentTurn(turn, conditions)
self.weather_widget.show() :arg turn Current turn number.
:arg conditions Current time and weather conditions.
"""
self.time_turn_widget.setCurrentTurn(turn, conditions)
self.weather_widget.setCurrentTurn(turn, conditions)
self.weather_widget.show()

View File

@ -1,16 +1,16 @@
from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QFrame, QSizePolicy from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QFrame, QSizePolicy
from game.game import Game from game.game import Game
from game.weather import Conditions, TimeOfDay, Weather from game.weather import Conditions, TimeOfDay, Weather
import qt_ui.uiconstants as CONST import qt_ui.uiconstants as CONST
class QWeatherInfoWindow(QDialog): class QWeatherInfoWindow(QDialog):
def __init__(self, turn: int, conditions: Conditions): def __init__(self, turn: int, conditions: Conditions):
super(QWeatherInfoWindow, self).__init__() super(QWeatherInfoWindow, self).__init__()
self.setModal(True) self.setModal(True)
self.setWindowTitle("Weather Forecast Report") self.setWindowTitle("Weather Forecast Report")
self.setWindowIcon(CONST.ICONS["Money"]) self.setWindowIcon(CONST.ICONS["Money"])
self.setMinimumSize(450, 200) self.setMinimumSize(450, 200)