diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..a04c5174 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,11 @@ +[tool.black] +line-length = 110 +target-version = ['py39', 'py310'] +include = '\.py$' +force-exclude = ''' +/( + | rare/ui + | rare/legendary + | rare/resources +)/ +''' diff --git a/rare/app.py b/rare/app.py index a8db08dd..d78fd3b5 100644 --- a/rare/app.py +++ b/rare/app.py @@ -68,7 +68,7 @@ class App(QApplication): # init Legendary try: - self.core = LegendaryCoreSingleton() + self.core = LegendaryCoreSingleton(init=True) except configparser.MissingSectionHeaderError as e: logger.warning(f"Config is corrupt: {e}") if config_path := os.environ.get("XDG_CONFIG_HOME"): @@ -77,7 +77,7 @@ class App(QApplication): path = os.path.expanduser("~/.config/legendary") with open(os.path.join(path, "config.ini"), "w") as config_file: config_file.write("[Legendary]") - self.core = LegendaryCoreSingleton() + self.core = LegendaryCoreSingleton(init=True) if "Legendary" not in self.core.lgd.config.sections(): self.core.lgd.config.add_section("Legendary") self.core.lgd.save_config() @@ -101,7 +101,7 @@ class App(QApplication): self.setOrganizationName("Rare") self.settings = QSettings() - self.signals = GlobalSignalsSingleton() + self.signals = GlobalSignalsSingleton(init=True) self.signals.exit_app.connect(self.exit_app) self.signals.send_notification.connect( diff --git a/rare/components/dialogs/install_dialog.py b/rare/components/dialogs/install_dialog.py index ca3496bd..fb99f448 100644 --- a/rare/components/dialogs/install_dialog.py +++ b/rare/components/dialogs/install_dialog.py @@ -141,11 +141,9 @@ class InstallDialog(QDialog, Ui_InstallDialog): if self.dl_item.options.overlay: self.platform_label.setVisible(False) self.platform_combo_box.setVisible(False) - self.ignore_space_info_label.setVisible(False) self.ignore_space_check.setVisible(False) self.ignore_space_label.setVisible(False) self.download_only_check.setVisible(False) - self.download_only_info_label.setVisible(False) self.download_only_label.setVisible(False) self.shortcut_cb.setVisible(False) self.shortcut_lbl.setVisible(False) @@ -306,16 +304,16 @@ class InstallDialog(QDialog, Ui_InstallDialog): self.cancel_clicked() -class InstallInfoSignals(QObject): - result = pyqtSignal(InstallDownloadModel) - failed = pyqtSignal(str) - finished = pyqtSignal() - - class InstallInfoWorker(QRunnable): + + class Signals(QObject): + result = pyqtSignal(InstallDownloadModel) + failed = pyqtSignal(str) + finished = pyqtSignal() + def __init__(self, core: LegendaryCore, dl_item: InstallQueueItemModel, game: Game = None): super(InstallInfoWorker, self).__init__() - self.signals = InstallInfoSignals() + self.signals = InstallInfoWorker.Signals() self.core = core self.dl_item = dl_item self.is_overlay_install = self.dl_item.options.overlay diff --git a/rare/components/dialogs/launch_dialog.py b/rare/components/dialogs/launch_dialog.py index 4a903dfe..b79acdc1 100644 --- a/rare/components/dialogs/launch_dialog.py +++ b/rare/components/dialogs/launch_dialog.py @@ -23,11 +23,11 @@ class LaunchDialogSignals(QObject): class ImageWorker(QRunnable): - def __init__(self, core: LegendaryCore): + def __init__(self): super(ImageWorker, self).__init__() self.signals = LaunchDialogSignals() self.setAutoDelete(True) - self.core = core + self.core = LegendaryCoreSingleton() def run(self): download_images(self.signals.image_progress, self.signals.result, self.core) @@ -45,16 +45,16 @@ class ApiRequestWorker(QRunnable): def run(self) -> None: if self.settings.value("mac_meta", platform.system() == "Darwin", bool): try: - result = self.core.get_game_and_dlc_list(True, "Mac") + result = self.core.get_game_and_dlc_list(update_assets=True, platform="Mac") except HTTPError: result = [], {} - self.signals.result.emit(result, "mac") else: - self.signals.result.emit(([], {}), "mac") + result = [], {} + self.signals.result.emit(result, "mac") if self.settings.value("win32_meta", False, bool): try: - result = self.core.get_game_and_dlc_list(True, "Win32") + result = self.core.get_game_and_dlc_list(update_assets=True, platform="Win32") except HTTPError: result = [], {} else: @@ -65,7 +65,7 @@ class ApiRequestWorker(QRunnable): class LaunchDialog(QDialog, Ui_LaunchDialog): quit_app = pyqtSignal(int) start_app = pyqtSignal() - finished = 0 + completed = 0 def __init__(self, parent=None): super(LaunchDialog, self).__init__(parent=parent) @@ -76,8 +76,7 @@ class LaunchDialog(QDialog, Ui_LaunchDialog): self.core = LegendaryCoreSingleton() self.args = ArgumentsSingleton() - self.thread_pool = QThreadPool() - self.thread_pool.setMaxThreadCount(2) + self.thread_pool = QThreadPool().globalInstance() self.api_results = ApiResults() def login(self): @@ -113,15 +112,15 @@ class LaunchDialog(QDialog, Ui_LaunchDialog): if not self.args.offline: self.image_info.setText(self.tr("Downloading Images")) - image_worker = ImageWorker(self.core) + image_worker = ImageWorker() image_worker.signals.image_progress.connect(self.update_image_progbar) image_worker.signals.result.connect(self.handle_api_worker_result) self.thread_pool.start(image_worker) # gamelist and no_asset games are from Image worker - worker = ApiRequestWorker() - worker.signals.result.connect(self.handle_api_worker_result) - self.thread_pool.start(worker) + api_worker = ApiRequestWorker() + api_worker.signals.result.connect(self.handle_api_worker_result) + self.thread_pool.start(api_worker) # cloud save from another worker, because it is used in cloud_save_utils too cloud_worker = CloudWorker() @@ -131,7 +130,7 @@ class LaunchDialog(QDialog, Ui_LaunchDialog): self.thread_pool.start(cloud_worker) else: - self.finished = 2 + self.completed = 2 if self.core.lgd.assets: ( self.api_results.game_list, @@ -183,10 +182,10 @@ class LaunchDialog(QDialog, Ui_LaunchDialog): self.finish() def finish(self): - if self.finished == 1: + if self.completed == 1: logger.info("App starting") self.image_info.setText(self.tr("Starting...")) ApiResultsSingleton(self.api_results) self.start_app.emit() else: - self.finished += 1 + self.completed += 1 diff --git a/rare/components/extra/console.py b/rare/components/extra/console.py index 70551efb..c24f83a1 100644 --- a/rare/components/extra/console.py +++ b/rare/components/extra/console.py @@ -1,32 +1,52 @@ +from PyQt5.QtCore import QProcessEnvironment from PyQt5.QtGui import QTextCursor, QFont from PyQt5.QtWidgets import ( QPlainTextEdit, - QWidget, + QDialog, QPushButton, QFileDialog, QVBoxLayout, + QHBoxLayout, + QSpacerItem, + QSizePolicy, QTableWidgetItem, QHeaderView, ) +from rare.ui.components.extra.console_env import Ui_ConsoleEnv -class ConsoleWindow(QWidget): - def __init__(self): - super(ConsoleWindow, self).__init__() - self.layout = QVBoxLayout() - self.setWindowTitle("Rare Console") + +class Console(QDialog): + env: QProcessEnvironment + + def __init__(self, parent=None): + super(Console, self).__init__(parent=parent) + self.setWindowTitle("Rare - Console") self.setGeometry(0, 0, 600, 400) + layout = QVBoxLayout() - self.console = Console() - self.layout.addWidget(self.console) + self.console = ConsoleEdit(self) + layout.addWidget(self.console) + + button_layout = QHBoxLayout() + button_layout.addItem(QSpacerItem(0, 0, QSizePolicy.Expanding, QSizePolicy.Fixed)) + + self.env_button = QPushButton(self.tr("Show environment")) + button_layout.addWidget(self.env_button) + self.env_button.clicked.connect(self.show_env) self.save_button = QPushButton(self.tr("Save output to file")) - self.layout.addWidget(self.save_button) + button_layout.addWidget(self.save_button) self.save_button.clicked.connect(self.save) - self.clear_button = QPushButton(self.tr("Clear")) - self.layout.addWidget(self.clear_button) + self.clear_button = QPushButton(self.tr("Clear console")) + button_layout.addWidget(self.clear_button) self.clear_button.clicked.connect(self.console.clear) - self.setLayout(self.layout) + layout.addLayout(button_layout) + + self.setLayout(layout) + + self.env_variables = ConsoleEnv(self) + self.env_variables.hide() def save(self): file, ok = QFileDialog.getSaveFileName( @@ -40,6 +60,13 @@ class ConsoleWindow(QWidget): f.close() self.save_button.setText(self.tr("Saved")) + def set_env(self, env: QProcessEnvironment): + self.env = env + + def show_env(self): + self.env_variables.setTable(self.env) + self.env_variables.show() + def log(self, text: str, end: str = "\n"): self.console.log(text + end) @@ -47,9 +74,27 @@ class ConsoleWindow(QWidget): self.console.error(text + end) -class Console(QPlainTextEdit): - def __init__(self): - super().__init__() +class ConsoleEnv(QDialog): + + def __init__(self, parent=None): + super(ConsoleEnv, self).__init__(parent=parent) + self.ui = Ui_ConsoleEnv() + self.ui.setupUi(self) + + def setTable(self, env: QProcessEnvironment): + self.ui.table.clearContents() + self.ui.table.setRowCount(len(env.keys())) + + for idx, key in enumerate(env.keys()): + self.ui.table.setItem(idx, 0, QTableWidgetItem(env.keys()[idx])) + self.ui.table.setItem(idx, 1, QTableWidgetItem(env.value(env.keys()[idx]))) + + self.ui.table.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) + + +class ConsoleEdit(QPlainTextEdit): + def __init__(self, parent=None): + super(ConsoleEdit, self).__init__(parent=parent) self.setReadOnly(True) self.setFont(QFont("monospace")) self._cursor_output = self.textCursor() diff --git a/rare/components/tabs/games/game_utils.py b/rare/components/tabs/games/game_utils.py index f6412334..b5f22b92 100644 --- a/rare/components/tabs/games/game_utils.py +++ b/rare/components/tabs/games/game_utils.py @@ -11,7 +11,7 @@ from PyQt5.QtWidgets import QMessageBox, QPushButton from legendary.models.game import LaunchParameters, InstalledGame from rare.components.dialogs.uninstall_dialog import UninstallDialog -from rare.components.extra.console import ConsoleWindow +from rare.components.extra.console import Console from rare.components.tabs.games import CloudSaveUtils from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton from rare.utils import legendary_utils @@ -58,7 +58,7 @@ class GameUtils(QObject): self.signals = GlobalSignalsSingleton() self.args = ArgumentsSingleton() - self.console = ConsoleWindow() + self.console = Console() self.cloud_save_utils = CloudSaveUtils() self.cloud_save_utils.sync_finished.connect(self.sync_finished) self.game_meta = RareGameMeta() @@ -245,7 +245,7 @@ class GameUtils(QObject): def _launch_pre_command(self, env: dict): proc = QProcess() - environment = QProcessEnvironment() + environment = QProcessEnvironment().systemEnvironment() for e in env: environment.insert(e, env[e]) proc.setProcessEnvironment(environment) @@ -260,12 +260,13 @@ class GameUtils(QObject): str(proc.readAllStandardError().data(), "utf-8", "ignore") ) ) + self.console.set_env(environment) return proc def _get_process(self, app_name, env): process = GameProcess(app_name) - environment = QProcessEnvironment() + environment = QProcessEnvironment().systemEnvironment() for e in env: environment.insert(e, env[e]) process.setProcessEnvironment(environment) @@ -287,6 +288,7 @@ class GameUtils(QObject): and QSettings().value("show_console", False, bool)) else None ) + self.console.set_env(environment) return process def _launch_origin(self, app_name, process: QProcess): diff --git a/rare/components/tabs/games/head_bar.py b/rare/components/tabs/games/head_bar.py index ba104333..77085442 100644 --- a/rare/components/tabs/games/head_bar.py +++ b/rare/components/tabs/games/head_bar.py @@ -19,7 +19,6 @@ class GameListHeadBar(QWidget): def __init__(self, parent=None): super(GameListHeadBar, self).__init__(parent=parent) self.api_results = ApiResultsSingleton() - self.setLayout(QHBoxLayout()) # self.installed_only = QCheckBox(self.tr("Installed only")) self.settings = QSettings() # self.installed_only.setChecked(self.settings.value("installed_only", False, bool)) @@ -32,7 +31,6 @@ class GameListHeadBar(QWidget): self.tr("Installed only"), self.tr("Offline Games"), ]) - self.layout().addWidget(self.filter) self.available_filters = [ "all", @@ -61,40 +59,43 @@ class GameListHeadBar(QWidget): self.filter.setCurrentIndex(0) self.filter.currentIndexChanged.connect(self.filter_changed) - self.layout().addStretch(1) self.import_game = QPushButton(icon("mdi.import", "fa.arrow-down"), self.tr("Import Game")) self.import_clicked = self.import_game.clicked - self.layout().addWidget(self.import_game) self.egl_sync = QPushButton(icon("mdi.sync", "fa.refresh"), self.tr("Sync with EGL")) self.egl_sync_clicked = self.egl_sync.clicked - self.layout().addWidget(self.egl_sync) # FIXME: Until it is ready # self.egl_sync.setEnabled(False) - self.layout().addStretch(1) - icon_label = QLabel() icon_label.setPixmap(icon("fa.search").pixmap(QSize(20, 20))) - self.layout().addWidget(icon_label) self.search_bar = QLineEdit() self.search_bar.setObjectName("search_bar") self.search_bar.setFrame(False) self.search_bar.setMinimumWidth(200) self.search_bar.setPlaceholderText(self.tr("Search Game")) - self.layout().addWidget(self.search_bar) - self.layout().addStretch(2) checked = QSettings().value("icon_view", True, bool) self.view = SelectViewWidget(checked) - self.layout().addWidget(self.view) - self.layout().addStretch(1) self.refresh_list = QPushButton() self.refresh_list.setIcon(icon("fa.refresh")) # Reload icon - self.layout().addWidget(self.refresh_list) + + layout = QHBoxLayout() + layout.addWidget(self.filter) + layout.addStretch(1) + layout.addWidget(self.import_game) + layout.addWidget(self.egl_sync) + layout.addStretch(1) + layout.addWidget(icon_label) + layout.addWidget(self.search_bar) + layout.addStretch(3) + layout.addWidget(self.view) + layout.addStretch(1) + layout.addWidget(self.refresh_list) + self.setLayout(layout) def filter_changed(self, i): self.filterChanged.emit(self.available_filters[i]) diff --git a/rare/components/tabs/games/import_sync/import_group.py b/rare/components/tabs/games/import_sync/import_group.py index e296d6e7..fa5e52a1 100644 --- a/rare/components/tabs/games/import_sync/import_group.py +++ b/rare/components/tabs/games/import_sync/import_group.py @@ -1,7 +1,8 @@ import json import os from logging import getLogger -from typing import List, Tuple +from pathlib import Path +from typing import List, Tuple, Optional from PyQt5.QtCore import Qt, QModelIndex, pyqtSignal from PyQt5.QtGui import QStandardItemModel @@ -21,9 +22,7 @@ class AppNameCompleter(QCompleter): def __init__(self, app_names: List, parent=None): super(AppNameCompleter, self).__init__(parent) # pylint: disable=E1136 - super(AppNameCompleter, self).activated[QModelIndex].connect( - self.__activated_idx - ) + super(AppNameCompleter, self).activated[QModelIndex].connect(self.__activated_idx) model = QStandardItemModel(len(app_names), 2) for idx, game in enumerate(app_names): @@ -52,18 +51,17 @@ class AppNameCompleter(QCompleter): # lk: Note to self, the completer and popup models are different. # lk: Getting the index from the popup and trying to use it in the completer will return invalid results if isinstance(idx, QModelIndex): - self.activated.emit( - self.popup().model().data(self.popup().model().index(idx.row(), 1)) - ) + self.activated.emit(self.popup().model().data(self.popup().model().index(idx.row(), 1))) # TODO: implement conversion from app_name to app_title (signal loop here) # if isinstance(idx_str, str): # self.activated.emit(idx_str) -class ImportGroup(QGroupBox, Ui_ImportGroup): +class ImportGroup(QGroupBox): def __init__(self, parent=None): super(ImportGroup, self).__init__(parent=parent) - self.setupUi(self) + self.ui = Ui_ImportGroup() + self.ui.setupUi(self) self.core = LegendaryCoreSingleton() self.signals = GlobalSignalsSingleton() self.api_results = ApiResultsSingleton() @@ -84,23 +82,32 @@ class ImportGroup(QGroupBox, Ui_ImportGroup): parent=self, ) self.path_edit.textChanged.connect(self.path_changed) - self.path_edit_layout.addWidget(self.path_edit) + self.ui.path_edit_layout.addWidget(self.path_edit) - self.app_name = IndicatorLineEdit( + self.app_name_edit = IndicatorLineEdit( placeholder=self.tr("Use in case the app name was not found automatically"), completer=AppNameCompleter( - app_names=[ - (i.app_name, i.app_title) for i in self.api_results.game_list - ] + app_names=[(i.app_name, i.app_title) for i in self.api_results.game_list] ), edit_func=self.app_name_edit_cb, parent=self, ) - self.app_name.textChanged.connect(self.app_name_changed) - self.app_name_layout.addWidget(self.app_name) + self.app_name_edit.textChanged.connect(self.app_name_changed) + self.ui.app_name_layout.addWidget(self.app_name_edit) - self.import_button.setEnabled(False) - self.import_button.clicked.connect(self.import_game) + self.ui.import_button.setEnabled(False) + self.ui.import_button.clicked.connect( + lambda: self.import_games(self.path_edit.text()) + if self.ui.import_folder_check.isChecked() + else self.import_game(self.path_edit.text()) + ) + + self.ui.import_folder_check.stateChanged.connect( + lambda s: self.ui.import_button.setEnabled(s or (not s and self.app_name_edit.is_valid)) + ) + self.ui.import_folder_check.stateChanged.connect( + lambda s: self.app_name_edit.setEnabled(not s) + ) def path_edit_cb(self, path) -> Tuple[bool, str, str]: if os.path.exists(path): @@ -113,11 +120,12 @@ class ImportGroup(QGroupBox, Ui_ImportGroup): return False, path, "" def path_changed(self, path): - self.info_label.setText(str()) + self.ui.info_label.setText(str()) + self.ui.import_folder_check.setChecked(False) if self.path_edit.is_valid: - self.app_name.setText(self.find_app_name(path)) + self.app_name_edit.setText(self.find_app_name(path)) else: - self.app_name.setText(str()) + self.app_name_edit.setText(str()) def app_name_edit_cb(self, text) -> Tuple[bool, str, str]: if not text: @@ -128,56 +136,59 @@ class ImportGroup(QGroupBox, Ui_ImportGroup): return False, text, IndicatorLineEdit.reasons.game_not_installed def app_name_changed(self, text): - self.info_label.setText(str()) - if self.app_name.is_valid: - self.import_button.setEnabled(True) + self.ui.info_label.setText(str()) + if self.app_name_edit.is_valid: + self.ui.import_button.setEnabled(True) else: - self.import_button.setEnabled(False) + self.ui.import_button.setEnabled(False) - def find_app_name(self, path): - if not os.path.exists(os.path.join(path, ".egstore")): - return None - for i in os.listdir(os.path.join(path, ".egstore")): - if i.endswith(".mancpn"): - file = os.path.join(path, ".egstore", i) - return json.load(open(file, "r")).get("AppName") + def find_app_name(self, path: str) -> Optional[str]: + if os.path.exists(os.path.join(path, ".egstore")): + for i in os.listdir(os.path.join(path, ".egstore")): + if i.endswith(".mancpn"): + file = os.path.join(path, ".egstore", i) + return json.load(open(file, "r")).get("AppName") + elif app_name := legendary_utils.resolve_aliases( + self.core, os.path.basename(os.path.normpath(path))): + return app_name else: - logger.warning("File was not found") - return None + logger.warning(f"Could not find AppName for {path}") + return None def import_game(self, path=None): - app_name = self.app_name.text() if not path: path = self.path_edit.text() - if not app_name: + if not (app_name := self.app_name_edit.text()): # try to find app name if a_n := self.find_app_name(path): app_name = a_n else: - self.info_label.setText(self.tr("Could not find app name")) + self.ui.info_label.setText(self.tr("Could not find AppName")) return + self.__import_game(app_name, path) - if not ( - err := legendary_utils.import_game(self.core, app_name=app_name, path=path) - ): + def import_games(self, path=None): + if not path: + path = self.path_edit.text() + path = Path(path) + for child in path.iterdir(): + if child.is_dir(): + if (app_name := self.find_app_name(str(child))) is not None: + self.__import_game(app_name, str(child)) + + def __import_game(self, app_name, path): + if not (err := legendary_utils.import_game(self.core, app_name=app_name, path=path)): igame = self.core.get_installed_game(app_name) - self.info_label.setText( - self.tr("Successfully imported {}").format(igame.title) - ) - self.app_name.setText(str()) + logger.info(f"Successfully imported {igame.title}") + self.ui.info_label.setText(self.tr("Successfully imported {}").format(igame.title)) self.signals.update_gamelist.emit([app_name]) - if ( - igame.version - != self.core.get_asset(app_name, igame.platform, False).build_version - ): + if igame.version != self.core.get_asset(app_name, igame.platform, False).build_version: # update available self.signals.add_download.emit(igame.app_name) self.signals.update_download_tab_text.emit() else: logger.warning(f'Failed to import "{app_name}"') - self.info_label.setText( - self.tr("Could not import {}: {}").format(app_name, err) - ) + self.ui.info_label.setText(self.tr("Could not import {}: {}").format(app_name, err)) return diff --git a/rare/components/tabs/settings/widgets/eos.py b/rare/components/tabs/settings/widgets/eos.py index 28bbad87..81cfb762 100644 --- a/rare/components/tabs/settings/widgets/eos.py +++ b/rare/components/tabs/settings/widgets/eos.py @@ -202,9 +202,11 @@ class EosWidget(QGroupBox, Ui_EosWidget): def install_overlay(self, update=False): if platform.system() != "Windows": - if QMessageBox.No == QMessageBox.question(self, "Warning", - self.tr("Epic overlay is currently not supported by wine, so it won't work. Install anyway? "), - QMessageBox.Yes | QMessageBox.No, QMessageBox.No): + if QMessageBox.No == QMessageBox.question( + self, + self.tr("Warning"), + self.tr("Epic overlay is currently not supported by wine, so it won't work. Install anyway? "), + QMessageBox.Yes | QMessageBox.No, QMessageBox.No): return base_path = os.path.expanduser("~/legendary/.overlay") diff --git a/rare/resources/resources.py b/rare/resources/resources.py index 391f9176..3f35740f 100644 Binary files a/rare/resources/resources.py and b/rare/resources/resources.py differ diff --git a/rare/resources/stylesheets/RareStyle/stylesheet.qss b/rare/resources/stylesheets/RareStyle/stylesheet.qss index 5683ae8d..25a94baa 100644 --- a/rare/resources/stylesheets/RareStyle/stylesheet.qss +++ b/rare/resources/stylesheets/RareStyle/stylesheet.qss @@ -1,42 +1,44 @@ /* [Text] -normal: #eeeeee -- main font color -disabled: #43474d -- disabled font color - +normal: #eeeeee rgb(238, 238, 238) -- main font color +disabled: #43474d rgb( 67, 71, 77) -- disabled font color + rgba( 67, 71, 77, 55%) == rgb( 51, 54, 59) + rgba( 67, 71, 77, 25%) == rgb( 41, 43, 47) [Background] -normal: #202225 -- main background color -editable: #333344 -- background color for reactive/editable widgets (TextEdits, ProgressBars etc) -hover: #222233 -- background color when hovering over reactive widgets (Buttons, Headers) -selection: #2f4f4f -- background color for selectable widgets -alternate: #282a2e -- background color for alternating rows in List/Tree/TableViews and for ScrollBars +normal: #202225 rgb( 32, 34, 37) -- main background color +editable: #333344 rgb( 51, 51, 68) -- background color for reactive/editable widgets (TextEdits, ProgressBars etc) +hover: #222233 rgb( 34, 34, 51) -- background color when hovering over reactive widgets (Buttons, Headers) +selection: #2f4f4f rgb( 47, 79, 79) -- background color for selectable widgets +alternate: #282a2e rgb( 40, 42, 46) -- background color for alternating rows in List/Tree/TableViews and for ScrollBars [Border] -normal: #483d8b -- border color for most widgets -editable: #2f4f4f -- border color for editable widgets (TextEdits, ProgressBars etc) -highlight: #5246a0 -- border color for dropdown widgets, a bit lighter than border for more separation -disabled: #43474d -- border for disabled widgets -alternate: #3c3f41 -- border color for gradient backgrounds on widgets like Tabs and Popups +normal: #483d8b rgb( 72, 61, 139) -- border color for most widgets + rgba( 72, 61, 139, 25%) == rgb( 42, 40, 63) +editable: #2f4f4f rgb( 47, 79, 79) -- border color for editable widgets (TextEdits, ProgressBars etc) +highlight: #5246a0 rgb( 82, 70, 160) -- border color for dropdown widgets, a bit lighter than border for more separation +disabled: #43474d rgb( 67, 71, 77) -- border for disabled widgets +alternate: #3c3f41 rgb( 60, 63, 65) -- border color for gradient backgrounds on widgets like Tabs and Popups [Special] -info-normal: #bbb -- infoLabel -install-normal: #090 -- install -install-hover: #060 -- install -install-disabled: #020 -- install -uninstall-normal: #900 -- uninstall -uninstall-hover: #600 -- uninstall -uninstall-disabled: #200 -- uninstall +info-normal: #bbb rgb(187, 187, 187) -- infoLabel +install-normal: #070 rgb( 0, 119, 0) -- install +install-hover: #050 rgb( 0, 85, 0) -- install +install-disabled: #020 rgb( 0, 34, 0) -- install +uninstall-normal: #700 rgb(119, 0, 0) -- uninstall +uninstall-hover: #500 rgb( 85, 0, 0) -- uninstall +uninstall-disabled: #200 rgb( 34, 0, 0) -- uninstall */ * { - color: #eeeeee; - border-color: #483d8b; - background-color: #202225; + color: rgb(238, 238, 238); + border-color: rgb( 72, 61, 139); + background-color: rgb( 32, 34, 37); } *:disabled, *:editable:disabled { - color: #43474d; - border-color: #43474d; - background-color: #202225; + color: rgb( 67, 71, 77); + border-color: rgb( 67, 71, 77); + background-color: rgb( 32, 34, 37); } QLabel, @@ -44,10 +46,10 @@ QLabel:disabled { border-width: 0px; background-color: transparent; padding: 0px; - selection-background-color: #2f4f4f; + selection-background-color: rgb( 47, 79, 79); } QLabel[infoLabel="1"] { - color: #bbb; + color: rgb(187, 187, 187); font-style: italic; font-weight: normal; } @@ -94,9 +96,9 @@ QSpinBox, QDoubleSpinBox, QProgressBar, QScrollBar { - border-color: #2f4f4f; - background-color: #333344; - selection-background-color: #2f4f4f; + border-color: rgb( 47, 79, 79); + background-color: rgb( 51, 51, 68); + selection-background-color: rgb( 47, 79, 79); } QLineEdit, QTextEdit, @@ -123,17 +125,17 @@ QStackedWidget[noBorder="1"] { border-color: transparent; } QComboBox { - background-color: rgba(67, 71, 77, 55%); + background-color: rgb( 51, 54, 59); } QComboBox:disabled { - background-color: rgba(67, 71, 77, 25%); + background-color: rgb( 41, 43, 47); } QComboBox:!editable:hover { - background-color: #222233; + background-color: rgb( 34, 34, 51); } *::item:selected, QComboBox QAbstractItemView { - selection-background-color: #2f4f4f; + selection-background-color: rgb( 47, 79, 79); } *::drop-down, *::drop-down:editable, @@ -150,19 +152,19 @@ QComboBox QAbstractItemView { *::drop-down:editable:disabled, *::up-button:disabled, *::down-button:disabled { - border-color: #43474d; + border-color: rgb( 67, 71, 77); background-color: transparent; } *::drop-down { subcontrol-position: top right; - border-color: #483d8b; - border-left-color: #5246a0; /* #483d8b lighter */ + border-color: rgb( 72, 61, 139); + border-left-color: rgb( 82, 70, 160); /* rgb( 72, 61, 139) lighter */ } *::drop-down:editable, *::up-button, *::down-button { - border-color: #2f4f4f; - background-color: #3c3f41; + border-color: rgb( 47, 79, 79); + background-color: rgb( 60, 63, 65); } *::drop-down, *::drop-down:editable { @@ -189,12 +191,12 @@ QProgressBar { QProgressBar::chunk { width: 2%; margin: 0%; - background-color: #2f4f4f; + background-color: rgb( 47, 79, 79); } QScrollBar { border-radius: 4px; padding: 1px; - background-color: #282a2e; + background-color: rgb( 40, 42, 46); } QScrollBar:vertical { width: 11px; @@ -229,8 +231,8 @@ QScrollBar::sub-line:horizontal { QScrollBar::handle { border-width: 1px; border-style: solid; - border-color: #483d8b; - background-color: #333344; + border-color: rgb( 72, 61, 139); + background-color: rgb( 51, 51, 68); border-radius: 2px; min-height: 30px; min-width: 30px; @@ -259,11 +261,11 @@ QListView, QTreeView, QTableView { outline: 0; - gridline-color: #282a2e; + gridline-color: rgb( 40, 42, 46); show-decoration-selected: 0; selection-background-color: transparent; - background-color: #202225; - alternate-background-color: #282a2e; + background-color: rgb( 32, 34, 37); + alternate-background-color: rgb( 40, 42, 46); } QListView::item, @@ -282,28 +284,28 @@ QTableView[currentRow="0"]::item { QListView::item:hover, QTreeView::item:hover, QTableView::item:hover { - border-color: #483d8b; - background-color: #222233; + border-color: rgb( 72, 61, 139); + background-color: rgb( 34, 34, 51); } QListView::item:selected, QTreeView::item:selected, QTableView::item:selected { - border-color: #483d8b; - background-color: #2f4f4f; + border-color: rgb( 72, 61, 139); + background-color: rgb( 47, 79, 79); } QPushButton, QToolButton { - background-color: rgba(67, 71, 77, 55%); + background-color: rgb( 51, 54, 59); } QPushButton:disabled, QToolButton:disabled { - background-color: rgba(67, 71, 77, 25%); + background-color: rgb( 41, 43, 47); } QPushButton:hover, QToolButton:hover, QHeaderView::section:hover { - background-color: #222233; + background-color: rgb( 34, 34, 51); } QPushButton, QToolButton { @@ -327,36 +329,36 @@ QPushButton#menu { } QPushButton#menu_button { border-width: 0px; - background-color: #3c3f41; + background-color: rgb( 60, 63, 65); width: 18px; height: 18px; } QPushButton#menu_button:hover { - background-color: "#333344"; + background-color: rgb( 51, 51, 68); } QPushButton[install="1"], QPushButton#install_button { - background-color: "#070"; + background-color: rgb( 0, 119, 0); } QPushButton[install="1"]:hover, QPushButton#install_button:hover { - background-color: "#050"; + background-color: rgb( 0, 85, 0); } QPushButton[install="1"]:disabled, QPushButton#install_button:disabled { - background-color: "#020"; + background-color: rgb( 0, 34, 0); } QPushButton[uninstall="1"], QPushButton#uninstall_button { - background-color: "#900"; + background-color: rgb(119, 0, 0); } QPushButton[uninstall="1"]:hover, QPushButton#uninstall_button:hover { - background-color: "#600"; + background-color: rgb( 85, 0, 0); } QPushButton[uninstall="1"]:disabled, QPushButton#uninstall_button:disabled { - background-color: "#200"; + background-color: rgb( 34, 0, 0); } QPushButton#success{ background-color: lime; @@ -376,10 +378,10 @@ QRadioButton::indicator, QListView::indicator, QTreeView::indicator, QTableView::indicator { - border-color: #2f4f4f; + border-color: rgb( 47, 79, 79); border-width: 1px; border-style: solid; - background-color: #202225; + background-color: rgb( 32, 34, 37); } QCheckBox::indicator, QRadioButton::indicator, @@ -395,7 +397,7 @@ QRadioButton::indicator:disabled, QListView::indicator:disabled, QTreeView::indicator:disabled, QTableView::indicator:disabled { - border-color: #43474d; + border-color: rgb( 67, 71, 77); } QRadioButton::indicator { border-radius: 5%; @@ -469,17 +471,20 @@ QGroupBox::title { border-style: solid; border-top-left-radius: 4px; border-bottom-right-radius: 4px; - border-color: #483d8b; + border-color: rgb( 72, 61, 139); padding: 1px; /* background: qlineargradient( - x1: -2, y1: 0, x2: 1, y2: 1, stop: 0 #483d8b, stop: 1 #202225); + x1: -2, y1: 0, + x2: 1, y2: 1, + stop: 0 rgb( 72, 61, 139), + stop: 1 rgb( 32, 34, 37)); */ - background-color: rgba(72, 61, 139, 25%); + background-color: rgb( 42, 40, 63); } QGroupBox::title:disabled { - border-color: #43474d; - background-color: rgba(67, 71, 77, 25%); + border-color: rgb( 67, 71, 77); + background-color: rgb( 41, 43, 47); } QSizeGrip { @@ -495,7 +500,7 @@ QSizeGrip { #search_bar { padding: 3px; border-radius: 5px; - background-color: "#333344"; + background-color: rgb( 51, 51, 68); } QTabWidget::pane { @@ -519,54 +524,66 @@ QTabBar::tab:bottom { } QTabBar::tab:top:hover, QTabBar::tab:bottom:hover { - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-left-color: transparent; border-right-color: transparent; } QTabBar::tab:top { border-top-width: 3px; - border-top-color: #3c3f41; - border-bottom-color: #483d8b; + border-top-color: rgb( 60, 63, 65); + border-bottom-color: rgb( 72, 61, 139); background: qlineargradient( - x1: 0, y1: -1, x2: 0, y2: 1, stop: 0 #3c3f41, stop: 1 #202225); + x1: 0, y1: -1, + x2: 0, y2: 1, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:bottom { border-bottom-width: 3px; - border-top-color: #483d8b; - border-bottom-color: #3c3f41; + border-top-color: rgb( 72, 61, 139); + border-bottom-color: rgb( 60, 63, 65); background: qlineargradient( - x1: 0, y1: 2, x2: 0, y2: 0, stop: 0 #3c3f41, stop: 1 #202225); + x1: 0, y1: 2, + x2: 0, y2: 0, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:top:hover { background: qlineargradient( - x1: 0, y1: -1, x2: 0, y2: 1, stop: 0 #483d8b, stop: 1 #202225); + x1: 0, y1: -1, + x2: 0, y2: 1, + stop: 0 rgb( 72, 61, 139), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:bottom:hover { background: qlineargradient( - x1: 0, y1: 2, x2: 0, y2: 0, stop: 0 #483d8b, stop: 1 #202225); + x1: 0, y1: 2, + x2: 0, y2: 0, + stop: 0 rgb( 72, 61, 139), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:top:selected { - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-bottom-color: transparent; - background: #202225; + background: rgb( 32, 34, 37); } QTabBar::tab:bottom:selected { - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-top-color: transparent; - background: #202225; + background: rgb( 32, 34, 37); } QTabBar::tab:top:disabled { - border-bottom-color: #3c3f41; + border-bottom-color: rgb( 60, 63, 65); } QTabBar::tab:bottom:disabled { - border-top-color: #3c3f41; + border-top-color: rgb( 60, 63, 65); } QTabBar::tab:top:selected:disabled { - border-color: #3c3f41; + border-color: rgb( 60, 63, 65); border-bottom-color: transparent; } QTabBar::tab:bottom:selected:disabled { - border-color: #3c3f41; + border-color: rgb( 60, 63, 65); border-top-color: transparent; } QTabBar::tab:left, @@ -576,54 +593,66 @@ QTabBar::tab:right { } QTabBar::tab:left:hover, QTabBar::tab:right:hover { - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-top-color: transparent; border-bottom-color: transparent; } QTabBar::tab:left { border-left-width: 3px; - border-left-color: #3c3f41; - border-right-color: #483d8b; + border-left-color: rgb( 60, 63, 65); + border-right-color: rgb( 72, 61, 139); background: qlineargradient( - x1: -1, y1: 0, x2: 1, y2: 0, stop: 0 #3c3f41, stop: 1 #202225); + x1: -1, y1: 0, + x2: 1, y2: 0, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:right { border-right-width: 3px; - border-right-color: #3c3f41; - border-left-color: #483d8b; + border-right-color: rgb( 60, 63, 65); + border-left-color: rgb( 72, 61, 139); background: qlineargradient( - x1: 2, y1: 0, x2: 0, y2: 0, stop: 0 #3c3f41, stop: 1 #202225); + x1: 2, y1: 0, + x2: 0, y2: 0, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:left:hover { background: qlineargradient( - x1: -1, y1: 0, x2: 1, y2: 0, stop: 0 #483d8b, stop: 1 #202225); + x1: -1, y1: 0, + x2: 1, y2: 0, + stop: 0 rgb( 72, 61, 139), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:right:hover { background: qlineargradient( - x1: 2, y1: 0, x2: 0, y2: 0, stop: 0 #483d8b, stop: 1 #202225); + x1: 2, y1: 0, + x2: 0, y2: 0, + stop: 0 rgb( 72, 61, 139), + stop: 1 rgb( 32, 34, 37)); } QTabBar::tab:left:selected { - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-right-color: transparent; - background: #202225; + background: rgb( 32, 34, 37); } QTabBar::tab:right:selected { - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-left-color: transparent; - background: #202225; + background: rgb( 32, 34, 37); } QTabBar::tab:left:disabled { - border-right-color: #3c3f41; + border-right-color: rgb( 60, 63, 65); } QTabBar::tab:right:disabled { - border-left-color: #3c3f41; + border-left-color: rgb( 60, 63, 65); } QTabBar::tab:left:selected:disabled { - border-color: #3c3f41; + border-color: rgb( 60, 63, 65); border-right-color: transparent; } QTabBar::tab:right:selected:disabled { - border-color: #3c3f41; + border-color: rgb( 60, 63, 65); border-left-color: transparent; } @@ -631,21 +660,24 @@ QTabBar#MainTabBar { border-width: 1px; border-style: solid; border-color: transparent; - border-bottom-color: #483d8b; + border-bottom-color: rgb( 72, 61, 139); /* background: qlineargradient( - x1: 0, y1: -3, x2: 0, y2: 1, stop: 0 #3c3f41, stop: 1 #202225); + x1: 0, y1: -3, + x2: 0, y2: 1, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); */ } QTabBar#MainTabBar:disabled { border-color: transparent; - border-bottom-color: #3c3f41; + border-bottom-color: rgb( 60, 63, 65); } QTabBar#MainTabBar::tab { margin-left: 3px; margin-right: 3px; border-top-color: transparent; - border-bottom-color: #483d8b; + border-bottom-color: rgb( 72, 61, 139); padding: 5px; }/* QTabBar#MainTabBar::tab:top:first, @@ -659,25 +691,28 @@ QTabBar#MainTabBar::tab:bottom:last { border-right: transparent; }*/ QTabBar#MainTabBar::tab:top:hover { - border-top-color: #483d8b; + border-top-color: rgb( 72, 61, 139); } QTabBar#MainTabBar::tab:top:selected { - border-color: #483d8b; - border-bottom-color: #202225; + border-color: rgb( 72, 61, 139); + border-bottom-color: rgb( 32, 34, 37); } QTabBar#SideTabBar { border-width: 1px; border-style: solid; border-color: transparent; - border-right-color: #483d8b; + border-right-color: rgb( 72, 61, 139); /* background: qlineargradient( - x1: -3, y1: 0, x2: 1, y2: 0, stop: 0 #3c3f41, stop: 1 #202225); + x1: -3, y1: 0, + x2: 1, y2: 0, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); */ } QTabBar#SideTabBar:disabled { border-color: transparent; - border-right-color: #3c3f41; + border-right-color: rgb( 60, 63, 65); } QTabBar#SideTabBar::tab { margin-top: 3px; @@ -703,44 +738,47 @@ QStatusBar { border-width: 1px; border-style: solid; border-color: transparent; - border-top-color: #483d8b; - border-bottom-color: #3c3f41; + border-top-color: rgb( 72, 61, 139); + border-bottom-color: rgb( 60, 63, 65); background: qlineargradient( - x1: 0, y1: 3, x2: 0, y2: 0, stop: 0 #3c3f41, stop: 1 #202225); + x1: 0, y1: 3, + x2: 0, y2: 0, + stop: 0 rgb( 60, 63, 65), + stop: 1 rgb( 32, 34, 37)); } QToolTip { border-width: 1px; border-style: solid; - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-radius: 4px; padding: 1px; opacity: 200; } QBalloonTip { - color: #eeeeee; - background-color: #202225; + color: rgb(238, 238, 238); + background-color: rgb( 32, 34, 37); border-width: 1px; border-style: solid; - border-color: #483d8b; + border-color: rgb( 72, 61, 139); border-radius: 4px; padding: 1px; } /* Wrapper settings styling */ QPushButton#WrapperWidgetButton { - border-color: rgba(67, 71, 77, 55%); + border-color: rgb( 51, 54, 59); } QPushButton#WrapperWidgetButton:disabled { - border-color: rgba(67, 71, 77, 25%); + border-color: rgb( 41, 43, 47); } QScrollArea#WrapperSettingsScroll { - border-color: #2f4f4f; - background-color: #282a2e; + border-color: rgb( 47, 79, 79); + background-color: rgb( 40, 42, 46); } QScrollBar#WrapperSettingsScrollBar { - background-color: #282a2e; + background-color: rgb( 40, 42, 46); } QLabel#WrapperSettingsLabel { border-width: 1px; @@ -748,6 +786,6 @@ QLabel#WrapperSettingsLabel { border-radius: 2px; padding: 2px; color: #999; - border-color: #2f4f4f; - background-color: #282a2e; + border-color: rgb( 47, 79, 79); + background-color: rgb( 40, 42, 46); } diff --git a/rare/shared.py b/rare/shared.py index 5de855fd..33ce579f 100644 --- a/rare/shared.py +++ b/rare/shared.py @@ -1,37 +1,47 @@ from argparse import Namespace +from typing import Optional from legendary.core import LegendaryCore + from rare.utils.models import ApiResults, GlobalSignals -_legendary_core_singleton: LegendaryCore = None -_global_signals_singleton: GlobalSignals = None -_arguments_singleton: Namespace = None -_api_results_singleton: ApiResults = None +_legendary_core_singleton: Optional[LegendaryCore] = None +_global_signals_singleton: Optional[GlobalSignals] = None +_arguments_singleton: Optional[Namespace] = None +_api_results_singleton: Optional[ApiResults] = None -def LegendaryCoreSingleton() -> LegendaryCore: +def LegendaryCoreSingleton(init: bool = False) -> LegendaryCore: global _legendary_core_singleton + if _legendary_core_singleton is None and not init: + raise RuntimeError("Uninitialized use of LegendaryCoreSingleton") if _legendary_core_singleton is None: _legendary_core_singleton = LegendaryCore() return _legendary_core_singleton -def GlobalSignalsSingleton() -> GlobalSignals: +def GlobalSignalsSingleton(init: bool = False) -> GlobalSignals: global _global_signals_singleton + if _global_signals_singleton is None and not init: + raise RuntimeError("Uninitialized use of GlobalSignalsSingleton") if _global_signals_singleton is None: _global_signals_singleton = GlobalSignals() return _global_signals_singleton -def ArgumentsSingleton(args: Namespace = None) -> Namespace: +def ArgumentsSingleton(args: Namespace = None) -> Optional[Namespace]: global _arguments_singleton + if _arguments_singleton is None and args is None: + raise RuntimeError("Uninitialized use of ArgumentsSingleton") if _arguments_singleton is None: _arguments_singleton = args return _arguments_singleton -def ApiResultsSingleton(res: ApiResults = None) -> ApiResults: +def ApiResultsSingleton(res: ApiResults = None) -> Optional[ApiResults]: global _api_results_singleton + if _api_results_singleton is None and res is None: + raise RuntimeError("Uninitialized use of ApiResultsSingleton") if _api_results_singleton is None: _api_results_singleton = res return _api_results_singleton diff --git a/rare/ui/components/dialogs/install_dialog.py b/rare/ui/components/dialogs/install_dialog.py index c8bb87dd..80927028 100644 --- a/rare/ui/components/dialogs/install_dialog.py +++ b/rare/ui/components/dialogs/install_dialog.py @@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_InstallDialog(object): def setupUi(self, InstallDialog): InstallDialog.setObjectName("InstallDialog") - InstallDialog.resize(324, 347) + InstallDialog.resize(337, 372) InstallDialog.setWindowTitle("Rare") self.install_dialog_layout = QtWidgets.QFormLayout(InstallDialog) self.install_dialog_layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) @@ -58,6 +58,7 @@ class Ui_InstallDialog(object): sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.force_download_check.sizePolicy().hasHeightForWidth()) self.force_download_check.setSizePolicy(sizePolicy) + self.force_download_check.setText("") self.force_download_check.setObjectName("force_download_check") self.install_dialog_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.force_download_check) self.platform_label = QtWidgets.QLabel(InstallDialog) @@ -74,50 +75,14 @@ class Ui_InstallDialog(object): self.ignore_space_label = QtWidgets.QLabel(InstallDialog) self.ignore_space_label.setObjectName("ignore_space_label") self.install_dialog_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.ignore_space_label) - self.ignore_space_layout = QtWidgets.QHBoxLayout() - self.ignore_space_layout.setObjectName("ignore_space_layout") - self.ignore_space_check = QtWidgets.QCheckBox(InstallDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.ignore_space_check.sizePolicy().hasHeightForWidth()) - self.ignore_space_check.setSizePolicy(sizePolicy) - self.ignore_space_check.setObjectName("ignore_space_check") - self.ignore_space_layout.addWidget(self.ignore_space_check) - self.ignore_space_info_label = QtWidgets.QLabel(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.ignore_space_info_label.setFont(font) - self.ignore_space_info_label.setObjectName("ignore_space_info_label") - self.ignore_space_layout.addWidget(self.ignore_space_info_label) - self.install_dialog_layout.setLayout(5, QtWidgets.QFormLayout.FieldRole, self.ignore_space_layout) self.download_only_label = QtWidgets.QLabel(InstallDialog) self.download_only_label.setObjectName("download_only_label") self.install_dialog_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.download_only_label) - self.download_only_layout = QtWidgets.QHBoxLayout() - self.download_only_layout.setObjectName("download_only_layout") - self.download_only_check = QtWidgets.QCheckBox(InstallDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.download_only_check.sizePolicy().hasHeightForWidth()) - self.download_only_check.setSizePolicy(sizePolicy) - self.download_only_check.setText("") - self.download_only_check.setObjectName("download_only_check") - self.download_only_layout.addWidget(self.download_only_check) - self.download_only_info_label = QtWidgets.QLabel(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.download_only_info_label.setFont(font) - self.download_only_info_label.setObjectName("download_only_info_label") - self.download_only_layout.addWidget(self.download_only_info_label) - self.install_dialog_layout.setLayout(6, QtWidgets.QFormLayout.FieldRole, self.download_only_layout) self.shortcut_lbl = QtWidgets.QLabel(InstallDialog) self.shortcut_lbl.setObjectName("shortcut_lbl") self.install_dialog_layout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.shortcut_lbl) self.shortcut_cb = QtWidgets.QCheckBox(InstallDialog) self.shortcut_cb.setText("") - self.shortcut_cb.setChecked(True) self.shortcut_cb.setObjectName("shortcut_cb") self.install_dialog_layout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.shortcut_cb) self.sdl_list_label = QtWidgets.QLabel(InstallDialog) @@ -181,6 +146,28 @@ class Ui_InstallDialog(object): self.install_preqs_check.setText("") self.install_preqs_check.setObjectName("install_preqs_check") self.install_dialog_layout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.install_preqs_check) + self.ignore_space_check = QtWidgets.QCheckBox(InstallDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.ignore_space_check.sizePolicy().hasHeightForWidth()) + self.ignore_space_check.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setItalic(True) + self.ignore_space_check.setFont(font) + self.ignore_space_check.setObjectName("ignore_space_check") + self.install_dialog_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.ignore_space_check) + self.download_only_check = QtWidgets.QCheckBox(InstallDialog) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.download_only_check.sizePolicy().hasHeightForWidth()) + self.download_only_check.setSizePolicy(sizePolicy) + font = QtGui.QFont() + font.setItalic(True) + self.download_only_check.setFont(font) + self.download_only_check.setObjectName("download_only_check") + self.install_dialog_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.download_only_check) self.retranslateUi(InstallDialog) QtCore.QMetaObject.connectSlotsByName(InstallDialog) @@ -194,9 +181,7 @@ class Ui_InstallDialog(object): self.force_download_label.setText(_translate("InstallDialog", "Force redownload")) self.platform_label.setText(_translate("InstallDialog", "Platform")) self.ignore_space_label.setText(_translate("InstallDialog", "Ignore free space")) - self.ignore_space_info_label.setText(_translate("InstallDialog", "Use with caution!")) self.download_only_label.setText(_translate("InstallDialog", "Download only")) - self.download_only_info_label.setText(_translate("InstallDialog", "Do not try to install.")) self.shortcut_lbl.setText(_translate("InstallDialog", "Create shortcut")) self.sdl_list_label.setText(_translate("InstallDialog", "Optional packs")) self.download_size_label.setText(_translate("InstallDialog", "Download size")) @@ -209,6 +194,8 @@ class Ui_InstallDialog(object): self.verify_button.setText(_translate("InstallDialog", "Verify")) self.install_button.setText(_translate("InstallDialog", "Install")) self.install_preqs_lbl.setText(_translate("InstallDialog", "Install prerequisites")) + self.ignore_space_check.setText(_translate("InstallDialog", "Use with caution!")) + self.download_only_check.setText(_translate("InstallDialog", "Do not try to install.")) if __name__ == "__main__": diff --git a/rare/ui/components/dialogs/install_dialog.ui b/rare/ui/components/dialogs/install_dialog.ui index 908d2a6f..5c43d499 100644 --- a/rare/ui/components/dialogs/install_dialog.ui +++ b/rare/ui/components/dialogs/install_dialog.ui @@ -6,8 +6,8 @@ 0 0 - 324 - 347 + 337 + 372 @@ -85,6 +85,9 @@ 0 + + + @@ -111,32 +114,6 @@ - - - - - - - 0 - 0 - - - - - - - - - true - - - - Use with caution! - - - - - @@ -144,35 +121,6 @@ - - - - - - - 0 - 0 - - - - - - - - - - - - true - - - - Do not try to install. - - - - - @@ -185,9 +133,6 @@ - - true - @@ -323,7 +268,43 @@ - + + + + + + + + + 0 + 0 + + + + + true + + + + Use with caution! + + + + + + + + 0 + 0 + + + + + true + + + + Do not try to install. diff --git a/rare/ui/components/dialogs/login/login_dialog.py b/rare/ui/components/dialogs/login/login_dialog.py index e5e5b84b..b7650abd 100644 --- a/rare/ui/components/dialogs/login/login_dialog.py +++ b/rare/ui/components/dialogs/login/login_dialog.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'rare/ui/components/dialogs/login/login_dialog.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. @@ -14,16 +14,17 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_LoginDialog(object): def setupUi(self, LoginDialog): LoginDialog.setObjectName("LoginDialog") - LoginDialog.resize(498, 269) - self.verticalLayout = QtWidgets.QVBoxLayout(LoginDialog) - self.verticalLayout.setObjectName("verticalLayout") - spacerItem = QtWidgets.QSpacerItem(477, 17, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) - self.verticalLayout.addItem(spacerItem) + LoginDialog.resize(492, 267) + self.login_layout = QtWidgets.QVBoxLayout(LoginDialog) + self.login_layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) + self.login_layout.setObjectName("login_layout") + spacerItem = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.login_layout.addItem(spacerItem) self.welcome_label = QtWidgets.QLabel(LoginDialog) self.welcome_label.setObjectName("welcome_label") - self.verticalLayout.addWidget(self.welcome_label) - spacerItem1 = QtWidgets.QSpacerItem(477, 17, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed) - self.verticalLayout.addItem(spacerItem1) + self.login_layout.addWidget(self.welcome_label) + spacerItem1 = QtWidgets.QSpacerItem(0, 17, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.login_layout.addItem(spacerItem1) self.login_stack = QtWidgets.QStackedWidget(LoginDialog) self.login_stack.setEnabled(True) self.login_stack.setMinimumSize(QtCore.QSize(480, 135)) @@ -73,7 +74,7 @@ class Ui_LoginDialog(object): self.login_browser_radio.setObjectName("login_browser_radio") self.login_page_layout.addWidget(self.login_browser_radio, 1, 0, 1, 1) self.login_stack.addWidget(self.login_page) - self.verticalLayout.addWidget(self.login_stack) + self.login_layout.addWidget(self.login_stack) self.button_layout = QtWidgets.QHBoxLayout() self.button_layout.setObjectName("button_layout") spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) @@ -87,7 +88,7 @@ class Ui_LoginDialog(object): self.next_button = QtWidgets.QPushButton(LoginDialog) self.next_button.setObjectName("next_button") self.button_layout.addWidget(self.next_button) - self.verticalLayout.addLayout(self.button_layout) + self.login_layout.addLayout(self.button_layout) self.retranslateUi(LoginDialog) self.login_stack.setCurrentIndex(0) diff --git a/rare/ui/components/dialogs/login/login_dialog.ui b/rare/ui/components/dialogs/login/login_dialog.ui index d4051943..2adbb98a 100644 --- a/rare/ui/components/dialogs/login/login_dialog.ui +++ b/rare/ui/components/dialogs/login/login_dialog.ui @@ -6,25 +6,22 @@ 0 0 - 498 - 269 + 492 + 267 Rare Login - + + + QLayout::SetFixedSize + - - Qt::Vertical - - - QSizePolicy::Fixed - - 477 + 0 17 @@ -39,15 +36,9 @@ - - Qt::Vertical - - - QSizePolicy::Fixed - - 477 + 0 17 diff --git a/rare/ui/components/extra/__init__.py b/rare/ui/components/extra/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rare/ui/components/extra/console_env.py b/rare/ui/components/extra/console_env.py new file mode 100644 index 00000000..51c88559 --- /dev/null +++ b/rare/ui/components/extra/console_env.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'rare/ui/components/extra/console_env.ui' +# +# 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, QtGui, QtWidgets + + +class Ui_ConsoleEnv(object): + def setupUi(self, ConsoleEnv): + ConsoleEnv.setObjectName("ConsoleEnv") + ConsoleEnv.resize(600, 400) + self.layout = QtWidgets.QVBoxLayout(ConsoleEnv) + self.layout.setObjectName("layout") + self.table = QtWidgets.QTableWidget(ConsoleEnv) + font = QtGui.QFont() + font.setFamily("Monospace") + self.table.setFont(font) + self.table.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) + self.table.setAlternatingRowColors(True) + self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) + self.table.setCornerButtonEnabled(True) + self.table.setColumnCount(2) + self.table.setObjectName("table") + self.table.setRowCount(0) + item = QtWidgets.QTableWidgetItem() + self.table.setHorizontalHeaderItem(0, item) + item = QtWidgets.QTableWidgetItem() + self.table.setHorizontalHeaderItem(1, item) + self.table.horizontalHeader().setVisible(True) + self.table.horizontalHeader().setStretchLastSection(True) + self.table.verticalHeader().setVisible(False) + self.layout.addWidget(self.table) + self.buttons = QtWidgets.QDialogButtonBox(ConsoleEnv) + self.buttons.setOrientation(QtCore.Qt.Horizontal) + self.buttons.setStandardButtons(QtWidgets.QDialogButtonBox.Close) + self.buttons.setObjectName("buttons") + self.layout.addWidget(self.buttons) + + self.retranslateUi(ConsoleEnv) + self.buttons.accepted.connect(ConsoleEnv.accept) # type: ignore + self.buttons.rejected.connect(ConsoleEnv.reject) # type: ignore + QtCore.QMetaObject.connectSlotsByName(ConsoleEnv) + + def retranslateUi(self, ConsoleEnv): + _translate = QtCore.QCoreApplication.translate + ConsoleEnv.setWindowTitle(_translate("ConsoleEnv", "Rare - Console Environment")) + self.table.setSortingEnabled(True) + item = self.table.horizontalHeaderItem(0) + item.setText(_translate("ConsoleEnv", "Variable")) + item = self.table.horizontalHeaderItem(1) + item.setText(_translate("ConsoleEnv", "Value")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + ConsoleEnv = QtWidgets.QDialog() + ui = Ui_ConsoleEnv() + ui.setupUi(ConsoleEnv) + ConsoleEnv.show() + sys.exit(app.exec_()) diff --git a/rare/ui/components/extra/console_env.ui b/rare/ui/components/extra/console_env.ui new file mode 100644 index 00000000..91283242 --- /dev/null +++ b/rare/ui/components/extra/console_env.ui @@ -0,0 +1,110 @@ + + + ConsoleEnv + + + + 0 + 0 + 600 + 400 + + + + Rare - Console Environment + + + + + + + Monospace + + + + QAbstractItemView::NoEditTriggers + + + true + + + QAbstractItemView::SelectRows + + + true + + + true + + + 2 + + + true + + + true + + + false + + + + Variable + + + + + Value + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + buttons + accepted() + ConsoleEnv + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttons + rejected() + ConsoleEnv + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/rare/ui/components/tabs/games/game_info/game_info.py b/rare/ui/components/tabs/games/game_info/game_info.py index b5a57ee4..755b0a2f 100644 --- a/rare/ui/components/tabs/games/game_info/game_info.py +++ b/rare/ui/components/tabs/games/game_info/game_info.py @@ -16,7 +16,6 @@ class Ui_GameInfo(object): GameInfo.setObjectName("GameInfo") GameInfo.resize(791, 583) self.layout_game_info = QtWidgets.QHBoxLayout(GameInfo) - self.layout_game_info.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) self.layout_game_info.setObjectName("layout_game_info") self.image = QtWidgets.QLabel(GameInfo) self.image.setFrameShape(QtWidgets.QFrame.StyledPanel) diff --git a/rare/ui/components/tabs/games/game_info/game_info.ui b/rare/ui/components/tabs/games/game_info/game_info.ui index 73b9be19..a97bfa66 100644 --- a/rare/ui/components/tabs/games/game_info/game_info.ui +++ b/rare/ui/components/tabs/games/game_info/game_info.ui @@ -14,9 +14,6 @@ Game Info - - QLayout::SetFixedSize - diff --git a/rare/ui/components/tabs/games/import_sync/import_group.py b/rare/ui/components/tabs/games/import_sync/import_group.py index 7b13f92d..f1e8222e 100644 --- a/rare/ui/components/tabs/games/import_sync/import_group.py +++ b/rare/ui/components/tabs/games/import_sync/import_group.py @@ -8,30 +8,37 @@ # 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_ImportGroup(object): def setupUi(self, ImportGroup): ImportGroup.setObjectName("ImportGroup") - ImportGroup.resize(235, 127) + ImportGroup.resize(501, 154) ImportGroup.setWindowTitle("ImportGroup") ImportGroup.setWindowFilePath("") self.import_layout = QtWidgets.QFormLayout(ImportGroup) - self.import_layout.setLabelAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignTrailing | QtCore.Qt.AlignVCenter) + self.import_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.import_layout.setObjectName("import_layout") self.path_edit_label = QtWidgets.QLabel(ImportGroup) self.path_edit_label.setObjectName("path_edit_label") self.import_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.path_edit_label) - self.app_name_label = QtWidgets.QLabel(ImportGroup) - self.app_name_label.setObjectName("app_name_label") - self.import_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label) self.path_edit_layout = QtWidgets.QHBoxLayout() self.path_edit_layout.setObjectName("path_edit_layout") self.import_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.path_edit_layout) + self.app_name_label = QtWidgets.QLabel(ImportGroup) + self.app_name_label.setObjectName("app_name_label") + self.import_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label) self.app_name_layout = QtWidgets.QHBoxLayout() self.app_name_layout.setObjectName("app_name_layout") self.import_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.app_name_layout) + self.import_folder_label = QtWidgets.QLabel(ImportGroup) + self.import_folder_label.setObjectName("import_folder_label") + self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.import_folder_label) + self.info_label = QtWidgets.QLabel(ImportGroup) + self.info_label.setText("") + self.info_label.setObjectName("info_label") + self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.info_label) self.import_button = QtWidgets.QPushButton(ImportGroup) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -39,11 +46,13 @@ class Ui_ImportGroup(object): sizePolicy.setHeightForWidth(self.import_button.sizePolicy().hasHeightForWidth()) self.import_button.setSizePolicy(sizePolicy) self.import_button.setObjectName("import_button") - self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.import_button) - self.info_label = QtWidgets.QLabel(ImportGroup) - self.info_label.setText("") - self.info_label.setObjectName("info_label") - self.import_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.info_label) + self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_button) + self.import_folder_check = QtWidgets.QCheckBox(ImportGroup) + font = QtGui.QFont() + font.setItalic(True) + self.import_folder_check.setFont(font) + self.import_folder_check.setObjectName("import_folder_check") + self.import_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.import_folder_check) self.retranslateUi(ImportGroup) QtCore.QMetaObject.connectSlotsByName(ImportGroup) @@ -53,7 +62,9 @@ class Ui_ImportGroup(object): ImportGroup.setTitle(_translate("ImportGroup", "Import EGL game from a directory")) self.path_edit_label.setText(_translate("ImportGroup", "Installation path")) self.app_name_label.setText(_translate("ImportGroup", "Override app name")) + self.import_folder_label.setText(_translate("ImportGroup", "Import all folders")) self.import_button.setText(_translate("ImportGroup", "Import Game")) + self.import_folder_check.setText(_translate("ImportGroup", "Scan the installation path for game folders and import them")) if __name__ == "__main__": diff --git a/rare/ui/components/tabs/games/import_sync/import_group.ui b/rare/ui/components/tabs/games/import_sync/import_group.ui index 9e156c41..0545451f 100644 --- a/rare/ui/components/tabs/games/import_sync/import_group.ui +++ b/rare/ui/components/tabs/games/import_sync/import_group.ui @@ -6,8 +6,8 @@ 0 0 - 235 - 127 + 501 + 154 @@ -30,6 +30,9 @@ + + + @@ -37,13 +40,24 @@ - - - + + + + Import all folders + + + + + + + + + + @@ -57,9 +71,14 @@ - + + + + true + + - + Scan the installation path for game folders and import them diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py index 117f0516..ba880244 100644 --- a/rare/utils/extra_widgets.py +++ b/rare/utils/extra_widgets.py @@ -4,6 +4,7 @@ from typing import Callable, Tuple from PyQt5.QtCore import ( Qt, + QEvent, QCoreApplication, QRect, QSize, @@ -49,6 +50,7 @@ class FlowLayout(QLayout): self._vspacing = vspacing self._items = [] self.setContentsMargins(margin, margin, margin, margin) + self.setObjectName(type(self).__name__) def __del__(self): del self._items[:] @@ -148,7 +150,9 @@ class FlowLayout(QLayout): class IndicatorReasons: dir_not_empty = QCoreApplication.translate("IndicatorReasons", "Directory is not empty") wrong_format = QCoreApplication.translate("IndicatorReasons", "Given text has wrong format") - game_not_installed = QCoreApplication.translate("IndicatorReasons", "Game is not installed or does not exist") + game_not_installed = QCoreApplication.translate( + "IndicatorReasons", "Game is not installed or does not exist" + ) dir_not_exist = QCoreApplication.translate("IndicatorReasons", "Directory does not exist") file_not_exist = QCoreApplication.translate("IndicatorReasons", "File does not exist") wrong_path = QCoreApplication.translate("IndicatorReasons", "Wrong Directory") @@ -160,29 +164,29 @@ class IndicatorLineEdit(QWidget): reasons = IndicatorReasons() def __init__( - self, - text: str = "", - placeholder: str = "", - completer: QCompleter = None, - edit_func: Callable[[str], Tuple[bool, str, str]] = None, - save_func: Callable[[str], None] = None, - horiz_policy: QSizePolicy = QSizePolicy.Expanding, - parent=None, + self, + text: str = "", + placeholder: str = "", + completer: QCompleter = None, + edit_func: Callable[[str], Tuple[bool, str, str]] = None, + save_func: Callable[[str], None] = None, + horiz_policy: QSizePolicy = QSizePolicy.Expanding, + parent=None, ): super(IndicatorLineEdit, self).__init__(parent=parent) - self.setObjectName("IndicatorLineEdit") - self.layout = QHBoxLayout(self) - self.layout.setObjectName("layout") - self.layout.setContentsMargins(0, 0, 0, 0) + self.setObjectName(type(self).__name__) + layout = QHBoxLayout(self) + layout.setObjectName(f"{self.objectName()}Layout") + layout.setContentsMargins(0, 0, 0, 0) # Add line_edit self.line_edit = QLineEdit(self) - self.line_edit.setObjectName("line_edit") + self.line_edit.setObjectName(f"{type(self).__name__}Edit") self.line_edit.setPlaceholderText(placeholder) self.line_edit.setSizePolicy(horiz_policy, QSizePolicy.Fixed) # Add hint_label to line_edit self.line_edit.setLayout(QHBoxLayout()) self.hint_label = QLabel() - self.hint_label.setObjectName("HintLabel") + self.hint_label.setObjectName(f"{type(self).__name__}Label") self.hint_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter) self.line_edit.layout().setContentsMargins(0, 0, 10, 0) self.line_edit.layout().addWidget(self.hint_label) @@ -191,20 +195,16 @@ class IndicatorLineEdit(QWidget): completer.popup().setItemDelegate(QStyledItemDelegate(self)) completer.popup().setAlternatingRowColors(True) self.line_edit.setCompleter(completer) - self.layout.addWidget(self.line_edit) + layout.addWidget(self.line_edit) if edit_func is not None: self.indicator_label = QLabel() - self.indicator_label.setPixmap( - qta_icon("ei.info-circle", color="gray").pixmap(16, 16) - ) + self.indicator_label.setPixmap(qta_icon("ei.info-circle", color="gray").pixmap(16, 16)) self.indicator_label.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) - self.layout.addWidget(self.indicator_label) + layout.addWidget(self.indicator_label) if not placeholder: _translate = QCoreApplication.translate - self.line_edit.setPlaceholderText( - _translate(self.__class__.__name__, "Default") - ) + self.line_edit.setPlaceholderText(_translate(self.__class__.__name__, "Default")) self.edit_func = edit_func self.save_func = save_func @@ -233,9 +233,7 @@ class IndicatorLineEdit(QWidget): def __indicator(self, res, reason=None): color = "green" if res else "red" - self.indicator_label.setPixmap( - qta_icon("ei.info-circle", color=color).pixmap(16, 16) - ) + self.indicator_label.setPixmap(qta_icon("ei.info-circle", color=color).pixmap(16, 16)) if reason: self.indicator_label.setToolTip(reason) else: @@ -297,16 +295,16 @@ class PathEdit(IndicatorLineEdit): compl_model = QFileSystemModel() def __init__( - self, - path: str = "", - file_type: QFileDialog.FileType = QFileDialog.AnyFile, - type_filter: str = "", - name_filter: str = "", - placeholder: str = "", - edit_func: Callable[[str], Tuple[bool, str, str]] = None, - save_func: Callable[[str], None] = None, - horiz_policy: QSizePolicy = QSizePolicy.Expanding, - parent=None, + self, + path: str = "", + file_type: QFileDialog.FileType = QFileDialog.AnyFile, + type_filter: str = "", + name_filter: str = "", + placeholder: str = "", + edit_func: Callable[[str], Tuple[bool, str, str]] = None, + save_func: Callable[[str], None] = None, + horiz_policy: QSizePolicy = QSizePolicy.Expanding, + parent=None, ): try: self.compl_model.setOptions( @@ -320,7 +318,7 @@ class PathEdit(IndicatorLineEdit): self.compl_model.setRootPath(path) self.completer.setModel(self.compl_model) - edit_func = self._wrap_edit_function(edit_func) + edit_func = self.__wrap_edit_function(edit_func) super(PathEdit, self).__init__( text=path, @@ -331,11 +329,12 @@ class PathEdit(IndicatorLineEdit): horiz_policy=horiz_policy, parent=parent, ) - self.setObjectName("PathEdit") - self.line_edit.setMinimumSize(QSize(300, 0)) + self.setObjectName(type(self).__name__) + self.line_edit.setMinimumSize(QSize(250, 0)) self.path_select = QToolButton(self) - self.path_select.setObjectName("path_select") - self.layout.addWidget(self.path_select) + self.path_select.setObjectName(f"{type(self).__name__}Button") + layout = self.layout() + layout.addWidget(self.path_select) _translate = QCoreApplication.translate self.path_select.setText(_translate("PathEdit", "Browse...")) @@ -361,7 +360,7 @@ class PathEdit(IndicatorLineEdit): self.line_edit.setText(names[0]) self.compl_model.setRootPath(names[0]) - def _wrap_edit_function(self, edit_function: Callable[[str], Tuple[bool, str, str]]): + def __wrap_edit_function(self, edit_function: Callable[[str], Tuple[bool, str, str]]): if edit_function: return lambda text: edit_function(os.path.expanduser(text) if text.startswith("~") else text) @@ -478,9 +477,7 @@ class SelectViewWidget(QWidget): def __init__(self, icon_view: bool): super(SelectViewWidget, self).__init__() self.icon_view = icon_view - self.setStyleSheet( - """QPushButton{border: none; background-color: transparent}""" - ) + self.setStyleSheet("""QPushButton{border: none; background-color: transparent}""") self.icon_view_button = QPushButton() self.list_view = QPushButton() if icon_view: @@ -505,7 +502,9 @@ class SelectViewWidget(QWidget): return self.icon_view def icon(self): - self.icon_view_button.setIcon(qta_icon("mdi.view-grid-outline", "ei.th-large", color="orange")) + self.icon_view_button.setIcon( + qta_icon("mdi.view-grid-outline", "ei.th-large", color="orange") + ) self.list_view.setIcon(qta_icon("fa5s.list", "ei.th-list")) self.icon_view = False self.toggled.emit() @@ -589,9 +588,7 @@ class ButtonLineEdit(QLineEdit): "QLineEdit {padding-right: %dpx; }" % (buttonSize.width() + frameWidth + 1) ) self.setMinimumSize( - max( - self.minimumSizeHint().width(), buttonSize.width() + frameWidth * 2 + 2 - ), + max(self.minimumSizeHint().width(), buttonSize.width() + frameWidth * 2 + 2), max( self.minimumSizeHint().height(), buttonSize.height() + frameWidth * 2 + 2, diff --git a/rare/utils/legendary_utils.py b/rare/utils/legendary_utils.py index 77e09788..a32de593 100644 --- a/rare/utils/legendary_utils.py +++ b/rare/utils/legendary_utils.py @@ -157,6 +157,19 @@ class VerifyWorker(QRunnable): self.signals.summary.emit(len(failed), len(missing), self.app_name) +# FIXME: lk: ah ef me sideways, we can't even import this thing properly +# FIXME: lk: so copy it here +def resolve_aliases(core: LegendaryCore, name): + # make sure aliases exist if not yet created + core.update_aliases(force=False) + name = name.strip() + # resolve alias (if any) to real app name + return core.lgd.config.get( + section='Legendary.aliases', option=name, + fallback=core.lgd.aliases.get(name.lower(), name) + ) + + def import_game(core: LegendaryCore, app_name: str, path: str) -> str: _tr = QCoreApplication.translate logger.info(f"Import {app_name}") diff --git a/rare/utils/models.py b/rare/utils/models.py index 37b152ec..54743e4e 100644 --- a/rare/utils/models.py +++ b/rare/utils/models.py @@ -2,7 +2,7 @@ import os import platform from dataclasses import field, dataclass from multiprocessing import Queue -from typing import Union, List +from typing import Union, List, Optional from PyQt5.QtCore import QObject, pyqtSignal @@ -46,9 +46,9 @@ class InstallDownloadModel: @dataclass class InstallQueueItemModel: - status_q: Queue = None - download: InstallDownloadModel = None - options: InstallOptionsModel = None + status_q: Optional[Queue] = None + download: Optional[InstallDownloadModel] = None + options: Optional[InstallOptionsModel] = None def __bool__(self): return ( @@ -105,12 +105,12 @@ class PathSpec: @dataclass class ApiResults: - game_list: list = None - dlcs: dict = None - bit32_games: list = None - mac_games: list = None - no_asset_games: list = None - saves: list = None + game_list: Optional[list] = None + dlcs: Optional[dict] = None + bit32_games: Optional[list] = None + mac_games: Optional[list] = None + no_asset_games: Optional[list] = None + saves: Optional[list] = None def __bool__(self): return ( diff --git a/rare/utils/paths.py b/rare/utils/paths.py index 971d60f0..ef9284d0 100644 --- a/rare/utils/paths.py +++ b/rare/utils/paths.py @@ -1,13 +1,13 @@ -import os -import pathlib +from pathlib import Path + from PyQt5.QtCore import QStandardPaths -resources_path = pathlib.Path(__file__).absolute().parent.parent.joinpath("resources") -data_dir = os.path.join(QStandardPaths.writableLocation(QStandardPaths.DataLocation), "rare") -cache_dir = os.path.join(QStandardPaths.writableLocation(QStandardPaths.CacheLocation), "rare") -image_dir = os.path.join(data_dir, "images") -tmp_dir = os.path.join(cache_dir, "tmp") +resources_path = Path(__file__).absolute().parent.parent.joinpath("resources") +data_dir = Path(QStandardPaths.writableLocation(QStandardPaths.DataLocation), "rare") +cache_dir = Path(QStandardPaths.writableLocation(QStandardPaths.CacheLocation), "rare") +image_dir = data_dir.joinpath("images") +tmp_dir = cache_dir.joinpath("tmp") for path in (data_dir, cache_dir, image_dir, tmp_dir): - if not os.path.exists(path): - os.makedirs(path) + if not path.exists(): + path.mkdir(parents=True) diff --git a/setup.py b/setup.py index 9e2aac2b..7870e58c 100644 --- a/setup.py +++ b/setup.py @@ -13,13 +13,13 @@ requirements = [ "QtAwesome", "psutil", "pypresence", - 'pywin32; platform_system == "Windows"' + 'pywin32; platform_system == "Windows"', ] optional_reqs = dict( webview=[ 'pywebview[gtk]; platform_system == "Linux"', - 'pywebview[cef]; platform_system == "Windows"' + 'pywebview[cef]; platform_system == "Windows"', ] )