From 432116a13d989cd7422599f761dda17e9c94b042 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sat, 30 Mar 2019 22:52:26 +0100 Subject: [PATCH 01/11] Create screen for Rx/Tx --- artemis.py | 3 +- artemis.ui | 805 +++++- forecast_data.py | 44 + icons_imgs/search_icon.png | Bin 5486 -> 0 bytes icons_imgs/volume.png | Bin 34475 -> 0 bytes main_window.ui | 4916 ------------------------------------ switchable_label.py | 37 + threads.py | 3 - 8 files changed, 885 insertions(+), 4923 deletions(-) create mode 100644 forecast_data.py delete mode 100644 icons_imgs/search_icon.png delete mode 100644 icons_imgs/volume.png delete mode 100644 main_window.ui create mode 100644 switchable_label.py diff --git a/artemis.py b/artemis.py index 759d21c..cf9cb99 100644 --- a/artemis.py +++ b/artemis.py @@ -26,7 +26,7 @@ from audio_player import AudioPlayer from double_text_button import DoubleTextButton from download_window import DownloadWindow - +from switchable_label import SwitchableLabel, SwitchableLabelIterable from constants import (Constants, Ftype, GfdType, @@ -35,7 +35,6 @@ from constants import (Constants, Messages, Signal,) from themes import Theme - from utilities import (checksum_ok, uncheck_and_emit, pop_up, diff --git a/artemis.ui b/artemis.ui index 07569d2..61e4b3d 100644 --- a/artemis.ui +++ b/artemis.ui @@ -7,7 +7,7 @@ 0 0 1206 - 634 + 674 @@ -178,7 +178,7 @@ QTabWidget::Rounded - 0 + 3 true @@ -4592,6 +4592,802 @@ www.qrg.globaltuners.com + + + Rx/Tx Conditions + + + + + + + Now + + + + + + + + + + + + 9 + 75 + true + true + + + + X-Rays + + + + + + + + + Radio Blackout + + + + + + + + + + + 75 + true + + + + R0 + + + + + + + + 75 + true + + + + R1 + + + + + + + + 75 + true + + + + R2 + + + + + + + + 75 + true + + + + R3 + + + + + + + + 75 + true + + + + R4 + + + + + + + + 75 + true + + + + R5 + + + + + + + + + + + + + 9 + 75 + true + true + + + + Protons-Electrons Flux + + + + + + + + + Solar Radiation Storm + + + + + + + + + + + 75 + true + + + + S0 + + + + + + + + 75 + true + + + + S1 + + + + + + + + 75 + true + + + + S2 + + + + + + + + 75 + true + + + + S3 + + + + + + + + 75 + true + + + + S4 + + + + + + + + 75 + true + + + + S5 + + + + + + + + + + + + + 9 + 75 + true + true + + + + Solar Activity + + + + + + + + + K-Index + + + + + + + - + + + + + + + + + + + A-Index + + + + + + + - + + + + + + + + + + + + + 7 + + + + EXTREMELY SEVERE +STORM + + + + + + + + 7 + + + + VERY SEVERE STORM + + + + + + + + 7 + + + + SEVERE STORM + + + + + + + + 7 + + + + MAJOR STORM + + + + + + + + 7 + + + + MINOR STORM + + + + + + + + 7 + + + + ACTIVE + + + + + + + + 7 + + + + UNSETTLED + + + + + + + + 7 + + + + QUIET + + + + + + + + 7 + + + + VERY QUIET + + + + + + + + 7 + + + + INACTIVE + + + + + + + + + + + + + + 7 + + + + SEVERE STORM + + + + + + + + 7 + + + + MAJOR STORM + + + + + + + + 7 + + + + MINOR STORM + + + + + + + + 7 + + + + ACTIVE + + + + + + + + 7 + + + + UNSETTLED + + + + + + + + 7 + + + + QUIET + + + + + + + + + + + + SFI + + + + + + + - + + + + + + + + + + + SN + + + + + + + - + + + + + + + + + Geomagnetic Storm (now) + + + + + + + + + + + 75 + true + + + + G0 + + + + + + + + 75 + true + + + + G1 + + + + + + + + 75 + true + + + + G2 + + + + + + + + 75 + true + + + + G3 + + + + + + + + 75 + true + + + + G4 + + + + + + + + 75 + true + + + + G5 + + + + + + + + + + Geomagnetic Storm (MAX 24 hrs) + + + + + + + + + + + 75 + true + + + + G0 + + + + + + + + 75 + true + + + + G1 + + + + + + + + 75 + true + + + + G2 + + + + + + + + 75 + true + + + + G3 + + + + + + + + 75 + true + + + + G4 + + + + + + + + 75 + true + + + + G5 + + + + + + + + + + + + Peak Flux Class + + + + + + + - + + + Qt::AlignCenter + + + + + + + + + + + + + + + + 15 + 75 + true + true + + + + Protons-Electrons Flux + + + + + + + + + + + + Info + + + + + + + Update + + + + + + + 1 + + + -1 + + + false + + + + + + + + Tab 2 + + + + + + @@ -4908,6 +5704,11 @@ QSlider::handle:horizontal { QPushButton
double_text_button.h
+ + SwitchableLabel + QLabel +
switchable_label.h
+
diff --git a/forecast_data.py b/forecast_data.py new file mode 100644 index 0000000..5be58b6 --- /dev/null +++ b/forecast_data.py @@ -0,0 +1,44 @@ +from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject + +from threads import UpadteForecastThread, ThreadStatus +from utilities import double_split + +class ForecastData(QObject): + update_complete = pyqtSignal(bool) + + def __init__(self): + super().__init__() + self.xray = '' + self.prot_el = '' + self.ak_index = '' + self.sgas = '' + self.geo_storm = '' + self.__update_thread = UpadteForecastThread(self) + self.__update_thread.finished.connect(self.__parse_and_emit_signal) + + @pyqtSlot() + def update(self): + self.__update_thread.start() + + def __parse_data(self): + self.xray = double_split(str(self.xray)) + self.prot_el = double_split(str(self.prot_el)) + self.ak_index = double_split(str(self.ak_index)) + self.sgas = double_split(str(self.sgas)) + self.geo_storm = double_split(str(self.geo_storm)) + + def remove_data(self): + self.xray = '' + self.prot_el = '' + self.ak_index = '' + self.sgas = '' + self.geo_storm = '' + + @pyqtSlot() + def __parse_and_emit_signal(self): + if self.__update_thread.status != ThreadStatus.OK: + status_ok = False + else: + status_ok = True + self.__parse_data() + self.update_complete.emit(status_ok) diff --git a/icons_imgs/search_icon.png b/icons_imgs/search_icon.png deleted file mode 100644 index cc72a1e70e10f361ea99b1f8acb076ca2702faa2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5486 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 diff --git a/main_window.ui b/main_window.ui deleted file mode 100644 index 21be4d1..0000000 --- a/main_window.ui +++ /dev/null @@ -1,4916 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 1206 - 634 - - - - - 0 - 0 - - - - ARTEMIS3 - - - - :/icons/Artemis3.ico:/icons/Artemis3.ico - - - - - - - - - - Qt::Horizontal - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 2 - - - - - - - - - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - - - - themes/1-default/icons/search_icon.png - - - true - - - - - - - - 0 - 0 - - - - - 9 - 50 - false - - - - - - - - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAsNeeded - - - 16 - - - false - - - - - - - - true - - - - 1 - 0 - - - - - 200 - 400 - - - - Qt::LeftToRight - - - - - - QTabWidget::North - - - QTabWidget::Rounded - - - 0 - - - true - - - - - 0 - 0 - - - - - 0 - 0 - - - - Main - - - - - - - 0 - 0 - - - - - 20 - 75 - true - - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:20pt; font-weight:600; font-style:normal;"> -<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">No Signal</p></body></html> - - - - - - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Mode - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Frequency - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Modulation - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Location - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Bandwidth - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - ACF - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - - - - 0 - 0 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Categories - - - Qt::AlignBottom|Qt::AlignHCenter - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Military - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Radar - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Active - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Inactive - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - HAM - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Commercial - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Aviation - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Marine - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Analogue - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Digital - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Trunked - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Utility - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Sat - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Navigation - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Interfering - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Time Signal - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - - 10 - 75 - true - - - - color: #9f9f9f; - - - Number Stations - - - Qt::AlignCenter - - - - - - - - - - - 0 - 0 - - - - - - - false - - - - 0 - 0 - - - - - 12 - 75 - true - true - - - - <html><head/><body><p><span style=" color:#000000;">Go to the signal's wiki.</span></p></body></html> - - - - - - Signal's wiki - - - true - - - - - - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Description - - - Qt::AlignCenter - - - - - - - - 11 - - - - border: 0px; -/*border-radius: 8px;*/ - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAsNeeded - - - true - - - - - - - <html><head/><body><p><span style=" color:#000000;">Frequency bands</span></p></body></html> - - - color: #9f9f9f; - - - - - - - - - 12 - 75 - true - - - - color: #9f9f9f; - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - ELF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - color: #9f9f9f; - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - color: #9f9f9f; - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - color: #9f9f9f; - - - SLF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - ULF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - VLF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - LF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - MF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - color: #9f9f9f; - - - HF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - VHF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - UHF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - SHF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - color: #9f9f9f; - - - - - - Qt::AlignCenter - - - - - - - - - - - - 12 - 75 - true - - - - - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - EHF - - - Qt::AlignCenter - - - - - - - - 12 - 75 - true - - - - color: #9f9f9f; - - - - - - Qt::AlignCenter - - - - - - - - - - - - - Filters - - - - - - - - - 0 - - - true - - - - Frequency - - - - - - - 0 - 0 - - - - - - - - - - true - - - - 0 - 0 - - - - - 12 - 75 - true - - - - ELF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - SLF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - ULF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - VLF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - LF - - - true - - - - - - - true - - - - 0 - 0 - - - - - 12 - 75 - true - - - - MF - - - true - - - - - - - true - - - - 0 - 0 - - - - - 12 - 75 - true - - - - HF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - VHF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - UHF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - SHF - - - true - - - - - - - true - - - - 12 - 75 - true - - - - EHF - - - true - - - false - - - - - - - - - - Qt::Horizontal - - - - 24 - 20 - - - - - - - - - 0 - 0 - - - - - - - - - - - 12 - 75 - true - - - - Lower frequency - - - false - - - - - - - false - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 100000000 - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 16777215 - 16777215 - - - - - 12 - 75 - true - - - - - - - MHz - - - 4 - - - false - - - 0 - - - - MHz - - - - - Hz - - - - - kHz - - - - - GHz - - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Confidence % - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 50 - 16777215 - - - - - 12 - - - - - - - false - - - Qt::AlignCenter - - - QAbstractSpinBox::UpDownArrows - - - - - - 100 - - - 0 - - - - - - - - 12 - 75 - true - - - - Upper frequency - - - false - - - - - - - false - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 100000000 - - - 1 - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 16777215 - 16777215 - - - - - 12 - 75 - true - - - - - - - MHz - - - - MHz - - - - - Hz - - - - - kHz - - - - - GHz - - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Confidence % - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 50 - 16777215 - - - - - 12 - - - - - - - false - - - Qt::AlignCenter - - - QAbstractSpinBox::UpDownArrows - - - - - - 100 - - - 0 - - - - - - - false - - - - 0 - 0 - - - - - 12 - 75 - false - true - false - - - - color: #9f9f9f; - - - Selected range: - -Inactive - - - Qt::AlignCenter - - - - - - - - - - Qt::Horizontal - - - - 24 - 20 - - - - - - - - - 12 - 75 - true - - - - Include undefined frequencies - - - true - - - - - - - true - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - - - - - - Bandwidth - - - - - - Qt::Horizontal - - - - 44 - 20 - - - - - - - - - 0 - 0 - - - - - - - - - - false - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 100000000 - - - 5000 - - - - - - - false - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 100000000 - - - 5000 - - - - - - - - 12 - 75 - true - - - - Upper band - - - false - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 50 - 16777215 - - - - - 12 - - - - - - - false - - - Qt::AlignCenter - - - QAbstractSpinBox::UpDownArrows - - - - - - 100 - - - 0 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Confidence % - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 16777215 - 16777215 - - - - - 12 - 75 - true - - - - - - - MHz - - - 4 - - - false - - - 0 - - - - MHz - - - - - Hz - - - - - kHz - - - - - GHz - - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 50 - 16777215 - - - - - 12 - - - - - - - false - - - Qt::AlignCenter - - - QAbstractSpinBox::UpDownArrows - - - - - - 100 - - - 0 - - - - - - - false - - - - 0 - 0 - - - - - 60 - 0 - - - - - 16777215 - 16777215 - - - - - 12 - 75 - true - - - - - - - MHz - - - - MHz - - - - - Hz - - - - - kHz - - - - - GHz - - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Confidence % - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 12 - 75 - true - - - - Lower band - - - false - - - - - - - false - - - - 0 - 0 - - - - - 12 - 75 - false - true - false - - - - - - - Selected range: - -Inactive - - - Qt::AlignCenter - - - - - - - - - - Qt::Horizontal - - - - 44 - 20 - - - - - - - - true - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - - - - - - 12 - 75 - true - - - - Include undefined bandwidths - - - true - - - - - - - - Category - - - - - - Qt::Horizontal - - - - 102 - 20 - - - - - - - - - 50 - - - - - - 12 - 75 - true - - - - <html><head/><body><p>Keep all the signals which belong to <span style=" font-style:italic;">at least</span> one of the selected categories.</p></body></html> - - - - - - At least one selected - - - true - - - - - - - - 12 - 75 - true - - - - <html><head/><body><p>Keep all the signals which belong to <span style=" font-style:italic;">all </span>the selected categories.</p></body></html> - - - All selected - - - false - - - - - - - - - - Qt::Horizontal - - - - 102 - 20 - - - - - - - - - 0 - 0 - - - - - - - - 12 - 75 - true - - - - Number Stations - - - true - - - - - - - - 12 - 75 - true - - - - Time Signal - - - true - - - - - - - - 12 - 75 - true - - - - Interfering - - - true - - - - - - - - 12 - 75 - true - - - - Satellite - - - true - - - - - - - - 12 - 75 - true - - - - Navigation - - - true - - - - - - - - 12 - 75 - true - - - - Utility - - - true - - - - - - - - 12 - 75 - true - - - - Digital - - - true - - - - - - - - 12 - 75 - true - - - - Marine - - - true - - - - - - - - 12 - 75 - true - - - - Commercial - - - true - - - - - - - - 12 - 75 - true - - - - Inactive - - - true - - - - - - - - 12 - 75 - true - - - - Radar - - - true - - - - - - - - 12 - 75 - true - - - - Military - - - true - - - - - - - - 12 - 75 - true - - - - Active - - - true - - - - - - - - 12 - 75 - true - - - - HAM - - - true - - - - - - - - 12 - 75 - true - - - - Aviation - - - true - - - - - - - - 12 - 75 - true - - - - Analogue - - - true - - - - - - - - 12 - 75 - true - - - - Trunked - - - true - - - - - - - - - - true - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - - - - - - Mode - - - - - - Qt::Horizontal - - - - 171 - 20 - - - - - - - - - 12 - 75 - true - - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::MultiSelection - - - QAbstractItemView::SelectItems - - - true - - - true - - - 1 - - - - 1 - - - - - - - - Qt::Horizontal - - - - 170 - 20 - - - - - - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - - - - - - 12 - 75 - true - - - - Include unknown modulations - - - true - - - - - - - - Modulation - - - - - - Qt::Horizontal - - - - 162 - 20 - - - - - - - - - - - - 0 - 0 - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - 20 - 20 - - - - - - - icons_imgs/search_icon.png - - - true - - - Qt::AlignCenter - - - - - - - - 12 - 50 - false - - - - QAbstractItemView::NoEditTriggers - - - QAbstractItemView::MultiSelection - - - - - - - - - - Qt::Horizontal - - - - 161 - 20 - - - - - - - - true - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - - - - - - Location - - - - - - Qt::Horizontal - - - - 162 - 20 - - - - - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - - - icons_imgs/search_icon.png - - - true - - - - - - - - 12 - - - - QAbstractItemView::MultiSelection - - - - - - - - - - Qt::Horizontal - - - - 161 - 20 - - - - - - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - false - - - - - - - - ACF - - - - - - Qt::Horizontal - - - - 52 - 22 - - - - - - - - - - - - - - 12 - 75 - true - - - - AC interval - - - - - - - true - - - - 0 - 0 - - - - - 80 - 0 - - - - - 100 - 16777215 - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 10000 - - - 50 - - - - - - - - 12 - 75 - true - - - - ms - - - - - - - Qt::Horizontal - - - - 49 - 20 - - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Confidence % - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - true - - - - 0 - 0 - - - - - 60 - 0 - - - - - 50 - 16777215 - - - - - 12 - - - - - - - false - - - Qt::AlignCenter - - - QAbstractSpinBox::UpDownArrows - - - - - - 100 - - - 0 - - - - - - - - - false - - - - 0 - 0 - - - - - 12 - 75 - false - true - false - - - - - - - Selected range: - -Inactive - - - Qt::AlignCenter - - - - - - - - - - Qt::Horizontal - - - - 51 - 20 - - - - - - - - - 12 - 75 - true - - - - Include undefined ACFs - - - true - - - - - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - false - - - - - - - - 12 - 75 - true - - - - Info - - - - - - - - - - - true - - - - 15 - 75 - true - - - - - - - Reset all filters - - - - - - - - GFD - - - - - - - - - 20 - 75 - true - - - - Search on Global Frequencies Database - -www.qrg.globaltuners.com - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 100 - - - - - - - - - 15 - 75 - true - - - - Search by - - - Qt::AlignCenter - - - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 80 - - - - - - - - Qt::Horizontal - - - - 37 - 20 - - - - - - - - - - - - - 12 - 75 - true - - - - Frequency - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 40 - - - - - - - - - - true - - - - 0 - 0 - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - 12 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 1 - - - 100000000 - - - 100 - - - - - - - true - - - - 0 - 0 - - - - - 60 - 0 - - - - - 16777215 - 16777215 - - - - - 12 - 75 - true - - - - - - - MHz - - - 4 - - - false - - - 0 - - - - MHz - - - - - Hz - - - - - kHz - - - - - GHz - - - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 20 - - - - - - - - - 15 - 75 - true - - - - Search - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 12 - 75 - true - - - - Location/Callsign - - - Qt::AlignCenter - - - - - - - Qt::Vertical - - - QSizePolicy::Minimum - - - - 20 - 40 - - - - - - - - - 12 - - - - - - - - Qt::Vertical - - - QSizePolicy::MinimumExpanding - - - - 20 - 20 - - - - - - - - - 15 - 75 - true - - - - Search - - - - - - - - - - - Qt::Horizontal - - - - 37 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 34 - - - - - - - - - - - - - - 0 - 0 - - - - - 270 - 0 - - - - - 270 - 575 - - - - - - - - - - - 0 - 0 - - - - -QWidget { - border: 0px; -} -QPushButton { - border: 0px solid gray; - border-color: #1d5eff; - border-radius: 20px; -} - - - - - - false - - - - 0 - 0 - - - - - 16777215 - 10 - - - - - - - 0 - - - false - - - - - - - false - - - - 0 - 0 - - - - - 70 - 70 - - - - - - - false - - - - - - - false - - - - 0 - 0 - - - - - 70 - 70 - - - - - - - false - - - - - - - false - - - - 0 - 0 - - - - - 70 - 70 - - - - - - - - - - - - - - 0 - 0 - - - - - 20 - 20 - - - - - - - themes/1-default/icons/volume.png - - - true - - - - - - - QSlider::groove:horizontal { - /*border: 1px solid #999999;*/ - height: 6px; /* the groove expands to the size of the slider by default. by giving it a height, it has a fixed size */ - background: #7a7a7a; - margin: 0 5px; - border-radius: 3px -} - -QSlider::handle:horizontal { - background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 gray, stop:0.5 white, stop:1.0 gray); - border: 1px solid #5c5c5c; - width: 15px; - margin: -5px -5px; /* handle is placed by default on the contents rect of the groove. Expand outside the groove */ - border-radius: 8px; -} - - - - 0 - - - 100 - - - 10 - - - 50 - - - Qt::Horizontal - - - - - - - - - - - - - 0 - 0 - - - - - 250 - 417 - - - - Signal waterfall - - - - - - - - - themes/1-system/icons/nosignalselected.png - - - true - - - - - - - - - - - - 0 - 0 - 1206 - 21 - - - - - - - - - - - File - - - - - - Updates - - - - - - - Themes - - - - - - - - - color: rgb(255, 255, 255); - - - - - Exit - - - - - Update database - - - - - Check latest database version - - - - - - DoubleTextButton - QPushButton -
double_text_button.h
-
-
- - - - -
diff --git a/switchable_label.py b/switchable_label.py new file mode 100644 index 0000000..44b9207 --- /dev/null +++ b/switchable_label.py @@ -0,0 +1,37 @@ +from PyQt5.QtWidgets import QLabel + +class SwitchableLabel(QLabel): + def __init__(self, parent = None): + super().__init__(parent) + self.switch_on_color = None + self.switch_off_color = None + + def set_colors(self, on, off): + self.switch_on_color = on + self.switch_off_color = off + + def switch_on(self): + self.setStyleSheet(f"background-color: {self.switch_on_color}") + + def switch_off(self): + self.setStyleSheet(f"background-color: {self.switch_off_color}") + + +class SwitchableLabelIterable(object): + def __init__(self, *labels): + self.labels = labels + + def __iter__(self): + for lab in self.labels: + yield lab + + def switch_on(label): + for lab in self.labels: + if lab == label: + lab.switch_on() + else: + lab.switch_off() + + def switch_off_all(self): + for lab in self.labels: + lab.switch_off() diff --git a/threads.py b/threads.py index d18ce53..fa36d01 100644 --- a/threads.py +++ b/threads.py @@ -33,8 +33,6 @@ class DownloadThread(QThread): def run(self): try: db = urllib3.PoolManager().request('GET', Database.LINK_LOC) - # db = urllib.request.urlopen(constants.Database.LINK_LOC) - # raise urllib.error.URLError('Test') except urllib3.exceptions.MaxRetryError: # No internet connection. self.__status = ThreadStatus.NO_CONNECTION_ERR return @@ -54,7 +52,6 @@ class DownloadThread(QThread): if os.path.exists(Constants.DATA_FOLDER): rmtree(Constants.DATA_FOLDER) try: - # data_folder = db.read() with ZipFile(BytesIO(db.data)) as zipped: zipped.extractall() except: From f04aec4926d208034abfdc62b4954adc2a7b1b44 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sat, 30 Mar 2019 23:40:34 +0100 Subject: [PATCH 02/11] First half of space weather screen. Still missing values updates on screen --- artemis.py | 27 ++++++++++++++++++----- constants.py | 6 +++++ forecast_data.py => space_weather_data.py | 16 +++++++------- threads.py | 26 +++++++++++++++++++++- utilities.py | 3 +++ 5 files changed, 64 insertions(+), 14 deletions(-) rename forecast_data.py => space_weather_data.py (68%) diff --git a/artemis.py b/artemis.py index cf9cb99..d2589e9 100644 --- a/artemis.py +++ b/artemis.py @@ -23,7 +23,7 @@ from PyQt5.QtCore import (QFileInfo, pyqtSlot,) from audio_player import AudioPlayer - +from space_weather_data import SpaceWeatherData from double_text_button import DoubleTextButton from download_window import DownloadWindow from switchable_label import SwitchableLabel, SwitchableLabelIterable @@ -345,13 +345,10 @@ class Artemis(QMainWindow, Ui_MainWindow): # ########################################################################################## - # self.load_db() - # Left list widget and search bar. self.search_bar.textChanged.connect(self.display_signals) self.result_list.currentItemChanged.connect(self.display_specs) self.result_list.itemDoubleClicked.connect(lambda: self.main_tab.setCurrentWidget(self.signal_properties_tab)) - # self.display_signals() self.audio_widget = AudioPlayer(self.play, self.pause, self.stop, @@ -375,12 +372,33 @@ class Artemis(QMainWindow, Ui_MainWindow): BandLabel(self.ehf_left, self.ehf, self.ehf_right), ] + # Space weather + self.info_now_btn.clicked.connect(lambda : webbrowser.open(Constants.FORECAST_INFO)) + self.update_now_btn.clicked.connect(self.start_update_space_weather) + self.space_weather_data = SpaceWeatherData() + self.space_weather_data.update_complete.connect(self.update_space_weather) + # Final operations. self.theme.initialize() self.load_db() self.display_signals() self.show() + @pyqtSlot() + def start_update_space_weather(self): + self.update_now_bar.setMaximum(self.update_now_bar.minimum()) + self.space_weather_data.update() + + @pyqtSlot(bool) + def update_space_weather(self, status_ok): + self.update_now_bar.setMaximum(self.update_now_bar.minimum() + 1) + if status_ok: + print('ok') # Insert labels values and colors here. + else: + pop_up(self, title = Messages.BAD_DOWNLOAD, + text = Messages.BAD_DOWNLOAD_MSG).show() + self.space_weather_data.remove_data() + @pyqtSlot() def go_to_gfd(self, by): query = "/?q=" @@ -394,7 +412,6 @@ class Artemis(QMainWindow, Ui_MainWindow): except: pass - @pyqtSlot(QListWidgetItem) def remove_if_unselected_modulation(self, item): if not item.isSelected(): diff --git a/constants.py b/constants.py index 16f8617..904d340 100644 --- a/constants.py +++ b/constants.py @@ -68,6 +68,12 @@ class Database(object): class Constants(object): ACF_DOCS = "https://aresvalley.com/documentation/" + FORECAST_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt" + FORECAST_PROT = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt" + FORECAST_AK_IND = "https://services.swpc.noaa.gov/text/wwv.txt" + FORECAST_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt" + FORECAST_G = "https://services.swpc.noaa.gov/text/3-day-forecast.txt" + FORECAST_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf" SEARCH_LABEL_IMG = "search_icon.png" VOLUME_LABEL_IMG = "volume.png" DATA_FOLDER = "Data" diff --git a/forecast_data.py b/space_weather_data.py similarity index 68% rename from forecast_data.py rename to space_weather_data.py index 5be58b6..e33f1bd 100644 --- a/forecast_data.py +++ b/space_weather_data.py @@ -1,9 +1,9 @@ from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject -from threads import UpadteForecastThread, ThreadStatus +from threads import UpadteSpaceWeatherThread, ThreadStatus from utilities import double_split -class ForecastData(QObject): +class SpaceWeatherData(QObject): update_complete = pyqtSignal(bool) def __init__(self): @@ -13,7 +13,7 @@ class ForecastData(QObject): self.ak_index = '' self.sgas = '' self.geo_storm = '' - self.__update_thread = UpadteForecastThread(self) + self.__update_thread = UpadteSpaceWeatherThread(self) self.__update_thread.finished.connect(self.__parse_and_emit_signal) @pyqtSlot() @@ -21,11 +21,11 @@ class ForecastData(QObject): self.__update_thread.start() def __parse_data(self): - self.xray = double_split(str(self.xray)) - self.prot_el = double_split(str(self.prot_el)) - self.ak_index = double_split(str(self.ak_index)) - self.sgas = double_split(str(self.sgas)) - self.geo_storm = double_split(str(self.geo_storm)) + self.xray = double_split(self.xray) + self.prot_el = double_split(self.prot_el) + self.ak_index = double_split(self.ak_index) + self.sgas = double_split(self.sgas) + self.geo_storm = double_split(self.geo_storm) def remove_data(self): self.xray = '' diff --git a/threads.py b/threads.py index fa36d01..dcb6310 100644 --- a/threads.py +++ b/threads.py @@ -8,7 +8,6 @@ from zipfile import ZipFile from PyQt5.QtCore import QThread from constants import Constants, Database, ChecksumWhat from utilities import checksum_ok -import constants class ThreadStatus(Enum): OK = auto() @@ -56,3 +55,28 @@ class DownloadThread(QThread): zipped.extractall() except: self.__status = ThreadStatus.UNKNOWN_ERR + + +class UpadteSpaceWeatherThread(QThread): + def __init__(self, space_weather_data): + super().__init__() + self.__status = ThreadStatus.OK + self.__space_weather_data = space_weather_data + + @property + def status(self): + return self.__status + + def __del__(self): + self.terminate() + self.wait() + + def run(self): + try: + self.__space_weather_data.xray = str(urllib3.PoolManager().request('GET', Constants.FORECAST_XRAY).data) + self.__space_weather_data.prot_el = str(urllib3.PoolManager().request('GET', Constants.FORECAST_PROT).data) + self.__space_weather_data.ak_index = str(urllib3.PoolManager().request('GET', Constants.FORECAST_AK_IND).data) + self.__space_weather_data.sgas = str(urllib3.PoolManager().request('GET', Constants.FORECAST_SGAS).data) + self.__space_weather_data.geo_storm = str(urllib3.PoolManager().request('GET', Constants.FORECAST_G).data) + except: + self.__status = ThreadStatus.UNKNOWN_ERR diff --git a/utilities.py b/utilities.py index de0b8d9..e79ff95 100644 --- a/utilities.py +++ b/utilities.py @@ -107,3 +107,6 @@ def format_numbers(lower, upper): return f"{lower:,} {units[lower_factor]} - {upper:,} {units[upper_factor]}" else: return f"{lower:,} {units[lower_factor]}" + +def double_split(string): + return [i.split() for i in string.splitlines()] From 5b95d19d7c77712ba9fe7fc72e78c0f4b0a200d4 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Mon, 1 Apr 2019 22:53:54 +0200 Subject: [PATCH 03/11] Update left half of space weather with colored labels. Also apply minor modifications --- artemis.py | 217 +++++++++- artemis.ui | 951 ++++++++++++++++++++++++++---------------- constants.py | 24 ++ download_window.py | 6 +- space_weather_data.py | 12 +- switchable_label.py | 12 +- themes.py | 4 +- threads.py | 10 +- utilities.py | 11 +- 9 files changed, 854 insertions(+), 393 deletions(-) diff --git a/artemis.py b/artemis.py index d2589e9..1cbceca 100644 --- a/artemis.py +++ b/artemis.py @@ -1,4 +1,5 @@ from collections import namedtuple +from itertools import chain from functools import partial from glob import glob import webbrowser @@ -26,14 +27,15 @@ from audio_player import AudioPlayer from space_weather_data import SpaceWeatherData from double_text_button import DoubleTextButton from download_window import DownloadWindow -from switchable_label import SwitchableLabel, SwitchableLabelIterable +from switchable_label import SwitchableLabel, SwitchableLabelsIterable from constants import (Constants, Ftype, GfdType, Database, ChecksumWhat, Messages, - Signal,) + Signal, + Colors,) from themes import Theme from utilities import (checksum_ok, uncheck_and_emit, @@ -377,6 +379,81 @@ class Artemis(QMainWindow, Ui_MainWindow): self.update_now_btn.clicked.connect(self.start_update_space_weather) self.space_weather_data = SpaceWeatherData() self.space_weather_data.update_complete.connect(self.update_space_weather) + self.switchable_r_labels = SwitchableLabelsIterable(self.r0_now_lbl, + self.r1_now_lbl, + self.r2_now_lbl, + self.r3_now_lbl, + self.r4_now_lbl, + self.r5_now_lbl,) + self.switchable_s_labels = SwitchableLabelsIterable(self.s0_now_lbl, + self.s1_now_lbl, + self.s2_now_lbl, + self.s3_now_lbl, + self.s4_now_lbl, + self.s5_now_lbl,) + self.switchable_g_now_labels = SwitchableLabelsIterable(self.g0_now_lbl, + self.g1_now_lbl, + self.g2_now_lbl, + self.g3_now_lbl, + self.g4_now_lbl, + self.g5_now_lbl) + self.switchable_g_today_labels = SwitchableLabelsIterable(self.g0_today_lbl, + self.g1_today_lbl, + self.g2_today_lbl, + self.g3_today_lbl, + self.g4_today_lbl, + self.g5_today_lbl) + colors_array = [[Colors.WHITE_LIGHT, Colors.WHITE_DARK], + [Colors.BLUE_LIGHT, Colors.BLUE_DARK], + [Colors.GREEN_LIGHT, Colors.GREEN_DARK], + [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], + [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], + [Colors.RED_LIGHT, Colors.RED_DARK]] + + for lab, [light_color, dark_color] in zip(chain(self.switchable_r_labels, + self.switchable_s_labels, + self.switchable_g_now_labels, + self.switchable_g_today_labels), + colors_array * 4): + lab.set_colors(light_color, dark_color) + + k_storms_colors = [[Colors.RED_LIGHT, Colors.RED_DARK], + [Colors.RED2_LIGHT, Colors.RED2_DARK], + [Colors.RED3_LIGHT, Colors.RED3_DARK], + [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], + [Colors.ORANGE2_LIGHT, Colors.ORANGE2_DARK], + [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], + [Colors.GREEN3_LIGHT, Colors.GREEN3_DARK], + [Colors.GREEN2_LIGHT, Colors.GREEN2_DARK], + [Colors.GREEN_LIGHT, Colors.GREEN_DARK], + [Colors.BLUE_LIGHT, Colors.BLUE_DARK]] + a_storm_colors = [[Colors.RED_LIGHT, Colors.RED_DARK], + [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], + [Colors.ORANGE2_LIGHT, Colors.ORANGE2_DARK], + [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], + [Colors.GREEN_LIGHT, Colors.GREEN_DARK], + [Colors.BLUE_LIGHT, Colors.BLUE_DARK]] + + self.k_storm_labels = SwitchableLabelsIterable(self.k_ex_sev_storm_lbl, + self.k_very_sev_storm_lbl, + self.k_sev_storm_lbl, + self.k_maj_storm_lbl, + self.k_min_storm_lbl, + self.k_active_lbl, + self.k_unsettled_lbl, + self.k_quiet_lbl, + self.k_very_quiet_lbl, + self.k_inactive_lbl) + self.a_storm_labels = SwitchableLabelsIterable(self.a_sev_storm_lbl, + self.a_maj_storm_lbl, + self.a_min_storm_lbl, + self.a_active_lbl, + self.a_unsettled_lbl, + self.a_quiet_lbl) + + for lab, [light_color, dark_color] in zip(chain(self.k_storm_labels, self.a_storm_labels), + chain(k_storms_colors, a_storm_colors)): + lab.set_colors(light_color, dark_color) # Final operations. self.theme.initialize() @@ -393,7 +470,129 @@ class Artemis(QMainWindow, Ui_MainWindow): def update_space_weather(self, status_ok): self.update_now_bar.setMaximum(self.update_now_bar.minimum() + 1) if status_ok: - print('ok') # Insert labels values and colors here. + xray_long = float(self.space_weather_data.xray[-1][7]) + format_text = lambda letter, power : letter + f"{xray_long * 10**power:.1f}" + if xray_long < 1e-8 and xray_long != -1.00e+05: + self.peak_flux_lbl.setText(format_text("= 1e-8 and xray_long < 1e-7: + self.peak_flux_lbl.setText(format_text("A", 8)) + elif xray_long >= 1e-7 and xray_long < 1e-6: + self.peak_flux_lbl.setText(format_text("B", 7)) + elif xray_long >= 1e-6 and xray_long < 1e-5: + self.peak_flux_lbl.setText(format_text("C", 6)) + elif xray_long >= 1e-5 and xray_long < 1e-4: + self.peak_flux_lbl.setText(format_text("M", 5)) + elif xray_long >= 1e-4: + self.peak_flux_lbl.setText(format_text("X", 4)) + elif xray_long == -1.00e+05: + self.peak_flux_lbl.setText("No Data") + + if xray_long < 1e-5 and xray_long != -1.00e+05: + self.switchable_r_labels.switch_on(self.r0_now_lbl) + elif xray_long >= 1e-5 and xray_long < 5e-5: + self.switchable_r_labels.switch_on(self.r1_now_lbl) + elif xray_long >= 5e-5 and xray_long < 1e-4: + self.switchable_r_labels.switch_on(self.r2_now_lbl) + elif xray_long >= 1e-4 and xray_long < 1e-3: + self.switchable_r_labels.switch_on(self.r3_now_lbl) + elif xray_long >= 1e-3 and xray_long < 2e-3: + self.switchable_r_labels.switch_on(self.r4_now_lbl) + elif xray_long >= 2e-3: + self.switchable_r_labels.switch_on(self.r5_now_lbl) + elif xray_long == -1.00e+05: + self.switchable_r_labels.switch_off_all() + + pro10 = float(self.space_weather_data.prot_el[-1][8]) + if pro10 < 10 and pro10 != -1.00e+05: + self.switchable_s_labels.switch_on(self.s0_now_lbl) + elif pro10 >= 10 and pro10 < 100: + self.switchable_s_labels.switch_on(self.s1_now_lbl) + elif pro10 >= 100 and pro10 < 1000: + self.switchable_s_labels.switch_on(self.s2_now_lbl) + elif pro10 >= 1000 and pro10 < 10000: + self.switchable_s_labels.switch_on(self.s3_now_lbl) + elif pro10 >= 10000 and pro10 < 100000: + self.switchable_s_labels.switch_on(self.s4_now_lbl) + elif pro10 >= 100000: + self.switchable_s_labels.switch_on(self.s5_now_lbl) + elif pro10 == -1.00e+05: + self.switchable_s_labels.switch_off_all() + + k_index = int(self.space_weather_data.ak_index[8][11].replace('.', '')) + self.k_index_lbl.setText(str(k_index)) + a_index = int(self.space_weather_data.ak_index[7][7].replace('.', '')) + self.a_index_lbl.setText(str(a_index)) + + if k_index == 0: + self.switchable_g_now_labels.switch_on(self.g0_now_lbl) + self.k_storm_labels.switch_on(self.k_inactive_lbl) + elif k_index == 1: + self.switchable_g_now_labels.switch_on(self.g0_now_lbl) + self.k_storm_labels.switch_on(self.k_very_quiet_lbl) + elif k_index == 2: + self.switchable_g_now_labels.switch_on(self.g0_now_lbl) + self.k_storm_labels.switch_on(self.k_quiet_lbl) + elif k_index == 3: + self.switchable_g_now_labels.switch_on(self.g0_now_lbl) + self.k_storm_labels.switch_on(self.k_unsettled_lbl) + elif k_index == 4: + self.switchable_g_now_labels.switch_on(self.g0_now_lbl) + self.k_storm_labels.switch_on(self.k_active_lbl) + elif k_index == 5: + self.switchable_g_now_labels.switch_on(self.g1_now_lbl) + self.k_storm_labels.switch_on(self.k_min_storm_lbl) + elif k_index == 6: + self.switchable_g_now_labels.switch_on(self.g2_now_lbl) + self.k_storm_labels.switch_on(self.k_maj_storm_lbl) + elif k_index == 7: + self.switchable_g_now_labels.switch_on(self.g3_now_lbl) + self.k_storm_labels.switch_on(self.k_sev_storm_lbl) + elif k_index == 8: + self.switchable_g_now_labels.switch_on(self.g4_now_lbl) + self.k_storm_labels.switch_on(self.k_very_sev_storm_lbl) + elif k_index == 9: + self.switchable_g_now_labels.switch_on(self.g5_now_lbl) + self.k_storm_labels.switch_on(self.k_ex_sev_storm_lbl) + + if a_index >= 0 and a_index < 8: + self.a_storm_labels.switch_on(self.a_quiet_lbl) + elif a_index >= 8 and a_index < 16: + self.a_storm_labels.switch_on(self.a_unsettled_lbl) + elif a_index >= 16 and a_index < 30: + self.a_storm_labels.switch_on(self.a_active_lbl) + elif a_index >= 30 and a_index < 50: + self.a_storm_labels.switch_on(self.a_min_storm_lbl) + elif a_index >= 50 and a_index < 100: + self.a_storm_labels.switch_on(self.a_maj_storm_lbl) + elif a_index >= 100 and a_index < 400: + self.a_storm_labels.switch_on(self.a_sev_storm_lbl) + + index = self.space_weather_data.geo_storm[6].index("was") + 1 + k_index_24_hmax = int(self.space_weather_data.geo_storm[6][index]) + if k_index_24_hmax == 0: + self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + elif k_index_24_hmax == 1: + self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + elif k_index_24_hmax == 2: + self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + elif k_index_24_hmax == 3: + self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + elif k_index_24_hmax == 4: + self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + elif k_index_24_hmax == 5: + self.switchable_g_today_labels.switch_on(self.g1_today_lbl) + elif k_index_24_hmax == 6: + self.switchable_g_today_labels.switch_on(self.g2_today_lbl) + elif k_index_24_hmax == 7: + self.switchable_g_today_labels.switch_on(self.g3_today_lbl) + elif k_index_24_hmax == 8: + self.switchable_g_today_labels.switch_on(self.g4_today_lbl) + elif k_index_24_hmax == 9: + self.switchable_g_today_labels.switch_on(self.g5_today_lbl) + + self.sfi_lbl.setText(self.space_weather_data.ak_index[7][2].replace('.', '').lstrip('0')) + self.sn_lbl.setText([x[4] for i, x in enumerate(self.space_weather_data.sgas) if "SSN" in x][0].lstrip('0')) + else: pop_up(self, title = Messages.BAD_DOWNLOAD, text = Messages.BAD_DOWNLOAD_MSG).show() @@ -402,10 +601,10 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def go_to_gfd(self, by): query = "/?q=" - if by == GfdType.FREQ: + if by is GfdType.FREQ: value_in_mhz = self.freq_gfd.value() * Constants.CONVERSION_FACTORS[self.unit_freq_gfd.currentText()] / Constants.CONVERSION_FACTORS["MHz"] query += str(value_in_mhz) - elif by == GfdType.LOC: + elif by is GfdType.LOC: query += self.gfd_line_edit.text() try: webbrowser.open(Constants.GFD_SITE + query.lower()) @@ -1060,9 +1259,9 @@ if __name__ == '__main__': my_app = QApplication(sys.argv) img = QPixmap(":/icons/Artemis3.500px.png") # img = img.scaled(600, 600, aspectRatioMode = Qt.KeepAspectRatio) - splash = QSplashScreen(img) - splash.show() - sleep(2) + # splash = QSplashScreen(img) + # splash.show() + # sleep(2) w = Artemis() - splash.finish(w) + # splash.finish(w) sys.exit(my_app.exec_()) diff --git a/artemis.ui b/artemis.ui index 61e4b3d..920bdb3 100644 --- a/artemis.ui +++ b/artemis.ui @@ -6,8 +6,8 @@ 0 0 - 1206 - 674 + 1387 + 761
@@ -4604,7 +4604,7 @@ www.qrg.globaltuners.com Now - + @@ -4613,7 +4613,7 @@ www.qrg.globaltuners.com - 9 + 11 75 true true @@ -4624,106 +4624,11 @@ www.qrg.globaltuners.com - - - - - - Radio Blackout - - - - - - - - - - - 75 - true - - - - R0 - - - - - - - - 75 - true - - - - R1 - - - - - - - - 75 - true - - - - R2 - - - - - - - - 75 - true - - - - R3 - - - - - - - - 75 - true - - - - R4 - - - - - - - - 75 - true - - - - R5 - - - - - - - - - + - 9 + 11 75 true true @@ -4734,10 +4639,15 @@ www.qrg.globaltuners.com - + + + + 9 + + Solar Radiation Storm @@ -4757,6 +4667,9 @@ www.qrg.globaltuners.com S0 + + Qt::AlignCenter + @@ -4770,6 +4683,9 @@ www.qrg.globaltuners.com S1 + + Qt::AlignCenter + @@ -4783,6 +4699,9 @@ www.qrg.globaltuners.com S2 + + Qt::AlignCenter + @@ -4796,6 +4715,9 @@ www.qrg.globaltuners.com S3 + + Qt::AlignCenter + @@ -4809,6 +4731,9 @@ www.qrg.globaltuners.com S4 + + Qt::AlignCenter + @@ -4822,6 +4747,9 @@ www.qrg.globaltuners.com S5 + + Qt::AlignCenter + @@ -4833,7 +4761,7 @@ www.qrg.globaltuners.com - 9 + 11 75 true true @@ -4848,6 +4776,13 @@ www.qrg.globaltuners.com + + + 9 + 75 + true + + K-Index @@ -4855,6 +4790,11 @@ www.qrg.globaltuners.com + + + 9 + + - @@ -4862,10 +4802,17 @@ www.qrg.globaltuners.com - + + + + 9 + 75 + true + + A-Index @@ -4873,6 +4820,11 @@ www.qrg.globaltuners.com + + + 9 + + - @@ -4884,202 +4836,282 @@ www.qrg.globaltuners.com - + - 7 + 9 + 75 + true EXTREMELY SEVERE STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true VERY SEVERE STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true SEVERE STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true MAJOR STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true MINOR STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true ACTIVE + + Qt::AlignCenter + - + - 7 + 9 + 75 + true UNSETTLED + + Qt::AlignCenter + - + - 7 + 9 + 75 + true QUIET + + Qt::AlignCenter + - + - 7 + 9 + 75 + true VERY QUIET + + Qt::AlignCenter + - + - 7 + 9 + 75 + true INACTIVE + + Qt::AlignCenter + - + - + - 7 + 9 + 75 + true SEVERE STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true MAJOR STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true MINOR STORM + + Qt::AlignCenter + - + - 7 + 9 + 75 + true ACTIVE + + Qt::AlignCenter + - + - 7 + 9 + 75 + true UNSETTLED + + Qt::AlignCenter + - + - 7 + 9 + 75 + true QUIET + + Qt::AlignCenter + @@ -5089,6 +5121,13 @@ STORM + + + 9 + 75 + true + + SFI @@ -5096,6 +5135,11 @@ STORM + + + 9 + + - @@ -5103,10 +5147,17 @@ STORM - + + + + 9 + 75 + true + + SN @@ -5114,6 +5165,11 @@ STORM + + + 9 + + - @@ -5121,192 +5177,251 @@ STORM - - - - Geomagnetic Storm (now) - - - - - - - - - - - 75 - true - - - - G0 - - - - - - - - 75 - true - - - - G1 - - - - - - - - 75 - true - - - - G2 - - - - - - - - 75 - true - - - - G3 - - - - - - - - 75 - true - - - - G4 - - - - - - - - 75 - true - - - - G5 - - - - - - - - - Geomagnetic Storm (MAX 24 hrs) - - + + + + + + 9 + + + + Geomagnetic Storm (MAX 24 hrs) + + + + + + + + + + + 75 + true + + + + G0 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G1 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G2 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G3 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G4 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G5 + + + Qt::AlignCenter + + + + + + + - - - - - - - - 75 - true - - - - G0 - - - - - - - - 75 - true - - - - G1 - - - - - - - - 75 - true - - - - G2 - - - - - - - - 75 - true - - - - G3 - - - - - - - - 75 - true - - - - G4 - - - - - - - - 75 - true - - - - G5 - - - - - + + + + + + + 9 + + + + Geomagnetic Storm (now) + + + + + + + + + + + 75 + true + + + + G0 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G1 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G2 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G3 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G4 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + G5 + + + Qt::AlignCenter + + + + + + + - + + + + 9 + + Peak Flux Class @@ -5314,6 +5429,11 @@ STORM + + + 9 + + - @@ -5324,6 +5444,124 @@ STORM + + + + + + + 9 + + + + Radio Blackout + + + + + + + + + + + 75 + true + + + + R0 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + R1 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + R2 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + R3 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + R4 + + + Qt::AlignCenter + + + + + + + + 75 + true + + + + R5 + + + Qt::AlignCenter + + + + + + + + @@ -5331,17 +5569,47 @@ STORM - - - - 15 - 75 - true - true - + + + + 0 + 0 + - Protons-Electrons Flux + Info + + + + + + + + 0 + 0 + + + + Update + + + + + + + + 0 + 0 + + + + 1 + + + -1 + + + false @@ -5350,33 +5618,6 @@ STORM - - - - Info - - - - - - - Update - - - - - - - 1 - - - -1 - - - false - - - @@ -5645,7 +5886,7 @@ QSlider::handle:horizontal { 0 0 - 1206 + 1387 21 diff --git a/constants.py b/constants.py index 904d340..b4c6ec7 100644 --- a/constants.py +++ b/constants.py @@ -66,6 +66,30 @@ class Database(object): Signal.SUP_BAND, Signal.CATEGORY_CODE,) +class Colors(object): + RED_DARK = "#4d0000" + RED_LIGHT = "#ff0000" + RED2_DARK = "#4c0c00" + RED2_LIGHT = "#ff2700" + RED3_DARK = "#4b1100" + RED3_LIGHT = "#ff3a00" + ORANGE_DARK = "#4d2e00" + ORANGE_LIGHT = "#ffad33" + ORANGE2_DARK = "#4c2000" + ORANGE2_LIGHT = "#ff6c00" + GREEN_DARK = "#003300" + GREEN_LIGHT = "#33ff33" + GREEN2_DARK = "#424d00" + GREEN2_LIGHT = "#dcff00" + GREEN3_DARK = "#344d00" + GREEN3_LIGHT = "#aeff00" + BLUE_DARK = "#000033" + BLUE_LIGHT = "#3333ff" + WHITE_DARK = "#333333" + WHITE_LIGHT = "#d9b3ff" + YELLOW_DARK = "#333300" + YELLOW_LIGHT = "#ffff33" + class Constants(object): ACF_DOCS = "https://aresvalley.com/documentation/" FORECAST_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt" diff --git a/download_window.py b/download_window.py index 8b0df8e..47907e2 100644 --- a/download_window.py +++ b/download_window.py @@ -50,11 +50,11 @@ class DownloadWindow(QWidget, Ui_Download_window): @pyqtSlot() def wait_close(self): - if self.download_thread.status == ThreadStatus.OK: + if self.download_thread.status is ThreadStatus.OK: self.close() - elif self.download_thread.status == ThreadStatus.NO_CONNECTION_ERR: + elif self.download_thread.status is ThreadStatus.NO_CONNECTION_ERR: self.show_no_connection_warning() - elif self.download_thread.status == ThreadStatus.BAD_DOWNLOAD_ERR: + elif self.download_thread.status is ThreadStatus.BAD_DOWNLOAD_ERR: self.show_bad_download_warning() else: self.close() diff --git a/space_weather_data.py b/space_weather_data.py index e33f1bd..694c4c8 100644 --- a/space_weather_data.py +++ b/space_weather_data.py @@ -1,7 +1,6 @@ from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject from threads import UpadteSpaceWeatherThread, ThreadStatus -from utilities import double_split class SpaceWeatherData(QObject): update_complete = pyqtSignal(bool) @@ -21,10 +20,11 @@ class SpaceWeatherData(QObject): self.__update_thread.start() def __parse_data(self): - self.xray = double_split(self.xray) - self.prot_el = double_split(self.prot_el) - self.ak_index = double_split(self.ak_index) - self.sgas = double_split(self.sgas) + double_split = lambda string : [i.split() for i in string.splitlines()] + self.xray = double_split(self.xray) + self.prot_el = double_split(self.prot_el) + self.ak_index = double_split(self.ak_index) + self.sgas = double_split(self.sgas) self.geo_storm = double_split(self.geo_storm) def remove_data(self): @@ -36,7 +36,7 @@ class SpaceWeatherData(QObject): @pyqtSlot() def __parse_and_emit_signal(self): - if self.__update_thread.status != ThreadStatus.OK: + if self.__update_thread.status is not ThreadStatus.OK: status_ok = False else: status_ok = True diff --git a/switchable_label.py b/switchable_label.py index 44b9207..68639b6 100644 --- a/switchable_label.py +++ b/switchable_label.py @@ -11,13 +11,15 @@ class SwitchableLabel(QLabel): self.switch_off_color = off def switch_on(self): - self.setStyleSheet(f"background-color: {self.switch_on_color}") + self.setStyleSheet(f"""background-color: {self.switch_on_color}; + color:#000000;""") def switch_off(self): - self.setStyleSheet(f"background-color: {self.switch_off_color}") + self.setStyleSheet(f"""background-color: {self.switch_off_color}; + color:#000000;""") -class SwitchableLabelIterable(object): +class SwitchableLabelsIterable(object): def __init__(self, *labels): self.labels = labels @@ -25,9 +27,9 @@ class SwitchableLabelIterable(object): for lab in self.labels: yield lab - def switch_on(label): + def switch_on(self, label): for lab in self.labels: - if lab == label: + if lab is label: lab.switch_on() else: lab.switch_off() diff --git a/themes.py b/themes.py index a1603c4..db2cb69 100644 --- a/themes.py +++ b/themes.py @@ -1,10 +1,11 @@ from functools import partial import os +import re from PyQt5.QtWidgets import QAction from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QPixmap from constants import Constants -from utilities import pop_up, is_valid_html_color +from utilities import pop_up class ThemeConstants(object): FOLDER = "themes" @@ -138,6 +139,7 @@ class Theme(object): valid_format = True quality, color = line.split(ThemeConstants.COLOR_SEPARATOR) color = color.rstrip() + is_valid_html_color = lambda color : bool(re.match("#([a-zA-Z0-9]){6}", color)) if quality.lower() == Constants.ACTIVE and is_valid_html_color(color): self.__parent.active_color = color active_color_ok = True diff --git a/threads.py b/threads.py index dcb6310..8ea2cbb 100644 --- a/threads.py +++ b/threads.py @@ -73,10 +73,10 @@ class UpadteSpaceWeatherThread(QThread): def run(self): try: - self.__space_weather_data.xray = str(urllib3.PoolManager().request('GET', Constants.FORECAST_XRAY).data) - self.__space_weather_data.prot_el = str(urllib3.PoolManager().request('GET', Constants.FORECAST_PROT).data) - self.__space_weather_data.ak_index = str(urllib3.PoolManager().request('GET', Constants.FORECAST_AK_IND).data) - self.__space_weather_data.sgas = str(urllib3.PoolManager().request('GET', Constants.FORECAST_SGAS).data) - self.__space_weather_data.geo_storm = str(urllib3.PoolManager().request('GET', Constants.FORECAST_G).data) + self.__space_weather_data.xray = str(urllib3.PoolManager().request('GET', Constants.FORECAST_XRAY).data, 'utf-8') + self.__space_weather_data.prot_el = str(urllib3.PoolManager().request('GET', Constants.FORECAST_PROT).data, 'utf-8') + self.__space_weather_data.ak_index = str(urllib3.PoolManager().request('GET', Constants.FORECAST_AK_IND).data, 'utf-8') + self.__space_weather_data.sgas = str(urllib3.PoolManager().request('GET', Constants.FORECAST_SGAS).data, 'utf-8') + self.__space_weather_data.geo_storm = str(urllib3.PoolManager().request('GET', Constants.FORECAST_G).data, 'utf-8') except: self.__status = ThreadStatus.UNKNOWN_ERR diff --git a/utilities.py b/utilities.py index e79ff95..51d7c66 100644 --- a/utilities.py +++ b/utilities.py @@ -1,6 +1,5 @@ from functools import partial import hashlib -import re import sys import os from pandas import read_csv @@ -42,9 +41,9 @@ def pop_up(cls, title, text, def checksum_ok(data, what): code = hashlib.sha256() code.update(data) - if what == ChecksumWhat.FOLDER: + if what is ChecksumWhat.FOLDER: n = 0 - elif what == ChecksumWhat.DB: + elif what is ChecksumWhat.DB: n = 1 else: raise ValueError("Wrong entry name.") @@ -55,9 +54,6 @@ def checksum_ok(data, what): raise return code.hexdigest() == reference -def is_valid_html_color(color): - return bool(re.match("#([a-zA-Z0-9]){6}", color)) - def connect_to(events_to_connect, fun_to_connect, fun_args): if fun_args: for event in events_to_connect: @@ -107,6 +103,3 @@ def format_numbers(lower, upper): return f"{lower:,} {units[lower_factor]} - {upper:,} {units[upper_factor]}" else: return f"{lower:,} {units[lower_factor]}" - -def double_split(string): - return [i.split() for i in string.splitlines()] From d626475acee60e08cd49d382aabe025a7e3466ff Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sat, 6 Apr 2019 18:54:33 +0200 Subject: [PATCH 04/11] Completes first forecast screen (experimental colors). Adds checkable theme in action bar. Fixes bug in show_matching_strings function --- artemis.py | 45 +- artemis.ui | 2634 ++++++++++++++++++++++++++++------------- constants.py | 33 +- space_weather_data.py | 11 +- switchable_label.py | 20 +- themes.py | 24 +- threads.py | 9 + 7 files changed, 1920 insertions(+), 856 deletions(-) diff --git a/artemis.py b/artemis.py index 1cbceca..a6cd62c 100644 --- a/artemis.py +++ b/artemis.py @@ -415,21 +415,21 @@ class Artemis(QMainWindow, Ui_MainWindow): self.switchable_g_now_labels, self.switchable_g_today_labels), colors_array * 4): - lab.set_colors(light_color, dark_color) + lab.set_colors(None, None) k_storms_colors = [[Colors.RED_LIGHT, Colors.RED_DARK], [Colors.RED2_LIGHT, Colors.RED2_DARK], [Colors.RED3_LIGHT, Colors.RED3_DARK], - [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], [Colors.ORANGE2_LIGHT, Colors.ORANGE2_DARK], + [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], - [Colors.GREEN3_LIGHT, Colors.GREEN3_DARK], [Colors.GREEN2_LIGHT, Colors.GREEN2_DARK], + [Colors.GREEN3_LIGHT, Colors.GREEN3_DARK], [Colors.GREEN_LIGHT, Colors.GREEN_DARK], [Colors.BLUE_LIGHT, Colors.BLUE_DARK]] a_storm_colors = [[Colors.RED_LIGHT, Colors.RED_DARK], - [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], [Colors.ORANGE2_LIGHT, Colors.ORANGE2_DARK], + [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], [Colors.GREEN_LIGHT, Colors.GREEN_DARK], [Colors.BLUE_LIGHT, Colors.BLUE_DARK]] @@ -453,7 +453,7 @@ class Artemis(QMainWindow, Ui_MainWindow): for lab, [light_color, dark_color] in zip(chain(self.k_storm_labels, self.a_storm_labels), chain(k_storms_colors, a_storm_colors)): - lab.set_colors(light_color, dark_color) + lab.set_colors(None, None) # Final operations. self.theme.initialize() @@ -571,27 +571,56 @@ class Artemis(QMainWindow, Ui_MainWindow): k_index_24_hmax = int(self.space_weather_data.geo_storm[6][index]) if k_index_24_hmax == 0: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + self.expected_noise_lbl.setText("S0 - S1 (<-120 dBm)") elif k_index_24_hmax == 1: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + self.expected_noise_lbl.setText("S0 - S1 (<-120 dBm)") elif k_index_24_hmax == 2: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + self.expected_noise_lbl.setText("S1 - S2 (-115 dBm)") elif k_index_24_hmax == 3: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + self.expected_noise_lbl.setText("S2 - S3 (-110 dBm)") elif k_index_24_hmax == 4: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) + self.expected_noise_lbl.setText("S3 - S4 (-100 dBm)") elif k_index_24_hmax == 5: self.switchable_g_today_labels.switch_on(self.g1_today_lbl) + self.expected_noise_lbl.setText("S4 - S6 (-90 dBm)") elif k_index_24_hmax == 6: self.switchable_g_today_labels.switch_on(self.g2_today_lbl) + self.expected_noise_lbl.setText("S6 - S9 (-80 dBm)") elif k_index_24_hmax == 7: self.switchable_g_today_labels.switch_on(self.g3_today_lbl) + self.expected_noise_lbl.setText("S9 - S20 (>-60 dBm)") elif k_index_24_hmax == 8: self.switchable_g_today_labels.switch_on(self.g4_today_lbl) + self.expected_noise_lbl.setText("S20 - S30 (>-60 dBm)") elif k_index_24_hmax == 9: self.switchable_g_today_labels.switch_on(self.g5_today_lbl) + self.expected_noise_lbl.setText("S30+ (>>-60 dBm)") + self.expected_noise_lbl.setStyleSheet(f""" + color:#ffffff; + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #4776e6 ,stop: 1 #8e54e9);""") - self.sfi_lbl.setText(self.space_weather_data.ak_index[7][2].replace('.', '').lstrip('0')) - self.sn_lbl.setText([x[4] for i, x in enumerate(self.space_weather_data.sgas) if "SSN" in x][0].lstrip('0')) + val = int(self.space_weather_data.ak_index[7][2].replace('.', '')) + self.sfi_lbl.setText(f"{val}") + val = int([x[4] for x in self.space_weather_data.sgas if "SSN" in x][0]) + self.sn_lbl.setText(f"{val:d}") + + forecast_labels = (self.forecast_lbl_0, + self.forecast_lbl_1, + self.forecast_lbl_2, + self.forecast_lbl_3, + self.forecast_lbl_4, + self.forecast_lbl_5, + self.forecast_lbl_6, + self.forecast_lbl_7, + self.forecast_lbl_8) + for label, pixmap in zip(forecast_labels, self.space_weather_data.images): + label.setText('') + label.setPixmap(pixmap) + label.setScaledContents(True) else: pop_up(self, title = Messages.BAD_DOWNLOAD, @@ -632,7 +661,7 @@ class Artemis(QMainWindow, Ui_MainWindow): def show_matching_strings(self, list_elements, text): for index in range(list_elements.count()): item = list_elements.item(index) - if text.upper() in item.text() or item.isSelected(): + if text.lower() in item.text().lower() or item.isSelected(): item.setHidden(False) else: item.setHidden(True) diff --git a/artemis.ui b/artemis.ui index 920bdb3..1b5ac82 100644 --- a/artemis.ui +++ b/artemis.ui @@ -178,7 +178,7 @@ QTabWidget::Rounded - 3 + 0 true @@ -4604,704 +4604,1062 @@ www.qrg.globaltuners.com Now - - - - - - - + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + true + + + + X-Rays + + + + + + + + + + 0 + 0 + + 11 - 75 - true - true - X-Rays + Radio Blackout - - - - - 11 - 75 - true - true - + + + + + 0 + 0 + - - Protons-Electrons Flux - - - - - - - - - - 9 - - - - Solar Radiation Storm - - - - - - - - - - - 75 - true - - - - S0 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - S1 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - S2 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - S3 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - S4 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - S5 - - - Qt::AlignCenter - - - - - - - - - - - - - 11 - 75 - true - true - - - - Solar Activity - - - - - - - - - - 9 - 75 - true - - - - K-Index - - - - - - - - 9 - - - - - - - - - - - - - - - - - 9 - 75 - true - - - - A-Index - - - - - - - - 9 - - - - - - - - - - - - - + + + 2 + - + - 9 + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + - EXTREMELY SEVERE + R0 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + R1 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + R2 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + R3 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + R4 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + R5 + + + Qt::AlignCenter + + + + + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + true + + + + Protons-Electrons Flux + + + + + + + + + + 0 + 0 + + + + + 11 + + + + Solar Radiation Storm + + + + + + + + 0 + 0 + + + + + 2 + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + S0 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + S1 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + S2 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + S3 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + S4 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + S5 + + + Qt::AlignCenter + + + + + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + true + + + + Solar Activity + + + + + + + + + + 0 + 0 + + + + + 11 + 75 + true + + + + K-Index: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 12 + + + + - + + + + + + + + + + + + 0 + 0 + + + + + 11 + 75 + true + + + + A-Index: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 12 + + + + - + + + + + + + + + + 0 + 0 + + + + + 1 + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + EXTREMELY SEVERE STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - VERY SEVERE STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - SEVERE STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - MAJOR STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - MINOR STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - ACTIVE - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - UNSETTLED - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - QUIET - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - VERY QUIET - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - INACTIVE - - - Qt::AlignCenter - - - - + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + VERY SEVERE STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + SEVERE STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + MAJOR STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + MINOR STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + ACTIVE + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + UNSETTLED + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + QUIET + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + VERY QUIET + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + INACTIVE + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + + 1 + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + SEVERE STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + MAJOR STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + MINOR STORM + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + ACTIVE + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + UNSETTLED + + + Qt::AlignCenter + + + + + + + + 0 + 0 + + + + + 9 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + QUIET + + + Qt::AlignCenter + + + + + + + + + + + + + 0 + 0 + + + + + 11 + 75 + true + + + + SFI: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + - - - - - - - - 9 - 75 - true - - - - SEVERE STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - MAJOR STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - MINOR STORM - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - ACTIVE - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - UNSETTLED - - - Qt::AlignCenter - - - - - - - - 9 - 75 - true - - - - QUIET - - - Qt::AlignCenter - - - - + + + + + 0 + 0 + + + + + 12 + + + + - + - - - - - - - 9 - 75 - true - - - - SFI - - - - - - - - 9 - - - - - - - - - + + + + + + + + + 0 + 0 + + + + + 11 + 75 + true + + + + SN: + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + - - - - - - - 9 - 75 - true - - - - SN - - - - - - - - 9 - - - - - - - - - + + + + + 0 + 0 + + + + + 12 + + + + - + + - - - - - - - 9 - - - - Geomagnetic Storm (MAX 24 hrs) - - - - - - - - - - - 75 - true - - - - G0 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - G1 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - G2 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - G3 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - G4 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - G5 - - - Qt::AlignCenter - - - - - - - - - - + + + + + + + + + 0 + 0 + + - 9 + 11 @@ -5309,17 +5667,53 @@ STORM + + + + + 0 + 0 + + + + + 11 + + + + Geomagnetic Storm (MAX 24 hrs) + + + + + + + + + + 0 + 0 + + + + 2 + + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G0 @@ -5332,10 +5726,15 @@ STORM + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G1 @@ -5348,10 +5747,15 @@ STORM + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G2 @@ -5364,10 +5768,15 @@ STORM + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G3 @@ -5380,10 +5789,15 @@ STORM + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G4 @@ -5396,10 +5810,156 @@ STORM + 10 75 true + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + G5 + + + Qt::AlignCenter + + + + + + + + + + + 0 + 0 + + + + + 2 + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + G0 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + G1 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + G2 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + G3 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + G4 + + + Qt::AlignCenter + + + + + + + + 10 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + G5 @@ -5413,160 +5973,586 @@ STORM - - - - - - - 9 - - - - Peak Flux Class - - - - - - - - 9 - - - - - - - - Qt::AlignCenter - - - - + + + + + + + + + 0 + 0 + + + + + 11 + + + + Peak Flux Class + + - - - - - - - 9 - - - - Radio Blackout - - - - - - - - - - - 75 - true - - - - R0 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - R1 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - R2 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - R3 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - R4 - - - Qt::AlignCenter - - - - - - - - 75 - true - - - - R5 - - - Qt::AlignCenter - - - - - - - + + + + + 0 + 0 + + + + + 9 + + + + - + + + Qt::AlignCenter + + - - - - + + + + + + + + QFrame::Sunken + + + 1 + + + 0 + + + Qt::Vertical + + + + + + + + 0 + 0 + + + + + + + + 13 + 75 + true + true + + + + Propagation Data + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + E.M.E + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + Meteor Scatter + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + M.U.F. + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + Hystorical Index + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + 50 MHz in EU + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + 70 MHz in EU + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + 144 MHz in EU + + + + + + + + 0 + 0 + + + + + 11 + true + + + + 144 MHz in NA + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 11 + true + + + + VHF Aurora + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 10 + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + true + + + + Expected HF Noise + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 5 + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 10 + + + + + @@ -5614,9 +6600,9 @@ STORM - - - + + + diff --git a/constants.py b/constants.py index b4c6ec7..e513bf8 100644 --- a/constants.py +++ b/constants.py @@ -67,28 +67,28 @@ class Database(object): Signal.CATEGORY_CODE,) class Colors(object): - RED_DARK = "#4d0000" - RED_LIGHT = "#ff0000" + RED_DARK = "#4d0000" + RED_LIGHT = "#ff0000" RED2_DARK = "#4c0c00" RED2_LIGHT = "#ff2700" RED3_DARK = "#4b1100" RED3_LIGHT = "#ff3a00" - ORANGE_DARK = "#4d2e00" - ORANGE_LIGHT = "#ffad33" + ORANGE_DARK = "#4d2e00" + ORANGE_LIGHT = "#ffad33" ORANGE2_DARK = "#4c2000" ORANGE2_LIGHT = "#ff6c00" - GREEN_DARK = "#003300" - GREEN_LIGHT = "#33ff33" + GREEN_DARK = "#003300" + GREEN_LIGHT = "#33ff33" GREEN2_DARK = "#424d00" GREEN2_LIGHT = "#dcff00" GREEN3_DARK = "#344d00" GREEN3_LIGHT = "#aeff00" - BLUE_DARK = "#000033" - BLUE_LIGHT = "#3333ff" - WHITE_DARK = "#333333" - WHITE_LIGHT = "#d9b3ff" - YELLOW_DARK = "#333300" - YELLOW_LIGHT = "#ffff33" + BLUE_DARK = "#000033" + BLUE_LIGHT = "#3333ff" + WHITE_DARK = "#333333" + WHITE_LIGHT = "#d9b3ff" + YELLOW_DARK = "#333300" + YELLOW_LIGHT = "#ffff33" class Constants(object): ACF_DOCS = "https://aresvalley.com/documentation/" @@ -98,6 +98,15 @@ class Constants(object): FORECAST_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt" FORECAST_G = "https://services.swpc.noaa.gov/text/3-day-forecast.txt" FORECAST_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf" + FORECAST_IMG_0 = "http://www.mmmonvhf.de/eme/eme.png" + FORECAST_IMG_1 = "http://www.mmmonvhf.de/ms/ms.png" + FORECAST_IMG_2 = "http://www.mmmonvhf.de/es/es.png" + FORECAST_IMG_3 = "http://www.mmmonvhf.de/solar/solar.png" + FORECAST_IMG_4 = "http://amunters.home.xs4all.nl/eskipstatusNA.gif" + FORECAST_IMG_5 = "http://amunters.home.xs4all.nl/aurorastatus.gif" + FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskip50status.gif" + FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip70status.gif" + FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskipstatus.gif" SEARCH_LABEL_IMG = "search_icon.png" VOLUME_LABEL_IMG = "volume.png" DATA_FOLDER = "Data" diff --git a/space_weather_data.py b/space_weather_data.py index 694c4c8..52bf30a 100644 --- a/space_weather_data.py +++ b/space_weather_data.py @@ -1,5 +1,5 @@ +from PyQt5.QtGui import QPixmap from PyQt5.QtCore import pyqtSlot, pyqtSignal, QObject - from threads import UpadteSpaceWeatherThread, ThreadStatus class SpaceWeatherData(QObject): @@ -12,6 +12,15 @@ class SpaceWeatherData(QObject): self.ak_index = '' self.sgas = '' self.geo_storm = '' + self.images = [QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap()] self.__update_thread = UpadteSpaceWeatherThread(self) self.__update_thread.finished.connect(self.__parse_and_emit_signal) diff --git a/switchable_label.py b/switchable_label.py index 68639b6..5d32e89 100644 --- a/switchable_label.py +++ b/switchable_label.py @@ -11,12 +11,24 @@ class SwitchableLabel(QLabel): self.switch_off_color = off def switch_on(self): - self.setStyleSheet(f"""background-color: {self.switch_on_color}; - color:#000000;""") + if self.switch_on_color and self.switch_off_color: + self.setStyleSheet(f"""background-color: {self.switch_on_color}; + color:#000000;""") + else: + self.setStyleSheet(""" + color:#ffffff; + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #4776e6 ,stop: 1 #8e54e9); + """) def switch_off(self): - self.setStyleSheet(f"""background-color: {self.switch_off_color}; - color:#000000;""") + if self.switch_on_color and self.switch_off_color: + self.setStyleSheet(f"""background-color: {self.switch_off_color}; + color:#000000;""") + else: + self.setStyleSheet(""" + color:#ffffff; + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + """) class SwitchableLabelsIterable(object): diff --git a/themes.py b/themes.py index db2cb69..8d9f419 100644 --- a/themes.py +++ b/themes.py @@ -1,7 +1,7 @@ from functools import partial import os import re -from PyQt5.QtWidgets import QAction +from PyQt5.QtWidgets import QAction, QActionGroup from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QPixmap from constants import Constants @@ -29,6 +29,7 @@ class Theme(object): self.__parent.default_images_folder = os.path.join(ThemeConstants.FOLDER, ThemeConstants.DEFAULT, ThemeConstants.ICONS_FOLDER) + self.__theme_names = {} self.__detect_themes() def __refresh_range_labels(self): @@ -60,21 +61,26 @@ class Theme(object): self.__refresh_range_labels() self.__parent.audio_widget.refresh_btns_colors(self.__parent.active_color, self.__parent.inactive_color) + def __pretty_name(self, bad_name): + return ' '.join( + map(lambda s: s.capitalize(), + bad_name.split('-')[1].split('_') + ) + ) + def __detect_themes(self): themes = [] + ag = QActionGroup(self.__parent, exclusive = True) for theme_folder in os.listdir(ThemeConstants.FOLDER): relative_folder = os.path.join(ThemeConstants.FOLDER, theme_folder) if os.path.isdir(os.path.abspath(relative_folder)): relative_folder = os.path.join(ThemeConstants.FOLDER, theme_folder) themes.append(relative_folder) for theme_path in themes: - theme_name = '&' + ' '.join( - map(lambda s: s.capitalize(), - os.path.basename(theme_path).split('-')[1].split('_') - ) - ) - new_theme = QAction(theme_name, self.__parent) + theme_name = '&' + self.__pretty_name(os.path.basename(theme_path)) + new_theme = ag.addAction(QAction(theme_name, self.__parent, checkable = True)) self.__parent.menu_themes.addAction(new_theme) + self.__theme_names[theme_name.lstrip('&')] = new_theme new_theme.triggered.connect(partial(self.__apply, theme_path)) def __change(self): @@ -163,5 +169,9 @@ class Theme(object): if os.path.exists(current_theme_file): with open(current_theme_file, "r") as current_theme_path: theme_path = current_theme_path.read() + theme_name = self.__pretty_name(os.path.basename(theme_path)) + self.__theme_names[theme_name].setChecked(True) if theme_path != ThemeConstants.DEFAULT: self.__apply(theme_path) + else: + self.__theme_names[self.__pretty_name(ThemeConstants.DEFAULT)].setChecked(True) diff --git a/threads.py b/threads.py index 8ea2cbb..0ca188b 100644 --- a/threads.py +++ b/threads.py @@ -78,5 +78,14 @@ class UpadteSpaceWeatherThread(QThread): self.__space_weather_data.ak_index = str(urllib3.PoolManager().request('GET', Constants.FORECAST_AK_IND).data, 'utf-8') self.__space_weather_data.sgas = str(urllib3.PoolManager().request('GET', Constants.FORECAST_SGAS).data, 'utf-8') self.__space_weather_data.geo_storm = str(urllib3.PoolManager().request('GET', Constants.FORECAST_G).data, 'utf-8') + self.__space_weather_data.images[0].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_0).data) + self.__space_weather_data.images[1].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_1).data) + self.__space_weather_data.images[2].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_2).data) + self.__space_weather_data.images[3].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_3).data) + self.__space_weather_data.images[4].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_4).data) + self.__space_weather_data.images[5].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_5).data) + self.__space_weather_data.images[6].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_6).data) + self.__space_weather_data.images[7].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_7).data) + self.__space_weather_data.images[8].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_8).data) except: self.__status = ThreadStatus.UNKNOWN_ERR From 3d4961825d22e41c71f1fe87a36883f10a0b737a Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sat, 6 Apr 2019 18:57:54 +0200 Subject: [PATCH 05/11] Fix a label font size --- artemis.ui | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artemis.ui b/artemis.ui index 1b5ac82..e94f866 100644 --- a/artemis.ui +++ b/artemis.ui @@ -6005,7 +6005,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - 9 + 12 From 3742e5372e17a7f6397643036fb79eba6ad06ddb Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 7 Apr 2019 13:12:13 +0200 Subject: [PATCH 06/11] Only update speca weather if it not already updating. Also remove QPixmaps if already displayed --- artemis.py | 5 +++-- constants.py | 6 +++--- space_weather_data.py | 13 +++++++++++++ 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/artemis.py b/artemis.py index a6cd62c..5ffda16 100644 --- a/artemis.py +++ b/artemis.py @@ -463,8 +463,9 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def start_update_space_weather(self): - self.update_now_bar.setMaximum(self.update_now_bar.minimum()) - self.space_weather_data.update() + if not self.space_weather_data.is_updating: + self.update_now_bar.setMaximum(self.update_now_bar.minimum()) + self.space_weather_data.update() @pyqtSlot(bool) def update_space_weather(self, status_ok): diff --git a/constants.py b/constants.py index e513bf8..b7c5cae 100644 --- a/constants.py +++ b/constants.py @@ -104,9 +104,9 @@ class Constants(object): FORECAST_IMG_3 = "http://www.mmmonvhf.de/solar/solar.png" FORECAST_IMG_4 = "http://amunters.home.xs4all.nl/eskipstatusNA.gif" FORECAST_IMG_5 = "http://amunters.home.xs4all.nl/aurorastatus.gif" - FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskip50status.gif" - FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip70status.gif" - FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskipstatus.gif" + FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskipstatus.gif" + FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip50status.gif" + FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskip70status.gif" SEARCH_LABEL_IMG = "search_icon.png" VOLUME_LABEL_IMG = "volume.png" DATA_FOLDER = "Data" diff --git a/space_weather_data.py b/space_weather_data.py index 52bf30a..3f6191d 100644 --- a/space_weather_data.py +++ b/space_weather_data.py @@ -24,6 +24,10 @@ class SpaceWeatherData(QObject): self.__update_thread = UpadteSpaceWeatherThread(self) self.__update_thread.finished.connect(self.__parse_and_emit_signal) + @property + def is_updating(self): + return self.__update_thread.isRunning() + @pyqtSlot() def update(self): self.__update_thread.start() @@ -42,6 +46,15 @@ class SpaceWeatherData(QObject): self.ak_index = '' self.sgas = '' self.geo_storm = '' + self.images = [QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap(), + QPixmap()] @pyqtSlot() def __parse_and_emit_signal(self): From 40ce9057f49bc5d91a59d55696778311b5bc02fd Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 7 Apr 2019 15:41:52 +0200 Subject: [PATCH 07/11] Add clickable progress bar class. Few changes of main screen. Round floating point numbers to 2 decimanl digits in man screen. Hide border in mode screen for themes --- artemis.py | 9 +- artemis.ui | 966 ++++++++++-------- clickable_progress_bar.py | 31 + constants.py | 182 ++-- themes/2-dark/dark.qss | 13 +- .../material_design_dark.qss | 19 +- .../material_design_light.qss | 19 +- utilities.py | 4 + 8 files changed, 683 insertions(+), 560 deletions(-) create mode 100644 clickable_progress_bar.py diff --git a/artemis.py b/artemis.py index 5ffda16..3ce3b70 100644 --- a/artemis.py +++ b/artemis.py @@ -27,7 +27,7 @@ from audio_player import AudioPlayer from space_weather_data import SpaceWeatherData from double_text_button import DoubleTextButton from download_window import DownloadWindow -from switchable_label import SwitchableLabel, SwitchableLabelsIterable +from switchable_label import SwitchableLabelsIterable from constants import (Constants, Ftype, GfdType, @@ -376,7 +376,8 @@ class Artemis(QMainWindow, Ui_MainWindow): # Space weather self.info_now_btn.clicked.connect(lambda : webbrowser.open(Constants.FORECAST_INFO)) - self.update_now_btn.clicked.connect(self.start_update_space_weather) + self.update_now_bar.clicked.connect(self.start_update_space_weather) + self.update_now_bar.set_idle() self.space_weather_data = SpaceWeatherData() self.space_weather_data.update_complete.connect(self.update_space_weather) self.switchable_r_labels = SwitchableLabelsIterable(self.r0_now_lbl, @@ -464,12 +465,12 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def start_update_space_weather(self): if not self.space_weather_data.is_updating: - self.update_now_bar.setMaximum(self.update_now_bar.minimum()) + self.update_now_bar.set_updating() self.space_weather_data.update() @pyqtSlot(bool) def update_space_weather(self, status_ok): - self.update_now_bar.setMaximum(self.update_now_bar.minimum() + 1) + self.update_now_bar.set_idle() if status_ok: xray_long = float(self.space_weather_data.xray[-1][7]) format_text = lambda letter, power : letter + f"{xray_long * 10**power:.1f}" diff --git a/artemis.ui b/artemis.ui index e94f866..d633fe0 100644 --- a/artemis.ui +++ b/artemis.ui @@ -199,8 +199,46 @@ Main - - + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 90 + 20 + + + + + + + + + 11 + + + + border: 0px; +/*border-radius: 8px;*/ + + + Qt::ScrollBarAsNeeded + + + Qt::ScrollBarAsNeeded + + + true + + + + @@ -233,297 +271,391 @@ p, li { white-space: pre-wrap; } - - - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Mode - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Frequency - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Modulation - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Location - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 12 - - - - N/A - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Bandwidth - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - 0 - 0 - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - ACF - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Description + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 90 + 20 + + + + + + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 12 + + + + N/A + + + + + + + + 0 + 0 + + + + + 12 + + + + N/A + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Mode + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 12 + + + + N/A + + + + + + + + 0 + 0 + + + + + 12 + + + + N/A + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Frequency + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 12 + + + + N/A + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Modulation + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Location + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 12 + + + + N/A + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Bandwidth + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + ACF + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + + 0 + 0 + + + + + + + false + + + + 0 + 0 + + + + + 12 + 75 + true + true + + + + <html><head/><body><p><span style=" color:#000000;">Go to the signal's wiki.</span></p></body></html> + + + + + + Signal's wiki + + + true + + + + + + + - + @@ -1032,99 +1164,25 @@ p, li { white-space: pre-wrap; } - - - - - 0 - 0 - - - - - - - false - - - - 0 - 0 - - - - - 12 - 75 - true - true - - - - <html><head/><body><p><span style=" color:#000000;">Go to the signal's wiki.</span></p></body></html> - - - - - - Signal's wiki - - - true - - - - - - - - - - - 0 - 0 - + + + + Qt::Vertical - - - 12 - 75 - true - + + QSizePolicy::MinimumExpanding - - Description + + + 20 + 20 + - - Qt::AlignCenter - - + - - - - - 11 - - - - border: 0px; -/*border-radius: 8px;*/ - - - Qt::ScrollBarAsNeeded - - - Qt::ScrollBarAsNeeded - - - true - - - - + <html><head/><body><p><span style=" color:#000000;">Frequency bands</span></p></body></html> @@ -3516,20 +3574,20 @@ Inactive Mode - - + + Qt::Horizontal - 171 + 170 20 - + @@ -3563,50 +3621,6 @@ Inactive - - - - Qt::Horizontal - - - - 170 - 20 - - - - - - - - - 12 - 75 - true - - - - Apply - - - true - - - - - - - - 12 - 75 - true - - - - Reset - - - @@ -3624,6 +3638,66 @@ Inactive + + + + + 12 + 75 + true + + + + Apply + + + true + + + + + + + + 12 + 75 + true + + + + Reset + + + + + + + Qt::Horizontal + + + + 171 + 20 + + + + + + + + Qt::Vertical + + + QSizePolicy::Minimum + + + + 20 + 20 + + + + @@ -6568,34 +6642,37 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - 0 - 0 - - - - Update - - - - - + 0 0 + + + 8 + 75 + true + + + + + 1 -1 + + Qt::AlignCenter + - false + true + + + %p% @@ -6936,6 +7013,11 @@ QSlider::handle:horizontal { QLabel
switchable_label.h
+ + ClickableProgressBar + QProgressBar +
clickable_progress_bar.h
+
diff --git a/clickable_progress_bar.py b/clickable_progress_bar.py new file mode 100644 index 0000000..0cbf2fc --- /dev/null +++ b/clickable_progress_bar.py @@ -0,0 +1,31 @@ +from PyQt5.QtWidgets import QProgressBar +from PyQt5.QtCore import Qt, pyqtSignal +from constants import Constants + +class ClickableProgressBar(QProgressBar): + + clicked = pyqtSignal() + + def __init__(self, parent = None): + self.__text = '' + super().__init__(parent) + + def __set_text(self, text): + self.__text = text + + def text(self): + return self.__text + + def set_idle(self): + self.__set_text(Constants.CLICK_TO_UPDATE_STR) + self.setMaximum(self.minimum() + 1) + + def set_updating(self): + self.__set_text(Constants.UPDATING_STR) + self.setMaximum(self.minimum()) + + def mousePressEvent(self, event): + if event.button() == Qt.LeftButton: + self.clicked.emit() + else: + super().mousePressEvent(event) diff --git a/constants.py b/constants.py index b7c5cae..d52c367 100644 --- a/constants.py +++ b/constants.py @@ -91,65 +91,67 @@ class Colors(object): YELLOW_LIGHT = "#ffff33" class Constants(object): - ACF_DOCS = "https://aresvalley.com/documentation/" - FORECAST_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt" - FORECAST_PROT = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt" - FORECAST_AK_IND = "https://services.swpc.noaa.gov/text/wwv.txt" - FORECAST_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt" - FORECAST_G = "https://services.swpc.noaa.gov/text/3-day-forecast.txt" - FORECAST_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf" - FORECAST_IMG_0 = "http://www.mmmonvhf.de/eme/eme.png" - FORECAST_IMG_1 = "http://www.mmmonvhf.de/ms/ms.png" - FORECAST_IMG_2 = "http://www.mmmonvhf.de/es/es.png" - FORECAST_IMG_3 = "http://www.mmmonvhf.de/solar/solar.png" - FORECAST_IMG_4 = "http://amunters.home.xs4all.nl/eskipstatusNA.gif" - FORECAST_IMG_5 = "http://amunters.home.xs4all.nl/aurorastatus.gif" - FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskipstatus.gif" - FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip50status.gif" - FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskip70status.gif" - SEARCH_LABEL_IMG = "search_icon.png" - VOLUME_LABEL_IMG = "volume.png" - DATA_FOLDER = "Data" - SPECTRA_FOLDER = "Spectra" - SPECTRA_EXT = ".png" - AUDIO_FOLDER = "Audio" - ACTIVE = "active" - INACTIVE = "inactive" - NOT_AVAILABLE = "spectrumnotavailable.png" - NOT_SELECTED = "nosignalselected.png" - __Band = namedtuple("Band", ["lower", "upper"]) - __ELF = __Band(0, 30) # Formally it is (3, 30) Hz. - __SLF = __Band(30, 300) - __ULF = __Band(300, 3000) - __VLF = __Band(3000, 30000) - __LF = __Band(30 * 10**3, 300 * 10**3) - __MF = __Band(300 * 10 ** 3, 3000 * 10**3) - __HF = __Band(3 * 10**6, 30 * 10**6) - __VHF = __Band(30 * 10**6, 300 * 10**6) - __UHF = __Band(300 * 10**6, 3000 * 10**6) - __SHF = __Band(3 * 10**9, 30 * 10**9) - __EHF = __Band(30 * 10**9, 300 * 10**9) - BANDS = (__ELF, __SLF, __ULF, __VLF, __LF, __MF, __HF, __VHF, __UHF, __SHF, __EHF) - MAX_DIGITS = 3 - RANGE_SEPARATOR = ' ÷ ' - GFD_SITE = "http://qrg.globaltuners.com/" - CONVERSION_FACTORS = {"Hz" : 1, - "kHz": 1000, - "MHz": 1000000, - "GHz": 1000000000} - MODES = {"FM": ("NFM", "WFM"), - "AM": (), - "CW": (), - "SK": ("FSK", "PSK", "MSK"), - "SB": ("LSB", "USB", "DSB"), - "Chirp Spread Spectrum": (), - "FHSS-TDM": (), - "RAW": (), - "SC-FDMA": (),} - APPLY = "Apply" - REMOVE = "Remove" - UNKNOWN = "N/A" - MODULATIONS = ("8VSB", + CLICK_TO_UPDATE_STR = "Click to update" + UPDATING_STR = "Updating..." + ACF_DOCS = "https://aresvalley.com/documentation/" + FORECAST_XRAY = "https://services.swpc.noaa.gov/text/goes-xray-flux-primary.txt" + FORECAST_PROT = "https://services.swpc.noaa.gov/text/goes-particle-flux-primary.txt" + FORECAST_AK_IND = "https://services.swpc.noaa.gov/text/wwv.txt" + FORECAST_SGAS = "https://services.swpc.noaa.gov/text/sgas.txt" + FORECAST_G = "https://services.swpc.noaa.gov/text/3-day-forecast.txt" + FORECAST_INFO = "https://www.swpc.noaa.gov/sites/default/files/images/NOAAscales.pdf" + FORECAST_IMG_0 = "http://www.mmmonvhf.de/eme/eme.png" + FORECAST_IMG_1 = "http://www.mmmonvhf.de/ms/ms.png" + FORECAST_IMG_2 = "http://www.mmmonvhf.de/es/es.png" + FORECAST_IMG_3 = "http://www.mmmonvhf.de/solar/solar.png" + FORECAST_IMG_4 = "http://amunters.home.xs4all.nl/eskipstatusNA.gif" + FORECAST_IMG_5 = "http://amunters.home.xs4all.nl/aurorastatus.gif" + FORECAST_IMG_6 = "http://amunters.home.xs4all.nl/eskipstatus.gif" + FORECAST_IMG_7 = "http://amunters.home.xs4all.nl/eskip50status.gif" + FORECAST_IMG_8 = "http://amunters.home.xs4all.nl/eskip70status.gif" + SEARCH_LABEL_IMG = "search_icon.png" + VOLUME_LABEL_IMG = "volume.png" + DATA_FOLDER = "Data" + SPECTRA_FOLDER = "Spectra" + SPECTRA_EXT = ".png" + AUDIO_FOLDER = "Audio" + ACTIVE = "active" + INACTIVE = "inactive" + NOT_AVAILABLE = "spectrumnotavailable.png" + NOT_SELECTED = "nosignalselected.png" + __Band = namedtuple("Band", ["lower", "upper"]) + __ELF = __Band(0, 30) # Formally it is (3, 30) Hz. + __SLF = __Band(30, 300) + __ULF = __Band(300, 3000) + __VLF = __Band(3000, 30000) + __LF = __Band(30 * 10**3, 300 * 10**3) + __MF = __Band(300 * 10 ** 3, 3000 * 10**3) + __HF = __Band(3 * 10**6, 30 * 10**6) + __VHF = __Band(30 * 10**6, 300 * 10**6) + __UHF = __Band(300 * 10**6, 3000 * 10**6) + __SHF = __Band(3 * 10**9, 30 * 10**9) + __EHF = __Band(30 * 10**9, 300 * 10**9) + BANDS = (__ELF, __SLF, __ULF, __VLF, __LF, __MF, __HF, __VHF, __UHF, __SHF, __EHF) + MAX_DIGITS = 3 + RANGE_SEPARATOR = ' ÷ ' + GFD_SITE = "http://qrg.globaltuners.com/" + CONVERSION_FACTORS = {"Hz" : 1, + "kHz": 1000, + "MHz": 1000000, + "GHz": 1000000000} + MODES = {"FM": ("NFM", "WFM"), + "AM": (), + "CW": (), + "SK": ("FSK", "PSK", "MSK"), + "SB": ("LSB", "USB", "DSB"), + "Chirp Spread Spectrum": (), + "FHSS-TDM": (), + "RAW": (), + "SC-FDMA": (),} + APPLY = "Apply" + REMOVE = "Remove" + UNKNOWN = "N/A" + MODULATIONS = ("8VSB", "AFSK", "AM", "BFSK", @@ -174,34 +176,34 @@ class Constants(object): "PSK", "QAM", "TDMA",) - LOCATIONS = (UNKNOWN, - "Australia", - "Canada", - "Central Europe", - "China", - "Cyprus", - "Eastern Europe", - "Europe", - "Europe, japan and Asia", - "Exmouth, Australia", - "Finland", - "France", - "Germany", - "Home Base Mobile , AL", - "Hungary", - "Iran", - "Israel", - "Japan", - "LaMour, North Dakota", - "Lualualei, Hawaii", - "North America", - "North Korea", - "Poland", - "Romania", - "Ruda, Sweden", - "UK", - "United Kingdom", - "United States", - "Varberg, Sweden", - "World Wide", - "Worldwide",) + LOCATIONS = (UNKNOWN, + "Australia", + "Canada", + "Central Europe", + "China", + "Cyprus", + "Eastern Europe", + "Europe", + "Europe, japan and Asia", + "Exmouth, Australia", + "Finland", + "France", + "Germany", + "Home Base Mobile , AL", + "Hungary", + "Iran", + "Israel", + "Japan", + "LaMour, North Dakota", + "Lualualei, Hawaii", + "North America", + "North Korea", + "Poland", + "Romania", + "Ruda, Sweden", + "UK", + "United Kingdom", + "United States", + "Varberg, Sweden", + "World Wide", + "Worldwide",) diff --git a/themes/2-dark/dark.qss b/themes/2-dark/dark.qss index cdc3f79..bece62f 100644 --- a/themes/2-dark/dark.qss +++ b/themes/2-dark/dark.qss @@ -137,7 +137,7 @@ QLabel { QDialog { background-color: transparent; color: #949a9c; -} +} QTextBrowser { background-color: transparent; @@ -157,15 +157,15 @@ QLineEdit { QLineEdit:hover { border-width: 1px; border-radius: 10px; - border-style: solid; - border-color: #4545e5 ; + border-style: solid; + border-color: #4545e5 ; } QLineEdit:focus { border-width: 1px; border-radius: 10px; - border-style: solid; - border-color: #4545e5 ; + border-style: solid; + border-color: #4545e5 ; } /************************************* @@ -307,7 +307,7 @@ QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 20px; - border-top-right-radius: 2px; + border-top-right-radius: 2px; border-bottom-right-radius: 2px; } @@ -433,6 +433,7 @@ TreeViewMenu (Mode) QTreeView { background-color: transparent; selection-background-color: transparent; + border: 0px; } QTreeView::item { diff --git a/themes/3-material_design_dark/material_design_dark.qss b/themes/3-material_design_dark/material_design_dark.qss index bdfe948..86f5544 100644 --- a/themes/3-material_design_dark/material_design_dark.qss +++ b/themes/3-material_design_dark/material_design_dark.qss @@ -158,7 +158,7 @@ QLabel { QDialog { background-color: transparent; color: #949a9c; -} +} QTextBrowser { background-color: transparent; @@ -172,19 +172,19 @@ QLineEdit { background-color: transparent; selection-background-color: #669900; color: #669900; - border-width: 1px; - border-style: solid; - border-color: transparent transparent #669900 transparent; + border-width: 1px; + border-style: solid; + border-color: transparent transparent #669900 transparent; } QLineEdit:hover { - border-width: 2px; - border-color: transparent transparent #88cc00 transparent; + border-width: 2px; + border-color: transparent transparent #88cc00 transparent; } QLineEdit:focus { - border-width: 2px; - border-color: transparent transparent #88cc00 transparent; + border-width: 2px; + border-color: transparent transparent #88cc00 transparent; } /************************************* @@ -326,7 +326,7 @@ QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 20px; - border-top-right-radius: 2px; + border-top-right-radius: 2px; border-bottom-right-radius: 2px; } @@ -452,6 +452,7 @@ TreeViewMenu (Mode) QTreeView { background-color: transparent; selection-background-color: transparent; + border: 0px; } QTreeView::item { diff --git a/themes/4-material_design_light/material_design_light.qss b/themes/4-material_design_light/material_design_light.qss index f206187..4874c85 100644 --- a/themes/4-material_design_light/material_design_light.qss +++ b/themes/4-material_design_light/material_design_light.qss @@ -158,7 +158,7 @@ QLabel { QDialog { background-color: transparent; color: #29353B; -} +} QTextBrowser { background-color: transparent; @@ -172,19 +172,19 @@ QLineEdit { background-color: transparent; selection-background-color: #669900; color: #669900; - border-width: 1px; - border-style: solid; - border-color: transparent transparent #669900 transparent; + border-width: 1px; + border-style: solid; + border-color: transparent transparent #669900 transparent; } QLineEdit:hover { - border-width: 2px; - border-color: transparent transparent #6ECE12 transparent; + border-width: 2px; + border-color: transparent transparent #6ECE12 transparent; } QLineEdit:focus { - border-width: 2px; - border-color: transparent transparent #6ECE12 transparent; + border-width: 2px; + border-color: transparent transparent #6ECE12 transparent; } /************************************* @@ -326,7 +326,7 @@ QComboBox::drop-down { subcontrol-origin: padding; subcontrol-position: top right; width: 20px; - border-top-right-radius: 2px; + border-top-right-radius: 2px; border-bottom-right-radius: 2px; } @@ -452,6 +452,7 @@ TreeViewMenu (Mode) QTreeView { background-color: transparent; selection-background-color: transparent; + border: 0px; } QTreeView::item { diff --git a/utilities.py b/utilities.py index 51d7c66..7401e24 100644 --- a/utilities.py +++ b/utilities.py @@ -97,8 +97,12 @@ def format_numbers(lower, upper): upper = int(upper) / upper_factor if lower.is_integer(): lower = int(lower) + else: + lower = round(lower, 2) if upper.is_integer(): upper = int(upper) + else: + upper = round(upper, 2) if pre_lower != pre_upper: return f"{lower:,} {units[lower_factor]} - {upper:,} {units[upper_factor]}" else: From 7625016b56ad1023f2476ddb38ef86354c4e1d09 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sat, 13 Apr 2019 15:17:11 +0200 Subject: [PATCH 08/11] Fix bug in download_window.py. Set fixed aspect ratio for forecast images. --- .gitignore | 4 +- artemis.py | 65 ++-- artemis.ui | 592 +++++++++++++++++++++-------------- download_window.py | 20 +- fixed_aspect_ratio_label.py | 14 + fixed_aspect_ratio_widget.py | 19 ++ threads.py | 9 +- 7 files changed, 435 insertions(+), 288 deletions(-) create mode 100644 fixed_aspect_ratio_label.py create mode 100644 fixed_aspect_ratio_widget.py diff --git a/.gitignore b/.gitignore index 4cca36c..bcc7033 100644 --- a/.gitignore +++ b/.gitignore @@ -5,9 +5,7 @@ wav_converter.py to_do.txt csv_info.txt pyinstaller_cmd.txt -icons_imgs -TestData themes/.current_theme *.bat *.sh -splash.jpg \ No newline at end of file +.vscode/ diff --git a/artemis.py b/artemis.py index 3ce3b70..1eb0689 100644 --- a/artemis.py +++ b/artemis.py @@ -1,7 +1,6 @@ from collections import namedtuple from itertools import chain from functools import partial -from glob import glob import webbrowser import os import sys @@ -15,7 +14,6 @@ from PyQt5.QtWidgets import (QMainWindow, QListWidgetItem, QMessageBox, QSplashScreen, - QTreeView, QTreeWidgetItem,) from PyQt5.QtGui import QPixmap from PyQt5 import uic @@ -25,7 +23,6 @@ from PyQt5.QtCore import (QFileInfo, from audio_player import AudioPlayer from space_weather_data import SpaceWeatherData -from double_text_button import DoubleTextButton from download_window import DownloadWindow from switchable_label import SwitchableLabelsIterable from constants import (Constants, @@ -44,11 +41,10 @@ from utilities import (checksum_ok, filters_ok, is_undef_freq, is_undef_band, - change_unit, format_numbers, resource_path,) -import icon_rc +# import icon_rc qt_creator_file = resource_path("artemis.ui") Ui_MainWindow, _ = uic.loadUiType(qt_creator_file) @@ -60,6 +56,7 @@ class Artemis(QMainWindow, Ui_MainWindow): self.setupUi(self) self.set_initial_size() self.download_window = DownloadWindow() + self.download_window.complete.connect(self.show_downloaded_signals) self.actionExit.triggered.connect(qApp.quit) self.action_update_database.triggered.connect(self.ask_if_download) self.action_check_db_ver.triggered.connect(self.check_db_ver) @@ -456,11 +453,21 @@ class Artemis(QMainWindow, Ui_MainWindow): chain(k_storms_colors, a_storm_colors)): lab.set_colors(None, None) + self.forecast_labels = (self.forecast_lbl_0, + self.forecast_lbl_1, + self.forecast_lbl_2, + self.forecast_lbl_3, + self.forecast_lbl_4, + self.forecast_lbl_5, + self.forecast_lbl_6, + self.forecast_lbl_7, + self.forecast_lbl_8) + self.forecast_label_container.labels = self.forecast_labels + # Final operations. self.theme.initialize() self.load_db() self.display_signals() - self.show() @pyqtSlot() def start_update_space_weather(self): @@ -610,20 +617,11 @@ class Artemis(QMainWindow, Ui_MainWindow): val = int([x[4] for x in self.space_weather_data.sgas if "SSN" in x][0]) self.sn_lbl.setText(f"{val:d}") - forecast_labels = (self.forecast_lbl_0, - self.forecast_lbl_1, - self.forecast_lbl_2, - self.forecast_lbl_3, - self.forecast_lbl_4, - self.forecast_lbl_5, - self.forecast_lbl_6, - self.forecast_lbl_7, - self.forecast_lbl_8) - for label, pixmap in zip(forecast_labels, self.space_weather_data.images): + for label, pixmap in zip(self.forecast_labels, self.space_weather_data.images): label.setText('') - label.setPixmap(pixmap) - label.setScaledContents(True) - + label.pixmap = pixmap + label.setPixmap(pixmap.scaled(label.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) + label.setStyleSheet("background-color: transparent;") else: pop_up(self, title = Messages.BAD_DOWNLOAD, text = Messages.BAD_DOWNLOAD_MSG).show() @@ -687,10 +685,8 @@ class Artemis(QMainWindow, Ui_MainWindow): item.child(i).setSelected(True) def set_initial_size(self): - """ - Function to handle high resolution screens. The function sets bigger sizes - for all the relevant fixed-size widgets. - """ + """Function to handle high resolution screens. The function sets bigger sizes + for all the relevant fixed-size widgets.""" d = QDesktopWidget().availableGeometry() w = d.width() h = d.height() @@ -738,7 +734,6 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def download_db(self): if not self.download_window.isVisible(): - self.download_window.download_thread.finished.connect(self.show_downloaded_signals) self.download_window.download_thread.start() self.download_window.show() @@ -782,6 +777,8 @@ class Artemis(QMainWindow, Ui_MainWindow): text = Messages.NO_DB_AVAIL, informative_text = Messages.DOWNLOAD_NOW_QUESTION, is_question = True).exec() + if answer == QMessageBox.Yes: + self.download_db() else: try: is_checksum_ok = checksum_ok(db, ChecksumWhat.DB) @@ -792,7 +789,6 @@ class Artemis(QMainWindow, Ui_MainWindow): if is_checksum_ok: pop_up(self, title = Messages.DB_UP_TO_DATE, text = Messages.DB_UP_TO_DATE_MSG).show() - else: answer = pop_up(self, title = Messages.DB_NEW_VER, text = Messages.DB_NEW_VER_MSG, @@ -803,10 +799,9 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def show_downloaded_signals(self): - if self.download_window.everything_ok: - self.search_bar.setEnabled(True) - self.load_db() - self.display_signals() + self.search_bar.setEnabled(True) + self.load_db() + self.display_signals() def load_db(self): names = Database.NAMES @@ -831,7 +826,9 @@ class Artemis(QMainWindow, Ui_MainWindow): self.db.fillna(Constants.UNKNOWN, inplace = True) self.db[Signal.WIKI_CLICKED] = False self.update_status_tip(self.total_signals) + self.result_list.clear() self.result_list.addItems(self.signal_names) + self.result_list.setCurrentItem(None) @pyqtSlot() def set_min_value_upper_limit(self, lower_combo_box, @@ -845,7 +842,6 @@ class Artemis(QMainWindow, Ui_MainWindow): lower_units = lower_combo_box.currentText() upper_units = upper_combo_box.currentText() lower_value = lower_spin_box.value() - upper_value = upper_spin_box.value() inf_limit = (lower_value * Constants.CONVERSION_FACTORS[lower_units]) \ // Constants.CONVERSION_FACTORS[upper_units] counter = 0 @@ -949,7 +945,7 @@ class Artemis(QMainWindow, Ui_MainWindow): else: self.result_list.item(index).setHidden(True) # Remove selected item. - self.result_list.selectionModel().clear() + self.result_list.setCurrentItem(None) self.update_status_tip(available_signals) def update_status_tip(self, available_signals): @@ -1123,7 +1119,6 @@ class Artemis(QMainWindow, Ui_MainWindow): selected_items = [item for item in self.mode_tree_widget.selectedItems()] selected_items_text = [i.text(0) for i in selected_items] parents = [item for item in selected_items_text if item in Constants.MODES.keys()] - children = [item for item in selected_items_text if item not in parents] ok = [] for item in selected_items: if item.text(0) in parents: @@ -1288,11 +1283,11 @@ class Artemis(QMainWindow, Ui_MainWindow): if __name__ == '__main__': my_app = QApplication(sys.argv) - img = QPixmap(":/icons/Artemis3.500px.png") - # img = img.scaled(600, 600, aspectRatioMode = Qt.KeepAspectRatio) + # img = QPixmap(":/icons/Artemis3.500px.png") # splash = QSplashScreen(img) # splash.show() # sleep(2) - w = Artemis() + artemis = Artemis() + artemis.show() # splash.finish(w) sys.exit(my_app.exec_()) diff --git a/artemis.ui b/artemis.ui index d633fe0..690fa4c 100644 --- a/artemis.ui +++ b/artemis.ui @@ -6119,7 +6119,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto 0
- + @@ -6144,6 +6144,9 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto + + 0 + @@ -6163,30 +6166,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - @@ -6206,30 +6185,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - @@ -6249,30 +6204,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - @@ -6292,30 +6223,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - @@ -6335,30 +6242,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - @@ -6378,30 +6261,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - @@ -6421,7 +6280,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - + @@ -6440,31 +6299,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - + @@ -6483,52 +6318,292 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - - 12 - 75 - true - + + + + + 0 + 0 + - - color:#ffffff; + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Qt::NoFocus + + + color:#ffffff; background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 12 - 75 - true - - - - color:#ffffff; + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 0 + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + color:#ffffff; +background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + + + OFF + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + @@ -6588,27 +6663,63 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - 0 - 0 - - - - - 13 - 75 - true - - - - - - - Qt::AlignCenter - - + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 13 + 75 + true + + + + + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Maximum + + + + 40 + 20 + + + + + @@ -7018,6 +7129,17 @@ QSlider::handle:horizontal { QProgressBar
clickable_progress_bar.h
+ + FixedAspectRatioWidget + QWidget +
fixed_aspect_ratio_widget.h
+ 1 +
+ + FixedAspectRatioLabel + QLabel +
fixed_aspect_ratio_label.h
+
diff --git a/download_window.py b/download_window.py index 47907e2..6957f63 100644 --- a/download_window.py +++ b/download_window.py @@ -1,5 +1,5 @@ from PyQt5 import uic -from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal from PyQt5.QtWidgets import QWidget from threads import DownloadThread, ThreadStatus from utilities import pop_up, resource_path @@ -8,6 +8,9 @@ from constants import Messages Ui_Download_window, _ = uic.loadUiType(resource_path("download_db_window.ui")) class DownloadWindow(QWidget, Ui_Download_window): + + complete = pyqtSignal() + def __init__(self): super().__init__() self.setupUi(self) @@ -18,7 +21,6 @@ class DownloadWindow(QWidget, Ui_Download_window): Qt.WindowCloseButtonHint #| # Qt.WindowStaysOnTopHint ) - self.everything_ok = True self.no_internet_msg = pop_up(self, title = Messages.NO_CONNECTION, text = Messages.NO_CONNECTION_MSG, @@ -30,17 +32,8 @@ class DownloadWindow(QWidget, Ui_Download_window): self.download_thread = DownloadThread() self.download_thread.finished.connect(self.wait_close) - self.cancel_btn.clicked.connect(self.terminate_process) - def show_no_connection_warning(self): - self.no_internet_msg.show() - self.everything_ok = False - - def show_bad_download_warning(self): - self.bad_db_download_msg.show() - self.everything_ok = False - @pyqtSlot() def terminate_process(self): if self.download_thread.isRunning(): @@ -51,11 +44,12 @@ class DownloadWindow(QWidget, Ui_Download_window): @pyqtSlot() def wait_close(self): if self.download_thread.status is ThreadStatus.OK: + self.complete.emit() self.close() elif self.download_thread.status is ThreadStatus.NO_CONNECTION_ERR: - self.show_no_connection_warning() + self.no_internet_msg.show() elif self.download_thread.status is ThreadStatus.BAD_DOWNLOAD_ERR: - self.show_bad_download_warning() + self.bad_db_download_msg.show() else: self.close() diff --git a/fixed_aspect_ratio_label.py b/fixed_aspect_ratio_label.py new file mode 100644 index 0000000..e73103f --- /dev/null +++ b/fixed_aspect_ratio_label.py @@ -0,0 +1,14 @@ +from PyQt5.QtWidgets import QLabel +from PyQt5.QtCore import QSize, Qt + +class FixedAspectRatioLabel(QLabel): + def __init__(self, parent = None): + super().__init__(parent) + self.pixmap = None + + def rescale(self, w, h): + self.resize(QSize(w, h)) + if self.pixmap: + self.setPixmap( + self.pixmap.scaled( + self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) diff --git a/fixed_aspect_ratio_widget.py b/fixed_aspect_ratio_widget.py new file mode 100644 index 0000000..a867899 --- /dev/null +++ b/fixed_aspect_ratio_widget.py @@ -0,0 +1,19 @@ +from PyQt5.QtWidgets import QWidget + +class FixedAspectRatioWidget(QWidget): + space = 10 + def __init__(self, parent = None): + super().__init__(parent) + self.labels = [] + + def resizeEvent(self, event): + h, w = self.height(), self.width() + h_lbl = h / 9 - self.space + w_lbl = 5 * h_lbl + + if w_lbl > w: + w_lbl = w + h_lbl = h / 9 - self.space + + for label in self.labels: + label.rescale(w_lbl, h_lbl) diff --git a/threads.py b/threads.py index 0ca188b..50a6c0d 100644 --- a/threads.py +++ b/threads.py @@ -14,11 +14,12 @@ class ThreadStatus(Enum): NO_CONNECTION_ERR = auto() UNKNOWN_ERR = auto() BAD_DOWNLOAD_ERR = auto() + UNDEFINED = auto() class DownloadThread(QThread): def __init__(self): super().__init__() - self.__status = ThreadStatus.OK + self.__status = ThreadStatus.UNDEFINED self.reason = 0 @property @@ -55,12 +56,14 @@ class DownloadThread(QThread): zipped.extractall() except: self.__status = ThreadStatus.UNKNOWN_ERR + else: + self.__status = ThreadStatus.OK class UpadteSpaceWeatherThread(QThread): def __init__(self, space_weather_data): super().__init__() - self.__status = ThreadStatus.OK + self.__status = ThreadStatus.UNDEFINED self.__space_weather_data = space_weather_data @property @@ -89,3 +92,5 @@ class UpadteSpaceWeatherThread(QThread): self.__space_weather_data.images[8].loadFromData(urllib3.PoolManager().request('GET', Constants.FORECAST_IMG_8).data) except: self.__status = ThreadStatus.UNKNOWN_ERR + else: + self.__status = ThreadStatus.OK From 91bfcde7cc900400b88eb8918244c043f33a9d36 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 14 Apr 2019 15:57:18 +0200 Subject: [PATCH 09/11] Fix bug in reset of mode filters. Make forecast labels theme-dependent. --- artemis.py | 188 ++-- artemis.ui | 1091 +++++++++++---------- constants.py | 27 +- fixed_aspect_ratio_label.py | 19 +- fixed_aspect_ratio_widget.py | 3 +- switchable_label.py | 49 +- themes.py | 88 +- themes/2-dark/colors.txt | 5 +- themes/3-material_design_dark/colors.txt | 2 + themes/4-material_design_light/colors.txt | 2 + 10 files changed, 771 insertions(+), 703 deletions(-) diff --git a/artemis.py b/artemis.py index 1eb0689..de1d2f7 100644 --- a/artemis.py +++ b/artemis.py @@ -1,5 +1,4 @@ from collections import namedtuple -from itertools import chain from functools import partial import webbrowser import os @@ -31,8 +30,7 @@ from constants import (Constants, Database, ChecksumWhat, Messages, - Signal, - Colors,) + Signal,) from themes import Theme from utilities import (checksum_ok, uncheck_and_emit, @@ -64,6 +62,66 @@ class Artemis(QMainWindow, Ui_MainWindow): self.current_signal_name = '' self.signal_names = [] self.total_signals = 0 + self.switchable_r_labels = SwitchableLabelsIterable(self.r0_now_lbl, + self.r1_now_lbl, + self.r2_now_lbl, + self.r3_now_lbl, + self.r4_now_lbl, + self.r5_now_lbl,) + + self.switchable_s_labels = SwitchableLabelsIterable(self.s0_now_lbl, + self.s1_now_lbl, + self.s2_now_lbl, + self.s3_now_lbl, + self.s4_now_lbl, + self.s5_now_lbl,) + + self.switchable_g_now_labels = SwitchableLabelsIterable(self.g0_now_lbl, + self.g1_now_lbl, + self.g2_now_lbl, + self.g3_now_lbl, + self.g4_now_lbl, + self.g5_now_lbl) + + self.switchable_g_today_labels = SwitchableLabelsIterable(self.g0_today_lbl, + self.g1_today_lbl, + self.g2_today_lbl, + self.g3_today_lbl, + self.g4_today_lbl, + self.g5_today_lbl) + + self.k_storm_labels = SwitchableLabelsIterable(self.k_ex_sev_storm_lbl, + self.k_very_sev_storm_lbl, + self.k_sev_storm_lbl, + self.k_maj_storm_lbl, + self.k_min_storm_lbl, + self.k_active_lbl, + self.k_unsettled_lbl, + self.k_quiet_lbl, + self.k_very_quiet_lbl, + self.k_inactive_lbl) + + self.a_storm_labels = SwitchableLabelsIterable(self.a_sev_storm_lbl, + self.a_maj_storm_lbl, + self.a_min_storm_lbl, + self.a_active_lbl, + self.a_unsettled_lbl, + self.a_quiet_lbl) + + self.forecast_labels = (self.forecast_lbl_0, + self.forecast_lbl_1, + self.forecast_lbl_2, + self.forecast_lbl_3, + self.forecast_lbl_4, + self.forecast_lbl_5, + self.forecast_lbl_6, + self.forecast_lbl_7, + self.forecast_lbl_8) + + for lab in self.forecast_labels: + lab.set_default_stylesheet() + + self.forecast_label_container.labels = self.forecast_labels self.theme = Theme(self) # Manage frequency filters. @@ -377,92 +435,6 @@ class Artemis(QMainWindow, Ui_MainWindow): self.update_now_bar.set_idle() self.space_weather_data = SpaceWeatherData() self.space_weather_data.update_complete.connect(self.update_space_weather) - self.switchable_r_labels = SwitchableLabelsIterable(self.r0_now_lbl, - self.r1_now_lbl, - self.r2_now_lbl, - self.r3_now_lbl, - self.r4_now_lbl, - self.r5_now_lbl,) - self.switchable_s_labels = SwitchableLabelsIterable(self.s0_now_lbl, - self.s1_now_lbl, - self.s2_now_lbl, - self.s3_now_lbl, - self.s4_now_lbl, - self.s5_now_lbl,) - self.switchable_g_now_labels = SwitchableLabelsIterable(self.g0_now_lbl, - self.g1_now_lbl, - self.g2_now_lbl, - self.g3_now_lbl, - self.g4_now_lbl, - self.g5_now_lbl) - self.switchable_g_today_labels = SwitchableLabelsIterable(self.g0_today_lbl, - self.g1_today_lbl, - self.g2_today_lbl, - self.g3_today_lbl, - self.g4_today_lbl, - self.g5_today_lbl) - colors_array = [[Colors.WHITE_LIGHT, Colors.WHITE_DARK], - [Colors.BLUE_LIGHT, Colors.BLUE_DARK], - [Colors.GREEN_LIGHT, Colors.GREEN_DARK], - [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], - [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], - [Colors.RED_LIGHT, Colors.RED_DARK]] - - for lab, [light_color, dark_color] in zip(chain(self.switchable_r_labels, - self.switchable_s_labels, - self.switchable_g_now_labels, - self.switchable_g_today_labels), - colors_array * 4): - lab.set_colors(None, None) - - k_storms_colors = [[Colors.RED_LIGHT, Colors.RED_DARK], - [Colors.RED2_LIGHT, Colors.RED2_DARK], - [Colors.RED3_LIGHT, Colors.RED3_DARK], - [Colors.ORANGE2_LIGHT, Colors.ORANGE2_DARK], - [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], - [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], - [Colors.GREEN2_LIGHT, Colors.GREEN2_DARK], - [Colors.GREEN3_LIGHT, Colors.GREEN3_DARK], - [Colors.GREEN_LIGHT, Colors.GREEN_DARK], - [Colors.BLUE_LIGHT, Colors.BLUE_DARK]] - a_storm_colors = [[Colors.RED_LIGHT, Colors.RED_DARK], - [Colors.ORANGE2_LIGHT, Colors.ORANGE2_DARK], - [Colors.ORANGE_LIGHT, Colors.ORANGE_DARK], - [Colors.YELLOW_LIGHT, Colors.YELLOW_DARK], - [Colors.GREEN_LIGHT, Colors.GREEN_DARK], - [Colors.BLUE_LIGHT, Colors.BLUE_DARK]] - - self.k_storm_labels = SwitchableLabelsIterable(self.k_ex_sev_storm_lbl, - self.k_very_sev_storm_lbl, - self.k_sev_storm_lbl, - self.k_maj_storm_lbl, - self.k_min_storm_lbl, - self.k_active_lbl, - self.k_unsettled_lbl, - self.k_quiet_lbl, - self.k_very_quiet_lbl, - self.k_inactive_lbl) - self.a_storm_labels = SwitchableLabelsIterable(self.a_sev_storm_lbl, - self.a_maj_storm_lbl, - self.a_min_storm_lbl, - self.a_active_lbl, - self.a_unsettled_lbl, - self.a_quiet_lbl) - - for lab, [light_color, dark_color] in zip(chain(self.k_storm_labels, self.a_storm_labels), - chain(k_storms_colors, a_storm_colors)): - lab.set_colors(None, None) - - self.forecast_labels = (self.forecast_lbl_0, - self.forecast_lbl_1, - self.forecast_lbl_2, - self.forecast_lbl_3, - self.forecast_lbl_4, - self.forecast_lbl_5, - self.forecast_lbl_6, - self.forecast_lbl_7, - self.forecast_lbl_8) - self.forecast_label_container.labels = self.forecast_labels # Final operations. self.theme.initialize() @@ -580,37 +552,35 @@ class Artemis(QMainWindow, Ui_MainWindow): k_index_24_hmax = int(self.space_weather_data.geo_storm[6][index]) if k_index_24_hmax == 0: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) - self.expected_noise_lbl.setText("S0 - S1 (<-120 dBm)") + self.expected_noise_lbl.setText(" S0 - S1 (<-120 dBm) ") elif k_index_24_hmax == 1: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) - self.expected_noise_lbl.setText("S0 - S1 (<-120 dBm)") + self.expected_noise_lbl.setText(" S0 - S1 (<-120 dBm) ") elif k_index_24_hmax == 2: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) - self.expected_noise_lbl.setText("S1 - S2 (-115 dBm)") + self.expected_noise_lbl.setText(" S1 - S2 (-115 dBm) ") elif k_index_24_hmax == 3: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) - self.expected_noise_lbl.setText("S2 - S3 (-110 dBm)") + self.expected_noise_lbl.setText(" S2 - S3 (-110 dBm) ") elif k_index_24_hmax == 4: self.switchable_g_today_labels.switch_on(self.g0_today_lbl) - self.expected_noise_lbl.setText("S3 - S4 (-100 dBm)") + self.expected_noise_lbl.setText(" S3 - S4 (-100 dBm) ") elif k_index_24_hmax == 5: self.switchable_g_today_labels.switch_on(self.g1_today_lbl) - self.expected_noise_lbl.setText("S4 - S6 (-90 dBm)") + self.expected_noise_lbl.setText(" S4 - S6 (-90 dBm) ") elif k_index_24_hmax == 6: self.switchable_g_today_labels.switch_on(self.g2_today_lbl) - self.expected_noise_lbl.setText("S6 - S9 (-80 dBm)") + self.expected_noise_lbl.setText(" S6 - S9 (-80 dBm) ") elif k_index_24_hmax == 7: self.switchable_g_today_labels.switch_on(self.g3_today_lbl) - self.expected_noise_lbl.setText("S9 - S20 (>-60 dBm)") + self.expected_noise_lbl.setText(" S9 - S20 (>-60 dBm) ") elif k_index_24_hmax == 8: self.switchable_g_today_labels.switch_on(self.g4_today_lbl) - self.expected_noise_lbl.setText("S20 - S30 (>-60 dBm)") + self.expected_noise_lbl.setText(" S20 - S30 (>-60 dBm) ") elif k_index_24_hmax == 9: self.switchable_g_today_labels.switch_on(self.g5_today_lbl) - self.expected_noise_lbl.setText("S30+ (>>-60 dBm)") - self.expected_noise_lbl.setStyleSheet(f""" - color:#ffffff; - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #4776e6 ,stop: 1 #8e54e9);""") + self.expected_noise_lbl.setText(" S30+ (>>-60 dBm) ") + self.expected_noise_lbl.switch_on() val = int(self.space_weather_data.ak_index[7][2].replace('.', '')) self.sfi_lbl.setText(f"{val}") @@ -618,10 +588,9 @@ class Artemis(QMainWindow, Ui_MainWindow): self.sn_lbl.setText(f"{val:d}") for label, pixmap in zip(self.forecast_labels, self.space_weather_data.images): - label.setText('') label.pixmap = pixmap - label.setPixmap(pixmap.scaled(label.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) - label.setStyleSheet("background-color: transparent;") + label.make_transparent() + label.apply_pixmap() else: pop_up(self, title = Messages.BAD_DOWNLOAD, text = Messages.BAD_DOWNLOAD_MSG).show() @@ -998,8 +967,15 @@ class Artemis(QMainWindow, Ui_MainWindow): @pyqtSlot() def reset_mode_filters(self): uncheck_and_emit(self.apply_remove_mode_filter_btn) + parents = Constants.MODES.keys() + selected_children = [] for item in self.mode_tree_widget.selectedItems(): - item.setSelected(False) + if item.text(0) in parents: + item.setSelected(False) + else: + selected_children.append(item) + for children in selected_children: + children.setSelected(False) if self.include_unknown_modes_btn.isChecked(): self.include_unknown_modes_btn.setChecked(False) diff --git a/artemis.ui b/artemis.ui index 690fa4c..8b3f37a 100644 --- a/artemis.ui +++ b/artemis.ui @@ -4678,6 +4678,22 @@ www.qrg.globaltuners.com Now + + + + QFrame::Sunken + + + 1 + + + 0 + + + Qt::Vertical + + + @@ -5115,7 +5131,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto
- - + N/A @@ -5160,7 +5176,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto
- - + N/A @@ -5194,8 +5210,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto
- color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + EXTREMELY SEVERE @@ -5222,8 +5237,7 @@ STORM - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + VERY SEVERE STORM @@ -5249,8 +5263,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + SEVERE STORM @@ -5276,8 +5289,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + MAJOR STORM @@ -5303,8 +5315,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + MINOR STORM @@ -5330,8 +5341,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + ACTIVE @@ -5357,8 +5367,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + UNSETTLED @@ -5384,8 +5393,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + QUIET @@ -5411,8 +5419,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + VERY QUIET @@ -5438,8 +5445,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + INACTIVE @@ -5480,8 +5486,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + SEVERE STORM @@ -5507,8 +5512,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + MAJOR STORM @@ -5534,8 +5538,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + MINOR STORM @@ -5561,8 +5564,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + ACTIVE @@ -5588,8 +5590,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + UNSETTLED @@ -5615,8 +5616,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); + QUIET @@ -5668,7 +5668,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + N/A @@ -5713,7 +5713,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + N/A @@ -6083,7 +6083,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - + N/A Qt::AlignCenter @@ -6095,22 +6095,6 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - QFrame::Sunken - - - 1 - - - 0 - - - Qt::Vertical - - - @@ -6136,478 +6120,530 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - - - - 0 - 0 - - - - - 0 - - - - - - 0 - 0 - + + + + + + 0 + 0 + + + + + 9 - - - 11 - true - + + 0 - - E.M.E - - - - - - - - 0 - 0 - - - - - 11 - true - - - - Meteor Scatter - - - - - - - - 0 - 0 - - - - - 11 - true - - - - M.U.F. - - - - - - - - 0 - 0 - - - - - 11 - true - - - - Hystorical Index - - - - - - - - 0 - 0 - - - - - 11 - true - - - - 50 MHz in EU - - - - - - - - 0 - 0 - - - - - 11 - true - - - - 70 MHz in EU - - - - - - - - 0 - 0 - - - - - 11 - true - - - - 144 MHz in EU - - - - - - - - 0 - 0 - - - - - 11 - true - - - - 144 MHz in NA - - - - - - - - 0 - 0 - - - - - 11 - true - - - - VHF Aurora - - - - - - - - 0 - 0 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - Qt::NoFocus - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 0 - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - 0 - 0 - - - - - 12 - 75 - true - - - - color:#ffffff; -background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - - - OFF - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - 12 - - - - - - - - + + + + + 0 + 0 + + + + + 13 + false + + + + E.M.E→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + 50 MHz in EU→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + VHF Aurora→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + Hystorical Index→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + 144 MHz in EU→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + M.U.F.→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + Meteor Scatter→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + 144 MHz in NA→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + 13 + false + + + + 70 MHz in EU→ + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 15 + + + + + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + Qt::NoFocus + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 0 + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + 0 + 0 + + + + + 12 + 75 + true + + + + + + + NO DATA + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + 12 + + + + + + + + + + @@ -6681,7 +6717,7 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - + 0 @@ -6690,17 +6726,20 @@ background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,sto - 13 + 10 75 true - + N/A Qt::AlignCenter + + 0 + diff --git a/constants.py b/constants.py index d52c367..559dc47 100644 --- a/constants.py +++ b/constants.py @@ -66,30 +66,6 @@ class Database(object): Signal.SUP_BAND, Signal.CATEGORY_CODE,) -class Colors(object): - RED_DARK = "#4d0000" - RED_LIGHT = "#ff0000" - RED2_DARK = "#4c0c00" - RED2_LIGHT = "#ff2700" - RED3_DARK = "#4b1100" - RED3_LIGHT = "#ff3a00" - ORANGE_DARK = "#4d2e00" - ORANGE_LIGHT = "#ffad33" - ORANGE2_DARK = "#4c2000" - ORANGE2_LIGHT = "#ff6c00" - GREEN_DARK = "#003300" - GREEN_LIGHT = "#33ff33" - GREEN2_DARK = "#424d00" - GREEN2_LIGHT = "#dcff00" - GREEN3_DARK = "#344d00" - GREEN3_LIGHT = "#aeff00" - BLUE_DARK = "#000033" - BLUE_LIGHT = "#3333ff" - WHITE_DARK = "#333333" - WHITE_LIGHT = "#d9b3ff" - YELLOW_DARK = "#333300" - YELLOW_LIGHT = "#ffff33" - class Constants(object): CLICK_TO_UPDATE_STR = "Click to update" UPDATING_STR = "Updating..." @@ -117,6 +93,9 @@ class Constants(object): AUDIO_FOLDER = "Audio" ACTIVE = "active" INACTIVE = "inactive" + LABEL_ON_COLOR = "on" + LABEL_OFF_COLOR = "off" + TEXT_COLOR = "text" NOT_AVAILABLE = "spectrumnotavailable.png" NOT_SELECTED = "nosignalselected.png" __Band = namedtuple("Band", ["lower", "upper"]) diff --git a/fixed_aspect_ratio_label.py b/fixed_aspect_ratio_label.py index e73103f..2461c29 100644 --- a/fixed_aspect_ratio_label.py +++ b/fixed_aspect_ratio_label.py @@ -1,14 +1,27 @@ from PyQt5.QtWidgets import QLabel -from PyQt5.QtCore import QSize, Qt +from PyQt5.QtCore import Qt class FixedAspectRatioLabel(QLabel): def __init__(self, parent = None): super().__init__(parent) self.pixmap = None - def rescale(self, w, h): - self.resize(QSize(w, h)) + def set_default_stylesheet(self): + self.setStyleSheet(""" + color: #ffffff; + background-color: #666666; + """) + + def make_transparent(self): + self.setText('') + self.setStyleSheet("background-color: transparent;") + + def apply_pixmap(self): if self.pixmap: self.setPixmap( self.pixmap.scaled( self.size(), Qt.IgnoreAspectRatio, Qt.SmoothTransformation)) + + def rescale(self, size): + self.resize(size) + self.apply_pixmap() diff --git a/fixed_aspect_ratio_widget.py b/fixed_aspect_ratio_widget.py index a867899..71e78f9 100644 --- a/fixed_aspect_ratio_widget.py +++ b/fixed_aspect_ratio_widget.py @@ -1,4 +1,5 @@ from PyQt5.QtWidgets import QWidget +from PyQt5.QtCore import QSize class FixedAspectRatioWidget(QWidget): space = 10 @@ -16,4 +17,4 @@ class FixedAspectRatioWidget(QWidget): h_lbl = h / 9 - self.space for label in self.labels: - label.rescale(w_lbl, h_lbl) + label.rescale(QSize(w_lbl, h_lbl)) diff --git a/switchable_label.py b/switchable_label.py index 5d32e89..c4f6f12 100644 --- a/switchable_label.py +++ b/switchable_label.py @@ -3,32 +3,26 @@ from PyQt5.QtWidgets import QLabel class SwitchableLabel(QLabel): def __init__(self, parent = None): super().__init__(parent) - self.switch_on_color = None - self.switch_off_color = None - - def set_colors(self, on, off): - self.switch_on_color = on - self.switch_off_color = off + self.switch_on_colors = () + self.switch_off_colors = () + self.text_color = '' + self.is_on = False def switch_on(self): - if self.switch_on_color and self.switch_off_color: - self.setStyleSheet(f"""background-color: {self.switch_on_color}; - color:#000000;""") - else: - self.setStyleSheet(""" - color:#ffffff; - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #4776e6 ,stop: 1 #8e54e9); - """) + self.is_on = True + self.__apply_colors(*self.switch_on_colors) def switch_off(self): - if self.switch_on_color and self.switch_off_color: - self.setStyleSheet(f"""background-color: {self.switch_off_color}; - color:#000000;""") - else: - self.setStyleSheet(""" - color:#ffffff; - background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #283048 ,stop: 1 #859398); - """) + self.is_on = False + self.__apply_colors(*self.switch_off_colors) + + def __apply_colors(self, start, end): + self.setStyleSheet( + f""" + color:{self.text_color}; + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 {start} ,stop: 1 {end}); + """ + ) class SwitchableLabelsIterable(object): @@ -49,3 +43,14 @@ class SwitchableLabelsIterable(object): def switch_off_all(self): for lab in self.labels: lab.switch_off() + + def set(self, attr, value): + for lab in self.labels: + setattr(lab, attr, value) + + def refresh(self): + for lab in self.labels: + if lab.is_on: + lab.switch_on() + else: + lab.switch_off() diff --git a/themes.py b/themes.py index 8d9f419..c3db60b 100644 --- a/themes.py +++ b/themes.py @@ -1,10 +1,12 @@ from functools import partial +from itertools import chain import os import re from PyQt5.QtWidgets import QAction, QActionGroup from PyQt5.QtCore import pyqtSlot from PyQt5.QtGui import QPixmap from constants import Constants +from switchable_label import SwitchableLabelsIterable from utilities import pop_up class ThemeConstants(object): @@ -15,8 +17,11 @@ class ThemeConstants(object): CURRENT = ".current_theme" COLORS = "colors.txt" COLOR_SEPARATOR = "=" - DEFAULT_ACTIVE_COLOR = "#39eaff" + DEFAULT_ACTIVE_COLOR = "#000000" DEFAULT_INACTIVE_COLOR = "#9f9f9f" + DEFAULT_OFF_COLORS = "#000000", "#434343" + DEFAULT_ON_COLORS = "#4b79a1", "#283e51" + DEFAULT_TEXT_COLOR = "#ffffff" THEME_NOT_FOUND = "Theme not found" MISSING_THEME = "Missing theme in '" + FOLDER + "' folder." @@ -25,10 +30,25 @@ class Theme(object): self.__parent = parent self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR - self.__theme_path = ThemeConstants.DEFAULT + + self.__theme_path = "" + self.__current_theme = "" + self.__parent.default_images_folder = os.path.join(ThemeConstants.FOLDER, ThemeConstants.DEFAULT, ThemeConstants.ICONS_FOLDER) + + self.__forecast_labels = SwitchableLabelsIterable(*list(chain(self.__parent.switchable_r_labels, + self.__parent.switchable_s_labels, + self.__parent.switchable_g_now_labels, + self.__parent.switchable_g_today_labels, + self.__parent.k_storm_labels, + self.__parent.a_storm_labels, + [self.__parent.expected_noise_lbl]))) + + self.__forecast_labels.set("switch_on_colors", ThemeConstants.DEFAULT_ON_COLORS) + self.__forecast_labels.set("switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS) + self.__theme_names = {} self.__detect_themes() @@ -43,6 +63,7 @@ class Theme(object): self.__parent.upper_band_filter_unit, self.__parent.upper_band_confidence, self.__parent.band_range_lbl) + self.__parent.set_band_filter_label(self.__parent.activate_low_freq_filter_btn, self.__parent.lower_freq_spinbox, self.__parent.lower_freq_filter_unit, @@ -56,10 +77,12 @@ class Theme(object): @pyqtSlot() def __apply(self, theme_path): self.__theme_path = theme_path - self.__change() - self.__parent.display_specs(self.__parent.result_list.currentItem(), None) - self.__refresh_range_labels() - self.__parent.audio_widget.refresh_btns_colors(self.__parent.active_color, self.__parent.inactive_color) + if self.__theme_path != self.__current_theme: + self.__change() + self.__parent.display_specs(self.__parent.result_list.currentItem(), None) + self.__refresh_range_labels() + self.__parent.audio_widget.refresh_btns_colors(self.__parent.active_color, self.__parent.inactive_color) + self.__forecast_labels.refresh() def __pretty_name(self, bad_name): return ' '.join( @@ -135,28 +158,53 @@ class Theme(object): path_to_colors = os.path.join(self.__theme_path, ThemeConstants.COLORS) active_color_ok = False inactive_color_ok = False - valid_format = False - valid_file = False + switch_on_color_ok = False + switch_off_color_ok = False + text_color_ok = False + if os.path.exists(path_to_colors): - valid_file = True + is_valid_html_color = lambda colors : all([bool(re.match("#([a-zA-Z0-9]){6}", color)) for color in colors]) with open(path_to_colors, "r") as colors_file: for line in colors_file: if ThemeConstants.COLOR_SEPARATOR in line: - valid_format = True quality, color = line.split(ThemeConstants.COLOR_SEPARATOR) color = color.rstrip() - is_valid_html_color = lambda color : bool(re.match("#([a-zA-Z0-9]){6}", color)) - if quality.lower() == Constants.ACTIVE and is_valid_html_color(color): - self.__parent.active_color = color - active_color_ok = True - if quality.lower() == Constants.INACTIVE and is_valid_html_color(color): - self.__parent.inactive_color = color - inactive_color_ok = True + if ',' in color: + color = [c.rstrip().lstrip() for c in color.split(',')] + else: + color = [color] + if len(color) > 2: + break + if is_valid_html_color(color): + if quality.lower() == Constants.ACTIVE: + self.__parent.active_color = color[0] + active_color_ok = True + if quality.lower() == Constants.INACTIVE: + self.__parent.inactive_color = color[0] + inactive_color_ok = True + if quality.lower() == Constants.LABEL_ON_COLOR: + switch_on_color_ok = True + self.__forecast_labels.set("switch_on_colors", color) + if quality.lower() == Constants.LABEL_OFF_COLOR: + switch_off_color_ok = True + self.__forecast_labels.set("switch_off_colors", color) + if quality.lower() == Constants.TEXT_COLOR: + text_color_ok = True + self.__forecast_labels.set("text_color", color[0]) - if not all([valid_file, valid_format, active_color_ok, inactive_color_ok]): + if not (active_color_ok and inactive_color_ok): self.__parent.active_color = ThemeConstants.DEFAULT_ACTIVE_COLOR self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR + if not (switch_on_color_ok and switch_off_color_ok): + for label in self.__forecast_labels: + label.switch_on_colors = ThemeConstants.DEFAULT_ON_COLORS + label.switch_off_colors = ThemeConstants.DEFAULT_OFF_COLORS + + if not text_color_ok: + self.__forecast_labels.set("text_color", ThemeConstants.DEFAULT_TEXT_COLOR) + self.__current_theme = self.__theme_path + try: with open(os.path.join(ThemeConstants.FOLDER, ThemeConstants.CURRENT), "w") as current_theme: @@ -171,7 +219,7 @@ class Theme(object): theme_path = current_theme_path.read() theme_name = self.__pretty_name(os.path.basename(theme_path)) self.__theme_names[theme_name].setChecked(True) - if theme_path != ThemeConstants.DEFAULT: - self.__apply(theme_path) + self.__apply(theme_path) else: self.__theme_names[self.__pretty_name(ThemeConstants.DEFAULT)].setChecked(True) + self.__apply(os.path.join(ThemeConstants.FOLDER, ThemeConstants.DEFAULT)) diff --git a/themes/2-dark/colors.txt b/themes/2-dark/colors.txt index 6050d7d..784707f 100644 --- a/themes/2-dark/colors.txt +++ b/themes/2-dark/colors.txt @@ -1,2 +1,5 @@ -active=#4da6ff +active=#4545e5 inactive=#546E7A +off=#283048,#859398 +on=#4776e6, #8e54e9 +text=#ffffff diff --git a/themes/3-material_design_dark/colors.txt b/themes/3-material_design_dark/colors.txt index 7c4ba0a..40ab6c1 100644 --- a/themes/3-material_design_dark/colors.txt +++ b/themes/3-material_design_dark/colors.txt @@ -1,2 +1,4 @@ active=#88cc00 inactive=#546E7A +off=#304352,#d7d2cc +on=#3ca55c,#b5ac49 diff --git a/themes/4-material_design_light/colors.txt b/themes/4-material_design_light/colors.txt index c1bccbe..29e38f6 100644 --- a/themes/4-material_design_light/colors.txt +++ b/themes/4-material_design_light/colors.txt @@ -1,2 +1,4 @@ active=#6ECE12 inactive=#b3b3cc +off=#948e99,#2e1437 +on=#b993d6,#8ca6db From f8e55a9606a3d71fc4d91291cced9c130fa7b95f Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Sun, 14 Apr 2019 16:04:13 +0200 Subject: [PATCH 10/11] Also check that there actually 2 colors in colors.txt for the forecast labels --- themes.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/themes.py b/themes.py index c3db60b..2e7bfa8 100644 --- a/themes.py +++ b/themes.py @@ -182,12 +182,13 @@ class Theme(object): if quality.lower() == Constants.INACTIVE: self.__parent.inactive_color = color[0] inactive_color_ok = True - if quality.lower() == Constants.LABEL_ON_COLOR: - switch_on_color_ok = True - self.__forecast_labels.set("switch_on_colors", color) - if quality.lower() == Constants.LABEL_OFF_COLOR: - switch_off_color_ok = True - self.__forecast_labels.set("switch_off_colors", color) + if len(color) == 2: + if quality.lower() == Constants.LABEL_ON_COLOR: + switch_on_color_ok = True + self.__forecast_labels.set("switch_on_colors", color) + if quality.lower() == Constants.LABEL_OFF_COLOR: + switch_off_color_ok = True + self.__forecast_labels.set("switch_off_colors", color) if quality.lower() == Constants.TEXT_COLOR: text_color_ok = True self.__forecast_labels.set("text_color", color[0]) @@ -197,9 +198,8 @@ class Theme(object): self.__parent.inactive_color = ThemeConstants.DEFAULT_INACTIVE_COLOR if not (switch_on_color_ok and switch_off_color_ok): - for label in self.__forecast_labels: - label.switch_on_colors = ThemeConstants.DEFAULT_ON_COLORS - label.switch_off_colors = ThemeConstants.DEFAULT_OFF_COLORS + self.__forecast_labels.set("switch_on_colors", ThemeConstants.DEFAULT_ON_COLORS) + self.__forecast_labels.set("switch_off_colors", ThemeConstants.DEFAULT_OFF_COLORS) if not text_color_ok: self.__forecast_labels.set("text_color", ThemeConstants.DEFAULT_TEXT_COLOR) From 266111829d56b6de7c2b87c11a94f39bbdc742a6 Mon Sep 17 00:00:00 2001 From: alessandro90 Date: Thu, 25 Apr 2019 19:58:28 +0200 Subject: [PATCH 11/11] Change color of forecast labels with downloadable images --- fixed_aspect_ratio_label.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fixed_aspect_ratio_label.py b/fixed_aspect_ratio_label.py index 2461c29..27c00e8 100644 --- a/fixed_aspect_ratio_label.py +++ b/fixed_aspect_ratio_label.py @@ -9,7 +9,7 @@ class FixedAspectRatioLabel(QLabel): def set_default_stylesheet(self): self.setStyleSheet(""" color: #ffffff; - background-color: #666666; + background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0,stop:0 #304352 ,stop: 1 #d7d2cc); """) def make_transparent(self):