diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e7d8cecb..0ab3d840 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -52,7 +52,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: - python-version: '3.8' + python-version: '3.9.5' - name: Install python deps run: | pip3 install cx_Freeze setuptools wheel diff --git a/MANIFEST.in b/MANIFEST.in index 3ee6d4e8..f1893424 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,5 @@ include README.md include rare/languages/*.qm -include rare/styles/* \ No newline at end of file +include rare/styles/* +include rare/styles/qss/* +include rare/styles/colors/* diff --git a/custom_legendary/utils/manifests.py b/custom_legendary/utils/manifests.py index 44b682c0..744ffa28 100644 --- a/custom_legendary/utils/manifests.py +++ b/custom_legendary/utils/manifests.py @@ -20,8 +20,19 @@ def combine_manifests(base_manifest: Manifest, delta_manifest: Manifest): base_manifest.file_manifest_list.count = len(base_manifest.file_manifest_list.elements) base_manifest.file_manifest_list._path_map = None - # add chunks from delta manifest to main manifest and again clear path caches - base_manifest.chunk_data_list.elements.extend(delta_manifest.chunk_data_list.elements) + # ensure guid map exists + try: + base_manifest.chunk_data_list.get_chunk_by_guid(0) + except: + pass + + # add new chunks from delta manifest to main manifest and again clear maps and update count + existing_chunk_guids = base_manifest.chunk_data_list._guid_int_map.keys() + + for chunk in delta_manifest.chunk_data_list.elements: + if chunk.guid_num not in existing_chunk_guids: + base_manifest.chunk_data_list.elements.append(chunk) + base_manifest.chunk_data_list.count = len(base_manifest.chunk_data_list.elements) base_manifest.chunk_data_list._guid_map = None base_manifest.chunk_data_list._guid_int_map = None diff --git a/rare/__main__.py b/rare/__main__.py index cbb387f8..271ddaff 100644 --- a/rare/__main__.py +++ b/rare/__main__.py @@ -1,8 +1,10 @@ +#!/usr/bin/python + import os from argparse import ArgumentParser from rare import __version__ -from rare.utils import singleton +from rare.utils import singleton, utils def main(): @@ -16,6 +18,11 @@ def main(): help="Do not download and check data from ProtonDB. Disable it, if you don't need grades") parser.add_argument("--enable-protondb", action="store_true", dest="enable_protondb", help="Enable ProtonDB data, after disabled") + + parser.add_argument("--desktop-shortcut", action="store_true", dest="desktop_shortcut", + help="Use this, if there is no link on desktop to start Rare") + parser.add_argument("--startmenu-shortcut", action="store_true", dest="startmenu_shortcut", + help="Use this, if there is no link in start menu to launch Rare") subparsers = parser.add_subparsers(title="Commands", dest="subparser") launch_parser = subparsers.add_parser("launch") @@ -23,6 +30,13 @@ def main(): args = parser.parse_args() + if args.desktop_shortcut: + utils.create_rare_desktop_link("desktop") + print("Link created") + if args.startmenu_shortcut: + utils.create_rare_desktop_link("start_menu") + print("link created") + if args.version: print(__version__) exit(0) diff --git a/rare/components/dialogs/install_dialog.py b/rare/components/dialogs/install_dialog.py index 92127ac0..42572669 100644 --- a/rare/components/dialogs/install_dialog.py +++ b/rare/components/dialogs/install_dialog.py @@ -1,24 +1,41 @@ import os +from multiprocessing import Queue as MPQueue -from PyQt5.QtWidgets import QDialog, QFormLayout, QVBoxLayout, QSpinBox, QFileDialog, QLabel, QPushButton, QHBoxLayout, \ - QCheckBox +from PyQt5.QtCore import Qt, QObject, QRunnable, QThreadPool, pyqtSignal, pyqtSlot +from PyQt5.QtGui import QCloseEvent +from PyQt5.QtWidgets import QDialog, QFileDialog, QCheckBox, QMessageBox from custom_legendary.core import LegendaryCore +from custom_legendary.utils.selective_dl import games +from rare.ui.components.dialogs.install_dialog import Ui_InstallDialog from rare.utils.extra_widgets import PathEdit +from rare.utils.models import InstallDownloadModel, InstallQueueItemModel from rare.utils.utils import get_size -class InstallDialog(QDialog): - infos = 0 +class InstallDialog(QDialog, Ui_InstallDialog): + result_ready = pyqtSignal(InstallQueueItemModel) + + def __init__(self, core: LegendaryCore, dl_item: InstallQueueItemModel, update=False, silent=False, parent=None): + super(InstallDialog, self).__init__(parent) + self.setupUi(self) + self.setAttribute(Qt.WA_DeleteOnClose, True) + self.setWindowFlags(Qt.Dialog | Qt.CustomizeWindowHint | Qt.WindowTitleHint) - def __init__(self, app_name, core: LegendaryCore, update=False): - super(InstallDialog, self).__init__() - self.layout = QVBoxLayout() self.core = core - self.game = self.core.get_game(app_name) - self.form = QFormLayout() - self.update_game = update - self.layout.addWidget(QLabel(self.tr("

Install {}

").format(self.game.app_title))) + self.dl_item = dl_item + self.dl_item.status_q = MPQueue() + self.app_name = self.dl_item.options.app_name + self.game = self.core.get_game(self.app_name) + self.update = update + self.silent = silent + + self.threadpool = QThreadPool(self) + self.threadpool.setMaxThreadCount(1) + + header = self.tr("Update") if update else self.tr("Install") + self.install_dialog_label.setText(f"

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

") + self.setWindowTitle(f"{self.windowTitle()} - {header} \"{self.game.app_title}\"") if self.core.lgd.config.has_option("Legendary", "install_dir"): default_path = self.core.lgd.config.get("Legendary", "install_dir") @@ -26,92 +43,218 @@ class InstallDialog(QDialog): default_path = os.path.expanduser("~/legendary") if not default_path: default_path = os.path.expanduser("~/legendary") - if not update: - self.install_path_field = PathEdit(text=default_path, file_type=QFileDialog.DirectoryOnly) - self.form.addRow(QLabel("Install directory"), self.install_path_field) + + self.install_dir_edit = PathEdit(text=default_path, + file_type=QFileDialog.DirectoryOnly, + edit_func=self.option_changed) + self.install_dir_layout.addWidget(self.install_dir_edit) + + if self.update: + self.install_dir_label.setVisible(False) + self.install_dir_edit.setVisible(False) if self.core.lgd.config.has_option("Legendary", "max_workers"): max_workers = self.core.lgd.config.get("Legendary", "max_workers") else: max_workers = 0 + self.max_workers_spin.setValue(int(max_workers)) + self.max_workers_spin.valueChanged.connect(self.option_changed) - self.max_workes = QSpinBox() - self.max_workes.setValue(int(max_workers)) - self.form.addRow(QLabel(self.tr("Max workers (0: Default)")), self.max_workes) + self.force_download_check.stateChanged.connect(self.option_changed) + self.ignore_space_check.stateChanged.connect(self.option_changed) + self.download_only_check.stateChanged.connect(self.option_changed) - self.force = QCheckBox() - self.force.setChecked(False) - self.form.addRow(QLabel(self.tr("Force download")), self.force) + self.sdl_list_checks = list() + try: + for key, info in games[self.app_name].items(): + cb = QDataCheckBox(info['name'], info['tags']) + if key == '__required': + self.dl_item.options.sdl_list.extend(info['tags']) + cb.setChecked(True) + cb.setDisabled(True) + self.sdl_list_layout.addWidget(cb) + self.sdl_list_checks.append(cb) + self.sdl_list_frame.resize(self.sdl_list_frame.minimumSize()) + for cb in self.sdl_list_checks: + cb.stateChanged.connect(self.option_changed) + except KeyError: + self.sdl_list_frame.setVisible(False) + self.sdl_list_label.setVisible(False) - self.ignore_free_space = QCheckBox() - self.ignore_free_space.setChecked(False) - self.form.addRow(QLabel(self.tr("Ignore free space (Warning!)")), self.ignore_free_space) + self.install_button.setEnabled(False) - self.download_only = QCheckBox() - self.download_only.setChecked(False) - self.form.addRow(QLabel(self.tr("Do not install game")), self.download_only) + self.cancel_button.clicked.connect(self.cancel_clicked) + self.verify_button.clicked.connect(self.verify_clicked) + self.install_button.clicked.connect(self.install_clicked) - self.layout.addLayout(self.form) + self.options_changed = False + self.worker_running = False + self.reject_close = True - self.ok_btn = QPushButton("Next") - self.ok_btn.clicked.connect(self.ok) - self.cancel = QPushButton("Cancel") - self.cancel.clicked.connect(lambda: self.close()) + self.resize(self.minimumSize()) + self.setFixedSize(self.size()) - self.button_layout = QHBoxLayout() - self.button_layout.addStretch(1) - self.button_layout.addWidget(self.ok_btn) - self.button_layout.addWidget(self.cancel) + def execute(self): + if self.silent: + self.reject_close = False + self.get_download_info() + else: + self.show() - self.layout.addLayout(self.button_layout) + 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.max_workers_spin.value() + self.dl_item.options.force = self.force_download_check.isChecked() + self.dl_item.options.ignore_space_req = self.ignore_space_check.isChecked() + self.dl_item.options.no_install = self.download_only_check.isChecked() + self.dl_item.options.sdl_list = [''] + for cb in self.sdl_list_checks: + if data := cb.isChecked(): + self.dl_item.options.sdl_list.extend(data) - self.setLayout(self.layout) + def get_download_info(self): + self.dl_item.download = None + info_worker = InstallInfoWorker(self.core, self.dl_item) + info_worker.setAutoDelete(True) + info_worker.signals.result.connect(self.on_worker_result) + info_worker.signals.failed.connect(self.on_worker_failed) + info_worker.signals.finished.connect(self.on_worker_finished) + self.worker_running = True + self.threadpool.start(info_worker) - def get_information(self, path=None): - if path: - self.install_path_field.text_edit.setText(path) - self.exec_() - return self.infos + def verify_clicked(self): + message = self.tr("Updating...") + self.download_size_info_label.setText(message) + self.download_size_info_label.setStyleSheet("font-style: italic; font-weight: normal") + self.install_size_info_label.setText(message) + self.install_size_info_label.setStyleSheet("font-style: italic; font-weight: normal") + self.cancel_button.setEnabled(False) + self.verify_button.setEnabled(False) + self.install_button.setEnabled(False) + self.options_changed = False + self.get_options() + self.get_download_info() - def ok(self): - self.infos = self.install_path_field.text() if not self.update_game else None, \ - self.max_workes.value(), \ - self.force.isChecked(), \ - self.ignore_free_space.isChecked(), \ - self.download_only.isChecked() + def option_changed(self): + self.options_changed = True + self.install_button.setEnabled(False) + self.verify_button.setEnabled(not self.worker_running) + + def cancel_clicked(self): + self.dl_item.download = None + self.reject_close = False self.close() - -class InstallInfoDialog(QDialog): - accept: bool = False - - def __init__(self, dl_size, install_size): - super(InstallInfoDialog, self).__init__() - self.layout = QVBoxLayout() - self.infos = QLabel(self.tr( - "Download size: {}\nInstall size: {}").format(get_size(dl_size), get_size(install_size))) - self.layout.addWidget(self.infos) - - self.btn_layout = QHBoxLayout() - self.install_btn = QPushButton(self.tr("Install")) - self.install_btn.clicked.connect(self.install) - self.cancel_button = QPushButton(self.tr("Cancel")) - self.cancel_button.clicked.connect(self.cancel) - self.btn_layout.addStretch(1) - self.btn_layout.addWidget(self.install_btn) - self.btn_layout.addWidget(self.cancel_button) - self.layout.addLayout(self.btn_layout) - - self.setLayout(self.layout) - - def get_accept(self): - self.exec_() - return self.accept - - def install(self): - self.accept = True + def install_clicked(self): + self.reject_close = False self.close() - def cancel(self): - self.accept = False - self.close() + def on_worker_result(self, dl_item: InstallDownloadModel): + self.dl_item.download = dl_item + # TODO: Check available size and act accordingly + # TODO: (show message in label | color it | disable install unless ignore) + # TODO: Find a way to get the installation size delta and show it + download_size = self.dl_item.download.analysis.dl_size + install_size = self.dl_item.download.analysis.install_size + if download_size: + self.download_size_info_label.setText("{}".format(get_size(download_size))) + self.download_size_info_label.setStyleSheet("font-style: normal; font-weight: bold") + self.install_button.setEnabled(not self.options_changed) + else: + self.install_size_info_label.setText(self.tr("Game already installed")) + self.install_size_info_label.setStyleSheet("font-style: italics; font-weight: normal") + self.install_size_info_label.setText("{}".format(get_size(install_size))) + self.install_size_info_label.setStyleSheet("font-style: normal; font-weight: bold") + self.verify_button.setEnabled(self.options_changed) + self.cancel_button.setEnabled(True) + if self.silent: + self.close() + + def on_worker_failed(self, message: str): + error_text = self.tr("Error") + self.download_size_info_label.setText(error_text) + self.install_size_info_label.setText(error_text) + QMessageBox.critical(self, self.windowTitle(), message) + self.verify_button.setEnabled(self.options_changed) + self.cancel_button.setEnabled(True) + if self.silent: + self.close() + + def on_worker_finished(self): + self.worker_running = False + + # lk: happens when close() is called, also when top right 'X' is pressed. + # lk: reject any events not coming from the buttons in case the WM + # lk: doesn't honor the window hints + def closeEvent(self, a0: QCloseEvent) -> None: + if self.reject_close: + a0.ignore() + else: + self.threadpool.clear() + self.threadpool.waitForDone() + self.result_ready.emit(self.dl_item) + a0.accept() + + +class InstallInfoWorkerSignals(QObject): + result = pyqtSignal(InstallDownloadModel) + failed = pyqtSignal(str) + finished = pyqtSignal() + + +class InstallInfoWorker(QRunnable): + + def __init__(self, core: LegendaryCore, dl_item: InstallQueueItemModel): + super(InstallInfoWorker, self).__init__() + self.signals = InstallInfoWorkerSignals() + self.core = core + self.dl_item = dl_item + + @pyqtSlot() + def run(self): + try: + download = InstallDownloadModel(*self.core.prepare_download( + app_name=self.dl_item.options.app_name, + base_path=self.dl_item.options.base_path, + force=self.dl_item.options.force, + no_install=self.dl_item.options.no_install, + status_q=self.dl_item.status_q, + # max_shm=, + max_workers=self.dl_item.options.max_workers, + # game_folder=, + # disable_patching=, + # override_manifest=, + # override_old_manifest=, + # override_base_url=, + # platform_override=, + # file_prefix_filter=, + # file_exclude_filter=, + # file_install_tag=, + # dl_optimizations=, + # dl_timeout=, + repair=self.dl_item.options.repair, + # repair_use_latest=, + ignore_space_req=self.dl_item.options.ignore_space_req, + # disable_delta=, + # override_delta_manifest=, + # reset_sdl=, + sdl_prompt=lambda app_name, title: self.dl_item.options.sdl_list + )) + self.signals.result.emit(download) + except RuntimeError as e: + self.signals.failed.emit(str(e)) + self.signals.finished.emit() + + +class QDataCheckBox(QCheckBox): + + def __init__(self, text, data=None, parent=None): + super(QDataCheckBox, self).__init__(parent) + self.setText(text) + self.data = data + + def isChecked(self): + if super(QDataCheckBox, self).isChecked(): + return self.data + else: + return False diff --git a/rare/components/tab_widget.py b/rare/components/tab_widget.py index 56ffd501..fe0213f2 100644 --- a/rare/components/tab_widget.py +++ b/rare/components/tab_widget.py @@ -14,7 +14,7 @@ from rare.components.tabs.downloads import DownloadTab from rare.components.tabs.games import GameTab from rare.components.tabs.settings import SettingsTab from rare.utils import legendary_utils -from rare.utils.models import InstallOptions +from rare.utils.models import InstallQueueItemModel, InstallOptionsModel class TabWidget(QTabWidget): @@ -83,8 +83,8 @@ class TabWidget(QTabWidget): # install game self.games_tab.uninstalled_info_widget.info.install_game.connect(self.install_game) # repair game - self.games_tab.game_info.info.verify_game.connect(lambda app_name: self.downloadTab.install_game( - InstallOptions(app_name, core.get_installed_game(app_name).install_path, repair=True))) + self.games_tab.game_info.info.verify_game.connect(lambda app_name: self.start_download( + InstallOptionsModel(app_name, core.get_installed_game(app_name).install_path, repair=True))) # Finished sync self.cloud_saves.finished.connect(self.finished_sync) @@ -96,18 +96,21 @@ class TabWidget(QTabWidget): self.setIconSize(QSize(25, 25)) def install_game(self, app_name, disable_path=False): + install_dialog = InstallDialog(self.core, + InstallQueueItemModel(options=InstallOptionsModel(app_name=app_name)), + update=disable_path, parent=self) + install_dialog.result_ready.connect(self.on_install_dialog_closed) + install_dialog.execute() - infos = InstallDialog(app_name, self.core, disable_path).get_information() - if infos != 0: - path, max_workers, force, ignore_free_space, dl_only = infos - options = InstallOptions(app_name=app_name, max_workers=max_workers, path=path, force=force, - ignore_free_space=ignore_free_space, download_only=dl_only) + def on_install_dialog_closed(self, download_item: InstallQueueItemModel): + if download_item: self.setCurrentIndex(1) - self.start_download(options) + self.start_download(download_item) def start_download(self, options): downloads = len(self.downloadTab.dl_queue) + len(self.downloadTab.update_widgets.keys()) + 1 self.setTabText(1, "Downloads" + ((" (" + str(downloads) + ")") if downloads != 0 else "")) + self.setCurrentIndex(1) self.downloadTab.install_game(options) def game_imported(self, app_name: str): diff --git a/rare/components/tabs/downloads/__init__.py b/rare/components/tabs/downloads/__init__.py index 5ca1a62e..7e85e779 100644 --- a/rare/components/tabs/downloads/__init__.py +++ b/rare/components/tabs/downloads/__init__.py @@ -1,19 +1,17 @@ import datetime from logging import getLogger -from multiprocessing import Queue as MPQueue -from PyQt5.QtCore import QThread, pyqtSignal, Qt, QSettings -from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton, QDialog, \ - QListWidget, QHBoxLayout, QGroupBox +from PyQt5.QtCore import QThread, pyqtSignal, QSettings +from PyQt5.QtWidgets import QWidget, QMessageBox, QVBoxLayout, QLabel, QGridLayout, QProgressBar, QPushButton, \ + QHBoxLayout, QGroupBox from custom_legendary.core import LegendaryCore from custom_legendary.models.downloading import UIUpdate from custom_legendary.models.game import Game, InstalledGame -from custom_legendary.utils.selective_dl import games -from rare.components.dialogs.install_dialog import InstallInfoDialog, InstallDialog +from rare.components.dialogs.install_dialog import InstallDialog from rare.components.tabs.downloads.dl_queue_widget import DlQueueWidget from rare.components.tabs.downloads.download_thread import DownloadThread -from rare.utils.models import InstallOptions +from rare.utils.models import InstallOptionsModel, InstallQueueItemModel from rare.utils.utils import get_size logger = getLogger("Download") @@ -29,6 +27,7 @@ class DownloadTab(QWidget): self.core = core self.layout = QVBoxLayout() self.active_game: Game = None + self.analysis = None self.info_layout = QGridLayout() @@ -85,7 +84,7 @@ class DownloadTab(QWidget): widget = UpdateWidget(self.core, igame, self) self.update_layout.addWidget(widget) self.update_widgets[igame.app_name] = widget - widget.update.connect(self.update_game) + widget.update_signal.connect(self.update_game) if QSettings().value("auto_update", False, bool): self.update_game(igame.app_name, True) widget.update_button.setDisabled(True) @@ -96,111 +95,26 @@ class DownloadTab(QWidget): def stop_download(self): self.thread.kill() - def install_game(self, options: InstallOptions, from_update=False): - - status_queue = MPQueue() - try: - dlm, analysis, game, igame, repair, repair_file = self.core.prepare_download( - app_name=options.app_name, - base_path=options.path, - force=options.force, - no_install=options.download_only, - status_q=status_queue, - # max_shm=, - max_workers=options.max_workers, - # game_folder=, - # disable_patching=, - # override_manifest=, - # override_old_manifest=, - # override_base_url=, - # platform_override=, - # file_prefix_filter=, - # file_exclude_filter=, - # file_install_tag=, - # dl_optimizations=, - # dl_timeout=, - repair=options.repair, - # repair_use_latest=, - ignore_space_req=options.ignore_free_space, - # disable_delta=, - # override_delta_manifest=, - # reset_sdl=, - sdl_prompt=self.sdl_prompt) - except Exception as e: - QMessageBox.warning(self, self.tr("Error preparing download"), - str(e)) - return - - if not analysis.dl_size: - QMessageBox.information(self, "Warning", self.tr("Download size is 0. Game already exists")) - return - - # Information - if not from_update: - if not InstallInfoDialog(dl_size=analysis.dl_size, install_size=analysis.install_size).get_accept(): - self.finished.emit(False, None) - return - + def install_game(self, queue_item: InstallQueueItemModel): if self.active_game is None: - self.start_installation(dlm, game, status_queue, igame, repair_file, options, analysis, - options.download_only) + self.start_installation(queue_item) else: - self.dl_queue.append( - (dlm, game, status_queue, igame, repair_file, options, analysis, options.download_only)) + self.dl_queue.append(queue_item) self.queue_widget.update_queue(self.dl_queue) - def start_installation(self, dlm, game, status_queue, igame, repair_file, options: InstallOptions, analysis, - dl_only): + def start_installation(self, queue_item: InstallQueueItemModel): if self.dl_queue: self.dl_queue.pop(0) self.queue_widget.update_queue(self.dl_queue) - self.active_game = game - self.thread = DownloadThread(dlm, self.core, status_queue, igame, options.repair, repair_file, dl_only) + self.active_game = queue_item.download.game + self.thread = DownloadThread(self.core, queue_item) self.thread.status.connect(self.status) self.thread.statistics.connect(self.statistics) self.thread.start() self.kill_button.setDisabled(False) - self.analysis = analysis + self.analysis = queue_item.download.analysis self.installing_game.setText(self.tr("Installing Game: ") + self.active_game.app_title) - def sdl_prompt(self, app_name: str = '', title: str = '') -> list: - sdl = QDialog() - sdl.setWindowTitle('Select Additional Downloads') - - layout = QVBoxLayout(sdl) - sdl.setLayout(layout) - - pack_list = QListWidget() - layout.addWidget(pack_list) - - done = QPushButton(text='Done') - done.clicked.connect(sdl.accept) - layout.addWidget(done) - - tags = [''] - if '__required' in games[app_name]: - tags.extend(games[app_name]['__required']['tags']) - - # add available additional downloads to list - pack_list.addItems([tag + ': ' + info['name'] for tag, info in games[app_name].items() if tag != '__required']) - - # enable checkboxes - for i in range(len(pack_list)): - item = pack_list.item(i) - item.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled) - item.setCheckState(Qt.Unchecked) - - sdl.exec_() - - # read checkboxes states - for i in range(len(pack_list)): - item = pack_list.item(i) - if item.checkState() == Qt.Checked: - tag = item.text().split(':')[0] - tags.extend(games[app_name][tag]['tags']) - - return tags - def status(self, text): if text == "dl_finished": pass @@ -223,7 +137,7 @@ class DownloadTab(QWidget): self.active_game = None if self.dl_queue: - if self.dl_queue[0][1] == app_name: + if self.dl_queue[0].download.game.app_name == app_name: self.dl_queue.pop(0) self.queue_widget.update_queue(self.dl_queue) @@ -241,7 +155,7 @@ class DownloadTab(QWidget): self.reset_infos() if len(self.dl_queue) != 0: - self.start_installation(*self.dl_queue[0]) + self.start_installation(self.dl_queue[0]) else: self.queue_widget.update_queue(self.dl_queue) @@ -253,7 +167,7 @@ class DownloadTab(QWidget): self.active_game = None self.finished.emit((False, None)) if self.dl_queue: - self.start_installation(*self.dl_queue[0]) + self.start_installation(self.dl_queue[0]) def reset_infos(self): self.kill_button.setDisabled(True) @@ -279,18 +193,18 @@ class DownloadTab(QWidget): def update_game(self, app_name: str, auto=False): logger.info("Update " + app_name) - if not auto: - infos = InstallDialog(app_name, self.core, True).get_information() + install_dialog = InstallDialog(self.core, + InstallQueueItemModel(options=InstallOptionsModel(app_name=app_name)), + update=True, silent=auto, parent=self) + install_dialog.result_ready.connect(self.on_install_dialog_closed) + install_dialog.execute() + + def on_install_dialog_closed(self, download_item: InstallQueueItemModel): + if download_item: + self.install_game(download_item) else: - self.install_game(InstallOptions(app_name=app_name), True) - return - if infos != 0: - path, max_workers, force, ignore_free_space, dl_only = infos - self.install_game(InstallOptions(app_name=app_name, max_workers=max_workers, path=path, - force=force, ignore_free_space=ignore_free_space, dl_only=dl_only), True) - else: - self.update_widgets[app_name].update_button.setDisabled(False) - self.update_widgets[app_name].update_with_settings.setDisabled(False) + self.update_widgets[download_item.options.app_name].update_button.setDisabled(False) + self.update_widgets[download_item.options.app_name].update_with_settings.setDisabled(False) class UpdateWidget(QWidget): diff --git a/rare/components/tabs/downloads/dl_queue_widget.py b/rare/components/tabs/downloads/dl_queue_widget.py index 72edd64f..b97a0e8e 100644 --- a/rare/components/tabs/downloads/dl_queue_widget.py +++ b/rare/components/tabs/downloads/dl_queue_widget.py @@ -4,6 +4,8 @@ from PyQt5.QtCore import pyqtSignal from PyQt5.QtWidgets import QGroupBox, QVBoxLayout, QLabel, QHBoxLayout, QPushButton, QWidget from qtawesome import icon +from rare.utils.models import InstallQueueItemModel + logger = getLogger("QueueWidget") @@ -12,9 +14,9 @@ class DlWidget(QWidget): move_down = pyqtSignal(str) # app_name remove = pyqtSignal(str) # app_name - def __init__(self, index, item): + def __init__(self, index, queue_item: InstallQueueItemModel): super(DlWidget, self).__init__() - self.app_name = item[1].app_name + self.app_name = queue_item.download.game.app_name self.layout = QHBoxLayout() self.left_layout = QVBoxLayout() @@ -33,11 +35,11 @@ class DlWidget(QWidget): self.layout.addLayout(self.left_layout) self.right_layout = QVBoxLayout() - self.title = QLabel(item[1].app_title) + self.title = QLabel(queue_item.download.game.app_title) self.right_layout.addWidget(self.title) - dl_size = item[-1].dl_size - install_size = item[-1].install_size + dl_size = queue_item.download.analysis.dl_size + install_size = queue_item.download.analysis.install_size self.size = QHBoxLayout() @@ -69,7 +71,7 @@ class DlQueueWidget(QGroupBox): self.setLayout(self.layout) def update_queue(self, dl_queue: list): - logger.info("Update Queue " + ", ".join(i[1].app_title for i in dl_queue)) + logger.info("Update Queue " + ", ".join(i.download.game.app_title for i in dl_queue)) self.dl_queue = dl_queue self.setLayout(QVBoxLayout()) QWidget().setLayout(self.layout) @@ -93,7 +95,7 @@ class DlQueueWidget(QGroupBox): def remove(self, app_name): for index, i in enumerate(self.dl_queue): - if i[1].app_name == app_name: + if i.download.game.app_name == app_name: self.dl_queue.pop(index) break else: @@ -106,7 +108,7 @@ class DlQueueWidget(QGroupBox): index: int for i, item in enumerate(self.dl_queue): - if item[1].app_name == app_name: + if item.download.game.app_name == app_name: index = i break else: @@ -120,7 +122,7 @@ class DlQueueWidget(QGroupBox): index: int for i, item in enumerate(self.dl_queue): - if item[1].app_name == app_name: + if item.download.game.app_name == app_name: index = i break else: diff --git a/rare/components/tabs/downloads/download_thread.py b/rare/components/tabs/downloads/download_thread.py index 195ff932..923c06ac 100644 --- a/rare/components/tabs/downloads/download_thread.py +++ b/rare/components/tabs/downloads/download_thread.py @@ -4,7 +4,6 @@ import subprocess import sys import time from logging import getLogger -from multiprocessing import Queue as MPQueue from queue import Empty import psutil @@ -12,8 +11,8 @@ from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtWidgets import QMessageBox from custom_legendary.core import LegendaryCore -from custom_legendary.downloader.manager import DLManager from custom_legendary.models.downloading import UIUpdate, WriterTask +from rare.utils.models import InstallQueueItemModel logger = getLogger("Download") @@ -22,16 +21,15 @@ class DownloadThread(QThread): status = pyqtSignal(str) statistics = pyqtSignal(UIUpdate) - def __init__(self, dlm: DLManager, core: LegendaryCore, status_queue: MPQueue, igame, repair=False, - repair_file=None, dl_only=False): + def __init__(self, core: LegendaryCore, queue_item: InstallQueueItemModel): super(DownloadThread, self).__init__() - self.dlm = dlm self.core = core - self.dl_only = dl_only - self.status_queue = status_queue - self.igame = igame - self.repair = repair - self.repair_file = repair_file + self.dlm = queue_item.download.dlmanager + self.no_install = queue_item.options.no_install + self.status_q = queue_item.status_q + self.igame = queue_item.download.igame + self.repair = queue_item.download.repair + self.repair_file = queue_item.download.repair_file self._kill = False def run(self): @@ -105,7 +103,7 @@ class DownloadThread(QThread): dl_stopped = True try: if not dl_stopped: - self.statistics.emit(self.status_queue.get(timeout=1)) + self.statistics.emit(self.status_q.get(timeout=1)) except queue.Empty: pass @@ -124,7 +122,7 @@ class DownloadThread(QThread): logger.info(f"Download finished in {start_time - end_t}s") game = self.core.get_game(self.igame.app_name) - if not self.dl_only: + if not self.no_install: postinstall = self.core.install_game(self.igame) if postinstall: self._handle_postinstall(postinstall, self.igame) diff --git a/rare/components/tabs/games/game_info/__init__.py b/rare/components/tabs/games/game_info/__init__.py index 465fd8b6..b9729dfa 100644 --- a/rare/components/tabs/games/game_info/__init__.py +++ b/rare/components/tabs/games/game_info/__init__.py @@ -7,7 +7,7 @@ from PyQt5.QtWidgets import QWidget, QTabWidget, QMessageBox from qtawesome import icon from custom_legendary.core import LegendaryCore -from custom_legendary.models.game import InstalledGame, Game +from custom_legendary.models.game import Game, InstalledGame from rare.components.tabs.games.game_info.dlcs import DlcTab from rare.components.tabs.games.game_info.game_settings import GameSettings from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo @@ -65,22 +65,26 @@ class GameInfo(QWidget, Ui_GameInfo): def __init__(self, core: LegendaryCore, parent): super(GameInfo, self).__init__(parent=parent) self.setupUi(self) - self.ratings = {"platinum": self.tr("Platimum"), + self.core = core + + self.ratings = {"platinum": self.tr("Platinum"), "gold": self.tr("Gold"), "silver": self.tr("Silver"), "bronze": self.tr("Bronze"), - "fail": self.tr("Could not get grade from ProtonDB"), - "pending": "Not enough reports"} + "fail": self.tr("Could not get grade"), + "pending": self.tr("Not enough reports")} if os.path.exists(p := os.path.expanduser("~/.cache/rare/game_list.json")): self.grade_table = json.load(open(p)) else: self.grade_table = {} - self.widget = QWidget() - self.core = core + if os.name == "nt": self.lbl_grade.setVisible(False) self.grade.setVisible(False) + self.game_actions_stack.setCurrentIndex(0) + self.game_actions_stack.resize(self.game_actions_stack.minimumSize()) + self.uninstall_button.clicked.connect(self.uninstall) self.verify_button.clicked.connect(self.verify) self.repair_button.clicked.connect(self.repair) @@ -153,14 +157,15 @@ class GameInfo(QWidget, Ui_GameInfo): if os.name != "nt" and self.grade_table: try: - grade = self.ratings.get(self.grade_table[app_name].get("grade")) + grade = self.grade_table[app_name]["grade"] except KeyError: - grade = (self.tr("Error")) - self.grade.setText(grade) + grade = "fail" + self.grade.setText(self.ratings[grade]) if len(self.verify_threads.keys()) == 0 or not self.verify_threads.get(app_name): self.verify_widget.setCurrentIndex(0) elif self.verify_threads.get(app_name): self.verify_widget.setCurrentIndex(1) self.verify_progress.setValue( - self.verify_threads[app_name].num / self.verify_threads[app_name].total * 100) + self.verify_threads[app_name].num / self.verify_threads[app_name].total * 100 + ) diff --git a/rare/components/tabs/games/game_info/uninstalled_info.py b/rare/components/tabs/games/game_info/uninstalled_info.py index fcb5b781..8a230516 100644 --- a/rare/components/tabs/games/game_info/uninstalled_info.py +++ b/rare/components/tabs/games/game_info/uninstalled_info.py @@ -1,15 +1,17 @@ import json import os -from PyQt5.QtCore import pyqtSignal, QSettings, Qt +from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtGui import QPixmap, QKeyEvent -from PyQt5.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QTabWidget, QTreeView +from PyQt5.QtWidgets import QWidget, QTabWidget, QTreeView from qtawesome import icon from custom_legendary.core import LegendaryCore from custom_legendary.models.game import Game +from rare.ui.components.tabs.games.game_info.game_info import Ui_GameInfo from rare.utils.extra_widgets import SideTabBar from rare.utils.json_formatter import QJsonModel +from rare.utils.utils import IMAGE_DIR class UninstalledTabInfo(QTabWidget): @@ -18,7 +20,6 @@ class UninstalledTabInfo(QTabWidget): self.app_name = "" self.core = core self.setTabBar(SideTabBar()) - self.setTabPosition(QTabWidget.West) self.addTab(QWidget(), icon("mdi.keyboard-backspace", color="white"), self.tr("Back")) @@ -49,69 +50,44 @@ class UninstalledTabInfo(QTabWidget): self.parent().layout.setCurrentIndex(0) -class UninstalledInfo(QWidget): +class UninstalledInfo(QWidget, Ui_GameInfo): game: Game install_game = pyqtSignal(str) - def __init__(self, core: LegendaryCore, parent): + def __init__(self, core: LegendaryCore, parent=None): super(UninstalledInfo, self).__init__(parent=parent) - self.layout = QVBoxLayout() - - if os.path.exists(p := os.path.expanduser("~/.cache/rare/game_list.json")): - self.grade_table = json.load(open(p)) - else: - self.grade_table = {} + self.setupUi(self) + self.core = core self.ratings = {"platinum": self.tr("Platinum"), "gold": self.tr("Gold"), "silver": self.tr("Silver"), "bronze": self.tr("Bronze"), - "fail": self.tr("Could not get grade from ProtonDB"), - "pending": "Not enough reports"} + "fail": self.tr("Could not get grade"), + "pending": self.tr("Not enough reports")} + if os.path.exists(p := os.path.expanduser("~/.cache/rare/game_list.json")): + self.grade_table = json.load(open(p)) + else: + self.grade_table = {} - self.core = core + if os.name == "nt": + self.lbl_grade.setVisible(False) + self.grade.setVisible(False) - self.settings = QSettings() + self.install_size.setEnabled(False) + self.lbl_install_size.setEnabled(False) + self.install_path.setEnabled(False) + self.lbl_install_path.setEnabled(False) - self.top_layout = QHBoxLayout() - left_layout = QVBoxLayout() - self.image = QLabel() - left_layout.addWidget(self.image) - left_layout.addStretch(1) - self.top_layout.addLayout(left_layout) - self.right_layout = QVBoxLayout() + self.game_actions_stack.setCurrentIndex(1) + self.game_actions_stack.resize(self.game_actions_stack.minimumSize()) - self.title = QLabel("Error") - self.right_layout.addWidget(self.title) - - self.app_name = QLabel("Error") - self.right_layout.addWidget(self.app_name) - if os.name != "nt": - self.rating = QLabel("Rating: Error") - self.right_layout.addWidget(self.rating) - - self.install_button = QPushButton(self.tr("Install")) - self.install_button.setFixedWidth(300) - self.install_button.setStyleSheet("""background-color: #090""") self.install_button.clicked.connect(lambda: self.install_game.emit(self.game.app_name)) - self.right_layout.addWidget(self.install_button) - self.version = QLabel("Error") - self.right_layout.addWidget(self.version) - self.right_layout.addStretch(1) - self.top_layout.addLayout(self.right_layout) - - self.top_layout.addStretch(1) - self.layout.addLayout(self.top_layout) - - self.setLayout(self.layout) def update_game(self, app_name): self.game = self.core.get_game(app_name) - self.title.setText(f"

{self.game.app_title}

") - self.app_name.setText("Appname: " + app_name) - - IMAGE_DIR = self.settings.value("img_dir", os.path.expanduser("~/.cache/rare/images"), str) + self.game_title.setText(f"

{self.game.app_title}

") if os.path.exists(f"{IMAGE_DIR}/{self.game.app_name}/FinalArt.png"): pixmap = QPixmap(f"{IMAGE_DIR}/{self.game.app_name}/FinalArt.png") @@ -127,13 +103,15 @@ class UninstalledInfo(QWidget): pixmap = pixmap.scaled(w, int(w * 4 / 3)) self.image.setPixmap(pixmap) - self.version.setText(self.game.asset_info.build_version) - if self.grade_table and (not os.name == "nt"): + self.app_name.setText(self.game.app_name) + self.version.setText(self.game.app_version) + self.dev.setText(self.game.metadata["developer"]) + self.install_size.setText("N/A") + self.install_path.setText("N/A") + + if os.name != "nt" and self.grade_table: try: - rating = self.grade_table[app_name]["grade"] + grade = self.grade_table[app_name]["grade"] except KeyError: - rating = "fail" - if rating not in ["fail", "pending"]: - self.rating.setText(self.tr("Rating from ProtonDB: ") + self.ratings[rating]) - else: - self.rating.setText(self.ratings[rating]) + grade = "fail" + self.grade.setText(self.ratings[grade]) diff --git a/rare/components/tabs/games/game_list.py b/rare/components/tabs/games/game_list.py index 36b56942..5954ba31 100644 --- a/rare/components/tabs/games/game_list.py +++ b/rare/components/tabs/games/game_list.py @@ -13,14 +13,14 @@ from rare.components.tabs.games.game_widgets.installed_list_widget import Instal from rare.components.tabs.games.game_widgets.uninstalled_icon_widget import IconWidgetUninstalled from rare.components.tabs.games.game_widgets.uninstalled_list_widget import ListWidgetUninstalled from rare.utils.extra_widgets import FlowLayout -from rare.utils.models import InstallOptions +from rare.utils.models import InstallOptionsModel from rare.utils.utils import download_image logger = getLogger("Game list") class GameList(QStackedWidget): - install_game = pyqtSignal(InstallOptions) + install_game = pyqtSignal(InstallOptionsModel) show_game_info = pyqtSignal(str) update_game = pyqtSignal() game_exited = pyqtSignal(str) @@ -346,14 +346,14 @@ class GameList(QStackedWidget): else: installed_names = [i.app_name for i in self.core.get_installed_list()] # get Uninstalled games - uninstalled_games = [] + uninstalled_names = [] games = self.core.get_game_list(True) for game in sorted(games, key=lambda x: x.app_title): if not game.app_name in installed_names: - uninstalled_games.append(game.app_name) + uninstalled_names.append(game.app_name) new_installed_games = list(set(installed_names) - set([i.app_name for i in self.installed])) - new_uninstalled_games = list(set(uninstalled_games) - set([i.app_name for i in self.uninstalled_names])) + new_uninstalled_games = list(set(uninstalled_names) - set([i.app_name for i in self.uninstalled_games])) if (not new_uninstalled_games) and (not new_installed_games): return @@ -388,7 +388,7 @@ class GameList(QStackedWidget): for game in sorted(games, key=lambda x: x.app_title): if not game.app_name in installed_names: self.uninstalled_names.append(game) - for name in uninstalled_games: + for name in uninstalled_names: i_widget, list_widget = self.widgets[name] self.icon_layout.addWidget(i_widget) self.list_layout.addWidget(list_widget) diff --git a/rare/components/tabs/settings/rare.py b/rare/components/tabs/settings/rare.py index 3aaff5e4..2fafc3d9 100644 --- a/rare/components/tabs/settings/rare.py +++ b/rare/components/tabs/settings/rare.py @@ -9,6 +9,7 @@ from PyQt5.QtWidgets import QFileDialog, QWidget from rare.components.tabs.settings.rpc_settings import RPCSettings from rare.ui.components.tabs.settings.rare import Ui_RareSettings +from rare.utils import utils from rare.utils.extra_widgets import PathEdit from rare.utils.utils import get_lang, get_possible_langs, get_color_schemes, get_style_sheets @@ -99,10 +100,58 @@ class RareSettings(QWidget, Ui_RareSettings): lambda: self.settings.setValue("save_size", self.save_size.isChecked()) ) + if os.name == "posix": + self.desktop_file = os.path.expanduser("~/Desktop/Rare.desktop") + self.start_menu_link = os.path.expanduser("~/.local/share/applications/Rare.desktop") + elif os.name == "nt": + self.desktop_file = os.path.expanduser("~/Desktop/Rare.lnk") + self.start_menu_link = os.path.expandvars("%appdata%/Microsoft/Windows/Start Menu") + else: + self.desktop_file = "" + self.start_menu_link = "" + + if os.path.exists(self.desktop_file): + self.desktop_link.setText(self.tr("Remove desktop link")) + if os.path.exists(self.start_menu_link): + self.startmenu_link.setText(self.tr("Remove start menu link")) + + self.desktop_link.clicked.connect(self.create_desktop_link) + self.startmenu_link.clicked.connect(self.create_start_menu_link) + self.log_dir_open_button.clicked.connect(self.open_dir) + self.log_dir_clean_button.clicked.connect(self.clean_logdir) + + logdir = os.path.expanduser("~/.cache/rare/logs") + # get size of logdir + size = 0 + for i in os.listdir(logdir): + size += os.path.getsize(os.path.join(logdir, i)) + + self.log_dir_size_label.setText(utils.get_size(size)) # TODO: Implement - self.log_dir_clean_button.setVisible(False) - self.log_dir_size_label.setVisible(False) + # self.log_dir_clean_button.setVisible(False) + # self.log_dir_size_label.setVisible(False) + + def clean_logdir(self): + for i in os.listdir(os.path.expanduser("~/.cache/rare/logs")): + os.remove(os.path.expanduser("~/.cache/rare/logs/") + i) + self.log_dir_size_label.setText("0KB") + + def create_start_menu_link(self): + if not os.path.exists(self.start_menu_link): + utils.create_rare_desktop_link("start_menu") + self.startmenu_link.setText(self.tr("Remove start menu link")) + else: + os.remove(self.start_menu_link) + self.startmenu_link.setText(self.tr("Create start menu link")) + + def create_desktop_link(self): + if not os.path.exists(self.desktop_file): + utils.create_rare_desktop_link("start_menu") + self.desktop_link.setText(self.tr("Remove Desktop link")) + else: + os.remove(self.desktop_file) + self.desktop_link.setText(self.tr("Create desktop link")) def on_color_select_changed(self, color): if color: diff --git a/rare/styles/colors/Adapta-Nokto.scheme b/rare/styles/colors/Adapta-Nokto.scheme new file mode 100644 index 00000000..0c2b5543 --- /dev/null +++ b/rare/styles/colors/Adapta-Nokto.scheme @@ -0,0 +1,25 @@ +[ColorScheme] +Active\AlternateBase=#ff273339 +Active\Base=#ff2f3d44 +Active\BrightText=#ffffffff +Active\Button=#ff263238 +Active\ButtonText=#ffb9c3c7 +Active\Dark=#ff1f292e +Active\Highlight=#ff00bcd4 +Active\HighlightedText=#ffffffff +Active\Light=#ff2f3e46 +Active\Link=#ff0000ff +Active\LinkVisited=#ffff00ff +Active\Mid=#ffb8b5b2 +Active\Midlight=#ffcbc7c4 +Active\PlaceholderText=#80b9c3c7 +Active\Shadow=#ff1d262b +Active\Text=#ffb9c3c7 +Active\ToolTipBase=#ff263238 +Active\ToolTipText=#ffcfd8dc +Active\Window=#ff263238 +Active\WindowText=#ffb9c3c7 +Disabled\ButtonText=#ff808080 +Disabled\HighlightedText=#ff808080 +Disabled\Text=#ff808080 +Disabled\WindowText=#ff808080 diff --git a/rare/styles/colors/Airy.scheme b/rare/styles/colors/Airy.scheme new file mode 100644 index 00000000..f445a80a --- /dev/null +++ b/rare/styles/colors/Airy.scheme @@ -0,0 +1,39 @@ +[ColorScheme] +Active\AlternateBase=#ff5c5b5a +Active\Base=#ffc8c8c8 +Active\BrightText=#ff0a0a0a +Active\Button=#ffdcdcdc +Active\ButtonText=#ff0a0a0a +Active\Dark=#ff646464 +Active\Highlight=#ff0986d3 +Active\HighlightedText=#ff0a0a0a +Active\Light=#ffdcdcdc +Active\Link=#ff0986d3 +Active\LinkVisited=#ffa70b06 +Active\Mid=#ffe1e1e1 +Active\Midlight=#ff5e5c5b +Active\PlaceholderText=#80000000 +Active\Shadow=#ffe7e4e0 +Active\Text=#ff000000 +Active\ToolTipBase=#ff646464 +Active\ToolTipText=#ff050505 +Active\Window=#ffffffff +Active\WindowText=#ff000000 +Disabled\Base=#ff969696 +Disabled\BrightText=#ffffffff +Disabled\Button=#ff424245 +Disabled\ButtonText=#ff808080 +Disabled\HighlightedText=#ff808080 +Disabled\Text=#ff808080 +Disabled\ToolTipText=#ffffffff +Disabled\Window=#ffc8c8c8 +Disabled\WindowText=#ffffffff +Inactive\Base=#ff969696 +Inactive\BrightText=#ff323232 +Inactive\Button=#ffb4b4b4 +Inactive\ButtonText=#ff323232 +Inactive\HighlightedText=#ff323232 +Inactive\Text=#ff323232 +Inactive\ToolTipText=#ff323232 +Inactive\Window=#ffc8c8c8 +Inactive\WindowText=#ff323232 diff --git a/rare/styles/colors/Arc-Dark.scheme b/rare/styles/colors/Arc-Dark.scheme new file mode 100644 index 00000000..c734d720 --- /dev/null +++ b/rare/styles/colors/Arc-Dark.scheme @@ -0,0 +1,26 @@ +[ColorScheme] +Active\AlternateBase=#ff3f4350 +Active\Base=#ff404552 +Active\BrightText=#ffffffff +Active\Button=#ff383c4a +Active\ButtonText=#ffd3dae3 +Active\Dark=#ff2e323d +Active\Highlight=#ff5294e2 +Active\HighlightedText=#ffffffff +Active\Light=#ff464b5c +Active\Link=#ff0000ff +Active\LinkVisited=#ffff00ff +Active\Mid=#ffa0a0a4 +Active\Midlight=#ffe9e7e3 +Active\PlaceholderText=#80d3dae3 +Active\Shadow=#ff2b2e39 +Active\Text=#ffd3dae3 +Active\ToolTipBase=#ffffffdc +Active\ToolTipText=#ffd3dae3 +Active\Window=#ff383c4a +Active\WindowText=#ffd3dae3 +Disabled\ButtonText=#ff858b96 +Disabled\Highlight=#ffe2e2e2 +Disabled\Text=#ff858b96 +Disabled\WindowText=#ff858b96 +Inactive\Highlight=#ff4084d6 diff --git a/rare/styles/colors/Arc-Darker.scheme b/rare/styles/colors/Arc-Darker.scheme new file mode 100644 index 00000000..0462ed08 --- /dev/null +++ b/rare/styles/colors/Arc-Darker.scheme @@ -0,0 +1,26 @@ +[ColorScheme] +Active\AlternateBase=#fffafafa +Active\Base=#ffffffff +Active\BrightText=#ffffffff +Active\Button=#fff5f6f7 +Active\ButtonText=#ff5c616c +Active\Dark=#ffcccdce +Active\Highlight=#ff5294e2 +Active\HighlightedText=#ffffffff +Active\Light=#ffffffff +Active\Link=#ff0000ff +Active\LinkVisited=#ffff00ff +Active\Mid=#ffa0a0a4 +Active\Midlight=#ffe9e7e3 +Active\PlaceholderText=#805c616c +Active\Shadow=#ffbdbdbe +Active\Text=#ff5c616c +Active\ToolTipBase=#ffffffdc +Active\ToolTipText=#ff5c616c +Active\Window=#fff5f6f7 +Active\WindowText=#ff5c616c +Disabled\ButtonText=#ffa8abb1 +Disabled\Highlight=#ffe2e2e2 +Disabled\Text=#ffa8abb1 +Disabled\WindowText=#ffa8abb1 +Inactive\Highlight=#ff4084d6 diff --git a/rare/styles/colors/Darker.scheme b/rare/styles/colors/Darker.scheme new file mode 100644 index 00000000..db91755f --- /dev/null +++ b/rare/styles/colors/Darker.scheme @@ -0,0 +1,25 @@ +[ColorScheme] +Active\AlternateBase=#ff5c5b5a +Active\Base=#ff3d3d3d +Active\BrightText=#ffffffff +Active\Button=#ff424245 +Active\ButtonText=#ffffffff +Active\Dark=#ff302f2e +Active\Highlight=#ff12608a +Active\HighlightedText=#fff9f9f9 +Active\Light=#ff979797 +Active\Link=#ff0986d3 +Active\LinkVisited=#ffa70b06 +Active\Mid=#ff4a4947 +Active\Midlight=#ff5e5c5b +Active\PlaceholderText=#80ffffff +Active\Shadow=#ffe7e4e0 +Active\Text=#ffffffff +Active\ToolTipBase=#ff3f3f36 +Active\ToolTipText=#ffffffff +Active\Window=#ff222020 +Active\WindowText=#ffffffff +Disabled\ButtonText=#ff808080 +Disabled\HighlightedText=#ff808080 +Disabled\Text=#ff808080 +Disabled\WindowText=#ff808080 diff --git a/rare/styles/colors/Dusk.scheme b/rare/styles/colors/Dusk.scheme new file mode 100644 index 00000000..49e4012f --- /dev/null +++ b/rare/styles/colors/Dusk.scheme @@ -0,0 +1,26 @@ +[ColorScheme] +Active\AlternateBase=#ff7f7f7f +Active\Base=#ff7f7f7f +Active\BrightText=#ffffffff +Active\Button=#ff7f7f7f +Active\ButtonText=#ff000000 +Active\Dark=#ff7f7f7f +Active\Highlight=#ff308cc6 +Active\HighlightedText=#ffffffff +Active\Light=#ffffffff +Active\Link=#ff0000ff +Active\LinkVisited=#ffff00ff +Active\Mid=#ffb8b5b2 +Active\Midlight=#ffcbc7c4 +Active\PlaceholderText=#80000000 +Active\Shadow=#ff707070 +Active\Text=#ff000000 +Active\ToolTipBase=#ff7f7f7f +Active\ToolTipText=#ff000000 +Active\Window=#ff7f7f7f +Active\WindowText=#ff000000 +Disabled\ButtonText=#ffbebebe +Disabled\Highlight=#ff7f7f7f +Disabled\Shadow=#ffb1aeab +Disabled\Text=#ffbebebe +Disabled\WindowText=#ffbebebe diff --git a/rare/styles/colors/Numix-Dark.scheme b/rare/styles/colors/Numix-Dark.scheme index 7aa182da..faab227e 100644 --- a/rare/styles/colors/Numix-Dark.scheme +++ b/rare/styles/colors/Numix-Dark.scheme @@ -1,61 +1,25 @@ [ColorScheme] -Active\AlternateBase=#2f2f2f -Active\Base=#333333 -Active\BrightText=#ffffff -Active\Button=#525252 -Active\ButtonText=#dddddd -Active\Dark=#333333 -Active\Highlight=#f0544c -Active\HighlightedText=#ffffff -Active\Light=#555555 -Active\Link=#fc6f5d -Active\LinkVisited=#853931 -Active\Mid=#a0a0a4 -Active\Midlight=#e9e7e3 -Active\PlaceholderText=#eeeeee -Active\Shadow=#343434 -Active\Text=#eeeeee -Active\ToolTipBase=#444444 -Active\ToolTipText=#eeeeee -Active\Window=#444444 -Active\WindowText=#dddddd -Disabled\AlternateBase=#2f2f2f -Disabled\Base=#333333 -Disabled\BrightText=#ffffff -Disabled\Button=#525252 -Disabled\ButtonText=#808080 -Disabled\Dark=#333333 -Disabled\Highlight=#f0544c -Disabled\HighlightedText=#808080 -Disabled\Light=#555555 -Disabled\Link=#fc6f5d -Disabled\LinkVisited=#853931 -Disabled\Mid=#a0a0a4 -Disabled\Midlight=#e9e7e3 -Disabled\PlaceholderText=#eeeeee -Disabled\Shadow=#343434 -Disabled\Text=#808080 -Disabled\ToolTipBase=#444444 -Disabled\ToolTipText=#eeeeee -Disabled\Window=#444444 -Disabled\WindowText=#808080 -Inactive\AlternateBase=#2f2f2f -Inactive\Base=#333333 -Inactive\BrightText=#ffffff -Inactive\Button=#525252 -Inactive\ButtonText=#dddddd -Inactive\Dark=#333333 -Inactive\Highlight=#f0544c -Inactive\HighlightedText=#ffffff -Inactive\Light=#555555 -Inactive\Link=#fc6f5d -Inactive\LinkVisited=#853931 -Inactive\Mid=#a0a0a4 -Inactive\Midlight=#e9e7e3 -Inactive\PlaceholderText=#eeeeee -Inactive\Shadow=#343434 -Inactive\Text=#eeeeee -Inactive\ToolTipBase=#444444 -Inactive\ToolTipText=#eeeeee -Inactive\Window=#444444 -Inactive\WindowText=#dddddd +Active\AlternateBase=#ff2f2f2f +Active\Base=#ff333333 +Active\BrightText=#ffffffff +Active\Button=#ff525252 +Active\ButtonText=#ffdddddd +Active\Dark=#ff333333 +Active\Highlight=#fff0544c +Active\HighlightedText=#ffffffff +Active\Light=#ff555555 +Active\Link=#fffc6f5d +Active\LinkVisited=#ff853931 +Active\Mid=#ffa0a0a4 +Active\Midlight=#ffe9e7e3 +Active\PlaceholderText=#80eeeeee +Active\Shadow=#ff343434 +Active\Text=#ffeeeeee +Active\ToolTipBase=#ff444444 +Active\ToolTipText=#ffeeeeee +Active\Window=#ff444444 +Active\WindowText=#ffdddddd +Disabled\ButtonText=#ff808080 +Disabled\HighlightedText=#ff808080 +Disabled\Text=#ff808080 +Disabled\WindowText=#ff808080 diff --git a/rare/styles/colors/Rare.scheme b/rare/styles/colors/Rare.scheme index 1b954210..e2f3146c 100644 --- a/rare/styles/colors/Rare.scheme +++ b/rare/styles/colors/Rare.scheme @@ -1,61 +1,25 @@ [ColorScheme] -Active\AlternateBase=#f7f7f7 -Active\Base=#333344 -Active\BrightText=#ffffff -Active\Button=#3c3f41 -Active\ButtonText=#eeeeee -Active\Dark=#9f0910 -Active\Highlight=#2f4f4f -Active\HighlightedText=#eeeeee -Active\Light=#ffffff -Active\Link=#0000ff -Active\LinkVisited=#ff00ff -Active\Mid=#b80e35 -Active\Midlight=#ca0651 -Active\PlaceholderText=#eeeeee -Active\Shadow=#767676 -Active\Text=#eeeeee -Active\ToolTipBase=#ffffdc -Active\ToolTipText=#eeeeee -Active\Window=#202225 -Active\WindowText=#eeeeee -Disabled\AlternateBase=#f7f7f7 -Disabled\Base=#333344 -Disabled\BrightText=#ffffff -Disabled\Button=#3c3f41 -Disabled\ButtonText=#808080 -Disabled\Dark=#9f0910 -Disabled\Highlight=#2f4f4f -Disabled\HighlightedText=#808080 -Disabled\Light=#ffffff -Disabled\Link=#0000ff -Disabled\LinkVisited=#ff00ff -Disabled\Mid=#b80e35 -Disabled\Midlight=#ca0651 -Disabled\PlaceholderText=#eeeeee -Disabled\Shadow=#767676 -Disabled\Text=#808080 -Disabled\ToolTipBase=#ffffdc -Disabled\ToolTipText=#eeeeee -Disabled\Window=#202225 -Disabled\WindowText=#808080 -Inactive\AlternateBase=#f7f7f7 -Inactive\Base=#333344 -Inactive\BrightText=#ffffff -Inactive\Button=#3c3f41 -Inactive\ButtonText=#eeeeee -Inactive\Dark=#9f0910 -Inactive\Highlight=#2f4f4f -Inactive\HighlightedText=#eeeeee -Inactive\Light=#ffffff -Inactive\Link=#0000ff -Inactive\LinkVisited=#ff00ff -Inactive\Mid=#b80e35 -Inactive\Midlight=#ca0651 -Inactive\PlaceholderText=#eeeeee -Inactive\Shadow=#767676 -Inactive\Text=#eeeeee -Inactive\ToolTipBase=#ffffdc -Inactive\ToolTipText=#eeeeee -Inactive\Window=#202225 -Inactive\WindowText=#eeeeee +Active\AlternateBase=#fff7f7f7 +Active\Base=#ff333344 +Active\BrightText=#ffffffff +Active\Button=#ff3c3f41 +Active\ButtonText=#ffeeeeee +Active\Dark=#ff9f0910 +Active\Highlight=#ff2f4f4f +Active\HighlightedText=#ffeeeeee +Active\Light=#ffffffff +Active\Link=#ff0000ff +Active\LinkVisited=#ffff00ff +Active\Mid=#ffb80e35 +Active\Midlight=#ffca0651 +Active\PlaceholderText=#80eeeeee +Active\Shadow=#ff767676 +Active\Text=#ffeeeeee +Active\ToolTipBase=#ffffffdc +Active\ToolTipText=#ffeeeeee +Active\Window=#ff202225 +Active\WindowText=#ffeeeeee +Disabled\ButtonText=#ff808080 +Disabled\HighlightedText=#ff808080 +Disabled\Text=#ff808080 +Disabled\WindowText=#ff808080 diff --git a/rare/styles/colors/Zukitre.scheme b/rare/styles/colors/Zukitre.scheme new file mode 100644 index 00000000..85fd63bc --- /dev/null +++ b/rare/styles/colors/Zukitre.scheme @@ -0,0 +1,25 @@ +[ColorScheme] +Active\AlternateBase=#fff7f7f7 +Active\Base=#fff7f7f7 +Active\BrightText=#ffffffff +Active\Button=#ffd6d6d6 +Active\ButtonText=#ff2c2c2c +Active\Dark=#ffb3b3b3 +Active\Highlight=#ff258ef8 +Active\HighlightedText=#ffffffff +Active\Light=#ffffffff +Active\Link=#ff0000ff +Active\LinkVisited=#ffff00ff +Active\Mid=#ffa0a0a4 +Active\Midlight=#ffe9e7e3 +Active\PlaceholderText=#802c2c2c +Active\Shadow=#ffa5a5a5 +Active\Text=#ff2c2c2c +Active\ToolTipBase=#ffffffdc +Active\ToolTipText=#ff000000 +Active\Window=#ffd6d6d6 +Active\WindowText=#ff2c2c2c +Disabled\ButtonText=#ff808080 +Disabled\HighlightedText=#ff808080 +Disabled\Text=#ff808080 +Disabled\WindowText=#ff808080 diff --git a/rare/styles/colors/ia_ora.scheme b/rare/styles/colors/ia_ora.scheme deleted file mode 100644 index 5fbbc868..00000000 --- a/rare/styles/colors/ia_ora.scheme +++ /dev/null @@ -1,61 +0,0 @@ -[ColorScheme] -Active\AlternateBase=#eff3f7 -Active\Base=#eff3f7 -Active\BrightText=#ffffff -Active\Button=#eff3f7 -Active\ButtonText=#000000 -Active\Dark=#c7cbce -Active\Highlight=#4965ae -Active\HighlightedText=#ffffff -Active\Light=#ffffff -Active\Link=#0000ff -Active\LinkVisited=#ff00ff -Active\Mid=#a0a0a4 -Active\Midlight=#e9e7e3 -Active\PlaceholderText=#000000 -Active\Shadow=#b8bbbe -Active\Text=#000000 -Active\ToolTipBase=#ffffdc -Active\ToolTipText=#000000 -Active\Window=#eff3f7 -Active\WindowText=#000000 -Disabled\AlternateBase=#eff3f7 -Disabled\Base=#eff3f7 -Disabled\BrightText=#ffffff -Disabled\Button=#eff3f7 -Disabled\ButtonText=#808080 -Disabled\Dark=#c7cbce -Disabled\Highlight=#4965ae -Disabled\HighlightedText=#808080 -Disabled\Light=#ffffff -Disabled\Link=#0000ff -Disabled\LinkVisited=#ff00ff -Disabled\Mid=#a0a0a4 -Disabled\Midlight=#e9e7e3 -Disabled\PlaceholderText=#000000 -Disabled\Shadow=#b8bbbe -Disabled\Text=#808080 -Disabled\ToolTipBase=#ffffdc -Disabled\ToolTipText=#000000 -Disabled\Window=#eff3f7 -Disabled\WindowText=#808080 -Inactive\AlternateBase=#eff3f7 -Inactive\Base=#eff3f7 -Inactive\BrightText=#ffffff -Inactive\Button=#eff3f7 -Inactive\ButtonText=#000000 -Inactive\Dark=#c7cbce -Inactive\Highlight=#4965ae -Inactive\HighlightedText=#ffffff -Inactive\Light=#ffffff -Inactive\Link=#0000ff -Inactive\LinkVisited=#ff00ff -Inactive\Mid=#a0a0a4 -Inactive\Midlight=#e9e7e3 -Inactive\PlaceholderText=#000000 -Inactive\Shadow=#b8bbbe -Inactive\Text=#000000 -Inactive\ToolTipBase=#ffffdc -Inactive\ToolTipText=#000000 -Inactive\Window=#eff3f7 -Inactive\WindowText=#000000 diff --git a/rare/ui/components/dialogs/install_dialog.py b/rare/ui/components/dialogs/install_dialog.py new file mode 100644 index 00000000..58a817ca --- /dev/null +++ b/rare/ui/components/dialogs/install_dialog.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'install_dialog.ui' +# +# Created by: PyQt5 UI code generator 5.15.4 +# +# 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_InstallDialog(object): + def setupUi(self, InstallDialog): + InstallDialog.setObjectName("InstallDialog") + InstallDialog.setWindowTitle("Rare") + self.install_dialog_layout = QtWidgets.QGridLayout(InstallDialog) + self.install_dialog_layout.setObjectName("install_dialog_layout") + self.force_download_label = QtWidgets.QLabel(InstallDialog) + self.force_download_label.setObjectName("force_download_label") + self.install_dialog_layout.addWidget(self.force_download_label, 3, 0, 1, 1, QtCore.Qt.AlignRight) + self.button_layout = QtWidgets.QHBoxLayout() + self.button_layout.setObjectName("button_layout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.button_layout.addItem(spacerItem) + self.cancel_button = QtWidgets.QPushButton(InstallDialog) + self.cancel_button.setObjectName("cancel_button") + self.button_layout.addWidget(self.cancel_button) + self.verify_button = QtWidgets.QPushButton(InstallDialog) + self.verify_button.setObjectName("verify_button") + self.button_layout.addWidget(self.verify_button) + self.install_button = QtWidgets.QPushButton(InstallDialog) + self.install_button.setObjectName("install_button") + self.button_layout.addWidget(self.install_button) + self.install_dialog_layout.addLayout(self.button_layout, 9, 0, 1, 3) + self.ignore_space_info_label = QtWidgets.QLabel(InstallDialog) + font = QtGui.QFont() + font.setItalic(True) + self.ignore_space_info_label.setFont(font) + self.ignore_space_info_label.setObjectName("ignore_space_info_label") + self.install_dialog_layout.addWidget(self.ignore_space_info_label, 4, 2, 1, 1) + self.install_dir_label = QtWidgets.QLabel(InstallDialog) + self.install_dir_label.setObjectName("install_dir_label") + self.install_dialog_layout.addWidget(self.install_dir_label, 1, 0, 1, 1, QtCore.Qt.AlignRight) + self.ignore_space_check = QtWidgets.QCheckBox(InstallDialog) + self.ignore_space_check.setObjectName("ignore_space_check") + self.install_dialog_layout.addWidget(self.ignore_space_check, 4, 1, 1, 1) + 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.install_dialog_layout.addWidget(self.max_workers_info_label, 2, 2, 1, 1) + self.max_workers_spin = QtWidgets.QSpinBox(InstallDialog) + self.max_workers_spin.setObjectName("max_workers_spin") + self.install_dialog_layout.addWidget(self.max_workers_spin, 2, 1, 1, 1) + self.download_only_info_label = QtWidgets.QLabel(InstallDialog) + font = QtGui.QFont() + font.setItalic(True) + self.download_only_info_label.setFont(font) + self.download_only_info_label.setObjectName("download_only_info_label") + self.install_dialog_layout.addWidget(self.download_only_info_label, 5, 2, 1, 1) + self.install_size_label = QtWidgets.QLabel(InstallDialog) + self.install_size_label.setObjectName("install_size_label") + self.install_dialog_layout.addWidget(self.install_size_label, 8, 0, 1, 1, QtCore.Qt.AlignRight) + self.install_dir_layout = QtWidgets.QHBoxLayout() + self.install_dir_layout.setObjectName("install_dir_layout") + self.install_dialog_layout.addLayout(self.install_dir_layout, 1, 1, 1, 2) + spacerItem1 = QtWidgets.QSpacerItem(0, 0, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.install_dialog_layout.addItem(spacerItem1, 3, 2, 1, 1) + self.ignore_space_label = QtWidgets.QLabel(InstallDialog) + self.ignore_space_label.setObjectName("ignore_space_label") + self.install_dialog_layout.addWidget(self.ignore_space_label, 4, 0, 1, 1, QtCore.Qt.AlignRight) + self.download_only_label = QtWidgets.QLabel(InstallDialog) + self.download_only_label.setObjectName("download_only_label") + self.install_dialog_layout.addWidget(self.download_only_label, 5, 0, 1, 1, QtCore.Qt.AlignRight) + self.max_workers_label = QtWidgets.QLabel(InstallDialog) + self.max_workers_label.setObjectName("max_workers_label") + self.install_dialog_layout.addWidget(self.max_workers_label, 2, 0, 1, 1, QtCore.Qt.AlignRight) + self.install_size_info_label = QtWidgets.QLabel(InstallDialog) + font = QtGui.QFont() + font.setItalic(True) + self.install_size_info_label.setFont(font) + self.install_size_info_label.setObjectName("install_size_info_label") + self.install_dialog_layout.addWidget(self.install_size_info_label, 8, 1, 1, 2) + self.download_size_label = QtWidgets.QLabel(InstallDialog) + self.download_size_label.setObjectName("download_size_label") + self.install_dialog_layout.addWidget(self.download_size_label, 7, 0, 1, 1, QtCore.Qt.AlignRight) + self.download_size_info_label = QtWidgets.QLabel(InstallDialog) + font = QtGui.QFont() + font.setItalic(True) + self.download_size_info_label.setFont(font) + self.download_size_info_label.setObjectName("download_size_info_label") + self.install_dialog_layout.addWidget(self.download_size_info_label, 7, 1, 1, 2) + self.force_download_check = QtWidgets.QCheckBox(InstallDialog) + self.force_download_check.setObjectName("force_download_check") + self.install_dialog_layout.addWidget(self.force_download_check, 3, 1, 1, 1) + self.install_dialog_label = QtWidgets.QLabel(InstallDialog) + self.install_dialog_label.setObjectName("install_dialog_label") + self.install_dialog_layout.addWidget(self.install_dialog_label, 0, 0, 1, 3) + self.download_only_check = QtWidgets.QCheckBox(InstallDialog) + self.download_only_check.setText("") + self.download_only_check.setObjectName("download_only_check") + self.install_dialog_layout.addWidget(self.download_only_check, 5, 1, 1, 1) + 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.setSpacing(0) + self.sdl_list_layout.setObjectName("sdl_list_layout") + self.install_dialog_layout.addWidget(self.sdl_list_frame, 6, 1, 1, 2, QtCore.Qt.AlignTop) + self.sdl_list_label = QtWidgets.QLabel(InstallDialog) + self.sdl_list_label.setObjectName("sdl_list_label") + self.install_dialog_layout.addWidget(self.sdl_list_label, 6, 0, 1, 1, QtCore.Qt.AlignRight) + + self.retranslateUi(InstallDialog) + QtCore.QMetaObject.connectSlotsByName(InstallDialog) + + def retranslateUi(self, InstallDialog): + _translate = QtCore.QCoreApplication.translate + self.force_download_label.setText(_translate("InstallDialog", "Force redownload")) + self.cancel_button.setText(_translate("InstallDialog", "Cancel")) + self.verify_button.setText(_translate("InstallDialog", "Verify")) + self.install_button.setText(_translate("InstallDialog", "Install")) + self.ignore_space_info_label.setText(_translate("InstallDialog", "Use with caution!")) + self.install_dir_label.setText(_translate("InstallDialog", "Install directory")) + self.max_workers_info_label.setText(_translate("InstallDialog", "Less is slower. (0: Default)")) + self.download_only_info_label.setText(_translate("InstallDialog", "Do not try to install.")) + self.install_size_label.setText(_translate("InstallDialog", "Total install size")) + self.ignore_space_label.setText(_translate("InstallDialog", "Ignore free space")) + self.download_only_label.setText(_translate("InstallDialog", "Download only")) + self.max_workers_label.setText(_translate("InstallDialog", "Max workers")) + self.install_size_info_label.setText(_translate("InstallDialog", "Click verify...")) + self.download_size_label.setText(_translate("InstallDialog", "Download size")) + self.download_size_info_label.setText(_translate("InstallDialog", "Click verify...")) + self.install_dialog_label.setText(_translate("InstallDialog", "error")) + self.sdl_list_label.setText(_translate("InstallDialog", "Optional packs")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + InstallDialog = QtWidgets.QDialog() + ui = Ui_InstallDialog() + ui.setupUi(InstallDialog) + InstallDialog.show() + sys.exit(app.exec_()) diff --git a/rare/ui/components/dialogs/install_dialog.ui b/rare/ui/components/dialogs/install_dialog.ui new file mode 100644 index 00000000..d6ee9141 --- /dev/null +++ b/rare/ui/components/dialogs/install_dialog.ui @@ -0,0 +1,221 @@ + + + InstallDialog + + + Rare + + + + + + Force redownload + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Cancel + + + + + + + Verify + + + + + + + Install + + + + + + + + + + true + + + + Use with caution! + + + + + + + Install directory + + + + + + + + + + + true + + + + Less is slower. (0: Default) + + + + + + + + + + + true + + + + Do not try to install. + + + + + + + Total install size + + + + + + + + + + Qt::Horizontal + + + + 0 + 0 + + + + + + + + Ignore free space + + + + + + + Download only + + + + + + + Max workers + + + + + + + + true + + + + Click verify... + + + + + + + Download size + + + + + + + + true + + + + Click verify... + + + + + + + + + + error + + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Raised + + + + 0 + + + + + + + + Optional packs + + + + + + + + diff --git a/rare/ui/components/dialogs/launch_dialog.py b/rare/ui/components/dialogs/launch_dialog.py index a563f459..bc78839f 100644 --- a/rare/ui/components/dialogs/launch_dialog.py +++ b/rare/ui/components/dialogs/launch_dialog.py @@ -8,7 +8,7 @@ # run again. Do not edit this file unless you know what you are doing. -from PyQt5 import QtCore, QtWidgets +from PyQt5 import QtCore, QtGui, QtWidgets class Ui_LaunchDialog(object): @@ -40,7 +40,7 @@ class Ui_LaunchDialog(object): def retranslateUi(self, LaunchDialog): _translate = QtCore.QCoreApplication.translate - LaunchDialog.setWindowTitle(_translate("LaunchDialog", "Dialog")) + LaunchDialog.setWindowTitle(_translate("LaunchDialog", "Launching Rare")) self.title_label.setText(_translate("LaunchDialog", "

Launching Rare

")) self.image_info.setText(_translate("LaunchDialog", "Downloading images")) self.steam_info.setText(_translate("LaunchDialog", "Getting Steam grades")) @@ -48,7 +48,6 @@ class Ui_LaunchDialog(object): if __name__ == "__main__": import sys - app = QtWidgets.QApplication(sys.argv) LaunchDialog = QtWidgets.QDialog() ui = Ui_LaunchDialog() diff --git a/rare/ui/components/dialogs/launch_dialog.ui b/rare/ui/components/dialogs/launch_dialog.ui index a5b0a134..e82ac7af 100644 --- a/rare/ui/components/dialogs/launch_dialog.ui +++ b/rare/ui/components/dialogs/launch_dialog.ui @@ -1,56 +1,56 @@ - LaunchDialog - - - - 0 - 0 - 400 - 168 - - - - Dialog - - - - - - <h2>Launching Rare</h2> - - - - - - - 0 - - - - - - - Downloading images - - - - - - - 0 - - - - - - - Getting Steam grades - - - - + LaunchDialog + + + + 0 + 0 + 400 + 168 + + + + Launching Rare + + + + + + <h2>Launching Rare</h2> + - - + + + + + 0 + + + + + + + Downloading images + + + + + + + 0 + + + + + + + Getting Steam grades + + + + + + + diff --git a/rare/ui/components/tabs/games/game_info/game_info.py b/rare/ui/components/tabs/games/game_info/game_info.py index 11f5b1d9..d320f7a9 100644 --- a/rare/ui/components/tabs/games/game_info/game_info.py +++ b/rare/ui/components/tabs/games/game_info/game_info.py @@ -22,7 +22,7 @@ class Ui_GameInfo(object): self.layout_game_info_form.setObjectName("layout_game_info_form") self.install_size = QtWidgets.QLabel(GameInfo) self.install_size.setText("error") - self.install_size.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.install_size.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.install_size.setObjectName("install_size") self.layout_game_info_form.addWidget(self.install_size, 4, 1, 1, 1) self.lbl_dev = QtWidgets.QLabel(GameInfo) @@ -39,7 +39,7 @@ class Ui_GameInfo(object): self.layout_game_info_form.addWidget(self.lbl_dev, 0, 0, 1, 1, QtCore.Qt.AlignRight) self.version = QtWidgets.QLabel(GameInfo) self.version.setText("error") - self.version.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.version.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.version.setObjectName("version") self.layout_game_info_form.addWidget(self.version, 2, 1, 1, 1) self.lbl_install_path = QtWidgets.QLabel(GameInfo) @@ -70,43 +70,6 @@ class Ui_GameInfo(object): self.layout_game_info_form.addItem(spacerItem, 7, 1, 1, 1) spacerItem1 = QtWidgets.QSpacerItem(20, 0, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) self.layout_game_info_form.addItem(spacerItem1, 7, 0, 1, 1) - self.wg_game_actions = QtWidgets.QWidget(GameInfo) - self.wg_game_actions.setMinimumSize(QtCore.QSize(250, 0)) - self.wg_game_actions.setObjectName("wg_game_actions") - self.layout_game_actions = QtWidgets.QVBoxLayout(self.wg_game_actions) - self.layout_game_actions.setContentsMargins(0, 0, 0, 0) - self.layout_game_actions.setObjectName("layout_game_actions") - self.uninstall_button = QtWidgets.QPushButton(self.wg_game_actions) - self.uninstall_button.setObjectName("uninstall_button") - self.layout_game_actions.addWidget(self.uninstall_button) - self.verify_widget = QtWidgets.QStackedWidget(self.wg_game_actions) - self.verify_widget.setObjectName("verify_widget") - self.page_verify_button = QtWidgets.QWidget() - self.page_verify_button.setObjectName("page_verify_button") - self.layout_verify_button = QtWidgets.QVBoxLayout(self.page_verify_button) - self.layout_verify_button.setContentsMargins(0, 0, 0, 0) - self.layout_verify_button.setSpacing(0) - self.layout_verify_button.setObjectName("layout_verify_button") - self.verify_button = QtWidgets.QPushButton(self.page_verify_button) - self.verify_button.setObjectName("verify_button") - self.layout_verify_button.addWidget(self.verify_button) - self.verify_widget.addWidget(self.page_verify_button) - self.page_verify_progress = QtWidgets.QWidget() - self.page_verify_progress.setObjectName("page_verify_progress") - self.layout_verify_progress = QtWidgets.QVBoxLayout(self.page_verify_progress) - self.layout_verify_progress.setContentsMargins(0, 0, 0, 0) - self.layout_verify_progress.setSpacing(0) - self.layout_verify_progress.setObjectName("layout_verify_progress") - self.verify_progress = QtWidgets.QProgressBar(self.page_verify_progress) - self.verify_progress.setProperty("value", 24) - self.verify_progress.setObjectName("verify_progress") - self.layout_verify_progress.addWidget(self.verify_progress) - self.verify_widget.addWidget(self.page_verify_progress) - self.layout_game_actions.addWidget(self.verify_widget) - self.repair_button = QtWidgets.QPushButton(self.wg_game_actions) - self.repair_button.setObjectName("repair_button") - self.layout_game_actions.addWidget(self.repair_button) - self.layout_game_info_form.addWidget(self.wg_game_actions, 6, 1, 1, 1, QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) self.lbl_version = QtWidgets.QLabel(GameInfo) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -133,18 +96,18 @@ class Ui_GameInfo(object): self.layout_game_info_form.addWidget(self.lbl_app_name, 1, 0, 1, 1, QtCore.Qt.AlignRight) self.dev = QtWidgets.QLabel(GameInfo) self.dev.setText("error") - self.dev.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.dev.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.dev.setObjectName("dev") self.layout_game_info_form.addWidget(self.dev, 0, 1, 1, 1) self.app_name = QtWidgets.QLabel(GameInfo) self.app_name.setText("error") - self.app_name.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.app_name.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.app_name.setObjectName("app_name") self.layout_game_info_form.addWidget(self.app_name, 1, 1, 1, 1) self.install_path = QtWidgets.QLabel(GameInfo) self.install_path.setText("error") self.install_path.setWordWrap(True) - self.install_path.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.install_path.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.install_path.setObjectName("install_path") self.layout_game_info_form.addWidget(self.install_path, 5, 1, 1, 1) self.lbl_game_actions = QtWidgets.QLabel(GameInfo) @@ -168,23 +131,74 @@ class Ui_GameInfo(object): self.layout_game_info_form.addWidget(self.lbl_grade, 3, 0, 1, 1, QtCore.Qt.AlignRight) self.grade = QtWidgets.QLabel(GameInfo) self.grade.setText("error") - self.grade.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.grade.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.grade.setObjectName("grade") self.layout_game_info_form.addWidget(self.grade, 3, 1, 1, 1) + self.game_actions_stack = QtWidgets.QStackedWidget(GameInfo) + self.game_actions_stack.setMinimumSize(QtCore.QSize(250, 0)) + self.game_actions_stack.setObjectName("game_actions_stack") + self.installed_page = QtWidgets.QWidget() + self.installed_page.setObjectName("installed_page") + self.installed_layout = QtWidgets.QVBoxLayout(self.installed_page) + self.installed_layout.setContentsMargins(0, 0, 0, 0) + self.installed_layout.setObjectName("installed_layout") + self.verify_widget = QtWidgets.QStackedWidget(self.installed_page) + self.verify_widget.setObjectName("verify_widget") + self.page_verify_button = QtWidgets.QWidget() + self.page_verify_button.setObjectName("page_verify_button") + self.layout_verify_button = QtWidgets.QVBoxLayout(self.page_verify_button) + self.layout_verify_button.setContentsMargins(0, 0, 0, 0) + self.layout_verify_button.setSpacing(0) + self.layout_verify_button.setObjectName("layout_verify_button") + self.verify_button = QtWidgets.QPushButton(self.page_verify_button) + self.verify_button.setObjectName("verify_button") + self.layout_verify_button.addWidget(self.verify_button) + self.verify_widget.addWidget(self.page_verify_button) + self.page_verify_progress = QtWidgets.QWidget() + self.page_verify_progress.setObjectName("page_verify_progress") + self.layout_verify_progress = QtWidgets.QVBoxLayout(self.page_verify_progress) + self.layout_verify_progress.setContentsMargins(0, 0, 0, 0) + self.layout_verify_progress.setSpacing(0) + self.layout_verify_progress.setObjectName("layout_verify_progress") + self.verify_progress = QtWidgets.QProgressBar(self.page_verify_progress) + self.verify_progress.setProperty("value", 24) + self.verify_progress.setObjectName("verify_progress") + self.layout_verify_progress.addWidget(self.verify_progress) + self.verify_widget.addWidget(self.page_verify_progress) + self.installed_layout.addWidget(self.verify_widget) + self.repair_button = QtWidgets.QPushButton(self.installed_page) + self.repair_button.setObjectName("repair_button") + self.installed_layout.addWidget(self.repair_button) + self.uninstall_button = QtWidgets.QPushButton(self.installed_page) + self.uninstall_button.setStyleSheet("background-color: #900") + self.uninstall_button.setObjectName("uninstall_button") + self.installed_layout.addWidget(self.uninstall_button) + self.game_actions_stack.addWidget(self.installed_page) + self.uninstalled_page = QtWidgets.QWidget() + self.uninstalled_page.setObjectName("uninstalled_page") + self.uninstalled_layout = QtWidgets.QVBoxLayout(self.uninstalled_page) + self.uninstalled_layout.setObjectName("uninstalled_layout") + self.install_button = QtWidgets.QPushButton(self.uninstalled_page) + self.install_button.setStyleSheet("background-color: #090") + self.install_button.setObjectName("install_button") + self.uninstalled_layout.addWidget(self.install_button) + self.game_actions_stack.addWidget(self.uninstalled_page) + self.layout_game_info_form.addWidget(self.game_actions_stack, 6, 1, 1, 1, QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.layout_game_info.addLayout(self.layout_game_info_form, 2, 1, 1, 1) self.image = QtWidgets.QLabel(GameInfo) self.image.setFrameShape(QtWidgets.QFrame.StyledPanel) self.image.setFrameShadow(QtWidgets.QFrame.Sunken) self.image.setText("") self.image.setObjectName("image") - self.layout_game_info.addWidget(self.image, 2, 0, 1, 1, QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop) + self.layout_game_info.addWidget(self.image, 2, 0, 1, 1, QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop) self.game_title = QtWidgets.QLabel(GameInfo) self.game_title.setText("error") - self.game_title.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextSelectableByMouse) + self.game_title.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse) self.game_title.setObjectName("game_title") self.layout_game_info.addWidget(self.game_title, 0, 0, 1, 3) self.retranslateUi(GameInfo) + self.game_actions_stack.setCurrentIndex(0) self.verify_widget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(GameInfo) @@ -194,18 +208,18 @@ class Ui_GameInfo(object): self.lbl_dev.setText(_translate("GameInfo", "Developer")) self.lbl_install_path.setText(_translate("GameInfo", "Installation Path")) self.lbl_install_size.setText(_translate("GameInfo", "Installation Size")) - self.uninstall_button.setText(_translate("GameInfo", "Uninstall Game")) - self.verify_button.setText(_translate("GameInfo", "Verify Installation")) - self.repair_button.setText(_translate("GameInfo", "Repair Instalation")) self.lbl_version.setText(_translate("GameInfo", "Version")) self.lbl_app_name.setText(_translate("GameInfo", "Application Name")) self.lbl_game_actions.setText(_translate("GameInfo", "Actions")) self.lbl_grade.setText(_translate("GameInfo", "ProtonDB Grade")) + self.verify_button.setText(_translate("GameInfo", "Verify Installation")) + self.repair_button.setText(_translate("GameInfo", "Repair Instalation")) + self.uninstall_button.setText(_translate("GameInfo", "Uninstall Game")) + self.install_button.setText(_translate("GameInfo", "Install Game")) if __name__ == "__main__": import sys - app = QtWidgets.QApplication(sys.argv) GameInfo = QtWidgets.QWidget() ui = Ui_GameInfo() diff --git a/rare/ui/components/tabs/games/game_info/game_info.ui b/rare/ui/components/tabs/games/game_info/game_info.ui index 1d1926b6..edec48ef 100644 --- a/rare/ui/components/tabs/games/game_info/game_info.ui +++ b/rare/ui/components/tabs/games/game_info/game_info.ui @@ -1,376 +1,390 @@ - GameInfo - - - - 0 - 0 - 436 - 317 - - - - Game Info - - - - - - 6 - - - 6 - - - 6 - - - 6 - - - 12 - - - - - error - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Developer - - - - - - - error - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Installation Path - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Installation Size - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - 250 - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Uninstall Game - - - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Verify Installation - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 24 - - - - - - - - - - - Repair Instalation - - - - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Version - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Application Name - - - - - - - error - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - error - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - error - - - true - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - 0 - 0 - - - - - 75 - true - - - - Actions - - - - - - - - 75 - true - - - - ProtonDB Grade - - - - - - - error - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - - - QFrame::StyledPanel - - - QFrame::Sunken - - - - - - - - - - error - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - + GameInfo + + + Game Info + + + + + + 6 + + + 6 + + + 6 + + + 6 + + + 12 + + + + + error + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Developer + + + + + + + error + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Installation Path + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Installation Size + + + + + + + Qt::Horizontal + + + + 0 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 0 + + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Version + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Application Name + + + + + + + error + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + error + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + error + + + true + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 0 + 0 + + + + + 75 + true + + + + Actions + + + + + + + + 75 + true + + + + ProtonDB Grade + + + + + + + error + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + + 250 + 0 + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Verify Installation + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 24 + + + + + + + + + + + Repair Instalation + + + + + + + background-color: #900 + + + Uninstall Game + + + + + + + + + + background-color: #090 + + + Install Game + + + + + + + + + + + + + QFrame::StyledPanel + + + QFrame::Sunken + + + + - - + + + + + error + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + diff --git a/rare/ui/components/tabs/settings/rare.py b/rare/ui/components/tabs/settings/rare.py index b7f6b1ff..6e948018 100644 --- a/rare/ui/components/tabs/settings/rare.py +++ b/rare/ui/components/tabs/settings/rare.py @@ -16,56 +16,26 @@ class Ui_RareSettings(object): RareSettings.setObjectName("RareSettings") self.rare_layout = QtWidgets.QGridLayout(RareSettings) self.rare_layout.setObjectName("rare_layout") - self.interface_group = QtWidgets.QGroupBox(RareSettings) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.interface_group.sizePolicy().hasHeightForWidth()) - self.interface_group.setSizePolicy(sizePolicy) - self.interface_group.setObjectName("interface_group") - self.interface_layout = QtWidgets.QGridLayout(self.interface_group) - self.interface_layout.setObjectName("interface_layout") - self.color_select = QtWidgets.QComboBox(self.interface_group) - self.color_select.setObjectName("color_select") - self.color_select.addItem("") - self.interface_layout.addWidget(self.color_select, 1, 1, 1, 1) - self.style_label = QtWidgets.QLabel(self.interface_group) - self.style_label.setObjectName("style_label") - self.interface_layout.addWidget(self.style_label, 2, 0, 1, 1, QtCore.Qt.AlignRight) - self.lang_label = QtWidgets.QLabel(self.interface_group) - self.lang_label.setObjectName("lang_label") - self.interface_layout.addWidget(self.lang_label, 0, 0, 1, 1, QtCore.Qt.AlignRight) - self.lang_select = QtWidgets.QComboBox(self.interface_group) - self.lang_select.setObjectName("lang_select") - self.interface_layout.addWidget(self.lang_select, 0, 1, 1, 1) - self.color_label = QtWidgets.QLabel(self.interface_group) - self.color_label.setObjectName("color_label") - self.interface_layout.addWidget(self.color_label, 1, 0, 1, 1, QtCore.Qt.AlignRight) - self.interface_info = QtWidgets.QLabel(self.interface_group) - font = QtGui.QFont() - font.setItalic(True) - self.interface_info.setFont(font) - self.interface_info.setWordWrap(True) - self.interface_info.setObjectName("interface_info") - self.interface_layout.addWidget(self.interface_info, 3, 0, 1, 3) - self.style_select = QtWidgets.QComboBox(self.interface_group) - self.style_select.setObjectName("style_select") - self.style_select.addItem("") - self.interface_layout.addWidget(self.style_select, 2, 1, 1, 1) - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.interface_layout.addItem(spacerItem, 1, 2, 1, 1) - self.rare_layout.addWidget(self.interface_group, 1, 0, 1, 1, QtCore.Qt.AlignTop) - self.img_dir_group = QtWidgets.QGroupBox(RareSettings) - self.img_dir_group.setObjectName("img_dir_group") - self.img_dir_layout = QtWidgets.QVBoxLayout(self.img_dir_group) - self.img_dir_layout.setObjectName("img_dir_layout") - self.rare_layout.addWidget(self.img_dir_group, 0, 0, 1, 1, QtCore.Qt.AlignTop) + self.rpc_layout = QtWidgets.QVBoxLayout() + self.rpc_layout.setObjectName("rpc_layout") + self.rare_layout.addLayout(self.rpc_layout, 1, 1, 1, 1) + self.groupBox = QtWidgets.QGroupBox(RareSettings) + self.groupBox.setObjectName("groupBox") + self.verticalLayout = QtWidgets.QVBoxLayout(self.groupBox) + self.verticalLayout.setObjectName("verticalLayout") + self.desktop_link = QtWidgets.QPushButton(self.groupBox) + self.desktop_link.setObjectName("desktop_link") + self.verticalLayout.addWidget(self.desktop_link) + self.startmenu_link = QtWidgets.QPushButton(self.groupBox) + self.startmenu_link.setObjectName("startmenu_link") + self.verticalLayout.addWidget(self.startmenu_link) + self.rare_layout.addWidget(self.groupBox, 2, 1, 1, 1, QtCore.Qt.AlignTop) self.settings_group = QtWidgets.QGroupBox(RareSettings) self.settings_group.setObjectName("settings_group") self.behavior_layout = QtWidgets.QGridLayout(self.settings_group) self.behavior_layout.setObjectName("behavior_layout") - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.behavior_layout.addItem(spacerItem1, 2, 1, 2, 1) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.behavior_layout.addItem(spacerItem, 2, 1, 2, 1) self.save_size = QtWidgets.QCheckBox(self.settings_group) self.save_size.setObjectName("save_size") self.behavior_layout.addWidget(self.save_size, 5, 0, 1, 1) @@ -101,11 +71,52 @@ class Ui_RareSettings(object): self.log_dir_size_label.setObjectName("log_dir_size_label") self.log_dir_layout.addWidget(self.log_dir_size_label) self.rare_layout.addWidget(self.log_dir_group, 0, 1, 1, 1, QtCore.Qt.AlignTop) - self.rpc_layout = QtWidgets.QVBoxLayout() - self.rpc_layout.setObjectName("rpc_layout") - self.rare_layout.addLayout(self.rpc_layout, 1, 1, 1, 1) + self.interface_group = QtWidgets.QGroupBox(RareSettings) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.interface_group.sizePolicy().hasHeightForWidth()) + self.interface_group.setSizePolicy(sizePolicy) + self.interface_group.setObjectName("interface_group") + self.interface_layout = QtWidgets.QGridLayout(self.interface_group) + self.interface_layout.setObjectName("interface_layout") + self.color_select = QtWidgets.QComboBox(self.interface_group) + self.color_select.setObjectName("color_select") + self.color_select.addItem("") + self.interface_layout.addWidget(self.color_select, 1, 1, 1, 1) + self.style_label = QtWidgets.QLabel(self.interface_group) + self.style_label.setObjectName("style_label") + self.interface_layout.addWidget(self.style_label, 2, 0, 1, 1, QtCore.Qt.AlignRight) + self.style_select = QtWidgets.QComboBox(self.interface_group) + self.style_select.setObjectName("style_select") + self.style_select.addItem("") + self.interface_layout.addWidget(self.style_select, 2, 1, 1, 1) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.interface_layout.addItem(spacerItem1, 1, 2, 1, 1) + self.interface_info = QtWidgets.QLabel(self.interface_group) + font = QtGui.QFont() + font.setItalic(True) + self.interface_info.setFont(font) + self.interface_info.setWordWrap(True) + self.interface_info.setObjectName("interface_info") + self.interface_layout.addWidget(self.interface_info, 3, 0, 1, 3) + self.lang_label = QtWidgets.QLabel(self.interface_group) + self.lang_label.setObjectName("lang_label") + self.interface_layout.addWidget(self.lang_label, 0, 0, 1, 1, QtCore.Qt.AlignRight) + self.lang_select = QtWidgets.QComboBox(self.interface_group) + self.lang_select.setObjectName("lang_select") + self.interface_layout.addWidget(self.lang_select, 0, 1, 1, 1) + self.color_label = QtWidgets.QLabel(self.interface_group) + self.color_label.setObjectName("color_label") + self.interface_layout.addWidget(self.color_label, 1, 0, 1, 1, QtCore.Qt.AlignRight) + self.rare_layout.addWidget(self.interface_group, 1, 0, 1, 1, QtCore.Qt.AlignTop) + self.img_dir_group = QtWidgets.QGroupBox(RareSettings) + self.img_dir_group.setObjectName("img_dir_group") + self.img_dir_layout = QtWidgets.QVBoxLayout(self.img_dir_group) + self.img_dir_layout.setObjectName("img_dir_layout") + self.rare_layout.addWidget(self.img_dir_group, 0, 0, 1, 1, QtCore.Qt.AlignTop) spacerItem2 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) - self.rare_layout.addItem(spacerItem2, 2, 1, 1, 1) + self.rare_layout.addItem(spacerItem2, 3, 0, 1, 2) self.retranslateUi(RareSettings) QtCore.QMetaObject.connectSlotsByName(RareSettings) @@ -113,14 +124,9 @@ class Ui_RareSettings(object): def retranslateUi(self, RareSettings): _translate = QtCore.QCoreApplication.translate RareSettings.setWindowTitle(_translate("RareSettings", "RareSettings")) - self.interface_group.setTitle(_translate("RareSettings", "Interface")) - self.color_select.setItemText(0, _translate("RareSettings", "None")) - self.style_label.setText(_translate("RareSettings", "Style Sheet")) - self.lang_label.setText(_translate("RareSettings", "Language")) - self.color_label.setText(_translate("RareSettings", "Color Scheme")) - self.interface_info.setText(_translate("RareSettings", "Restart Rare to apply.")) - self.style_select.setItemText(0, _translate("RareSettings", "None")) - self.img_dir_group.setTitle(_translate("RareSettings", "Image Cache Directory")) + self.groupBox.setTitle(_translate("RareSettings", "Shortcuts")) + self.desktop_link.setText(_translate("RareSettings", "Create Desktop link")) + self.startmenu_link.setText(_translate("RareSettings", "Create start menu link")) self.settings_group.setTitle(_translate("RareSettings", "Behavior")) self.save_size.setText(_translate("RareSettings", "Restore window size on application startup")) self.notification.setText(_translate("RareSettings", "Show notification on download completion")) @@ -131,11 +137,18 @@ class Ui_RareSettings(object): self.log_dir_group.setTitle(_translate("RareSettings", "Logs")) self.log_dir_open_button.setText(_translate("RareSettings", "Open Log directory")) self.log_dir_clean_button.setText(_translate("RareSettings", "Clean Log directory")) + self.interface_group.setTitle(_translate("RareSettings", "Interface")) + self.color_select.setItemText(0, _translate("RareSettings", "None")) + self.style_label.setText(_translate("RareSettings", "Style Sheet")) + self.style_select.setItemText(0, _translate("RareSettings", "None")) + self.interface_info.setText(_translate("RareSettings", "Restart Rare to apply.")) + self.lang_label.setText(_translate("RareSettings", "Language")) + self.color_label.setText(_translate("RareSettings", "Color Scheme")) + self.img_dir_group.setTitle(_translate("RareSettings", "Image Cache Directory")) if __name__ == "__main__": import sys - app = QtWidgets.QApplication(sys.argv) RareSettings = QtWidgets.QWidget() ui = Ui_RareSettings() diff --git a/rare/ui/components/tabs/settings/rare.ui b/rare/ui/components/tabs/settings/rare.ui index 0b0c6193..377f874c 100644 --- a/rare/ui/components/tabs/settings/rare.ui +++ b/rare/ui/components/tabs/settings/rare.ui @@ -1,219 +1,242 @@ - RareSettings - - - RareSettings + RareSettings + + + RareSettings + + + + + + + + + Shortcuts + + + + + + Create Desktop link - - - - - - 0 - 0 - - - - Interface - - - - - - - None - - - - - - - - Style Sheet - - - - - - - Language - - - - - - - - - - Color Scheme - - - - - - - - true - - - - Restart Rare to apply. - - - true - - - - - - - - None - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - Image Cache Directory - - - - - - - - Behavior - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Restore window size on application startup - - - - - - - Show notification on download completion - - - - - - - Automatically sync with cloud - - - - - - - Confirm game launch - - - - - - - Update games on application startup - - - - - - - Exit to System tray - - - - - - - - - - Logs - - - - - - Open Log directory - - - - - - - Clean Log directory - - - - - - - - - - true - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + + + + Create start menu link + + + + - - + + + + + Behavior + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Restore window size on application startup + + + + + + + Show notification on download completion + + + + + + + Automatically sync with cloud + + + + + + + Confirm game launch + + + + + + + Update games on application startup + + + + + + + Exit to System tray + + + + + + + + + + Logs + + + + + + Open Log directory + + + + + + + Clean Log directory + + + + + + + + + + true + + + + + + + + + + + 0 + 0 + + + + Interface + + + + + + + None + + + + + + + + Style Sheet + + + + + + + + None + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + true + + + + Restart Rare to apply. + + + true + + + + + + + Language + + + + + + + + + + Color Scheme + + + + + + + + + + Image Cache Directory + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + diff --git a/rare/utils/extra_widgets.py b/rare/utils/extra_widgets.py index 31db79cf..121ab59d 100644 --- a/rare/utils/extra_widgets.py +++ b/rare/utils/extra_widgets.py @@ -152,6 +152,9 @@ class PathEdit(QWidget, Ui_PathEdit): def text(self): return self.text_edit.text() + def setText(self, text: str): + self.text_edit.setText(text) + def save(self): self.save_func() self.save_path_button.setDisabled(True) diff --git a/rare/utils/models.py b/rare/utils/models.py index 503d0532..44400ddc 100644 --- a/rare/utils/models.py +++ b/rare/utils/models.py @@ -1,15 +1,36 @@ import os -class InstallOptions: - def __init__(self, app_name: str, path: str = os.path.expanduser("~/legendary"), - max_workers: int = os.cpu_count() * 2, repair: bool = False, - download_only: bool = False, ignore_free_space: bool = False, force: bool = False, +class InstallOptionsModel: + def __init__(self, app_name: str, base_path: str = os.path.expanduser("~/legendary"), + max_workers: int = os.cpu_count() * 2, repair: bool = False, no_install: bool = False, + ignore_space_req: bool = False, force: bool = False, sdl_list: list = [''] ): self.app_name = app_name - self.path = path + self.base_path = base_path self.max_workers = max_workers self.repair = repair - self.download_only = download_only - self.ignore_free_space = ignore_free_space + self.no_install = no_install + self.ignore_space_req = ignore_space_req self.force = force + self.sdl_list = sdl_list + + +class InstallDownloadModel: + def __init__(self, dlmanager, analysis, game, igame, repair: bool, repair_file: str): + self.dlmanager = dlmanager + self.analysis = analysis + self.game = game + self.igame = igame + self.repair = repair + self.repair_file = repair_file + + +class InstallQueueItemModel: + def __init__(self, status_q=None, download: InstallDownloadModel = None, options: InstallOptionsModel = None): + self.status_q = status_q + self.download = download + self.options = options + + def __bool__(self): + return (self.status_q is not None) and (self.download is not None) and (self.options is not None) diff --git a/rare/utils/utils.py b/rare/utils/utils.py index c09c4f1a..f295a28b 100644 --- a/rare/utils/utils.py +++ b/rare/utils/utils.py @@ -157,7 +157,7 @@ color_group_map = { def load_color_scheme(path: str): - custom_palette = QPalette() + palette = QPalette() settings = QSettings(path, QSettings.IniFormat) try: settings.beginGroup("ColorScheme") @@ -166,17 +166,16 @@ def load_color_scheme(path: str): group = QPalette.ColorGroup(g) for r in color_role_map: role = QPalette.ColorRole(r) - custom_palette.setColor(group, role, QColor(settings.value(color_role_map[r]))) + color = settings.value(color_role_map[r], None) + if color is not None: + palette.setColor(group, role, QColor(color)) + else: + palette.setColor(group, role, palette.color(QPalette.Active, role)) settings.endGroup() settings.endGroup() - text_color = custom_palette.text().color() - text_color.setAlpha(128) - custom_palette.setColor(custom_palette.Active, custom_palette.PlaceholderText, text_color) - custom_palette.setColor(custom_palette.Inactive, custom_palette.PlaceholderText, text_color) - custom_palette.setColor(custom_palette.Disabled, custom_palette.PlaceholderText, text_color) except: - custom_palette = None - return custom_palette + palette = None + return palette def get_color_schemes(): @@ -219,8 +218,58 @@ def get_size(b: int) -> str: b /= 1024 +def create_rare_desktop_link(type_of_link): + # Linux + if os.name == "posix": + if type_of_link == "desktop": + path = os.path.expanduser(f"~/Desktop/") + elif type_of_link == "start_menu": + path = os.path.expanduser("~/.local/share/applications/") + else: + return + + with open(f"{path}Rare.desktop", "w") as desktop_file: + desktop_file.write("[Desktop Entry]\n" + f"Name=Rare\n" + f"Type=Application\n" + f"Icon={os.path.join(style_path, 'Logo.png')}\n" + f"Exec={os.path.abspath(sys.argv[0])}\n" + "Terminal=false\n" + "StartupWMClass=rare\n" + ) + desktop_file.close() + os.chmod(os.path.expanduser(f"{path}Rare.desktop"), 0o755) + + elif os.name == "nt": + # Target of shortcut + if type_of_link == "desktop": + target_folder = os.path.expanduser('~/Desktop/') + elif type_of_link == "start_menu": + target_folder = os.path.expandvars("%appdata%/Microsoft/Windows/Start Menu") + else: + logger.warning("No valid type of link") + return + linkName = "Rare.lnk" + + # Path to location of link file + pathLink = os.path.join(target_folder, linkName) + + # Add shortcut + shell = Dispatch('WScript.Shell') + shortcut = shell.CreateShortCut(pathLink) + shortcut.Targetpath = os.path.abspath(sys.argv[0]) + shortcut.Arguments = "" + shortcut.WorkingDirectory = os.getcwd() + + # Icon + shortcut.IconLocation = os.path.join(style_path, "Logo.ico") + + shortcut.save() + + def create_desktop_link(app_name, core: LegendaryCore, type_of_link="desktop"): igame = core.get_installed_game(app_name) + if os.path.exists( os.path.join(QSettings('Rare', 'Rare').value('img_dir', os.path.expanduser('~/.cache/rare/images'), str), igame.app_name, 'Thumbnail.png')):