Implement themes

This commit is contained in:
alessandro90
2019-03-16 10:54:56 +01:00
parent 9cd87a12fb
commit d4c13f09a7
25 changed files with 1298 additions and 740 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ wav_converter.py
*.txt
icons_imgs
TestData
themes/.current_theme

View File

@@ -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):

View File

@@ -14,33 +14,7 @@
<string>Download database</string>
</property>
<property name="styleSheet">
<string notr="true">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;
}</string>
<string notr="true"/>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="sizeConstraint">
@@ -73,6 +47,9 @@ Please wait</string>
<property name="value">
<number>-1</number>
</property>
<property name="textVisible">
<bool>false</bool>
</property>
</widget>
</item>
<item>
@@ -83,13 +60,7 @@ Please wait</string>
</font>
</property>
<property name="styleSheet">
<string notr="true">QPushButton {
background-color: rgb(52,52,52);
color: #FFFFFF;
border: 1px solid gray;
border-radius: 8px;
}
</string>
<string notr="true"/>
</property>
<property name="text">
<string>Cancel</string>

202
main.py
View File

@@ -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};")

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

239
themes/2-dark/dark.th Normal file
View File

@@ -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;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 820 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -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 &quot;on&quot; 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");
}

View File

@@ -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
def __get__(self, obj, objtype):
return self.__value
def __set__(self, obj, value):
return NotImplementedError("Cannot change a constant.")
# def change_hardcoded_value(self, value):
# class _ReadOnlyProperty(object):
# def __init__(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 __get__(self, obj, objtype):
# return self.__value
@__make_read_only
class __Constants(object):
# def __set__(self, obj, value):
# return NotImplementedError("Cannot change a constant.")
# 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):
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)
@@ -142,3 +182,6 @@ def checksum_ok(data, what):
except HTTPError:
return False
return code.hexdigest() == reference
def is_valid_html_color(color):
return bool(re.match("#([a-zA-Z0-9]){6}", color))