1
0
Fork 0
mirror of synced 2024-06-29 03:31:06 +12:00

Merge pull request #127 from loathingKernel/main

Pre-release bug fixes
This commit is contained in:
Dummerle 2021-11-21 21:49:30 +01:00 committed by GitHub
commit 8686afcc68
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 424 additions and 259 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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__":

View file

@ -105,16 +105,16 @@
</widget>
</item>
<item row="2" column="1">
<widget class="QWidget" name="launch_params_widget" native="true">
<layout class="QHBoxLayout" name="launch_params_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
<widget class="QWidget" name="launch_params_widget" native="true">
<layout class="QHBoxLayout" name="launch_params_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
@ -142,24 +142,24 @@
</layout>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="wrapper_label">
<property name="text">
<string>Wrapper</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QWidget" name="wrapper_widget" native="true">
<layout class="QHBoxLayout" name="wrapper_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
<item row="3" column="0">
<widget class="QLabel" name="wrapper_label">
<property name="text">
<string>Wrapper</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QWidget" name="wrapper_widget" native="true">
<layout class="QHBoxLayout" name="wrapper_layout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
@ -190,6 +190,32 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="cloud_gb">
<property name="title">
<string>Cloud Saves</string>
</property>
<layout class="QFormLayout" name="cloud_saves_layout">
<property name="labelAlignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="cloud_sync_label">
<property name="text">
<string>Sync with cloud</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="cloud_sync">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item alignment="Qt::AlignTop">
<widget class="QGroupBox" name="proton_groupbox">
<property name="title">
@ -232,51 +258,28 @@
<layout class="QVBoxLayout" name="proton_prefix_layout"/>
</item>
<item row="3" column="0" colspan="2">
<layout class="QVBoxLayout" name="linux_layout">
<property name="spacing">
<number>0</number>
</property>
</layout>
<layout class="QVBoxLayout" name="linux_layout">
<property name="spacing">
<number>0</number>
</property>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="cloud_gb">
<property name="title">
<string>Cloud Saves</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="cloud_sync_label">
<property name="text">
<string>Sync with cloud</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="cloud_sync">
<property name="text">
<string notr="true"/>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="game_settings_vspacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="game_settings_vspacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<resources/>

View file

@ -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__":

View file

@ -27,14 +27,14 @@
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<item row="0" column="0">
<widget class="QLabel" name="egl_path_label">
<widget class="QLabel" name="egl_path_edit_label">
<property name="text">
<string>Prefix/Manifest path</string>
</property>
</widget>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="egl_path_layout"/>
<layout class="QHBoxLayout" name="egl_path_edit_layout"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="egl_path_info_label">
@ -64,7 +64,7 @@
<layout class="QVBoxLayout" name="import_export_layout"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="egl_sync_label">
<widget class="QLabel" name="egl_sync_check_label">
<property name="text">
<string>Enable automatic sync</string>
</property>

View file

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

View file

@ -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]