diff --git a/misc/qrc2py.sh b/misc/qrc2py.sh index 3eb738b9..04a74082 100755 --- a/misc/qrc2py.sh +++ b/misc/qrc2py.sh @@ -1,16 +1,48 @@ -#!/bin/sh +#!/bin/bash cwd="$(pwd)" cd "$(dirname "$0")"/../ || exit -pyrcc5 -compress 6 \ - rare/resources/resources.qrc \ - -o rare/resources/resources.py -pyrcc5 -compress 6 \ - rare/resources/stylesheets/RareStyle/stylesheet.qrc \ - -o rare/resources/stylesheets/RareStyle/__init__.py -pyrcc5 -compress 6 \ - rare/resources/stylesheets/ChildOfMetropolis/stylesheet.qrc \ - -o rare/resources/stylesheets/ChildOfMetropolis/__init__.py +resources=( + "rare/resources/images/" + "rare/resources/colors/" + "rare/resources/resources.qrc" +) + +resources_changed=0 + +for r in "${resources[@]}" +do + if [[ $(git diff --name-only HEAD "$r") ]] + then + resources_changed=1 + fi +done + +if [[ $resources_changed -eq 1 ]] +then + echo "Re-compiling main resources" + pyrcc5 -compress 6 \ + rare/resources/resources.qrc \ + -o rare/resources/resources.py +fi + +if [[ $(git diff --name-only HEAD "rare/resources/stylesheets/RareStyle/") ]] +then + echo "Re-compiling RareStyle stylesheet resources" + pyrcc5 -compress 6 \ + rare/resources/stylesheets/RareStyle/stylesheet.qrc \ + -o rare/resources/stylesheets/RareStyle/__init__.py +fi + + +if [[ $(git diff --name-only HEAD "rare/resources/stylesheets/ChildOfMetropolis/") ]] +then + echo "Re-compiling ChildOfMetropolis stylesheet resources" + pyrcc5 -compress 6 \ + rare/resources/stylesheets/ChildOfMetropolis/stylesheet.qrc \ + -o rare/resources/stylesheets/ChildOfMetropolis/__init__.py +fi + cd "$cwd" || exit diff --git a/rare/app.py b/rare/app.py index b3bc055e..f343052c 100644 --- a/rare/app.py +++ b/rare/app.py @@ -8,7 +8,7 @@ from datetime import datetime from typing import Optional import requests.exceptions -from PyQt5.QtCore import QThreadPool, QTimer, pyqtSlot +from PyQt5.QtCore import QThreadPool, QTimer, pyqtSlot, Qt from PyQt5.QtWidgets import QApplication, QMessageBox from requests import HTTPError @@ -128,6 +128,8 @@ def start(args): sys.excepthook = excepthook while True: + QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) + QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) app = App(args) exit_code = app.exec_() # if not restart diff --git a/rare/components/dialogs/install_dialog.py b/rare/components/dialogs/install_dialog.py index d9cbf953..7d2becf2 100644 --- a/rare/components/dialogs/install_dialog.py +++ b/rare/components/dialogs/install_dialog.py @@ -5,23 +5,33 @@ from typing import Tuple, List, Union, Optional from PyQt5.QtCore import Qt, QObject, QRunnable, QThreadPool, pyqtSignal, pyqtSlot, QSettings from PyQt5.QtGui import QCloseEvent, QKeyEvent -from PyQt5.QtWidgets import QDialog, QFileDialog, QCheckBox, QLayout +from PyQt5.QtWidgets import QDialog, QFileDialog, QCheckBox, QLayout, QWidget, QVBoxLayout, QApplication from legendary.models.downloading import ConditionCheckResult from legendary.models.game import Game from legendary.utils.selective_dl import get_sdl_appname -from rare.lgndr.api_arguments import LgndrInstallGameArgs -from rare.lgndr.api_exception import LgndrException -from rare.lgndr.api_monkeys import LgndrIndirectStatus from rare.lgndr.cli import LegendaryCLI from rare.lgndr.core import LegendaryCore +from rare.lgndr.glue.arguments import LgndrInstallGameArgs +from rare.lgndr.glue.exception import LgndrException +from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.models.install import InstallDownloadModel, InstallQueueItemModel from rare.shared import LegendaryCoreSingleton, ApiResultsSingleton, ArgumentsSingleton from rare.ui.components.dialogs.install_dialog import Ui_InstallDialog +from rare.ui.components.dialogs.install_dialog_advanced import Ui_InstallDialogAdvanced from rare.utils import config_helper from rare.utils.extra_widgets import PathEdit from rare.utils.misc import get_size -from rare.widgets.collabsible_widget import CollabsibleWidget +from rare.widgets.collapsible_widget import CollapsibleFrame + + +class InstallDialogAdvanced(CollapsibleFrame): + def __init__(self, parent=None): + widget = QWidget() + title = widget.tr("Advanced Options") + self.ui = Ui_InstallDialogAdvanced() + self.ui.setupUi(widget) + super(InstallDialogAdvanced, self).__init__(widget=widget, title=title, parent=parent) class InstallDialog(QDialog): @@ -43,11 +53,12 @@ class InstallDialog(QDialog): if not self.dl_item.options.overlay else Game(app_name=self.app_name, app_title="Epic Overlay") ) - self.ui.advanced_layout.setParent(None) - self.advanced_widget = CollabsibleWidget( - child_layout=self.ui.advanced_layout, title=self.tr("Advanced options"), parent=self - ) - self.ui.collapsible_layout.addWidget(self.advanced_widget) + + self.advanced = InstallDialogAdvanced(parent=self) + self.ui.advanced_layout.addWidget(self.advanced) + + self.selectable = CollapsibleFrame(widget=None, title=self.tr("Optional downloads"), parent=self) + self.ui.selectable_layout.addWidget(self.selectable) self.game_path = self.game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value", "") @@ -64,7 +75,7 @@ class InstallDialog(QDialog): header = self.tr("Update") if update else self.tr("Install") self.ui.install_dialog_label.setText(f'

{header} "{self.game.app_title}"

') - self.setWindowTitle(f'{self.windowTitle()} - {header} "{self.game.app_title}"') + self.setWindowTitle(f'{QApplication.instance().applicationName()} - {header} "{self.game.app_title}"') if not self.dl_item.options.base_path: self.dl_item.options.base_path = self.core.lgd.config.get( @@ -112,19 +123,23 @@ class InstallDialog(QDialog): if pf.system() == "Darwin" and "Mac" in platforms: self.ui.platform_combo.setCurrentIndex(platforms.index("Mac")) - self.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0)) - self.ui.max_workers_spin.valueChanged.connect(self.option_changed) + self.advanced.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0)) + self.advanced.ui.max_workers_spin.valueChanged.connect(self.option_changed) - self.ui.max_memory_spin.setValue(self.core.lgd.config.getint("Legendary", "max_memory", fallback=0)) - self.ui.max_memory_spin.valueChanged.connect(self.option_changed) + self.advanced.ui.max_memory_spin.setValue(self.core.lgd.config.getint("Legendary", "max_memory", fallback=0)) + self.advanced.ui.max_memory_spin.valueChanged.connect(self.option_changed) - self.ui.dl_optimizations_check.stateChanged.connect(self.option_changed) - self.ui.force_download_check.stateChanged.connect(self.option_changed) - self.ui.ignore_space_check.stateChanged.connect(self.option_changed) - self.ui.download_only_check.stateChanged.connect(lambda: self.non_reload_option_changed("download_only")) - self.ui.shortcut_check.stateChanged.connect(lambda: self.non_reload_option_changed("shortcut")) + self.advanced.ui.dl_optimizations_check.stateChanged.connect(self.option_changed) + self.advanced.ui.force_download_check.stateChanged.connect(self.option_changed) + self.advanced.ui.ignore_space_check.stateChanged.connect(self.option_changed) + self.advanced.ui.download_only_check.stateChanged.connect( + lambda: self.non_reload_option_changed("download_only") + ) + self.ui.shortcut_check.stateChanged.connect( + lambda: self.non_reload_option_changed("shortcut") + ) - self.sdl_list_cbs: List[TagCheckBox] = [] + self.selectable_checks: List[TagCheckBox] = [] self.config_tags: Optional[List[str]] = None self.setup_sdl_list("Mac" if pf.system() == "Darwin" and "Mac" in platforms else "Windows") @@ -133,23 +148,24 @@ class InstallDialog(QDialog): if self.dl_item.options.overlay: self.ui.platform_label.setVisible(False) self.ui.platform_combo.setVisible(False) - self.ui.ignore_space_label.setVisible(False) - self.ui.ignore_space_check.setVisible(False) - self.ui.download_only_label.setVisible(False) - self.ui.download_only_check.setVisible(False) + self.advanced.ui.ignore_space_label.setVisible(False) + self.advanced.ui.ignore_space_check.setVisible(False) + self.advanced.ui.download_only_label.setVisible(False) + self.advanced.ui.download_only_check.setVisible(False) self.ui.shortcut_label.setVisible(False) self.ui.shortcut_check.setVisible(False) - self.ui.sdl_list_label.setVisible(False) - self.ui.sdl_list_frame.setVisible(False) + self.selectable.setVisible(False) if pf.system() == "Darwin": self.ui.shortcut_check.setDisabled(True) self.ui.shortcut_check.setChecked(False) self.ui.shortcut_check.setToolTip(self.tr("Creating a shortcut is not supported on MacOS")) - self.ui.install_prereqs_label.setEnabled(False) - self.ui.install_prereqs_check.setEnabled(False) - self.ui.install_prereqs_check.stateChanged.connect(lambda: self.non_reload_option_changed("install_prereqs")) + self.advanced.ui.install_prereqs_label.setEnabled(False) + self.advanced.ui.install_prereqs_check.setEnabled(False) + self.advanced.ui.install_prereqs_check.stateChanged.connect( + lambda: self.non_reload_option_changed("install_prereqs") + ) self.non_reload_option_changed("shortcut") @@ -157,7 +173,7 @@ class InstallDialog(QDialog): self.ui.verify_button.clicked.connect(self.verify_clicked) self.ui.install_button.clicked.connect(self.install_clicked) - self.ui.install_prereqs_check.setChecked(self.dl_item.options.install_prereqs) + self.advanced.ui.install_prereqs_check.setChecked(self.dl_item.options.install_prereqs) self.ui.install_dialog_layout.setSizeConstraint(QLayout.SetFixedSize) @@ -171,20 +187,22 @@ class InstallDialog(QDialog): @pyqtSlot(str) def setup_sdl_list(self, platform="Windows"): - for cb in self.sdl_list_cbs: + for cb in self.selectable_checks: cb.disconnect() cb.deleteLater() - self.sdl_list_cbs.clear() + self.selectable_checks.clear() if config_tags := self.core.lgd.config.get(self.game.app_name, 'install_tags', fallback=None): self.config_tags = config_tags.split(",") config_disable_sdl = self.core.lgd.config.getboolean(self.game.app_name, 'disable_sdl', fallback=False) sdl_name = get_sdl_appname(self.game.app_name) if not config_disable_sdl and sdl_name is not None: - self.ui.sdl_list_text.hide() # FIXME: this should be updated whenever platform changes sdl_data = self.core.get_sdl_data(sdl_name, platform=platform) if sdl_data: + widget = QWidget(self.selectable) + layout = QVBoxLayout(widget) + layout.setSpacing(0) for tag, info in sdl_data.items(): cb = TagCheckBox(info["name"], info["tags"]) if tag == "__required": @@ -193,30 +211,29 @@ class InstallDialog(QDialog): if self.config_tags is not None: if all(elem in self.config_tags for elem in info["tags"]): cb.setChecked(True) - self.ui.sdl_list_layout.addWidget(cb) - self.sdl_list_cbs.append(cb) - for cb in self.sdl_list_cbs: + layout.addWidget(cb) + self.selectable_checks.append(cb) + for cb in self.selectable_checks: cb.stateChanged.connect(self.option_changed) + self.selectable.setWidget(widget) else: - self.ui.sdl_list_text.show() - self.ui.sdl_list_label.setEnabled(False) - self.ui.sdl_list_frame.setEnabled(False) + self.selectable.setDisabled(True) def get_options(self): self.dl_item.options.base_path = self.install_dir_edit.text() if not self.update else None - self.dl_item.options.max_workers = self.ui.max_workers_spin.value() - self.dl_item.options.shared_memory = self.ui.max_memory_spin.value() - self.dl_item.options.order_opt = self.ui.dl_optimizations_check.isChecked() - self.dl_item.options.force = self.ui.force_download_check.isChecked() - self.dl_item.options.ignore_space = self.ui.ignore_space_check.isChecked() - self.dl_item.options.no_install = self.ui.download_only_check.isChecked() + self.dl_item.options.max_workers = self.advanced.ui.max_workers_spin.value() + self.dl_item.options.shared_memory = self.advanced.ui.max_memory_spin.value() + self.dl_item.options.order_opt = self.advanced.ui.dl_optimizations_check.isChecked() + self.dl_item.options.force = self.advanced.ui.force_download_check.isChecked() + self.dl_item.options.ignore_space = self.advanced.ui.ignore_space_check.isChecked() + self.dl_item.options.no_install = self.advanced.ui.download_only_check.isChecked() self.dl_item.options.platform = self.ui.platform_combo.currentText() - self.dl_item.options.install_prereqs = self.ui.install_prereqs_check.isChecked() + self.dl_item.options.install_prereqs = self.advanced.ui.install_prereqs_check.isChecked() self.dl_item.options.create_shortcut = self.ui.shortcut_check.isChecked() - if self.sdl_list_cbs: + if self.selectable_checks: self.dl_item.options.install_tag = [""] - for cb in self.sdl_list_cbs: + for cb in self.selectable_checks: if data := cb.isChecked(): # noinspection PyTypeChecker self.dl_item.options.install_tag.extend(data) @@ -253,12 +270,12 @@ class InstallDialog(QDialog): def non_reload_option_changed(self, option: str): if option == "download_only": - self.dl_item.options.no_install = self.ui.download_only_check.isChecked() + self.dl_item.options.no_install = self.advanced.ui.download_only_check.isChecked() elif option == "shortcut": QSettings().setValue("create_shortcut", self.ui.shortcut_check.isChecked()) self.dl_item.options.create_shortcut = self.ui.shortcut_check.isChecked() elif option == "install_prereqs": - self.dl_item.options.install_prereqs = self.ui.install_prereqs_check.isChecked() + self.dl_item.options.install_prereqs = self.advanced.ui.install_prereqs_check.isChecked() def cancel_clicked(self): if self.config_tags: @@ -292,13 +309,13 @@ class InstallDialog(QDialog): self.ui.cancel_button.setEnabled(True) if pf.system() == "Windows" or ArgumentsSingleton().debug: if dl_item.igame.prereq_info and not dl_item.igame.prereq_info.get("installed", False): - self.ui.install_prereqs_check.setEnabled(True) - self.ui.install_prereqs_label.setEnabled(True) - self.ui.install_prereqs_check.setChecked(True) + self.advanced.ui.install_prereqs_check.setEnabled(True) + self.advanced.ui.install_prereqs_label.setEnabled(True) + self.advanced.ui.install_prereqs_check.setChecked(True) prereq_name = dl_item.igame.prereq_info.get("name", "") prereq_path = os.path.split(dl_item.igame.prereq_info.get("path", ""))[-1] prereq_desc = prereq_name if prereq_name else prereq_path - self.ui.install_prereqs_check.setText( + self.advanced.ui.install_prereqs_check.setText( self.tr("Also install: {}").format(prereq_desc) ) if self.silent: @@ -333,7 +350,7 @@ class InstallDialog(QDialog): self.threadpool.clear() self.threadpool.waitForDone() self.result_ready.emit(self.dl_item) - a0.accept() + super(InstallDialog, self).closeEvent(a0) def keyPressEvent(self, e: QKeyEvent) -> None: if e.key() == Qt.Key_Escape: @@ -403,7 +420,4 @@ class TagCheckBox(QCheckBox): self.tags = tags def isChecked(self) -> Union[bool, List[str]]: - if super(TagCheckBox, self).isChecked(): - return self.tags - else: - return False + return self.tags if super(TagCheckBox, self).isChecked() else False diff --git a/rare/components/tabs/__init__.py b/rare/components/tabs/__init__.py index b6710a9e..03c245a9 100644 --- a/rare/components/tabs/__init__.py +++ b/rare/components/tabs/__init__.py @@ -1,4 +1,4 @@ -from PyQt5.QtCore import QSize, pyqtSignal +from PyQt5.QtCore import QSize, pyqtSignal, pyqtSlot from PyQt5.QtWidgets import QMenu, QTabWidget, QWidget, QWidgetAction, QShortcut, QMessageBox from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ArgumentsSingleton @@ -23,9 +23,7 @@ class TabWidget(QTabWidget): self.args = ArgumentsSingleton() disabled_tab = 3 if not self.args.offline else 1 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")) @@ -53,12 +51,10 @@ class TabWidget(QTabWidget): self.addTab(QWidget(), "") self.setTabEnabled(disabled_tab, False) # Button - self.account = QWidget() - self.addTab(self.account, "") + self.addTab(QWidget(), "") self.setTabEnabled(disabled_tab + 1, False) self.account_widget = AccountWidget(self) - self.account_widget.exit_app.connect(self.exit_app) self.account_widget.logout.connect(self.logout) account_action = QWidgetAction(self) account_action.setDefaultWidget(self.account_widget) @@ -115,6 +111,7 @@ class TabWidget(QTabWidget): self.tabBar().setMinimumWidth(self.width()) super(TabWidget, self).resizeEvent(event) + @pyqtSlot() def logout(self): # FIXME: Don't allow logging out if there are active downloads if self.downloads_tab.is_download_active: @@ -135,4 +132,4 @@ class TabWidget(QTabWidget): if reply == QMessageBox.Yes: self.core.lgd.invalidate_userdata() - self.exit_app(-133742) # restart exit code + self.exit_app.emit(-133742) # restart exit code diff --git a/rare/components/tabs/account/__init__.py b/rare/components/tabs/account/__init__.py index a5b6e1e5..5aa48f1d 100644 --- a/rare/components/tabs/account/__init__.py +++ b/rare/components/tabs/account/__init__.py @@ -8,16 +8,12 @@ from rare.utils.misc import icon class AccountWidget(QWidget): - # int: exit code - exit_app: pyqtSignal = pyqtSignal(int) - logout = pyqtSignal() + logout: pyqtSignal = pyqtSignal() def __init__(self, parent): super(AccountWidget, self).__init__(parent=parent) self.core = LegendaryCoreSingleton() self.signals = GlobalSignalsSingleton() - # FIXME: This is why widgets should be decoupled from procedures. - # FIXME: pass downloads tab as argument to check if there are active downloads username = self.core.lgd.userdata.get("display_name") if not username: @@ -30,7 +26,7 @@ class AccountWidget(QWidget): ) ) self.logout_button = QPushButton(self.tr("Logout")) - self.logout_button.clicked.connect(lambda: self.logout.emit()) + self.logout_button.clicked.connect(self.logout) layout = QVBoxLayout(self) layout.addWidget(QLabel(self.tr("Account"))) diff --git a/rare/components/tabs/downloads/__init__.py b/rare/components/tabs/downloads/__init__.py index d08ce848..952935ce 100644 --- a/rare/components/tabs/downloads/__init__.py +++ b/rare/components/tabs/downloads/__init__.py @@ -17,7 +17,7 @@ from legendary.models.game import Game, InstalledGame from rare.components.dialogs.install_dialog import InstallDialog from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget, DlWidget from rare.components.tabs.downloads.download_thread import DownloadThread -from rare.lgndr.downloading import UIUpdate +from rare.lgndr.models.downloading import UIUpdate from rare.models.install import InstallOptionsModel, InstallQueueItemModel from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton from rare.ui.components.tabs.downloads.downloads_tab import Ui_DownloadsTab diff --git a/rare/components/tabs/downloads/download_thread.py b/rare/components/tabs/downloads/download_thread.py index 923dd775..6933b2f4 100644 --- a/rare/components/tabs/downloads/download_thread.py +++ b/rare/components/tabs/downloads/download_thread.py @@ -10,9 +10,9 @@ from typing import List, Optional, Dict from PyQt5.QtCore import QThread, pyqtSignal, QProcess from legendary.core import LegendaryCore -from rare.lgndr.api_monkeys import DLManagerSignals from rare.lgndr.cli import LegendaryCLI -from rare.lgndr.downloading import UIUpdate +from rare.lgndr.glue.monkeys import DLManagerSignals +from rare.lgndr.models.downloading import UIUpdate from rare.models.install import InstallQueueItemModel from rare.shared import GlobalSignalsSingleton, ArgumentsSingleton diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py index 835c1289..d75569e7 100644 --- a/rare/components/tabs/games/__init__.py +++ b/rare/components/tabs/games/__init__.py @@ -26,7 +26,7 @@ from .game_widgets.installing_game_widget import InstallingGameWidget from .game_widgets.uninstalled_icon_widget import UninstalledIconWidget from .game_widgets.uninstalled_list_widget import UninstalledListWidget from .head_bar import GameListHeadBar -from .import_sync import ImportSyncTabs +from .integrations import IntegrationsTabs logger = getLogger("GamesTab") @@ -60,8 +60,9 @@ class GamesTab(QStackedWidget): self.addWidget(self.games) self.head_bar = GameListHeadBar(parent=self.games) - self.head_bar.import_clicked.connect(self.show_import) - self.head_bar.egl_sync_clicked.connect(self.show_egl_sync) + self.head_bar.goto_import.connect(self.show_import) + self.head_bar.goto_egl_sync.connect(self.show_egl_sync) + self.head_bar.goto_eos_ubisoft.connect(self.show_eos_ubisoft) self.games.layout().addWidget(self.head_bar) self.game_info_tabs = GameInfoTabs(self.dlcs, self.game_utils, self) @@ -73,9 +74,9 @@ class GamesTab(QStackedWidget): ) self.game_info_tabs.info.uninstalled.connect(lambda x: self.setCurrentWidget(self.games)) - self.import_sync_tabs = ImportSyncTabs(self) - self.import_sync_tabs.back_clicked.connect(lambda: self.setCurrentWidget(self.games)) - self.addWidget(self.import_sync_tabs) + self.integrations_tabs = IntegrationsTabs(self) + self.integrations_tabs.back_clicked.connect(lambda: self.setCurrentWidget(self.games)) + self.addWidget(self.integrations_tabs) for i in self.game_list: if i.app_name.startswith("UE_4"): @@ -193,13 +194,20 @@ class GamesTab(QStackedWidget): i_widget.leaveEvent(None) l_widget.update_text() + @pyqtSlot() def show_import(self): - self.setCurrentWidget(self.import_sync_tabs) - self.import_sync_tabs.show_import() + self.setCurrentWidget(self.integrations_tabs) + self.integrations_tabs.show_import() - def show_egl_sync(self, idx): - self.setCurrentWidget(self.import_sync_tabs) - self.import_sync_tabs.show_egl_sync() + @pyqtSlot() + def show_egl_sync(self): + self.setCurrentWidget(self.integrations_tabs) + self.integrations_tabs.show_egl_sync() + + @pyqtSlot() + def show_eos_ubisoft(self): + self.setCurrentWidget(self.integrations_tabs) + self.integrations_tabs.show_eos_ubisoft() def show_game_info(self, app_name): self.game_info_tabs.update_game(app_name) diff --git a/rare/components/tabs/games/game_info/__init__.py b/rare/components/tabs/games/game_info/__init__.py index ec3b1c82..0ebec2a4 100644 --- a/rare/components/tabs/games/game_info/__init__.py +++ b/rare/components/tabs/games/game_info/__init__.py @@ -1,12 +1,12 @@ from PyQt5.QtCore import Qt from PyQt5.QtGui import QKeyEvent +from rare.components.tabs.games.game_utils import GameUtils from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton from rare.utils.extra_widgets import SideTabWidget from .game_dlc import GameDlc from .game_info import GameInfo from .game_settings import GameSettings -from ..game_utils import GameUtils class GameInfoTabs(SideTabWidget): diff --git a/rare/components/tabs/games/head_bar.py b/rare/components/tabs/games/head_bar.py index e22ca957..06fe1627 100644 --- a/rare/components/tabs/games/head_bar.py +++ b/rare/components/tabs/games/head_bar.py @@ -4,7 +4,7 @@ from PyQt5.QtWidgets import ( QPushButton, QWidget, QHBoxLayout, - QComboBox, + QComboBox, QToolButton, QMenu, QAction, ) from qtawesome import IconWidget @@ -14,7 +14,10 @@ from rare.utils.misc import icon class GameListHeadBar(QWidget): - filterChanged = pyqtSignal(str) + filterChanged: pyqtSignal = pyqtSignal(str) + goto_import: pyqtSignal = pyqtSignal() + goto_egl_sync: pyqtSignal = pyqtSignal() + goto_eos_ubisoft: pyqtSignal = pyqtSignal() def __init__(self, parent=None): super(GameListHeadBar, self).__init__(parent=parent) @@ -58,13 +61,24 @@ class GameListHeadBar(QWidget): self.filter.currentIndexChanged.connect(self.filter_changed) - self.import_game = QPushButton(icon("mdi.import", "fa.arrow-down"), self.tr("Import Game")) - self.import_clicked = self.import_game.clicked + integrations_menu = QMenu(self) + import_action = QAction(icon("mdi.import", "fa.arrow-down"), self.tr("Import Game"), integrations_menu) - self.egl_sync = QPushButton(icon("mdi.sync", "fa.refresh"), self.tr("Sync with EGL")) - self.egl_sync_clicked = self.egl_sync.clicked - # FIXME: Until it is ready - # self.egl_sync.setEnabled(False) + import_action.triggered.connect(self.goto_import) + egl_sync_action = QAction(icon("mdi.sync", "fa.refresh"), self.tr("Sync with EGL"), integrations_menu) + egl_sync_action.triggered.connect(self.goto_egl_sync) + + eos_ubisoft_action = QAction(icon("mdi.rocket", "fa.rocket"), self.tr("Epic Overlay and Ubisoft"), integrations_menu) + eos_ubisoft_action.triggered.connect(self.goto_eos_ubisoft) + + integrations_menu.addAction(import_action) + integrations_menu.addAction(egl_sync_action) + integrations_menu.addAction(eos_ubisoft_action) + + integrations = QToolButton(self) + integrations.setText(self.tr("Integrations")) + integrations.setMenu(integrations_menu) + integrations.setPopupMode(QToolButton.InstantPopup) self.search_bar = ButtonLineEdit("fa.search", placeholder_text=self.tr("Search Game")) self.search_bar.setObjectName("search_bar") @@ -97,10 +111,9 @@ class GameListHeadBar(QWidget): layout = QHBoxLayout() layout.setContentsMargins(0, 5, 0, 5) layout.addWidget(self.filter) - layout.addStretch(1) - layout.addWidget(self.import_game) - layout.addWidget(self.egl_sync) - layout.addStretch(2) + layout.addStretch(0) + layout.addWidget(integrations) + layout.addStretch(5) layout.addWidget(self.search_bar) layout.addStretch(2) layout.addWidget(self.installed_icon) diff --git a/rare/components/tabs/games/import_sync/__init__.py b/rare/components/tabs/games/import_sync/__init__.py deleted file mode 100644 index cba2a520..00000000 --- a/rare/components/tabs/games/import_sync/__init__.py +++ /dev/null @@ -1,45 +0,0 @@ -from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSpacerItem, QSizePolicy - -from rare.utils.extra_widgets import SideTabWidget -from .egl_sync_group import EGLSyncGroup -from .import_group import ImportGroup - - -class ImportSyncTabs(SideTabWidget): - def __init__(self, parent=None): - super(ImportSyncTabs, self).__init__(show_back=True, parent=parent) - self.import_widget = ImportSyncWidget( - ImportGroup(self), - self.tr("To import games from Epic Games Store, please enable EGL Sync."), - self, - ) - self.addTab(self.import_widget, self.tr("Import Games")) - - self.egl_sync_widget = ImportSyncWidget( - EGLSyncGroup(self), - self.tr("To import EGL games from directories, please use Import Game."), - self, - ) - self.addTab(self.egl_sync_widget, self.tr("Sync with EGL")) - - self.tabBar().setCurrentIndex(1) - - def show_import(self): - self.setCurrentIndex(1) - - def show_egl_sync(self): - self.setCurrentIndex(2) - - -class ImportSyncWidget(QWidget): - def __init__(self, widget: QWidget, info: str, parent=None): - super(ImportSyncWidget, self).__init__(parent=parent) - self.info = QLabel(f"

{info}

") - - layout = QVBoxLayout() - layout.addWidget(widget) - layout.addWidget(self.info) - layout.addItem( - QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) - ) - self.setLayout(layout) diff --git a/rare/components/tabs/games/integrations/__init__.py b/rare/components/tabs/games/integrations/__init__.py new file mode 100644 index 00000000..8f0c5485 --- /dev/null +++ b/rare/components/tabs/games/integrations/__init__.py @@ -0,0 +1,66 @@ +from typing import Optional + +from PyQt5.QtCore import Qt +from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSpacerItem, QSizePolicy + +from rare.utils.extra_widgets import SideTabWidget +from .egl_sync_group import EGLSyncGroup +from .import_group import ImportGroup +from .eos_group import EOSGroup +from .ubisoft_group import UbisoftGroup + + +class IntegrationsTabs(SideTabWidget): + def __init__(self, parent=None): + super(IntegrationsTabs, self).__init__(show_back=True, parent=parent) + self.import_widget = IntegrationsWidget( + ImportGroup(self), + self.tr("To import games from Epic Games Store, please enable EGL Sync."), + self, + ) + self.addTab(self.import_widget, self.tr("Import Games")) + + self.egl_sync_widget = IntegrationsWidget( + EGLSyncGroup(self), + self.tr("To import EGL games from directories, please use Import Game."), + self, + ) + self.addTab(self.egl_sync_widget, self.tr("Sync with EGL")) + + self.eos_ubisoft = IntegrationsWidget( + None, + self.tr(""), + self, + ) + self.eos_ubisoft.addWidget(UbisoftGroup(self.eos_ubisoft)) + self.eos_ubisoft.addWidget(EOSGroup(self.eos_ubisoft)) + self.addTab(self.eos_ubisoft, self.tr("Epic Overlay and Ubisoft")) + + self.tabBar().setCurrentIndex(1) + + def show_import(self): + self.setCurrentIndex(1) + + def show_egl_sync(self): + self.setCurrentIndex(2) + + def show_eos_ubisoft(self): + self.setCurrentIndex(3) + + +class IntegrationsWidget(QWidget): + def __init__(self, widget: Optional[QWidget], info: str, parent=None): + super(IntegrationsWidget, self).__init__(parent=parent) + self.info = QLabel(f"{info}") + + layout = QVBoxLayout() + if widget is not None: + layout.addWidget(widget) + layout.addWidget(self.info) + layout.addItem( + QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding) + ) + self.setLayout(layout) + + def addWidget(self, widget: QWidget, stretch: int = 0, alignment: Qt.AlignmentFlag = Qt.Alignment()): + self.layout().insertWidget(self.layout().count() - 2, widget, stretch, alignment) diff --git a/rare/components/tabs/games/import_sync/egl_sync_group.py b/rare/components/tabs/games/integrations/egl_sync_group.py similarity index 87% rename from rare/components/tabs/games/import_sync/egl_sync_group.py rename to rare/components/tabs/games/integrations/egl_sync_group.py index 79d3ab4d..f1ecdc97 100644 --- a/rare/components/tabs/games/import_sync/egl_sync_group.py +++ b/rare/components/tabs/games/integrations/egl_sync_group.py @@ -4,17 +4,17 @@ from logging import getLogger from typing import Tuple, Iterable, List from PyQt5.QtCore import Qt, QThreadPool, QRunnable, pyqtSlot, pyqtSignal -from PyQt5.QtWidgets import QGroupBox, QListWidgetItem, QFileDialog, QMessageBox +from PyQt5.QtWidgets import QGroupBox, QListWidgetItem, QFileDialog, QMessageBox, QFrame -from rare.lgndr.api_exception import LgndrException +from rare.lgndr.glue.exception import LgndrException from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton -from rare.ui.components.tabs.games.import_sync.egl_sync_group import Ui_EGLSyncGroup -from rare.ui.components.tabs.games.import_sync.egl_sync_list_group import ( +from rare.ui.components.tabs.games.integrations.egl_sync_group import Ui_EGLSyncGroup +from rare.ui.components.tabs.games.integrations.egl_sync_list_group import ( Ui_EGLSyncListGroup, ) from rare.utils.extra_widgets import PathEdit -from rare.utils.models import PathSpec from rare.utils.misc import WineResolver +from rare.utils.models import PathSpec logger = getLogger("EGLSync") @@ -207,51 +207,50 @@ class EGLSyncListItem(QListWidgetItem): return self.game.app_title -class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup): +class EGLSyncListGroup(QGroupBox): action_errors = pyqtSignal(list) def __init__(self, export: bool, parent=None): super(EGLSyncListGroup, self).__init__(parent=parent) - self.setupUi(self) + self.ui = Ui_EGLSyncListGroup() + self.ui.setupUi(self) + self.ui.list.setFrameShape(QFrame.NoFrame) self.core = LegendaryCoreSingleton() self.signals = GlobalSignalsSingleton() - self.list.setProperty("noBorder", 1) - # TODO: Convert the CSS and the code to adhere to NoFrame - # self.list.setFrameShape(self.list.NoFrame) self.export = export if export: self.setTitle(self.tr("Exportable games")) - self.label.setText(self.tr("No games to export to EGL")) - self.action_button.setText(self.tr("Export")) + self.ui.label.setText(self.tr("No games to export to EGL")) + self.ui.action_button.setText(self.tr("Export")) self.list_func = self.core.egl_get_exportable else: self.setTitle(self.tr("Importable games")) - self.label.setText(self.tr("No games to import from EGL")) - self.action_button.setText(self.tr("Import")) + self.ui.label.setText(self.tr("No games to import from EGL")) + self.ui.action_button.setText(self.tr("Import")) self.list_func = self.core.egl_get_importable - self.list.itemDoubleClicked.connect( + self.ui.list.itemDoubleClicked.connect( lambda item: item.setCheckState(Qt.Unchecked) if item.checkState() != Qt.Unchecked else item.setCheckState(Qt.Checked) ) - self.list.itemChanged.connect(self.has_selected) + self.ui.list.itemChanged.connect(self.has_selected) - self.select_all_button.clicked.connect(lambda: self.mark(Qt.Checked)) - self.select_none_button.clicked.connect(lambda: self.mark(Qt.Unchecked)) + self.ui.select_all_button.clicked.connect(lambda: self.mark(Qt.Checked)) + self.ui.select_none_button.clicked.connect(lambda: self.mark(Qt.Unchecked)) - self.action_button.clicked.connect(self.action) + self.ui.action_button.clicked.connect(self.action) self.action_errors.connect(self.show_errors) def has_selected(self): for item in self.items: if item.is_checked(): - self.action_button.setEnabled(True) + self.ui.action_button.setEnabled(True) return - self.action_button.setEnabled(False) + self.ui.action_button.setEnabled(False) def mark(self, state): for item in self.items: @@ -259,17 +258,17 @@ class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup): def populate(self, enabled: bool): if enabled: - self.list.clear() + self.ui.list.clear() for item in self.list_func(): try: - i = EGLSyncListItem(item, self.export, self.list) + i = EGLSyncListItem(item, self.export, self.ui.list) except AttributeError: logger.error(f"{item.app_name} does not work. Ignoring") else: - self.list.addItem(i) - self.label.setVisible(not enabled or not bool(self.list.count())) - self.list.setVisible(enabled and bool(self.list.count())) - self.buttons_widget.setVisible(enabled and bool(self.list.count())) + self.ui.list.addItem(i) + self.ui.label.setVisible(not enabled or not bool(self.ui.list.count())) + self.ui.list.setVisible(enabled and bool(self.ui.list.count())) + self.ui.buttons_widget.setVisible(enabled and bool(self.ui.list.count())) def action(self): imported: List = [] @@ -280,7 +279,7 @@ class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup): errors.append(e) else: imported.append(item.app_name) - self.list.takeItem(self.list.row(item)) + self.ui.list.takeItem(self.ui.list.row(item)) if not self.export and imported: self.signals.update_gamelist.emit(imported) self.populate(True) @@ -301,7 +300,7 @@ class EGLSyncListGroup(QGroupBox, Ui_EGLSyncListGroup): def items(self) -> Iterable[EGLSyncListItem]: # for i in range(self.list.count()): # yield self.list.item(i) - return [self.list.item(i) for i in range(self.list.count())] + return [self.ui.list.item(i) for i in range(self.ui.list.count())] class EGLSyncWorker(QRunnable): diff --git a/rare/components/tabs/settings/widgets/eos.py b/rare/components/tabs/games/integrations/eos_group.py similarity index 89% rename from rare/components/tabs/settings/widgets/eos.py rename to rare/components/tabs/games/integrations/eos_group.py index 45a5b96a..30f7a034 100644 --- a/rare/components/tabs/settings/widgets/eos.py +++ b/rare/components/tabs/games/integrations/eos_group.py @@ -5,11 +5,11 @@ from typing import List from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool from PyQt5.QtWidgets import QGroupBox, QMessageBox - from legendary.lfs import eos -from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton -from rare.ui.components.tabs.settings.widgets.eos_widget import Ui_EosWidget + from rare.models.install import InstallOptionsModel +from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton +from rare.ui.components.tabs.games.integrations.eos_widget import Ui_EosWidget logger = getLogger("EOS") @@ -42,9 +42,9 @@ class CheckForUpdateWorker(QRunnable): self.signals.update_available.emit(self.core.overlay_update_available) -class EosWidget(QGroupBox, Ui_EosWidget): - def __init__(self): - super(EosWidget, self).__init__() +class EOSGroup(QGroupBox, Ui_EosWidget): + def __init__(self, parent=None): + super(EOSGroup, self).__init__(parent=parent) self.setupUi(self) self.core = LegendaryCoreSingleton() self.signals = GlobalSignalsSingleton() @@ -55,7 +55,6 @@ class EosWidget(QGroupBox, Ui_EosWidget): self.uninstall_button.clicked.connect(self.uninstall_overlay) self.update_button.setVisible(False) - self.update_info_lbl.setVisible(False) self.overlay = self.core.lgd.get_overlay_install_info() self.signals.overlay_installation_finished.connect(self.overlay_installation_finished) @@ -66,12 +65,12 @@ class EosWidget(QGroupBox, Ui_EosWidget): self.update_button.clicked.connect(lambda: self.install_overlay(True)) if self.overlay: # installed - self.installed_version_lbl.setText(self.overlay.version) - self.installed_path_lbl.setText(self.overlay.install_path) - self.info_stack.setCurrentIndex(0) + self.installed_version_lbl.setText(f"{self.overlay.version}") + self.installed_path_lbl.setText(f"{self.overlay.install_path}") + self.overlay_stack.setCurrentIndex(0) else: - self.info_stack.setCurrentIndex(1) - self.enable_gb.setDisabled(True) + self.overlay_stack.setCurrentIndex(1) + self.enable_frame.setDisabled(True) if platform.system() == "Windows": self.current_prefix = None @@ -84,7 +83,7 @@ class EosWidget(QGroupBox, Ui_EosWidget): for pfx in pfxs: self.select_pfx_combo.addItem(pfx.replace(os.path.expanduser("~/"), "~/")) if not pfxs: - self.enable_gb.setDisabled(True) + self.enable_frame.setDisabled(True) else: self.select_pfx_combo.setCurrentIndex(0) @@ -111,7 +110,6 @@ class EosWidget(QGroupBox, Ui_EosWidget): def check_for_update(self): def worker_finished(update_available): self.update_button.setVisible(update_available) - self.update_info_lbl.setVisible(update_available) self.update_check_button.setDisabled(False) if not update_available: self.update_check_button.setText(self.tr("No update available")) @@ -129,14 +127,13 @@ class EosWidget(QGroupBox, Ui_EosWidget): QMessageBox.warning(self, "Error", self.tr("Something went wrong, when installing overlay")) return - self.info_stack.setCurrentIndex(0) - self.installed_version_lbl.setText(self.overlay.version) - self.installed_path_lbl.setText(self.overlay.install_path) + self.overlay_stack.setCurrentIndex(0) + self.installed_version_lbl.setText(f"{self.overlay.version}") + self.installed_path_lbl.setText(f"{self.overlay.install_path}") self.update_button.setVisible(False) - self.update_info_lbl.setVisible(False) - self.enable_gb.setEnabled(True) + self.enable_frame.setEnabled(True) def update_select_combo(self, i: None): if i is None: @@ -215,8 +212,8 @@ class EosWidget(QGroupBox, Ui_EosWidget): base_path = os.path.expanduser("~/legendary/.overlay") if update: if not self.overlay: - self.info_stack.setCurrentIndex(1) - self.enable_gb.setDisabled(True) + self.overlay_stack.setCurrentIndex(1) + self.enable_frame.setDisabled(True) QMessageBox.warning(self, "Warning", self.tr("Overlay is not installed. Could not update")) return base_path = self.overlay.install_path @@ -229,7 +226,7 @@ class EosWidget(QGroupBox, Ui_EosWidget): def uninstall_overlay(self): if not self.core.is_overlay_installed(): logger.error('No legendary-managed overlay installation found.') - self.info_stack.setCurrentIndex(1) + self.overlay_stack.setCurrentIndex(1) return if QMessageBox.No == QMessageBox.question( @@ -248,6 +245,6 @@ class EosWidget(QGroupBox, Ui_EosWidget): logger.warning(f"{prefix}: {e}") self.core.remove_overlay_install() - self.info_stack.setCurrentIndex(1) + self.overlay_stack.setCurrentIndex(1) - self.enable_gb.setDisabled(True) + self.enable_frame.setDisabled(True) diff --git a/rare/components/tabs/games/import_sync/import_group.py b/rare/components/tabs/games/integrations/import_group.py similarity index 93% rename from rare/components/tabs/games/import_sync/import_group.py rename to rare/components/tabs/games/integrations/import_group.py index 29a17ff5..806b74fc 100644 --- a/rare/components/tabs/games/import_sync/import_group.py +++ b/rare/components/tabs/games/integrations/import_group.py @@ -10,11 +10,11 @@ from PyQt5.QtCore import Qt, QModelIndex, pyqtSignal, QRunnable, QObject, QThrea from PyQt5.QtGui import QStandardItemModel from PyQt5.QtWidgets import QFileDialog, QGroupBox, QCompleter, QTreeView, QHeaderView, QMessageBox -from rare.lgndr.api_arguments import LgndrImportGameArgs -from rare.lgndr.api_monkeys import LgndrIndirectStatus from rare.lgndr.cli import LegendaryCLI +from rare.lgndr.glue.arguments import LgndrImportGameArgs +from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton, ApiResultsSingleton -from rare.ui.components.tabs.games.import_sync.import_group import Ui_ImportGroup +from rare.ui.components.tabs.games.integrations.import_group import Ui_ImportGroup from rare.utils.extra_widgets import IndicatorLineEdit, PathEdit from rare.widgets.elide_label import ElideLabel @@ -173,7 +173,7 @@ class ImportGroup(QGroupBox): self.path_edit = PathEdit( self.core.get_default_install_dir(), QFileDialog.DirectoryOnly, - edit_func=self.path_edit_cb, + edit_func=self.path_edit_callback, parent=self, ) self.path_edit.textChanged.connect(self.path_changed) @@ -184,7 +184,7 @@ class ImportGroup(QGroupBox): completer=AppNameCompleter( app_names=[(i.app_name, i.app_title) for i in self.api_results.game_list] ), - edit_func=self.app_name_edit_cb, + edit_func=self.app_name_edit_callback, parent=self, ) self.app_name_edit.textChanged.connect(self.app_name_changed) @@ -192,6 +192,7 @@ class ImportGroup(QGroupBox): self.ui.import_folder_check.stateChanged.connect(self.import_folder_changed) self.ui.import_dlcs_check.setEnabled(False) + self.ui.import_dlcs_check.stateChanged.connect(self.import_dlcs_changed) self.ui.import_button.setEnabled(False) self.ui.import_button.clicked.connect( @@ -203,7 +204,7 @@ class ImportGroup(QGroupBox): self.threadpool = QThreadPool.globalInstance() - def path_edit_cb(self, path) -> Tuple[bool, str, str]: + def path_edit_callback(self, path) -> Tuple[bool, str, str]: if os.path.exists(path): if os.path.exists(os.path.join(path, ".egstore")): return True, path, "" @@ -213,7 +214,8 @@ class ImportGroup(QGroupBox): return False, path, PathEdit.reasons.dir_not_exist return False, path, "" - def path_changed(self, path): + @pyqtSlot(str) + def path_changed(self, path: str): self.info_label.setText("") self.ui.import_folder_check.setCheckState(Qt.Unchecked) if self.path_edit.is_valid: @@ -221,7 +223,7 @@ class ImportGroup(QGroupBox): else: self.app_name_edit.setText("") - def app_name_edit_cb(self, text) -> Tuple[bool, str, str]: + def app_name_edit_callback(self, text) -> Tuple[bool, str, str]: if not text: return False, text, "" if text in self.app_name_list: @@ -229,6 +231,7 @@ class ImportGroup(QGroupBox): else: return False, text, IndicatorLineEdit.reasons.game_not_installed + @pyqtSlot(str) def app_name_changed(self, app_name: str): self.info_label.setText("") self.ui.import_dlcs_check.setCheckState(Qt.Unchecked) @@ -241,7 +244,8 @@ class ImportGroup(QGroupBox): self.ui.import_dlcs_check.setEnabled(False) self.ui.import_button.setEnabled(False) - def import_folder_changed(self, state): + @pyqtSlot(int) + def import_folder_changed(self, state: Qt.CheckState): self.app_name_edit.setEnabled(not state) self.ui.import_dlcs_check.setCheckState(Qt.Unchecked) self.ui.import_dlcs_check.setEnabled( @@ -250,6 +254,10 @@ class ImportGroup(QGroupBox): ) self.ui.import_button.setEnabled(state or (not state and self.app_name_edit.is_valid)) + @pyqtSlot(int) + def import_dlcs_changed(self, state: Qt.CheckState): + self.ui.import_button.setEnabled(self.ui.import_folder_check.isChecked() or self.app_name_edit.is_valid) + def import_pressed(self, path=None): if not path: path = self.path_edit.text() diff --git a/rare/components/tabs/settings/widgets/ubisoft_activation.py b/rare/components/tabs/games/integrations/ubisoft_group.py similarity index 92% rename from rare/components/tabs/settings/widgets/ubisoft_activation.py rename to rare/components/tabs/games/integrations/ubisoft_group.py index 028d3c5c..f58a7431 100644 --- a/rare/components/tabs/settings/widgets/ubisoft_activation.py +++ b/rare/components/tabs/games/integrations/ubisoft_group.py @@ -3,7 +3,7 @@ import webbrowser from logging import getLogger from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool, QSize -from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QPushButton +from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QSizePolicy, QPushButton, QGroupBox, QVBoxLayout from legendary.models.game import Game from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton @@ -82,6 +82,7 @@ class UbiLinkWidget(QWidget): super(UbiLinkWidget, self).__init__() self.args = ArgumentsSingleton() layout = QHBoxLayout() + layout.setContentsMargins(0, 0, 0, 0) self.game = game self.ubi_account_id = ubi_account_id @@ -130,12 +131,13 @@ class UbiLinkWidget(QWidget): self.link_button.setDisabled(False) -class UbiActivationHelper(QObject): - def __init__(self, widget: QWidget): - super(UbiActivationHelper, self).__init__() +class UbisoftGroup(QGroupBox): + def __init__(self, parent=None): + super(UbisoftGroup, self).__init__(parent=parent) + self.setTitle(self.tr("Link Ubisoft Games")) + self.setLayout(QVBoxLayout()) self.core = LegendaryCoreSingleton() self.args = ArgumentsSingleton() - self.widget = widget self.thread_pool = QThreadPool.globalInstance() worker = UbiGetInfoWorker() @@ -147,7 +149,7 @@ class UbiActivationHelper(QObject): logger.error( "No linked ubisoft account found! Link your accounts via your browser and try again." ) - self.widget.layout().addWidget( + self.layout().addWidget( QLabel( self.tr( "Your account is not linked with Ubisoft. Please link your account first" @@ -158,10 +160,10 @@ class UbiActivationHelper(QObject): open_browser_button.clicked.connect( lambda: webbrowser.open("https://www.epicgames.com/id/link/ubisoft") ) - self.widget.layout().addWidget(open_browser_button) + self.layout().addWidget(open_browser_button) return elif ubi_account_id == "error": - self.widget.layout().addWidget(QLabel(self.tr("An error occurred"))) + self.layout().addWidget(QLabel(self.tr("An error occurred"))) return games = self.core.get_game_list(False) @@ -195,13 +197,13 @@ class UbiActivationHelper(QObject): if not uplay_games: if activated >= 1: - self.widget.layout().addWidget( + self.layout().addWidget( QLabel( self.tr("All your Ubisoft games have already been activated") ) ) else: - self.widget.layout().addWidget( + self.layout().addWidget( QLabel(self.tr("You don't own any Ubisoft games")) ) if self.args.debug: @@ -209,10 +211,10 @@ class UbiActivationHelper(QObject): Game(app_name="Test", app_title="This is a test game"), ubi_account_id, ) - self.widget.layout().addWidget(widget) + self.layout().addWidget(widget) return logger.info(f"Found {len(uplay_games)} game(s) to redeem") for game in uplay_games: widget = UbiLinkWidget(game, ubi_account_id) - self.widget.layout().addWidget(widget) + self.layout().addWidget(widget) diff --git a/rare/components/tabs/settings/legendary.py b/rare/components/tabs/settings/legendary.py index 51f22e88..996f0623 100644 --- a/rare/components/tabs/settings/legendary.py +++ b/rare/components/tabs/settings/legendary.py @@ -6,8 +6,6 @@ from typing import Tuple from PyQt5.QtCore import Qt, QRunnable, QObject, pyqtSignal, QThreadPool, QSettings from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox -from rare.components.tabs.settings.widgets.eos import EosWidget -from rare.components.tabs.settings.widgets.ubisoft_activation import UbiActivationHelper from rare.shared import LegendaryCoreSingleton from rare.ui.components.tabs.settings.legendary import Ui_LegendarySettings from rare.utils.extra_widgets import PathEdit, IndicatorLineEdit @@ -87,10 +85,6 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): ) self.locale_layout.addWidget(self.locale_edit) - self.ubi_helper = UbiActivationHelper(self.ubisoft_gb) - self.eos_widget = EosWidget() - self.left_layout.insertWidget(3, self.eos_widget, alignment=Qt.AlignTop) - self.win32_cb.setChecked(self.settings.value("win32_meta", False, bool)) self.win32_cb.stateChanged.connect(lambda: self.settings.setValue("win32_meta", self.win32_cb.isChecked())) diff --git a/rare/game_launch_helper/__init__.py b/rare/game_launch_helper/__init__.py index f684ed56..e7ed0224 100644 --- a/rare/game_launch_helper/__init__.py +++ b/rare/game_launch_helper/__init__.py @@ -7,9 +7,10 @@ from argparse import Namespace from logging import getLogger from typing import Union, Optional -from PyQt5.QtCore import QObject, QProcess, pyqtSignal, QUrl, QRunnable, QThreadPool, QSettings +from PyQt5.QtCore import QObject, QProcess, pyqtSignal, QUrl, QRunnable, QThreadPool, QSettings, Qt from PyQt5.QtGui import QDesktopServices from PyQt5.QtNetwork import QLocalServer, QLocalSocket +from PyQt5.QtWidgets import QApplication from rare.lgndr.core import LegendaryCore from rare.widgets.rare_app import RareApp @@ -217,6 +218,9 @@ class GameProcessApp(RareApp): def start_game(args: Namespace): args = InitArgs.from_argparse(args) + QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) + QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) + app = GameProcessApp(args) app.setQuitOnLastWindowClosed(True) diff --git a/rare/lgndr/cli.py b/rare/lgndr/cli.py index 1baa1094..a4216807 100644 --- a/rare/lgndr/cli.py +++ b/rare/lgndr/cli.py @@ -11,7 +11,9 @@ from legendary.models.game import Game, InstalledGame, VerifyResult from legendary.lfs.utils import validate_files from legendary.utils.selective_dl import get_sdl_appname -from .api_arguments import ( +from rare.lgndr.core import LegendaryCore +from rare.lgndr.downloader.mp.manager import DLManager +from rare.lgndr.glue.arguments import ( LgndrInstallGameArgs, LgndrImportGameArgs, LgndrVerifyGameArgs, @@ -19,9 +21,7 @@ from .api_arguments import ( LgndrInstallGameRealArgs, LgndrInstallGameRealRet, ) -from .api_monkeys import LgndrIndirectStatus, LgndrIndirectLogger -from .core import LegendaryCore -from .manager import DLManager +from rare.lgndr.glue.monkeys import LgndrIndirectStatus, LgndrIndirectLogger # fmt: off diff --git a/rare/lgndr/core.py b/rare/lgndr/core.py index b12d66ae..52fb26dc 100644 --- a/rare/lgndr/core.py +++ b/rare/lgndr/core.py @@ -1,4 +1,3 @@ -from hashlib import sha1 from multiprocessing import Queue # On Windows the monkeypatching of `run_real` below doesn't work like on Linux @@ -10,8 +9,8 @@ from legendary.models.downloading import AnalysisResult from legendary.models.game import Game, InstalledGame from legendary.models.manifest import ManifestMeta -from .api_exception import LgndrException, LgndrCoreLogHandler -from .manager import DLManager +from rare.lgndr.downloader.mp.manager import DLManager +from rare.lgndr.glue.exception import LgndrException, LgndrCoreLogHandler legendary.core.DLManager = DLManager diff --git a/rare/ui/components/tabs/games/import_sync/__init__.py b/rare/lgndr/downloader/__init__.py similarity index 100% rename from rare/ui/components/tabs/games/import_sync/__init__.py rename to rare/lgndr/downloader/__init__.py diff --git a/rare/lgndr/downloader/mp/__init__.py b/rare/lgndr/downloader/mp/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rare/lgndr/manager.py b/rare/lgndr/downloader/mp/manager.py similarity index 98% rename from rare/lgndr/manager.py rename to rare/lgndr/downloader/mp/manager.py index b9eb32d2..9a783668 100644 --- a/rare/lgndr/manager.py +++ b/rare/lgndr/downloader/mp/manager.py @@ -11,8 +11,8 @@ from legendary.downloader.mp.manager import DLManager as DLManagerReal from legendary.downloader.mp.workers import DLWorker, FileWorker from legendary.models.downloading import ChunkTask, SharedMemorySegment, TerminateWorkerTask -from .downloading import UIUpdate -from .api_monkeys import DLManagerSignals +from rare.lgndr.glue.monkeys import DLManagerSignals +from rare.lgndr.models.downloading import UIUpdate # fmt: off diff --git a/rare/lgndr/glue/__init__.py b/rare/lgndr/glue/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rare/lgndr/api_arguments.py b/rare/lgndr/glue/arguments.py similarity index 97% rename from rare/lgndr/api_arguments.py rename to rare/lgndr/glue/arguments.py index 03a28942..5bc6d0d2 100644 --- a/rare/lgndr/api_arguments.py +++ b/rare/lgndr/glue/arguments.py @@ -2,14 +2,14 @@ from dataclasses import dataclass from enum import IntEnum from typing import Callable, List, Optional, Dict -from .api_monkeys import ( +from rare.lgndr.glue.monkeys import ( LgndrIndirectStatus, GetBooleanChoiceProtocol, get_boolean_choice, verify_stdout, DLManagerSignals ) -from .downloading import UIUpdate +from rare.lgndr.models.downloading import UIUpdate """ @dataclass(kw_only=True) diff --git a/rare/lgndr/api_exception.py b/rare/lgndr/glue/exception.py similarity index 98% rename from rare/lgndr/api_exception.py rename to rare/lgndr/glue/exception.py index 11779f79..34c24c27 100644 --- a/rare/lgndr/api_exception.py +++ b/rare/lgndr/glue/exception.py @@ -1,5 +1,5 @@ import logging -import warnings +# import warnings class LgndrException(RuntimeError): diff --git a/rare/lgndr/api_monkeys.py b/rare/lgndr/glue/monkeys.py similarity index 100% rename from rare/lgndr/api_monkeys.py rename to rare/lgndr/glue/monkeys.py diff --git a/rare/lgndr/models/__init__.py b/rare/lgndr/models/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rare/lgndr/downloading.py b/rare/lgndr/models/downloading.py similarity index 100% rename from rare/lgndr/downloading.py rename to rare/lgndr/models/downloading.py diff --git a/rare/models/install.py b/rare/models/install.py index d9a487c9..6b5d6122 100644 --- a/rare/models/install.py +++ b/rare/models/install.py @@ -6,7 +6,7 @@ from typing import List, Optional, Callable, Dict from legendary.models.downloading import AnalysisResult, ConditionCheckResult from legendary.models.game import Game, InstalledGame -from rare.lgndr.manager import DLManager +from rare.lgndr.downloader.mp.manager import DLManager @dataclass diff --git a/rare/resources/stylesheets/ChildOfMetropolis/__init__.py b/rare/resources/stylesheets/ChildOfMetropolis/__init__.py index 0fc74bf6..5e825b3c 100644 Binary files a/rare/resources/stylesheets/ChildOfMetropolis/__init__.py and b/rare/resources/stylesheets/ChildOfMetropolis/__init__.py differ diff --git a/rare/resources/stylesheets/ChildOfMetropolis/stylesheet.qss b/rare/resources/stylesheets/ChildOfMetropolis/stylesheet.qss index 8d84174f..c0d0defa 100644 --- a/rare/resources/stylesheets/ChildOfMetropolis/stylesheet.qss +++ b/rare/resources/stylesheets/ChildOfMetropolis/stylesheet.qss @@ -65,6 +65,7 @@ QTableView::item, QHeaderView::section, QTableView QTableCornerButton::section, QFrame[frameShape="6"], +QGroupBox, QLineEdit, QTextEdit, QTimeEdit, @@ -115,15 +116,12 @@ QPushButton { QToolButton { height: 1.10em; } +QFrame[frameShape="0"] { + border-width: 0px; +} QFrame[frameShape="6"] { border-radius: 4px; } -QFrame[noBorder="1"], -QListView[noBorder="1"], -QScrollArea[noBorder="1"], -QStackedWidget[noBorder="1"] { - border-color: transparent; -} QComboBox { background-color: #DADDDE; } @@ -383,6 +381,7 @@ QTableView::indicator { border-style: solid; background-color: #C2C4C5; } +QGroupBox::indicator, QCheckBox::indicator, QRadioButton::indicator, QListView::indicator, @@ -391,6 +390,9 @@ QTableView::indicator { width: 11px; height: 11px; } +QGroupBox::indicator { + padding: 1px; +} QGroupBox::indicator:disabled, QCheckBox::indicator:disabled, QRadioButton::indicator:disabled, @@ -482,6 +484,7 @@ QGroupBox::title { */ background-color: #B2D3DE; } +QToolBox::tab:disabled, QGroupBox::title:disabled { border-color: #767778; background-color: #A8AAAB; diff --git a/rare/resources/stylesheets/RareStyle/__init__.py b/rare/resources/stylesheets/RareStyle/__init__.py index 63d76ed0..c1f610f0 100644 Binary files a/rare/resources/stylesheets/RareStyle/__init__.py and b/rare/resources/stylesheets/RareStyle/__init__.py differ diff --git a/rare/resources/stylesheets/RareStyle/stylesheet.qss b/rare/resources/stylesheets/RareStyle/stylesheet.qss index e04063c3..1fdef16d 100644 --- a/rare/resources/stylesheets/RareStyle/stylesheet.qss +++ b/rare/resources/stylesheets/RareStyle/stylesheet.qss @@ -65,6 +65,7 @@ QTableView::item, QHeaderView::section, QTableView QTableCornerButton::section, QFrame[frameShape="6"], +QGroupBox, QLineEdit, QTextEdit, QTimeEdit, @@ -115,15 +116,12 @@ QPushButton { QToolButton { height: 1.10em; } +QFrame[frameShape="0"] { + border-width: 0px; +} QFrame[frameShape="6"] { border-radius: 4px; } -QFrame[noBorder="1"], -QListView[noBorder="1"], -QScrollArea[noBorder="1"], -QStackedWidget[noBorder="1"] { - border-color: transparent; -} QComboBox { background-color: rgb( 51, 54, 59); } @@ -383,6 +381,7 @@ QTableView::indicator { border-style: solid; background-color: rgb( 32, 34, 37); } +QGroupBox::indicator, QCheckBox::indicator, QRadioButton::indicator, QListView::indicator, @@ -391,6 +390,9 @@ QTableView::indicator { width: 11px; height: 11px; } +QGroupBox::indicator { + padding: 0px; +} QGroupBox::indicator:disabled, QCheckBox::indicator:disabled, QRadioButton::indicator:disabled, @@ -482,6 +484,7 @@ QGroupBox::title { */ background-color: rgb( 42, 40, 63); } +QToolBox::tab:disabled, QGroupBox::title:disabled { border-color: rgb( 67, 71, 77); background-color: rgb( 41, 43, 47); diff --git a/rare/ui/components/dialogs/install_dialog.py b/rare/ui/components/dialogs/install_dialog.py index 01c1a99a..389a42f1 100644 --- a/rare/ui/components/dialogs/install_dialog.py +++ b/rare/ui/components/dialogs/install_dialog.py @@ -14,8 +14,8 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_InstallDialog(object): def setupUi(self, InstallDialog): InstallDialog.setObjectName("InstallDialog") - InstallDialog.resize(383, 438) - InstallDialog.setWindowTitle("Rare") + InstallDialog.resize(324, 224) + InstallDialog.setWindowTitle("InstallDialog") self.install_dialog_layout = QtWidgets.QFormLayout(InstallDialog) self.install_dialog_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.install_dialog_layout.setObjectName("install_dialog_layout") @@ -47,119 +47,12 @@ class Ui_InstallDialog(object): self.shortcut_check.setText("") self.shortcut_check.setObjectName("shortcut_check") self.install_dialog_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.shortcut_check) - self.sdl_list_label = QtWidgets.QLabel(InstallDialog) - self.sdl_list_label.setObjectName("sdl_list_label") - self.install_dialog_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.sdl_list_label) - self.sdl_list_frame = QtWidgets.QFrame(InstallDialog) - self.sdl_list_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) - self.sdl_list_frame.setFrameShadow(QtWidgets.QFrame.Raised) - self.sdl_list_frame.setObjectName("sdl_list_frame") - self.sdl_list_layout = QtWidgets.QVBoxLayout(self.sdl_list_frame) - self.sdl_list_layout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize) - self.sdl_list_layout.setContentsMargins(-1, 0, -1, 0) - self.sdl_list_layout.setSpacing(0) - self.sdl_list_layout.setObjectName("sdl_list_layout") - self.sdl_list_text = QtWidgets.QLabel(self.sdl_list_frame) - self.sdl_list_text.setObjectName("sdl_list_text") - self.sdl_list_layout.addWidget(self.sdl_list_text) - self.install_dialog_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.sdl_list_frame) - self.collapsible_layout = QtWidgets.QVBoxLayout() - self.collapsible_layout.setObjectName("collapsible_layout") - self.advanced_layout = QtWidgets.QFormLayout() - self.advanced_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.selectable_layout = QtWidgets.QVBoxLayout() + self.selectable_layout.setObjectName("selectable_layout") + self.install_dialog_layout.setLayout(4, QtWidgets.QFormLayout.SpanningRole, self.selectable_layout) + self.advanced_layout = QtWidgets.QVBoxLayout() self.advanced_layout.setObjectName("advanced_layout") - self.max_workers_label = QtWidgets.QLabel(InstallDialog) - self.max_workers_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) - self.max_workers_label.setObjectName("max_workers_label") - self.advanced_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.max_workers_label) - self.max_workers_layout = QtWidgets.QHBoxLayout() - self.max_workers_layout.setObjectName("max_workers_layout") - self.max_workers_spin = QtWidgets.QSpinBox(InstallDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.max_workers_spin.sizePolicy().hasHeightForWidth()) - self.max_workers_spin.setSizePolicy(sizePolicy) - self.max_workers_spin.setObjectName("max_workers_spin") - self.max_workers_layout.addWidget(self.max_workers_spin) - self.max_workers_info_label = QtWidgets.QLabel(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.max_workers_info_label.setFont(font) - self.max_workers_info_label.setObjectName("max_workers_info_label") - self.max_workers_layout.addWidget(self.max_workers_info_label) - self.advanced_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.max_workers_layout) - self.max_memory_label = QtWidgets.QLabel(InstallDialog) - self.max_memory_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) - self.max_memory_label.setObjectName("max_memory_label") - self.advanced_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.max_memory_label) - self.max_memory_layout = QtWidgets.QHBoxLayout() - self.max_memory_layout.setObjectName("max_memory_layout") - self.max_memory_spin = QtWidgets.QSpinBox(InstallDialog) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.max_memory_spin.sizePolicy().hasHeightForWidth()) - self.max_memory_spin.setSizePolicy(sizePolicy) - self.max_memory_spin.setMinimum(0) - self.max_memory_spin.setMaximum(10240) - self.max_memory_spin.setSingleStep(128) - self.max_memory_spin.setProperty("value", 1024) - self.max_memory_spin.setObjectName("max_memory_spin") - self.max_memory_layout.addWidget(self.max_memory_spin) - self.max_memory_info_label = QtWidgets.QLabel(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.max_memory_info_label.setFont(font) - self.max_memory_info_label.setObjectName("max_memory_info_label") - self.max_memory_layout.addWidget(self.max_memory_info_label) - self.advanced_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.max_memory_layout) - self.install_prereqs_label = QtWidgets.QLabel(InstallDialog) - self.install_prereqs_label.setObjectName("install_prereqs_label") - self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_label) - self.install_prereqs_check = QtWidgets.QCheckBox(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.install_prereqs_check.setFont(font) - self.install_prereqs_check.setText("") - self.install_prereqs_check.setChecked(False) - self.install_prereqs_check.setObjectName("install_prereqs_check") - self.advanced_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.install_prereqs_check) - self.dl_optimizations_label = QtWidgets.QLabel(InstallDialog) - self.dl_optimizations_label.setObjectName("dl_optimizations_label") - self.advanced_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.dl_optimizations_label) - self.dl_optimizations_check = QtWidgets.QCheckBox(InstallDialog) - self.dl_optimizations_check.setText("") - self.dl_optimizations_check.setChecked(False) - self.dl_optimizations_check.setObjectName("dl_optimizations_check") - self.advanced_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.dl_optimizations_check) - self.force_download_label = QtWidgets.QLabel(InstallDialog) - self.force_download_label.setObjectName("force_download_label") - self.advanced_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.force_download_label) - self.force_download_check = QtWidgets.QCheckBox(InstallDialog) - self.force_download_check.setText("") - self.force_download_check.setObjectName("force_download_check") - self.advanced_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.force_download_check) - self.ignore_space_label = QtWidgets.QLabel(InstallDialog) - self.ignore_space_label.setObjectName("ignore_space_label") - self.advanced_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.ignore_space_label) - self.ignore_space_check = QtWidgets.QCheckBox(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.ignore_space_check.setFont(font) - self.ignore_space_check.setObjectName("ignore_space_check") - self.advanced_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.ignore_space_check) - self.download_only_label = QtWidgets.QLabel(InstallDialog) - self.download_only_label.setObjectName("download_only_label") - self.advanced_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.download_only_label) - self.download_only_check = QtWidgets.QCheckBox(InstallDialog) - font = QtGui.QFont() - font.setItalic(True) - self.download_only_check.setFont(font) - self.download_only_check.setObjectName("download_only_check") - self.advanced_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.download_only_check) - self.collapsible_layout.addLayout(self.advanced_layout) - self.install_dialog_layout.setLayout(5, QtWidgets.QFormLayout.SpanningRole, self.collapsible_layout) + self.install_dialog_layout.setLayout(5, QtWidgets.QFormLayout.SpanningRole, self.advanced_layout) self.download_size_label = QtWidgets.QLabel(InstallDialog) self.download_size_label.setObjectName("download_size_label") self.install_dialog_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.download_size_label) @@ -215,20 +108,6 @@ class Ui_InstallDialog(object): self.install_dir_label.setText(_translate("InstallDialog", "Install directory")) self.platform_label.setText(_translate("InstallDialog", "Platform")) self.shortcut_label.setText(_translate("InstallDialog", "Create shortcut")) - self.sdl_list_label.setText(_translate("InstallDialog", "Optional packs")) - self.sdl_list_text.setText(_translate("InstallDialog", "None")) - self.max_workers_label.setText(_translate("InstallDialog", "Max workers")) - self.max_workers_info_label.setText(_translate("InstallDialog", "Less is slower. (0: Default)")) - self.max_memory_label.setText(_translate("InstallDialog", "Max shared memory")) - self.max_memory_spin.setSuffix(_translate("InstallDialog", "MiB")) - self.max_memory_info_label.setText(_translate("InstallDialog", "Less is slower (0: Default)")) - self.install_prereqs_label.setText(_translate("InstallDialog", "Install prerequisites")) - self.dl_optimizations_label.setText(_translate("InstallDialog", "Enable reordering")) - self.force_download_label.setText(_translate("InstallDialog", "Force redownload")) - self.ignore_space_label.setText(_translate("InstallDialog", "Ignore free space")) - self.ignore_space_check.setText(_translate("InstallDialog", "Use with caution!")) - self.download_only_label.setText(_translate("InstallDialog", "Download only")) - self.download_only_check.setText(_translate("InstallDialog", "Do not try to install.")) self.download_size_label.setText(_translate("InstallDialog", "Download size")) self.download_size_text.setText(_translate("InstallDialog", "Click verify...")) self.install_size_label.setText(_translate("InstallDialog", "Total install size")) diff --git a/rare/ui/components/dialogs/install_dialog.ui b/rare/ui/components/dialogs/install_dialog.ui index 4111ce79..fb100a69 100644 --- a/rare/ui/components/dialogs/install_dialog.ui +++ b/rare/ui/components/dialogs/install_dialog.ui @@ -6,12 +6,12 @@ 0 0 - 383 - 438 + 324 + 224 - Rare + InstallDialog @@ -68,232 +68,11 @@ - - - - Optional packs - - - - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - QLayout::SetFixedSize - - - 0 - - - 0 - - - - - None - - - - - + + - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Max workers - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - - - - - - true - - - - Less is slower. (0: Default) - - - - - - - - - Max shared memory - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - - - - - - - - - - 0 - 0 - - - - MiB - - - 0 - - - 10240 - - - 128 - - - 1024 - - - - - - - - true - - - - Less is slower (0: Default) - - - - - - - - - Install prerequisites - - - - - - - - true - - - - - - - false - - - - - - - Enable reordering - - - - - - - - - - false - - - - - - - Force redownload - - - - - - - - - - - - - - Ignore free space - - - - - - - - true - - - - Use with caution! - - - - - - - Download only - - - - - - - - true - - - - Do not try to install. - - - - - - + diff --git a/rare/ui/components/dialogs/install_dialog_advanced.py b/rare/ui/components/dialogs/install_dialog_advanced.py index c853bb74..736b6d10 100644 --- a/rare/ui/components/dialogs/install_dialog_advanced.py +++ b/rare/ui/components/dialogs/install_dialog_advanced.py @@ -15,6 +15,7 @@ class Ui_InstallDialogAdvanced(object): def setupUi(self, InstallDialogAdvanced): InstallDialogAdvanced.setObjectName("InstallDialogAdvanced") InstallDialogAdvanced.resize(379, 208) + InstallDialogAdvanced.setWindowTitle("InstallDialogAdvanced") self.install_dialog_advanced_layout = QtWidgets.QFormLayout(InstallDialogAdvanced) self.install_dialog_advanced_layout.setObjectName("install_dialog_advanced_layout") self.max_workers_label = QtWidgets.QLabel(InstallDialogAdvanced) @@ -31,12 +32,12 @@ class Ui_InstallDialogAdvanced(object): self.max_workers_spin.setSizePolicy(sizePolicy) self.max_workers_spin.setObjectName("max_workers_spin") self.max_workers_layout.addWidget(self.max_workers_spin) - self.max_workers_info_label = QtWidgets.QLabel(InstallDialogAdvanced) + self.max_workers_info = QtWidgets.QLabel(InstallDialogAdvanced) font = QtGui.QFont() font.setItalic(True) - self.max_workers_info_label.setFont(font) - self.max_workers_info_label.setObjectName("max_workers_info_label") - self.max_workers_layout.addWidget(self.max_workers_info_label) + self.max_workers_info.setFont(font) + self.max_workers_info.setObjectName("max_workers_info") + self.max_workers_layout.addWidget(self.max_workers_info) self.install_dialog_advanced_layout.setLayout(0, QtWidgets.QFormLayout.FieldRole, self.max_workers_layout) self.max_memory_label = QtWidgets.QLabel(InstallDialogAdvanced) self.max_memory_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) @@ -56,16 +57,16 @@ class Ui_InstallDialogAdvanced(object): self.max_memory_spin.setProperty("value", 1024) self.max_memory_spin.setObjectName("max_memory_spin") self.max_memory_layout.addWidget(self.max_memory_spin) - self.max_memory_info_label = QtWidgets.QLabel(InstallDialogAdvanced) + self.max_memory_info = QtWidgets.QLabel(InstallDialogAdvanced) font = QtGui.QFont() font.setItalic(True) - self.max_memory_info_label.setFont(font) - self.max_memory_info_label.setObjectName("max_memory_info_label") - self.max_memory_layout.addWidget(self.max_memory_info_label) + self.max_memory_info.setFont(font) + self.max_memory_info.setObjectName("max_memory_info") + self.max_memory_layout.addWidget(self.max_memory_info) self.install_dialog_advanced_layout.setLayout(1, QtWidgets.QFormLayout.FieldRole, self.max_memory_layout) - self.install_prereqs_lbl = QtWidgets.QLabel(InstallDialogAdvanced) - self.install_prereqs_lbl.setObjectName("install_prereqs_lbl") - self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_lbl) + self.install_prereqs_label = QtWidgets.QLabel(InstallDialogAdvanced) + self.install_prereqs_label.setObjectName("install_prereqs_label") + self.install_dialog_advanced_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.install_prereqs_label) self.install_prereqs_check = QtWidgets.QCheckBox(InstallDialogAdvanced) font = QtGui.QFont() font.setItalic(True) @@ -113,13 +114,12 @@ class Ui_InstallDialogAdvanced(object): def retranslateUi(self, InstallDialogAdvanced): _translate = QtCore.QCoreApplication.translate - InstallDialogAdvanced.setWindowTitle(_translate("InstallDialogAdvanced", "Form")) self.max_workers_label.setText(_translate("InstallDialogAdvanced", "Max workers")) - self.max_workers_info_label.setText(_translate("InstallDialogAdvanced", "Less is slower. (0: Default)")) + self.max_workers_info.setText(_translate("InstallDialogAdvanced", "Less is slower. (0: Default)")) self.max_memory_label.setText(_translate("InstallDialogAdvanced", "Max shared memory")) self.max_memory_spin.setSuffix(_translate("InstallDialogAdvanced", "MiB")) - self.max_memory_info_label.setText(_translate("InstallDialogAdvanced", "Less is slower (0: Default)")) - self.install_prereqs_lbl.setText(_translate("InstallDialogAdvanced", "Install prerequisites")) + self.max_memory_info.setText(_translate("InstallDialogAdvanced", "Less is slower (0: Default)")) + self.install_prereqs_label.setText(_translate("InstallDialogAdvanced", "Install prerequisites")) self.dl_optimizations_label.setText(_translate("InstallDialogAdvanced", "Enable reordering")) self.force_download_label.setText(_translate("InstallDialogAdvanced", "Force redownload")) self.ignore_space_label.setText(_translate("InstallDialogAdvanced", "Ignore free space")) diff --git a/rare/ui/components/dialogs/install_dialog_advanced.ui b/rare/ui/components/dialogs/install_dialog_advanced.ui index 160c386f..6298e45b 100644 --- a/rare/ui/components/dialogs/install_dialog_advanced.ui +++ b/rare/ui/components/dialogs/install_dialog_advanced.ui @@ -11,7 +11,7 @@ - Form + InstallDialogAdvanced @@ -37,7 +37,7 @@ - + true @@ -88,7 +88,7 @@ - + true @@ -102,7 +102,7 @@ - + Install prerequisites diff --git a/rare/ui/components/tabs/games/integrations/__init__.py b/rare/ui/components/tabs/games/integrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/rare/ui/components/tabs/games/import_sync/egl_sync_group.py b/rare/ui/components/tabs/games/integrations/egl_sync_group.py similarity index 100% rename from rare/ui/components/tabs/games/import_sync/egl_sync_group.py rename to rare/ui/components/tabs/games/integrations/egl_sync_group.py diff --git a/rare/ui/components/tabs/games/import_sync/egl_sync_group.ui b/rare/ui/components/tabs/games/integrations/egl_sync_group.ui similarity index 100% rename from rare/ui/components/tabs/games/import_sync/egl_sync_group.ui rename to rare/ui/components/tabs/games/integrations/egl_sync_group.ui diff --git a/rare/ui/components/tabs/games/import_sync/egl_sync_list_group.py b/rare/ui/components/tabs/games/integrations/egl_sync_list_group.py similarity index 100% rename from rare/ui/components/tabs/games/import_sync/egl_sync_list_group.py rename to rare/ui/components/tabs/games/integrations/egl_sync_list_group.py diff --git a/rare/ui/components/tabs/games/import_sync/egl_sync_list_group.ui b/rare/ui/components/tabs/games/integrations/egl_sync_list_group.ui similarity index 100% rename from rare/ui/components/tabs/games/import_sync/egl_sync_list_group.ui rename to rare/ui/components/tabs/games/integrations/egl_sync_list_group.ui diff --git a/rare/ui/components/tabs/games/integrations/eos_widget.py b/rare/ui/components/tabs/games/integrations/eos_widget.py new file mode 100644 index 00000000..666d5a87 --- /dev/null +++ b/rare/ui/components/tabs/games/integrations/eos_widget.py @@ -0,0 +1,152 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'rare/ui/components/tabs/games/import_sync/eos_widget.ui' +# +# Created by: PyQt5 UI code generator 5.15.7 +# +# 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_EosWidget(object): + def setupUi(self, EosWidget): + EosWidget.setObjectName("EosWidget") + EosWidget.resize(586, 146) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(EosWidget.sizePolicy().hasHeightForWidth()) + EosWidget.setSizePolicy(sizePolicy) + EosWidget.setWindowTitle("GroupBox") + self.eos_layout = QtWidgets.QHBoxLayout(EosWidget) + self.eos_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) + self.eos_layout.setObjectName("eos_layout") + self.overlay_stack = QtWidgets.QStackedWidget(EosWidget) + self.overlay_stack.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.overlay_stack.setFrameShadow(QtWidgets.QFrame.Raised) + self.overlay_stack.setObjectName("overlay_stack") + self.overlay_info_page = QtWidgets.QWidget() + self.overlay_info_page.setObjectName("overlay_info_page") + self.formLayout_3 = QtWidgets.QFormLayout(self.overlay_info_page) + self.formLayout_3.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout_3.setFormAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft) + self.formLayout_3.setObjectName("formLayout_3") + self.installed_version_info_lbl = QtWidgets.QLabel(self.overlay_info_page) + self.installed_version_info_lbl.setObjectName("installed_version_info_lbl") + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.installed_version_info_lbl) + self.installed_version_lbl = QtWidgets.QLabel(self.overlay_info_page) + self.installed_version_lbl.setText("error") + self.installed_version_lbl.setObjectName("installed_version_lbl") + self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.installed_version_lbl) + self.installed_path_info_lbl = QtWidgets.QLabel(self.overlay_info_page) + self.installed_path_info_lbl.setObjectName("installed_path_info_lbl") + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.installed_path_info_lbl) + self.installed_path_lbl = QtWidgets.QLabel(self.overlay_info_page) + self.installed_path_lbl.setText("error") + self.installed_path_lbl.setObjectName("installed_path_lbl") + self.formLayout_3.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.installed_path_lbl) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.uninstall_button = QtWidgets.QPushButton(self.overlay_info_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.uninstall_button.sizePolicy().hasHeightForWidth()) + self.uninstall_button.setSizePolicy(sizePolicy) + self.uninstall_button.setMaximumSize(QtCore.QSize(150, 16777215)) + self.uninstall_button.setObjectName("uninstall_button") + self.horizontalLayout.addWidget(self.uninstall_button) + self.update_check_button = QtWidgets.QPushButton(self.overlay_info_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.update_check_button.sizePolicy().hasHeightForWidth()) + self.update_check_button.setSizePolicy(sizePolicy) + self.update_check_button.setMaximumSize(QtCore.QSize(150, 16777215)) + self.update_check_button.setObjectName("update_check_button") + self.horizontalLayout.addWidget(self.update_check_button) + self.update_button = QtWidgets.QPushButton(self.overlay_info_page) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.update_button.sizePolicy().hasHeightForWidth()) + self.update_button.setSizePolicy(sizePolicy) + self.update_button.setMaximumSize(QtCore.QSize(150, 16777215)) + self.update_button.setObjectName("update_button") + self.horizontalLayout.addWidget(self.update_button) + self.formLayout_3.setLayout(3, QtWidgets.QFormLayout.SpanningRole, self.horizontalLayout) + spacerItem1 = QtWidgets.QSpacerItem(6, 6, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.formLayout_3.setItem(2, QtWidgets.QFormLayout.SpanningRole, spacerItem1) + self.overlay_stack.addWidget(self.overlay_info_page) + self.overlay_install_page = QtWidgets.QWidget() + self.overlay_install_page.setObjectName("overlay_install_page") + self.formLayout = QtWidgets.QFormLayout(self.overlay_install_page) + self.formLayout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.formLayout.setFormAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft) + self.formLayout.setObjectName("formLayout") + self.label = QtWidgets.QLabel(self.overlay_install_page) + self.label.setObjectName("label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.label) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout_3.addItem(spacerItem2) + self.install_button = QtWidgets.QPushButton(self.overlay_install_page) + self.install_button.setObjectName("install_button") + self.horizontalLayout_3.addWidget(self.install_button) + self.formLayout.setLayout(2, QtWidgets.QFormLayout.SpanningRole, self.horizontalLayout_3) + spacerItem3 = QtWidgets.QSpacerItem(6, 6, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.formLayout.setItem(1, QtWidgets.QFormLayout.SpanningRole, spacerItem3) + self.overlay_stack.addWidget(self.overlay_install_page) + self.eos_layout.addWidget(self.overlay_stack) + self.enable_frame = QtWidgets.QFrame(EosWidget) + self.enable_frame.setFrameShape(QtWidgets.QFrame.StyledPanel) + self.enable_frame.setFrameShadow(QtWidgets.QFrame.Raised) + self.enable_frame.setObjectName("enable_frame") + self.verticalLayout = QtWidgets.QVBoxLayout(self.enable_frame) + self.verticalLayout.setObjectName("verticalLayout") + self.select_pfx_combo = QtWidgets.QComboBox(self.enable_frame) + self.select_pfx_combo.setObjectName("select_pfx_combo") + self.verticalLayout.addWidget(self.select_pfx_combo) + self.enabled_cb = QtWidgets.QCheckBox(self.enable_frame) + self.enabled_cb.setObjectName("enabled_cb") + self.verticalLayout.addWidget(self.enabled_cb) + self.enabled_info_label = QtWidgets.QLabel(self.enable_frame) + font = QtGui.QFont() + font.setItalic(True) + self.enabled_info_label.setFont(font) + self.enabled_info_label.setText("") + self.enabled_info_label.setObjectName("enabled_info_label") + self.verticalLayout.addWidget(self.enabled_info_label) + self.eos_layout.addWidget(self.enable_frame) + + self.retranslateUi(EosWidget) + self.overlay_stack.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(EosWidget) + + def retranslateUi(self, EosWidget): + _translate = QtCore.QCoreApplication.translate + EosWidget.setTitle(_translate("EosWidget", "Epic Overlay")) + self.installed_version_info_lbl.setText(_translate("EosWidget", "Version")) + self.installed_path_info_lbl.setText(_translate("EosWidget", "Location")) + self.uninstall_button.setText(_translate("EosWidget", "Uninstall")) + self.update_check_button.setText(_translate("EosWidget", "Check for update")) + self.update_button.setText(_translate("EosWidget", "Update")) + self.label.setText(_translate("EosWidget", "Epic Overlay Services is not installed")) + self.install_button.setText(_translate("EosWidget", "Install")) + self.enabled_cb.setText(_translate("EosWidget", "Activated")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + EosWidget = QtWidgets.QGroupBox() + ui = Ui_EosWidget() + ui.setupUi(EosWidget) + EosWidget.show() + sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/games/integrations/eos_widget.ui b/rare/ui/components/tabs/games/integrations/eos_widget.ui new file mode 100644 index 00000000..7a70d318 --- /dev/null +++ b/rare/ui/components/tabs/games/integrations/eos_widget.ui @@ -0,0 +1,259 @@ + + + EosWidget + + + + 0 + 0 + 586 + 146 + + + + + 0 + 0 + + + + GroupBox + + + Epic Overlay + + + + QLayout::SetDefaultConstraint + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + 0 + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + Version + + + + + + + error + + + + + + + Location + + + + + + + error + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Uninstall + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Check for update + + + + + + + + 0 + 0 + + + + + 150 + 16777215 + + + + Update + + + + + + + + + Qt::Vertical + + + + 6 + 6 + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft + + + + + Epic Overlay Services is not installed + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Install + + + + + + + + + Qt::Vertical + + + + 6 + 6 + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + + + + + + Activated + + + + + + + + true + + + + + + + + + + + + + + + diff --git a/rare/ui/components/tabs/games/import_sync/import_group.py b/rare/ui/components/tabs/games/integrations/import_group.py similarity index 100% rename from rare/ui/components/tabs/games/import_sync/import_group.py rename to rare/ui/components/tabs/games/integrations/import_group.py diff --git a/rare/ui/components/tabs/games/import_sync/import_group.ui b/rare/ui/components/tabs/games/integrations/import_group.ui similarity index 100% rename from rare/ui/components/tabs/games/import_sync/import_group.ui rename to rare/ui/components/tabs/games/integrations/import_group.ui diff --git a/rare/ui/components/tabs/settings/legendary.py b/rare/ui/components/tabs/settings/legendary.py index 96c62572..4cd3bc7e 100644 --- a/rare/ui/components/tabs/settings/legendary.py +++ b/rare/ui/components/tabs/settings/legendary.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.ui' # -# Created by: PyQt5 UI code generator 5.15.6 +# Created by: PyQt5 UI code generator 5.15.7 # # 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. @@ -98,12 +98,6 @@ class Ui_LegendarySettings(object): self.disable_https_check.setObjectName("disable_https_check") self.download_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.disable_https_check) self.left_layout.addWidget(self.download_group, 0, QtCore.Qt.AlignTop) - self.ubisoft_gb = QtWidgets.QGroupBox(LegendarySettings) - self.ubisoft_gb.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) - self.ubisoft_gb.setObjectName("ubisoft_gb") - self.verticalLayout = QtWidgets.QVBoxLayout(self.ubisoft_gb) - self.verticalLayout.setObjectName("verticalLayout") - self.left_layout.addWidget(self.ubisoft_gb, 0, QtCore.Qt.AlignTop) spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.left_layout.addItem(spacerItem) self.legendary_layout.addLayout(self.left_layout) @@ -165,7 +159,6 @@ class Ui_LegendarySettings(object): self.preferred_cdn_label.setText(_translate("LegendarySettings", "Preferred CDN")) self.preferred_cdn_line.setPlaceholderText(_translate("LegendarySettings", "Default")) self.disable_https_label.setText(_translate("LegendarySettings", "Disable HTTPS")) - self.ubisoft_gb.setTitle(_translate("LegendarySettings", "Link Ubisoft Games")) self.locale_group.setTitle(_translate("LegendarySettings", "Locale")) self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup")) self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests")) diff --git a/rare/ui/components/tabs/settings/legendary.ui b/rare/ui/components/tabs/settings/legendary.ui index f3e27bd5..a69ef823 100644 --- a/rare/ui/components/tabs/settings/legendary.ui +++ b/rare/ui/components/tabs/settings/legendary.ui @@ -166,17 +166,6 @@ - - - - Link Ubisoft Games - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - - diff --git a/rare/ui/components/tabs/settings/widgets/eos_widget.py b/rare/ui/components/tabs/settings/widgets/eos_widget.py deleted file mode 100644 index 947db4fd..00000000 --- a/rare/ui/components/tabs/settings/widgets/eos_widget.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/widgets/eos_widget.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_EosWidget(object): - def setupUi(self, EosWidget): - EosWidget.setObjectName("EosWidget") - EosWidget.resize(364, 218) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(EosWidget.sizePolicy().hasHeightForWidth()) - EosWidget.setSizePolicy(sizePolicy) - EosWidget.setWindowTitle("GroupBox") - self.eos_layout = QtWidgets.QHBoxLayout(EosWidget) - self.eos_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint) - self.eos_layout.setObjectName("eos_layout") - self.info_stack = QtWidgets.QStackedWidget(EosWidget) - self.info_stack.setObjectName("info_stack") - self.installed_info_page = QtWidgets.QWidget() - self.installed_info_page.setObjectName("installed_info_page") - self.installed_info_page_layout = QtWidgets.QVBoxLayout(self.installed_info_page) - self.installed_info_page_layout.setContentsMargins(0, 0, 0, 0) - self.installed_info_page_layout.setObjectName("installed_info_page_layout") - self.installed_info_gb = QtWidgets.QGroupBox(self.installed_info_page) - self.installed_info_gb.setObjectName("installed_info_gb") - self.installed_info_layout = QtWidgets.QFormLayout(self.installed_info_gb) - self.installed_info_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.installed_info_layout.setObjectName("installed_info_layout") - self.installed_version_info_lbl = QtWidgets.QLabel(self.installed_info_gb) - self.installed_version_info_lbl.setObjectName("installed_version_info_lbl") - self.installed_info_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.installed_version_info_lbl) - self.installed_version_lbl = QtWidgets.QLabel(self.installed_info_gb) - self.installed_version_lbl.setText("TextLabel") - self.installed_version_lbl.setObjectName("installed_version_lbl") - self.installed_info_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.installed_version_lbl) - self.installed_path_info_lbl = QtWidgets.QLabel(self.installed_info_gb) - self.installed_path_info_lbl.setObjectName("installed_path_info_lbl") - self.installed_info_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.installed_path_info_lbl) - self.installed_path_lbl = QtWidgets.QLabel(self.installed_info_gb) - self.installed_path_lbl.setText("TextLabel") - self.installed_path_lbl.setObjectName("installed_path_lbl") - self.installed_info_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.installed_path_lbl) - self.update_available_info_label = QtWidgets.QLabel(self.installed_info_gb) - self.update_available_info_label.setObjectName("update_available_info_label") - self.installed_info_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.update_available_info_label) - self.update_check_button = QtWidgets.QPushButton(self.installed_info_gb) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.update_check_button.sizePolicy().hasHeightForWidth()) - self.update_check_button.setSizePolicy(sizePolicy) - self.update_check_button.setMaximumSize(QtCore.QSize(150, 16777215)) - self.update_check_button.setObjectName("update_check_button") - self.installed_info_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.update_check_button) - self.uninstall_info_label = QtWidgets.QLabel(self.installed_info_gb) - self.uninstall_info_label.setObjectName("uninstall_info_label") - self.installed_info_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.uninstall_info_label) - self.uninstall_button = QtWidgets.QPushButton(self.installed_info_gb) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.uninstall_button.sizePolicy().hasHeightForWidth()) - self.uninstall_button.setSizePolicy(sizePolicy) - self.uninstall_button.setMaximumSize(QtCore.QSize(150, 16777215)) - self.uninstall_button.setObjectName("uninstall_button") - self.installed_info_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.uninstall_button) - self.update_button = QtWidgets.QPushButton(self.installed_info_gb) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Minimum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.update_button.sizePolicy().hasHeightForWidth()) - self.update_button.setSizePolicy(sizePolicy) - self.update_button.setMaximumSize(QtCore.QSize(150, 16777215)) - self.update_button.setObjectName("update_button") - self.installed_info_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.update_button) - self.update_info_lbl = QtWidgets.QLabel(self.installed_info_gb) - self.update_info_lbl.setObjectName("update_info_lbl") - self.installed_info_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.update_info_lbl) - self.installed_info_page_layout.addWidget(self.installed_info_gb, 0, QtCore.Qt.AlignTop) - self.info_stack.addWidget(self.installed_info_page) - self.install_overlay_page = QtWidgets.QWidget() - self.install_overlay_page.setObjectName("install_overlay_page") - self.install_overlay_page_layout = QtWidgets.QVBoxLayout(self.install_overlay_page) - self.install_overlay_page_layout.setContentsMargins(0, 0, 0, 0) - self.install_overlay_page_layout.setObjectName("install_overlay_page_layout") - self.install_overlay_gb = QtWidgets.QGroupBox(self.install_overlay_page) - self.install_overlay_gb.setObjectName("install_overlay_gb") - self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.install_overlay_gb) - self.verticalLayout_4.setObjectName("verticalLayout_4") - self.label = QtWidgets.QLabel(self.install_overlay_gb) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth()) - self.label.setSizePolicy(sizePolicy) - self.label.setObjectName("label") - self.verticalLayout_4.addWidget(self.label) - self.install_button = QtWidgets.QPushButton(self.install_overlay_gb) - self.install_button.setMinimumSize(QtCore.QSize(120, 0)) - self.install_button.setObjectName("install_button") - self.verticalLayout_4.addWidget(self.install_button, 0, QtCore.Qt.AlignRight) - self.install_overlay_page_layout.addWidget(self.install_overlay_gb, 0, QtCore.Qt.AlignTop) - self.info_stack.addWidget(self.install_overlay_page) - self.eos_layout.addWidget(self.info_stack) - self.enable_gb = QtWidgets.QGroupBox(EosWidget) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.enable_gb.sizePolicy().hasHeightForWidth()) - self.enable_gb.setSizePolicy(sizePolicy) - self.enable_gb.setObjectName("enable_gb") - self.enable_layout = QtWidgets.QVBoxLayout(self.enable_gb) - self.enable_layout.setObjectName("enable_layout") - self.select_pfx_combo = QtWidgets.QComboBox(self.enable_gb) - self.select_pfx_combo.setObjectName("select_pfx_combo") - self.enable_layout.addWidget(self.select_pfx_combo) - self.enabled_cb = QtWidgets.QCheckBox(self.enable_gb) - self.enabled_cb.setObjectName("enabled_cb") - self.enable_layout.addWidget(self.enabled_cb) - self.enabled_info_label = QtWidgets.QLabel(self.enable_gb) - font = QtGui.QFont() - font.setItalic(True) - self.enabled_info_label.setFont(font) - self.enabled_info_label.setText("") - self.enabled_info_label.setObjectName("enabled_info_label") - self.enable_layout.addWidget(self.enabled_info_label, 0, QtCore.Qt.AlignTop) - self.enable_layout.setStretch(2, 1) - self.eos_layout.addWidget(self.enable_gb) - - self.retranslateUi(EosWidget) - self.info_stack.setCurrentIndex(1) - QtCore.QMetaObject.connectSlotsByName(EosWidget) - - def retranslateUi(self, EosWidget): - _translate = QtCore.QCoreApplication.translate - EosWidget.setTitle(_translate("EosWidget", "Epic Overlay settings")) - self.installed_info_gb.setTitle(_translate("EosWidget", "Installed Info")) - self.installed_version_info_lbl.setText(_translate("EosWidget", "Installed version")) - self.installed_path_info_lbl.setText(_translate("EosWidget", "Installed path")) - self.update_available_info_label.setText(_translate("EosWidget", "Updates")) - self.update_check_button.setText(_translate("EosWidget", "Check for Update")) - self.uninstall_info_label.setText(_translate("EosWidget", "Uninstall")) - self.uninstall_button.setText(_translate("EosWidget", "Uninstall")) - self.update_button.setText(_translate("EosWidget", "Update")) - self.update_info_lbl.setText(_translate("EosWidget", "Install Update")) - self.install_overlay_gb.setTitle(_translate("EosWidget", "Install Overlay")) - self.label.setText(_translate("EosWidget", "No overlays are installed")) - self.install_button.setText(_translate("EosWidget", "Install")) - self.enable_gb.setTitle(_translate("EosWidget", "Enable / Disable")) - self.enabled_cb.setText(_translate("EosWidget", "Activated")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - EosWidget = QtWidgets.QGroupBox() - ui = Ui_EosWidget() - ui.setupUi(EosWidget) - EosWidget.show() - sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/widgets/eos_widget.ui b/rare/ui/components/tabs/settings/widgets/eos_widget.ui deleted file mode 100644 index 0c36b2fc..00000000 --- a/rare/ui/components/tabs/settings/widgets/eos_widget.ui +++ /dev/null @@ -1,262 +0,0 @@ - - - EosWidget - - - - 0 - 0 - 364 - 218 - - - - - 0 - 0 - - - - GroupBox - - - Epic Overlay settings - - - - QLayout::SetDefaultConstraint - - - - - 1 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Installed Info - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Installed version - - - - - - - TextLabel - - - - - - - Installed path - - - - - - - TextLabel - - - - - - - Updates - - - - - - - - 0 - 0 - - - - - 150 - 16777215 - - - - Check for Update - - - - - - - Uninstall - - - - - - - - 0 - 0 - - - - - 150 - 16777215 - - - - Uninstall - - - - - - - - 0 - 0 - - - - - 150 - 16777215 - - - - Update - - - - - - - Install Update - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Install Overlay - - - - - - - 0 - 0 - - - - No overlays are installed - - - - - - - - 120 - 0 - - - - Install - - - - - - - - - - - - - - - 0 - 0 - - - - Enable / Disable - - - - - - - - - Activated - - - - - - - - true - - - - - - - - - - - - - - - diff --git a/rare/utils/legendary_utils.py b/rare/utils/legendary_utils.py index 77fccfe6..f8d0523f 100644 --- a/rare/utils/legendary_utils.py +++ b/rare/utils/legendary_utils.py @@ -5,9 +5,9 @@ from logging import getLogger from PyQt5.QtCore import pyqtSignal, QObject, QRunnable, QStandardPaths from legendary.core import LegendaryCore -from rare.lgndr.api_arguments import LgndrVerifyGameArgs, LgndrUninstallGameArgs -from rare.lgndr.api_monkeys import LgndrIndirectStatus from rare.lgndr.cli import LegendaryCLI +from rare.lgndr.glue.arguments import LgndrVerifyGameArgs, LgndrUninstallGameArgs +from rare.lgndr.glue.monkeys import LgndrIndirectStatus from rare.shared import LegendaryCoreSingleton, ArgumentsSingleton from rare.utils import config_helper diff --git a/rare/widgets/collabsible_widget.py b/rare/widgets/collabsible_widget.py deleted file mode 100644 index f9f2280e..00000000 --- a/rare/widgets/collabsible_widget.py +++ /dev/null @@ -1,85 +0,0 @@ -from PyQt5.QtCore import QParallelAnimationGroup, Qt, QPropertyAnimation, QAbstractAnimation -from PyQt5.QtWidgets import QWidget, QFrame, QToolButton, QGridLayout, QSizePolicy, QLayout - -from rare.utils.misc import icon - -# https://newbedev.com/how-to-make-an-expandable-collapsable-section-widget-in-qt - - -class CollabsibleWidget(QWidget): - def __init__( - self, child_layout: QLayout = None, title: str = "", animation_duration: int = 200, parent=None - ): - """ - References: - # Adapted from c++ version - https://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt - """ - super(CollabsibleWidget, self).__init__(parent=parent) - - self.animationDuration = animation_duration - self.toggleAnimation = QParallelAnimationGroup() - self.contentArea = QWidget() - self.headerLine = QFrame() - self.toggleButton = QToolButton() - self.mainLayout = QGridLayout() - - toggleButton = self.toggleButton - toggleButton.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) - toggleButton.setIcon(icon("fa.arrow-right")) - toggleButton.setText(str(title)) - toggleButton.setCheckable(True) - toggleButton.setChecked(False) - - headerLine = self.headerLine - headerLine.setFrameShape(QFrame.StyledPanel) - headerLine.setFrameShadow(QFrame.Plain) - headerLine.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Maximum) - - self.contentArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) - # start out collapsed - self.contentArea.setMaximumHeight(0) - self.contentArea.setMinimumHeight(0) - # let the entire widget grow and shrink with its content - toggleAnimation = self.toggleAnimation - toggleAnimation.addAnimation(QPropertyAnimation(self, b"minimumHeight")) - toggleAnimation.addAnimation(QPropertyAnimation(self, b"maximumHeight")) - toggleAnimation.addAnimation(QPropertyAnimation(self.contentArea, b"maximumHeight")) - # don't waste space - mainLayout = self.mainLayout - mainLayout.setVerticalSpacing(0) - mainLayout.setContentsMargins(0, 0, 0, 0) - row = 0 - mainLayout.addWidget(self.toggleButton, row, 0, 1, 1, Qt.AlignLeft) - mainLayout.addWidget(self.headerLine, row, 2, 1, 1) - row += 1 - mainLayout.addWidget(self.contentArea, row, 0, 1, 3) - self.setLayout(self.mainLayout) - - def start_animation(checked): - arrow_type = icon("fa.arrow-down") if checked else icon("fa.arrow-right") - direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward - toggleButton.setIcon(arrow_type) - self.toggleAnimation.setDirection(direction) - self.toggleAnimation.start() - - self.toggleButton.clicked.connect(start_animation) - - if child_layout: - self.setContentLayout(child_layout) - - def setContentLayout(self, content_layout: QLayout): - # Not sure if this is equivalent to self.contentArea.destroy() - self.contentArea.destroy() - self.contentArea.setLayout(content_layout) - collapsedHeight = self.sizeHint().height() - self.contentArea.maximumHeight() - contentHeight = content_layout.sizeHint().height() - for i in range(self.toggleAnimation.animationCount() - 1): - spoilerAnimation = self.toggleAnimation.animationAt(i) - spoilerAnimation.setDuration(self.animationDuration) - spoilerAnimation.setStartValue(collapsedHeight) - spoilerAnimation.setEndValue(collapsedHeight + contentHeight) - contentAnimation = self.toggleAnimation.animationAt(self.toggleAnimation.animationCount() - 1) - contentAnimation.setDuration(self.animationDuration) - contentAnimation.setStartValue(0) - contentAnimation.setEndValue(contentHeight) diff --git a/rare/widgets/collapsible_widget.py b/rare/widgets/collapsible_widget.py new file mode 100644 index 00000000..dd0c7cae --- /dev/null +++ b/rare/widgets/collapsible_widget.py @@ -0,0 +1,238 @@ +from abc import abstractmethod +from typing import Optional + +from PyQt5.QtCore import QParallelAnimationGroup, Qt, QPropertyAnimation, QAbstractAnimation, QSize +from PyQt5.QtWidgets import QWidget, QFrame, QToolButton, QGridLayout, QSizePolicy, QGroupBox, QLabel + +from rare.utils.misc import icon + + +class CollapsibleBase(object): + """ + References: + # Adapted from c++ version + https://stackoverflow.com/questions/32476006/how-to-make-an-expandable-collapsable-section-widget-in-qt + # Adapted from python version + https://newbedev.com/how-to-make-an-expandable-collapsable-section-widget-in-qt + """ + def __init__(self): + self.animation_duration = None + self.toggle_animation = None + self.content_area = None + self.content_toggle_animation = None + + def setup(self, animation_duration: int = 200): + self.animation_duration = animation_duration + self.content_area: Optional[QWidget] = None + self.content_toggle_animation: Optional[QPropertyAnimation] = None + + # let the entire widget grow and shrink with its content + self.toggle_animation = QParallelAnimationGroup(self) + self.toggle_animation.addAnimation(QPropertyAnimation(self, b"minimumHeight")) + self.toggle_animation.addAnimation(QPropertyAnimation(self, b"maximumHeight")) + + @abstractmethod + def isChecked(self) -> bool: + ... + + @abstractmethod + def click(self) -> None: + ... + + @abstractmethod + def addToLayout(self, widget: QWidget) -> None: + ... + + @abstractmethod + def sizeHint(self) -> QSize: + ... + + def animationStart(self, checked): + direction = QAbstractAnimation.Forward if checked else QAbstractAnimation.Backward + self.toggle_animation.setDirection(direction) + self.toggle_animation.start() + + def setWidget(self, widget: QWidget): + if widget is None or widget is self.content_area: + return + is_checked = self.isChecked() + if self.content_area is not None: + # Collapse the parent before replacing the child + if is_checked: + self.click() + self.toggle_animation.removeAnimation(self.content_toggle_animation) + self.content_area.setParent(None) + self.content_area.deleteLater() + + self.content_area = widget + self.content_area.setParent(self) + self.content_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) + + # start out collapsed + if not is_checked: + self.content_area.setMaximumHeight(0) + self.content_area.setMinimumHeight(0) + + self.content_toggle_animation = QPropertyAnimation(self.content_area, b"maximumHeight") + self.toggle_animation.addAnimation(self.content_toggle_animation) + self.addToLayout(self.content_area) + collapsed_height = self.sizeHint().height() + content_height = self.content_area.sizeHint().height() + for i in range(self.toggle_animation.animationCount() - 1): + spoiler_animation = self.toggle_animation.animationAt(i) + spoiler_animation.setDuration(self.animation_duration) + spoiler_animation.setStartValue(collapsed_height) + spoiler_animation.setEndValue(collapsed_height + content_height) + content_animation = self.toggle_animation.animationAt(self.toggle_animation.animationCount() - 1) + content_animation.setDuration(self.animation_duration) + content_animation.setStartValue(0) + content_animation.setEndValue(content_height) + if is_checked: + self.click() + + +class CollapsibleFrame(QFrame, CollapsibleBase): + def __init__( + self, widget: QWidget = None, title: str = "", button_text: str = "", animation_duration: int = 200, parent=None + ): + super(CollapsibleFrame, self).__init__(parent=parent) + self.setup(animation_duration) + self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken) + + self.toggle_button = QToolButton(self) + self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) + self.toggle_button.setIcon(icon("fa.arrow-right")) + self.toggle_button.setText(button_text) + self.toggle_button.setCheckable(True) + self.toggle_button.setChecked(False) + + self.title_label = QLabel(title) + font = self.title_label.font() + font.setBold(True) + self.title_label.setFont(font) + self.title_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) + + # don't waste space + self.main_layout = QGridLayout(self) + self.main_layout.setVerticalSpacing(0) + self.main_layout.setContentsMargins(0, 0, 0, 0) + self.main_layout.addWidget(self.toggle_button, 0, 0, 1, 1, Qt.AlignLeft) + self.main_layout.addWidget(self.title_label, 0, 1, 1, 1) + self.main_layout.setColumnStretch(1, 1) + self.main_layout.setRowStretch(0, 0) + self.main_layout.setRowStretch(1, 1) + self.setLayout(self.main_layout) + + self.toggle_button.clicked.connect(self.animationStart) + + if widget is not None: + self.setWidget(widget) + + def isChecked(self) -> bool: + return self.toggle_button.isChecked() + + def click(self) -> None: + self.toggle_button.click() + + def addToLayout(self, widget: QWidget) -> None: + self.main_layout.addWidget(widget, 1, 0, 1, 2) + + def sizeHint(self) -> QSize: + return super(CollapsibleFrame, self).sizeHint() + + def animationStart(self, checked): + arrow_type = icon("fa.arrow-down") if checked else icon("fa.arrow-right") + self.toggle_button.setIcon(arrow_type) + super(CollapsibleFrame, self).animationStart(checked) + + +class CollapsibleGroupBox(QGroupBox, CollapsibleBase): + def __init__( + self, widget: QWidget = None, title: str = "", animation_duration: int = 200, parent=None + ): + super(CollapsibleGroupBox, self).__init__(parent=parent) + self.setup(animation_duration) + self.setTitle(title) + self.setCheckable(True) + self.setChecked(False) + + # don't waste space + self.main_layout = QVBoxLayout(self) + self.main_layout.setSpacing(0) + self.main_layout.setContentsMargins(0, 0, 0, -1) + self.setLayout(self.main_layout) + + self.toggled.connect(self.animationStart) + + if widget is not None: + self.setWidget(widget) + + def isChecked(self) -> bool: + return super(CollapsibleGroupBox, self).isChecked() + + def click(self) -> None: + self.setChecked(not self.isChecked()) + + def addToLayout(self, widget: QWidget) -> None: + self.main_layout.addWidget(widget) + + def sizeHint(self) -> QSize: + return super(CollapsibleGroupBox, self).sizeHint() + + +if __name__ == "__main__": + import sys + from PyQt5.QtWidgets import QApplication, QDialog, QVBoxLayout + from rare.ui.components.dialogs.install_dialog_advanced import Ui_InstallDialogAdvanced + from rare.utils.misc import set_style_sheet + from rare.resources.stylesheets import RareStyle + app = QApplication(sys.argv) + + set_style_sheet("RareStyle") + + ui_frame = Ui_InstallDialogAdvanced() + widget_frame = QWidget() + ui_frame.setupUi(widget_frame) + collapsible_frame = CollapsibleFrame(widget_frame, title="Frame me!") + collapsible_frame.setDisabled(False) + + def replace_func_frame(state): + widget2_frame = QWidget() + ui2_frame = Ui_InstallDialogAdvanced() + ui2_frame.setupUi(widget2_frame) + if state: + ui2_frame.install_dialog_advanced_layout.removeRow(3) + ui2_frame.install_dialog_advanced_layout.removeRow(4) + collapsible_frame.setWidget(widget2_frame) + + ui_group = Ui_InstallDialogAdvanced() + widget_group = QWidget() + ui_group.setupUi(widget_group) + collapsible_group = CollapsibleGroupBox(widget_group, title="Group me!") + collapsible_group.setDisabled(False) + + def replace_func_group(state): + widget2_group = QWidget() + ui2_group = Ui_InstallDialogAdvanced() + ui2_group.setupUi(widget2_group) + if state: + ui2_group.install_dialog_advanced_layout.removeRow(3) + ui2_group.install_dialog_advanced_layout.removeRow(4) + collapsible_group.setWidget(widget2_group) + + replace_button = QToolButton() + replace_button.setText("Replace me!") + replace_button.setCheckable(True) + replace_button.setChecked(False) + replace_button.clicked.connect(replace_func_frame) + replace_button.clicked.connect(replace_func_group) + + dialog = QDialog() + dialog.setLayout(QVBoxLayout()) + dialog.layout().addWidget(replace_button) + dialog.layout().addWidget(collapsible_frame) + dialog.layout().addWidget(collapsible_group) + dialog.layout().setSizeConstraint(QVBoxLayout.SetFixedSize) + dialog.show() + sys.exit(app.exec_()) + diff --git a/rare/widgets/rare_app.py b/rare/widgets/rare_app.py index 86097096..f0c5df91 100644 --- a/rare/widgets/rare_app.py +++ b/rare/widgets/rare_app.py @@ -6,7 +6,7 @@ import time from argparse import Namespace import legendary -from PyQt5.QtCore import Qt, QSettings, QTranslator, QT_VERSION_STR, PYQT_VERSION_STR +from PyQt5.QtCore import QSettings, QTranslator, QT_VERSION_STR, PYQT_VERSION_STR from PyQt5.QtGui import QIcon from PyQt5.QtWidgets import QApplication @@ -21,8 +21,6 @@ class RareApp(QApplication): def __init__(self, args: Namespace, log_file: str): super(RareApp, self).__init__(sys.argv) self.setQuitOnLastWindowClosed(False) - if hasattr(Qt, "AA_UseHighDpiPixmaps"): - self.setAttribute(Qt.AA_UseHighDpiPixmaps) self.setApplicationName("Rare") self.setOrganizationName("Rare")