diff --git a/.gitignore b/.gitignore index c158ac8..660e8c3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ wav_converter.py *.txt icons_imgs TestData +themes/.current_theme diff --git a/audio_player.py b/audio_player.py index 27754e7..2d4c2f5 100644 --- a/audio_player.py +++ b/audio_player.py @@ -3,9 +3,9 @@ import sys from pydub import AudioSegment from pygame import mixer from PyQt5.QtCore import QTimer, QTimer, pyqtSlot, QObject -import qtawesome as qta from utilities import Constants +import qtawesome as qta class AudioPlayer(QObject): # Maybe useless inheriting from QObject @@ -17,7 +17,7 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject __time_step = 500 # Milliseconds. - def __init__(self, play, pause, stop, volume, audio_progress): + def __init__(self, play, pause, stop, volume, audio_progress, active_color, inactive_color): super().__init__() self.__paused = False self.__first_call = True @@ -33,18 +33,21 @@ class AudioPlayer(QObject): # Maybe useless inheriting from QObject self.__pause.clicked.connect(self.__pause_audio) self.__stop.clicked.connect(self.__stop_audio) self.__volume.valueChanged.connect(self.__set_volume) - self.__play.setIcon(qta.icon('fa5.play-circle', - color = "#4facf1", - color_disabled = '#7a7a7a')) self.__play.setIconSize(self.__play.size()) - self.__pause.setIcon(qta.icon('fa5.pause-circle', - color = "#4facf1", - color_disabled = '#7a7a7a')) self.__pause.setIconSize(self.__pause.size()) - self.__stop.setIcon(qta.icon('fa5.stop-circle', - color = "#4facf1", - color_disabled = '#7a7a7a')) self.__stop.setIconSize(self.__stop.size()) + self.refresh_btns_colors(active_color, inactive_color) + + def refresh_btns_colors(self, active_color, inactive_color): + self.__play.setIcon(qta.icon('fa5.play-circle', + color = active_color, + color_disabled = inactive_color)) + self.__pause.setIcon(qta.icon('fa5.pause-circle', + color = active_color, + color_disabled = inactive_color)) + self.__stop.setIcon(qta.icon('fa5.stop-circle', + color = active_color, + color_disabled = inactive_color)) @pyqtSlot() def __set_volume(self): diff --git a/download_db_window.ui b/download_db_window.ui index 2f17663..6f3c1f8 100644 --- a/download_db_window.ui +++ b/download_db_window.ui @@ -14,33 +14,7 @@ Download database - QWidget { - background-color: #464646 -} - -QLabel { - color: #ffffff; -} - -QProgressBar { - border: 2px #7a7a7a; - border-radius: 5px; - background-color: #7a7a7a; -} - -QProgressBar::chunk { - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #1d5eff, stop:0.5 #4177ff, stop:1 #1d5eff); - border-radius: 5px; -} - - -QMessageBox { - color: #ffffff; -} - -QPushButton { - color: #ffffff; -} + @@ -73,6 +47,9 @@ Please wait -1 + + false + @@ -83,13 +60,7 @@ Please wait - QPushButton { - background-color: rgb(52,52,52); - color: #FFFFFF; - border: 1px solid gray; - border-radius: 8px; -} - + Cancel diff --git a/main.py b/main.py index 1c584ff..7a14016 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,6 @@ from collections import namedtuple from functools import partial +from glob import glob import webbrowser import os import sys @@ -7,12 +8,13 @@ import sys from pandas import read_csv from PyQt5.QtWidgets import (QMainWindow, QApplication, + QAction, QMessageBox, qApp, QDesktopWidget, QListWidgetItem, QTreeView, - QTreeWidgetItem) + QTreeWidgetItem,) from PyQt5.QtGui import QPixmap from PyQt5 import uic from PyQt5.QtCore import (QFileInfo, @@ -24,7 +26,12 @@ from audio_player import AudioPlayer from double_text_button import DoubleTextButton from download_window import DownloadWindow -from utilities import Constants, reset_apply_remove_btn + + +from utilities import (Constants, + reset_apply_remove_btn, + throwable_message, + is_valid_html_color,) qt_creator_file = "main_window.ui" Ui_MainWindow, _ = uic.loadUiType(qt_creator_file) @@ -42,6 +49,8 @@ class MyApp(QMainWindow, Ui_MainWindow): self.current_signal_name = '' self.signal_names = [] self.total_signals = 0 + self.active_color = Constants.ACTIVE_COLOR + self.inactive_color = Constants.INACTIVE_COLOR # Manage frequency filters. self.frequency_filters_btns = ( @@ -301,6 +310,13 @@ class MyApp(QMainWindow, Ui_MainWindow): self.reset_location_filters_btn.clicked.connect(self.reset_location_filters) self.locations_list.itemClicked.connect(self.remove_if_unselected_location) + # Find available themes. + self.default_images_folder = os.path.join(Constants.THEMES_FOLDER, + Constants.DEFAULT_THEME, + Constants.ICONS_FOLDER) + # self.find_themes() + # self.set_theme() + # ########################################################################################## self.load_db() @@ -309,16 +325,15 @@ class MyApp(QMainWindow, Ui_MainWindow): self.search_bar.textChanged.connect(self.display_signals) self.result_list.addItems(self.signal_names) self.result_list.currentItemChanged.connect(self.display_specs) - self.result_list.itemDoubleClicked.connect(lambda: self.main_tab.setCurrentWidget( - self.signal_properties_tab - ) - ) + 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, self.volume, - self.audio_progress) + self.audio_progress, + self.active_color, + self.inactive_color) BandLabel = namedtuple("BandLabel", ["left", "center", "right"]) self.band_labels = [ @@ -334,8 +349,124 @@ class MyApp(QMainWindow, Ui_MainWindow): BandLabel(self.shf_left, self.shf, self.shf_right), BandLabel(self.ehf_left, self.ehf, self.ehf_right), ] + + self.find_themes() + self.set_theme() + self.show() + def find_themes(self): + themes = [] + for theme_folder in os.listdir(Constants.THEMES_FOLDER): + relative_folder = os.path.join(Constants.THEMES_FOLDER, theme_folder) + if os.path.isdir(os.path.abspath(relative_folder)): + relative_folder = os.path.join(Constants.THEMES_FOLDER, theme_folder) + themes.append(relative_folder) + for theme in themes: + theme_name = '&' + ' '.join( + map(lambda s: s.capitalize(), + os.path.basename(theme).split('-')[1].split('_') + ) + ) + new_theme = QAction(theme_name, self) + self.menu_themes.addAction(new_theme) + + @pyqtSlot() + def show_new_theme(theme): + self.change_theme(theme) + self.display_specs(self.result_list.currentItem(), None) + new_theme.triggered.connect(partial(show_new_theme, theme)) + + @pyqtSlot() + def change_theme(self, theme_path): + try: + with open(os.path.join( + theme_path, + os.path.basename(theme_path).split('-')[1] + Constants.THEME_EXTENSION) + ) as stylesheet: + style = stylesheet.read() + self.setStyleSheet(style) + self.download_window.setStyleSheet(style) + except FileNotFoundError: + throwable_message(self, title = "Theme not found", + text = f"Missing theme in {Constants.THEMES_FOLDER} folder.").show() + else: + icons_path = os.path.join(theme_path, Constants.ICONS_FOLDER) + default_icons_path = os.path.join(Constants.THEMES_FOLDER, Constants.DEFAULT_THEME, Constants.ICONS_FOLDER) + + if os.path.exists(os.path.join(icons_path, Constants.NOT_SELECTED)) and \ + os.path.exists(os.path.join(icons_path, Constants.NOT_AVAILABLE)): + self.default_images_folder = icons_path + else: + self.default_images_folder = default_icons_path + + path_to_search_label = os.path.join(icons_path, Constants.SEARCH_LABEL_IMG) + default_search_label = os.path.join(default_icons_path, Constants.SEARCH_LABEL_IMG) + + if os.path.exists(path_to_search_label): + self.search_label.setPixmap(QPixmap(path_to_search_label)) + self.modulation_search_label.setPixmap(QPixmap(path_to_search_label)) + self.location_search_label.setPixmap(QPixmap(path_to_search_label)) + else: + self.search_label.setPixmap(QPixmap(default_search_label)) + self.modulation_search_label.setPixmap(QPixmap(default_search_label)) + self.location_search_label.setPixmap(QPixmap(default_search_label)) + + self.search_label.setScaledContents(True) + self.modulation_search_label.setScaledContents(True) + self.location_search_label.setScaledContents(True) + + path_to_volume_label = os.path.join(icons_path, Constants.VOLUME_LABEL_IMG) + default_volume_label = os.path.join(default_icons_path, Constants.VOLUME_LABEL_IMG) + + if os.path.exists(path_to_volume_label): + self.volume_label.setPixmap(QPixmap(path_to_volume_label)) + else: + self.volume_label.setPixmap(QPixmap(default_volume_label)) + + self.volume_label.setScaledContents(True) + + path_to_colors = os.path.join(theme_path, Constants.THEME_COLORS) + active_color_ok = False + inactive_color_ok = False + valid_format = False + valid_file = False + if os.path.exists(path_to_colors): + valid_file = True + with open(path_to_colors, "r") as colors_file: + for line in colors_file: + if '=' in line: + valid_format = True + quality, color = line.split("=") + color = color.rstrip() + if quality == "active" and is_valid_html_color(color): + self.active_color = color + active_color_ok = True + if quality == "inactive" and is_valid_html_color(color): + self.inactive_color = color + inactive_color_ok = True + + if not all([valid_file, valid_format, active_color_ok, inactive_color_ok]): + self.active_color = Constants.ACTIVE_COLOR + self.inactive_color = Constants.INACTIVE_COLOR + + self.audio_widget.refresh_btns_colors(self.active_color, self.inactive_color) + + try: + with open(os.path.join(Constants.THEMES_FOLDER, + Constants.CURRENT_THEME), "w") as current_theme: + current_theme.write(theme_path) + except: + pass + + def set_theme(self): + current_theme_file = os.path.join(Constants.THEMES_FOLDER, Constants.CURRENT_THEME) + if os.path.exists(current_theme_file): + with open(current_theme_file) as current_theme: + theme = current_theme.read() + if theme != Constants.DEFAULT_THEME: + self.change_theme(theme) + @pyqtSlot(QListWidgetItem) def remove_if_unselected_modulation(self, item): if not item.isSelected(): @@ -440,42 +571,25 @@ class MyApp(QMainWindow, Ui_MainWindow): self.display_signals() def load_db(self): - names = ["name", - "inf_freq", - "sup_freq", - "mode", - "inf_band", - "sup_band", - "location", - "url", - "description", - "modulation", - "category_code", - "acf",] + names = Constants.DB_NAMES try: - self.db = read_csv(os.path.join(Constants.DATA_FOLDER, 'db.csv'), + self.db = read_csv(os.path.join(Constants.DATA_FOLDER, Constants.DB_NAME), sep = '*', header = None, index_col = 0, - dtype = {'inf_freq': str, - 'sup_freq': str, - 'mode': str, - 'inf_band': str, - 'sup_band': str, - 'category_code': str,}, + dtype = {name : str for name in Constants.DB_STRINGS}, names = names,) except FileNotFoundError: self.search_bar.setDisabled(True) box = QMessageBox(self) - box.setWindowTitle("No database") - box.setText("No database available.\n" - "Go to Updates->Update database.") + box.setWindowTitle(Constants.Messages.NO_DB) + box.setText(Constants.Messages.NO_DB_AVAIL) box.show() else: self.signal_names = self.db.index self.total_signals = len(self.signal_names) self.db.fillna(Constants.UNKNOWN, inplace = True) - self.db["url_clicked"] = False + self.db[Constants.DB_WIKI_CLICKED] = False self.update_status_tip(self.total_signals) @staticmethod @@ -530,13 +644,13 @@ class MyApp(QMainWindow, Ui_MainWindow): range_lbl): activate_low = False activate_high = False - color = Constants.INACTIVE_COLOR + color = self.inactive_color title = '' to_display = '' if activate_low_btn.isChecked(): to_display += str(lower_spinbox.value()) + ' ' + lower_unit.currentText() activate_low = True - color = Constants.ACTIVE_COLOR + color = self.active_color if lower_confidence.value() != 0: to_display += ' - ' + str(lower_confidence.value()) + ' %' else: @@ -545,7 +659,7 @@ class MyApp(QMainWindow, Ui_MainWindow): if activate_up_btn.isChecked(): to_display += str(upper_spinbox.value()) + ' ' + upper_unit.currentText() activate_high = True - color = Constants.ACTIVE_COLOR + color = self.active_color if upper_confidence.value() != 0: to_display += ' + ' + str(upper_confidence.value()) + ' %' else: @@ -591,7 +705,7 @@ class MyApp(QMainWindow, Ui_MainWindow): def update_status_tip(self, available_signals): if available_signals < self.total_signals: - self.statusbar.setStyleSheet(f'color: {Constants.ACTIVE_COLOR}') + self.statusbar.setStyleSheet(f'color: {self.active_color}') else: self.statusbar.setStyleSheet('color: #ffffff') self.statusbar.showMessage(f"{available_signals} out of {self.total_signals} signals displayed.") @@ -821,21 +935,21 @@ class MyApp(QMainWindow, Ui_MainWindow): self.description_text.setText(current_signal.at["description"]) for cat, cat_lab in zip(category_code, self.category_labels): if cat == '0': - cat_lab.setStyleSheet(f"color: {Constants.INACTIVE_COLOR};") + cat_lab.setStyleSheet(f"color: {self.inactive_color};") elif cat == '1': - cat_lab.setStyleSheet(f"color: {Constants.ACTIVE_COLOR};") + cat_lab.setStyleSheet(f"color: {self.active_color};") self.set_band_range(current_signal) self.audio_widget.set_audio_player(self.current_signal_name) else: self.url_button.setEnabled(False) self.url_button.setStyleSheet(f"color: {self.url_button.colors.inactive};") self.current_signal_name = '' - self.name_lab.setText("No signal") + self.name_lab.setText("No Signal") self.name_lab.setAlignment(Qt.AlignHCenter) for lab in self.property_labels: lab.setText(Constants.UNKNOWN) for lab in self.category_labels: - lab.setStyleSheet(f"color: {Constants.INACTIVE_COLOR};") + lab.setStyleSheet(f"color: {self.inactive_color};") self.set_band_range() self.audio_widget.set_audio_player() @@ -882,23 +996,21 @@ class MyApp(QMainWindow, Ui_MainWindow): return 10**9 def display_spectrogram(self): - default_pic = os.path.join(Constants.ICONS_FOLDER, "nosignalselected.png") + default_pic = os.path.join(self.default_images_folder, Constants.NOT_SELECTED) item = self.result_list.currentItem() if item: spectrogram_name = item.text() path_spectr = os.path.join(Constants.DATA_FOLDER, Constants.SPECTRA_FOLDER, - spectrogram_name + ".png") + spectrogram_name + Constants.SPECTRA_EXT) if not QFileInfo(path_spectr).exists(): - path_spectr = os.path.join(Constants.ICONS_FOLDER, - "spectrumnotavailable.png") + path_spectr = os.path.join(self.default_images_folder, Constants.NOT_AVAILABLE) else: path_spectr = default_pic self.spectrogram.setPixmap(QPixmap(path_spectr)) - @staticmethod - def activate_band_category(band_label, activate = True): - color = Constants.ACTIVE_COLOR if activate else Constants.INACTIVE_COLOR + def activate_band_category(self, band_label, activate = True): + color = self.active_color if activate else self.inactive_color for label in band_label: label.setStyleSheet(f"color: {color};") diff --git a/main_window.ui b/main_window.ui index 59ef163..6b9a454 100644 --- a/main_window.ui +++ b/main_window.ui @@ -20,135 +20,7 @@ ARTEMIS3 - QWidget { - background-color: #464646 -} - -QLabel { - color: #ffffff; -} - -QPushButton { - color: #FFFFFF -} - -QProgressBar { - border: 2px #7a7a7a; - border-radius: 3px; - background-color: #7a7a7a; -} - -QProgressBar::chunk { - /*background-color: #1d5eff;*/ - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #1d5eff, stop:0.5 #4177ff, stop:1 #1d5eff); - border-radius: 3px; -} - -QAbstractScrollArea::corner { - background: none; - border: none; -} - -QScrollBar:vertical, QScrollBar:horizontal{ - background-color:#343434; - border-radius: 5px; - /*background: none;*/ -} - -QScrollBar:vertical { - margin-top: 0px; - margin-bottom: 0px; - /*width: 10px;*/ -} -QScrollBar:horizontal{ - margin-left: 0px; - margin-right: 0px; - /*height: 10px;*/ -} - -QScrollBar::handle:vertical, QScrollBar::handle:horizontal{ - border-radius: 5px; - border-color: none; - border-width: 1px; - background-color: #999999; -} - -QScrollBar::add-line:vertical, QScrollBar::add-line:horizontal{ - width: 0px; - height: 0px; -} - -QScrollBar::sub-line:vertical, QScrollBar::sub-line:horizontal{ - width: 0px; - height: 0px; -} - -QScrollBar::add-page:vertical{ - border-left: 1px solid gray; - background: transparent; - border-radius: 5px; -/* - border: 1px#343434; - background-color: #343434;*/ -} -QScrollBar::add-page:horizontal{ - border-top: 1px solid gray; - background: transparent; - border-radius: 5px; -/* - border: 1px#343434; - background-color: #343434;*/ -} -QScrollBar::sub-page:vertical{ - border-left: 1px solid gray; - background: transparent; - border-radius: 5px; -/* border: 1px #343434; - background-color: #343434;*/ -} -QScrollBar::sub-page:horizontal{ - border-top: 1px solid gray; - background: transparent; - border-radius: 5px; -/* border: 1px #343434; - background-color: #343434;*/ -} - -QTextEdit{ - color: #ffffff; -} - -QMessageBox { - color: #ffffff; -} - -QToolTip { - color: #000000; -} - -QTextBrowser { - background-color: #464646; - color: #ffffff; - border: 0px; -} - -QRadioButton { - color: #ffffff; -} - -QListWidget { - background-color:rgb(52,52,52); - color: rgb(255, 255, 255); - border: 1px solid gray; - border-radius: 8px; -} - -QLineEdit { - background-color: #343434; - color: rgb(255, 255, 255); - border: 1px solid gray; - border-radius: 5px; -} + @@ -229,7 +101,7 @@ QLineEdit { - icons_imgs/search_icon.png + themes/1-default/icons/search_icon.png true @@ -293,40 +165,7 @@ QLineEdit { Qt::LeftToRight - QTabWidget::pane { /* The tab widget frame */ - /* border-left: 1px solid gray;*/ -} - - -QTabWidget::tab-bar { - left: 30px; /* move to the right by 5px */ -} - - -/* Style the tab using the tab sub-control. Note that - it reads QTabBar _not_ QTabWidget */ -QTabBar::tab { - background: #7a7a7a; - border-top-left-radius: 8px; - border-top-right-radius: 8px; - min-width: 16ex; - padding: 2px; - color: #FFFFFF -} - -QTabBar::tab:selected { - background: #999999; - color: #1d5eff -} - - -QTabBar::tab:!selected { - margin-top: 3px; /* make non-selected tabs look smaller */ -} - -QPushButton:!enabled { - color:#9f9f9f; -} + QTabWidget::North @@ -335,7 +174,7 @@ QPushButton:!enabled { QTabWidget::Rounded - 1 + 0 true @@ -1221,7 +1060,7 @@ p, li { white-space: pre-wrap; } <html><head/><body><p><span style=" color:#000000;">Go to the signal's wiki.</span></p></body></html> - color: #9f9f9f; + Signal's wiki @@ -1929,49 +1768,7 @@ p, li { white-space: pre-wrap; } - QComboBox { - background-color: rgb(52,52,52); - color: #ffffff; - border: 1px solid gray; - border-radius: 5px; -} - -QComboBox:!enabled { - color: #9f9f9f; -} - -QComboBox QAbstractItemView { - border: 1px solid gray; - selection-background-color: #999999; - selection-color: #1d5eff; - color: #ffffff; -} - -QSpinBox { - background-color: rgb(52,52,52); - color: #ffffff; - border: 1px solid gray; - border-radius: 5px; -} - -QSpinBox:!enabled { - color:#9f9f9f; -} - -QPushButton { - background-color: rgb(52,52,52); - border: 1px solid gray; - border-radius: 5px; -} - -QPushButton:!enabled { - color:#9f9f9f; -} - -QPushButton:checked { - color: #39eaff; -} - + 5 @@ -2262,15 +2059,7 @@ QPushButton:checked { - QWidget#freq_filter_container { - border: 1px solid gray; - background-color: rgb(52,52,52); - border-radius: 12px; -} - -QRadioButton, QLabel { - background-color: rgb(52,52,52); -} + @@ -2319,7 +2108,7 @@ QRadioButton, QLabel { - background-color: #464646; + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -2363,7 +2152,7 @@ QRadioButton, QLabel { - background-color: #464646; + MHz @@ -2451,7 +2240,7 @@ QRadioButton, QLabel { - background-color: #464646; + false @@ -2519,7 +2308,7 @@ QRadioButton, QLabel { - background-color: #464646; + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -2566,7 +2355,7 @@ QRadioButton, QLabel { - background-color: #464646; + MHz @@ -2645,7 +2434,7 @@ QRadioButton, QLabel { - background-color: #464646; + false @@ -2796,15 +2585,7 @@ Inactive - QWidget#band_filter_container { - border: 1px solid gray; - background-color: rgb(52,52,52); - border-radius: 12px; -} - -QRadioButton, QLabel { - background-color: rgb(52,52,52); -} + @@ -2836,7 +2617,7 @@ QRadioButton, QLabel { - background-color: #464646; + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -2881,7 +2662,7 @@ QRadioButton, QLabel { - background-color: #464646; + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter @@ -2943,7 +2724,7 @@ QRadioButton, QLabel { - background-color: #464646; + false @@ -3019,7 +2800,7 @@ QRadioButton, QLabel { - background-color: #464646; + MHz @@ -3084,7 +2865,7 @@ QRadioButton, QLabel { - background-color: #464646; + false @@ -3137,7 +2918,7 @@ QRadioButton, QLabel { - background-color: #464646; + MHz @@ -3225,7 +3006,7 @@ QRadioButton, QLabel { - color: #9f9f9f; + Selected range: @@ -3311,47 +3092,383 @@ Inactive Category - - - - - 12 - 75 - true - + + + + Qt::Horizontal - - <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 + + + 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 + + + + - - - - 12 - 75 - true - + + + Qt::Horizontal - - <html><head/><body><p>Keep all the signals which belong to <span style=" font-style:italic;">all </span>the selected categories.</p></body></html> + + + 102 + 20 + - - All selected - - - false + + + + + + + 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 + + + + @@ -3388,307 +3505,6 @@ Inactive - - - - - 0 - 0 - - - - - - - - 12 - 75 - true - - - - Military - - - true - - - - - - - - 12 - 75 - true - - - - Radar - - - true - - - - - - - - 12 - 75 - true - - - - Active - - - true - - - - - - - - 12 - 75 - true - - - - Inactive - - - true - - - - - - - - 12 - 75 - true - - - - HAM - - - true - - - - - - - - 12 - 75 - true - - - - Commercial - - - true - - - - - - - - 12 - 75 - true - - - - Aviation - - - true - - - - - - - - 12 - 75 - true - - - - Marine - - - true - - - - - - - - 12 - 75 - true - - - - Analogue - - - true - - - - - - - - 12 - 75 - true - - - - Digital - - - true - - - - - - - - 12 - 75 - true - - - - Trunked - - - true - - - - - - - - 12 - 75 - true - - - - Utility - - - true - - - - - - - - 12 - 75 - true - - - - Satellite - - - true - - - - - - - - 12 - 75 - true - - - - Navigation - - - true - - - - - - - - 12 - 75 - true - - - - Interfering - - - true - - - - - - - - 12 - 75 - true - - - - Time Signal - - - true - - - - - - - - 12 - 75 - true - - - - Number Stations - - - true - - - - - - @@ -3838,7 +3654,7 @@ Inactive - + 0 @@ -3965,7 +3781,7 @@ Inactive - + 0 @@ -4073,9 +3889,7 @@ Inactive - background-color: rgb(52,52,52); -border: 1px solid gray; -border-radius: 5px; + Reset all filters @@ -4108,25 +3922,7 @@ border-radius: 5px; - QWidget { -background-color:rgb(52,52,52); -border: 1px solid gray; -border-radius: 8px; -} -QProgressBar { - border: 2px #7a7a7a; - border-radius: 3px; - background-color: #7a7a7a; -} - -QProgressBar::chunk { - /*background-color: #1d5eff;*/ - background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #1d5eff, stop:0.5 #4177ff, stop:1 #1d5eff); - border-radius: 3px; -} -QLabel, QPushButton, QSlider { - border: 0px; -} + @@ -4143,17 +3939,10 @@ QWidget { border: 0px; } QPushButton { - /*background-color: #1d5eff;*/ border: 0px solid gray; border-color: #1d5eff; border-radius: 20px; -} - -/* -QPushButton:disabled { - background-color: #7a7a7a; -} -*/ +} @@ -4259,7 +4048,7 @@ QPushButton:disabled { - + 0 @@ -4276,7 +4065,7 @@ QPushButton:disabled { - icons_imgs/volume.png + themes/1-default/icons/volume.png true @@ -4349,7 +4138,7 @@ QSlider::handle:horizontal { - icons_imgs/nosignalselected.png + themes/1-system/icons/nosignalselected.png true @@ -4371,23 +4160,7 @@ QSlider::handle:horizontal { - QMenuBar { - color: rgb(255, 255, 255); -} - -QMenuBar::item:selected { - background:#999999; - color: #1d5eff -} - -QMenu::item:selected { - background-color: #999999; - color: #1d5eff -} - -QMenu { - color: #ffffff; -} + @@ -4404,8 +4177,14 @@ QMenu { + + + Themes + + + diff --git a/themes/1-system/icons/nosignalselected.png b/themes/1-system/icons/nosignalselected.png new file mode 100644 index 0000000..a9e40f8 Binary files /dev/null and b/themes/1-system/icons/nosignalselected.png differ diff --git a/themes/1-system/icons/search_icon.png b/themes/1-system/icons/search_icon.png new file mode 100644 index 0000000..cc72a1e Binary files /dev/null and b/themes/1-system/icons/search_icon.png differ diff --git a/themes/1-system/icons/spectrumnotavailable.png b/themes/1-system/icons/spectrumnotavailable.png new file mode 100644 index 0000000..2c22abc Binary files /dev/null and b/themes/1-system/icons/spectrumnotavailable.png differ diff --git a/themes/1-system/icons/volume.png b/themes/1-system/icons/volume.png new file mode 100644 index 0000000..5cc5645 Binary files /dev/null and b/themes/1-system/icons/volume.png differ diff --git a/themes/1-system/system.th b/themes/1-system/system.th new file mode 100644 index 0000000..e69de29 diff --git a/themes/2-dark/dark.th b/themes/2-dark/dark.th new file mode 100644 index 0000000..82622f4 --- /dev/null +++ b/themes/2-dark/dark.th @@ -0,0 +1,239 @@ +QMenuBar { + color: rgb(255, 255, 255); +} + +QMenuBar::item:selected { + background:#999999; + color: #1d5eff +} + +QMenu::item:selected { + background-color: #999999; + color: #1d5eff +} + +QMenu { + color: #ffffff; +} + +QWidget { + background-color: #464646 +} + +QLabel { + color: #ffffff; +} + +QPushButton { + color: #FFFFFF; + background-color: rgb(52,52,52); + border: 1px solid gray; + border-radius: 5px; +} + +QPushButton:!enabled { + color:#9f9f9f; +} + +QPushButton:checked { + color: #39eaff; +} + +QTabWidget::pane { /* The tab widget frame */ + /* border-left: 1px solid gray;*/ + border: 0px; +} + + +QTabWidget::tab-bar { + left: 30px; /* move to the right by 5px */ +} + + +/* Style the tab using the tab sub-control. Note that + it reads QTabBar _not_ QTabWidget */ +QTabBar::tab { + background: #7a7a7a; + border-top-left-radius: 8px; + border-top-right-radius: 8px; + min-width: 16ex; + padding: 2px; + color: #FFFFFF +} + +QTabBar::tab:selected { + background: #999999; + color: #1d5eff +} + + +QTabBar::tab:!selected { + margin-top: 3px; /* make non-selected tabs look smaller */ +} + + + +QProgressBar { + border: 2px #7a7a7a; + border-radius: 3px; + background-color: #7a7a7a; +} + +QProgressBar::chunk { + /*background-color: #1d5eff;*/ + background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #1d5eff, stop:0.5 #4177ff, stop:1 #1d5eff); + border-radius: 3px; +} + + +QAbstractScrollArea::corner { + background: none; + border: none; +} + +QScrollBar:vertical, QScrollBar:horizontal{ + background-color:#343434; + border-radius: 5px; + /*background: none;*/ +} + +QScrollBar:vertical { + margin-top: 0px; + margin-bottom: 0px; + /*width: 10px;*/ +} +QScrollBar:horizontal{ + margin-left: 0px; + margin-right: 0px; + /*height: 10px;*/ +} + +QScrollBar::handle:vertical, QScrollBar::handle:horizontal{ + border-radius: 5px; + border-color: none; + border-width: 1px; + background-color: #999999; +} + +QScrollBar::add-line:vertical, QScrollBar::add-line:horizontal{ + width: 0px; + height: 0px; +} + +QScrollBar::sub-line:vertical, QScrollBar::sub-line:horizontal{ + width: 0px; + height: 0px; +} + +QScrollBar::add-page:vertical{ + border-left: 1px solid gray; + background: transparent; + border-radius: 5px; +/* + border: 1px#343434; + background-color: #343434;*/ +} +QScrollBar::add-page:horizontal{ + border-top: 1px solid gray; + background: transparent; + border-radius: 5px; +/* + border: 1px#343434; + background-color: #343434;*/ +} +QScrollBar::sub-page:vertical{ + border-left: 1px solid gray; + background: transparent; + border-radius: 5px; +/* border: 1px #343434; + background-color: #343434;*/ +} +QScrollBar::sub-page:horizontal{ + border-top: 1px solid gray; + background: transparent; + border-radius: 5px; +/* border: 1px #343434; + background-color: #343434;*/ +} + +QTextEdit{ + color: #ffffff; +} + +QMessageBox { + color: #ffffff; +} + +QToolTip { + color: #000000; +} + +QTextBrowser { + background-color: #464646; + color: #ffffff; + border: 0px; +} + +QRadioButton { + color: #ffffff; +} + +QListWidget { + background-color:rgb(52,52,52); + color: rgb(255, 255, 255); + border: 1px solid gray; + border-radius: 8px; +} + +QLineEdit { + background-color: #343434; + color: rgb(255, 255, 255); + border: 1px solid gray; + border-radius: 5px; +} + +QComboBox { + background-color: rgb(52,52,52); + color: #ffffff; + border: 1px solid gray; + border-radius: 5px; +} + +QComboBox:!enabled { + color: #9f9f9f; +} + +QComboBox QAbstractItemView { + border: 1px solid gray; + selection-background-color: #999999; + selection-color: #1d5eff; + color: #ffffff; +} + +QSpinBox { + background-color: rgb(52,52,52); + color: #ffffff; + border: 1px solid gray; + border-radius: 5px; +} + +QSpinBox:!enabled { + color:#9f9f9f; +} + +/* SPECIAL WIDGETS */ +QPushButton#url_button { + color: #9f9f9f; + border: 0px; + background-color: #464646; +} + +QPushButton#play, QPushButton#pause, QPushButton#stop { + color: #464646; + border: 0px; + background-color: #464646; +} + +QLabel#band_range_lbl { + color: #9f9f9f; +} diff --git a/themes/3-material_design/icons/down-arrow.png b/themes/3-material_design/icons/down-arrow.png new file mode 100644 index 0000000..b2cd4a5 Binary files /dev/null and b/themes/3-material_design/icons/down-arrow.png differ diff --git a/themes/3-material_design/icons/down-arrow_hover.png b/themes/3-material_design/icons/down-arrow_hover.png new file mode 100644 index 0000000..f7ad171 Binary files /dev/null and b/themes/3-material_design/icons/down-arrow_hover.png differ diff --git a/themes/3-material_design/icons/down-arrow_off.png b/themes/3-material_design/icons/down-arrow_off.png new file mode 100644 index 0000000..e7f0af3 Binary files /dev/null and b/themes/3-material_design/icons/down-arrow_off.png differ diff --git a/themes/3-material_design/icons/off.png b/themes/3-material_design/icons/off.png new file mode 100644 index 0000000..ef39d9e Binary files /dev/null and b/themes/3-material_design/icons/off.png differ diff --git a/themes/3-material_design/icons/off_press.png b/themes/3-material_design/icons/off_press.png new file mode 100644 index 0000000..3355d12 Binary files /dev/null and b/themes/3-material_design/icons/off_press.png differ diff --git a/themes/3-material_design/icons/on.png b/themes/3-material_design/icons/on.png new file mode 100644 index 0000000..2244ffe Binary files /dev/null and b/themes/3-material_design/icons/on.png differ diff --git a/themes/3-material_design/icons/on_press.png b/themes/3-material_design/icons/on_press.png new file mode 100644 index 0000000..4754508 Binary files /dev/null and b/themes/3-material_design/icons/on_press.png differ diff --git a/themes/3-material_design/icons/search_icon.png b/themes/3-material_design/icons/search_icon.png new file mode 100644 index 0000000..dd0ec52 Binary files /dev/null and b/themes/3-material_design/icons/search_icon.png differ diff --git a/themes/3-material_design/icons/up-arrow.png b/themes/3-material_design/icons/up-arrow.png new file mode 100644 index 0000000..6f0f090 Binary files /dev/null and b/themes/3-material_design/icons/up-arrow.png differ diff --git a/themes/3-material_design/icons/up-arrow_hover.png b/themes/3-material_design/icons/up-arrow_hover.png new file mode 100644 index 0000000..149eae0 Binary files /dev/null and b/themes/3-material_design/icons/up-arrow_hover.png differ diff --git a/themes/3-material_design/icons/up-arrow_off.png b/themes/3-material_design/icons/up-arrow_off.png new file mode 100644 index 0000000..ac2217f Binary files /dev/null and b/themes/3-material_design/icons/up-arrow_off.png differ diff --git a/themes/3-material_design/icons/volume.png b/themes/3-material_design/icons/volume.png new file mode 100644 index 0000000..88e4c7e Binary files /dev/null and b/themes/3-material_design/icons/volume.png differ diff --git a/themes/3-material_design/material_design.th b/themes/3-material_design/material_design.th new file mode 100644 index 0000000..e5b9d6e --- /dev/null +++ b/themes/3-material_design/material_design.th @@ -0,0 +1,410 @@ +/***************************************************************************** +MainWindow +*****************************************************************************/ +QWidget:window { + border: 0px solid #2e2f34; + background-color: #2e2f34; +} + +/***************************************************************************** +Search bar +*****************************************************************************/ +QLineEdit { + background-color: transparent; + border: 0px solid transparent; + border-bottom: 2px solid #669900; + color: #669900; +} + +/***************************************************************************** +Scroll Bars +*****************************************************************************/ +QScrollBar:horizontal { + background: transparent; /* Background where slider is not */ + height: 10px; + margin: 0; +} + +QScrollBar:vertical { + background: transparent; /* Background where slider is not */ + width: 10px; + margin: 0; +} + +QScrollBar::handle:horizontal { + background: #37474F; /* Slider color */ + min-width: 16px; + border-radius: 5px; +} + +QScrollBar::handle:vertical { + background: #37474F; /* Slider color */ + min-height: 16px; + border-radius: 5px; +} + +QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal, +QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { + background: none; /* Removes the dotted background */ +} + +QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal, +QScrollBar::add-line:vertical, QScrollBar::sub-line:vertical { /* Hides the slider arrows */ + border: none; + background: none; +} + +/***************************************************************************** +List +*****************************************************************************/ +QListWidget { + background-color: transparent; + border: 0px solid transparent; + border-bottom: 2px solid #80CBC4; + color: #c2cfd6; +} + +QListView::item:hover { + color: #669900; + background: transparent; +} + +QListView::item:selected { + color: #88cc00; + background: transparent; +} + +QListView { + background-color: transparent; + color: #c2cfd6; + outline: 0; + border: 0px solid transparent; +} + +/* === QTabBar === */ +QTabBar { + background: transparent; +} + +QTabWidget::pane { + background: transparent; /* Only at the very bottom of the tabs */ +} + +QTabBar::tab { + background: transparent; + border: 0px solid transparent; + border-bottom: 2px solid transparent; + color: #546E7A; + padding-left: 10px; + padding-right: 10px; + padding-top: 3px; + padding-bottom: 3px; +} + +QTabBar::tab:hover { + background-color: transparent; + border: 0px solid transparent; + border-bottom: 2px solid #88cc00; + color: #AFBDC4; +} + +QTabBar::tab:selected { + background-color: transparent; + border: 0px solid transparent; + border-top: none; + border-bottom: 2px solid #88cc00; + color: #FFFFFF; +} + +QStackedWidget { + background: #2e2f34;/* This covers a bunch of things, I was thinking about making it transparent, */ + /* but I would have to find all the other elements... but QTabWidget::pane may be it */ +} + +/* ==================== Dialog ==================== */ +QLabel { + background: transparent; + color: #CFD8DC; /* Not sure about this one */ +} + +QDialog { + background-color: #263238; + color: #546E7A; + outline: 0; + border: 2px solid transparent; +} + +/***************************************************************************** +Buttons +*****************************************************************************/ + +QToolTip { + background-color: #80CBC4; + color: black; + padding: 5px; + border-radius: 0; + opacity: 200; +} + +QPushButton { + background-color: transparent; + color: #c2cfd6; + border: 1px solid transparent; + padding: 4px 22px; +} + +QPushButton:hover { + border-left: 2px solid #88cc00; + border-right: 2px solid #88cc00; + color: #f0f3f5; +} + +QPushButton:pressed { + color: #efffcc; +} + +QPushButton:disabled { + color:#546E7A; +} + +QPushButton:checked { + color: #88cc00; +} + +/***************************************************************************** +Rich Text Box +*****************************************************************************/ +QTextBrowser { + background: transparent; + border: 0px solid transparent; + color: #546E7A; +} + +/***************************************************************************** +Main Menu (Upper part) +*****************************************************************************/ +QTreeView { + background-color: #263238; +} + +QMenu { + background-color: #263238; /* File Menu Background color */ + color: #546E7A; +} + +QMenu::item:selected { + color: #AFBDC4; +} + +QMenu::item:pressed { + color: #FFFFFF; +} + +QMenu::separator { + height: 1px; + background: transparent; /* Could change this to #546E7A and reduce the margin top and bottom to 1px */ + margin-left: 10px; + margin-right: 10px; + margin-top: 5px; + margin-bottom: 5px; +} + +/***************************************************************************** +Main Menu (Bar) +*****************************************************************************/ +QMenuBar { + background-color: transparent; + color: #546E7A; +} + +QMenuBar::item { + background: transparent; +} + +QMenuBar::item:disabled { + color: gray; +} + +QMenuBar::item:selected { + color: #AFBDC4; +} + +QMenuBar::item:pressed { + color: #FFFFFF; +} + +QToolBar { + background: transparent; + border: 1px solid transparent; +} + +QToolBar:handle { + background: transparent; + border-left: 2px dotted #80CBC4; /* Fix the 4 handle dots so it doesn't look crappy */ + color: transparent; +} + +QToolBar::separator { + border: 0; +} + +/***************************************************************************** +ComboBox +*****************************************************************************/ +QComboBox { + border: 0px solid gray; + border-radius: 2px; + padding: 1px 6px 1px 6px; + min-width: 2em; +} + +QComboBox:!editable, QComboBox::drop-down:editable { + color: #c2cfd6; + selection-color: #80CBC4; + background-color: transparent; + selection-background-color: transparent; +} + +QComboBox:disabled { + color: #546E7A; +} + +/* QComboBox gets the "on" state when the popup is open */ +QComboBox:!editable:on, +QComboBox::drop-down:editable:on { + color: #c2cfd6; + background-color: transparent; + selection-background-color: transparent; +} + +QComboBox:on { /* shift the text when the popup opens */ + padding-top: 3px; + padding-left: 4px; +} + +QComboBox::drop-down { + background-color: transparent; + subcontrol-origin: padding; + subcontrol-position: top right; + width: 20px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; +} + +QComboBox::down-arrow:enabled { + image: url("./themes/3-material_design/icons/down-arrow.png"); +} + +QComboBox::down-arrow:disabled { + image: url("./themes/3-material_design/icons/down-arrow_off.png"); +} + +QComboBox::down-arrow:hover { + image: url("./themes/3-material_design/icons/down-arrow_hover.png"); +} + +QComboBox::down-arrow:on { /* shift the arrow when popup is open */ + top: 1px; + left: 1px; +} + +QComboBox QAbstractItemView { +background-color: #2e2f34; +} + +/***************************************************************************** +RadioButton +*****************************************************************************/ + +QRadioButton{ + color: #c2cfd6; +} + +QRadioButton:disabled{ + color: #546E7A; +} + +QRadioButton::indicator{ + width: 50px; + height: 50px; +} + +QRadioButton::indicator::unchecked { + image: url("./themes/3-material_design/icons/off.png"); +} + +QRadioButton::indicator:unchecked:hover { + image: url("./themes/3-material_design/icons/off_press.png"); +} + +QRadioButton::indicator:unchecked:pressed { + image: url("./themes/3-material_design/icons/off_press.png"); +} + +QRadioButton::indicator::checked { + image: url("./themes/3-material_design/icons/on.png"); +} + +QRadioButton::indicator:checked:hover { + image: url("./themes/3-material_design/icons/on_press.png"); +} + +QRadioButton::indicator:checked:pressed { + image: url("./themes/3-material_design/icons/on_press.png"); +} + +/***************************************************************************** +SpinBox +*****************************************************************************/ +QSpinBox { + color: #c2cfd6; + border-width: 0px; + background: transparent; +} + +QSpinBox:disabled { + color: #546E7A; + border-width: 0px; + background: transparent; +} + +QSpinBox::up-button { + subcontrol-origin: border; + subcontrol-position: top right; + width: 16px; + image: url("./themes/3-material_design/icons/up-arrow.png"); + border-width: 0px; +} + +QSpinBox::up-button:hover { + image: url("./themes/3-material_design/icons/up-arrow_hover.png"); +} + +QSpinBox::up-button:pressed { + image: url("./themes/3-material_design/icons/up-arrow.png"); +} + +QSpinBox::up-button:disabled { + image: url("./themes/3-material_design/icons/up-arrow_off.png"); +} + +QSpinBox::down-button { + subcontrol-origin: border; + subcontrol-position: bottom right; /* position at bottom right corner */ + width: 16px; + image: url("./themes/3-material_design/icons/down-arrow.png"); + border-width: 0px; + border-top-width: 0; +} + +QSpinBox::down-button:hover { + image: url("./themes/3-material_design/icons/down-arrow_hover.png"); +} + +QSpinBox::down-button:pressed { + image: url("./themes/3-material_design/icons/down-arrow.png"); +} + +QSpinBox::down-button:disabled { + image: url("./themes/3-material_design/icons/down-arrow_off.png"); +} \ No newline at end of file diff --git a/utilities.py b/utilities.py index 9e1453a..3f58e4d 100644 --- a/utilities.py +++ b/utilities.py @@ -1,37 +1,70 @@ from collections import namedtuple import hashlib +import re from pandas import read_csv -class _ReadOnlyProperty(object): - def __init__(self, value): - self.__value = value +from PyQt5.QtWidgets import QMessageBox + +# class _ReadOnlyProperty(object): +# def __init__(self, value): +# self.__value = value - def __get__(self, obj, objtype): - return self.__value +# def __get__(self, obj, objtype): +# return self.__value - def __set__(self, obj, value): - return NotImplementedError("Cannot change a constant.") +# def __set__(self, obj, value): +# return NotImplementedError("Cannot change a constant.") - # def change_hardcoded_value(self, value): - # self.__value = value +# def __make_read_only(cls): +# for k, v in cls.__dict__.items(): +# if not callable(getattr(cls, k)) and '__' not in k: +# setattr(cls, k, _ReadOnlyProperty(v)) +# # def raise_err(self, attr, value): +# # raise NotImplementedError("Cannot add an attribute.") +# # setattr(cls, '__setattr__', raise_err) +# return cls -def __make_read_only(cls): - for k, v in cls.__dict__.items(): - if not callable(getattr(cls, k)) and '__' not in k: - setattr(cls, k, _ReadOnlyProperty(v)) - # def raise_err(self, attr, value): - # raise NotImplementedError("Cannot add an attribute.") - # setattr(cls, '__setattr__', raise_err) - return cls - -@__make_read_only -class __Constants(object): +# @__make_read_only +class Constants(object): + class Messages(object): + NO_DB_AVAIL = "No database available.\nGo to Updates->Update database." + NO_DB = "No database" DB_LOCATION = "https://aresvalley.com/Storage/Artemis/Database/data.zip" REF_LOC = "https://aresvalley.com/Storage/Artemis/Database/data.zip.log" + DB_NAME = "db.csv" + DB_NAMES = ("name", + "inf_freq", + "sup_freq", + "mode", + "inf_band", + "sup_band", + "location", + "url", + "description", + "modulation", + "category_code", + "acf",) + DB_WIKI_CLICKED = "url_clicked" + DB_STRINGS = ('inf_freq', + 'sup_freq', + 'mode', + 'inf_band', + 'sup_band', + 'category_code',) DATA_FOLDER = "Data" SPECTRA_FOLDER = "Spectra" + SPECTRA_EXT = ".png" AUDIO_FOLDER = "Audio" - ICONS_FOLDER = "icons_imgs" + THEMES_FOLDER = "themes" + THEME_EXTENSION = ".th" + ICONS_FOLDER = "icons" + DEFAULT_THEME = "1-system" + CURRENT_THEME = ".current_theme" + THEME_COLORS = "colors.txt" + NOT_AVAILABLE = "spectrumnotavailable.png" + NOT_SELECTED = "nosignalselected.png" + SEARCH_LABEL_IMG = "search_icon.png" + VOLUME_LABEL_IMG = "volume.png" __Band = namedtuple("Band", ["lower", "upper"]) __ELF = __Band(0, 30) # Formally it is (3, 30) Hz. __SLF = __Band(30, 300) @@ -88,7 +121,6 @@ class __Constants(object): "PSK", "QAM", "TDMA",) - LOCATIONS = (UNKNOWN, "Australia", "Canada", @@ -121,13 +153,21 @@ class __Constants(object): "World Wide", "Worldwide",) -Constants = __Constants() +# Constants = __Constants() def reset_apply_remove_btn(button): if button.isChecked(): button.setChecked(False) button.clicked.emit() +def throwable_message(cls, title, text, connection = None): + msg = QMessageBox(cls) + msg.setWindowTitle(title) + msg.setText(text) + if connection: + msg.setText(text).finished.connect(connection) + return msg + def checksum_ok(data, what): code = hashlib.sha256() code.update(data) @@ -141,4 +181,7 @@ def checksum_ok(data, what): reference = read_csv(Constants.REF_LOC, delimiter = '*').iat[-1, n] except HTTPError: return False - return code.hexdigest() == reference \ No newline at end of file + return code.hexdigest() == reference + +def is_valid_html_color(color): + return bool(re.match("#([a-zA-Z0-9]){6}", color))