Merge pull request #370 from loathingKernel/next
Refactor EOS overlay management form
This commit is contained in:
commit
f9f9caf956
8
.github/workflows/checks.yml
vendored
8
.github/workflows/checks.yml
vendored
|
@ -22,13 +22,17 @@ on:
|
|||
|
||||
jobs:
|
||||
pylint:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-latest]
|
||||
version: [3.9, 3.10, 3.11, 3.12]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.9'
|
||||
python-version: ${{ matris.version }}
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python3 -m pip install --upgrade pip
|
||||
|
|
|
@ -12,7 +12,7 @@ from requests import HTTPError
|
|||
from rare.components.dialogs.launch_dialog import LaunchDialog
|
||||
from rare.components.main_window import MainWindow
|
||||
from rare.shared import RareCore
|
||||
from rare.utils import config_helper, paths
|
||||
from rare.utils import paths
|
||||
from rare.utils.misc import ExitCodes
|
||||
from rare.widgets.rare_app import RareApp, RareAppException
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ from typing import Tuple, List, Union, Optional
|
|||
from PyQt5.QtCore import QThreadPool, QSettings
|
||||
from PyQt5.QtCore import pyqtSignal, pyqtSlot
|
||||
from PyQt5.QtGui import QShowEvent
|
||||
from PyQt5.QtWidgets import QFileDialog, QCheckBox, QWidget, QVBoxLayout, QFormLayout
|
||||
from legendary.utils.selective_dl import get_sdl_appname
|
||||
from PyQt5.QtWidgets import QFileDialog, QCheckBox, QWidget, QFormLayout
|
||||
|
||||
from rare.models.game import RareGame
|
||||
from rare.models.install import InstallDownloadModel, InstallQueueItemModel, InstallOptionsModel
|
||||
|
@ -15,18 +14,46 @@ from rare.shared.workers.install_info import InstallInfoWorker
|
|||
from rare.ui.components.dialogs.install_dialog import Ui_InstallDialog
|
||||
from rare.ui.components.dialogs.install_dialog_advanced import Ui_InstallDialogAdvanced
|
||||
from rare.utils.misc import format_size, icon
|
||||
from rare.widgets.dialogs import ActionDialog, dialog_title_game
|
||||
from rare.widgets.collapsible_widget import CollapsibleFrame
|
||||
from rare.widgets.dialogs import ActionDialog, dialog_title_game
|
||||
from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon
|
||||
from rare.widgets.selective_widget import SelectiveWidget
|
||||
|
||||
|
||||
class InstallDialogAdvanced(CollapsibleFrame):
|
||||
def __init__(self, parent=None):
|
||||
widget = QWidget(parent)
|
||||
title = widget.tr("Advanced options")
|
||||
super(InstallDialogAdvanced, self).__init__(parent=parent)
|
||||
|
||||
title = self.tr("Advanced options")
|
||||
self.setTitle(title)
|
||||
|
||||
self.widget = QWidget(parent=self)
|
||||
self.ui = Ui_InstallDialogAdvanced()
|
||||
self.ui.setupUi(widget)
|
||||
super(InstallDialogAdvanced, self).__init__(widget=widget, title=title, parent=parent)
|
||||
self.ui.setupUi(self.widget)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
|
||||
class InstallDialogSelective(CollapsibleFrame):
|
||||
stateChanged: pyqtSignal = pyqtSignal()
|
||||
|
||||
def __init__(self, rgame: RareGame, parent=None):
|
||||
super(InstallDialogSelective, self).__init__(parent=parent)
|
||||
title = self.tr("Optional downloads")
|
||||
self.setTitle(title)
|
||||
self.setEnabled(bool(rgame.sdl_name))
|
||||
|
||||
self.widget: SelectiveWidget = None
|
||||
self.rgame = rgame
|
||||
|
||||
def update_list(self, platform: str):
|
||||
if self.widget is not None:
|
||||
self.widget.deleteLater()
|
||||
self.widget = SelectiveWidget(self.rgame, platform, parent=self)
|
||||
self.widget.stateChanged.connect(self.stateChanged)
|
||||
self.setWidget(self.widget)
|
||||
|
||||
def install_tags(self):
|
||||
return self.widget.install_tags()
|
||||
|
||||
|
||||
class InstallDialog(ActionDialog):
|
||||
|
@ -48,13 +75,12 @@ class InstallDialog(ActionDialog):
|
|||
header = self.tr("Modify")
|
||||
bicon = icon("fa.gear")
|
||||
self.setWindowTitle(dialog_title_game(header, rgame.app_title))
|
||||
self.setSubtitle(dialog_title_game(header, rgame.app_title))
|
||||
|
||||
install_widget = QWidget(self)
|
||||
self.ui = Ui_InstallDialog()
|
||||
self.ui.setupUi(install_widget)
|
||||
|
||||
self.ui.title_label.setText(f"<h4>{dialog_title_game(header, rgame.app_title)}</h4>")
|
||||
|
||||
self.core = rgame.core
|
||||
self.rgame = rgame
|
||||
self.__options: InstallOptionsModel = options
|
||||
|
@ -64,7 +90,8 @@ class InstallDialog(ActionDialog):
|
|||
self.advanced = InstallDialogAdvanced(parent=self)
|
||||
self.ui.advanced_layout.addWidget(self.advanced)
|
||||
|
||||
self.selectable = CollapsibleFrame(widget=None, title=self.tr("Optional downloads"), parent=self)
|
||||
self.selectable = InstallDialogSelective(rgame, parent=self)
|
||||
self.selectable.stateChanged.connect(self.option_changed)
|
||||
self.ui.selectable_layout.addWidget(self.selectable)
|
||||
|
||||
self.options_changed = False
|
||||
|
@ -82,13 +109,14 @@ class InstallDialog(ActionDialog):
|
|||
self.install_dir_edit = PathEdit(
|
||||
path=base_path,
|
||||
file_mode=QFileDialog.DirectoryOnly,
|
||||
edit_func=self.option_changed,
|
||||
save_func=self.save_install_edit,
|
||||
edit_func=self.install_dir_edit_callback,
|
||||
save_func=self.install_dir_save_callback,
|
||||
parent=self,
|
||||
)
|
||||
self.ui.main_layout.setWidget(
|
||||
self.ui.main_layout.getWidgetPosition(self.ui.install_dir_label)[0],
|
||||
QFormLayout.FieldRole, self.install_dir_edit
|
||||
QFormLayout.FieldRole,
|
||||
self.install_dir_edit,
|
||||
)
|
||||
|
||||
self.install_dir_edit.setDisabled(rgame.is_installed)
|
||||
|
@ -102,10 +130,10 @@ class InstallDialog(ActionDialog):
|
|||
self.ui.platform_combo.addItems(reversed(rgame.platforms))
|
||||
combo_text = rgame.igame.platform if rgame.is_installed else rgame.default_platform
|
||||
self.ui.platform_combo.setCurrentIndex(self.ui.platform_combo.findText(combo_text))
|
||||
self.ui.platform_combo.currentIndexChanged.connect(lambda i: self.option_changed(None))
|
||||
self.ui.platform_combo.currentIndexChanged.connect(self.option_changed)
|
||||
self.ui.platform_combo.currentIndexChanged.connect(self.check_incompatible_platform)
|
||||
self.ui.platform_combo.currentIndexChanged.connect(self.reset_install_dir)
|
||||
self.ui.platform_combo.currentIndexChanged.connect(self.reset_sdl_list)
|
||||
self.ui.platform_combo.currentTextChanged.connect(self.selectable.update_list)
|
||||
|
||||
self.ui.platform_label.setDisabled(rgame.is_installed)
|
||||
self.ui.platform_combo.setDisabled(rgame.is_installed)
|
||||
|
@ -131,11 +159,8 @@ class InstallDialog(ActionDialog):
|
|||
lambda: self.non_reload_option_changed("shortcut")
|
||||
)
|
||||
|
||||
self.selectable_checks: List[TagCheckBox] = []
|
||||
self.config_tags: Optional[List[str]] = None
|
||||
|
||||
self.reset_install_dir(self.ui.platform_combo.currentIndex())
|
||||
self.reset_sdl_list(self.ui.platform_combo.currentIndex())
|
||||
self.selectable.update_list(self.ui.platform_combo.currentText())
|
||||
self.check_incompatible_platform(self.ui.platform_combo.currentIndex())
|
||||
|
||||
self.accept_button.setEnabled(False)
|
||||
|
@ -180,7 +205,7 @@ class InstallDialog(ActionDialog):
|
|||
def showEvent(self, a0: QShowEvent) -> None:
|
||||
if a0.spontaneous():
|
||||
return super().showEvent(a0)
|
||||
self.save_install_edit(self.install_dir_edit.text())
|
||||
self.install_dir_save_callback(self.install_dir_edit.text())
|
||||
super().showEvent(a0)
|
||||
|
||||
def execute(self):
|
||||
|
@ -197,68 +222,31 @@ class InstallDialog(ActionDialog):
|
|||
default_dir = self.core.get_default_install_dir(platform)
|
||||
self.install_dir_edit.setText(default_dir)
|
||||
|
||||
@pyqtSlot(int)
|
||||
def reset_sdl_list(self, index: int):
|
||||
platform = self.ui.platform_combo.itemText(index)
|
||||
for cb in self.selectable_checks:
|
||||
cb.disconnect()
|
||||
cb.deleteLater()
|
||||
self.selectable_checks.clear()
|
||||
|
||||
if config_tags := self.core.lgd.config.get(self.rgame.app_name, 'install_tags', fallback=None):
|
||||
self.config_tags = config_tags.split(",")
|
||||
config_disable_sdl = self.core.lgd.config.getboolean(self.rgame.app_name, 'disable_sdl', fallback=False)
|
||||
sdl_name = get_sdl_appname(self.rgame.app_name)
|
||||
if not config_disable_sdl and sdl_name is not None:
|
||||
sdl_data = self.core.get_sdl_data(sdl_name, platform=platform)
|
||||
if sdl_data:
|
||||
widget = QWidget(self.selectable)
|
||||
layout = QVBoxLayout(widget)
|
||||
layout.setSpacing(0)
|
||||
for tag, info in sdl_data.items():
|
||||
cb = TagCheckBox(info["name"].strip(), info["description"].strip(), info["tags"])
|
||||
if tag == "__required":
|
||||
cb.setChecked(True)
|
||||
cb.setDisabled(True)
|
||||
if self.config_tags is not None:
|
||||
if all(elem in self.config_tags for elem in info["tags"]):
|
||||
cb.setChecked(True)
|
||||
layout.addWidget(cb)
|
||||
self.selectable_checks.append(cb)
|
||||
for cb in self.selectable_checks:
|
||||
cb.stateChanged.connect(self.option_changed)
|
||||
self.selectable.setWidget(widget)
|
||||
else:
|
||||
self.selectable.setDisabled(True)
|
||||
|
||||
@pyqtSlot(int)
|
||||
def check_incompatible_platform(self, index: int):
|
||||
platform = self.ui.platform_combo.itemText(index)
|
||||
if platform == "Mac" and pf.system() != "Darwin":
|
||||
self.error_box(
|
||||
self.tr("Warning"),
|
||||
self.tr("You will not be able to run the game if you select <b>{}</b> as platform").format(platform)
|
||||
self.tr("You will not be able to run the game if you select <b>{}</b> as platform").format(platform),
|
||||
)
|
||||
else:
|
||||
self.error_box()
|
||||
|
||||
def get_options(self):
|
||||
self.__options.base_path = "" if self.rgame.is_installed else self.install_dir_edit.text()
|
||||
base_path = os.path.join(self.install_dir_edit.text(), ".overlay" if self.__options.overlay else "")
|
||||
self.__options.base_path = "" if self.rgame.is_installed else base_path
|
||||
self.__options.platform = self.ui.platform_combo.currentText()
|
||||
self.__options.create_shortcut = self.ui.shortcut_check.isChecked()
|
||||
self.__options.max_workers = self.advanced.ui.max_workers_spin.value()
|
||||
self.__options.shared_memory = self.advanced.ui.max_memory_spin.value()
|
||||
self.__options.order_opt = self.advanced.ui.dl_optimizations_check.isChecked()
|
||||
self.__options.force = self.advanced.ui.force_download_check.isChecked()
|
||||
self.__options.ignore_space = self.advanced.ui.ignore_space_check.isChecked()
|
||||
self.__options.no_install = self.advanced.ui.download_only_check.isChecked()
|
||||
self.__options.platform = self.ui.platform_combo.currentText()
|
||||
self.__options.install_prereqs = self.advanced.ui.install_prereqs_check.isChecked()
|
||||
self.__options.create_shortcut = self.ui.shortcut_check.isChecked()
|
||||
if self.selectable_checks:
|
||||
self.__options.install_tag = [""]
|
||||
for cb in self.selectable_checks:
|
||||
if data := cb.isChecked():
|
||||
# noinspection PyTypeChecker
|
||||
self.__options.install_tag.extend(data)
|
||||
self.__options.install_tag = self.selectable.install_tags()
|
||||
self.__options.reset_sdl = True
|
||||
|
||||
def get_download_info(self):
|
||||
self.__download = None
|
||||
|
@ -279,13 +267,17 @@ class InstallDialog(ActionDialog):
|
|||
self.get_options()
|
||||
self.get_download_info()
|
||||
|
||||
def option_changed(self, path) -> Tuple[bool, str, int]:
|
||||
@pyqtSlot()
|
||||
def option_changed(self):
|
||||
self.options_changed = True
|
||||
self.accept_button.setEnabled(False)
|
||||
self.action_button.setEnabled(not self.active())
|
||||
|
||||
def install_dir_edit_callback(self, path: str) -> Tuple[bool, str, int]:
|
||||
self.option_changed()
|
||||
return True, path, IndicatorReasonsCommon.VALID
|
||||
|
||||
def save_install_edit(self, path: str):
|
||||
def install_dir_save_callback(self, path: str):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
_, _, free_space = shutil.disk_usage(path)
|
||||
|
@ -369,12 +361,6 @@ class InstallDialog(ActionDialog):
|
|||
self.__queue_item = InstallQueueItemModel(options=self.__options, download=self.__download)
|
||||
|
||||
def reject_handler(self):
|
||||
# FIXME: This is implemented through the selective downloads dialog now. remove soon
|
||||
# if self.config_tags is not None:
|
||||
# config_helper.set_option(self.rgame.app_name, 'install_tags', ','.join(self.config_tags))
|
||||
# else:
|
||||
# # lk: this is purely for cleaning any install tags we might have added erroneously to the config
|
||||
# config_helper.remove_option(self.rgame.app_name, 'install_tags')
|
||||
self.__queue_item = InstallQueueItemModel(options=self.__options, download=None)
|
||||
|
||||
|
||||
|
@ -387,6 +373,3 @@ class TagCheckBox(QCheckBox):
|
|||
|
||||
def isChecked(self) -> Union[bool, List[str]]:
|
||||
return self.tags if super(TagCheckBox, self).isChecked() else False
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -34,8 +34,7 @@ class MoveDialog(ActionDialog):
|
|||
super(MoveDialog, self).__init__(parent=parent)
|
||||
header = self.tr("Move")
|
||||
self.setWindowTitle(dialog_title_game(header, rgame.app_title))
|
||||
|
||||
title_label = QLabel(f"<h4>{dialog_title_game(header, rgame.app_title)}</h4>", self)
|
||||
self.setSubtitle(dialog_title_game(header, rgame.app_title))
|
||||
|
||||
self.rcore = RareCore.instance()
|
||||
self.core = RareCore.instance().core()
|
||||
|
@ -70,7 +69,6 @@ class MoveDialog(ActionDialog):
|
|||
|
||||
layout = QVBoxLayout()
|
||||
layout.setSizeConstraint(QLayout.SetFixedSize)
|
||||
layout.addWidget(title_label)
|
||||
layout.addWidget(self.path_edit)
|
||||
layout.addWidget(self.warn_label)
|
||||
layout.addLayout(bottom_layout)
|
||||
|
|
|
@ -1,18 +1,11 @@
|
|||
from typing import List, Union, Optional
|
||||
|
||||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import (
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
QCheckBox,
|
||||
QLayout, QGroupBox,
|
||||
)
|
||||
from legendary.utils.selective_dl import get_sdl_appname
|
||||
from PyQt5.QtWidgets import QLabel, QVBoxLayout, QLayout, QGroupBox
|
||||
|
||||
from rare.models.game import RareGame
|
||||
from rare.models.install import SelectiveDownloadsModel
|
||||
from rare.widgets.dialogs import ButtonDialog, dialog_title_game
|
||||
from rare.utils.misc import icon
|
||||
from rare.widgets.dialogs import ButtonDialog, dialog_title_game
|
||||
from rare.widgets.selective_widget import SelectiveWidget
|
||||
|
||||
|
||||
class SelectiveDialog(ButtonDialog):
|
||||
|
@ -22,23 +15,18 @@ class SelectiveDialog(ButtonDialog):
|
|||
super(SelectiveDialog, self).__init__(parent=parent)
|
||||
header = self.tr("Optional downloads for")
|
||||
self.setWindowTitle(dialog_title_game(header, rgame.app_title))
|
||||
self.setSubtitle(dialog_title_game(header, rgame.app_title))
|
||||
|
||||
title_label = QLabel(f"<h4>{dialog_title_game(header, rgame.app_title)}</h4>", self)
|
||||
|
||||
self.core = rgame.core
|
||||
self.rgame = rgame
|
||||
self.selective_widget = SelectiveWidget(rgame, rgame.igame.platform, self)
|
||||
|
||||
selectable_group = QGroupBox(self.tr("Optional downloads"), self)
|
||||
self.selectable_layout = QVBoxLayout(selectable_group)
|
||||
self.selectable_layout.setSpacing(0)
|
||||
|
||||
self.selectable_checks: List[TagCheckBox] = []
|
||||
self.config_tags: Optional[List[str]] = None
|
||||
container = QGroupBox(self.tr("Optional downloads"), self)
|
||||
container_layout = QVBoxLayout(container)
|
||||
container_layout.setContentsMargins(0, 0, 0, 0)
|
||||
container_layout.addWidget(self.selective_widget)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.setSizeConstraint(QLayout.SetFixedSize)
|
||||
layout.addWidget(title_label)
|
||||
layout.addWidget(selectable_group)
|
||||
layout.addWidget(container)
|
||||
|
||||
self.setCentralLayout(layout)
|
||||
|
||||
|
@ -47,62 +35,13 @@ class SelectiveDialog(ButtonDialog):
|
|||
|
||||
self.options: SelectiveDownloadsModel = SelectiveDownloadsModel(rgame.app_name)
|
||||
|
||||
config_disable_sdl = self.core.lgd.config.getboolean(self.rgame.app_name, "disable_sdl", fallback=False)
|
||||
sdl_name = get_sdl_appname(self.rgame.app_name)
|
||||
if not config_disable_sdl and sdl_name is not None:
|
||||
self.create_sdl_list()
|
||||
else:
|
||||
self.options.accepted = True
|
||||
self.accept()
|
||||
|
||||
def create_sdl_list(self):
|
||||
platform = self.rgame.igame.platform
|
||||
for cb in self.selectable_checks:
|
||||
cb.disconnect()
|
||||
cb.deleteLater()
|
||||
self.selectable_checks.clear()
|
||||
|
||||
if config_tags := self.core.lgd.config.get(self.rgame.app_name, "install_tags", fallback=None):
|
||||
self.config_tags = config_tags.split(",")
|
||||
config_disable_sdl = self.core.lgd.config.getboolean(self.rgame.app_name, "disable_sdl", fallback=False)
|
||||
sdl_name = get_sdl_appname(self.rgame.app_name)
|
||||
if not config_disable_sdl and sdl_name is not None:
|
||||
sdl_data = self.core.get_sdl_data(sdl_name, platform=platform)
|
||||
if sdl_data:
|
||||
for tag, info in sdl_data.items():
|
||||
cb = TagCheckBox(info["name"].strip(), info["description"].strip(), info["tags"])
|
||||
if tag == "__required":
|
||||
cb.setChecked(True)
|
||||
cb.setDisabled(True)
|
||||
if self.config_tags is not None:
|
||||
if all(elem in self.config_tags for elem in info["tags"]):
|
||||
cb.setChecked(True)
|
||||
self.selectable_layout.addWidget(cb)
|
||||
self.selectable_checks.append(cb)
|
||||
|
||||
def done_handler(self):
|
||||
self.result_ready.emit(self.rgame, self.options)
|
||||
|
||||
def accept_handler(self):
|
||||
install_tag = [""]
|
||||
for cb in self.selectable_checks:
|
||||
if data := cb.isChecked():
|
||||
# noinspection PyTypeChecker
|
||||
install_tag.extend(data)
|
||||
self.options.accepted = True
|
||||
self.options.install_tag = install_tag
|
||||
self.options.install_tag = self.selective_widget.install_tags()
|
||||
|
||||
def reject_handler(self):
|
||||
self.options.accepted = False
|
||||
self.options.install_tag = None
|
||||
|
||||
|
||||
class TagCheckBox(QCheckBox):
|
||||
def __init__(self, text, desc, tags: List[str], parent=None):
|
||||
super(TagCheckBox, self).__init__(parent)
|
||||
self.setText(text)
|
||||
self.setToolTip(desc)
|
||||
self.tags = tags
|
||||
|
||||
def isChecked(self) -> Union[bool, List[str]]:
|
||||
return self.tags if super(TagCheckBox, self).isChecked() else False
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
from PyQt5.QtCore import pyqtSignal
|
||||
from PyQt5.QtWidgets import (
|
||||
QLabel,
|
||||
QVBoxLayout,
|
||||
QCheckBox,
|
||||
)
|
||||
|
@ -18,19 +17,24 @@ class UninstallDialog(ButtonDialog):
|
|||
super(UninstallDialog, self).__init__(parent=parent)
|
||||
header = self.tr("Uninstall")
|
||||
self.setWindowTitle(dialog_title_game(header, rgame.app_title))
|
||||
|
||||
title_label = QLabel(f"<h4>{dialog_title_game(header, rgame.app_title)}</h4>", self)
|
||||
self.setSubtitle(dialog_title_game(header, rgame.app_title))
|
||||
|
||||
self.keep_files = QCheckBox(self.tr("Keep files"))
|
||||
self.keep_files.setChecked(bool(options.keep_files))
|
||||
self.keep_files.setEnabled(not rgame.is_overlay)
|
||||
|
||||
self.keep_config = QCheckBox(self.tr("Keep configuation"))
|
||||
self.keep_config.setChecked(bool(options.keep_config))
|
||||
self.keep_config.setEnabled(not rgame.is_overlay)
|
||||
|
||||
self.keep_overlay_keys = QCheckBox(self.tr("Keep EOS Overlay registry keys"))
|
||||
self.keep_overlay_keys.setChecked(bool(options.keep_overlay_keys))
|
||||
self.keep_overlay_keys.setEnabled(rgame.is_overlay)
|
||||
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(title_label)
|
||||
layout.addWidget(self.keep_files)
|
||||
layout.addWidget(self.keep_config)
|
||||
layout.addWidget(self.keep_overlay_keys)
|
||||
|
||||
self.setCentralLayout(layout)
|
||||
|
||||
|
@ -51,7 +55,8 @@ class UninstallDialog(ButtonDialog):
|
|||
True,
|
||||
self.keep_files.isChecked(),
|
||||
self.keep_config.isChecked(),
|
||||
self.keep_overlay_keys.isChecked(),
|
||||
)
|
||||
|
||||
def reject_handler(self):
|
||||
self.options.values = (None, None, None)
|
||||
self.options.values = (None, None, None, None)
|
||||
|
|
|
@ -105,7 +105,9 @@ class DownloadsTab(QWidget):
|
|||
def __add_update(self, update: Union[str, RareGame]):
|
||||
if isinstance(update, str):
|
||||
update = self.rcore.get_game(update)
|
||||
if update.metadata.auto_update or QSettings().value("auto_update", False, bool):
|
||||
if QSettings().value(
|
||||
f"{update.app_name}/auto_update", False, bool
|
||||
) or QSettings().value("auto_update", False, bool):
|
||||
self.__get_install_options(
|
||||
InstallOptionsModel(app_name=update.app_name, update=True, silent=True)
|
||||
)
|
||||
|
@ -192,7 +194,7 @@ class DownloadsTab(QWidget):
|
|||
if item.expired:
|
||||
self.__refresh_download(item)
|
||||
return
|
||||
dl_thread = DlThread(item, self.rcore.get_game(item.options.app_name), self.core, self.args.debug)
|
||||
dl_thread = DlThread(item, rgame, self.core, self.args.debug)
|
||||
dl_thread.result.connect(self.__on_download_result)
|
||||
dl_thread.progress.connect(self.__on_download_progress)
|
||||
dl_thread.finished.connect(dl_thread.deleteLater)
|
||||
|
@ -204,6 +206,11 @@ class DownloadsTab(QWidget):
|
|||
RareCore.instance().image_manager().get_pixmap(rgame.app_name, True)
|
||||
)
|
||||
|
||||
self.signals.application.notify.emit(
|
||||
self.tr("Downloads"),
|
||||
self.tr("Starting: \"{}\" is now downloading.").format(rgame.app_title)
|
||||
)
|
||||
|
||||
@pyqtSlot(UIUpdate, object)
|
||||
def __on_download_progress(self, ui_update: UIUpdate, dl_size: int):
|
||||
self.download_widget.ui.progress_bar.setValue(int(ui_update.progress))
|
||||
|
@ -229,19 +236,19 @@ class DownloadsTab(QWidget):
|
|||
if result.shortcut and desktop_links_supported():
|
||||
if not create_desktop_link(
|
||||
app_name=result.options.app_name,
|
||||
app_title=result.shortcut_title,
|
||||
link_name=result.shortcut_name,
|
||||
app_title=result.app_title,
|
||||
link_name=result.folder_name,
|
||||
link_type="desktop",
|
||||
):
|
||||
# maybe add it to download summary, to show in finished downloads
|
||||
logger.error(f"Failed to create desktop link on {platform.system()}")
|
||||
else:
|
||||
logger.info(f"Created desktop link {result.shortcut_name} for {result.options.app_name}")
|
||||
logger.info(f"Created desktop link {result.folder_name} for {result.app_title}")
|
||||
|
||||
if result.options.overlay:
|
||||
self.signals.application.overlay_installed.emit()
|
||||
else:
|
||||
self.signals.application.notify.emit(result.options.app_name)
|
||||
self.signals.application.notify.emit(
|
||||
self.tr("Downloads"),
|
||||
self.tr("Finished: \"{}\" is now playable.").format(result.app_title),
|
||||
)
|
||||
|
||||
if self.updates_group.contains(result.options.app_name):
|
||||
self.updates_group.set_widget_enabled(result.options.app_name, True)
|
||||
|
@ -319,6 +326,7 @@ class DownloadsTab(QWidget):
|
|||
if self.updates_group.contains(item.options.app_name):
|
||||
self.updates_group.set_widget_enabled(item.options.app_name, True)
|
||||
rgame.state = RareGame.State.IDLE
|
||||
self.update_queues_count()
|
||||
|
||||
@pyqtSlot(UninstallOptionsModel)
|
||||
def __get_uninstall_options(self, options: UninstallOptionsModel):
|
||||
|
|
|
@ -34,8 +34,8 @@ class DlResultModel:
|
|||
sync_saves: bool = False
|
||||
tip_url: str = ""
|
||||
shortcut: bool = False
|
||||
shortcut_name: str = ""
|
||||
shortcut_title: str = ""
|
||||
folder_name: str = ""
|
||||
app_title: str = ""
|
||||
|
||||
|
||||
class DlThread(QThread):
|
||||
|
@ -151,10 +151,9 @@ class DlThread(QThread):
|
|||
self.item.download.repair_file,
|
||||
)
|
||||
|
||||
if not self.item.options.update and self.item.options.create_shortcut:
|
||||
result.shortcut = True
|
||||
result.shortcut_name = self.rgame.folder_name
|
||||
result.shortcut_title = self.rgame.app_title
|
||||
result.shortcut = not self.item.options.update and self.item.options.create_shortcut
|
||||
result.folder_name = self.rgame.folder_name
|
||||
result.app_title = self.rgame.app_title
|
||||
|
||||
self.__finish(result)
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
from typing import Optional
|
||||
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSpacerItem, QSizePolicy
|
||||
from PyQt5.QtWidgets import QVBoxLayout, QWidget, QLabel, QSizePolicy
|
||||
|
||||
from rare.widgets.side_tab import SideTabWidget
|
||||
from .egl_sync_group import EGLSyncGroup
|
||||
from .eos_group import EOSGroup
|
||||
from .eos_group import EosGroup
|
||||
from .import_group import ImportGroup
|
||||
from .ubisoft_group import UbisoftGroup
|
||||
|
||||
|
@ -34,8 +34,8 @@ class IntegrationsTabs(SideTabWidget):
|
|||
self.tr(""),
|
||||
self,
|
||||
)
|
||||
self.eos_group = EosGroup(self.eos_ubisoft)
|
||||
self.ubisoft_group = UbisoftGroup(self.eos_ubisoft)
|
||||
self.eos_group = EOSGroup(self.eos_ubisoft)
|
||||
self.eos_ubisoft.addWidget(self.eos_group)
|
||||
self.eos_ubisoft.addWidget(self.ubisoft_group)
|
||||
self.eos_ubisoft_index = self.addTab(self.eos_ubisoft, self.tr("Epic Overlay and Ubisoft"))
|
||||
|
|
|
@ -1,259 +1,280 @@
|
|||
import os
|
||||
import platform
|
||||
from logging import getLogger
|
||||
from typing import List
|
||||
from typing import Optional
|
||||
|
||||
from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool
|
||||
from PyQt5.QtWidgets import QGroupBox, QMessageBox
|
||||
from legendary.lfs import eos
|
||||
from PyQt5.QtCore import QRunnable, QObject, pyqtSignal, QThreadPool, Qt, pyqtSlot, QSize
|
||||
from PyQt5.QtGui import QShowEvent
|
||||
from PyQt5.QtWidgets import (
|
||||
QGroupBox,
|
||||
QMessageBox,
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
QSizePolicy,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QFormLayout,
|
||||
QComboBox,
|
||||
)
|
||||
|
||||
from rare.models.install import InstallOptionsModel
|
||||
from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.game import RareEosOverlay
|
||||
from rare.shared import RareCore
|
||||
from rare.ui.components.tabs.games.integrations.eos_widget import Ui_EosWidget
|
||||
from rare.utils import config_helper as config
|
||||
from rare.utils.misc import icon
|
||||
from rare.widgets.elide_label import ElideLabel
|
||||
|
||||
logger = getLogger("EpicOverlay")
|
||||
|
||||
|
||||
def get_wine_prefixes() -> List[str]:
|
||||
prefixes = list()
|
||||
if os.path.exists(p := os.path.expanduser("~/.wine")):
|
||||
prefixes.append(p)
|
||||
|
||||
for name, section in LegendaryCoreSingleton().lgd.config.items():
|
||||
pfx = section.get("WINEPREFIX") or section.get("wine_prefix")
|
||||
if pfx and pfx not in prefixes:
|
||||
prefixes.append(pfx)
|
||||
|
||||
return prefixes
|
||||
|
||||
|
||||
class CheckForUpdateWorker(QRunnable):
|
||||
class CheckForUpdateSignals(QObject):
|
||||
update_available = pyqtSignal(bool)
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, core: LegendaryCore):
|
||||
super(CheckForUpdateWorker, self).__init__()
|
||||
self.signals = self.CheckForUpdateSignals()
|
||||
self.setAutoDelete(True)
|
||||
self.core = LegendaryCoreSingleton()
|
||||
self.core = core
|
||||
|
||||
def run(self) -> None:
|
||||
self.core.check_for_overlay_updates()
|
||||
self.signals.update_available.emit(self.core.overlay_update_available)
|
||||
|
||||
|
||||
class EOSGroup(QGroupBox):
|
||||
class EosPrefixWidget(QFrame):
|
||||
def __init__(self, overlay: RareEosOverlay, prefix: Optional[str], parent=None):
|
||||
super(EosPrefixWidget, self).__init__(parent=parent)
|
||||
self.setFrameShape(QFrame.StyledPanel)
|
||||
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
|
||||
|
||||
self.indicator = QLabel(parent=self)
|
||||
self.indicator.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Preferred)
|
||||
|
||||
self.prefix_label = ElideLabel(
|
||||
prefix.replace(os.path.expanduser("~"), "~") if prefix is not None else overlay.app_title,
|
||||
parent=self,
|
||||
)
|
||||
self.overlay_label = ElideLabel(parent=self)
|
||||
self.overlay_label.setDisabled(True)
|
||||
|
||||
self.path_select = QComboBox(self)
|
||||
self.path_select.setMaximumWidth(150)
|
||||
self.path_select.setMinimumWidth(150)
|
||||
|
||||
self.button = QPushButton(parent=self)
|
||||
self.button.setMinimumWidth(150)
|
||||
|
||||
layout = QHBoxLayout(self)
|
||||
layout.setContentsMargins(-1, 0, 0, 0)
|
||||
layout.addWidget(self.indicator)
|
||||
layout.addWidget(self.prefix_label, stretch=2)
|
||||
layout.addWidget(self.overlay_label, stretch=3)
|
||||
layout.addWidget(self.path_select)
|
||||
layout.addWidget(self.button)
|
||||
|
||||
self.overlay = overlay
|
||||
self.prefix = prefix
|
||||
|
||||
self.path_select.currentIndexChanged.connect(self.path_changed)
|
||||
self.button.clicked.connect(self.action)
|
||||
self.overlay.signals.game.installed.connect(self.update_state)
|
||||
self.overlay.signals.game.uninstalled.connect(self.update_state)
|
||||
|
||||
self.update_state()
|
||||
|
||||
@pyqtSlot(int)
|
||||
def path_changed(self, index: int) -> None:
|
||||
path = self.path_select.itemData(index, Qt.UserRole)
|
||||
active_path = os.path.normpath(p) if (p := self.overlay.active_path(self.prefix)) else ""
|
||||
if self.overlay.is_enabled(self.prefix) and (path == active_path):
|
||||
self.button.setText(self.tr("Disable overlay"))
|
||||
else:
|
||||
self.button.setText(self.tr("Enable overlay"))
|
||||
|
||||
@pyqtSlot()
|
||||
def update_state(self) -> None:
|
||||
active_path = os.path.normpath(p) if (p := self.overlay.active_path(self.prefix)) else ""
|
||||
|
||||
self.overlay_label.setText(f"<i>{active_path}</i>")
|
||||
self.path_select.clear()
|
||||
|
||||
if not self.overlay.is_installed and not self.overlay.available_paths(self.prefix):
|
||||
self.setDisabled(True)
|
||||
self.indicator.setPixmap(icon("fa.circle-o", color="grey").pixmap(20, 20))
|
||||
self.overlay_label.setText(self.overlay.active_path(self.prefix))
|
||||
self.button.setText(self.tr("Unavailable"))
|
||||
return
|
||||
|
||||
if self.overlay.is_enabled(self.prefix):
|
||||
self.indicator.setPixmap(icon("fa.check-circle-o", color="green").pixmap(QSize(20, 20)))
|
||||
else:
|
||||
self.indicator.setPixmap(icon("fa.times-circle-o", color="red").pixmap(QSize(20, 20)))
|
||||
|
||||
install_path = os.path.normpath(p) if (p := self.overlay.install_path) else ""
|
||||
|
||||
self.path_select.addItem("Auto-detect", "")
|
||||
self.path_select.setItemData(0, "Auto-detect", Qt.ToolTipRole)
|
||||
for path in self.overlay.available_paths(self.prefix):
|
||||
path = os.path.normpath(path)
|
||||
self.path_select.addItem("Legendary-managed" if path == install_path else "EGL-managed", path)
|
||||
self.path_select.setItemData(self.path_select.findData(path), path, Qt.ToolTipRole)
|
||||
self.path_select.setCurrentIndex(self.path_select.findData(active_path))
|
||||
|
||||
self.setEnabled(self.overlay.state == RareEosOverlay.State.IDLE)
|
||||
|
||||
@pyqtSlot()
|
||||
def action(self) -> None:
|
||||
path = self.path_select.currentData(Qt.UserRole)
|
||||
active_path = os.path.normpath(p) if (p := self.overlay.active_path(self.prefix)) else ""
|
||||
install_path = os.path.normpath(p) if (p := self.overlay.install_path) else ""
|
||||
if self.overlay.is_enabled(self.prefix) and (path == active_path):
|
||||
if not self.overlay.disable(prefix=self.prefix):
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"Warning",
|
||||
self.tr("Failed to completely disable the active EOS Overlay.{}").format(
|
||||
self.tr(
|
||||
" Since the previous overlay was managed by EGL you can safely ignore this is."
|
||||
)
|
||||
if active_path != install_path
|
||||
else ""
|
||||
),
|
||||
)
|
||||
else:
|
||||
self.overlay.disable(prefix=self.prefix)
|
||||
if not self.overlay.enable(prefix=self.prefix, path=path):
|
||||
QMessageBox.warning(
|
||||
self,
|
||||
"Warning",
|
||||
self.tr("Failed to completely enable EOS overlay.{}").format(
|
||||
self.tr(
|
||||
" Since the previous overlay was managed by EGL you can safely ignore this is."
|
||||
)
|
||||
if active_path != install_path
|
||||
else ""
|
||||
),
|
||||
)
|
||||
self.update_state()
|
||||
|
||||
|
||||
class EosGroup(QGroupBox):
|
||||
def __init__(self, parent=None):
|
||||
super(EOSGroup, self).__init__(parent=parent)
|
||||
super(EosGroup, self).__init__(parent=parent)
|
||||
self.ui = Ui_EosWidget()
|
||||
self.ui.setupUi(self)
|
||||
# lk: set object names for CSS properties
|
||||
self.ui.install_button.setObjectName("InstallButton")
|
||||
self.ui.install_button.setIcon(icon("ri.install-line"))
|
||||
self.ui.uninstall_button.setObjectName("UninstallButton")
|
||||
|
||||
self.ui.install_page_layout.setAlignment(Qt.AlignTop)
|
||||
self.ui.info_page_layout.setAlignment(Qt.AlignTop)
|
||||
|
||||
self.ui.install_button.setIcon(icon("ri.install-line"))
|
||||
self.ui.uninstall_button.setIcon(icon("ri.uninstall-line"))
|
||||
|
||||
self.core = LegendaryCoreSingleton()
|
||||
self.signals = GlobalSignalsSingleton()
|
||||
self.installed_path_label = ElideLabel(parent=self)
|
||||
self.installed_version_label = ElideLabel(parent=self)
|
||||
|
||||
self.prefix_enabled = False
|
||||
self.ui.info_label_layout.setWidget(0, QFormLayout.FieldRole, self.installed_version_label)
|
||||
self.ui.info_label_layout.setWidget(1, QFormLayout.FieldRole, self.installed_path_label)
|
||||
|
||||
self.ui.enabled_cb.stateChanged.connect(self.change_enable)
|
||||
self.rcore = RareCore.instance()
|
||||
self.core = self.rcore.core()
|
||||
self.signals = self.rcore.signals()
|
||||
self.overlay = self.rcore.get_overlay()
|
||||
|
||||
self.overlay.signals.widget.update.connect(self.update_state)
|
||||
self.overlay.signals.game.installed.connect(self.install_finished)
|
||||
self.overlay.signals.game.uninstalled.connect(self.uninstall_finished)
|
||||
|
||||
self.ui.install_button.clicked.connect(self.install_overlay)
|
||||
self.ui.update_button.clicked.connect(self.install_overlay)
|
||||
self.ui.uninstall_button.clicked.connect(self.uninstall_overlay)
|
||||
|
||||
self.ui.update_button.setVisible(False)
|
||||
self.overlay = self.core.lgd.get_overlay_install_info()
|
||||
|
||||
self.signals.application.overlay_installed.connect(self.overlay_installation_finished)
|
||||
self.signals.application.prefix_updated.connect(self.update_prefixes)
|
||||
|
||||
self.ui.update_check_button.clicked.connect(self.check_for_update)
|
||||
self.ui.install_button.clicked.connect(self.install_overlay)
|
||||
self.ui.update_button.clicked.connect(lambda: self.install_overlay(True))
|
||||
|
||||
if self.overlay: # installed
|
||||
self.ui.installed_version_lbl.setText(f"<b>{self.overlay.version}</b>")
|
||||
self.ui.installed_path_lbl.setText(f"<b>{self.overlay.install_path}</b>")
|
||||
self.ui.overlay_stack.setCurrentIndex(0)
|
||||
if self.overlay.is_installed: # installed
|
||||
self.installed_version_label.setText(f"<b>{self.overlay.version}</b>")
|
||||
self.installed_path_label.setText(os.path.normpath(self.overlay.install_path))
|
||||
self.ui.overlay_stack.setCurrentWidget(self.ui.info_page)
|
||||
else:
|
||||
self.ui.overlay_stack.setCurrentIndex(1)
|
||||
self.ui.enable_frame.setDisabled(True)
|
||||
|
||||
if platform.system() == "Windows":
|
||||
self.current_prefix = None
|
||||
self.ui.select_pfx_combo.setVisible(False)
|
||||
else:
|
||||
self.current_prefix = os.path.expanduser("~/.wine") \
|
||||
if os.path.exists(os.path.expanduser("~/.wine")) \
|
||||
else None
|
||||
pfxs = get_wine_prefixes()
|
||||
for pfx in pfxs:
|
||||
self.ui.select_pfx_combo.addItem(pfx.replace(os.path.expanduser("~/"), "~/"))
|
||||
if not pfxs:
|
||||
self.ui.enable_frame.setDisabled(True)
|
||||
else:
|
||||
self.ui.select_pfx_combo.setCurrentIndex(0)
|
||||
|
||||
self.ui.select_pfx_combo.currentIndexChanged.connect(self.update_select_combo)
|
||||
if pfxs:
|
||||
self.update_select_combo(None)
|
||||
|
||||
self.ui.enabled_info_label.setText("")
|
||||
self.ui.overlay_stack.setCurrentWidget(self.ui.install_page)
|
||||
self.ui.update_button.setEnabled(False)
|
||||
|
||||
self.threadpool = QThreadPool.globalInstance()
|
||||
self.worker: Optional[CheckForUpdateWorker] = None
|
||||
|
||||
def showEvent(self, a0: QShowEvent) -> None:
|
||||
if a0.spontaneous():
|
||||
return super().showEvent(a0)
|
||||
self.check_for_update()
|
||||
self.update_prefixes()
|
||||
self.update_state()
|
||||
super().showEvent(a0)
|
||||
|
||||
@pyqtSlot()
|
||||
def update_state(self):
|
||||
self.ui.install_button.setEnabled(self.overlay.state == RareEosOverlay.State.IDLE)
|
||||
self.ui.update_button.setEnabled(self.overlay.state == RareEosOverlay.State.IDLE and self.overlay.has_update)
|
||||
self.ui.uninstall_button.setEnabled(self.overlay.state == RareEosOverlay.State.IDLE)
|
||||
|
||||
def update_prefixes(self):
|
||||
logger.debug("Updated prefixes")
|
||||
pfxs = get_wine_prefixes() # returns /home/whatever
|
||||
self.ui.select_pfx_combo.clear()
|
||||
for widget in self.findChildren(EosPrefixWidget, options=Qt.FindDirectChildrenOnly):
|
||||
widget.deleteLater()
|
||||
|
||||
for pfx in pfxs:
|
||||
self.ui.select_pfx_combo.addItem(pfx.replace(os.path.expanduser("~/"), "~/"))
|
||||
if platform.system() != "Windows":
|
||||
prefixes = config.get_prefixes()
|
||||
prefixes = {prefix for prefix in prefixes if config.prefix_exists(prefix)}
|
||||
if platform.system() == "Darwin":
|
||||
# TODO: add crossover support
|
||||
pass
|
||||
for prefix in prefixes:
|
||||
widget = EosPrefixWidget(self.overlay, prefix)
|
||||
self.ui.eos_layout.addWidget(widget)
|
||||
logger.debug("Updated prefixes")
|
||||
else:
|
||||
widget = EosPrefixWidget(self.overlay, None)
|
||||
self.ui.eos_layout.addWidget(widget)
|
||||
|
||||
if self.current_prefix in pfxs:
|
||||
self.ui.select_pfx_combo.setCurrentIndex(
|
||||
self.ui.select_pfx_combo.findText(self.current_prefix.replace(os.path.expanduser("~/"), "~/")))
|
||||
@pyqtSlot(bool)
|
||||
def check_for_update_finished(self, update_available: bool):
|
||||
self.worker = None
|
||||
self.ui.update_button.setEnabled(update_available)
|
||||
|
||||
def check_for_update(self):
|
||||
def worker_finished(update_available):
|
||||
self.ui.update_button.setVisible(update_available)
|
||||
self.ui.update_check_button.setDisabled(False)
|
||||
if not update_available:
|
||||
self.ui.update_check_button.setText(self.tr("No update available"))
|
||||
|
||||
self.ui.update_check_button.setDisabled(True)
|
||||
worker = CheckForUpdateWorker()
|
||||
worker.signals.update_available.connect(worker_finished)
|
||||
QThreadPool.globalInstance().start(worker)
|
||||
|
||||
def overlay_installation_finished(self):
|
||||
self.overlay = self.core.lgd.get_overlay_install_info()
|
||||
|
||||
if not self.overlay:
|
||||
logger.error("Something went wrong, when installing overlay")
|
||||
QMessageBox.warning(self, "Error", self.tr("Something went wrong, when installing overlay"))
|
||||
self.ui.update_button.setEnabled(False)
|
||||
if not self.overlay.is_installed:
|
||||
return
|
||||
|
||||
self.ui.overlay_stack.setCurrentIndex(0)
|
||||
self.ui.installed_version_lbl.setText(f"<b>{self.overlay.version}</b>")
|
||||
self.ui.installed_path_lbl.setText(f"<b>{self.overlay.install_path}</b>")
|
||||
|
||||
self.ui.update_button.setVisible(False)
|
||||
|
||||
self.ui.enable_frame.setEnabled(True)
|
||||
|
||||
def update_select_combo(self, i: None):
|
||||
if i is None:
|
||||
i = self.ui.select_pfx_combo.currentIndex()
|
||||
prefix = os.path.expanduser(self.ui.select_pfx_combo.itemText(i))
|
||||
if platform.system() != "Windows" and not os.path.isfile(os.path.join(prefix, "user.reg")):
|
||||
if self.worker is not None:
|
||||
return
|
||||
self.current_prefix = prefix
|
||||
reg_paths = eos.query_registry_entries(self.current_prefix)
|
||||
|
||||
overlay_enabled = False
|
||||
if reg_paths['overlay_path'] and self.core.is_overlay_install(reg_paths['overlay_path']):
|
||||
overlay_enabled = True
|
||||
self.ui.enabled_cb.setChecked(overlay_enabled)
|
||||
self.worker = CheckForUpdateWorker(self.core)
|
||||
self.worker.signals.update_available.connect(self.check_for_update_finished)
|
||||
QThreadPool.globalInstance().start(self.worker)
|
||||
|
||||
def change_enable(self):
|
||||
enabled = self.ui.enabled_cb.isChecked()
|
||||
if not enabled:
|
||||
try:
|
||||
eos.remove_registry_entries(self.current_prefix)
|
||||
except PermissionError:
|
||||
logger.error("Can't disable eos overlay")
|
||||
QMessageBox.warning(self, "Error", self.tr(
|
||||
"Failed to disable Overlay. Probably it is installed by Epic Games Launcher"))
|
||||
return
|
||||
logger.info("Disabled Epic Overlay")
|
||||
self.ui.enabled_info_label.setText(self.tr("Disabled"))
|
||||
else:
|
||||
if not self.overlay:
|
||||
available_installs = self.core.search_overlay_installs(self.current_prefix)
|
||||
if not available_installs:
|
||||
logger.error('No EOS overlay installs found!')
|
||||
return
|
||||
path = available_installs[0]
|
||||
else:
|
||||
path = self.overlay.install_path
|
||||
@pyqtSlot()
|
||||
def install_finished(self):
|
||||
if not self.overlay.is_installed:
|
||||
logger.error("Something went wrong while installing overlay")
|
||||
QMessageBox.warning(self, "Error", self.tr("Something went wrong while installing Overlay"))
|
||||
return
|
||||
self.ui.overlay_stack.setCurrentWidget(self.ui.info_page)
|
||||
self.installed_version_label.setText(f"<b>{self.overlay.version}</b>")
|
||||
self.installed_path_label.setText(self.overlay.install_path)
|
||||
self.ui.update_button.setEnabled(False)
|
||||
|
||||
if not self.core.is_overlay_install(path):
|
||||
logger.error(f'Not a valid Overlay installation: {path}')
|
||||
self.ui.select_pfx_combo.removeItem(self.ui.select_pfx_combo.currentIndex())
|
||||
return
|
||||
@pyqtSlot()
|
||||
def uninstall_finished(self):
|
||||
self.ui.overlay_stack.setCurrentWidget(self.ui.install_page)
|
||||
|
||||
path = os.path.normpath(path)
|
||||
reg_paths = eos.query_registry_entries(self.current_prefix)
|
||||
if old_path := reg_paths["overlay_path"]:
|
||||
if os.path.normpath(old_path) == path:
|
||||
logger.info(f'Overlay already enabled, nothing to do.')
|
||||
return
|
||||
else:
|
||||
logger.info(f'Updating overlay registry entries from "{old_path}" to "{path}"')
|
||||
try:
|
||||
eos.remove_registry_entries(self.current_prefix)
|
||||
except PermissionError:
|
||||
logger.error("Can't disable eos overlay")
|
||||
QMessageBox.warning(self, "Error", self.tr(
|
||||
"Failed to disable Overlay. Probably it is installed by Epic Games Launcher"))
|
||||
return
|
||||
try:
|
||||
eos.add_registry_entries(path, self.current_prefix)
|
||||
except PermissionError:
|
||||
logger.error("Failed to disable eos overlay")
|
||||
QMessageBox.warning(self, "Error", self.tr(
|
||||
"Failed to enable EOS overlay. Maybe it is already installed by Epic Games Launcher"))
|
||||
return
|
||||
self.ui.enabled_info_label.setText(self.tr("Enabled"))
|
||||
logger.info(f'Enabled overlay at: {path}')
|
||||
|
||||
def update_checkbox(self):
|
||||
reg_paths = eos.query_registry_entries(self.current_prefix)
|
||||
enabled = False
|
||||
if reg_paths['overlay_path'] and self.core.is_overlay_install(reg_paths['overlay_path']):
|
||||
enabled = True
|
||||
self.ui.enabled_cb.setChecked(enabled)
|
||||
|
||||
def install_overlay(self, update=False):
|
||||
base_path = os.path.join(self.core.get_default_install_dir(), ".overlay")
|
||||
if update:
|
||||
if not self.overlay:
|
||||
self.ui.overlay_stack.setCurrentIndex(1)
|
||||
self.ui.enable_frame.setDisabled(True)
|
||||
QMessageBox.warning(self, "Warning", self.tr("Overlay is not installed. Could not update"))
|
||||
return
|
||||
base_path = self.overlay.install_path
|
||||
|
||||
options = InstallOptionsModel(
|
||||
app_name=eos.EOSOverlayApp.app_name, base_path=base_path, platform="Windows", overlay=True
|
||||
)
|
||||
|
||||
self.signals.game.install.emit(options)
|
||||
@pyqtSlot()
|
||||
def install_overlay(self):
|
||||
self.overlay.install()
|
||||
|
||||
def uninstall_overlay(self):
|
||||
if not self.core.is_overlay_installed():
|
||||
logger.error('No legendary-managed overlay installation found.')
|
||||
self.ui.overlay_stack.setCurrentIndex(1)
|
||||
if not self.overlay.is_installed:
|
||||
logger.error("No Legendary-managed overlay installation found.")
|
||||
self.ui.overlay_stack.setCurrentWidget(self.ui.install_page)
|
||||
return
|
||||
|
||||
if QMessageBox.No == QMessageBox.question(
|
||||
self, "Uninstall Overlay", self.tr("Do you want to uninstall overlay?"),
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No
|
||||
):
|
||||
return
|
||||
if platform.system() == "Windows":
|
||||
eos.remove_registry_entries(None)
|
||||
else:
|
||||
for prefix in [self.ui.select_pfx_combo.itemText(i) for i in range(self.ui.select_pfx_combo.count())]:
|
||||
logger.info(f"Removing registry entries from {prefix}")
|
||||
try:
|
||||
eos.remove_registry_entries(os.path.expanduser(prefix))
|
||||
except Exception as e:
|
||||
logger.warning(f"{prefix}: {e}")
|
||||
|
||||
self.core.remove_overlay_install()
|
||||
self.ui.overlay_stack.setCurrentIndex(1)
|
||||
|
||||
self.ui.enable_frame.setDisabled(True)
|
||||
self.overlay.uninstall()
|
||||
|
|
|
@ -8,17 +8,23 @@ class DebugSettings(QWidget):
|
|||
def __init__(self, parent=None):
|
||||
super(DebugSettings, self).__init__(parent=parent)
|
||||
|
||||
self.raise_runtime_exception_button = QPushButton("Raise Exception")
|
||||
self.raise_runtime_exception_button = QPushButton("Raise Exception", self)
|
||||
self.raise_runtime_exception_button.clicked.connect(self.raise_exception)
|
||||
self.restart_button = QPushButton("Restart")
|
||||
self.restart_button = QPushButton("Restart", self)
|
||||
self.restart_button.clicked.connect(
|
||||
lambda: GlobalSignalsSingleton().application.quit.emit(ExitCodes.LOGOUT)
|
||||
)
|
||||
self.send_notification_button = QPushButton("Notify", self)
|
||||
self.send_notification_button.clicked.connect(self.send_notification)
|
||||
|
||||
layout = QVBoxLayout(self)
|
||||
layout.addWidget(self.raise_runtime_exception_button)
|
||||
layout.addWidget(self.restart_button)
|
||||
layout.addWidget(self.send_notification_button)
|
||||
layout.addStretch(1)
|
||||
|
||||
def raise_exception(self):
|
||||
raise RuntimeError("Debug Crash")
|
||||
|
||||
def send_notification(self):
|
||||
GlobalSignalsSingleton().application.notify.emit("Debug", "Test notification")
|
||||
|
|
|
@ -116,6 +116,19 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
|
|||
lambda: self.settings.setValue("unreal_meta", self.fetch_unreal_check.isChecked())
|
||||
)
|
||||
|
||||
self.exclude_non_asset_check.setChecked(
|
||||
self.settings.value("exclude_non_asset", False, bool)
|
||||
)
|
||||
self.exclude_non_asset_check.stateChanged.connect(
|
||||
lambda: self.settings.setValue("exclude_non_asset", self.exclude_non_asset_check.isChecked())
|
||||
)
|
||||
self.exclude_entitlements_check.setChecked(
|
||||
self.settings.value("exclude_entitlements", False, bool)
|
||||
)
|
||||
self.exclude_entitlements_check.stateChanged.connect(
|
||||
lambda: self.settings.setValue("exclude_entitlements", self.exclude_entitlements_check.isChecked())
|
||||
)
|
||||
|
||||
self.refresh_metadata_button.clicked.connect(self.refresh_metadata)
|
||||
# FIXME: Disable the button for now because it interferes with RareCore
|
||||
self.refresh_metadata_button.setEnabled(False)
|
||||
|
|
|
@ -59,17 +59,10 @@ class TrayIcon(QSystemTrayIcon):
|
|||
last_played.sort(key=lambda g: g.metadata.last_played, reverse=True)
|
||||
return last_played[0:5]
|
||||
|
||||
@pyqtSlot(str)
|
||||
def notify(self, app_name: str):
|
||||
@pyqtSlot(str, str)
|
||||
def notify(self, title: str, body: str):
|
||||
if self.settings.value("notification", True, bool):
|
||||
self.showMessage(
|
||||
self.tr("Download finished"),
|
||||
self.tr("Download finished. {} is playable now").format(
|
||||
self.rcore.get_game(app_name).app_title
|
||||
),
|
||||
self.Information,
|
||||
4000,
|
||||
)
|
||||
self.showMessage(f"{QApplication.applicationName()} - {title}", body, QSystemTrayIcon.Information, 4000)
|
||||
|
||||
@pyqtSlot()
|
||||
def update_actions(self):
|
||||
|
|
|
@ -105,9 +105,15 @@ def get_game_params(rgame: RareGameSlim, args: InitArgs, launch_args: LaunchArgs
|
|||
app_name = rgame.game.metadata['mainGameItem']['releaseInfo'][0]['appId']
|
||||
rgame.igame = rgame.core.get_installed_game(app_name)
|
||||
|
||||
params: LaunchParameters = rgame.core.get_launch_parameters(
|
||||
app_name=rgame.game.app_name, offline=args.offline, addon_app_name=rgame.igame.app_name
|
||||
)
|
||||
try:
|
||||
params: LaunchParameters = rgame.core.get_launch_parameters(
|
||||
app_name=rgame.game.app_name, offline=args.offline, addon_app_name=rgame.igame.app_name
|
||||
)
|
||||
except TypeError:
|
||||
logger.warning("Using older get_launch_parameters due to legendary version")
|
||||
params: LaunchParameters = rgame.core.get_launch_parameters(
|
||||
app_name=rgame.game.app_name, offline=args.offline
|
||||
)
|
||||
|
||||
full_params = []
|
||||
launch_args.environment = QProcessEnvironment.systemEnvironment()
|
||||
|
|
|
@ -341,7 +341,7 @@ class LegendaryCLI(LegendaryCLIReal):
|
|||
self.core.uninstall_tag(old_igame)
|
||||
self.core.install_game(old_igame)
|
||||
|
||||
if old_igame.install_tags:
|
||||
if old_igame and old_igame.install_tags:
|
||||
self.core.lgd.config.set(game.app_name, 'install_tags', ','.join(old_igame.install_tags))
|
||||
self.core.lgd.save_config()
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ from typing import Optional, List, Tuple
|
|||
from PyQt5.QtCore import QObject, pyqtSignal, QRunnable, QThreadPool, QSettings
|
||||
from legendary.lfs import eos
|
||||
from legendary.models.game import SaveGameFile, SaveGameStatus, Game, InstalledGame
|
||||
from legendary.utils.selective_dl import get_sdl_appname
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.install import UninstallOptionsModel, InstallOptionsModel
|
||||
|
@ -178,6 +179,10 @@ class RareGameBase(QObject):
|
|||
except AttributeError:
|
||||
return False
|
||||
|
||||
@property
|
||||
def sdl_name(self) -> Optional[str]:
|
||||
return get_sdl_appname(self.app_name)
|
||||
|
||||
@property
|
||||
def version(self) -> str:
|
||||
"""!
|
||||
|
@ -268,7 +273,7 @@ class RareGameSlim(RareGameBase):
|
|||
return
|
||||
|
||||
if thread:
|
||||
worker = QRunnable.create(lambda: _upload())
|
||||
worker = QRunnable.create(_upload)
|
||||
QThreadPool.globalInstance().start(worker)
|
||||
else:
|
||||
_upload()
|
||||
|
@ -293,7 +298,7 @@ class RareGameSlim(RareGameBase):
|
|||
return
|
||||
|
||||
if thread:
|
||||
worker = QRunnable.create(lambda: _download())
|
||||
worker = QRunnable.create(_download)
|
||||
QThreadPool.globalInstance().start(worker)
|
||||
else:
|
||||
_download()
|
||||
|
|
|
@ -8,13 +8,13 @@ from threading import Lock
|
|||
from typing import List, Optional, Dict, Set
|
||||
|
||||
from PyQt5.QtCore import QRunnable, pyqtSlot, QProcess, QThreadPool
|
||||
from PyQt5.QtGui import QPixmap
|
||||
from PyQt5.QtGui import QPixmap, QPixmapCache
|
||||
from legendary.lfs import eos
|
||||
from legendary.models.game import Game, InstalledGame
|
||||
from legendary.utils.selective_dl import get_sdl_appname
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.install import InstallOptionsModel, UninstallOptionsModel
|
||||
from rare.models.base_game import RareGameBase, RareGameSlim
|
||||
from rare.models.install import InstallOptionsModel, UninstallOptionsModel
|
||||
from rare.shared.game_process import GameProcess
|
||||
from rare.shared.image_manager import ImageManager
|
||||
from rare.utils.paths import data_dir, get_rare_executable
|
||||
|
@ -412,10 +412,6 @@ class RareGame(RareGameSlim):
|
|||
else self.app_title
|
||||
)
|
||||
|
||||
@property
|
||||
def sdl_name(self) -> Optional[str]:
|
||||
return get_sdl_appname(self.app_name)
|
||||
|
||||
@property
|
||||
def save_path(self) -> Optional[str]:
|
||||
return super(RareGame, self).save_path
|
||||
|
@ -433,9 +429,12 @@ class RareGame(RareGameSlim):
|
|||
elapsed_time = abs(datetime.utcnow() - self.metadata.steam_date)
|
||||
if self.metadata.steam_grade is not None and elapsed_time.days < 3:
|
||||
return self.metadata.steam_grade
|
||||
worker = QRunnable.create(
|
||||
lambda: self.set_steam_grade(get_rating(self.core, self.app_name))
|
||||
)
|
||||
|
||||
def _set_steam_grade():
|
||||
rating = get_rating(self.core, self.app_name)
|
||||
self.set_steam_grade(rating)
|
||||
|
||||
worker = QRunnable.create(_set_steam_grade)
|
||||
QThreadPool.globalInstance().start(worker)
|
||||
return "pending"
|
||||
|
||||
|
@ -446,9 +445,10 @@ class RareGame(RareGameSlim):
|
|||
self.signals.widget.update.emit()
|
||||
|
||||
def grant_date(self, force=False) -> datetime:
|
||||
if (entitlements := self.core.lgd.entitlements) is None:
|
||||
return self.metadata.grant_date
|
||||
if self.metadata.grant_date is None or force:
|
||||
logger.debug("Grant date for %s not found in metadata, resolving", self.app_name)
|
||||
entitlements = self.core.lgd.entitlements
|
||||
matching = filter(lambda ent: ent["namespace"] == self.game.namespace, entitlements)
|
||||
entitlement = next(matching, None)
|
||||
grant_date = datetime.fromisoformat(
|
||||
|
@ -481,6 +481,7 @@ class RareGame(RareGameSlim):
|
|||
|
||||
def set_pixmap(self):
|
||||
self.pixmap = self.image_manager.get_pixmap(self.app_name, self.is_installed)
|
||||
QPixmapCache.clear()
|
||||
if not self.pixmap.isNull():
|
||||
self.signals.widget.update.emit()
|
||||
|
||||
|
@ -572,3 +573,93 @@ class RareEosOverlay(RareGameBase):
|
|||
else:
|
||||
self.igame = None
|
||||
self.signals.game.uninstalled.emit(self.app_name)
|
||||
|
||||
@property
|
||||
def has_update(self) -> bool:
|
||||
# lk: Don't check for updates here to ensure fast return
|
||||
# There is already a thread in the EosGroup form to update it for us asynchronously
|
||||
# and legendary does it too during login
|
||||
return self.core.overlay_update_available
|
||||
|
||||
def is_enabled(self, prefix: Optional[str] = None) -> bool:
|
||||
try:
|
||||
reg_paths = eos.query_registry_entries(prefix)
|
||||
except ValueError as e:
|
||||
logger.info("%s %s", e, prefix)
|
||||
return False
|
||||
return reg_paths["overlay_path"] and self.core.is_overlay_install(reg_paths["overlay_path"])
|
||||
|
||||
def active_path(self, prefix: Optional[str] = None) -> str:
|
||||
try:
|
||||
path = eos.query_registry_entries(prefix)["overlay_path"]
|
||||
except ValueError as e:
|
||||
logger.info("%s %s", e, prefix)
|
||||
return ""
|
||||
return path if path and self.core.is_overlay_install(path) else ""
|
||||
|
||||
def available_paths(self, prefix: Optional[str] = None) -> List[str]:
|
||||
try:
|
||||
installs = self.core.search_overlay_installs(prefix)
|
||||
except ValueError as e:
|
||||
logger.info("%s %s", e, prefix)
|
||||
return []
|
||||
return installs
|
||||
|
||||
def enable(
|
||||
self, prefix: Optional[str] = None, path: Optional[str] = None
|
||||
) -> bool:
|
||||
if self.is_enabled(prefix):
|
||||
return False
|
||||
if not path:
|
||||
if self.is_installed:
|
||||
path = self.igame.install_path
|
||||
else:
|
||||
path = self.available_paths(prefix)[-1]
|
||||
reg_paths = eos.query_registry_entries(prefix)
|
||||
if old_path := reg_paths["overlay_path"]:
|
||||
if os.path.normpath(old_path) == path:
|
||||
logger.info(f"Overlay already enabled, nothing to do.")
|
||||
return True
|
||||
else:
|
||||
logger.info(f'Updating overlay registry entries from "{old_path}" to "{path}"')
|
||||
eos.remove_registry_entries(prefix)
|
||||
try:
|
||||
eos.add_registry_entries(path, prefix)
|
||||
except PermissionError as e:
|
||||
logger.error("Exception while writing registry to enable the overlay.")
|
||||
logger.error(e)
|
||||
return False
|
||||
logger.info(f"Enabled overlay at: {path} for prefix: {prefix}")
|
||||
return True
|
||||
|
||||
def disable(self, prefix: Optional[str] = None) -> bool:
|
||||
if not self.is_enabled(prefix):
|
||||
return False
|
||||
logger.info(f"Disabling overlay (removing registry keys) for prefix: {prefix}")
|
||||
try:
|
||||
eos.remove_registry_entries(prefix)
|
||||
except PermissionError as e:
|
||||
logger.error("Exception while writing registry to disable the overlay.")
|
||||
logger.error(e)
|
||||
return False
|
||||
return True
|
||||
|
||||
def install(self) -> bool:
|
||||
if not self.is_idle:
|
||||
return False
|
||||
self.signals.game.install.emit(
|
||||
InstallOptionsModel(
|
||||
app_name=self.app_name,
|
||||
base_path=self.core.get_default_install_dir(),
|
||||
platform="Windows", update=self.is_installed, overlay=True
|
||||
)
|
||||
)
|
||||
return True
|
||||
|
||||
def uninstall(self) -> bool:
|
||||
if not self.is_idle or not self.is_installed:
|
||||
return False
|
||||
self.signals.game.uninstall.emit(
|
||||
UninstallOptionsModel(app_name=self.app_name)
|
||||
)
|
||||
return True
|
||||
|
|
|
@ -58,10 +58,10 @@ class ImageSize:
|
|||
def base(self) -> 'ImageSize.Preset':
|
||||
return self.__base
|
||||
|
||||
Image = Preset(1, 2)
|
||||
Image = Preset(1, 1)
|
||||
"""! @brief Size and pixel ratio of the image on disk"""
|
||||
|
||||
ImageWide = Preset(1, 2, Orientation.Wide)
|
||||
ImageWide = Preset(1, 1, Orientation.Wide)
|
||||
"""! @brief Size and pixel ratio for wide 16/9 image on disk"""
|
||||
|
||||
Display = Preset(1, 1, base=Image)
|
||||
|
|
|
@ -86,6 +86,7 @@ class UninstallOptionsModel:
|
|||
accepted: bool = None
|
||||
keep_files: bool = None
|
||||
keep_config: bool = None
|
||||
keep_overlay_keys: bool = None
|
||||
|
||||
def __bool__(self):
|
||||
return (
|
||||
|
@ -93,20 +94,21 @@ class UninstallOptionsModel:
|
|||
and (self.accepted is not None)
|
||||
and (self.keep_files is not None)
|
||||
and (self.keep_config is not None)
|
||||
and (self.keep_overlay_keys is not None)
|
||||
)
|
||||
|
||||
@property
|
||||
def values(self) -> Tuple[bool, bool, bool]:
|
||||
def values(self) -> Tuple[bool, bool, bool, bool]:
|
||||
"""
|
||||
This model's options
|
||||
|
||||
:return:
|
||||
Tuple of `accepted` `keep_files` `keep_config` `keep_overlay_keys`
|
||||
"""
|
||||
return self.accepted, self.keep_config, self.keep_files
|
||||
return self.accepted, self.keep_config, self.keep_files, self.keep_overlay_keys
|
||||
|
||||
@values.setter
|
||||
def values(self, values: Tuple[bool, bool, bool]):
|
||||
def values(self, values: Tuple[bool, bool, bool, bool]):
|
||||
"""
|
||||
Set this model's options
|
||||
|
||||
|
@ -117,6 +119,7 @@ class UninstallOptionsModel:
|
|||
self.accepted = values[0]
|
||||
self.keep_files = values[1]
|
||||
self.keep_config = values[2]
|
||||
self.keep_overlay_keys = values[3]
|
||||
|
||||
|
||||
@dataclass
|
||||
|
|
|
@ -10,14 +10,12 @@ class GlobalSignals:
|
|||
|
||||
class ApplicationSignals(QObject):
|
||||
# int: exit code
|
||||
quit = pyqtSignal(int)
|
||||
# str: app_title
|
||||
notify = pyqtSignal(str)
|
||||
quit = pyqtSignal(int)
|
||||
# str: title, str: body
|
||||
notify = pyqtSignal(str, str)
|
||||
# none
|
||||
prefix_updated = pyqtSignal()
|
||||
# none
|
||||
overlay_installed = pyqtSignal()
|
||||
# none
|
||||
update_tray = pyqtSignal()
|
||||
# none
|
||||
update_statusbar = pyqtSignal()
|
||||
|
@ -58,4 +56,4 @@ class GlobalSignals:
|
|||
self.download.deleteLater()
|
||||
del self.download
|
||||
self.discord_rpc.deleteLater()
|
||||
del self.discord_rpc
|
||||
del self.discord_rpc
|
||||
|
|
|
@ -64,7 +64,14 @@ class GameProcess(QObject):
|
|||
self.tried_connections += 1
|
||||
|
||||
if self.tried_connections > 50: # 10 seconds
|
||||
QMessageBox.warning(None, "Error", self.tr("Connection to game process failed (Timeout)"))
|
||||
QMessageBox.warning(
|
||||
None,
|
||||
self.tr("Error - {}").format(self.game.app_title),
|
||||
self.tr(
|
||||
"Connection to game launcher for <b>{}</b> failed due to timeout.\n"
|
||||
"This is usually do it the game or Rare's game launcher already running"
|
||||
).format(self.game.app_name)
|
||||
)
|
||||
self.timer.stop()
|
||||
self.finished.emit(GameProcess.Code.TIMEOUT)
|
||||
|
||||
|
|
|
@ -82,7 +82,7 @@ class ImageManager(QObject):
|
|||
self.device = ImageSize.Preset(1, QApplication.instance().devicePixelRatio())
|
||||
|
||||
self.threadpool = QThreadPool()
|
||||
self.threadpool.setMaxThreadCount(6)
|
||||
self.threadpool.setMaxThreadCount(4)
|
||||
|
||||
def __img_dir(self, app_name: str) -> Path:
|
||||
return self.image_dir.joinpath(app_name)
|
||||
|
|
|
@ -9,18 +9,22 @@ from typing import Dict, Iterator, Callable, Optional, List, Union, Iterable, Tu
|
|||
from PyQt5.QtCore import QObject, pyqtSignal, QSettings, pyqtSlot, QThreadPool, QRunnable, QTimer
|
||||
from legendary.lfs.eos import EOSOverlayApp
|
||||
from legendary.models.game import Game, SaveGameFile
|
||||
from requests import HTTPError
|
||||
from requests.exceptions import HTTPError, ConnectionError
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.models.base_game import RareSaveGame
|
||||
from rare.models.game import RareGame, RareEosOverlay
|
||||
from rare.models.signals import GlobalSignals
|
||||
from rare.utils.metrics import timelogger
|
||||
from rare.utils import config_helper
|
||||
from .image_manager import ImageManager
|
||||
from .workers import (
|
||||
QueueWorker,
|
||||
VerifyWorker,
|
||||
MoveWorker,
|
||||
FetchWorker,
|
||||
GamesDlcsWorker,
|
||||
EntitlementsWorker,
|
||||
OriginWineWorker,
|
||||
)
|
||||
from .workers.uninstall import uninstall_game
|
||||
|
@ -50,7 +54,7 @@ class RareCore(QObject):
|
|||
self.__core: Optional[LegendaryCore] = None
|
||||
self.__image_manager: Optional[ImageManager] = None
|
||||
|
||||
self.__start_time = time.time()
|
||||
self.__start_time = time.perf_counter()
|
||||
|
||||
self.args(args)
|
||||
self.signals(init=True)
|
||||
|
@ -66,6 +70,12 @@ class RareCore(QObject):
|
|||
|
||||
self.__library: Dict[str, RareGame] = {}
|
||||
self.__eos_overlay = RareEosOverlay(self.__core, EOSOverlayApp)
|
||||
self.__eos_overlay.signals.game.install.connect(self.__signals.game.install)
|
||||
self.__eos_overlay.signals.game.uninstall.connect(self.__signals.game.uninstall)
|
||||
|
||||
self.__fetch_progress: int = 0
|
||||
self.__fetched_games_dlcs: bool = False
|
||||
self.__fetched_entitlements: bool = False
|
||||
|
||||
RareCore.__instance = self
|
||||
|
||||
|
@ -224,12 +234,12 @@ class RareCore(QObject):
|
|||
for dlc in rgame.owned_dlcs:
|
||||
if dlc.is_installed:
|
||||
logger.info(f'Uninstalling DLC "{dlc.app_name}" ({dlc.app_title})...')
|
||||
uninstall_game(self.__core, dlc.app_name, keep_files=True, keep_config=True)
|
||||
uninstall_game(self.__core, dlc, keep_files=True, keep_config=True)
|
||||
dlc.igame = None
|
||||
logger.info(
|
||||
f'Removing "{rgame.app_title}" because "{rgame.igame.install_path}" does not exist...'
|
||||
)
|
||||
uninstall_game(self.__core, rgame.app_name, keep_files=True, keep_config=True)
|
||||
uninstall_game(self.__core, rgame, keep_files=True, keep_config=True)
|
||||
logger.info(f"Uninstalled {rgame.app_title}, because no game files exist")
|
||||
rgame.igame = None
|
||||
return
|
||||
|
@ -254,6 +264,9 @@ class RareCore(QObject):
|
|||
return self.__eos_overlay
|
||||
return self.__library[app_name]
|
||||
|
||||
def get_overlay(self):
|
||||
return self.get_game(EOSOverlayApp.app_name)
|
||||
|
||||
def __add_game(self, rgame: RareGame) -> None:
|
||||
rgame.signals.download.enqueue.connect(self.__signals.download.enqueue)
|
||||
rgame.signals.download.dequeue.connect(self.__signals.download.dequeue)
|
||||
|
@ -297,31 +310,52 @@ class RareCore(QObject):
|
|||
logger.info(f'Marking "{rgame.app_title}" as not installed because an exception has occurred...')
|
||||
logger.error(e)
|
||||
rgame.set_installed(False)
|
||||
self.progress.emit(int(idx/length * 80) + 20, self.tr("Loaded <b>{}</b>").format(rgame.app_title))
|
||||
progress = int(idx/length * self.__fetch_progress) + (100 - self.__fetch_progress)
|
||||
self.progress.emit(progress, self.tr("Loaded <b>{}</b>").format(rgame.app_title))
|
||||
|
||||
@pyqtSlot(int, str)
|
||||
def __on_fetch_progress(self, increment: int, message: str):
|
||||
self.__fetch_progress += increment
|
||||
self.progress.emit(self.__fetch_progress, message)
|
||||
|
||||
@pyqtSlot(object, int)
|
||||
def __on_fetch_result(self, result: Tuple[List, Dict], res_type: int):
|
||||
logger.info(f"Got API results for {FetchWorker.Result(res_type).name}")
|
||||
self.progress.emit(15, self.tr("Preparing library"))
|
||||
self.__add_games_and_dlcs(*result)
|
||||
self.progress.emit(100, self.tr("Launching Rare"))
|
||||
logger.debug(f"Fetch time {time.time() - self.__start_time} seconds")
|
||||
QTimer.singleShot(100, self.__post_init)
|
||||
self.completed.emit()
|
||||
def __on_fetch_result(self, result: Tuple, result_type: int):
|
||||
if result_type == FetchWorker.Result.GAMESDLCS:
|
||||
self.__add_games_and_dlcs(*result)
|
||||
self.__fetched_games_dlcs = True
|
||||
|
||||
if result_type == FetchWorker.Result.ENTITLEMENTS:
|
||||
self.__core.lgd.entitlements = result
|
||||
self.__fetched_entitlements = True
|
||||
|
||||
logger.info(f"Acquired data for {FetchWorker.Result(result_type).name}")
|
||||
|
||||
if all([self.__fetched_games_dlcs, self.__fetched_entitlements]):
|
||||
logger.debug(f"Fetch time {time.perf_counter() - self.__start_time} seconds")
|
||||
self.progress.emit(100, self.tr("Launching Rare"))
|
||||
self.completed.emit()
|
||||
QTimer.singleShot(100, self.__post_init)
|
||||
|
||||
def fetch(self):
|
||||
self.__start_time = time.time()
|
||||
fetch_worker = FetchWorker(self.__core, self.__args)
|
||||
fetch_worker.signals.progress.connect(self.progress)
|
||||
fetch_worker.signals.result.connect(self.__on_fetch_result)
|
||||
QThreadPool.globalInstance().start(fetch_worker)
|
||||
self.__start_time = time.perf_counter()
|
||||
|
||||
games_dlcs_worker = GamesDlcsWorker(self.__core, self.__args)
|
||||
games_dlcs_worker.signals.progress.connect(self.__on_fetch_progress)
|
||||
games_dlcs_worker.signals.result.connect(self.__on_fetch_result)
|
||||
|
||||
entitlements_worker = EntitlementsWorker(self.__core, self.__args)
|
||||
entitlements_worker.signals.progress.connect(self.__on_fetch_progress)
|
||||
entitlements_worker.signals.result.connect(self.__on_fetch_result)
|
||||
|
||||
QThreadPool.globalInstance().start(games_dlcs_worker)
|
||||
QThreadPool.globalInstance().start(entitlements_worker)
|
||||
|
||||
def fetch_saves(self):
|
||||
def __fetch() -> None:
|
||||
start_time = time.time()
|
||||
saves_dict: Dict[str, List[SaveGameFile]] = {}
|
||||
try:
|
||||
saves_list = self.__core.get_save_games()
|
||||
with timelogger(logger, "Request saves"):
|
||||
saves_list = self.__core.get_save_games()
|
||||
for s in saves_list:
|
||||
if s.app_name not in saves_dict.keys():
|
||||
saves_dict[s.app_name] = [s]
|
||||
|
@ -332,31 +366,14 @@ class RareCore(QObject):
|
|||
continue
|
||||
self.__library[app_name].load_saves(saves)
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.error(f"Exception while fetching saves from EGS: {e}")
|
||||
logger.error(f"Exception while fetching saves from EGS.")
|
||||
logger.error(e)
|
||||
return
|
||||
logger.debug(f"Saves: {len(saves_dict)}")
|
||||
logger.debug(f"Request saves: {time.time() - start_time} seconds")
|
||||
logger.info(f"Saves: {len(saves_dict)}")
|
||||
|
||||
saves_worker = QRunnable.create(__fetch)
|
||||
QThreadPool.globalInstance().start(saves_worker)
|
||||
|
||||
def fetch_entitlements(self) -> None:
|
||||
def __fetch() -> None:
|
||||
start_time = time.time()
|
||||
try:
|
||||
entitlements = self.__core.egs.get_user_entitlements()
|
||||
self.__core.lgd.entitlements = entitlements
|
||||
for game in self.__library.values():
|
||||
game.grant_date()
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.error(f"Failed to retrieve user entitlements from EGS: {e}")
|
||||
return
|
||||
logger.debug(f"Entitlements: {len(list(entitlements))}")
|
||||
logger.debug(f"Request Entitlements: {time.time() - start_time} seconds")
|
||||
|
||||
entitlements_worker = QRunnable.create(__fetch)
|
||||
QThreadPool.globalInstance().start(entitlements_worker)
|
||||
|
||||
def resolve_origin(self) -> None:
|
||||
origin_worker = OriginWineWorker(self.__core, list(self.origin_games))
|
||||
QThreadPool.globalInstance().start(origin_worker)
|
||||
|
@ -364,7 +381,6 @@ class RareCore(QObject):
|
|||
def __post_init(self) -> None:
|
||||
if not self.__args.offline:
|
||||
self.fetch_saves()
|
||||
self.fetch_entitlements()
|
||||
self.resolve_origin()
|
||||
|
||||
@property
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
from .fetch import FetchWorker
|
||||
from .fetch import FetchWorker, GamesDlcsWorker, EntitlementsWorker
|
||||
from .install_info import InstallInfoWorker
|
||||
from .move import MoveWorker
|
||||
from .uninstall import UninstallWorker
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
import platform
|
||||
import time
|
||||
from argparse import Namespace
|
||||
from enum import IntEnum
|
||||
from logging import getLogger
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal, QSettings
|
||||
from requests.exceptions import ConnectionError, HTTPError
|
||||
from requests.exceptions import HTTPError, ConnectionError
|
||||
|
||||
from rare.lgndr.core import LegendaryCore
|
||||
from rare.utils.metrics import timelogger
|
||||
from .worker import Worker
|
||||
|
||||
logger = getLogger("FetchWorker")
|
||||
|
@ -15,9 +15,9 @@ logger = getLogger("FetchWorker")
|
|||
|
||||
class FetchWorker(Worker):
|
||||
class Result(IntEnum):
|
||||
GAMES = 1
|
||||
NON_ASSET = 2
|
||||
COMBINED = 3
|
||||
ERROR = 0
|
||||
GAMESDLCS = 1
|
||||
ENTITLEMENTS = 2
|
||||
|
||||
class Signals(QObject):
|
||||
progress = pyqtSignal(int, str)
|
||||
|
@ -30,15 +30,39 @@ class FetchWorker(Worker):
|
|||
self.args = args
|
||||
self.settings = QSettings()
|
||||
|
||||
def run_real(self):
|
||||
# Fetch regular EGL games with assets
|
||||
start_time = time.time()
|
||||
|
||||
class EntitlementsWorker(FetchWorker):
|
||||
def __init__(self, core: LegendaryCore, args: Namespace):
|
||||
super(EntitlementsWorker, self).__init__(core, args)
|
||||
|
||||
def run_real(self):
|
||||
entitlements = ()
|
||||
want_entitlements = not self.settings.value("exclude_entitlements", False, bool)
|
||||
if want_entitlements:
|
||||
# Get entitlements, Ubisoft integration also uses them
|
||||
self.signals.progress.emit(0, self.signals.tr("Updating entitlements"))
|
||||
with timelogger(logger, "Request entitlements"):
|
||||
entitlements = self.core.egs.get_user_entitlements()
|
||||
self.core.lgd.entitlements = entitlements
|
||||
logger.info(f"Entitlements: %s", len(list(entitlements)))
|
||||
self.signals.result.emit(entitlements, FetchWorker.Result.ENTITLEMENTS)
|
||||
return
|
||||
|
||||
|
||||
class GamesDlcsWorker(FetchWorker):
|
||||
|
||||
def __init__(self, core: LegendaryCore, args: Namespace):
|
||||
super(GamesDlcsWorker, self).__init__(core, args)
|
||||
self.exclude_non_asset = QSettings().value("exclude_non_asset", False, bool)
|
||||
|
||||
def run_real(self):
|
||||
|
||||
# Fetch regular EGL games with assets
|
||||
want_unreal = self.settings.value("unreal_meta", False, bool) or self.args.debug
|
||||
want_win32 = self.settings.value("win32_meta", False, bool)
|
||||
want_macos = self.settings.value("macos_meta", False, bool)
|
||||
need_macos = platform.system() == "Darwin"
|
||||
need_windows = not any([want_win32, want_macos, need_macos, self.args.debug])
|
||||
need_windows = not any([want_win32, want_macos, need_macos, self.args.debug]) and not self.args.offline
|
||||
|
||||
if want_win32 or self.args.debug:
|
||||
logger.info(
|
||||
|
@ -47,9 +71,10 @@ class FetchWorker(Worker):
|
|||
"with" if want_unreal else "without"
|
||||
)
|
||||
self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
|
||||
self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Win32", skip_ue=not want_unreal
|
||||
)
|
||||
with timelogger(logger, "Request Win32 games"):
|
||||
self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Win32", skip_ue=not want_unreal
|
||||
)
|
||||
|
||||
if need_macos or want_macos or self.args.debug:
|
||||
logger.info(
|
||||
|
@ -58,9 +83,10 @@ class FetchWorker(Worker):
|
|||
"with" if want_unreal else "without"
|
||||
)
|
||||
self.signals.progress.emit(15, self.signals.tr("Updating game metadata for macOS"))
|
||||
self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Mac", skip_ue=not want_unreal
|
||||
)
|
||||
with timelogger(logger, "Request macOS games"):
|
||||
self.core.get_game_and_dlc_list(
|
||||
update_assets=not self.args.offline, platform="Mac", skip_ue=not want_unreal
|
||||
)
|
||||
|
||||
if need_windows:
|
||||
self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
|
||||
|
@ -68,39 +94,39 @@ class FetchWorker(Worker):
|
|||
"Requesting Windows metadata, %s Unreal engine",
|
||||
"with" if want_unreal else "without"
|
||||
)
|
||||
games, dlc_dict = self.core.get_game_and_dlc_list(
|
||||
update_assets=need_windows, platform="Windows", skip_ue=not want_unreal
|
||||
)
|
||||
logger.debug(f"Games {len(games)}, games with DLCs {len(dlc_dict)}")
|
||||
logger.debug(f"Request games: {time.time() - start_time} seconds")
|
||||
with timelogger(logger, "Request Windows games"):
|
||||
games, dlc_dict = self.core.get_game_and_dlc_list(
|
||||
update_assets=need_windows, platform="Windows", skip_ue=not want_unreal
|
||||
)
|
||||
logger.info(f"Games: %s. Games with DLCs: %s", len(games), len(dlc_dict))
|
||||
|
||||
# Fetch non-asset games
|
||||
self.signals.progress.emit(30, self.signals.tr("Updating non-asset game metadata"))
|
||||
start_time = time.time()
|
||||
try:
|
||||
na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.warning(f"Exception while fetching non asset games from EGS: {e}")
|
||||
na_games, na_dlc_dict = ([], {})
|
||||
# FIXME:
|
||||
# This is here because of broken appIds from Epic:
|
||||
# https://discord.com/channels/826881530310819914/884510635642216499/1111321692703305729
|
||||
# There is a tab character in the appId of Fallout New Vegas: Honest Hearts DLC, this breaks metadata storage
|
||||
# on Windows as they can't handle tabs at the end of the filename (?)
|
||||
# Legendary and Heroic are also affected, but it completely breaks Rare, so dodge it for now pending a fix.
|
||||
except Exception as e:
|
||||
logger.error(f"Exception while fetching non asset games from EGS: {e}")
|
||||
na_games, na_dlc_dict = ([], {})
|
||||
logger.debug(f"Non-asset {len(na_games)}, games with non-asset DLCs {len(na_dlc_dict)}")
|
||||
logger.debug(f"Request non-asset: {time.time() - start_time} seconds")
|
||||
want_non_asset = not self.settings.value("exclude_non_asset", False, bool)
|
||||
if want_non_asset:
|
||||
self.signals.progress.emit(30, self.signals.tr("Updating non-asset game metadata"))
|
||||
try:
|
||||
with timelogger(logger, "Request non-asset"):
|
||||
na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)
|
||||
except (HTTPError, ConnectionError) as e:
|
||||
logger.error(f"Network error while fetching non asset games")
|
||||
logger.error(e)
|
||||
na_games, na_dlc_dict = ([], {})
|
||||
# NOTE: This is here because of broken appIds from Epic
|
||||
# https://discord.com/channels/826881530310819914/884510635642216499/1111321692703305729
|
||||
except Exception as e:
|
||||
logger.error("General exception while fetching non asset games from EGS.")
|
||||
logger.error(e)
|
||||
na_games, na_dlc_dict = ([], {})
|
||||
logger.info("Non-asset: %s. Non-asset with DLCs: %s", len(na_games), len(na_dlc_dict))
|
||||
|
||||
# Combine the two games lists and the two dlc dictionaries between regular and non-asset results
|
||||
games += na_games
|
||||
for catalog_id, dlcs in na_dlc_dict.items():
|
||||
if catalog_id in dlc_dict.keys():
|
||||
dlc_dict[catalog_id] += dlcs
|
||||
else:
|
||||
dlc_dict[catalog_id] = dlcs
|
||||
logger.debug(f"Games {len(games)}, games with DLCs {len(dlc_dict)}")
|
||||
# Combine the two games lists and the two dlc dictionaries between regular and non-asset results
|
||||
games += na_games
|
||||
for catalog_id, dlcs in na_dlc_dict.items():
|
||||
if catalog_id in dlc_dict.keys():
|
||||
dlc_dict[catalog_id] += dlcs
|
||||
else:
|
||||
dlc_dict[catalog_id] = dlcs
|
||||
logger.info(f"Games: {len(games)}. Games with DLCs: {len(dlc_dict)}")
|
||||
|
||||
self.signals.result.emit((games, dlc_dict), FetchWorker.Result.COMBINED)
|
||||
self.signals.progress.emit(40, self.signals.tr("Preparing library"))
|
||||
self.signals.result.emit((games, dlc_dict), FetchWorker.Result.GAMESDLCS)
|
||||
|
|
|
@ -41,9 +41,6 @@ class InstallInfoWorker(Worker):
|
|||
else:
|
||||
raise LgndrException(status.message)
|
||||
else:
|
||||
if not os.path.exists(path := self.options.base_path):
|
||||
os.makedirs(path)
|
||||
|
||||
dlm, analysis, igame = self.core.prepare_overlay_install(
|
||||
path=self.options.base_path
|
||||
)
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import platform
|
||||
from logging import getLogger
|
||||
from typing import Tuple
|
||||
|
||||
from PyQt5.QtCore import QObject, pyqtSignal
|
||||
from legendary.core import LegendaryCore
|
||||
from legendary.lfs.eos import remove_registry_entries
|
||||
|
||||
from rare.lgndr.cli import LegendaryCLI
|
||||
from rare.lgndr.glue.arguments import LgndrUninstallGameArgs
|
||||
|
@ -16,14 +19,36 @@ logger = getLogger("UninstallWorker")
|
|||
|
||||
|
||||
# TODO: You can use RareGame directly here once this is called inside RareCore and skip metadata fetch
|
||||
def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_config=False):
|
||||
game = core.get_game(app_name)
|
||||
def uninstall_game(
|
||||
core: LegendaryCore, rgame: RareGame, keep_files=False, keep_config=False, keep_overlay_keys=False
|
||||
) -> Tuple[bool, str]:
|
||||
if rgame.is_overlay:
|
||||
logger.info('Deleting overlay installation...')
|
||||
core.remove_overlay_install()
|
||||
|
||||
if keep_overlay_keys:
|
||||
return True, ""
|
||||
|
||||
logger.info('Removing registry entries...')
|
||||
if platform.system() != "Window":
|
||||
prefixes = config_helper.get_wine_prefixes()
|
||||
if platform.system() == "Darwin":
|
||||
# TODO: add crossover support
|
||||
pass
|
||||
if prefixes is not None:
|
||||
for prefix in prefixes:
|
||||
remove_registry_entries(prefix)
|
||||
logger.debug("Removed registry entries for prefix %s", prefix)
|
||||
else:
|
||||
remove_registry_entries()
|
||||
|
||||
return True, ""
|
||||
|
||||
# remove shortcuts link
|
||||
if desktop_links_supported():
|
||||
for link_type in desktop_link_types():
|
||||
link_path = desktop_link_path(
|
||||
game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value"), link_type
|
||||
rgame.game.metadata.get("customAttributes", {}).get("FolderName", {}).get("value"), link_type
|
||||
)
|
||||
if link_path.exists():
|
||||
link_path.unlink(missing_ok=True)
|
||||
|
@ -31,7 +56,7 @@ def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_co
|
|||
status = LgndrIndirectStatus()
|
||||
LegendaryCLI(core).uninstall_game(
|
||||
LgndrUninstallGameArgs(
|
||||
app_name=app_name,
|
||||
app_name=rgame.app_name,
|
||||
keep_files=keep_files,
|
||||
skip_uninstaller=False,
|
||||
yes=True,
|
||||
|
@ -40,8 +65,8 @@ def uninstall_game(core: LegendaryCore, app_name: str, keep_files=False, keep_co
|
|||
)
|
||||
if not keep_config:
|
||||
logger.info("Removing sections in config file")
|
||||
config_helper.remove_section(app_name)
|
||||
config_helper.remove_section(f"{app_name}.env")
|
||||
config_helper.remove_section(rgame.app_name)
|
||||
config_helper.remove_section(f"{rgame.app_name}.env")
|
||||
|
||||
config_helper.save_config()
|
||||
|
||||
|
@ -62,7 +87,11 @@ class UninstallWorker(Worker):
|
|||
def run_real(self) -> None:
|
||||
self.rgame.state = RareGame.State.UNINSTALLING
|
||||
success, message = uninstall_game(
|
||||
self.core, self.rgame.app_name, self.options.keep_files, self.options.keep_config
|
||||
self.core,
|
||||
self.rgame,
|
||||
self.options.keep_files,
|
||||
self.options.keep_config,
|
||||
self.options.keep_overlay_keys,
|
||||
)
|
||||
self.rgame.state = RareGame.State.IDLE
|
||||
self.signals.result.emit(self.rgame, success, message)
|
||||
|
|
|
@ -14,20 +14,17 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
class Ui_InstallDialog(object):
|
||||
def setupUi(self, InstallDialog):
|
||||
InstallDialog.setObjectName("InstallDialog")
|
||||
InstallDialog.resize(179, 204)
|
||||
InstallDialog.resize(197, 195)
|
||||
InstallDialog.setWindowTitle("InstallDialog")
|
||||
self.main_layout = QtWidgets.QFormLayout(InstallDialog)
|
||||
self.main_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.main_layout.setObjectName("main_layout")
|
||||
self.title_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.title_label.setObjectName("title_label")
|
||||
self.main_layout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.title_label)
|
||||
self.install_dir_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.install_dir_label.setObjectName("install_dir_label")
|
||||
self.main_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.install_dir_label)
|
||||
self.main_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.install_dir_label)
|
||||
self.platform_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.platform_label.setObjectName("platform_label")
|
||||
self.main_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.platform_label)
|
||||
self.main_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.platform_label)
|
||||
self.platform_combo = QtWidgets.QComboBox(InstallDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
|
@ -35,43 +32,43 @@ class Ui_InstallDialog(object):
|
|||
sizePolicy.setHeightForWidth(self.platform_combo.sizePolicy().hasHeightForWidth())
|
||||
self.platform_combo.setSizePolicy(sizePolicy)
|
||||
self.platform_combo.setObjectName("platform_combo")
|
||||
self.main_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.platform_combo)
|
||||
self.main_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.platform_combo)
|
||||
self.shortcut_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.shortcut_label.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
self.shortcut_label.setObjectName("shortcut_label")
|
||||
self.main_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.shortcut_label)
|
||||
self.main_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.shortcut_label)
|
||||
self.shortcut_check = QtWidgets.QCheckBox(InstallDialog)
|
||||
self.shortcut_check.setText("")
|
||||
self.shortcut_check.setObjectName("shortcut_check")
|
||||
self.main_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.shortcut_check)
|
||||
self.main_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.shortcut_check)
|
||||
self.selectable_layout = QtWidgets.QVBoxLayout()
|
||||
self.selectable_layout.setObjectName("selectable_layout")
|
||||
self.main_layout.setLayout(4, QtWidgets.QFormLayout.SpanningRole, self.selectable_layout)
|
||||
self.main_layout.setLayout(3, QtWidgets.QFormLayout.SpanningRole, self.selectable_layout)
|
||||
self.advanced_layout = QtWidgets.QVBoxLayout()
|
||||
self.advanced_layout.setObjectName("advanced_layout")
|
||||
self.main_layout.setLayout(5, QtWidgets.QFormLayout.SpanningRole, self.advanced_layout)
|
||||
self.main_layout.setLayout(4, QtWidgets.QFormLayout.SpanningRole, self.advanced_layout)
|
||||
self.download_size_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.download_size_label.setObjectName("download_size_label")
|
||||
self.main_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.download_size_label)
|
||||
self.main_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.download_size_label)
|
||||
self.download_size_text = QtWidgets.QLabel(InstallDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.download_size_text.setFont(font)
|
||||
self.download_size_text.setObjectName("download_size_text")
|
||||
self.main_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.download_size_text)
|
||||
self.main_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.download_size_text)
|
||||
self.install_size_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.install_size_label.setObjectName("install_size_label")
|
||||
self.main_layout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.install_size_label)
|
||||
self.main_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.install_size_label)
|
||||
self.install_size_text = QtWidgets.QLabel(InstallDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.install_size_text.setFont(font)
|
||||
self.install_size_text.setWordWrap(True)
|
||||
self.install_size_text.setObjectName("install_size_text")
|
||||
self.main_layout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.install_size_text)
|
||||
self.main_layout.setWidget(6, QtWidgets.QFormLayout.FieldRole, self.install_size_text)
|
||||
self.avail_space_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.avail_space_label.setObjectName("avail_space_label")
|
||||
self.main_layout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.avail_space_label)
|
||||
self.main_layout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.avail_space_label)
|
||||
self.avail_space = QtWidgets.QLabel(InstallDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setBold(True)
|
||||
|
@ -79,10 +76,10 @@ class Ui_InstallDialog(object):
|
|||
self.avail_space.setFont(font)
|
||||
self.avail_space.setText("")
|
||||
self.avail_space.setObjectName("avail_space")
|
||||
self.main_layout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.avail_space)
|
||||
self.main_layout.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.avail_space)
|
||||
self.warning_label = QtWidgets.QLabel(InstallDialog)
|
||||
self.warning_label.setObjectName("warning_label")
|
||||
self.main_layout.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.warning_label)
|
||||
self.main_layout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.warning_label)
|
||||
self.warning_text = QtWidgets.QLabel(InstallDialog)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
|
@ -92,13 +89,12 @@ class Ui_InstallDialog(object):
|
|||
self.warning_text.setWordWrap(True)
|
||||
self.warning_text.setTextInteractionFlags(QtCore.Qt.LinksAccessibleByMouse|QtCore.Qt.TextSelectableByMouse)
|
||||
self.warning_text.setObjectName("warning_text")
|
||||
self.main_layout.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.warning_text)
|
||||
self.main_layout.setWidget(8, QtWidgets.QFormLayout.FieldRole, self.warning_text)
|
||||
|
||||
self.retranslateUi(InstallDialog)
|
||||
|
||||
def retranslateUi(self, InstallDialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
self.title_label.setText(_translate("InstallDialog", "error"))
|
||||
self.install_dir_label.setText(_translate("InstallDialog", "Install folder"))
|
||||
self.platform_label.setText(_translate("InstallDialog", "Platform"))
|
||||
self.shortcut_label.setText(_translate("InstallDialog", "Create shortcut"))
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>179</width>
|
||||
<height>204</height>
|
||||
<width>197</width>
|
||||
<height>195</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -17,28 +17,21 @@
|
|||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="title_label">
|
||||
<property name="text">
|
||||
<string>error</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="install_dir_label">
|
||||
<property name="text">
|
||||
<string>Install folder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="platform_label">
|
||||
<property name="text">
|
||||
<string>Platform</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="platform_combo">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
|
@ -48,7 +41,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="shortcut_label">
|
||||
<property name="text">
|
||||
<string>Create shortcut</string>
|
||||
|
@ -58,27 +51,27 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="shortcut_check">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<layout class="QVBoxLayout" name="selectable_layout"/>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<item row="4" column="0" colspan="2">
|
||||
<layout class="QVBoxLayout" name="advanced_layout"/>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="download_size_label">
|
||||
<property name="text">
|
||||
<string>Download size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<item row="5" column="1">
|
||||
<widget class="QLabel" name="download_size_text">
|
||||
<property name="font">
|
||||
<font>
|
||||
|
@ -90,14 +83,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="install_size_label">
|
||||
<property name="text">
|
||||
<string>Total install size</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<item row="6" column="1">
|
||||
<widget class="QLabel" name="install_size_text">
|
||||
<property name="font">
|
||||
<font>
|
||||
|
@ -112,14 +105,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="avail_space_label">
|
||||
<property name="text">
|
||||
<string>Available space</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<item row="7" column="1">
|
||||
<widget class="QLabel" name="avail_space">
|
||||
<property name="font">
|
||||
<font>
|
||||
|
@ -132,14 +125,14 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<item row="8" column="0">
|
||||
<widget class="QLabel" name="warning_label">
|
||||
<property name="text">
|
||||
<string>Warning</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<item row="8" column="1">
|
||||
<widget class="QLabel" name="warning_text">
|
||||
<property name="font">
|
||||
<font>
|
||||
|
|
|
@ -14,102 +14,71 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
class Ui_EosWidget(object):
|
||||
def setupUi(self, EosWidget):
|
||||
EosWidget.setObjectName("EosWidget")
|
||||
EosWidget.resize(586, 146)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(EosWidget.sizePolicy().hasHeightForWidth())
|
||||
EosWidget.setSizePolicy(sizePolicy)
|
||||
EosWidget.resize(464, 98)
|
||||
EosWidget.setWindowTitle("GroupBox")
|
||||
self.eos_layout = QtWidgets.QHBoxLayout(EosWidget)
|
||||
self.eos_layout = QtWidgets.QVBoxLayout(EosWidget)
|
||||
self.eos_layout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
|
||||
self.eos_layout.setObjectName("eos_layout")
|
||||
self.overlay_stack = QtWidgets.QStackedWidget(EosWidget)
|
||||
self.overlay_stack.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.overlay_stack.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.overlay_stack.setObjectName("overlay_stack")
|
||||
self.overlay_info_page = QtWidgets.QWidget()
|
||||
self.overlay_info_page.setObjectName("overlay_info_page")
|
||||
self.overlay_info_layout = QtWidgets.QFormLayout(self.overlay_info_page)
|
||||
self.overlay_info_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.overlay_info_layout.setFormAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft)
|
||||
self.overlay_info_layout.setObjectName("overlay_info_layout")
|
||||
self.installed_version_info_lbl = QtWidgets.QLabel(self.overlay_info_page)
|
||||
self.installed_version_info_lbl.setObjectName("installed_version_info_lbl")
|
||||
self.overlay_info_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.installed_version_info_lbl)
|
||||
self.installed_version_lbl = QtWidgets.QLabel(self.overlay_info_page)
|
||||
self.installed_version_lbl.setText("error")
|
||||
self.installed_version_lbl.setObjectName("installed_version_lbl")
|
||||
self.overlay_info_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.installed_version_lbl)
|
||||
self.installed_path_info_lbl = QtWidgets.QLabel(self.overlay_info_page)
|
||||
self.installed_path_info_lbl.setObjectName("installed_path_info_lbl")
|
||||
self.overlay_info_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.installed_path_info_lbl)
|
||||
self.installed_path_lbl = QtWidgets.QLabel(self.overlay_info_page)
|
||||
self.installed_path_lbl.setText("error")
|
||||
self.installed_path_lbl.setObjectName("installed_path_lbl")
|
||||
self.overlay_info_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.installed_path_lbl)
|
||||
self.info_buttons_layout = QtWidgets.QHBoxLayout()
|
||||
self.info_buttons_layout.setObjectName("info_buttons_layout")
|
||||
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.info_buttons_layout.addItem(spacerItem)
|
||||
self.uninstall_button = QtWidgets.QPushButton(self.overlay_info_page)
|
||||
self.uninstall_button.setMinimumSize(QtCore.QSize(120, 0))
|
||||
self.uninstall_button.setObjectName("uninstall_button")
|
||||
self.info_buttons_layout.addWidget(self.uninstall_button)
|
||||
self.update_check_button = QtWidgets.QPushButton(self.overlay_info_page)
|
||||
self.update_check_button.setMinimumSize(QtCore.QSize(120, 0))
|
||||
self.update_check_button.setObjectName("update_check_button")
|
||||
self.info_buttons_layout.addWidget(self.update_check_button)
|
||||
self.update_button = QtWidgets.QPushButton(self.overlay_info_page)
|
||||
self.update_button.setMinimumSize(QtCore.QSize(120, 0))
|
||||
self.update_button.setObjectName("update_button")
|
||||
self.info_buttons_layout.addWidget(self.update_button)
|
||||
self.overlay_info_layout.setLayout(3, QtWidgets.QFormLayout.SpanningRole, self.info_buttons_layout)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(6, 6, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.overlay_info_layout.setItem(2, QtWidgets.QFormLayout.SpanningRole, spacerItem1)
|
||||
self.overlay_stack.addWidget(self.overlay_info_page)
|
||||
self.overlay_install_page = QtWidgets.QWidget()
|
||||
self.overlay_install_page.setObjectName("overlay_install_page")
|
||||
self.overlay_install_layout = QtWidgets.QFormLayout(self.overlay_install_page)
|
||||
self.overlay_install_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.overlay_install_layout.setFormAlignment(QtCore.Qt.AlignBottom|QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft)
|
||||
self.overlay_install_layout.setObjectName("overlay_install_layout")
|
||||
self.label = QtWidgets.QLabel(self.overlay_install_page)
|
||||
self.label.setObjectName("label")
|
||||
self.overlay_install_layout.setWidget(0, QtWidgets.QFormLayout.SpanningRole, self.label)
|
||||
self.install_buttons_layout = QtWidgets.QHBoxLayout()
|
||||
self.install_buttons_layout.setObjectName("install_buttons_layout")
|
||||
spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
|
||||
self.install_buttons_layout.addItem(spacerItem2)
|
||||
self.install_button = QtWidgets.QPushButton(self.overlay_install_page)
|
||||
self.install_button.setMinimumSize(QtCore.QSize(120, 0))
|
||||
self.install_page = QtWidgets.QWidget()
|
||||
self.install_page.setObjectName("install_page")
|
||||
self.install_page_layout = QtWidgets.QHBoxLayout(self.install_page)
|
||||
self.install_page_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.install_page_layout.setObjectName("install_page_layout")
|
||||
self.install_label_layout = QtWidgets.QFormLayout()
|
||||
self.install_label_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.install_label_layout.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
self.install_label_layout.setObjectName("install_label_layout")
|
||||
self.install_label = QtWidgets.QLabel(self.install_page)
|
||||
self.install_label.setObjectName("install_label")
|
||||
self.install_label_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.install_label)
|
||||
self.install_text = QtWidgets.QLabel(self.install_page)
|
||||
self.install_text.setObjectName("install_text")
|
||||
self.install_label_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.install_text)
|
||||
self.install_page_layout.addLayout(self.install_label_layout)
|
||||
self.install_button_layout = QtWidgets.QVBoxLayout()
|
||||
self.install_button_layout.setContentsMargins(-1, -1, 0, -1)
|
||||
self.install_button_layout.setObjectName("install_button_layout")
|
||||
self.install_button = QtWidgets.QPushButton(self.install_page)
|
||||
self.install_button.setMinimumSize(QtCore.QSize(140, 0))
|
||||
self.install_button.setObjectName("install_button")
|
||||
self.install_buttons_layout.addWidget(self.install_button)
|
||||
self.overlay_install_layout.setLayout(2, QtWidgets.QFormLayout.SpanningRole, self.install_buttons_layout)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(6, 6, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.overlay_install_layout.setItem(1, QtWidgets.QFormLayout.SpanningRole, spacerItem3)
|
||||
self.overlay_stack.addWidget(self.overlay_install_page)
|
||||
self.install_button_layout.addWidget(self.install_button)
|
||||
self.install_page_layout.addLayout(self.install_button_layout)
|
||||
self.install_page_layout.setStretch(0, 1)
|
||||
self.overlay_stack.addWidget(self.install_page)
|
||||
self.info_page = QtWidgets.QWidget()
|
||||
self.info_page.setObjectName("info_page")
|
||||
self.info_page_layout = QtWidgets.QHBoxLayout(self.info_page)
|
||||
self.info_page_layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.info_page_layout.setObjectName("info_page_layout")
|
||||
self.info_label_layout = QtWidgets.QFormLayout()
|
||||
self.info_label_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.info_label_layout.setFormAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter)
|
||||
self.info_label_layout.setObjectName("info_label_layout")
|
||||
self.version_label = QtWidgets.QLabel(self.info_page)
|
||||
self.version_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.version_label.setObjectName("version_label")
|
||||
self.info_label_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.version_label)
|
||||
self.path_label = QtWidgets.QLabel(self.info_page)
|
||||
self.path_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.path_label.setObjectName("path_label")
|
||||
self.info_label_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.path_label)
|
||||
self.info_page_layout.addLayout(self.info_label_layout)
|
||||
self.info_button_layout = QtWidgets.QVBoxLayout()
|
||||
self.info_button_layout.setObjectName("info_button_layout")
|
||||
self.update_button = QtWidgets.QPushButton(self.info_page)
|
||||
self.update_button.setMinimumSize(QtCore.QSize(140, 0))
|
||||
self.update_button.setObjectName("update_button")
|
||||
self.info_button_layout.addWidget(self.update_button)
|
||||
self.uninstall_button = QtWidgets.QPushButton(self.info_page)
|
||||
self.uninstall_button.setMinimumSize(QtCore.QSize(140, 0))
|
||||
self.uninstall_button.setObjectName("uninstall_button")
|
||||
self.info_button_layout.addWidget(self.uninstall_button)
|
||||
self.info_page_layout.addLayout(self.info_button_layout)
|
||||
self.info_page_layout.setStretch(0, 1)
|
||||
self.overlay_stack.addWidget(self.info_page)
|
||||
self.eos_layout.addWidget(self.overlay_stack)
|
||||
self.enable_frame = QtWidgets.QFrame(EosWidget)
|
||||
self.enable_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
|
||||
self.enable_frame.setFrameShadow(QtWidgets.QFrame.Raised)
|
||||
self.enable_frame.setObjectName("enable_frame")
|
||||
self.enable_layout = QtWidgets.QVBoxLayout(self.enable_frame)
|
||||
self.enable_layout.setObjectName("enable_layout")
|
||||
self.select_pfx_combo = QtWidgets.QComboBox(self.enable_frame)
|
||||
self.select_pfx_combo.setObjectName("select_pfx_combo")
|
||||
self.enable_layout.addWidget(self.select_pfx_combo)
|
||||
self.enabled_cb = QtWidgets.QCheckBox(self.enable_frame)
|
||||
self.enabled_cb.setObjectName("enabled_cb")
|
||||
self.enable_layout.addWidget(self.enabled_cb)
|
||||
self.enabled_info_label = QtWidgets.QLabel(self.enable_frame)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.enabled_info_label.setFont(font)
|
||||
self.enabled_info_label.setText("")
|
||||
self.enabled_info_label.setObjectName("enabled_info_label")
|
||||
self.enable_layout.addWidget(self.enabled_info_label)
|
||||
self.eos_layout.addWidget(self.enable_frame)
|
||||
|
||||
self.retranslateUi(EosWidget)
|
||||
self.overlay_stack.setCurrentIndex(0)
|
||||
|
@ -117,14 +86,13 @@ class Ui_EosWidget(object):
|
|||
def retranslateUi(self, EosWidget):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
EosWidget.setTitle(_translate("EosWidget", "Epic Overlay"))
|
||||
self.installed_version_info_lbl.setText(_translate("EosWidget", "Version"))
|
||||
self.installed_path_info_lbl.setText(_translate("EosWidget", "Location"))
|
||||
self.uninstall_button.setText(_translate("EosWidget", "Uninstall"))
|
||||
self.update_check_button.setText(_translate("EosWidget", "Check for update"))
|
||||
self.update_button.setText(_translate("EosWidget", "Update"))
|
||||
self.label.setText(_translate("EosWidget", "Epic Overlay Services is not installed"))
|
||||
self.install_label.setText(_translate("EosWidget", "Status:"))
|
||||
self.install_text.setText(_translate("EosWidget", "Epic Online Services Overlay is not installed"))
|
||||
self.install_button.setText(_translate("EosWidget", "Install"))
|
||||
self.enabled_cb.setText(_translate("EosWidget", "Activated"))
|
||||
self.version_label.setText(_translate("EosWidget", "Version:"))
|
||||
self.path_label.setText(_translate("EosWidget", "Path:"))
|
||||
self.update_button.setText(_translate("EosWidget", "Update"))
|
||||
self.uninstall_button.setText(_translate("EosWidget", "Uninstall"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -6,179 +6,73 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>586</width>
|
||||
<height>146</height>
|
||||
<width>464</width>
|
||||
<height>98</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">GroupBox</string>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Epic Overlay</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="eos_layout" stretch="0,0">
|
||||
<layout class="QVBoxLayout" name="eos_layout" stretch="0">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetDefaultConstraint</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="overlay_stack">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="overlay_info_page">
|
||||
<layout class="QFormLayout" name="overlay_info_layout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
<widget class="QWidget" name="install_page">
|
||||
<layout class="QHBoxLayout" name="install_page_layout" stretch="1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="installed_version_info_lbl">
|
||||
<property name="text">
|
||||
<string>Version</string>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="install_label_layout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="installed_version_lbl">
|
||||
<property name="text">
|
||||
<string notr="true">error</string>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="installed_path_info_lbl">
|
||||
<property name="text">
|
||||
<string>Location</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLabel" name="installed_path_lbl">
|
||||
<property name="text">
|
||||
<string notr="true">error</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="info_buttons_layout">
|
||||
<item>
|
||||
<spacer name="info_buttons_hspacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uninstall_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="install_label">
|
||||
<property name="text">
|
||||
<string>Uninstall</string>
|
||||
<string>Status:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="update_check_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="install_text">
|
||||
<property name="text">
|
||||
<string>Check for update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="update_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
<string>Epic Online Services Overlay is not installed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<spacer name="info_page_vspacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="install_button_layout">
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="overlay_install_page">
|
||||
<layout class="QFormLayout" name="overlay_install_layout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Epic Overlay Services is not installed</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="install_buttons_layout">
|
||||
<item>
|
||||
<spacer name="install_buttons_hspacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="install_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
|
@ -189,57 +83,86 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<spacer name="install_page_vspacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="info_page">
|
||||
<layout class="QHBoxLayout" name="info_page_layout" stretch="1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="info_label_layout">
|
||||
<property name="labelAlignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>6</width>
|
||||
<height>6</height>
|
||||
</size>
|
||||
<property name="formAlignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</spacer>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="version_label">
|
||||
<property name="text">
|
||||
<string>Version:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="path_label">
|
||||
<property name="text">
|
||||
<string>Path:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="info_button_layout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="update_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uninstall_button">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>140</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Uninstall</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="enable_frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::StyledPanel</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="enable_layout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="select_pfx_combo"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enabled_cb">
|
||||
<property name="text">
|
||||
<string>Activated</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="enabled_info_label">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
|
|
@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
|
|||
class Ui_LegendarySettings(object):
|
||||
def setupUi(self, LegendarySettings):
|
||||
LegendarySettings.setObjectName("LegendarySettings")
|
||||
LegendarySettings.resize(681, 456)
|
||||
LegendarySettings.resize(608, 420)
|
||||
LegendarySettings.setWindowTitle("LegendarySettings")
|
||||
self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings)
|
||||
self.legendary_layout.setObjectName("legendary_layout")
|
||||
|
@ -128,26 +128,32 @@ class Ui_LegendarySettings(object):
|
|||
self.right_layout.addWidget(self.cleanup_group)
|
||||
self.metadata_group = QtWidgets.QGroupBox(LegendarySettings)
|
||||
self.metadata_group.setObjectName("metadata_group")
|
||||
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.metadata_group)
|
||||
self.verticalLayout_2.setObjectName("verticalLayout_2")
|
||||
self.metadata_layout = QtWidgets.QVBoxLayout(self.metadata_group)
|
||||
self.metadata_layout.setObjectName("metadata_layout")
|
||||
self.fetch_win32_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.fetch_win32_check.setObjectName("fetch_win32_check")
|
||||
self.verticalLayout_2.addWidget(self.fetch_win32_check)
|
||||
self.metadata_layout.addWidget(self.fetch_win32_check)
|
||||
self.fetch_macos_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.fetch_macos_check.setObjectName("fetch_macos_check")
|
||||
self.verticalLayout_2.addWidget(self.fetch_macos_check)
|
||||
self.metadata_layout.addWidget(self.fetch_macos_check)
|
||||
self.fetch_unreal_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.fetch_unreal_check.setObjectName("fetch_unreal_check")
|
||||
self.verticalLayout_2.addWidget(self.fetch_unreal_check)
|
||||
self.metadata_layout.addWidget(self.fetch_unreal_check)
|
||||
self.exclude_non_asset_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.exclude_non_asset_check.setObjectName("exclude_non_asset_check")
|
||||
self.metadata_layout.addWidget(self.exclude_non_asset_check)
|
||||
self.exclude_entitlements_check = QtWidgets.QCheckBox(self.metadata_group)
|
||||
self.exclude_entitlements_check.setObjectName("exclude_entitlements_check")
|
||||
self.metadata_layout.addWidget(self.exclude_entitlements_check)
|
||||
self.metadata_info = QtWidgets.QLabel(self.metadata_group)
|
||||
font = QtGui.QFont()
|
||||
font.setItalic(True)
|
||||
self.metadata_info.setFont(font)
|
||||
self.metadata_info.setObjectName("metadata_info")
|
||||
self.verticalLayout_2.addWidget(self.metadata_info)
|
||||
self.metadata_layout.addWidget(self.metadata_info)
|
||||
self.refresh_metadata_button = QtWidgets.QPushButton(self.metadata_group)
|
||||
self.refresh_metadata_button.setObjectName("refresh_metadata_button")
|
||||
self.verticalLayout_2.addWidget(self.refresh_metadata_button)
|
||||
self.metadata_layout.addWidget(self.refresh_metadata_button)
|
||||
self.right_layout.addWidget(self.metadata_group)
|
||||
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.right_layout.addItem(spacerItem1)
|
||||
|
@ -175,6 +181,14 @@ class Ui_LegendarySettings(object):
|
|||
self.fetch_win32_check.setText(_translate("LegendarySettings", "Include Win32 games"))
|
||||
self.fetch_macos_check.setText(_translate("LegendarySettings", "Include macOS games"))
|
||||
self.fetch_unreal_check.setText(_translate("LegendarySettings", "Include Unreal engine"))
|
||||
self.exclude_non_asset_check.setToolTip(_translate("LegendarySettings", "Do not load metadata for non-asset games (i.e. Origin games) on start-up.\n"
|
||||
"\n"
|
||||
"Disabling this greatly improves start-up time, but some games might not be visible in your library."))
|
||||
self.exclude_non_asset_check.setText(_translate("LegendarySettings", "Exclude non-asset games"))
|
||||
self.exclude_entitlements_check.setToolTip(_translate("LegendarySettings", "Do not load entitlement data (i.e game\'s date of purchase) on start-up.\n"
|
||||
"\n"
|
||||
"Disabling this greatly improves start-up time, but some library filters may not work."))
|
||||
self.exclude_entitlements_check.setText(_translate("LegendarySettings", "Exclude entitlements"))
|
||||
self.metadata_info.setText(_translate("LegendarySettings", "Restart Rare to apply"))
|
||||
self.refresh_metadata_button.setText(_translate("LegendarySettings", "Refresh metadata"))
|
||||
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>681</width>
|
||||
<height>456</height>
|
||||
<width>608</width>
|
||||
<height>420</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -231,7 +231,7 @@
|
|||
<property name="title">
|
||||
<string>Platforms</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<layout class="QVBoxLayout" name="metadata_layout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="fetch_win32_check">
|
||||
<property name="text">
|
||||
|
@ -253,6 +253,30 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="exclude_non_asset_check">
|
||||
<property name="toolTip">
|
||||
<string>Do not load metadata for non-asset games (i.e. Origin games) on start-up.
|
||||
|
||||
Disabling this greatly improves start-up time, but some games might not be visible in your library.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exclude non-asset games</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="exclude_entitlements_check">
|
||||
<property name="toolTip">
|
||||
<string>Do not load entitlement data (i.e game's date of purchase) on start-up.
|
||||
|
||||
Disabling this greatly improves start-up time, but some library filters may not work.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Exclude entitlements</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="metadata_info">
|
||||
<property name="font">
|
||||
|
|
|
@ -20,26 +20,39 @@ def save_config():
|
|||
_save_config()
|
||||
|
||||
|
||||
def add_option(app_name: str, option: str, value: str):
|
||||
def add_option(app_name: str, option: str, value: str) -> None:
|
||||
value = value.replace("%%", "%").replace("%", "%%")
|
||||
if not _config.has_section(app_name):
|
||||
_config[app_name] = {}
|
||||
|
||||
_config.set(app_name, option, value)
|
||||
save_config()
|
||||
|
||||
|
||||
def remove_option(app_name, option):
|
||||
def add_envvar(app_name: str, envvar: str, value: str) -> None:
|
||||
add_option(f"{app_name}.env", envvar, value)
|
||||
|
||||
|
||||
def remove_option(app_name: str, option: str) -> None:
|
||||
if _config.has_option(app_name, option):
|
||||
_config.remove_option(app_name, option)
|
||||
|
||||
# if _config.has_section(app_name) and not _config[app_name]:
|
||||
# _config.remove_section(app_name)
|
||||
|
||||
save_config()
|
||||
|
||||
|
||||
def remove_section(app_name):
|
||||
def remove_envvar(app_name: str, option: str) -> None:
|
||||
remove_option(f"{app_name}.env", option)
|
||||
|
||||
|
||||
def get_option(app_name: str, option: str, fallback: Any = None) -> str:
|
||||
return _config.get(app_name, option, fallback=fallback)
|
||||
|
||||
|
||||
def get_envvar(app_name: str, option: str, fallback: Any = None) -> str:
|
||||
return get_option(f"{app_name}.env", option, fallback=fallback)
|
||||
|
||||
|
||||
def remove_section(app_name: str) -> None:
|
||||
return
|
||||
# Disabled due to env variables implementation
|
||||
if _config.has_section(app_name):
|
||||
|
@ -61,13 +74,14 @@ def get_game_envvar(option: str, app_name: Optional[str] = None, fallback: Any =
|
|||
return _option
|
||||
|
||||
|
||||
def get_proton_compat_data(app_name: Optional[str] = None, fallback: Any = None) -> str:
|
||||
_compat = get_game_envvar("STEAM_COMPAT_DATA_PATH", app_name, fallback=fallback)
|
||||
# return os.path.join(_compat, "pfx") if _compat else fallback
|
||||
return _compat
|
||||
|
||||
|
||||
def get_wine_prefix(app_name: Optional[str] = None, fallback: Any = None) -> str:
|
||||
_prefix = os.path.join(
|
||||
_config.get("default.env", "STEAM_COMPAT_DATA_PATH", fallback=fallback), "pfx")
|
||||
if app_name is not None:
|
||||
_prefix = os.path.join(
|
||||
_config.get(f'{app_name}.env', "STEAM_COMPAT_DATA_PATH", fallback=_prefix), "pfx")
|
||||
_prefix = _config.get("default.env", "WINEPREFIX", fallback=_prefix)
|
||||
_prefix = _config.get("default.env", "WINEPREFIX", fallback=fallback)
|
||||
_prefix = _config.get("default", "wine_prefix", fallback=_prefix)
|
||||
if app_name is not None:
|
||||
_prefix = _config.get(f'{app_name}.env', 'WINEPREFIX', fallback=_prefix)
|
||||
|
@ -79,10 +93,47 @@ def get_wine_prefixes() -> Set[str]:
|
|||
_prefixes = []
|
||||
for name, section in _config.items():
|
||||
pfx = section.get("WINEPREFIX") or section.get("wine_prefix")
|
||||
if not pfx:
|
||||
pfx = os.path.join(compatdata, "pfx") if (compatdata := section.get("STEAM_COMPAT_DATA_PATH")) else ""
|
||||
if pfx:
|
||||
_prefixes.append(pfx)
|
||||
_prefixes = [os.path.expanduser(prefix) for prefix in _prefixes]
|
||||
return {p for p in _prefixes if os.path.isdir(p)}
|
||||
|
||||
|
||||
def get_proton_prefixes() -> Set[str]:
|
||||
_prefixes = []
|
||||
for name, section in _config.items():
|
||||
pfx = os.path.join(compatdata, "pfx") if (compatdata := section.get("STEAM_COMPAT_DATA_PATH")) else ""
|
||||
if pfx:
|
||||
_prefixes.append(pfx)
|
||||
_prefixes = [os.path.expanduser(prefix) for prefix in _prefixes]
|
||||
return {p for p in _prefixes if os.path.isdir(p)}
|
||||
|
||||
|
||||
def get_prefixes() -> Set[str]:
|
||||
return get_wine_prefixes().union(get_proton_prefixes())
|
||||
|
||||
|
||||
def prefix_exists(pfx: str) -> bool:
|
||||
return os.path.isdir(pfx) and os.path.isfile(os.path.join(pfx, "user.reg"))
|
||||
|
||||
|
||||
def get_prefix(app_name: str = "default") -> Optional[str]:
|
||||
_compat_path = _config.get(f"{app_name}.env", "STEAM_COMPAT_DATA_PATH", fallback=None)
|
||||
if _compat_path and prefix_exists(_compat_prefix := os.path.join(_compat_path, "pfx")):
|
||||
return _compat_prefix
|
||||
|
||||
_wine_prefix = _config.get(f"{app_name}.env", "WINEPREFIX", fallback=None)
|
||||
_wine_prefix = _config.get(app_name, "wine_prefix", fallback=_wine_prefix)
|
||||
if _wine_prefix and prefix_exists(_wine_prefix):
|
||||
return _wine_prefix
|
||||
|
||||
_compat_path = _config.get(f"default.env", "STEAM_COMPAT_DATA_PATH", fallback=None)
|
||||
if _compat_path and prefix_exists(_compat_prefix := os.path.join(_compat_path, "pfx")):
|
||||
return _compat_prefix
|
||||
|
||||
_wine_prefix = _config.get(f"default.env", "WINEPREFIX", fallback=None)
|
||||
_wine_prefix = _config.get("default", "wine_prefix", fallback=_wine_prefix)
|
||||
if _wine_prefix and prefix_exists(_wine_prefix):
|
||||
return _wine_prefix
|
||||
|
||||
return None
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
import platform as pf
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from logging import getLogger
|
||||
from typing import Optional, Union, List, Dict
|
||||
|
||||
import vdf
|
||||
if pf.system() in {"Linux", "FreeBSD"}:
|
||||
import vdf
|
||||
|
||||
logger = getLogger("Proton")
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import orjson
|
|||
from PyQt5.QtCore import QObject, pyqtSignal, QUrl, QUrlQuery, pyqtSlot
|
||||
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply, QNetworkDiskCache
|
||||
|
||||
REQUEST_LIMIT = 8
|
||||
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36"
|
||||
RequestHandler = TypeVar("RequestHandler", bound=Callable[[Union[Dict, bytes]], None])
|
||||
|
||||
|
@ -33,7 +32,6 @@ class QtRequests(QObject):
|
|||
self.log = getLogger(f"{type(self).__name__}_{type(parent).__name__}")
|
||||
self.manager = QNetworkAccessManager(self)
|
||||
self.manager.finished.connect(self.__on_finished)
|
||||
self.manager.finished.connect(self.__process_next)
|
||||
self.cache = None
|
||||
if cache is not None:
|
||||
self.log.debug("Using cache dir %s", cache)
|
||||
|
@ -44,8 +42,7 @@ class QtRequests(QObject):
|
|||
self.log.debug("Manager is authorized")
|
||||
self.token = token
|
||||
|
||||
self.__pending_requests = []
|
||||
self.__active_requests = {}
|
||||
self.__active_requests: Dict[QNetworkReply, RequestQueueItem] = {}
|
||||
|
||||
@staticmethod
|
||||
def __prepare_query(url, params) -> QUrl:
|
||||
|
@ -58,7 +55,7 @@ class QtRequests(QObject):
|
|||
|
||||
def __prepare_request(self, item: RequestQueueItem) -> QNetworkRequest:
|
||||
request = QNetworkRequest(item.url)
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json;charset=UTF-8")
|
||||
request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json; charset=UTF-8")
|
||||
request.setHeader(QNetworkRequest.UserAgentHeader, USER_AGENT)
|
||||
request.setAttribute(QNetworkRequest.RedirectPolicyAttribute, QNetworkRequest.NoLessSafeRedirectPolicy)
|
||||
if self.cache is not None:
|
||||
|
@ -76,10 +73,7 @@ class QtRequests(QObject):
|
|||
|
||||
def post(self, url: str, handler: RequestHandler, payload: dict):
|
||||
item = RequestQueueItem(method="post", url=QUrl(url), payload=payload, handlers=[handler])
|
||||
if len(self.__active_requests) < REQUEST_LIMIT:
|
||||
self.__post(item)
|
||||
else:
|
||||
self.__pending_requests.append(item)
|
||||
self.__post(item)
|
||||
|
||||
def __get(self, item: RequestQueueItem):
|
||||
request = self.__prepare_request(item)
|
||||
|
@ -90,10 +84,7 @@ class QtRequests(QObject):
|
|||
def get(self, url: str, handler: RequestHandler, payload: Dict = None, params: Dict = None):
|
||||
url = self.__prepare_query(url, params) if params is not None else QUrl(url)
|
||||
item = RequestQueueItem(method="get", url=url, payload=payload, handlers=[handler])
|
||||
if len(self.__active_requests) < REQUEST_LIMIT:
|
||||
self.__get(item)
|
||||
else:
|
||||
self.__pending_requests.append(item)
|
||||
self.__get(item)
|
||||
|
||||
def __on_error(self, error: QNetworkReply.NetworkError) -> None:
|
||||
self.log.error(error)
|
||||
|
@ -102,19 +93,9 @@ class QtRequests(QObject):
|
|||
def __parse_content_type(header) -> Tuple[str, str]:
|
||||
# lk: this looks weird but `cgi` is deprecated, PEP 594 suggests this way of parsing MIME
|
||||
m = Message()
|
||||
m['content-type'] = header
|
||||
m["content-type"] = header
|
||||
return m.get_content_type(), m.get_content_charset()
|
||||
|
||||
def __process_next(self):
|
||||
if self.__pending_requests:
|
||||
item = self.__pending_requests.pop(0)
|
||||
if item.method == "post":
|
||||
self.__post(item)
|
||||
elif item.method == "get":
|
||||
self.__get(item)
|
||||
else:
|
||||
raise NotImplementedError
|
||||
|
||||
@pyqtSlot(QNetworkReply)
|
||||
def __on_finished(self, reply: QNetworkReply):
|
||||
item = self.__active_requests.pop(reply, None)
|
||||
|
|
|
@ -101,9 +101,7 @@ class CollapsibleBase(object):
|
|||
|
||||
|
||||
class CollapsibleFrame(QFrame, CollapsibleBase):
|
||||
def __init__(
|
||||
self, widget: QWidget = None, title: str = "", button_text: str = "", animation_duration: int = 200, parent=None
|
||||
):
|
||||
def __init__(self, animation_duration: int = 200, parent=None):
|
||||
super(CollapsibleFrame, self).__init__(parent=parent)
|
||||
self.setup(animation_duration)
|
||||
self.setFrameStyle(QFrame.StyledPanel | QFrame.Sunken)
|
||||
|
@ -111,11 +109,10 @@ class CollapsibleFrame(QFrame, CollapsibleBase):
|
|||
self.toggle_button = QToolButton(self)
|
||||
self.toggle_button.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
|
||||
self.toggle_button.setIcon(icon("fa.arrow-right"))
|
||||
self.toggle_button.setText(button_text)
|
||||
self.toggle_button.setCheckable(True)
|
||||
self.toggle_button.setChecked(False)
|
||||
|
||||
self.title_label = QLabel(title)
|
||||
self.title_label = QLabel(self)
|
||||
font = self.title_label.font()
|
||||
font.setBold(True)
|
||||
self.title_label.setFont(font)
|
||||
|
@ -134,8 +131,11 @@ class CollapsibleFrame(QFrame, CollapsibleBase):
|
|||
|
||||
self.toggle_button.clicked.connect(self.animationStart)
|
||||
|
||||
if widget is not None:
|
||||
self.setWidget(widget)
|
||||
def setTitle(self, title: str):
|
||||
self.title_label.setText(title)
|
||||
|
||||
def setText(self, text: str):
|
||||
self.toggle_button.setText(text)
|
||||
|
||||
def isChecked(self) -> bool:
|
||||
return self.toggle_button.isChecked()
|
||||
|
@ -156,12 +156,9 @@ class CollapsibleFrame(QFrame, CollapsibleBase):
|
|||
|
||||
|
||||
class CollapsibleGroupBox(QGroupBox, CollapsibleBase):
|
||||
def __init__(
|
||||
self, widget: QWidget = None, title: str = "", animation_duration: int = 200, parent=None
|
||||
):
|
||||
def __init__(self, animation_duration: int = 200, parent=None):
|
||||
super(CollapsibleGroupBox, self).__init__(parent=parent)
|
||||
self.setup(animation_duration)
|
||||
self.setTitle(title)
|
||||
self.setCheckable(True)
|
||||
self.setChecked(False)
|
||||
|
||||
|
@ -173,9 +170,6 @@ class CollapsibleGroupBox(QGroupBox, CollapsibleBase):
|
|||
|
||||
self.toggled.connect(self.animationStart)
|
||||
|
||||
if widget is not None:
|
||||
self.setWidget(widget)
|
||||
|
||||
def isChecked(self) -> bool:
|
||||
return super(CollapsibleGroupBox, self).isChecked()
|
||||
|
||||
|
@ -202,7 +196,9 @@ if __name__ == "__main__":
|
|||
ui_frame = Ui_InstallDialogAdvanced()
|
||||
widget_frame = QWidget()
|
||||
ui_frame.setupUi(widget_frame)
|
||||
collapsible_frame = CollapsibleFrame(widget_frame, title="Frame me!")
|
||||
collapsible_frame = CollapsibleFrame()
|
||||
collapsible_frame.setWidget(widget_frame)
|
||||
collapsible_frame.setTitle("Frame me!")
|
||||
collapsible_frame.setDisabled(False)
|
||||
|
||||
def replace_func_frame(state):
|
||||
|
@ -217,7 +213,9 @@ if __name__ == "__main__":
|
|||
ui_group = Ui_InstallDialogAdvanced()
|
||||
widget_group = QWidget()
|
||||
ui_group.setupUi(widget_group)
|
||||
collapsible_group = CollapsibleGroupBox(widget_group, title="Group me!")
|
||||
collapsible_group = CollapsibleGroupBox()
|
||||
collapsible_group.setWidget(widget_group)
|
||||
collapsible_group.setTitle("Group me!")
|
||||
collapsible_group.setDisabled(False)
|
||||
|
||||
def replace_func_group(state):
|
||||
|
|
|
@ -11,7 +11,7 @@ from PyQt5.QtWidgets import (
|
|||
QVBoxLayout,
|
||||
QHBoxLayout,
|
||||
QWidget,
|
||||
QLayout, QSpacerItem, QSizePolicy,
|
||||
QLayout, QSpacerItem, QSizePolicy, QLabel,
|
||||
)
|
||||
|
||||
from rare.utils.misc import icon
|
||||
|
@ -74,6 +74,9 @@ class ButtonDialog(BaseDialog):
|
|||
def __init__(self, parent=None):
|
||||
super(ButtonDialog, self).__init__(parent=parent)
|
||||
|
||||
self.subtitle_label = QLabel(self)
|
||||
self.subtitle_label.setVisible(False)
|
||||
|
||||
self.reject_button = QPushButton(self)
|
||||
self.reject_button.setText(self.tr("Cancel"))
|
||||
self.reject_button.setIcon(icon("fa.remove"))
|
||||
|
@ -91,6 +94,7 @@ class ButtonDialog(BaseDialog):
|
|||
self.button_layout.addWidget(self.accept_button)
|
||||
|
||||
self.main_layout = QVBoxLayout(self)
|
||||
self.main_layout.addWidget(self.subtitle_label)
|
||||
# lk: dirty way to set a minimum width with fixed size constraint
|
||||
spacer = QSpacerItem(
|
||||
480, self.main_layout.spacing(),
|
||||
|
@ -103,13 +107,23 @@ class ButtonDialog(BaseDialog):
|
|||
def close(self):
|
||||
raise RuntimeError(f"Don't use `close()` with {type(self).__name__}")
|
||||
|
||||
def setSubtitle(self, text: str):
|
||||
self.subtitle_label.setText(f"<b>{text}</b>")
|
||||
self.subtitle_label.setVisible(True)
|
||||
|
||||
def setCentralWidget(self, widget: QWidget):
|
||||
widget.layout().setContentsMargins(0, 0, 0, 0)
|
||||
self.main_layout.insertWidget(0, widget)
|
||||
self.main_layout.insertWidget(
|
||||
self.main_layout.indexOf(self.subtitle_label) + 1,
|
||||
widget
|
||||
)
|
||||
|
||||
def setCentralLayout(self, layout: QLayout):
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.main_layout.insertLayout(0, layout)
|
||||
self.main_layout.insertLayout(
|
||||
self.main_layout.indexOf(self.subtitle_label) + 1,
|
||||
layout
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def accept_handler(self):
|
||||
|
|
58
rare/widgets/selective_widget.py
Normal file
58
rare/widgets/selective_widget.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
from typing import List, Union
|
||||
|
||||
from PyQt5.QtCore import Qt, pyqtSignal
|
||||
from PyQt5.QtWidgets import QCheckBox, QWidget, QVBoxLayout
|
||||
from legendary.utils.selective_dl import get_sdl_appname
|
||||
|
||||
from rare.models.game import RareGame
|
||||
|
||||
|
||||
class TagCheckBox(QCheckBox):
|
||||
def __init__(self, text, desc, tags: List[str], parent=None):
|
||||
super(TagCheckBox, self).__init__(parent)
|
||||
self.setText(text)
|
||||
self.setToolTip(desc)
|
||||
self.tags = tags
|
||||
|
||||
def isChecked(self) -> Union[bool, List[str]]:
|
||||
return self.tags if super(TagCheckBox, self).isChecked() else False
|
||||
|
||||
|
||||
class SelectiveWidget(QWidget):
|
||||
stateChanged: pyqtSignal = pyqtSignal()
|
||||
|
||||
def __init__(self, rgame: RareGame, platform: str, parent=None):
|
||||
super().__init__(parent=parent)
|
||||
|
||||
main_layout = QVBoxLayout(self)
|
||||
main_layout.setSpacing(0)
|
||||
|
||||
core = rgame.core
|
||||
|
||||
config_tags = core.lgd.config.get(rgame.app_name, "install_tags", fallback=None)
|
||||
config_disable_sdl = core.lgd.config.getboolean(rgame.app_name, "disable_sdl", fallback=False)
|
||||
sdl_name = get_sdl_appname(rgame.app_name)
|
||||
if not config_disable_sdl and sdl_name is not None:
|
||||
sdl_data = core.get_sdl_data(sdl_name, platform=platform)
|
||||
if sdl_data:
|
||||
for tag, info in sdl_data.items():
|
||||
cb = TagCheckBox(info["name"].strip(), info["description"].strip(), info["tags"])
|
||||
if tag == "__required":
|
||||
cb.setChecked(True)
|
||||
cb.setDisabled(True)
|
||||
if config_tags is not None:
|
||||
if all(elem in config_tags for elem in info["tags"]):
|
||||
cb.setChecked(True)
|
||||
cb.stateChanged.connect(self.stateChanged)
|
||||
main_layout.addWidget(cb)
|
||||
self.parent().setDisabled(False)
|
||||
else:
|
||||
self.parent().setDisabled(True)
|
||||
|
||||
def install_tags(self):
|
||||
install_tags = [""]
|
||||
for cb in self.findChildren(TagCheckBox, options=Qt.FindDirectChildrenOnly):
|
||||
if data := cb.isChecked():
|
||||
# noinspection PyTypeChecker
|
||||
install_tags.extend(data)
|
||||
return install_tags
|
|
@ -1,4 +1,4 @@
|
|||
requests
|
||||
requests<3.0
|
||||
QtAwesome
|
||||
setuptools
|
||||
legendary-gl>=0.20.34
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
requests
|
||||
requests<3.0
|
||||
PyQt5
|
||||
QtAwesome
|
||||
setuptools
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
requests
|
||||
requests<3.0
|
||||
PyQt5
|
||||
QtAwesome
|
||||
setuptools
|
||||
legendary-gl>=0.20.34; platform_system != "Windows" or platform_system != "Darwin"
|
||||
legendary-gl @ git+https://github.com/derrod/legendary@96e07ff ; platform_system == "Windows" or platform_system == "Darwin"
|
||||
orjson
|
||||
vdf; platform_system != "Windows"
|
||||
vdf; platform_system == "Linux" or platform_system == "FreeBSD"
|
||||
pywin32; platform_system == "Windows"
|
||||
|
|
Loading…
Reference in a new issue