diff --git a/rare/app.py b/rare/app.py
index 4bcceecf..7dcb39e2 100644
--- a/rare/app.py
+++ b/rare/app.py
@@ -1,15 +1,13 @@
import configparser
import logging
import os
-import platform
import sys
import time
import traceback
-import qtawesome
from PyQt5.QtCore import QThreadPool, QSettings, QTranslator
-from PyQt5.QtGui import QIcon, QPalette
-from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QStyleFactory, QMessageBox
+from PyQt5.QtGui import QIcon
+from PyQt5.QtWidgets import QApplication, QSystemTrayIcon, QMessageBox
from requests import HTTPError
import rare.shared as shared
@@ -17,7 +15,7 @@ from rare import languages_path, resources_path, cache_dir
from rare.components.dialogs.launch_dialog import LaunchDialog
from rare.components.main_window import MainWindow
from rare.components.tray_icon import TrayIcon
-from rare.utils.utils import load_color_scheme
+from rare.utils.utils import set_color_pallete, set_style_sheet
start_time = time.strftime('%y-%m-%d--%H-%M') # year-month-day-hour-minute
file_name = os.path.join(cache_dir, f"logs/Rare_{start_time}.log")
@@ -113,27 +111,20 @@ class App(QApplication):
self.installTranslator(self.qt_translator)
# Style
+ # lk: this is a bit silly but serves well until we have a class
+ # lk: store the default qt style name from the system on startup as a property for later reference
+ self.setProperty('rareDefaultQtStyle', self.style().objectName())
+
if self.settings.value("color_scheme", None) is None and self.settings.value("style_sheet", None) is None:
self.settings.setValue("color_scheme", "")
self.settings.setValue("style_sheet", "RareStyle")
- if color := self.settings.value("color_scheme", False):
- self.setStyle(QStyleFactory.create("Fusion"))
+ if color_scheme := self.settings.value("color_scheme", False):
self.settings.setValue("style_sheet", "")
- custom_palette = load_color_scheme(os.path.join(resources_path, "colors", color + ".scheme"))
- if custom_palette is not None:
- self.setPalette(custom_palette)
- qtawesome.set_defaults(color=custom_palette.color(QPalette.Text))
-
- elif style := self.settings.value("style_sheet", False):
- self.setStyle(QStyleFactory.create("Fusion"))
+ set_color_pallete(color_scheme)
+ elif style_sheet := self.settings.value("style_sheet", False):
self.settings.setValue("color_scheme", "")
- stylesheet = open(os.path.join(resources_path, "stylesheets", style, "stylesheet.qss")).read()
- style_resource_path = os.path.join(resources_path, "stylesheets", style, "")
- if platform.system() == "Windows":
- style_resource_path = style_resource_path.replace('\\', '/')
- self.setStyleSheet(stylesheet.replace("@path@", style_resource_path))
- qtawesome.set_defaults(color="white")
+ set_style_sheet(style_sheet)
self.setWindowIcon(QIcon(os.path.join(resources_path, "images", "Rare.png")))
# launch app
diff --git a/rare/components/main_window.py b/rare/components/main_window.py
index 5d45c64d..120f7a9f 100644
--- a/rare/components/main_window.py
+++ b/rare/components/main_window.py
@@ -1,8 +1,8 @@
import os
from logging import getLogger
-from PyQt5.QtCore import Qt, QSettings, QTimer
-from PyQt5.QtGui import QCloseEvent
+from PyQt5.QtCore import Qt, QSettings, QTimer, QSize, QRect
+from PyQt5.QtGui import QCloseEvent, QCursor
from PyQt5.QtWidgets import QMainWindow, QMessageBox, QApplication
from rare import data_dir, shared
@@ -21,18 +21,34 @@ class MainWindow(QMainWindow):
self.core = shared.core
self.signals = shared.signals
-
self.offline = shared.args.offline
- width, height = 1200, 800
- if self.settings.value("save_size", False):
- width, height = self.settings.value("window_size", (1200, 800), tuple)
-
- desktop = QApplication.desktop()
- self.setGeometry((desktop.width() - width) // 2, (desktop.height() - height) // 2, int(width), int(height))
self.setWindowTitle("Rare - GUI for legendary")
self.tab_widget = TabWidget(self)
self.setCentralWidget(self.tab_widget)
+
+ width, height = 1200, 800
+ if self.settings.value("save_size", False):
+ width, height = self.settings.value("window_size", (width, height), tuple)
+
+ # move the window outside the viewport
+ self.move(-50000, -50000)
+ # show the window in order for it to get decorated, otherwise windowHandle() is null
+ self.show()
+ # get the margins of the decorated window
+ margins = self.windowHandle().frameMargins()
+ # hide the window again because we don't want to show it at this point
+ self.hide()
+ # get the screen the cursor is on
+ current_screen = QApplication.screenAt(QCursor.pos())
+ # get the available screen geometry (excludes panels/docks)
+ screen_rect = current_screen.availableGeometry()
+ decor_width = margins.left() + margins.right()
+ decor_height = margins.top() + margins.bottom()
+ window_size = QSize(width, height).boundedTo(screen_rect.size() - QSize(decor_width, decor_height))
+ self.resize(window_size)
+ self.move(screen_rect.center() - self.rect().adjusted(0, 0, decor_width, decor_height).center())
+
if not shared.args.offline:
self.rpc = DiscordRPC()
self.tab_widget.delete_presence.connect(self.rpc.set_discord_rpc)
@@ -60,7 +76,6 @@ class MainWindow(QMainWindow):
self.tab_widget.games_tab.game_utils.prepare_launch(game, offline=shared.args.offline)
else:
logger.info(f"Could not find {game} in Games")
-
elif action.startswith("start"):
self.show()
os.remove(file_path)
diff --git a/rare/components/tabs/__init__.py b/rare/components/tabs/__init__.py
index ad4f925e..cd1e22b2 100644
--- a/rare/components/tabs/__init__.py
+++ b/rare/components/tabs/__init__.py
@@ -9,7 +9,7 @@ from rare.components.tabs.games import GamesTab
from rare.components.tabs.settings import SettingsTab
from rare.components.tabs.settings.debug import DebugSettings
from rare.components.tabs.shop import Shop
-from rare.components.tabs.tab_utils import TabBar, TabButtonWidget
+from rare.components.tabs.tab_utils import MainTabBar, TabButtonWidget
class TabWidget(QTabWidget):
@@ -20,7 +20,10 @@ class TabWidget(QTabWidget):
disabled_tab = 3 if not shared.args.offline else 1
self.core = shared.core
self.signals = shared.signals
- self.setTabBar(TabBar(disabled_tab))
+ self.setTabBar(MainTabBar(disabled_tab))
+ # lk: Figure out why this adds a white line at the top
+ # lk: despite setting qproperty-drawBase to 0 in the stylesheet
+ # self.setDocumentMode(True)
# Generate Tabs
self.games_tab = GamesTab()
self.addTab(self.games_tab, self.tr("Games"))
diff --git a/rare/components/tabs/games/game_info/game_settings.py b/rare/components/tabs/games/game_info/game_settings.py
index 7eed6f5c..8800edb2 100644
--- a/rare/components/tabs/games/game_info/game_settings.py
+++ b/rare/components/tabs/games/game_info/game_settings.py
@@ -4,7 +4,7 @@ from logging import getLogger
from typing import Tuple
from PyQt5.QtCore import QSettings, QThreadPool
-from PyQt5.QtWidgets import QWidget, QFileDialog, QMessageBox, QLabel, QVBoxLayout, QPushButton
+from PyQt5.QtWidgets import QWidget, QFileDialog, QMessageBox, QLabel, QPushButton, QSizePolicy
from qtawesome import icon
from legendary.core import LegendaryCore
@@ -54,19 +54,16 @@ class GameSettings(QWidget, Ui_GameSettings):
self.core = core
self.settings = QSettings()
- save_widget = QWidget()
- save_widget.setLayout(QVBoxLayout())
self.cloud_save_path_edit = PathEdit("", file_type=QFileDialog.DirectoryOnly,
ph_text=self.tr("Cloud save path"),
edit_func=lambda text: (os.path.exists(text), text),
save_func=self.save_save_path)
- save_widget.layout().addWidget(self.cloud_save_path_edit)
+ self.cloud_gb.layout().addRow(QLabel(self.tr("Save path")), self.cloud_save_path_edit)
self.compute_save_path_button = QPushButton(icon("fa.magic"), self.tr("Auto compute save path"))
- save_widget.layout().addWidget(self.compute_save_path_button)
+ self.compute_save_path_button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
self.compute_save_path_button.clicked.connect(self.compute_save_path)
-
- self.cloud_gb.layout().addRow(QLabel(self.tr("Save path")), save_widget)
+ self.cloud_gb.layout().addRow(None, self.compute_save_path_button)
self.offline.currentIndexChanged.connect(
lambda x: self.update_combobox(x, "offline")
@@ -102,6 +99,13 @@ class GameSettings(QWidget, Ui_GameSettings):
self.proton_prefix_layout.addWidget(self.proton_prefix)
self.linux_settings = LinuxAppSettings()
+ # FIXME: Remove the spacerItem from the linux settings
+ # FIXME: This should be handled differently at soem point in the future
+ for item in [self.linux_settings.layout().itemAt(idx) for idx in range(self.linux_settings.layout().count())]:
+ if item.spacerItem():
+ self.linux_settings.layout().removeItem(item)
+ del item
+ # FIXME: End of FIXME
self.linux_layout.addWidget(self.linux_settings)
else:
self.proton_groupbox.setVisible(False)
diff --git a/rare/components/tabs/games/import_sync/egl_sync_group.py b/rare/components/tabs/games/import_sync/egl_sync_group.py
index 7509d2ff..165f6bea 100644
--- a/rare/components/tabs/games/import_sync/egl_sync_group.py
+++ b/rare/components/tabs/games/import_sync/egl_sync_group.py
@@ -23,43 +23,33 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
self.setupUi(self)
self.egl_path_info.setProperty('infoLabel', 1)
- self.core = shared.core
- self.threadpool = QThreadPool.globalInstance()
- if not self.core.egl.programdata_path:
- if platform.system() == 'Windows':
- self.egl_path_info.setText(os.path.expandvars(PathSpec.egl_programdata))
- else:
- self.egl_path_info.setText(self.tr('Updating...'))
- wine_resolver = WineResolver(PathSpec.egl_programdata, 'default', shared.core)
- wine_resolver.signals.result_ready.connect(self.wine_resolver_cb)
- self.threadpool.start(wine_resolver)
+ self.thread_pool = QThreadPool.globalInstance()
- else:
- self.egl_path_info.setText(self.core.egl.programdata_path)
-
- egl_path = shared.core.egl.programdata_path
- if egl_path is None:
- egl_path = shared.core.lgd.config.get(
- "default",
- "wine_prefix",
- fallback=PathSpec().wine_egl_prefixes(results=1))
-
- self.egl_path_edit = PathEdit(
- path=egl_path,
- ph_text=self.tr('Path to the Wine prefix where EGL is installed, or the Manifests folder'),
- file_type=QFileDialog.DirectoryOnly,
- edit_func=self.egl_path_edit_cb,
- save_func=self.egl_path_save_cb,
- parent=self
- )
- self.egl_path_edit.textChanged.connect(self.egl_path_changed)
- self.egl_path_layout.addWidget(self.egl_path_edit)
-
- if platform.system() == "Windows":
- self.egl_path_label.setVisible(False)
+ if platform.system() == 'Windows':
+ self.egl_path_edit_label.setVisible(False)
self.egl_path_edit.setVisible(False)
self.egl_path_info_label.setVisible(False)
self.egl_path_info.setVisible(False)
+ else:
+ self.egl_path_edit = PathEdit(
+ path=shared.core.egl.programdata_path,
+ ph_text=self.tr('Path to the Wine prefix where EGL is installed, or the Manifests folder'),
+ file_type=QFileDialog.DirectoryOnly,
+ edit_func=self.egl_path_edit_edit_cb,
+ save_func=self.egl_path_edit_save_cb,
+ parent=self
+ )
+ self.egl_path_edit.textChanged.connect(self.egl_path_changed)
+ self.egl_path_edit_layout.addWidget(self.egl_path_edit)
+
+ if not shared.core.egl.programdata_path:
+ self.egl_path_info.setText(self.tr('Updating...'))
+ wine_resolver = WineResolver(PathSpec.egl_programdata, 'default', shared.core)
+ wine_resolver.signals.result_ready.connect(self.wine_resolver_cb)
+ self.thread_pool.start(wine_resolver)
+ else:
+ self.egl_path_info_label.setVisible(False)
+ self.egl_path_info.setVisible(False)
self.egl_sync_check.setChecked(shared.core.egl_sync_enabled)
self.egl_sync_check.stateChanged.connect(self.egl_sync_changed)
@@ -76,30 +66,33 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
def wine_resolver_cb(self, path):
self.egl_path_info.setText(path)
- if path:
- self.egl_path_edit.setText(path)
- else:
+ if not path:
self.egl_path_info.setText(
self.tr('Default Wine prefix is unset, or path does not exist. '
- 'Create it or configure it in Settings -> Linux'))
+ 'Create it or configure it in Settings -> Linux.'))
+ elif not os.path.exists(path):
+ self.egl_path_info.setText(
+ self.tr('Default Wine prefix is set but EGL manifests path does not exist. '
+ 'Your configured default Wine prefix might not be where EGL is installed.'))
+ else:
+ self.egl_path_edit.setText(path)
@staticmethod
- def egl_path_edit_cb(path) -> Tuple[bool, str]:
+ def egl_path_edit_edit_cb(path) -> Tuple[bool, str]:
if not path:
return True, path
- if platform.system() != "Windows":
- if os.path.exists(os.path.join(path, 'system.reg')) and os.path.exists(os.path.join(path, 'dosdevices/c:')):
- # path is a wine prefix
- path = os.path.join(path, 'dosdevices/c:', 'ProgramData/Epic/EpicGamesLauncher/Data/Manifests')
- elif not path.rstrip('/').endswith('ProgramData/Epic/EpicGamesLauncher/Data/Manifests'):
- # lower() might or might not be needed in the check
- return False, path
+ if os.path.exists(os.path.join(path, 'system.reg')) and os.path.exists(os.path.join(path, 'dosdevices/c:')):
+ # path is a wine prefix
+ path = os.path.join(path, 'dosdevices/c:', 'ProgramData/Epic/EpicGamesLauncher/Data/Manifests')
+ elif not path.rstrip('/').endswith('ProgramData/Epic/EpicGamesLauncher/Data/Manifests'):
+ # lower() might or might not be needed in the check
+ return False, path
if os.path.exists(path):
return True, path
return False, path
@staticmethod
- def egl_path_save_cb(path):
+ def egl_path_edit_save_cb(path):
if not path or not os.path.exists(path):
# This is the same as "--unlink"
shared.core.egl.programdata_path = None
@@ -127,25 +120,25 @@ class EGLSyncGroup(QGroupBox, Ui_EGLSyncGroup):
if state == Qt.Unchecked:
self.import_list.setEnabled(bool(self.import_list.items))
self.export_list.setEnabled(bool(self.export_list.items))
- self.core.lgd.config.remove_option('Legendary', 'egl_sync')
+ shared.core.lgd.config.remove_option('Legendary', 'egl_sync')
else:
- self.core.lgd.config.set('Legendary', 'egl_sync', str(True))
+ shared.core.lgd.config.set('Legendary', 'egl_sync', str(True))
# lk: do import/export here since automatic sync was selected
self.import_list.mark(Qt.Checked)
self.export_list.mark(Qt.Checked)
sync_worker = EGLSyncWorker(self.import_list, self.export_list)
- self.threadpool.start(sync_worker)
+ self.thread_pool.start(sync_worker)
self.import_list.setEnabled(False)
self.export_list.setEnabled(False)
# self.update_lists()
- self.core.lgd.save_config()
+ shared.core.lgd.save_config()
def update_lists(self):
# self.egl_watcher.blockSignals(True)
if have_path := bool(shared.core.egl.programdata_path) and self.egl_path_edit.is_valid:
# NOTE: need to clear known manifests to force refresh
shared.core.egl.manifests.clear()
- self.egl_sync_label.setEnabled(have_path)
+ self.egl_sync_check_label.setEnabled(have_path)
self.egl_sync_check.setEnabled(have_path)
self.import_list.populate(have_path)
self.import_list.setEnabled(have_path)
diff --git a/rare/components/tabs/settings/rare.py b/rare/components/tabs/settings/rare.py
index b601a3de..7720c58f 100644
--- a/rare/components/tabs/settings/rare.py
+++ b/rare/components/tabs/settings/rare.py
@@ -11,7 +11,7 @@ from rare import cache_dir, shared
from rare.components.tabs.settings.rpc import RPCSettings
from rare.ui.components.tabs.settings.rare import Ui_RareSettings
from rare.utils import utils
-from rare.utils.utils import get_translations, get_color_schemes, get_style_sheets
+from rare.utils.utils import get_translations, get_color_schemes, set_color_pallete, get_style_sheets, set_style_sheet
logger = getLogger("RareSettings")
@@ -163,9 +163,11 @@ class RareSettings(QWidget, Ui_RareSettings):
self.style_select.setCurrentIndex(0)
self.style_select.setDisabled(True)
self.settings.setValue("color_scheme", self.color_select.currentText())
+ set_color_pallete(self.color_select.currentText())
else:
self.settings.setValue("color_scheme", "")
self.style_select.setDisabled(False)
+ set_color_pallete("")
self.interface_info.setVisible(True)
def on_style_select_changed(self, style):
@@ -173,9 +175,11 @@ class RareSettings(QWidget, Ui_RareSettings):
self.color_select.setCurrentIndex(0)
self.color_select.setDisabled(True)
self.settings.setValue("style_sheet", self.style_select.currentText())
+ set_style_sheet(self.style_select.currentText())
else:
self.settings.setValue("style_sheet", "")
self.color_select.setDisabled(False)
+ set_style_sheet("")
self.interface_info.setVisible(True)
def open_dir(self):
diff --git a/rare/components/tabs/tab_utils.py b/rare/components/tabs/tab_utils.py
index e1597467..64b70e72 100644
--- a/rare/components/tabs/tab_utils.py
+++ b/rare/components/tabs/tab_utils.py
@@ -4,20 +4,20 @@ from PyQt5.QtWidgets import QTabBar, QToolButton
from qtawesome import icon
-class TabBar(QTabBar):
+class MainTabBar(QTabBar):
def __init__(self, expanded):
- super(TabBar, self).__init__()
+ super(MainTabBar, self).__init__()
self._expanded = expanded
- self.setObjectName("main_tab_bar")
+ self.setObjectName("MainTabBar")
self.setFont(QFont("Arial", 13))
# self.setContentsMargins(0,10,0,10)
def tabSizeHint(self, index):
- size = super(TabBar, self).tabSizeHint(index)
+ size = super(MainTabBar, self).tabSizeHint(index)
if index == self._expanded:
offset = self.width()
for index in range(self.count()):
- offset -= super(TabBar, self).tabSizeHint(index).width()
+ offset -= super(MainTabBar, self).tabSizeHint(index).width()
size.setWidth(max(size.width(), size.width() + offset))
return size
diff --git a/rare/resources/stylesheets/RareStyle/stylesheet.qss b/rare/resources/stylesheets/RareStyle/stylesheet.qss
index 07dbb465..02ff1230 100644
--- a/rare/resources/stylesheets/RareStyle/stylesheet.qss
+++ b/rare/resources/stylesheets/RareStyle/stylesheet.qss
@@ -81,16 +81,18 @@ QSpinBox,
QDoubleSpinBox,
QProgressBar,
QPushButton {
- height: 3ex;
+ height: 1.30em;
}
QToolButton {
- height: 2.5ex;
+ height: 1.10em;
}
QFrame[frameShape="6"] {
border-radius: 4px;
}
+QFrame[noBorder="1"],
QListView[noBorder="1"],
-QScrollArea[noBorder="1"] {
+QScrollArea[noBorder="1"],
+QStackedWidget[noBorder="1"] {
border-color: transparent;
}
QComboBox {
@@ -138,7 +140,7 @@ QComboBox QAbstractItemView {
*::drop-down,
*::drop-down:editable {
width: 14px;
- image: url(@path@drop-down.svg);
+ image: url("@path@drop-down.svg");
}
*::up-button,
*::down-button {
@@ -147,12 +149,12 @@ QComboBox QAbstractItemView {
*::up-button {
subcontrol-position: top right; /* position at the top right corner */
border-bottom-width: 1;
- image: url(@path@sort-up.svg);
+ image: url("@path@sort-up.svg");
}
*::down-button {
subcontrol-position: bottom right; /* position at bottom right corner */
border-top-width: 1;
- image: url(@path@sort-down.svg);
+ image: url("@path@sort-down.svg");
}
QProgressBar {
text-align: center;
@@ -234,7 +236,8 @@ QListView::item,
QTreeView::item {
margin-right: 1px;
}
-/* The first element is attaching to the QHeaderView
+/* The first element is attaching to the QHeaderView */
+/*
QTableView[currentColumn="0"]::item {
margin-left: 1px;
}
@@ -294,7 +297,7 @@ QPushButton#menu_button {
width: 18px;
height: 18px;
}
-QPushButton:hover#menu_button {
+QPushButton#menu_button:hover {
background-color: "#334";
}
QPushButton[install="1"],
@@ -302,11 +305,11 @@ QPushButton#install_button {
background-color: "#090";
}
QPushButton[install="1"]:hover,
-QPushButton:hover#install_button {
+QPushButton#install_button:hover {
background-color: "#060";
}
QPushButton[install="1"]:disabled,
-QPushButton:disabled#install_button {
+QPushButton#install_button:disabled {
background-color: "#020";
}
QPushButton[uninstall="1"],
@@ -314,17 +317,17 @@ QPushButton#uninstall_button {
background-color: "#900";
}
QPushButton[uninstall="1"]:hover,
-QPushButton:hover#uninstall_button {
+QPushButton#uninstall_button:hover {
background-color: "#600";
}
QPushButton[uninstall="1"]:disabled,
-QPushButton:disabled#uninstall_button {
+QPushButton#uninstall_button:disabled {
background-color: "#200";
}
QPushButton#success{
background-color: "lime";
}
-QPushButton:hover#installed_menu_button {
+QPushButton#installed_menu_button:hover {
background-color: green;
}
@@ -376,7 +379,7 @@ QListView::indicator:checked,
QTreeView::indicator:checked,
QTableView::indicator:checked {
border-radius: 2px;
- image: url(@path@square.svg);
+ image: url("@path@square.svg");
}
QGroupBox::indicator:indeterminate,
QCheckBox::indicator:indeterminate,
@@ -384,40 +387,40 @@ QListView::indicator:indeterminate,
QTreeView::indicator:indeterminate,
QTableView::indicator:indeterminate {
border-radius: 2px;
- image: url(@path@half-square.svg);
+ image: url("@path@half-square.svg");
}
QRadioButton::indicator:checked {
border-radius: 5%;
- image: url(@path@circle.svg);
+ image: url("@path@circle.svg");
}
QGroupBox::indicator:checked:disabled,
QCheckBox::indicator:checked:disabled,
QListView::indicator:checked:disabled,
QTreeView::indicator:checked:disabled,
QTableView::indicator:checked:disabled {
- image: url(@path@square-disabled.svg);
+ image: url("@path@square-disabled.svg");
}
QGroupBox::indicator:indeterminate:disabled,
QCheckBox::indicator:indeterminate:disabled,
QListView::indicator:indeterminate:disabled,
QTreeView::indicator:indeterminate:disabled,
QTableView::indicator:indeterminate:disabled {
- image: url(@path@half-square-disabled.svg);
+ image: url("@path@half-square-disabled.svg");
}
QRadioButton::indicator:checked:disabled {
- image: url(@path@circle-disabled.svg);
+ image: url("@path@circle-disabled.svg");
}
QGroupBox,
QGroupBox#group,
QGroupBox#settings_widget {
font-weight: bold;
- margin-top: 1ex;
+ margin-top: 0.5em;
/* margin-left: 0.5em; /* Offset to the left */
border-width: 1px;
border-style: solid;
border-radius: 4px;
- padding-top: 3ex;
+ padding-top: 1.2em;
}
QGroupBox#game_widget_icon {
margin: 2px;
@@ -466,7 +469,7 @@ QTabBar {
qproperty-drawBase: 0;
}
QTabBar::tab {
- margin: 3px;
+ margin: 0px;
border-width: 1px;
border-style: solid;
border-color: transparent;
@@ -477,75 +480,189 @@ QTabBar::tab:bottom {
padding-left: 12px;
padding-right: 12px;
}
+QTabBar::tab:top:hover,
+QTabBar::tab:bottom:hover {
+ border-color: #483d8b;
+ border-left-color: transparent;
+ border-right-color: transparent;
+}
QTabBar::tab:top {
border-top-width: 3px;
border-top-color: #3c3f41;
+ border-bottom-color: #483d8b;
+ background: qlineargradient(
+ x1: 0, y1: -1, x2: 0, y2: 1, stop: 0 #3c3f41, stop: 1 #202225);
}
QTabBar::tab:bottom {
border-bottom-width: 3px;
+ border-top-color: #483d8b;
+ border-bottom-color: #3c3f41;
+ background: qlineargradient(
+ x1: 0, y1: 2, x2: 0, y2: 0, stop: 0 #3c3f41, stop: 1 #202225);
+}
+QTabBar::tab:top:hover {
+ background: qlineargradient(
+ x1: 0, y1: -1, x2: 0, y2: 1, stop: 0 #483d8b, stop: 1 #202225);
+}
+QTabBar::tab:bottom:hover {
+ background: qlineargradient(
+ x1: 0, y1: 2, x2: 0, y2: 0, stop: 0 #483d8b, stop: 1 #202225);
+}
+QTabBar::tab:top:selected {
+ border-color: #483d8b;
+ border-bottom-color: transparent;
+ background: #202225;
+}
+QTabBar::tab:bottom:selected {
+ border-color: #483d8b;
+ border-top-color: transparent;
+ background: #202225;
+}
+QTabBar::tab:top:disabled {
border-bottom-color: #3c3f41;
}
-QTabBar::tab:hover:top,
-QTabBar::tab:hover:bottom {
- border-color: #483d8b;
+QTabBar::tab:bottom:disabled {
+ border-top-color: #3c3f41;
}
-QTabBar::tab:hover:top,
-QTabBar::tab:selected:top {
- border-top-color: #483d8b;
- background: qlineargradient(x1: 0, y1: -1, x2: 0, y2: 1,
- stop: 0 #483d8b, stop: 1 #202225); /* stop: 0 #28224D */
+QTabBar::tab:top:selected:disabled {
+ border-color: #3c3f41;
+ border-bottom-color: transparent;
}
-QTabBar::tab:hover:bottom,
-QTabBar::tab:selected:bottom {
- border-bottom-color: #483d8b;
- background: qlineargradient(x1: 0, y1: 2, x2: 0, y2: 0,
- stop: 0 #483d8b, stop: 1 #202225); /* stop: 0 #28224D */
-}
-QTabBar::tab:top#main_tab_bar {
- border-color: transparent;
- padding: 5px;
-}
-QTabBar::tab:hover:top#main_tab_bar {
- border-color: #483d8b;
-}
-QTabBar::tab:selected:top#main_tab_bar {
- border-top-color: #483d8b;
+QTabBar::tab:bottom:selected:disabled {
+ border-color: #3c3f41;
+ border-top-color: transparent;
}
QTabBar::tab:left,
QTabBar::tab:right {
padding-top: 2px;
padding-bottom: 2px;
}
+QTabBar::tab:left:hover,
+QTabBar::tab:right:hover {
+ border-color: #483d8b;
+ border-top-color: transparent;
+ border-bottom-color: transparent;
+}
QTabBar::tab:left {
border-left-width: 3px;
border-left-color: #3c3f41;
+ border-right-color: #483d8b;
+ background: qlineargradient(
+ x1: -1, y1: 0, x2: 1, y2: 0, stop: 0 #3c3f41, stop: 1 #202225);
}
QTabBar::tab:right {
border-right-width: 3px;
border-right-color: #3c3f41;
+ border-left-color: #483d8b;
+ background: qlineargradient(
+ x1: 2, y1: 0, x2: 0, y2: 0, stop: 0 #3c3f41, stop: 1 #202225);
}
-QTabBar::tab:hover:left,
-QTabBar::tab:hover:right {
- border-color: #483d8b; /* #2f4f4f */
+QTabBar::tab:left:hover {
+ background: qlineargradient(
+ x1: -1, y1: 0, x2: 1, y2: 0, stop: 0 #483d8b, stop: 1 #202225);
}
-QTabBar::tab:hover:left,
-QTabBar::tab:selected:left {
- border-left-color: #483d8b; /* #2f4f4f */
- background: qlineargradient(x1: -1, y1: 0, x2: 1, y2: 0,
- stop: 0 #483d8b, stop: 1 #202225); /* stop: 0 #2f4f4f stop: 0.2 #203636 */
+QTabBar::tab:right:hover {
+ background: qlineargradient(
+ x1: 2, y1: 0, x2: 0, y2: 0, stop: 0 #483d8b, stop: 1 #202225);
}
-QTabBar::tab:hover:right,
-QTabBar::tab:selected:right {
- border-right-color: #483d8b; /* #2f4f4f */
- background: qlineargradient(x1: 2, y1: 0, x2: 0, y2: 0,
- stop: 0 #483d8b, stop: 1 #202225); /* stop: 0 #2f4f4f stop: 0.2 #203636 */
+QTabBar::tab:left:selected {
+ border-color: #483d8b;
+ border-right-color: transparent;
+ background: #202225;
}
-QTabBar::tab:disabled#SideTabBar {
+QTabBar::tab:right:selected {
+ border-color: #483d8b;
+ border-left-color: transparent;
+ background: #202225;
+}
+QTabBar::tab:left:disabled {
+ border-right-color: #3c3f41;
+}
+QTabBar::tab:right:disabled {
+ border-left-color: #3c3f41;
+}
+QTabBar::tab:left:selected:disabled {
+ border-color: #3c3f41;
+ border-right-color: transparent;
+}
+QTabBar::tab:right:selected:disabled {
+ border-color: #3c3f41;
+ border-left-color: transparent;
+}
+
+QTabBar#MainTabBar {
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent;
+ border-bottom-color: #483d8b;
+ /*
+ background: qlineargradient(
+ x1: 0, y1: -3, x2: 0, y2: 1, stop: 0 #3c3f41, stop: 1 #202225);
+ */
+}
+QTabBar#MainTabBar:disabled {
+ border-color: transparent;
+ border-bottom-color: #3c3f41;
+}
+QTabBar#MainTabBar::tab {
+ margin-left: 3px;
+ margin-right: 3px;
+ border-top-color: transparent;
+ border-bottom-color: #483d8b;
+ padding: 5px;
+}/*
+QTabBar#MainTabBar::tab:top:first,
+QTabBar#MainTabBar::tab:bottom:first {
+ margin-left: 0px;
+ border-left: transparent;
+}
+QTabBar#MainTabBar::tab:top:last,
+QTabBar#MainTabBar::tab:bottom:last {
+ margin-right: 0px;
+ border-right: transparent;
+}*/
+QTabBar#MainTabBar::tab:top:hover {
+ border-top-color: #483d8b;
+}
+QTabBar#MainTabBar::tab:top:selected {
+ border-color: #483d8b;
+ border-bottom-color: #202225;
+}
+QTabBar#SideTabBar {
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent;
+ border-right-color: #483d8b;
+ /*
+ background: qlineargradient(
+ x1: -3, y1: 0, x2: 1, y2: 0, stop: 0 #3c3f41, stop: 1 #202225);
+ */
+}
+QTabBar#SideTabBar:disabled {
+ border-color: transparent;
+ border-right-color: #3c3f41;
+}
+QTabBar#SideTabBar::tab {
+ margin-top: 3px;
+ margin-bottom: 3px;
+}/*
+QTabBar#SideTabBar::tab:left:first,
+QTabBar#SideTabBar::tab:right:first {
+ margin-top: 0px;
+ border-top: transparent;
+}
+QTabBar#SideTabBar::tab:left:last,
+QTabBar#SideTabBar::tab:right:last {
+ margin-bottom: 0px;
+ border-bottom: transparent;
+}*/
+QTabBar#SideTabBar::tab:disabled {
color: transparent;
border-color: transparent;
background-color: transparent;
}
+
QToolTip {
border-width: 1px;
border-style: solid;
diff --git a/rare/ui/components/tabs/games/game_info/game_settings.py b/rare/ui/components/tabs/games/game_info/game_settings.py
index ecd7d813..438fb1a5 100644
--- a/rare/ui/components/tabs/games/game_info/game_settings.py
+++ b/rare/ui/components/tabs/games/game_info/game_settings.py
@@ -2,13 +2,13 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/games/game_info/game_settings.ui'
#
-# Created by: PyQt5 UI code generator 5.15.5
+# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
-from PyQt5 import QtCore, QtWidgets
+from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_GameSettings(object):
@@ -88,6 +88,19 @@ class Ui_GameSettings(object):
self.wrapper_layout.addWidget(self.wrapper_button)
self.launch_settings_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.wrapper_widget)
self.game_settings_layout.addWidget(self.launch_settings_groupbox, 0, QtCore.Qt.AlignTop)
+ self.cloud_gb = QtWidgets.QGroupBox(GameSettings)
+ self.cloud_gb.setObjectName("cloud_gb")
+ self.cloud_saves_layout = QtWidgets.QFormLayout(self.cloud_gb)
+ self.cloud_saves_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
+ self.cloud_saves_layout.setObjectName("cloud_saves_layout")
+ self.cloud_sync_label = QtWidgets.QLabel(self.cloud_gb)
+ self.cloud_sync_label.setObjectName("cloud_sync_label")
+ self.cloud_saves_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.cloud_sync_label)
+ self.cloud_sync = QtWidgets.QCheckBox(self.cloud_gb)
+ self.cloud_sync.setText("")
+ self.cloud_sync.setObjectName("cloud_sync")
+ self.cloud_saves_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.cloud_sync)
+ self.game_settings_layout.addWidget(self.cloud_gb)
self.proton_groupbox = QtWidgets.QGroupBox(GameSettings)
self.proton_groupbox.setObjectName("proton_groupbox")
self.proton_layout = QtWidgets.QFormLayout(self.proton_groupbox)
@@ -116,18 +129,6 @@ class Ui_GameSettings(object):
self.linux_layout.setObjectName("linux_layout")
self.proton_layout.setLayout(3, QtWidgets.QFormLayout.SpanningRole, self.linux_layout)
self.game_settings_layout.addWidget(self.proton_groupbox, 0, QtCore.Qt.AlignTop)
- self.cloud_gb = QtWidgets.QGroupBox(GameSettings)
- self.cloud_gb.setObjectName("cloud_gb")
- self.formLayout = QtWidgets.QFormLayout(self.cloud_gb)
- self.formLayout.setObjectName("formLayout")
- self.cloud_sync_label = QtWidgets.QLabel(self.cloud_gb)
- self.cloud_sync_label.setObjectName("cloud_sync_label")
- self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.cloud_sync_label)
- self.cloud_sync = QtWidgets.QCheckBox(self.cloud_gb)
- self.cloud_sync.setText("")
- self.cloud_sync.setObjectName("cloud_sync")
- self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.cloud_sync)
- self.game_settings_layout.addWidget(self.cloud_gb)
spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.game_settings_layout.addItem(spacerItem)
@@ -152,12 +153,12 @@ class Ui_GameSettings(object):
self.wrapper_label.setText(_translate("GameSettings", "Wrapper"))
self.wrapper.setPlaceholderText(_translate("GameSettings", "e.g. optirun"))
self.wrapper_button.setText(_translate("GameSettings", "Save"))
+ self.cloud_gb.setTitle(_translate("GameSettings", "Cloud Saves"))
+ self.cloud_sync_label.setText(_translate("GameSettings", "Sync with cloud"))
self.proton_groupbox.setTitle(_translate("GameSettings", "Linux Settings"))
self.proton_wrapper_label.setText(_translate("GameSettings", "Proton"))
self.proton_wrapper.setItemText(0, _translate("GameSettings", "Don\'t use Proton"))
self.proton_prefix_label.setText(_translate("GameSettings", "Prefix"))
- self.cloud_gb.setTitle(_translate("GameSettings", "Cloud Saves"))
- self.cloud_sync_label.setText(_translate("GameSettings", "Sync with cloud"))
if __name__ == "__main__":
diff --git a/rare/ui/components/tabs/games/game_info/game_settings.ui b/rare/ui/components/tabs/games/game_info/game_settings.ui
index 9962928d..41374075 100644
--- a/rare/ui/components/tabs/games/game_info/game_settings.ui
+++ b/rare/ui/components/tabs/games/game_info/game_settings.ui
@@ -105,16 +105,16 @@
-
-
-
-
- 0
-
-
- 0
-
-
- 0
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
0
@@ -142,24 +142,24 @@
- -
-
-
- Wrapper
-
-
-
- -
-
-
-
- 0
-
-
- 0
-
-
- 0
+
-
+
+
+ Wrapper
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
0
@@ -190,6 +190,32 @@
+ -
+
+
+ Cloud Saves
+
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
-
+
+
+ Sync with cloud
+
+
+
+ -
+
+
+
+
+
+
+
+
+
-
@@ -232,51 +258,28 @@
-
-
-
- 0
-
-
+
+
+ 0
+
+
- -
-
-
- Cloud Saves
-
-
-
-
-
-
- Sync with cloud
-
-
-
- -
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
diff --git a/rare/ui/components/tabs/games/import_sync/egl_sync_group.py b/rare/ui/components/tabs/games/import_sync/egl_sync_group.py
index 44da393d..c5f11ed1 100644
--- a/rare/ui/components/tabs/games/import_sync/egl_sync_group.py
+++ b/rare/ui/components/tabs/games/import_sync/egl_sync_group.py
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/games/import_sync/egl_sync_group.ui'
#
-# Created by: PyQt5 UI code generator 5.15.4
+# Created by: PyQt5 UI code generator 5.15.6
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -21,12 +21,12 @@ class Ui_EGLSyncGroup(object):
self.egl_sync_layout = QtWidgets.QFormLayout(EGLSyncGroup)
self.egl_sync_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.egl_sync_layout.setObjectName("egl_sync_layout")
- self.egl_path_label = QtWidgets.QLabel(EGLSyncGroup)
- self.egl_path_label.setObjectName("egl_path_label")
- self.egl_sync_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.egl_path_label)
- self.egl_path_layout = QtWidgets.QHBoxLayout()
- self.egl_path_layout.setObjectName("egl_path_layout")
- self.egl_sync_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.egl_path_layout)
+ self.egl_path_edit_label = QtWidgets.QLabel(EGLSyncGroup)
+ self.egl_path_edit_label.setObjectName("egl_path_edit_label")
+ self.egl_sync_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.egl_path_edit_label)
+ self.egl_path_edit_layout = QtWidgets.QHBoxLayout()
+ self.egl_path_edit_layout.setObjectName("egl_path_edit_layout")
+ self.egl_sync_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.egl_path_edit_layout)
self.egl_path_info_label = QtWidgets.QLabel(EGLSyncGroup)
self.egl_path_info_label.setObjectName("egl_path_info_label")
self.egl_sync_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.egl_path_info_label)
@@ -42,9 +42,9 @@ class Ui_EGLSyncGroup(object):
self.import_export_layout = QtWidgets.QVBoxLayout()
self.import_export_layout.setObjectName("import_export_layout")
self.egl_sync_layout.setLayout(3, QtWidgets.QFormLayout.SpanningRole, self.import_export_layout)
- self.egl_sync_label = QtWidgets.QLabel(EGLSyncGroup)
- self.egl_sync_label.setObjectName("egl_sync_label")
- self.egl_sync_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.egl_sync_label)
+ self.egl_sync_check_label = QtWidgets.QLabel(EGLSyncGroup)
+ self.egl_sync_check_label.setObjectName("egl_sync_check_label")
+ self.egl_sync_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.egl_sync_check_label)
self.retranslateUi(EGLSyncGroup)
QtCore.QMetaObject.connectSlotsByName(EGLSyncGroup)
@@ -52,9 +52,9 @@ class Ui_EGLSyncGroup(object):
def retranslateUi(self, EGLSyncGroup):
_translate = QtCore.QCoreApplication.translate
EGLSyncGroup.setTitle(_translate("EGLSyncGroup", "Sync with Epic Games Launcher"))
- self.egl_path_label.setText(_translate("EGLSyncGroup", "Prefix/Manifest path"))
+ self.egl_path_edit_label.setText(_translate("EGLSyncGroup", "Prefix/Manifest path"))
self.egl_path_info_label.setText(_translate("EGLSyncGroup", "Estimated path"))
- self.egl_sync_label.setText(_translate("EGLSyncGroup", "Enable automatic sync"))
+ self.egl_sync_check_label.setText(_translate("EGLSyncGroup", "Enable automatic sync"))
if __name__ == "__main__":
diff --git a/rare/ui/components/tabs/games/import_sync/egl_sync_group.ui b/rare/ui/components/tabs/games/import_sync/egl_sync_group.ui
index f62c5c91..fb23434c 100644
--- a/rare/ui/components/tabs/games/import_sync/egl_sync_group.ui
+++ b/rare/ui/components/tabs/games/import_sync/egl_sync_group.ui
@@ -27,14 +27,14 @@
Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
+
Prefix/Manifest path
-
-
+
-
@@ -64,7 +64,7 @@
-
-
+
Enable automatic sync
diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py
index 710e6936..2b5a362b 100644
--- a/rare/utils/extra_widgets.py
+++ b/rare/utils/extra_widgets.py
@@ -338,6 +338,7 @@ class SideTabWidget(QTabWidget):
def __init__(self, show_back: bool = False, parent=None):
super(SideTabWidget, self).__init__(parent=parent)
self.setTabBar(SideTabBar())
+ self.setDocumentMode(True)
self.setTabPosition(QTabWidget.West)
if show_back:
self.addTab(QWidget(), qta_icon("mdi.keyboard-backspace"), self.tr("Back"))
diff --git a/rare/utils/utils.py b/rare/utils/utils.py
index e4416452..fe01b82d 100644
--- a/rare/utils/utils.py
+++ b/rare/utils/utils.py
@@ -6,10 +6,12 @@ import shutil
import subprocess
import sys
from logging import getLogger
-from typing import Tuple
+from typing import Tuple, List
import requests
+import qtawesome
from PyQt5.QtCore import pyqtSignal, pyqtSlot, QObject, QRunnable, QSettings, Qt
+from PyQt5.QtWidgets import QApplication, QStyleFactory, QStyle
from PyQt5.QtGui import QPalette, QColor, QPixmap, QImage
from requests import HTTPError
@@ -116,7 +118,7 @@ color_group_map = {
}
-def load_color_scheme(path: str):
+def load_color_scheme(path: str) -> QPalette:
palette = QPalette()
scheme = QSettings(path, QSettings.IniFormat)
try:
@@ -138,7 +140,20 @@ def load_color_scheme(path: str):
return palette
-def get_color_schemes():
+def set_color_pallete(color_scheme: str):
+ if not color_scheme:
+ QApplication.instance().setStyle(QStyleFactory.create(QApplication.instance().property('rareDefaultQtStyle')))
+ QApplication.instance().setStyleSheet("")
+ QApplication.instance().setPalette(QApplication.instance().style().standardPalette())
+ return
+ QApplication.instance().setStyle(QStyleFactory.create("Fusion"))
+ custom_palette = load_color_scheme(os.path.join(resources_path, "colors", color_scheme + ".scheme"))
+ if custom_palette is not None:
+ QApplication.instance().setPalette(custom_palette)
+ qtawesome.set_defaults(color=custom_palette.color(QPalette.Text))
+
+
+def get_color_schemes() -> List[str]:
colors = []
for file in os.listdir(os.path.join(resources_path, "colors")):
if file.endswith(".scheme") and os.path.isfile(os.path.join(resources_path, "colors", file)):
@@ -146,7 +161,21 @@ def get_color_schemes():
return colors
-def get_style_sheets():
+def set_style_sheet(style_sheet: str):
+ if not style_sheet:
+ QApplication.instance().setStyle(QStyleFactory.create(QApplication.instance().property('rareDefaultQtStyle')))
+ QApplication.instance().setStyleSheet("")
+ return
+ QApplication.instance().setStyle(QStyleFactory.create("Fusion"))
+ stylesheet = open(os.path.join(resources_path, "stylesheets", style_sheet, "stylesheet.qss")).read()
+ style_resource_path = os.path.join(resources_path, "stylesheets", style_sheet, "")
+ if platform.system() == "Windows":
+ style_resource_path = style_resource_path.replace('\\', '/')
+ QApplication.instance().setStyleSheet(stylesheet.replace("@path@", style_resource_path))
+ qtawesome.set_defaults(color="white")
+
+
+def get_style_sheets() -> List[str]:
styles = []
for folder in os.listdir(os.path.join(resources_path, "stylesheets")):
if os.path.isfile(os.path.join(resources_path, "stylesheets", folder, "stylesheet.qss")):
@@ -398,6 +427,10 @@ class WineResolver(QRunnable):
# pylint: disable=E1136
self.signals.result_ready[str].emit(str())
return
+ if not os.path.exists(self.wine_binary) or not os.path.exists(self.winepath_binary):
+ # pylint: disable=E1136
+ self.signals.result_ready[str].emit(str())
+ return
path = self.path.strip().replace('/', '\\')
# lk: if path does not exist form
cmd = [self.wine_binary, 'cmd', '/c', 'echo', path]