Update PyQt version to PyQt6 and adjust window geometry in URLManager

This commit is contained in:
2024-07-15 09:29:51 +02:00
parent 3a52b5793f
commit 36b61c0600
4 changed files with 1208 additions and 3 deletions

View File

@ -1,12 +1,12 @@
# tabRemember # tabRemember
A open-source app written in Python using PyQT6 for managing links for Sims players who use custom content, and for others who need a nice, simple and little bookmark manager outside the browser. A open-source app written in Python using PyQt6 for managing links for Sims players who use custom content, and for others who need a nice, simple and little bookmark manager outside the browser.
# Wait, what? # Wait, what?
My wife is one of those people and I've seen how her browsers are, she has maxed out the tabs in the Safari browser in her iPhone and is always stressed that she might lose them at any given moment. Her computer is no better.. My wife is one of those people and I've seen how her browsers are, she has maxed out the tabs in the Safari browser in her iPhone and is always stressed that she might lose them at any given moment. Her computer is no better..
So this project is to create a cross platform app written in Python, relying on PyQT6 for theming and looks. So this project is to create a cross platform app written in Python, relying on PyQt6 for theming and looks.
I plan to have it multilingual as well since not everyone uses the same language. I plan to have it multilingual as well since not everyone uses the same language.
For the time being the languages at the start and while I build this app up towards the first release, I will only offer English and Icelandic. For the time being the languages at the start and while I build this app up towards the first release, I will only offer English and Icelandic.
@ -122,4 +122,3 @@ The app supports custom filters for extracting search terms from URLs. Filters a
1. Click the delete button (🗑️) next to the URL. 1. Click the delete button (🗑️) next to the URL.
2. Confirm the deletion in the dialog that appears. 2. Confirm the deletion in the dialog that appears.

510
app-new.py Normal file
View File

@ -0,0 +1,510 @@
import sys
import json
import os
from PyQt6.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QHBoxLayout,
QLineEdit, QPushButton, QTextEdit, QMessageBox,
QSpacerItem, QSizePolicy, QLabel, QFileDialog, QDialog,
QFormLayout, QTableWidget, QTableWidgetItem, QHeaderView,
QComboBox, QAbstractItemView
)
from PyQt6.QtGui import QIcon, QDesktopServices
from PyQt6.QtCore import Qt, QDateTime, QUrl
from PyQt6.QtSvgWidgets import QSvgWidget
class URLSearch:
def __init__(self, url, search_engine_url):
self.url = url
self.search_engine_url = search_engine_url
self.filters_dir = 'filters/'
self.available_filters = self.load_filters()
def load_filters(self):
filters = {}
for file_name in os.listdir(self.filters_dir):
if file_name.endswith('.filter.py'):
domain = '.'.join(file_name.split('.')[:-2]) # Extracting domain.tld from domain.tld.filter.py
filters[domain] = os.path.join(self.filters_dir, file_name)
print("Loaded filters:", filters) # Debug print
return filters
def extract_terms(self):
parsed_url = QUrl(self.url)
host_parts = parsed_url.host().split('.')
domain = '.'.join(host_parts[-2:]) # Extract full domain including TLD
print("Extracted domain:", domain) # Debug print
if domain in self.available_filters:
filter_file = self.available_filters[domain]
terms = self.apply_filter(filter_file)
if terms:
return terms
return None
def apply_filter(self, filter_file):
try:
with open(filter_file, 'r') as file:
filter_code = file.read()
local_vars = {'url': self.url, 'terms': [], 'QUrl': QUrl}
exec(filter_code, {}, local_vars)
return local_vars['terms']
except Exception as e:
print(f"Error applying filter: {e}")
return None
def search(self):
terms = self.extract_terms()
if terms:
search_query = '+'.join(terms)
search_url = f"{self.search_engine_url}{search_query}"
QDesktopServices.openUrl(QUrl(search_url))
else:
QDesktopServices.openUrl(QUrl(self.url)) # Open the URL directly if no valid search term is extracted
class URLManager(QWidget):
def __init__(self):
super().__init__()
self.settings = self.load_settings()
self.translations = {}
self.load_translations(f'lang/translations_{self.settings["language"].lower()[:2]}.json')
self.setWindowTitle(self.get_translation('title', 'URL Manager'))
self.setGeometry(100, 100, 600, 600)
self.setWindowIcon(QIcon('assets/logo.png'))
self.load_stylesheet("style-new.qss") # Load and apply the stylesheet
self.layout = QVBoxLayout()
# URL input and settings button layout
self.url_layout = QHBoxLayout()
self.url_input = QLineEdit()
self.url_input.setPlaceholderText(self.get_translation('url_placeholder', 'Enter URL'))
self.url_layout.addWidget(self.url_input)
self.settings_button = QPushButton()
self.settings_button.setFixedSize(28, 28)
self.settings_button.setStyleSheet("padding: 5px;")
self.settings_button.clicked.connect(self.show_settings_dialog)
self.url_layout.addWidget(self.settings_button)
self.info_button = QPushButton()
self.info_button.setFixedSize(28, 28)
self.info_button.setStyleSheet("padding: 5px;")
self.info_button.clicked.connect(self.show_info_dialog)
self.url_layout.addWidget(self.info_button)
self.layout.addLayout(self.url_layout)
self.update_icon_color()
self.description_input = QTextEdit()
self.description_input.setPlaceholderText(self.get_translation('description_placeholder', 'Enter Description or Thoughts'))
self.description_input.setMaximumHeight(100)
self.layout.addWidget(self.description_input)
self.add_button = QPushButton(self.get_translation('save_url_button', 'Save URL'))
self.add_button.clicked.connect(self.add_url)
self.layout.addWidget(self.add_button)
self.layout.addSpacerItem(QSpacerItem(0, 10, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed))
self.search_layout = QHBoxLayout()
self.search_input = QLineEdit()
self.search_input.setPlaceholderText(self.get_translation('search_placeholder', 'Search...'))
self.search_input.textChanged.connect(self.filter_urls)
self.search_layout.addWidget(self.search_input)
self.layout.addLayout(self.search_layout)
self.search_input.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
self.url_list = QTableWidget()
self.url_list.setColumnCount(3)
self.url_list.setHorizontalHeaderLabels([
self.get_translation('column_url', 'URL'),
self.get_translation('column_date', 'Date'),
self.get_translation('column_actions', 'Actions')
])
self.url_list.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Stretch)
self.url_list.setColumnWidth(1, 150)
self.url_list.setColumnWidth(2, 100)
self.url_list.setSelectionMode(QAbstractItemView.SelectionMode.NoSelection)
self.layout.addWidget(self.url_list)
self.setLayout(self.layout)
self.urls = []
self.load_urls()
self.search_engines = {
"Bing": "https://www.bing.com/search?q=",
"Brave": "https://search.brave.com/search?q=",
"DuckDuckGo": "https://duckduckgo.com/?q=",
"Ecosia": "https://www.ecosia.org/search?q=",
"Google": "https://www.google.com/search?q=",
"Startpage": "https://www.startpage.com/do/search?q=",
"Swisscows": "https://swisscows.com/web?query="
}
def load_stylesheet(self, stylesheet_path):
if os.path.exists(stylesheet_path):
with open(stylesheet_path, "r") as file:
self.setStyleSheet(file.read())
def load_translations(self, file_path):
if os.path.exists(file_path):
with open(file_path, 'r') as file:
data = json.load(file)
self.translations = data['translations']
def get_translation(self, key, default):
return self.translations.get(key, default)
def update_icon_color(self):
palette = self.palette()
if palette.color(palette.ColorRole.Window).value() < 128:
settings_icon_path = 'assets/cogwheel_dark.svg'
info_icon_path = 'assets/info_dark.svg'
self.action_icons = {
"visit": 'assets/visit_dark.svg',
"info": 'assets/info_dark.svg',
"search": 'assets/search_dark.svg',
"delete": 'assets/delete_dark.svg'
}
else:
settings_icon_path = 'assets/cogwheel_light.svg'
info_icon_path = 'assets/info_light.svg'
self.action_icons = {
"visit": 'assets/visit_light.svg',
"info": 'assets/info_light.svg',
"search": 'assets/search_light.svg',
"delete": 'assets/delete_light.svg'
}
self.settings_button.setIcon(QIcon(settings_icon_path))
self.info_button.setIcon(QIcon(info_icon_path))
def add_url(self):
url = self.url_input.text()
description = self.description_input.toPlainText()
if url:
date_added = QDateTime.currentDateTime().toString(Qt.DateFormat.ISODate)
url_data = {'url': url, 'description': description, 'date': date_added}
self.urls.append(url_data)
self.save_url(url_data)
self.update_url_list()
self.url_input.clear()
self.description_input.clear()
def save_url(self, url_data):
url_path = os.path.join(self.settings['data_directory'], 'urls.json')
if os.path.exists(url_path):
with open(url_path, 'r') as file:
url_list = json.load(file)
else:
url_list = []
url_list.append(url_data)
with open(url_path, 'w') as file:
json.dump(url_list, file)
def update_url(self, row, new_url, new_description):
self.urls[row]['url'] = new_url
self.urls[row]['description'] = new_description
self.save_urls()
self.update_url_list()
def delete_url(self, row):
reply = QMessageBox.question(self, self.get_translation('delete_confirmation_title', 'Delete URL'), self.get_translation('delete_confirmation', 'Are you sure you want to delete this URL?'),
QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No)
if reply == QMessageBox.StandardButton.Yes:
del self.urls[row]
self.save_urls()
self.update_url_list()
def filter_urls(self):
search_term = self.search_input.text().strip().lower()
if not search_term:
self.update_url_list()
return
filtered_urls = [url for url in self.urls if search_term in url['url'].lower() or search_term in url['description'].lower()]
self.update_url_list(filtered_urls)
def update_url_list(self, urls=None):
self.url_list.setRowCount(0)
urls_to_display = urls if urls else self.urls
for row, url in enumerate(urls_to_display):
self.url_list.insertRow(row)
self.url_list.setItem(row, 0, QTableWidgetItem(url['url']))
formatted_date = self.format_date(url['date'])
date_item = QTableWidgetItem(formatted_date)
date_item.setTextAlignment(Qt.AlignmentFlag.AlignVCenter)
self.url_list.setItem(row, 1, date_item)
actions_layout = QHBoxLayout()
actions_layout.setContentsMargins(0, 0, 0, 0)
actions_layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
visit_button = QPushButton()
visit_button.setIcon(QIcon(self.action_icons["visit"]))
visit_button.setFixedSize(22, 22)
visit_button.setStyleSheet("border: none; padding: 3px;")
visit_button.clicked.connect(lambda _, url=url['url']: self.visit_url(url))
actions_layout.addWidget(visit_button)
info_button = QPushButton()
info_button.setIcon(QIcon(self.action_icons["info"]))
info_button.setFixedSize(22, 22)
info_button.setStyleSheet("border: none; padding: 3px;")
info_button.clicked.connect(lambda _, row=row: self.view_description(row))
actions_layout.addWidget(info_button)
search_button = QPushButton()
search_button.setIcon(QIcon(self.action_icons["search"]))
search_button.setFixedSize(22, 22)
search_button.setStyleSheet("border: none; padding: 3px;")
search_button.clicked.connect(lambda _, url=url['url']: self.search_url(url))
actions_layout.addWidget(search_button)
delete_button = QPushButton()
delete_button.setIcon(QIcon(self.action_icons["delete"]))
delete_button.setFixedSize(22, 22)
delete_button.setStyleSheet("border: none; padding: 3px;")
delete_button.clicked.connect(lambda _, row=row: self.delete_url(row))
actions_layout.addWidget(delete_button)
actions_widget = QWidget()
actions_widget.setLayout(actions_layout)
self.url_list.setCellWidget(row, 2, actions_widget)
vertical_header = self.url_list.verticalHeader()
vertical_header.setVisible(False)
def format_date(self, date_str):
date = QDateTime.fromString(date_str, Qt.DateFormat.ISODate)
if self.settings['date_format'] == 'Nerdy':
return date.toString("yyyy-MM-ddTHH:mm:ss")
elif self.settings['date_format'] == 'Normal':
return date.toString("dd/MM/yy @ HH:mm")
elif self.settings['date_format'] == 'Murica!':
return date.toString("MM/dd/yyyy hh:mm AP")
else:
return date_str
def visit_url(self, url):
QDesktopServices.openUrl(QUrl(url))
def view_description(self, row):
dialog = DescriptionDialog(self, row)
dialog.exec()
def search_url(self, url):
search_engine_url = self.search_engines[self.settings['search_engine']]
url_search = URLSearch(url, search_engine_url)
url_search.search()
def load_settings(self):
settings_path = 'data/settings.json'
if os.path.exists(settings_path):
with open(settings_path, 'r') as file:
settings = json.load(file)
self.data_directory = settings['data_directory']
self.search_engine = settings['search_engine']
self.date_format = settings.get('date_format', 'Nerdy')
self.language = settings.get('language', 'English')
return settings
else:
default_settings = {
'data_directory': 'data/',
'search_engine': 'Google',
'date_format': 'Nerdy',
'language': 'English'
}
self.save_settings(default_settings)
return default_settings
def save_settings(self, settings=None):
settings_path = 'data/settings.json'
os.makedirs(os.path.dirname(settings_path), exist_ok=True)
if settings is None:
settings = {
'data_directory': self.data_directory,
'search_engine': self.search_engine,
'date_format': self.date_format,
'language': self.language
}
with open(settings_path, 'w') as file:
json.dump(settings, file)
def load_urls(self):
url_path = os.path.join(self.settings['data_directory'], 'urls.json')
if os.path.exists(url_path):
with open(url_path, 'r') as file:
self.urls = json.load(file)
self.update_url_list()
def save_urls(self):
url_path = os.path.join(self.settings['data_directory'], 'urls.json')
with open(url_path, 'w') as file:
json.dump(self.urls, file)
def show_info_dialog(self):
dialog = QDialog(self)
dialog.setWindowTitle(self.get_translation('about_title', 'About URL Manager'))
layout = QVBoxLayout()
svg_widget = QSvgWidget('assets/logo.svg')
svg_widget.setFixedSize(256, 256)
layout.addWidget(svg_widget, alignment=Qt.AlignmentFlag.AlignCenter)
written_by_label = QLabel(self.get_translation('developed_by', 'Developed by Axel Rafn'))
layout.addWidget(written_by_label, alignment=Qt.AlignmentFlag.AlignCenter)
link_label = QLabel()
link_label.setText(f'<a href="{self.get_translation("repository_link", "#")}">{self.get_translation("repository_link_name", "Project Home")}</a>')
link_label.setOpenExternalLinks(True)
layout.addWidget(link_label, alignment=Qt.AlignmentFlag.AlignCenter)
dialog.setLayout(layout)
dialog.exec()
def show_settings_dialog(self):
dialog = SettingsDialog(self)
if dialog.exec() == QDialog.DialogCode.Accepted:
self.settings = self.load_settings()
self.update_url_list()
class DescriptionDialog(QDialog):
def __init__(self, parent, row):
super().__init__(parent)
self.parent = parent
self.row = row
self.setWindowTitle(self.parent.get_translation('description_title', 'URL Description'))
layout = QVBoxLayout()
self.url_input = QLineEdit(self.parent.urls[row]['url'])
layout.addWidget(self.url_input)
self.description_input = QTextEdit(self.parent.urls[row]['description'])
layout.addWidget(self.description_input)
button_layout = QHBoxLayout()
self.update_button = QPushButton(self.parent.get_translation('update_button', 'Update'))
self.update_button.clicked.connect(self.update_url)
self.close_button = QPushButton(self.parent.get_translation('close_button', 'Close'))
self.close_button.clicked.connect(self.close)
button_layout.addWidget(self.update_button)
button_layout.addWidget(self.close_button)
layout.addLayout(button_layout)
self.setLayout(layout)
def update_url(self):
new_url = self.url_input.text()
new_description = self.description_input.toPlainText()
self.parent.update_url(self.row, new_url, new_description)
self.accept()
class SettingsDialog(QDialog):
def __init__(self, parent=None):
super().__init__(parent)
self.setWindowTitle(parent.get_translation('settings_title', 'Settings'))
self.setFixedWidth(360)
self.parent = parent
layout = QVBoxLayout()
directory_label = QLabel(parent.get_translation('data_directory_label', 'Data Directory:'))
layout.addWidget(directory_label)
directory_layout = QHBoxLayout()
self.directory_input = QLineEdit(self.parent.settings['data_directory'])
self.browse_button = QPushButton(self.parent.get_translation('browse_button', 'Browse...'))
self.browse_button.clicked.connect(self.browse_directory)
directory_layout.addWidget(self.directory_input)
directory_layout.addWidget(self.browse_button)
layout.addLayout(directory_layout)
layout.addSpacerItem(QSpacerItem(0, 4, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Fixed))
form_layout = QFormLayout()
# Populate Search Engine Combobox
self.search_engine_combobox = QComboBox()
search_engines = sorted(self.parent.search_engines.keys())
self.search_engine_combobox.addItems(search_engines)
self.search_engine_combobox.setCurrentText(self.parent.settings['search_engine'])
form_layout.addRow(self.parent.get_translation('search_engine_label', 'Search Engine:'), self.search_engine_combobox)
# Populate Date Format Combobox
self.date_format_combobox = QComboBox()
self.date_format_combobox.addItems(["Nerdy", "Normal", "Murica!"])
self.date_format_combobox.setCurrentText(self.parent.settings['date_format'])
form_layout.addRow(self.parent.get_translation('date_format_label', 'Date Format:'), self.date_format_combobox)
# Populate Language Combobox
self.language_combobox = QComboBox()
self.populate_language_combobox()
current_language_code = self.parent.settings['language']
self.set_current_language(current_language_code)
form_layout.addRow(self.parent.get_translation('language_label', 'Language:'), self.language_combobox)
layout.addLayout(form_layout)
self.save_button = QPushButton(self.parent.get_translation('save_button', 'Save'))
self.save_button.clicked.connect(self.save_settings)
layout.addWidget(self.save_button)
self.setLayout(layout)
def browse_directory(self):
directory = QFileDialog.getExistingDirectory(self, "Select Directory")
if directory:
self.directory_input.setText(directory)
def populate_language_combobox(self):
lang_dir = 'lang/'
language_files = [f for f in os.listdir(lang_dir) if f.startswith('translations_') and f.endswith('.json')]
self.language_map = {}
for file_name in language_files:
file_path = os.path.join(lang_dir, file_name)
with open(file_path, 'r') as file:
data = json.load(file)
language_name = data.get('language', 'Unknown')
language_code = file_name[len('translations_'):-len('.json')]
display_text = f"{language_name} ({language_code})"
self.language_combobox.addItem(display_text)
self.language_map[language_code] = display_text
def set_current_language(self, language_code):
if language_code in self.language_map:
display_text = self.language_map[language_code]
index = self.language_combobox.findText(display_text)
if index != -1:
self.language_combobox.setCurrentIndex(index)
def save_settings(self):
selected_language = self.language_combobox.currentText()
language_code = selected_language.split('(')[-1].strip(' )') # Extract language code from "(en)" format
old_language = self.parent.settings['language']
self.parent.settings['data_directory'] = self.directory_input.text()
self.parent.settings['search_engine'] = self.search_engine_combobox.currentText()
self.parent.settings['date_format'] = self.date_format_combobox.currentText()
self.parent.settings['language'] = language_code
self.parent.save_settings(self.parent.settings)
if old_language != language_code:
QMessageBox.information(self, self.parent.get_translation('restart_required_title', 'Restart Required'), self.parent.get_translation('restart_required_message', 'You need to restart the application for the language changes to take effect.'))
self.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = URLManager()
window.show()
sys.exit(app.exec())

196
style-new.qss Normal file
View File

@ -0,0 +1,196 @@
/* General application styling */
QWidget {
color: rgb(221, 221, 221);
font: 11pt "Segoe UI";
background-color: rgb(40, 44, 52);
}
/* QLineEdit styling */
QLineEdit {
background-color: rgb(33, 37, 43);
border: 2px solid rgb(33, 37, 43);
border-radius: 5px;
padding-left: 10px;
selection-color: rgb(255, 255, 255);
selection-background-color: rgb(189, 147, 249);
}
QLineEdit:hover {
border: 2px solid rgb(64, 71, 88);
}
QLineEdit:focus {
border: 2px solid rgb(91, 101, 124);
}
/* QTextEdit styling */
QTextEdit {
background-color: rgb(33, 37, 43);
border: 2px solid rgb(33, 37, 43);
border-radius: 5px;
padding: 10px;
selection-color: rgb(255, 255, 255);
selection-background-color: rgb(189, 147, 249);
}
QTextEdit:hover {
border: 2px solid rgb(64, 71, 88);
}
QTextEdit:focus {
border: 2px solid rgb(91, 101, 124);
}
/* QPushButton styling */
QPushButton {
background-color: rgb(52, 59, 72);
border: 2px solid rgb(52, 59, 72);
border-radius: 5px;
padding: 5px;
color: rgb(221, 221, 221);
}
QPushButton:hover {
background-color: rgb(57, 65, 80);
border: 2px solid rgb(61, 70, 86);
}
QPushButton:pressed {
background-color: rgb(35, 40, 49);
border: 2px solid rgb(43, 50, 61);
}
/* QTableWidget styling */
QTableWidget {
background-color: rgb(33, 37, 43);
border: 2px solid rgb(33, 37, 43);
border-radius: 5px;
padding: 10px;
gridline-color: rgb(44, 49, 58);
}
QTableWidget::item {
border-color: rgb(44, 49, 60);
padding-left: 5px;
padding-right: 5px;
gridline-color: rgb(44, 49, 60);
}
QTableWidget::item:selected {
background-color: rgb(189, 147, 249);
}
QHeaderView::section {
background-color: rgb(33, 37, 43);
border: 1px solid rgb(44, 49, 58);
padding: 3px;
}
QTableWidget::horizontalHeader {
background-color: rgb(33, 37, 43);
}
QHeaderView::section:horizontal {
border: 1px solid rgb(33, 37, 43);
background-color: rgb(33, 37, 43);
padding: 3px;
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
QHeaderView::section:vertical {
border: 1px solid rgb(44, 49, 60);
}
/* QComboBox styling */
QComboBox {
background-color: rgb(33, 37, 43);
border: 2px solid rgb(33, 37, 43);
border-radius: 5px;
padding: 5px;
padding-left: 10px;
}
QComboBox:hover {
border: 2px solid rgb(64, 71, 88);
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 25px;
border-left-width: 3px;
border-left-color: rgba(39, 44, 54, 150);
border-left-style: solid;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
background-image: url(:/icons/images/icons/cil-arrow-bottom.png);
background-position: center;
background-repeat: no-repeat;
}
QComboBox QAbstractItemView {
color: rgb(255, 121, 198);
background-color: rgb(33, 37, 43);
padding: 10px;
selection-background-color: rgb(39, 44, 54);
}
/* QScrollBar styling */
QScrollBar:horizontal {
border: none;
background: rgb(52, 59, 72);
height: 8px;
margin: 0px 21px 0 21px;
border-radius: 0px;
}
QScrollBar::handle:horizontal {
background: rgb(189, 147, 249);
min-width: 25px;
border-radius: 4px;
}
QScrollBar::add-line:horizontal {
border: none;
background: rgb(55, 63, 77);
width: 20px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
subcontrol-position: right;
subcontrol-origin: margin;
}
QScrollBar::sub-line:horizontal {
border: none;
background: rgb(55, 63, 77);
width: 20px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
subcontrol-position: left;
subcontrol-origin: margin;
}
QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal {
background: none;
}
QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
background: none;
}
QScrollBar:vertical {
border: none;
background: rgb(52, 59, 72);
width: 8px;
margin: 21px 0 21px 0;
border-radius: 0px;
}
QScrollBar::handle:vertical {
background: rgb(189, 147, 249);
min-height: 25px;
border-radius: 4px;
}
QScrollBar::add-line:vertical {
border: none;
background: rgb(55, 63, 77);
height: 20px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
border: none;
background: rgb(55, 63, 77);
height: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
background: none;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
background: none;
}

500
style.qss Normal file
View File

@ -0,0 +1,500 @@
QWidget{
color: rgb(221, 221, 221);
font: 10pt "Segoe UI";
}
Tooltip */
QToolTip {
color: #ffffff;
background-color: rgba(33, 37, 43, 180);
border: 1px solid rgb(44, 49, 58);
background-image: none;
background-position: left center;
background-repeat: no-repeat;
border: none;
border-left: 2px solid rgb(255, 121, 198);
text-align: left;
padding-left: 8px;
margin: 0px;
}
Bg App */
#bgApp {
background-color: rgb(40, 44, 52);
border: 1px solid rgb(44, 49, 58);
}
Left Menu */
#leftMenuBg {
background-color: rgb(33, 37, 43);
}
#topLogo {
background-color: rgb(33, 37, 43);
background-image: url(:/images/images/images/PyDracula.png);
background-position: centered;
background-repeat: no-repeat;
}
#titleLeftApp { font: 63 12pt "Segoe UI Semibold"; }
#titleLeftDescription { font: 8pt "Segoe UI"; color: rgb(189, 147, 249); }
/* MENUS */
#topMenu .QPushButton {
background-position: left center;
background-repeat: no-repeat;
border: none;
border-left: 22px solid transparent;
background-color: transparent;
text-align: left;
padding-left: 44px;
}
#topMenu .QPushButton:hover {
background-color: rgb(40, 44, 52);
}
#topMenu .QPushButton:pressed {
background-color: rgb(189, 147, 249);
color: rgb(255, 255, 255);
}
#bottomMenu .QPushButton {
background-position: left center;
background-repeat: no-repeat;
border: none;
border-left: 20px solid transparent;
background-color:transparent;
text-align: left;
padding-left: 44px;
}
#bottomMenu .QPushButton:hover {
background-color: rgb(40, 44, 52);
}
#bottomMenu .QPushButton:pressed {
background-color: rgb(189, 147, 249);
color: rgb(255, 255, 255);
}
#leftMenuFrame{
border-top: 3px solid rgb(44, 49, 58);
}
/* Toggle Button */
#toggleButton {
background-position: left center;
background-repeat: no-repeat;
border: none;
border-left: 20px solid transparent;
background-color: rgb(37, 41, 48);
text-align: left;
padding-left: 44px;
color: rgb(113, 126, 149);
}
#toggleButton:hover {
background-color: rgb(40, 44, 52);
}
#toggleButton:pressed {
background-color: rgb(189, 147, 249);
}
/* Title Menu */
#titleRightInfo { padding-left: 10px; }
Extra Tab */
#extraLeftBox {
background-color: rgb(44, 49, 58);
}
#extraTopBg{
background-color: rgb(189, 147, 249)
}
/* Icon */
#extraIcon {
background-position: center;
background-repeat: no-repeat;
background-image: url(:/icons/images/icons/icon_settings.png);
}
/* Label */
#extraLabel { color: rgb(255, 255, 255); }
/* Btn Close */
#extraCloseColumnBtn { background-color: rgba(255, 255, 255, 0); border: none; border-radius: 5px; }
#extraCloseColumnBtn:hover { background-color: rgb(196, 161, 249); border-style: solid; border-radius: 4px; }
#extraCloseColumnBtn:pressed { background-color: rgb(180, 141, 238); border-style: solid; border-radius: 4px; }
/* Extra Content */
#extraContent{
border-top: 3px solid rgb(40, 44, 52);
}
/* Extra Top Menus */
#extraTopMenu .QPushButton {
background-position: left center;
background-repeat: no-repeat;
border: none;
border-left: 22px solid transparent;
background-color:transparent;
text-align: left;
padding-left: 44px;
}
#extraTopMenu .QPushButton:hover {
background-color: rgb(40, 44, 52);
}
#extraTopMenu .QPushButton:pressed {
background-color: rgb(189, 147, 249);
color: rgb(255, 255, 255);
}
Content App */
#contentTopBg{
background-color: rgb(33, 37, 43);
}
#contentBottom{
border-top: 3px solid rgb(44, 49, 58);
}
/* Top Buttons */
#rightButtons .QPushButton { background-color: rgba(255, 255, 255, 0); border: none; border-radius: 5px; }
#rightButtons .QPushButton:hover { background-color: rgb(44, 49, 57); border-style: solid; border-radius: 4px; }
#rightButtons .QPushButton:pressed { background-color: rgb(23, 26, 30); border-style: solid; border-radius: 4px; }
/* Theme Settings */
#extraRightBox { background-color: rgb(44, 49, 58); }
#themeSettingsTopDetail { background-color: rgb(189, 147, 249); }
/* Bottom Bar */
#bottomBar { background-color: rgb(44, 49, 58); }
#bottomBar QLabel { font-size: 11px; color: rgb(113, 126, 149); padding-left: 10px; padding-right: 10px; padding-bottom: 2px; }
/* CONTENT SETTINGS */
/* MENUS */
#contentSettings .QPushButton {
background-position: left center;
background-repeat: no-repeat;
border: none;
border-left: 22px solid transparent;
background-color:transparent;
text-align: left;
padding-left: 44px;
}
#contentSettings .QPushButton:hover {
background-color: rgb(40, 44, 52);
}
#contentSettings .QPushButton:pressed {
background-color: rgb(189, 147, 249);
color: rgb(255, 255, 255);
}
QTableWidget */
QTableWidget {
background-color: transparent;
padding: 10px;
border-radius: 5px;
gridline-color: rgb(44, 49, 58);
border-bottom: 1px solid rgb(44, 49, 60);
}
QTableWidget::item{
border-color: rgb(44, 49, 60);
padding-left: 5px;
padding-right: 5px;
gridline-color: rgb(44, 49, 60);
}
QTableWidget::item:selected{
background-color: rgb(189, 147, 249);
}
QHeaderView::section{
background-color: rgb(33, 37, 43);
max-width: 30px;
border: 1px solid rgb(44, 49, 58);
border-style: none;
border-bottom: 1px solid rgb(44, 49, 60);
border-right: 1px solid rgb(44, 49, 60);
}
QTableWidget::horizontalHeader {
background-color: rgb(33, 37, 43);
}
QHeaderView::section:horizontal
{
border: 1px solid rgb(33, 37, 43);
background-color: rgb(33, 37, 43);
padding: 3px;
border-top-left-radius: 7px;
border-top-right-radius: 7px;
}
QHeaderView::section:vertical
{
border: 1px solid rgb(44, 49, 60);
}
LineEdit */
QLineEdit {
background-color: rgb(33, 37, 43);
border-radius: 5px;
border: 2px solid rgb(33, 37, 43);
padding-left: 10px;
selection-color: rgb(255, 255, 255);
selection-background-color: rgb(255, 121, 198);
}
QLineEdit:hover {
border: 2px solid rgb(64, 71, 88);
}
QLineEdit:focus {
border: 2px solid rgb(91, 101, 124);
}
PlainTextEdit */
QPlainTextEdit {
background-color: rgb(27, 29, 35);
border-radius: 5px;
padding: 10px;
selection-color: rgb(255, 255, 255);
selection-background-color: rgb(255, 121, 198);
}
QPlainTextEdit QScrollBar:vertical {
width: 8px;
}
QPlainTextEdit QScrollBar:horizontal {
height: 8px;
}
QPlainTextEdit:hover {
border: 2px solid rgb(64, 71, 88);
}
QPlainTextEdit:focus {
border: 2px solid rgb(91, 101, 124);
}
ScrollBars */
QScrollBar:horizontal {
border: none;
background: rgb(52, 59, 72);
height: 8px;
margin: 0px 21px 0 21px;
border-radius: 0px;
}
QScrollBar::handle:horizontal {
background: rgb(189, 147, 249);
min-width: 25px;
border-radius: 4px
}
QScrollBar::add-line:horizontal {
border: none;
background: rgb(55, 63, 77);
width: 20px;
border-top-right-radius: 4px;
border-bottom-right-radius: 4px;
subcontrol-position: right;
subcontrol-origin: margin;
}
QScrollBar::sub-line:horizontal {
border: none;
background: rgb(55, 63, 77);
width: 20px;
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
subcontrol-position: left;
subcontrol-origin: margin;
}
QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
{
background: none;
}
QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
{
background: none;
}
QScrollBar:vertical {
border: none;
background: rgb(52, 59, 72);
width: 8px;
margin: 21px 0 21px 0;
border-radius: 0px;
}
QScrollBar::handle:vertical {
background: rgb(189, 147, 249);
min-height: 25px;
border-radius: 4px
}
QScrollBar::add-line:vertical {
border: none;
background: rgb(55, 63, 77);
height: 20px;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
border: none;
background: rgb(55, 63, 77);
height: 20px;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
subcontrol-position: top;
subcontrol-origin: margin;
}
QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical {
background: none;
}
QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
background: none;
}
CheckBox */
QCheckBox::indicator {
border: 3px solid rgb(52, 59, 72);
width: 15px;
height: 15px;
border-radius: 10px;
background: rgb(44, 49, 60);
}
QCheckBox::indicator:hover {
border: 3px solid rgb(58, 66, 81);
}
QCheckBox::indicator:checked {
background: 3px solid rgb(52, 59, 72);
border: 3px solid rgb(52, 59, 72);
background-image: url(:/icons/images/icons/cil-check-alt.png);
}
RadioButton */
QRadioButton::indicator {
border: 3px solid rgb(52, 59, 72);
width: 15px;
height: 15px;
border-radius: 10px;
background: rgb(44, 49, 60);
}
QRadioButton::indicator:hover {
border: 3px solid rgb(58, 66, 81);
}
QRadioButton::indicator:checked {
background: 3px solid rgb(94, 106, 130);
border: 3px solid rgb(52, 59, 72);
}
ComboBox */
QComboBox{
background-color: rgb(27, 29, 35);
border-radius: 5px;
border: 2px solid rgb(33, 37, 43);
padding: 5px;
padding-left: 10px;
}
QComboBox:hover{
border: 2px solid rgb(64, 71, 88);
}
QComboBox::drop-down {
subcontrol-origin: padding;
subcontrol-position: top right;
width: 25px;
border-left-width: 3px;
border-left-color: rgba(39, 44, 54, 150);
border-left-style: solid;
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
background-image: url(:/icons/images/icons/cil-arrow-bottom.png);
background-position: center;
background-repeat: no-reperat;
}
QComboBox QAbstractItemView {
color: rgb(255, 121, 198);
background-color: rgb(33, 37, 43);
padding: 10px;
selection-background-color: rgb(39, 44, 54);
}
Sliders */
QSlider::groove:horizontal {
border-radius: 5px;
height: 10px;
margin: 0px;
background-color: rgb(52, 59, 72);
}
QSlider::groove:horizontal:hover {
background-color: rgb(55, 62, 76);
}
QSlider::handle:horizontal {
background-color: rgb(189, 147, 249);
border: none;
height: 10px;
width: 10px;
margin: 0px;
border-radius: 5px;
}
QSlider::handle:horizontal:hover {
background-color: rgb(195, 155, 255);
}
QSlider::handle:horizontal:pressed {
background-color: rgb(255, 121, 198);
}
QSlider::groove:vertical {
border-radius: 5px;
width: 10px;
margin: 0px;
background-color: rgb(52, 59, 72);
}
QSlider::groove:vertical:hover {
background-color: rgb(55, 62, 76);
}
QSlider::handle:vertical {
background-color: rgb(189, 147, 249);
border: none;
height: 10px;
width: 10px;
margin: 0px;
border-radius: 5px;
}
QSlider::handle:vertical:hover {
background-color: rgb(195, 155, 255);
}
QSlider::handle:vertical:pressed {
background-color: rgb(255, 121, 198);
}
CommandLinkButton */
QCommandLinkButton {
color: rgb(255, 121, 198);
border-radius: 5px;
padding: 5px;
}
QCommandLinkButton:hover {
color: rgb(255, 170, 255);
background-color: rgb(44, 49, 60);
}
QCommandLinkButton:pressed {
color: rgb(189, 147, 249);
background-color: rgb(52, 58, 71);
}
Button */
#pagesContainer QPushButton {
border: 2px solid rgb(52, 59, 72);
border-radius: 5px;
background-color: rgb(52, 59, 72);
}
#pagesContainer QPushButton:hover {
background-color: rgb(57, 65, 80);
border: 2px solid rgb(61, 70, 86);
}
#pagesContainer QPushButton:pressed {
background-color: rgb(35, 40, 49);
border: 2px solid rgb(43, 50, 61);
}