diff --git a/AppImageBuilder.yml b/AppImageBuilder.yml
index dc20b8e1..eb6cb1e3 100644
--- a/AppImageBuilder.yml
+++ b/AppImageBuilder.yml
@@ -20,7 +20,7 @@ AppDir:
id: io.github.dummerle.rare
name: Rare
icon: Rare
- version: 1.10.7
+ version: 1.10.9
exec: usr/bin/python3
exec_args: $APPDIR/usr/src/rare/main.py $@
apt:
diff --git a/pyproject.toml b/pyproject.toml
index 5d51e960..779fe56c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -12,7 +12,7 @@ force-exclude = '''
[tool.poetry]
name = "rare"
-version = "1.10.7"
+version = "1.10.9"
description = "A GUI for Legendary"
authors = ["Dummerle"]
license = "GPL3"
diff --git a/rare/__init__.py b/rare/__init__.py
index a1e30886..19e12745 100644
--- a/rare/__init__.py
+++ b/rare/__init__.py
@@ -1,4 +1,4 @@
-__version__ = "1.10.7"
+__version__ = "1.10.9"
__codename__ = "Garlic Crab"
# For PyCharm profiler
diff --git a/rare/components/__init__.py b/rare/components/__init__.py
index 8d0e4fd4..684a1133 100644
--- a/rare/components/__init__.py
+++ b/rare/components/__init__.py
@@ -45,8 +45,6 @@ class Rare(RareApp):
self.signals = RareCore.instance().signals()
self.core = RareCore.instance().core()
- config_helper.init_config_handler(self.core)
-
lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang)
diff --git a/rare/components/dialogs/install_dialog.py b/rare/components/dialogs/install_dialog.py
index 52e0aab2..a3042281 100644
--- a/rare/components/dialogs/install_dialog.py
+++ b/rare/components/dialogs/install_dialog.py
@@ -73,13 +73,15 @@ class InstallDialog(QDialog):
self.ui.install_dialog_label.setText(f'
{header} "{self.rgame.app_title}"
')
self.setWindowTitle(f'{header} "{self.rgame.app_title}" - {QCoreApplication.instance().applicationName()}')
- if not self.options.base_path:
- self.options.base_path = self.core.lgd.config.get(
- "Legendary", "install_dir", fallback=os.path.expanduser("~/legendary")
- )
+ if options.base_path:
+ base_path = options.base_path
+ elif rgame.is_installed:
+ base_path = rgame.install_path
+ else:
+ base_path = self.core.get_default_install_dir(rgame.default_platform)
self.install_dir_edit = PathEdit(
- path=self.options.base_path,
+ path=base_path,
file_mode=QFileDialog.DirectoryOnly,
edit_func=self.option_changed,
save_func=self.save_install_edit,
@@ -90,36 +92,24 @@ class InstallDialog(QDialog):
QFormLayout.FieldRole, self.install_dir_edit
)
- if self.options.update:
- self.ui.install_dir_label.setEnabled(False)
- self.install_dir_edit.setEnabled(False)
- self.ui.shortcut_label.setEnabled(False)
- self.ui.shortcut_check.setEnabled(False)
- else:
- self.ui.shortcut_check.setChecked(QSettings().value("create_shortcut", True, bool))
+ self.install_dir_edit.setDisabled(rgame.is_installed)
+ self.ui.install_dir_label.setDisabled(rgame.is_installed)
+ self.ui.shortcut_label.setDisabled(rgame.is_installed)
+ self.ui.shortcut_check.setDisabled(rgame.is_installed)
+ self.ui.shortcut_check.setChecked(not rgame.is_installed and QSettings().value("create_shortcut", True, bool))
self.error_box()
- platforms = self.rgame.platforms
- self.ui.platform_combo.addItems(reversed(platforms))
- self.ui.platform_combo.currentIndexChanged.connect(lambda: self.option_changed(None))
- self.ui.platform_combo.currentIndexChanged.connect(lambda: self.error_box())
- self.ui.platform_combo.currentIndexChanged.connect(
- lambda i: self.error_box(
- self.tr("Warning"),
- self.tr("You will not be able to run the game if you select {} as platform").format(
- self.ui.platform_combo.itemText(i)
- ),
- )
- if (self.ui.platform_combo.currentText() == "Mac" and pf.system() != "Darwin")
- else None
- )
- self.ui.platform_combo.setCurrentIndex(
- self.ui.platform_combo.findText(
- "Mac" if (pf.system() == "Darwin" and "Mac" in platforms) else "Windows"
- )
- )
- self.ui.platform_combo.currentTextChanged.connect(self.setup_sdl_list)
+ 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.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_label.setDisabled(rgame.is_installed)
+ self.ui.platform_combo.setDisabled(rgame.is_installed)
self.advanced.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0))
self.advanced.ui.max_workers_spin.valueChanged.connect(self.option_changed)
@@ -139,7 +129,10 @@ class InstallDialog(QDialog):
self.selectable_checks: List[TagCheckBox] = []
self.config_tags: Optional[List[str]] = None
- self.setup_sdl_list(self.ui.platform_combo.currentText())
+
+ self.reset_install_dir(self.ui.platform_combo.currentIndex())
+ self.reset_sdl_list(self.ui.platform_combo.currentIndex())
+ self.check_incompatible_platform(self.ui.platform_combo.currentIndex())
self.ui.install_button.setEnabled(False)
@@ -155,9 +148,10 @@ class InstallDialog(QDialog):
self.selectable.setEnabled(False)
if pf.system() == "Darwin":
+ self.ui.shortcut_label.setDisabled(True)
self.ui.shortcut_check.setDisabled(True)
self.ui.shortcut_check.setChecked(False)
- self.ui.shortcut_check.setToolTip(self.tr("Creating a shortcut is not supported on MacOS"))
+ self.ui.shortcut_check.setToolTip(self.tr("Creating a shortcut is not supported on macOS"))
self.advanced.ui.install_prereqs_label.setEnabled(False)
self.advanced.ui.install_prereqs_check.setEnabled(False)
@@ -190,8 +184,16 @@ class InstallDialog(QDialog):
self.__on_verify()
self.show()
- @pyqtSlot(str)
- def setup_sdl_list(self, platform="Windows"):
+ @pyqtSlot(int)
+ def reset_install_dir(self, index: int):
+ if not self.rgame.is_installed:
+ platform = self.ui.platform_combo.itemText(index)
+ 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()
@@ -223,8 +225,19 @@ class InstallDialog(QDialog):
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 {} as platform").format(platform)
+ )
+ else:
+ self.error_box()
+
def get_options(self):
- self.options.base_path = self.install_dir_edit.text() if not self.options.update else None
+ self.options.base_path = "" if self.rgame.is_installed else self.install_dir_edit.text()
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()
diff --git a/rare/components/tabs/downloads/__init__.py b/rare/components/tabs/downloads/__init__.py
index 7017ebc3..dfff5865 100644
--- a/rare/components/tabs/downloads/__init__.py
+++ b/rare/components/tabs/downloads/__init__.py
@@ -346,5 +346,5 @@ class DownloadsTab(QWidget):
@pyqtSlot(RareGame, bool, str)
def __on_uninstall_worker_result(self, rgame: RareGame, success: bool, message: str):
if not success:
- QMessageBox.warning(None, self.tr("Uninstall - {}").format(rgame.title), message, QMessageBox.Close)
+ QMessageBox.warning(None, self.tr("Uninstall - {}").format(rgame.app_title), message, QMessageBox.Close)
rgame.state = RareGame.State.IDLE
diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py
index c206b4e3..2cb3876d 100644
--- a/rare/components/tabs/games/__init__.py
+++ b/rare/components/tabs/games/__init__.py
@@ -1,6 +1,7 @@
from logging import getLogger
from PyQt5.QtCore import QSettings, Qt, pyqtSlot
+from PyQt5.QtGui import QShowEvent
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
from rare.models.game import RareGame
@@ -33,8 +34,6 @@ class GamesTab(QStackedWidget):
self.image_manager = ImageManagerSingleton()
self.settings = QSettings()
- self.active_filter: int = 0
-
self.games_page = QWidget(parent=self)
games_page_layout = QVBoxLayout(self.games_page)
self.addWidget(self.games_page)
@@ -69,6 +68,7 @@ class GamesTab(QStackedWidget):
self.icon_view = QWidget(self.icon_view_scroll)
icon_view_layout = LibraryLayout(self.icon_view)
+ icon_view_layout.setSpacing(9)
icon_view_layout.setContentsMargins(0, 13, 0, 13)
icon_view_layout.setAlignment(Qt.AlignTop)
@@ -97,16 +97,20 @@ class GamesTab(QStackedWidget):
self.head_bar.refresh_list.clicked.connect(self.library_controller.update_list)
self.head_bar.view.toggled.connect(self.toggle_view)
- f = self.settings.value("filter", 0, int)
- if f >= len(self.head_bar.available_filters):
- f = 0
- self.active_filter = self.head_bar.available_filters[f]
+ self.active_filter: str = self.head_bar.filter.currentData(Qt.UserRole)
# signals
self.signals.game.installed.connect(self.update_count_games_label)
self.signals.game.uninstalled.connect(self.update_count_games_label)
+ self.init = True
+
+ def showEvent(self, a0: QShowEvent):
+ if a0.spontaneous() or not self.init:
+ return super().showEvent(a0)
self.setup_game_list()
+ self.init = False
+ return super().showEvent(a0)
@pyqtSlot()
def scroll_to_top(self):
@@ -149,7 +153,7 @@ class GamesTab(QStackedWidget):
for rgame in self.rcore.games:
icon_widget, list_widget = self.add_library_widget(rgame)
if not icon_widget or not list_widget:
- logger.warning(f"Excluding {rgame.app_name} from the game list")
+ logger.warning("Excluding %s from the game list", rgame.app_title)
continue
self.icon_view.layout().addWidget(icon_widget)
self.list_view.layout().addWidget(list_widget)
@@ -160,8 +164,7 @@ class GamesTab(QStackedWidget):
try:
icon_widget, list_widget = self.library_controller.add_game(rgame)
except Exception as e:
- raise e
- logger.error(f"{rgame.app_name} is broken. Don't add it to game list: {e}")
+ logger.error("Could not add widget for %s to library: %s", rgame.app_name, e)
return None, None
icon_widget.show_info.connect(self.show_game_info)
list_widget.show_info.connect(self.show_game_info)
diff --git a/rare/components/tabs/games/game_info/cloud_saves.py b/rare/components/tabs/games/game_info/cloud_saves.py
index a39d492b..d9cd9f23 100644
--- a/rare/components/tabs/games/game_info/cloud_saves.py
+++ b/rare/components/tabs/games/game_info/cloud_saves.py
@@ -144,10 +144,10 @@ class CloudSaves(QWidget, SideTabContents):
self.cloud_save_path_edit.setText("")
QMessageBox.warning(
self,
- self.tr("Error - {}").format(self.rgame.title),
+ self.tr("Error - {}").format(self.rgame.app_title),
self.tr(
"Error while calculating path for {}. Insufficient permissions to create {}"
- ).format(self.rgame.title, path),
+ ).format(self.rgame.app_title, path),
)
return
if not path:
@@ -217,7 +217,7 @@ class CloudSaves(QWidget, SideTabContents):
self.rgame = rgame
- self.set_title.emit(rgame.title)
+ self.set_title.emit(rgame.app_title)
rgame.signals.widget.update.connect(self.__update_widget)
self.__update_widget()
diff --git a/rare/components/tabs/games/game_info/game_info.py b/rare/components/tabs/games/game_info/game_info.py
index a6735235..f0507021 100644
--- a/rare/components/tabs/games/game_info/game_info.py
+++ b/rare/components/tabs/games/game_info/game_info.py
@@ -121,7 +121,7 @@ class GameInfo(QWidget, SideTabContents):
if not os.path.exists(repair_file):
QMessageBox.warning(
self,
- self.tr("Error - {}").format(self.rgame.title),
+ self.tr("Error - {}").format(self.rgame.app_title),
self.tr(
"Repair file does not exist or game does not need a repair. Please verify game first"
),
@@ -135,11 +135,11 @@ class GameInfo(QWidget, SideTabContents):
if rgame.has_update:
ans = QMessageBox.question(
self,
- self.tr("Repair and update? - {}").format(self.rgame.title),
+ self.tr("Repair and update? - {}").format(self.rgame.app_title),
self.tr(
"There is an update for {} from {} to {}. "
"Do you want to update the game while repairing it?"
- ).format(rgame.title, rgame.version, rgame.remote_version),
+ ).format(rgame.app_title, rgame.version, rgame.remote_version),
) == QMessageBox.Yes
rgame.repair(repair_and_update=ans)
@@ -147,7 +147,7 @@ class GameInfo(QWidget, SideTabContents):
def __on_worker_error(self, rgame: RareGame, message: str):
QMessageBox.warning(
self,
- self.tr("Error - {}").format(rgame.title),
+ self.tr("Error - {}").format(rgame.app_title),
message
)
@@ -155,11 +155,11 @@ class GameInfo(QWidget, SideTabContents):
def __on_verify(self):
""" This method is to be called from the button only """
if not os.path.exists(self.rgame.igame.install_path):
- logger.error(f"Installation path {self.rgame.igame.install_path} for {self.rgame.title} does not exist")
+ logger.error(f"Installation path {self.rgame.igame.install_path} for {self.rgame.app_title} does not exist")
QMessageBox.warning(
self,
- self.tr("Error - {}").format(self.rgame.title),
- self.tr("Installation path for {} does not exist. Cannot continue.").format(self.rgame.title),
+ self.tr("Error - {}").format(self.rgame.app_title),
+ self.tr("Installation path for {} does not exist. Cannot continue.").format(self.rgame.app_title),
)
return
self.verify_game(self.rgame)
@@ -184,18 +184,18 @@ class GameInfo(QWidget, SideTabContents):
if success:
QMessageBox.information(
self,
- self.tr("Summary - {}").format(rgame.title),
+ self.tr("Summary - {}").format(rgame.app_title),
self.tr("{} has been verified successfully. "
- "No missing or corrupt files found").format(rgame.title),
+ "No missing or corrupt files found").format(rgame.app_title),
)
else:
ans = QMessageBox.question(
self,
- self.tr("Summary - {}").format(rgame.title),
+ self.tr("Summary - {}").format(rgame.app_title),
self.tr(
"{} failed verification, {} file(s) corrupted, {} file(s) are missing. "
"Do you want to repair them?"
- ).format(rgame.title, failed, missing),
+ ).format(rgame.app_title, failed, missing),
QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes,
)
@@ -216,7 +216,7 @@ class GameInfo(QWidget, SideTabContents):
if os.path.basename(self.rgame.install_path) in os.path.basename(item):
ans = QMessageBox.question(
self,
- self.tr("Move game? - {}").format(self.rgame.title),
+ self.tr("Move game? - {}").format(self.rgame.app_title),
self.tr(
"Destination {} already exists. "
"Are you sure you want to overwrite it?"
@@ -255,8 +255,8 @@ class GameInfo(QWidget, SideTabContents):
def __on_move_result(self, rgame: RareGame, dst_path: str):
QMessageBox.information(
self,
- self.tr("Summary - {}").format(rgame.title),
- self.tr("{} successfully moved to {}.").format(rgame.title, dst_path),
+ self.tr("Summary - {}").format(rgame.app_title),
+ self.tr("{} successfully moved to {}.").format(rgame.app_title, dst_path),
)
@pyqtSlot()
@@ -284,7 +284,9 @@ class GameInfo(QWidget, SideTabContents):
)
self.ui.platform.setText(
- self.rgame.igame.platform if self.rgame.is_installed and not self.rgame.is_non_asset else "Windows"
+ self.rgame.igame.platform
+ if self.rgame.is_installed and not self.rgame.is_non_asset
+ else self.rgame.default_platform
)
self.ui.lbl_grade.setDisabled(
diff --git a/rare/components/tabs/games/game_widgets/__init__.py b/rare/components/tabs/games/game_widgets/__init__.py
index b1df4b3d..a5d5b58b 100644
--- a/rare/components/tabs/games/game_widgets/__init__.py
+++ b/rare/components/tabs/games/game_widgets/__init__.py
@@ -38,15 +38,15 @@ class LibraryWidgetController(QObject):
elif "hidden" in widget.rgame.metadata.tags:
visible = False
elif filter_name == "installed":
- visible = widget.rgame.is_installed
+ visible = widget.rgame.is_installed and not widget.rgame.is_unreal
elif filter_name == "offline":
- visible = widget.rgame.can_run_offline
+ visible = widget.rgame.can_run_offline and not widget.rgame.is_unreal
elif filter_name == "32bit":
- visible = widget.rgame.is_win32
+ visible = widget.rgame.is_win32 and not widget.rgame.is_unreal
elif filter_name == "mac":
- visible = widget.rgame.is_mac
+ visible = widget.rgame.is_mac and not widget.rgame.is_unreal
elif filter_name == "installable":
- visible = not widget.rgame.is_non_asset
+ visible = not widget.rgame.is_non_asset and not widget.rgame.is_unreal
elif filter_name == "include_ue":
visible = True
elif filter_name == "all":
diff --git a/rare/components/tabs/games/game_widgets/icon_game_widget.py b/rare/components/tabs/games/game_widgets/icon_game_widget.py
index bf75c4e2..0bdaf07e 100644
--- a/rare/components/tabs/games/game_widgets/icon_game_widget.py
+++ b/rare/components/tabs/games/game_widgets/icon_game_widget.py
@@ -15,7 +15,7 @@ class IconGameWidget(GameWidget):
def __init__(self, rgame: RareGame, parent=None):
super().__init__(rgame, parent)
self.setObjectName(f"{rgame.app_name}")
- self.setFixedSize(ImageSize.Display)
+ self.setFixedSize(ImageSize.Library)
self.ui = IconWidget()
self.ui.setupUi(self)
diff --git a/rare/components/tabs/games/head_bar.py b/rare/components/tabs/games/head_bar.py
index 1178108c..2311d97c 100644
--- a/rare/components/tabs/games/head_bar.py
+++ b/rare/components/tabs/games/head_bar.py
@@ -1,4 +1,6 @@
-from PyQt5.QtCore import QSettings, pyqtSignal, pyqtSlot
+import platform as pf
+
+from PyQt5.QtCore import QSettings, pyqtSignal, pyqtSlot, Qt
from PyQt5.QtWidgets import (
QLabel,
QPushButton,
@@ -22,45 +24,28 @@ class GameListHeadBar(QWidget):
def __init__(self, parent=None):
super(GameListHeadBar, self).__init__(parent=parent)
self.rcore = RareCore.instance()
- self.settings = QSettings()
+ self.settings = QSettings(self)
- self.filter = QComboBox()
- self.filter.addItems(
- [
- self.tr("All games"),
- self.tr("Installed only"),
- self.tr("Offline Games"),
- # self.tr("Hidden")
- ]
- )
-
- self.available_filters = [
- "all",
- "installed",
- "offline",
- # "hidden"
- ]
+ self.filter = QComboBox(self)
+ self.filter.addItem(self.tr("All games"), "all")
+ self.filter.addItem(self.tr("Installed"), "installed")
+ self.filter.addItem(self.tr("Offline"), "offline")
+ # self.filter.addItem(self.tr("Hidden"), "hidden")
if self.rcore.bit32_games:
- self.filter.addItem(self.tr("32 Bit Games"))
- self.available_filters.append("32bit")
-
+ self.filter.addItem(self.tr("32bit games"), "32bit")
if self.rcore.mac_games:
- self.filter.addItem(self.tr("Mac games"))
- self.available_filters.append("mac")
-
+ self.filter.addItem(self.tr("macOS games"), "mac")
if self.rcore.origin_games:
- self.filter.addItem(self.tr("Exclude Origin"))
- self.available_filters.append("installable")
-
- self.filter.addItem(self.tr("Include Unreal Engine"))
- self.available_filters.append("include_ue")
+ self.filter.addItem(self.tr("Exclude Origin"), "installable")
+ self.filter.addItem(self.tr("Include Unreal"), "include_ue")
+ filter_default = "mac" if pf.system() == "Darwin" else "all"
+ filter_index = i if (i := self.filter.findData(filter_default, Qt.UserRole)) >= 0 else 0
try:
- self.filter.setCurrentIndex(self.settings.value("filter", 0, int))
+ self.filter.setCurrentIndex(self.settings.value("library_filter", filter_index, int))
except TypeError:
- self.settings.setValue("filter", 0)
- self.filter.setCurrentIndex(0)
-
+ self.settings.setValue("library_filter", filter_index)
+ self.filter.setCurrentIndex(filter_index)
self.filter.currentIndexChanged.connect(self.filter_changed)
integrations_menu = QMenu(self)
@@ -139,6 +124,6 @@ class GameListHeadBar(QWidget):
self.rcore.fetch()
@pyqtSlot(int)
- def filter_changed(self, i: int):
- self.filterChanged.emit(self.available_filters[i])
- self.settings.setValue("filter", i)
+ def filter_changed(self, index: int):
+ self.filterChanged.emit(self.filter.itemData(index, Qt.UserRole))
+ self.settings.setValue("library_filter", index)
diff --git a/rare/components/tabs/games/integrations/eos_group.py b/rare/components/tabs/games/integrations/eos_group.py
index 784d4ae4..174f34aa 100644
--- a/rare/components/tabs/games/integrations/eos_group.py
+++ b/rare/components/tabs/games/integrations/eos_group.py
@@ -213,9 +213,7 @@ class EOSGroup(QGroupBox, Ui_EosWidget):
self.enabled_cb.setChecked(enabled)
def install_overlay(self, update=False):
- base_path = os.path.join(
- self.core.lgd.config.get("Legendary", "install_dir", fallback=os.path.expanduser("~/legendary")),".overlay"
- )
+ base_path = os.path.join(self.core.get_default_install_dir(), ".overlay")
if update:
if not self.overlay:
self.overlay_stack.setCurrentIndex(1)
diff --git a/rare/components/tabs/games/integrations/import_group.py b/rare/components/tabs/games/integrations/import_group.py
index 24e05dff..f61f96d3 100644
--- a/rare/components/tabs/games/integrations/import_group.py
+++ b/rare/components/tabs/games/integrations/import_group.py
@@ -72,8 +72,10 @@ class ImportWorker(QRunnable):
def __init__(
self,
- core: LegendaryCore, path: str,
+ core: LegendaryCore,
+ path: str,
app_name: str = None,
+ platform: Optional[str] = None,
import_folder: bool = False,
import_dlcs: bool = False,
import_force: bool = False
@@ -86,6 +88,7 @@ class ImportWorker(QRunnable):
self.path = Path(path)
self.app_name = app_name
self.import_folder = import_folder
+ self.platform = platform if platform is not None else self.core.default_platform
self.import_dlcs = import_dlcs
self.import_force = import_force
@@ -110,9 +113,13 @@ class ImportWorker(QRunnable):
result = ImportedGame(ImportResult.ERROR)
result.path = str(path)
if app_name or (app_name := find_app_name(str(path), self.core)):
+ game = self.core.get_game(app_name)
result.app_name = app_name
- result.app_title = app_title = self.core.get_game(app_name).app_title
- success, message = self.__import_game(path, app_name, app_title)
+ result.app_title = game.app_title
+ platform = self.platform
+ if platform not in self.core.get_game(app_name, update_meta=False).asset_infos:
+ platform = "Windows"
+ success, message = self.__import_game(path, app_name, platform)
if not success:
result.result = ImportResult.FAILED
result.message = message
@@ -120,12 +127,13 @@ class ImportWorker(QRunnable):
result.result = ImportResult.SUCCESS
return result
- def __import_game(self, path: Path, app_name: str, app_title: str):
+ def __import_game(self, path: Path, app_name: str, platform: str):
cli = LegendaryCLI(self.core)
status = LgndrIndirectStatus()
args = LgndrImportGameArgs(
app_path=str(path),
app_name=app_name,
+ platform=platform,
disable_check=self.import_force,
skip_dlcs=not self.import_dlcs,
with_dlcs=self.import_dlcs,
@@ -192,7 +200,7 @@ class ImportGroup(QGroupBox):
self.__install_dirs: Set[str] = set()
self.path_edit = PathEdit(
- self.core.get_default_install_dir(),
+ self.core.get_default_install_dir(self.core.default_platform),
QFileDialog.DirectoryOnly,
edit_func=self.path_edit_callback,
parent=self,
@@ -206,6 +214,7 @@ class ImportGroup(QGroupBox):
self.app_name_edit = IndicatorLineEdit(
placeholder=self.tr("Use in case the app name was not found automatically"),
edit_func=self.app_name_edit_callback,
+ save_func=self.app_name_save_callback,
parent=self,
)
self.app_name_edit.textChanged.connect(self.app_name_changed)
@@ -247,8 +256,10 @@ class ImportGroup(QGroupBox):
def set_game(self, app_name: str):
if app_name:
- folder = self.rcore.get_game(app_name).folder_name
- self.path_edit.setText(os.path.join(self.core.get_default_install_dir(), folder))
+ rgame = self.rcore.get_game(app_name)
+ self.path_edit.setText(
+ os.path.join(self.core.get_default_install_dir(rgame.default_platform), rgame.folder_name)
+ )
self.app_name_edit.setText(app_name)
def path_edit_callback(self, path) -> Tuple[bool, str, int]:
@@ -279,6 +290,12 @@ class ImportGroup(QGroupBox):
else:
return False, text, IndicatorReasonsCommon.NOT_INSTALLED
+ def app_name_save_callback(self, text) -> None:
+ rgame = self.rcore.get_game(text)
+ self.ui.platform_combo.clear()
+ self.ui.platform_combo.addItems(rgame.platforms)
+ self.ui.platform_combo.setCurrentText(rgame.default_platform)
+
@pyqtSlot(str)
def app_name_changed(self, app_name: str):
self.info_label.setText("")
@@ -294,6 +311,14 @@ class ImportGroup(QGroupBox):
@pyqtSlot(int)
def import_folder_changed(self, state: Qt.CheckState):
self.app_name_edit.setEnabled(not state)
+ self.ui.platform_combo.setEnabled(not state)
+ self.ui.platform_combo.setToolTip(
+ self.tr(
+ "When importing multiple games, the current OS will be used at the"
+ " platform for the games that support it, otherwise the Windows version"
+ " will be imported."
+ ) if state else ""
+ )
self.ui.import_dlcs_check.setCheckState(Qt.Unchecked)
self.ui.import_force_check.setCheckState(Qt.Unchecked)
self.ui.import_dlcs_check.setEnabled(
@@ -322,10 +347,11 @@ class ImportGroup(QGroupBox):
self.worker = ImportWorker(
self.core,
path,
- self.app_name_edit.text(),
- self.ui.import_folder_check.isChecked(),
- self.ui.import_dlcs_check.isChecked(),
- self.ui.import_force_check.isChecked()
+ app_name=self.app_name_edit.text(),
+ platform=self.ui.platform_combo.currentText() if not self.ui.import_folder_check.isChecked() else None,
+ import_folder=self.ui.import_folder_check.isChecked(),
+ import_dlcs=self.ui.import_dlcs_check.isChecked(),
+ import_force=self.ui.import_force_check.isChecked()
)
self.worker.signals.progress.connect(self.__on_import_progress)
self.worker.signals.result.connect(self.__on_import_result)
diff --git a/rare/components/tabs/games/integrations/ubisoft_group.py b/rare/components/tabs/games/integrations/ubisoft_group.py
index eddd303d..008912be 100644
--- a/rare/components/tabs/games/integrations/ubisoft_group.py
+++ b/rare/components/tabs/games/integrations/ubisoft_group.py
@@ -74,7 +74,6 @@ class UbiConnectWorker(Worker):
def __init__(self, core: LegendaryCore, ubi_account_id, partner_link_id):
super(UbiConnectWorker, self).__init__()
self.signals = UbiConnectWorker.Signals()
- self.setAutoDelete(True)
self.core = core
self.ubi_account_id = ubi_account_id
self.partner_link_id = partner_link_id
diff --git a/rare/components/tabs/settings/game_settings.py b/rare/components/tabs/settings/game_settings.py
index 201f5fee..d52dd79f 100644
--- a/rare/components/tabs/settings/game_settings.py
+++ b/rare/components/tabs/settings/game_settings.py
@@ -40,8 +40,10 @@ class DefaultGameSettings(QWidget):
if platform.system() != "Windows":
self.linux_settings = LinuxAppSettings()
- self.proton_settings = ProtonSettings(self.linux_settings, self.wrapper_settings)
- self.ui.proton_layout.addWidget(self.proton_settings)
+ if platform.system() != "Darwin":
+ self.proton_settings = ProtonSettings(self.linux_settings, self.wrapper_settings)
+ self.ui.proton_layout.addWidget(self.proton_settings)
+ self.proton_settings.environ_changed.connect(self.env_vars.reset_model)
# FIXME: Remove the spacerItem and margins from the linux settings
# FIXME: This should be handled differently at soem point in the future
@@ -57,8 +59,6 @@ class DefaultGameSettings(QWidget):
lambda active: self.wrapper_settings.add_wrapper("mangohud")
if active else self.wrapper_settings.delete_wrapper("mangohud"))
self.linux_settings.environ_changed.connect(self.env_vars.reset_model)
- self.proton_settings.environ_changed.connect(self.env_vars.reset_model)
-
else:
self.ui.linux_settings_widget.setVisible(False)
@@ -77,7 +77,10 @@ class DefaultGameSettings(QWidget):
proton = self.wrapper_settings.wrappers.get("proton", "")
if proton:
proton = proton.text
- self.proton_settings.load_settings(app_name, proton)
+ if platform.system() != "Darwin":
+ self.proton_settings.load_settings(app_name, proton)
+ else:
+ proton = ""
if proton:
self.linux_settings.ui.wine_groupbox.setEnabled(False)
else:
diff --git a/rare/components/tabs/settings/legendary.py b/rare/components/tabs/settings/legendary.py
index ec132120..c4254608 100644
--- a/rare/components/tabs/settings/legendary.py
+++ b/rare/components/tabs/settings/legendary.py
@@ -1,7 +1,7 @@
-import platform
+import platform as pf
import re
from logging import getLogger
-from typing import Tuple
+from typing import Tuple, List
from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSettings
from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox
@@ -19,14 +19,21 @@ class RefreshGameMetaWorker(Worker):
class Signals(QObject):
finished = pyqtSignal()
- def __init__(self):
+ def __init__(self, platforms: List[str], include_unreal: bool):
super(RefreshGameMetaWorker, self).__init__()
self.signals = RefreshGameMetaWorker.Signals()
- self.setAutoDelete(True)
self.core = LegendaryCoreSingleton()
+ if platforms:
+ self.platforms = platforms
+ else:
+ self.platforms = ["Windows"]
+ self.skip_ue = not include_unreal
def run_real(self) -> None:
- self.core.get_game_and_dlc_list(True, force_refresh=True)
+ for platform in self.platforms:
+ self.core.get_game_and_dlc_list(
+ True, platform=platform, force_refresh=True, skip_ue=self.skip_ue
+ )
self.signals.finished.emit()
@@ -34,15 +41,26 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
def __init__(self, parent=None):
super(LegendarySettings, self).__init__(parent=parent)
self.setupUi(self)
- self.settings = QSettings()
+ self.settings = QSettings(self)
self.core = LegendaryCoreSingleton()
- # Default installation directory
+ # Platform specific installation directory for macOS games
+ if pf.system() == "Darwin":
+ self.mac_install_dir = PathEdit(
+ self.core.get_default_install_dir("Mac"),
+ placeholder=self.tr("Default installation folder for macOS games"),
+ file_mode=QFileDialog.DirectoryOnly,
+ save_func=self.__mac_path_save,
+ )
+ self.install_dir_layout.addWidget(self.mac_install_dir)
+
+ # Platform-independent installation directory
self.install_dir = PathEdit(
self.core.get_default_install_dir(),
+ placeholder=self.tr("Default installation folder for Windows games"),
file_mode=QFileDialog.DirectoryOnly,
- save_func=self.path_save,
+ save_func=self.__win_path_save,
)
self.install_dir_layout.addWidget(self.install_dir)
@@ -82,20 +100,36 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
)
self.locale_layout.addWidget(self.locale_edit)
- self.win32_cb.setChecked(self.settings.value("win32_meta", False, bool))
- self.win32_cb.stateChanged.connect(lambda: self.settings.setValue("win32_meta", self.win32_cb.isChecked()))
+ self.fetch_win32_check.setChecked(self.settings.value("win32_meta", False, bool))
+ self.fetch_win32_check.stateChanged.connect(
+ lambda: self.settings.setValue("win32_meta", self.fetch_win32_check.isChecked())
+ )
- self.mac_cb.setChecked(self.settings.value("mac_meta", platform.system() == "Darwin", bool))
- self.mac_cb.stateChanged.connect(lambda: self.settings.setValue("mac_meta", self.mac_cb.isChecked()))
+ self.fetch_macos_check.setChecked(self.settings.value("macos_meta", pf.system() == "Darwin", bool))
+ self.fetch_macos_check.stateChanged.connect(
+ lambda: self.settings.setValue("macos_meta", self.fetch_macos_check.isChecked())
+ )
+ self.fetch_macos_check.setDisabled(pf.system() == "Darwin")
- self.refresh_game_meta_btn.clicked.connect(self.refresh_game_meta)
+ self.fetch_unreal_check.setChecked(self.settings.value("unreal_meta", False, bool))
+ self.fetch_unreal_check.stateChanged.connect(
+ lambda: self.settings.setValue("unreal_meta", self.fetch_unreal_check.isChecked())
+ )
- def refresh_game_meta(self):
- self.refresh_game_meta_btn.setDisabled(True)
- self.refresh_game_meta_btn.setText(self.tr("Loading"))
- worker = RefreshGameMetaWorker()
- worker.signals.finished.connect(lambda: self.refresh_game_meta_btn.setDisabled(False))
- worker.signals.finished.connect(lambda: self.refresh_game_meta_btn.setText(self.tr("Refresh game meta")))
+ 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)
+ self.refresh_metadata_button.setVisible(False)
+
+ def refresh_metadata(self):
+ self.refresh_metadata_button.setDisabled(True)
+ platforms = []
+ if self.fetch_win32_check.isChecked():
+ platforms.append("Win32")
+ if self.fetch_macos_check.isChecked():
+ platforms.append("Mac")
+ worker = RefreshGameMetaWorker(platforms, self.fetch_unreal_check.isChecked())
+ worker.signals.finished.connect(lambda: self.refresh_metadata_button.setDisabled(False))
QThreadPool.globalInstance().start(worker)
@staticmethod
@@ -120,12 +154,20 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
self.core.lgd.config.remove_option("Legendary", "locale")
self.core.lgd.save_config()
- def path_save(self, text: str):
- self.core.lgd.config["Legendary"]["install_dir"] = text
- if not text and "install_dir" in self.core.lgd.config["Legendary"].keys():
- self.core.lgd.config["Legendary"].pop("install_dir")
+ def __mac_path_save(self, text: str) -> None:
+ self.__path_save(text, "mac_install_dir")
+
+ def __win_path_save(self, text: str) -> None:
+ self.__path_save(text, "install_dir")
+ if pf.system() != "Darwin":
+ self.__mac_path_save(text)
+
+ def __path_save(self, text: str, option: str = "Windows"):
+ self.core.lgd.config["Legendary"][option] = text
+ if not text and option in self.core.lgd.config["Legendary"].keys():
+ self.core.lgd.config["Legendary"].pop(option)
else:
- logger.debug(f"Set config install_dir to {text}")
+ logger.debug(f"Set %s option in config to %s", option, text)
self.core.lgd.save_config()
def max_worker_save(self, workers: str):
diff --git a/rare/components/tabs/settings/rare.py b/rare/components/tabs/settings/rare.py
index 25b8c447..1c42040a 100644
--- a/rare/components/tabs/settings/rare.py
+++ b/rare/components/tabs/settings/rare.py
@@ -82,8 +82,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.style_select.setCurrentIndex(0)
self.style_select.currentIndexChanged.connect(self.on_style_select_changed)
- self.interface_info.setVisible(False)
-
self.rpc = RPCSettings(self)
self.right_layout.insertWidget(1, self.rpc, alignment=Qt.AlignTop)
@@ -203,7 +201,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.settings.setValue("color_scheme", "")
self.style_select.setDisabled(False)
set_color_pallete("")
- self.interface_info.setVisible(True)
def on_style_select_changed(self, style):
if style:
@@ -215,7 +212,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.settings.setValue("style_sheet", "")
self.color_select.setDisabled(False)
set_style_sheet("")
- self.interface_info.setVisible(True)
def open_dir(self):
if platform.system() == "Windows":
@@ -230,7 +226,6 @@ class RareSettings(QWidget, Ui_RareSettings):
def update_lang(self, i: int):
self.settings.setValue("language", languages[i][0])
- self.interface_info.setVisible(True)
def init_checkboxes(self, checkboxes):
for cb in checkboxes:
diff --git a/rare/lgndr/cli.py b/rare/lgndr/cli.py
index 9261bcb8..d0a4e8d2 100644
--- a/rare/lgndr/cli.py
+++ b/rare/lgndr/cli.py
@@ -43,9 +43,9 @@ class LegendaryCLI(LegendaryCLIReal):
def unlock_installed(func):
@functools.wraps(func)
def unlock(self, *args, **kwargs):
- self.logger.debug("Using unlock decorator")
+ self.logger.debug("%s: Using unlock decorator", func.__name__)
if not self.core.lgd.lock_installed():
- self.logger.info("Data is locked, trying to forcufully release it")
+ self.logger.info("Data is locked, trying to forcefully release it")
# self.core.lgd._installed_lock.release(force=True)
try:
ret = func(self, *args, **kwargs)
diff --git a/rare/lgndr/core.py b/rare/lgndr/core.py
index aee89a78..15ac8f53 100644
--- a/rare/lgndr/core.py
+++ b/rare/lgndr/core.py
@@ -3,6 +3,7 @@ import json
import logging
import os
from multiprocessing import Queue
+from sys import platform as sys_platform
from uuid import uuid4
# On Windows the monkeypatching of `run_real` below doesn't work like on Linux
@@ -17,8 +18,8 @@ from legendary.models.game import Game, InstalledGame
from legendary.models.manifest import ManifestMeta
from rare.lgndr.downloader.mp.manager import DLManager
-from rare.lgndr.lfs.lgndry import LGDLFS
from rare.lgndr.glue.exception import LgndrException, LgndrLogHandler
+from rare.lgndr.lfs.lgndry import LGDLFS
legendary.core.DLManager = DLManager
legendary.core.LGDLFS = LGDLFS
@@ -30,6 +31,7 @@ class LegendaryCore(LegendaryCoreReal):
def __init__(self, *args, **kwargs):
super(LegendaryCore, self).__init__(*args, **kwargs)
self.log.info("Using Rare's LegendaryCore monkey")
+ self.log.info("Using config in %s", self.lgd.path.replace(os.getlogin(), ""))
self.handler = LgndrLogHandler(logging.CRITICAL)
self.log.addHandler(self.handler)
@@ -37,9 +39,9 @@ class LegendaryCore(LegendaryCoreReal):
def unlock_installed(func):
@functools.wraps(func)
def unlock(self, *args, **kwargs):
- self.log.debug("Using unlock decorator")
+ self.log.debug("%s: Using unlock decorator", func.__name__)
if not self.lgd.lock_installed():
- self.log.info("Data is locked, trying to forcufully release it")
+ self.log.info("Data is locked, trying to forcefully release it")
# self.lgd._installed_lock.release(force=True)
try:
ret = func(self, *args, **kwargs)
@@ -50,6 +52,18 @@ class LegendaryCore(LegendaryCoreReal):
return ret
return unlock
+ @property
+ def default_platform(self) -> str:
+ os_default = "Mac" if sys_platform == "darwin" else "Windows"
+ usr_platform = self.lgd.config.get("Legendary", "default_platform", fallback=os_default)
+ return usr_platform if usr_platform in ("Windows", "Win32", "Mac") else os_default
+
+ def update_check_enabled(self):
+ return False
+
+ def update_notice_enabled(self):
+ return False
+
# skip_sync defaults to false but since Rare is persistent, skip by default
# def get_installed_game(self, app_name, skip_sync=True) -> InstalledGame:
# return super(LegendaryCore, self).get_installed_game(app_name, skip_sync)
diff --git a/rare/main.py b/rare/main.py
index 54c2d661..5bf89d58 100755
--- a/rare/main.py
+++ b/rare/main.py
@@ -18,6 +18,8 @@ def main() -> int:
sys.stderr = open(os.devnull, 'w')
os.environ["QT_QPA_PLATFORMTHEME"] = ""
+ if "LEGENDARY_CONFIG_PATH" in os.environ:
+ os.environ["LEGENDARY_CONFIG_PATH"] = os.path.expanduser(os.environ["LEGENDARY_CONFIG_PATH"])
# fix cx_freeze
multiprocessing.freeze_support()
diff --git a/rare/models/base_game.py b/rare/models/base_game.py
index 8137fcf5..0a1ee7ab 100644
--- a/rare/models/base_game.py
+++ b/rare/models/base_game.py
@@ -97,15 +97,11 @@ class RareGameBase(QObject):
@property
def app_name(self) -> str:
- return self.igame.app_name if self.igame is not None else self.game.app_name
+ return self.game.app_name
@property
def app_title(self) -> str:
- return self.igame.title if self.igame is not None else self.game.app_title
-
- @property
- def title(self) -> str:
- return self.app_title
+ return self.game.app_title
@property
@abstractmethod
@@ -125,6 +121,10 @@ class RareGameBase(QObject):
"""
return tuple(self.game.asset_infos.keys())
+ @property
+ def default_platform(self) -> str:
+ return self.core.default_platform if self.core.default_platform in self.platforms else "Windows"
+
@property
def is_mac(self) -> bool:
"""!
@@ -173,7 +173,7 @@ class RareGameBase(QObject):
@return str The current version of the game
"""
- return self.igame.version if self.igame is not None else self.game.app_version()
+ return self.igame.version if self.igame is not None else self.game.app_version(self.default_platform)
@property
def install_path(self) -> Optional[str]:
@@ -234,7 +234,7 @@ class RareGameSlim(RareGameBase):
status, (dt_local, dt_remote) = self.save_game_state
def _upload():
- logger.info(f"Uploading save for {self.title}")
+ logger.info(f"Uploading save for {self.app_title}")
self.state = RareGameSlim.State.SYNCING
self.core.upload_save(self.app_name, self.igame.save_path, dt_local)
self.state = RareGameSlim.State.IDLE
@@ -246,7 +246,7 @@ class RareGameSlim(RareGameBase):
logger.warning("Can't upload non existing save")
return
if self.state == RareGameSlim.State.SYNCING:
- logger.error(f"{self.title} is already syncing")
+ logger.error(f"{self.app_title} is already syncing")
return
if thread:
@@ -259,7 +259,7 @@ class RareGameSlim(RareGameBase):
status, (dt_local, dt_remote) = self.save_game_state
def _download():
- logger.info(f"Downloading save for {self.title}")
+ logger.info(f"Downloading save for {self.app_title}")
self.state = RareGameSlim.State.SYNCING
self.core.download_saves(self.app_name, self.latest_save.file.manifest_name, self.save_path)
self.state = RareGameSlim.State.IDLE
@@ -271,7 +271,7 @@ class RareGameSlim(RareGameBase):
logger.error("Can't download non existing save")
return
if self.state == RareGameSlim.State.SYNCING:
- logger.error(f"{self.title} is already syncing")
+ logger.error(f"{self.app_title} is already syncing")
return
if thread:
diff --git a/rare/models/game.py b/rare/models/game.py
index 3d54eeef..e3b19044 100644
--- a/rare/models/game.py
+++ b/rare/models/game.py
@@ -166,7 +166,8 @@ class RareGame(RareGameSlim):
def update_game(self):
self.game = self.core.get_game(
- self.app_name, update_meta=False, platform=self.igame.platform if self.igame else "Windows"
+ self.app_name, update_meta=False,
+ platform=self.igame.platform if self.igame else self.default_platform
)
def update_igame(self):
@@ -228,7 +229,7 @@ class RareGame(RareGameSlim):
if self.igame is not None:
return self.game.app_version(self.igame.platform)
else:
- return self.game.app_version()
+ return self.game.app_version(self.default_platform)
@property
def has_update(self) -> bool:
diff --git a/rare/models/image.py b/rare/models/image.py
index 6202f5d6..68a87c9e 100644
--- a/rare/models/image.py
+++ b/rare/models/image.py
@@ -70,15 +70,15 @@ class ImageSize:
DisplayWide = Preset(1, 1, Orientation.Wide, base=ImageWide)
"""! @brief Size and pixel ratio for wide 16/9 image display"""
- Wide = DisplayWide
+ LibraryWide = Preset(1.21, 1, Orientation.Wide, base=ImageWide)
- Normal = Display
+ Library = Preset(1.21, 1, base=Image)
"""! @brief Same as Display"""
Small = Preset(3, 1, base=Image)
"""! @brief Small image size for displaying"""
- SmallWide = Preset(1, 1, Orientation.Wide, base=ImageWide)
+ SmallWide = Preset(3, 1, Orientation.Wide, base=ImageWide)
"""! @brief Small image size for displaying"""
Smaller = Preset(4, 1, base=Image)
diff --git a/rare/shared/rare_core.py b/rare/shared/rare_core.py
index abc68247..5b7301af 100644
--- a/rare/shared/rare_core.py
+++ b/rare/shared/rare_core.py
@@ -4,7 +4,7 @@ import time
from argparse import Namespace
from itertools import chain
from logging import getLogger
-from typing import Dict, Iterator, Callable, Optional, List, Union, Iterable, Tuple
+from typing import Dict, Iterator, Callable, Optional, List, Union, Iterable, Tuple, Set
from PyQt5.QtCore import QObject, pyqtSignal, QSettings, pyqtSlot, QThreadPool, QRunnable, QTimer
from legendary.lfs.eos import EOSOverlayApp
@@ -25,6 +25,7 @@ from .workers import (
)
from .workers.uninstall import uninstall_game
from .workers.worker import QueueWorkerInfo, QueueWorkerState
+from rare.utils import config_helper
logger = getLogger("RareCore")
@@ -54,9 +55,10 @@ class RareCore(QObject):
self.args(args)
self.signals(init=True)
self.core(init=True)
+ config_helper.init_config_handler(self.__core)
self.image_manager(init=True)
- self.settings = QSettings()
+ self.settings = QSettings(self)
self.queue_workers: List[QueueWorker] = []
self.queue_threadpool = QThreadPool()
@@ -129,17 +131,44 @@ class RareCore(QObject):
try:
self.__core = LegendaryCore()
except configparser.MissingSectionHeaderError as e:
- logger.warning(f"Config is corrupt: {e}")
- if config_path := os.environ.get("XDG_CONFIG_HOME"):
- path = os.path.join(config_path, "legendary")
+ logger.warning("Config is corrupt: %s", e)
+ if config_path := os.environ.get('LEGENDARY_CONFIG_PATH'):
+ path = config_path
+ elif config_path := os.environ.get('XDG_CONFIG_HOME'):
+ path = os.path.join(config_path, 'legendary')
else:
- path = os.path.expanduser("~/.config/legendary")
+ path = os.path.expanduser('~/.config/legendary')
+ logger.info("Creating config in path: %s", config_path)
with open(os.path.join(path, "config.ini"), "w") as config_file:
config_file.write("[Legendary]")
self.__core = LegendaryCore()
+
+ # Initialize sections if they don't exist
for section in ["Legendary", "default", "default.env"]:
if section not in self.__core.lgd.config.sections():
self.__core.lgd.config.add_section(section)
+
+ # Set some platform defaults if unset
+ def check_config(option: str, accepted: Set = None) -> bool:
+ _exists = self.__core.lgd.config.has_option("Legendary", option)
+ _value = self.__core.lgd.config.get("Legendary", option, fallback="")
+ _accepted = _value in accepted if accepted is not None else True
+ return _exists and bool(_value) and _accepted
+
+ if not check_config("default_platform", {"Windows", "Win32", "Mac"}):
+ self.__core.lgd.config.set("Legendary", "default_platform", self.__core.default_platform)
+ if not check_config("install_dir"):
+ self.__core.lgd.config.set(
+ "Legendary", "install_dir", self.__core.get_default_install_dir()
+ )
+ if not check_config("mac_install_dir"):
+ self.__core.lgd.config.set(
+ "Legendary", "mac_install_dir", self.__core.get_default_install_dir(self.__core.default_platform)
+ )
+ # Always set these options
+ # Avoid falling back to Windows games on macOS
+ self.__core.lgd.config.set("Legendary", "install_platform_fallback", 'false')
+
# workaround if egl sync enabled, but no programdata_path
# programdata_path might be unset if logging in through the browser
if self.__core.egl_sync_enabled:
@@ -148,6 +177,7 @@ class RareCore(QObject):
else:
if not os.path.exists(self.__core.egl.programdata_path):
self.__core.lgd.config.remove_option("Legendary", "egl_sync")
+
self.__core.lgd.save_config()
return self.__core
@@ -176,7 +206,9 @@ class RareCore(QObject):
del self.__args
self.__args = None
- del self.__eos_overlay
+ # del self.__eos_overlay
+ self.__eos_overlay = None
+
RareCore.__instance = None
super(RareCore, self).deleteLater()
@@ -357,7 +389,7 @@ class RareCore(QObject):
yield game.game
@property
- def dlcs(self) -> Dict[str, Game]:
+ def dlcs(self) -> Dict[str, set[RareGame]]:
"""!
RareGames that ARE DLCs themselves
"""
diff --git a/rare/shared/workers/fetch.py b/rare/shared/workers/fetch.py
index 701e1890..b18ea83f 100644
--- a/rare/shared/workers/fetch.py
+++ b/rare/shared/workers/fetch.py
@@ -1,9 +1,10 @@
+import platform
import time
from argparse import Namespace
from enum import IntEnum
from logging import getLogger
-from PyQt5.QtCore import QObject, pyqtSignal
+from PyQt5.QtCore import QObject, pyqtSignal, QSettings
from requests.exceptions import ConnectionError, HTTPError
from rare.lgndr.core import LegendaryCore
@@ -27,19 +28,54 @@ class FetchWorker(Worker):
self.signals = FetchWorker.Signals()
self.core = core
self.args = args
+ self.settings = QSettings()
def run_real(self):
# Fetch regular EGL games with assets
- self.signals.progress.emit(0, self.signals.tr("Updating game metadata"))
start_time = time.time()
+
+ 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])
+
+ if want_win32 or self.args.debug:
+ logger.info(
+ "Requesting Win32 metadata due to %s, %s Unreal engine",
+ "settings" if want_win32 else "debug",
+ "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
+ )
+
+ if need_macos or want_macos or self.args.debug:
+ logger.info(
+ "Requesting macOS metadata due to %s, %s Unreal engine",
+ "platform" if need_macos else "settings" if want_macos else "debug",
+ "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
+ )
+
+ if need_windows:
+ self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
+ logger.info(
+ "Requesting Windows metadata, %s Unreal engine",
+ "with" if want_unreal else "without"
+ )
games, dlc_dict = self.core.get_game_and_dlc_list(
- update_assets=not self.args.offline, platform="Windows", skip_ue=False
+ 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")
# Fetch non-asset games
- self.signals.progress.emit(10, self.signals.tr("Updating non-asset metadata"))
+ 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)
diff --git a/rare/shared/workers/wine_resolver.py b/rare/shared/workers/wine_resolver.py
index 563e78b3..fe63ea4e 100644
--- a/rare/shared/workers/wine_resolver.py
+++ b/rare/shared/workers/wine_resolver.py
@@ -104,17 +104,17 @@ class OriginWineWorker(QRunnable):
if install_dir:
logger.debug("Found Unix install directory %s", install_dir)
else:
- logger.info("Could not find Unix install directory for %s", rgame.title)
+ logger.info("Could not find Unix install directory for %s", rgame.app_title)
else:
- logger.info("Could not find Wine install directory for %s", rgame.title)
+ logger.info("Could not find Wine install directory for %s", rgame.app_title)
if install_dir:
if os.path.isdir(install_dir):
install_size = path_size(install_dir)
rgame.set_origin_attributes(install_dir, install_size)
- logger.info("Origin game %s (%s, %s)", rgame.title, install_dir, format_size(install_size))
+ logger.info("Origin game %s (%s, %s)", rgame.app_title, install_dir, format_size(install_size))
else:
- logger.warning("Origin game %s (%s does not exist)", rgame.title, install_dir)
+ logger.warning("Origin game %s (%s does not exist)", rgame.app_title, install_dir)
else:
- logger.info("Origin game %s is not installed", rgame.title)
+ logger.info("Origin game %s is not installed", rgame.app_title)
logger.info("Origin worker finished in %ss", time.time() - t)
diff --git a/rare/ui/components/tabs/games/integrations/import_group.py b/rare/ui/components/tabs/games/integrations/import_group.py
index cc28fda1..ccd97153 100644
--- a/rare/ui/components/tabs/games/integrations/import_group.py
+++ b/rare/ui/components/tabs/games/integrations/import_group.py
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ImportGroup(object):
def setupUi(self, ImportGroup):
ImportGroup.setObjectName("ImportGroup")
- ImportGroup.resize(506, 184)
+ ImportGroup.resize(651, 218)
ImportGroup.setWindowTitle("ImportGroup")
ImportGroup.setWindowFilePath("")
self.import_layout = QtWidgets.QFormLayout(ImportGroup)
@@ -28,26 +28,35 @@ class Ui_ImportGroup(object):
self.import_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label)
self.import_folder_label = QtWidgets.QLabel(ImportGroup)
self.import_folder_label.setObjectName("import_folder_label")
- self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.import_folder_label)
+ self.import_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.import_folder_label)
self.import_folder_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
self.import_folder_check.setFont(font)
self.import_folder_check.setObjectName("import_folder_check")
- self.import_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.import_folder_check)
+ self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.import_folder_check)
self.import_dlcs_label = QtWidgets.QLabel(ImportGroup)
self.import_dlcs_label.setObjectName("import_dlcs_label")
- self.import_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.import_dlcs_label)
+ self.import_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.import_dlcs_label)
self.import_dlcs_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
self.import_dlcs_check.setFont(font)
self.import_dlcs_check.setObjectName("import_dlcs_check")
- self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.import_dlcs_check)
+ self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_dlcs_check)
+ self.import_force_label = QtWidgets.QLabel(ImportGroup)
+ self.import_force_label.setObjectName("import_force_label")
+ self.import_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.import_force_label)
+ self.import_force_check = QtWidgets.QCheckBox(ImportGroup)
+ font = QtGui.QFont()
+ font.setItalic(True)
+ self.import_force_check.setFont(font)
+ self.import_force_check.setObjectName("import_force_check")
+ self.import_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.import_force_check)
self.import_button_label = QtWidgets.QLabel(ImportGroup)
self.import_button_label.setText("Error")
self.import_button_label.setObjectName("import_button_label")
- self.import_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.import_button_label)
+ self.import_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.import_button_label)
self.button_info_layout = QtWidgets.QHBoxLayout()
self.button_info_layout.setObjectName("button_info_layout")
self.import_button = QtWidgets.QPushButton(ImportGroup)
@@ -58,16 +67,27 @@ class Ui_ImportGroup(object):
self.import_button.setSizePolicy(sizePolicy)
self.import_button.setObjectName("import_button")
self.button_info_layout.addWidget(self.import_button)
- self.import_layout.setLayout(5, QtWidgets.QFormLayout.FieldRole, self.button_info_layout)
- self.import_force_label = QtWidgets.QLabel(ImportGroup)
- self.import_force_label.setObjectName("import_force_label")
- self.import_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.import_force_label)
- self.import_force_check = QtWidgets.QCheckBox(ImportGroup)
+ self.import_layout.setLayout(6, QtWidgets.QFormLayout.FieldRole, self.button_info_layout)
+ self.platform_label = QtWidgets.QLabel(ImportGroup)
+ self.platform_label.setObjectName("platform_label")
+ self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.platform_label)
+ self.platform_layout = QtWidgets.QHBoxLayout()
+ self.platform_layout.setObjectName("platform_layout")
+ self.platform_combo = QtWidgets.QComboBox(ImportGroup)
+ sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
+ sizePolicy.setHorizontalStretch(0)
+ sizePolicy.setVerticalStretch(0)
+ sizePolicy.setHeightForWidth(self.platform_combo.sizePolicy().hasHeightForWidth())
+ self.platform_combo.setSizePolicy(sizePolicy)
+ self.platform_combo.setObjectName("platform_combo")
+ self.platform_layout.addWidget(self.platform_combo)
+ self.platform_tooltip = QtWidgets.QLabel(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
- self.import_force_check.setFont(font)
- self.import_force_check.setObjectName("import_force_check")
- self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_force_check)
+ self.platform_tooltip.setFont(font)
+ self.platform_tooltip.setObjectName("platform_tooltip")
+ self.platform_layout.addWidget(self.platform_tooltip)
+ self.import_layout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.platform_layout)
self.retranslateUi(ImportGroup)
@@ -80,9 +100,11 @@ class Ui_ImportGroup(object):
self.import_folder_check.setText(_translate("ImportGroup", "Scan the installation path for game folders and import them"))
self.import_dlcs_label.setText(_translate("ImportGroup", "Import DLCs"))
self.import_dlcs_check.setText(_translate("ImportGroup", "If a game has DLCs, try to import them too"))
- self.import_button.setText(_translate("ImportGroup", "Import Game"))
self.import_force_label.setText(_translate("ImportGroup", "Force import"))
self.import_force_check.setText(_translate("ImportGroup", "Import game despite missing files"))
+ self.import_button.setText(_translate("ImportGroup", "Import Game"))
+ self.platform_label.setText(_translate("ImportGroup", "Platform"))
+ self.platform_tooltip.setText(_translate("ImportGroup", "Select the native platform of the game"))
if __name__ == "__main__":
diff --git a/rare/ui/components/tabs/games/integrations/import_group.ui b/rare/ui/components/tabs/games/integrations/import_group.ui
index 43ed7e5e..60dbd349 100644
--- a/rare/ui/components/tabs/games/integrations/import_group.ui
+++ b/rare/ui/components/tabs/games/integrations/import_group.ui
@@ -6,8 +6,8 @@
0
0
- 506
- 184
+ 651
+ 218
@@ -37,14 +37,14 @@
- -
+
-
Import all folders
- -
+
-
@@ -56,14 +56,14 @@
- -
+
-
Import DLCs
- -
+
-
@@ -76,13 +76,32 @@
-
+
+
+ Force import
+
+
+
+ -
+
+
+
+ true
+
+
+
+ Import game despite missing files
+
+
+
+ -
Error
- -
+
-
-
@@ -99,24 +118,38 @@
- -
-
+
-
+
- Force import
+ Platform
- -
-
-
-
- true
-
-
-
- Import game despite missing files
-
-
+
-
+
+
-
+
+
+
+ 0
+ 0
+
+
+
+
+ -
+
+
+
+ true
+
+
+
+ Select the native platform of the game
+
+
+
+
diff --git a/rare/ui/components/tabs/settings/legendary.py b/rare/ui/components/tabs/settings/legendary.py
index 634f5efa..829a60ab 100644
--- a/rare/ui/components/tabs/settings/legendary.py
+++ b/rare/ui/components/tabs/settings/legendary.py
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.ui'
#
-# Created by: PyQt5 UI code generator 5.15.7
+# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_LegendarySettings(object):
def setupUi(self, LegendarySettings):
LegendarySettings.setObjectName("LegendarySettings")
- LegendarySettings.resize(595, 334)
+ LegendarySettings.resize(681, 456)
LegendarySettings.setWindowTitle("LegendarySettings")
self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings)
self.legendary_layout.setObjectName("legendary_layout")
@@ -125,21 +125,30 @@ class Ui_LegendarySettings(object):
self.clean_button = QtWidgets.QPushButton(self.cleanup_group)
self.clean_button.setObjectName("clean_button")
self.cleanup_layout.addWidget(self.clean_button)
- self.right_layout.addWidget(self.cleanup_group, 0, QtCore.Qt.AlignTop)
- self.meta_group = QtWidgets.QGroupBox(LegendarySettings)
- self.meta_group.setObjectName("meta_group")
- self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.meta_group)
+ 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.win32_cb = QtWidgets.QCheckBox(self.meta_group)
- self.win32_cb.setObjectName("win32_cb")
- self.verticalLayout_2.addWidget(self.win32_cb)
- self.mac_cb = QtWidgets.QCheckBox(self.meta_group)
- self.mac_cb.setObjectName("mac_cb")
- self.verticalLayout_2.addWidget(self.mac_cb)
- self.refresh_game_meta_btn = QtWidgets.QPushButton(self.meta_group)
- self.refresh_game_meta_btn.setObjectName("refresh_game_meta_btn")
- self.verticalLayout_2.addWidget(self.refresh_game_meta_btn)
- self.right_layout.addWidget(self.meta_group)
+ 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.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.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_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.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.right_layout.addWidget(self.metadata_group)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.right_layout.addItem(spacerItem1)
self.legendary_layout.addLayout(self.right_layout)
@@ -148,11 +157,11 @@ class Ui_LegendarySettings(object):
def retranslateUi(self, LegendarySettings):
_translate = QtCore.QCoreApplication.translate
- self.install_dir_group.setTitle(_translate("LegendarySettings", "Default Installation Directory"))
- self.download_group.setTitle(_translate("LegendarySettings", "Download Settings"))
- self.max_workers_label.setText(_translate("LegendarySettings", "Max Workers"))
+ self.install_dir_group.setTitle(_translate("LegendarySettings", "Default installation folder"))
+ self.download_group.setTitle(_translate("LegendarySettings", "Download settings"))
+ self.max_workers_label.setText(_translate("LegendarySettings", "Max sorkers"))
self.max_workers_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)"))
- self.max_memory_label.setText(_translate("LegendarySettings", "Max Shared Memory"))
+ self.max_memory_label.setText(_translate("LegendarySettings", "Max shared memory"))
self.max_memory_spin.setSuffix(_translate("LegendarySettings", "MiB"))
self.max_memory_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)"))
self.preferred_cdn_label.setText(_translate("LegendarySettings", "Preferred CDN"))
@@ -162,10 +171,12 @@ class Ui_LegendarySettings(object):
self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup"))
self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests"))
self.clean_button.setText(_translate("LegendarySettings", "Remove everything"))
- self.meta_group.setTitle(_translate("LegendarySettings", "Game metadata"))
- self.win32_cb.setText(_translate("LegendarySettings", "Load 32bit data"))
- self.mac_cb.setText(_translate("LegendarySettings", "Load MacOS data"))
- self.refresh_game_meta_btn.setText(_translate("LegendarySettings", "Refresh game meta"))
+ self.metadata_group.setTitle(_translate("LegendarySettings", "Platforms"))
+ 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.metadata_info.setText(_translate("LegendarySettings", "Restart Rare to apply"))
+ self.refresh_metadata_button.setText(_translate("LegendarySettings", "Refresh metadata"))
if __name__ == "__main__":
diff --git a/rare/ui/components/tabs/settings/legendary.ui b/rare/ui/components/tabs/settings/legendary.ui
index a69ef823..65e69f1c 100644
--- a/rare/ui/components/tabs/settings/legendary.ui
+++ b/rare/ui/components/tabs/settings/legendary.ui
@@ -6,8 +6,8 @@
0
0
- 595
- 334
+ 681
+ 456
@@ -19,7 +19,7 @@
-
- Default Installation Directory
+ Default installation folder
Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
@@ -30,7 +30,7 @@
-
- Download Settings
+ Download settings
Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
@@ -48,7 +48,7 @@
- Max Workers
+ Max sorkers
@@ -90,7 +90,7 @@
-
- Max Shared Memory
+ Max shared memory
@@ -200,7 +200,7 @@
- -
+
-
Cleanup
@@ -227,29 +227,48 @@
-
-
+
- Game metadata
+ Platforms
-
-
+
- Load 32bit data
+ Include Win32 games
-
-
+
- Load MacOS data
+ Include macOS games
-
-
+
- Refresh game meta
+ Include Unreal engine
+
+
+
+ -
+
+
+
+ true
+
+
+
+ Restart Rare to apply
+
+
+
+ -
+
+
+ Refresh metadata
diff --git a/rare/ui/components/tabs/settings/rare.py b/rare/ui/components/tabs/settings/rare.py
index fc0bc69f..fc1abaff 100644
--- a/rare/ui/components/tabs/settings/rare.py
+++ b/rare/ui/components/tabs/settings/rare.py
@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/rare.ui'
#
-# Created by: PyQt5 UI code generator 5.15.6
+# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_RareSettings(object):
def setupUi(self, RareSettings):
RareSettings.setObjectName("RareSettings")
- RareSettings.resize(517, 434)
+ RareSettings.resize(623, 428)
RareSettings.setWindowTitle("RareSettings")
self.rare_layout = QtWidgets.QHBoxLayout(RareSettings)
self.rare_layout.setObjectName("rare_layout")
@@ -148,25 +148,25 @@ class Ui_RareSettings(object):
_translate = QtCore.QCoreApplication.translate
self.interface_group.setTitle(_translate("RareSettings", "Interface"))
self.lang_label.setText(_translate("RareSettings", "Language"))
- self.color_label.setText(_translate("RareSettings", "Color Scheme"))
+ self.color_label.setText(_translate("RareSettings", "Color scheme"))
self.color_select.setItemText(0, _translate("RareSettings", "None"))
- self.style_label.setText(_translate("RareSettings", "Style Sheet"))
+ self.style_label.setText(_translate("RareSettings", "Style sheet"))
self.style_select.setItemText(0, _translate("RareSettings", "None"))
- self.interface_info.setText(_translate("RareSettings", "Restart Rare to apply."))
+ self.interface_info.setText(_translate("RareSettings", "Restart Rare to apply changes."))
self.settings_group.setTitle(_translate("RareSettings", "Behavior"))
self.save_size.setText(_translate("RareSettings", "Restore window size on application startup"))
- self.notification.setText(_translate("RareSettings", "Show notification on download completion"))
- self.log_games.setText(_translate("RareSettings", "Show console for game debug"))
- self.sys_tray.setText(_translate("RareSettings", "Exit to System tray"))
- self.auto_update.setText(_translate("RareSettings", "Update games on application startup"))
- self.confirm_start.setText(_translate("RareSettings", "Confirm game launch"))
- self.auto_sync_cloud.setText(_translate("RareSettings", "Automatically sync with cloud"))
+ self.notification.setText(_translate("RareSettings", "Show notifications when downloads complete"))
+ self.log_games.setText(_translate("RareSettings", "Show console windows when launching games"))
+ self.sys_tray.setText(_translate("RareSettings", "Exit to system tray"))
+ self.auto_update.setText(_translate("RareSettings", "Queue game updates on application startup"))
+ self.confirm_start.setText(_translate("RareSettings", "Confirm before launching games"))
+ self.auto_sync_cloud.setText(_translate("RareSettings", "Automatically upload/download cloud saves"))
self.log_dir_group.setTitle(_translate("RareSettings", "Logs"))
- self.log_dir_open_button.setText(_translate("RareSettings", "Open Log directory"))
- self.log_dir_clean_button.setText(_translate("RareSettings", "Clean Log directory"))
+ self.log_dir_open_button.setText(_translate("RareSettings", "Open log folder"))
+ self.log_dir_clean_button.setText(_translate("RareSettings", "Clean log folder"))
self.groupBox.setTitle(_translate("RareSettings", "Shortcuts"))
- self.desktop_link_btn.setText(_translate("RareSettings", "Create Desktop link"))
- self.startmenu_link_btn.setText(_translate("RareSettings", "Create start menu link"))
+ self.desktop_link_btn.setText(_translate("RareSettings", "Create on desktop"))
+ self.startmenu_link_btn.setText(_translate("RareSettings", "Create in menu"))
if __name__ == "__main__":
diff --git a/rare/ui/components/tabs/settings/rare.ui b/rare/ui/components/tabs/settings/rare.ui
index 5f89464d..2178d31d 100644
--- a/rare/ui/components/tabs/settings/rare.ui
+++ b/rare/ui/components/tabs/settings/rare.ui
@@ -6,8 +6,8 @@
0
0
- 517
- 434
+ 623
+ 428
@@ -51,7 +51,7 @@
-
- Color Scheme
+ Color scheme
@@ -73,7 +73,7 @@
-
- Style Sheet
+ Style sheet
@@ -100,7 +100,7 @@
- Restart Rare to apply.
+ Restart Rare to apply changes.
true
@@ -126,42 +126,42 @@
-
- Show notification on download completion
+ Show notifications when downloads complete
-
- Show console for game debug
+ Show console windows when launching games
-
- Exit to System tray
+ Exit to system tray
-
- Update games on application startup
+ Queue game updates on application startup
-
- Confirm game launch
+ Confirm before launching games
-
- Automatically sync with cloud
+ Automatically upload/download cloud saves
@@ -207,14 +207,14 @@
-
- Open Log directory
+ Open log folder
-
- Clean Log directory
+ Clean log folder
@@ -246,14 +246,14 @@
-
- Create Desktop link
+ Create on desktop
-
- Create start menu link
+ Create in menu
diff --git a/rare/widgets/flow_layout.py b/rare/widgets/flow_layout.py
index f8d32735..c13b67b5 100644
--- a/rare/widgets/flow_layout.py
+++ b/rare/widgets/flow_layout.py
@@ -1,33 +1,55 @@
-from typing import Optional
+from typing import Optional, List, overload
-from PyQt5.QtCore import (
- Qt,
- QRect,
- QSize,
- QPoint,
-)
-from PyQt5.QtWidgets import (
- QLayout,
- QStyle,
- QSizePolicy,
- QLayoutItem,
-)
+from PyQt5.QtCore import Qt, QRect, QSize, QPoint
+from PyQt5.QtWidgets import QLayout, QStyle, QSizePolicy, QLayoutItem, QWidget
class FlowLayout(QLayout):
- def __init__(self, parent=None, margin=-1, hspacing=-1, vspacing=-1):
+ def __init__(self, parent=None):
super(FlowLayout, self).__init__(parent)
- self._hspacing = hspacing
- self._vspacing = vspacing
- self._items = []
- self.setContentsMargins(margin, margin, margin, margin)
self.setObjectName(type(self).__name__)
+ self._hspacing = -1
+ self._vspacing = -1
+ self._items: List[QLayoutItem] = []
def __del__(self):
del self._items[:]
+ @overload
+ def indexOf(self, a0: QWidget) -> int:
+ try:
+ return next(idx for idx, item in enumerate(self._items) if item.widget() is a0)
+ except:
+ return -1
+
+ def indexOf(self, a0: QLayoutItem) -> int:
+ try:
+ return self._items.index(a0)
+ except:
+ return -1
+
def addItem(self, a0: QLayoutItem) -> None:
self._items.append(a0)
+ self.invalidate()
+
+ def removeItem(self, a0: QLayoutItem) -> None:
+ self._items.remove(a0)
+ self.invalidate()
+
+ def spacing(self) -> int:
+ hspacing = self.horizontalSpacing()
+ if hspacing == self.verticalSpacing():
+ return hspacing
+ else:
+ return -1
+
+ def setSpacing(self, a0: int) -> None:
+ self._hspacing = self._vspacing = a0
+ self.invalidate()
+
+ def setHorizontalSpacing(self, a0: int) -> None:
+ self._hspacing = a0
+ self.invalidate()
def horizontalSpacing(self):
if self._hspacing >= 0:
@@ -35,6 +57,10 @@ class FlowLayout(QLayout):
else:
return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
+ def setVerticalSpacing(self, a0: int) -> None:
+ self._vspacing = a0
+ self.invalidate()
+
def verticalSpacing(self):
if self._vspacing >= 0:
return self._vspacing
@@ -51,11 +77,14 @@ class FlowLayout(QLayout):
def takeAt(self, index: int) -> Optional[QLayoutItem]:
if 0 <= index < len(self._items):
- return self._items.pop(index)
+ item = self._items.pop(index)
+ self.invalidate()
+ return item
return None
def expandingDirections(self) -> Qt.Orientations:
- return Qt.Horizontal | Qt.Vertical
+ return Qt.Orientations(Qt.Orientation(0))
+ # return Qt.Horizontal | Qt.Vertical
def hasHeightForWidth(self) -> bool:
return True
@@ -93,8 +122,6 @@ class FlowLayout(QLayout):
if item.isEmpty():
continue
widget = item.widget()
- if not widget.isVisible():
- continue
hspace = self.horizontalSpacing()
if hspace == -1:
hspace = widget.style().layoutSpacing(
diff --git a/rare/widgets/indicator_edit.py b/rare/widgets/indicator_edit.py
index c9a76bb6..9c31a737 100644
--- a/rare/widgets/indicator_edit.py
+++ b/rare/widgets/indicator_edit.py
@@ -4,7 +4,6 @@ from logging import getLogger
from typing import Callable, Tuple, Optional, Dict, List
from PyQt5.QtCore import (
- Qt,
QSize,
pyqtSignal,
QFileInfo,
@@ -135,7 +134,8 @@ class IndicatorLineEdit(QWidget):
# Add line_edit
self.line_edit = QLineEdit(self)
self.line_edit.setObjectName(f"{type(self).__name__}Edit")
- self.line_edit.setPlaceholderText(placeholder if placeholder else self.tr("Default"))
+ self.line_edit.setPlaceholderText(placeholder if placeholder else self.tr("Use global/default setting"))
+ self.line_edit.setToolTip(placeholder if placeholder else "")
self.line_edit.setSizePolicy(horiz_policy, QSizePolicy.Fixed)
# Add completer
self.setCompleter(completer)
diff --git a/rare/widgets/library_layout.py b/rare/widgets/library_layout.py
index dd2c056d..721e1ad3 100644
--- a/rare/widgets/library_layout.py
+++ b/rare/widgets/library_layout.py
@@ -1,23 +1,18 @@
from typing import Callable
-from PyQt5.QtCore import (
- Qt,
- QRect,
- QPoint,
-)
-from PyQt5.QtWidgets import (
- QSizePolicy,
-)
+from PyQt5.QtCore import Qt, QRect, QPoint
+from PyQt5.QtWidgets import QSizePolicy
from .flow_layout import FlowLayout
class LibraryLayout(FlowLayout):
- def __init__(self, parent=None, margin=6, spacing=11):
- super(LibraryLayout, self).__init__(parent=parent, margin=margin, hspacing=spacing, vspacing=spacing)
+ def __init__(self, parent=None):
+ super(LibraryLayout, self).__init__(parent)
def expandingDirections(self) -> Qt.Orientations:
- return Qt.Horizontal | Qt.Vertical
+ return Qt.Orientations(Qt.Orientation(0))
+ # return Qt.Horizontal | Qt.Vertical
def setGeometry(self, a0: QRect) -> None:
super(FlowLayout, self).setGeometry(a0)
@@ -127,4 +122,4 @@ class LibraryLayout(FlowLayout):
def sort(self, key: Callable, reverse=False) -> None:
self._items.sort(key=key, reverse=reverse)
- self.setGeometry(self.parent().contentsRect())
+ self.setGeometry(self.parent().contentsRect().adjusted(*self.parent().getContentsMargins()))