1
0
Fork 0
mirror of synced 2024-06-17 01:54:46 +12:00

Merge pull request #338 from loathingKernel/next

Prepare for 1.10.9
This commit is contained in:
Stelios Tsampas 2023-12-17 19:46:58 +02:00 committed by GitHub
commit 2803319373
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 596 additions and 340 deletions

View file

@ -20,7 +20,7 @@ AppDir:
id: io.github.dummerle.rare id: io.github.dummerle.rare
name: Rare name: Rare
icon: Rare icon: Rare
version: 1.10.7 version: 1.10.9
exec: usr/bin/python3 exec: usr/bin/python3
exec_args: $APPDIR/usr/src/rare/main.py $@ exec_args: $APPDIR/usr/src/rare/main.py $@
apt: apt:

View file

@ -12,7 +12,7 @@ force-exclude = '''
[tool.poetry] [tool.poetry]
name = "rare" name = "rare"
version = "1.10.7" version = "1.10.9"
description = "A GUI for Legendary" description = "A GUI for Legendary"
authors = ["Dummerle"] authors = ["Dummerle"]
license = "GPL3" license = "GPL3"

View file

@ -1,4 +1,4 @@
__version__ = "1.10.7" __version__ = "1.10.9"
__codename__ = "Garlic Crab" __codename__ = "Garlic Crab"
# For PyCharm profiler # For PyCharm profiler

View file

@ -45,8 +45,6 @@ class Rare(RareApp):
self.signals = RareCore.instance().signals() self.signals = RareCore.instance().signals()
self.core = RareCore.instance().core() self.core = RareCore.instance().core()
config_helper.init_config_handler(self.core)
lang = self.settings.value("language", self.core.language_code, type=str) lang = self.settings.value("language", self.core.language_code, type=str)
self.load_translator(lang) self.load_translator(lang)

View file

@ -73,13 +73,15 @@ class InstallDialog(QDialog):
self.ui.install_dialog_label.setText(f'<h3>{header} "{self.rgame.app_title}"</h3>') self.ui.install_dialog_label.setText(f'<h3>{header} "{self.rgame.app_title}"</h3>')
self.setWindowTitle(f'{header} "{self.rgame.app_title}" - {QCoreApplication.instance().applicationName()}') self.setWindowTitle(f'{header} "{self.rgame.app_title}" - {QCoreApplication.instance().applicationName()}')
if not self.options.base_path: if options.base_path:
self.options.base_path = self.core.lgd.config.get( base_path = options.base_path
"Legendary", "install_dir", fallback=os.path.expanduser("~/legendary") 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( self.install_dir_edit = PathEdit(
path=self.options.base_path, path=base_path,
file_mode=QFileDialog.DirectoryOnly, file_mode=QFileDialog.DirectoryOnly,
edit_func=self.option_changed, edit_func=self.option_changed,
save_func=self.save_install_edit, save_func=self.save_install_edit,
@ -90,36 +92,24 @@ class InstallDialog(QDialog):
QFormLayout.FieldRole, self.install_dir_edit QFormLayout.FieldRole, self.install_dir_edit
) )
if self.options.update: self.install_dir_edit.setDisabled(rgame.is_installed)
self.ui.install_dir_label.setEnabled(False) self.ui.install_dir_label.setDisabled(rgame.is_installed)
self.install_dir_edit.setEnabled(False) self.ui.shortcut_label.setDisabled(rgame.is_installed)
self.ui.shortcut_label.setEnabled(False) self.ui.shortcut_check.setDisabled(rgame.is_installed)
self.ui.shortcut_check.setEnabled(False) self.ui.shortcut_check.setChecked(not rgame.is_installed and QSettings().value("create_shortcut", True, bool))
else:
self.ui.shortcut_check.setChecked(QSettings().value("create_shortcut", True, bool))
self.error_box() self.error_box()
platforms = self.rgame.platforms self.ui.platform_combo.addItems(reversed(rgame.platforms))
self.ui.platform_combo.addItems(reversed(platforms)) combo_text = rgame.igame.platform if rgame.is_installed else rgame.default_platform
self.ui.platform_combo.currentIndexChanged.connect(lambda: self.option_changed(None)) self.ui.platform_combo.setCurrentIndex(self.ui.platform_combo.findText(combo_text))
self.ui.platform_combo.currentIndexChanged.connect(lambda: self.error_box()) self.ui.platform_combo.currentIndexChanged.connect(lambda i: self.option_changed(None))
self.ui.platform_combo.currentIndexChanged.connect( self.ui.platform_combo.currentIndexChanged.connect(self.check_incompatible_platform)
lambda i: self.error_box( self.ui.platform_combo.currentIndexChanged.connect(self.reset_install_dir)
self.tr("Warning"), self.ui.platform_combo.currentIndexChanged.connect(self.reset_sdl_list)
self.tr("You will not be able to run the game if you select <b>{}</b> as platform").format(
self.ui.platform_combo.itemText(i) self.ui.platform_label.setDisabled(rgame.is_installed)
), self.ui.platform_combo.setDisabled(rgame.is_installed)
)
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.advanced.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0)) self.advanced.ui.max_workers_spin.setValue(self.core.lgd.config.getint("Legendary", "max_workers", fallback=0))
self.advanced.ui.max_workers_spin.valueChanged.connect(self.option_changed) self.advanced.ui.max_workers_spin.valueChanged.connect(self.option_changed)
@ -139,7 +129,10 @@ class InstallDialog(QDialog):
self.selectable_checks: List[TagCheckBox] = [] self.selectable_checks: List[TagCheckBox] = []
self.config_tags: Optional[List[str]] = None 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) self.ui.install_button.setEnabled(False)
@ -155,9 +148,10 @@ class InstallDialog(QDialog):
self.selectable.setEnabled(False) self.selectable.setEnabled(False)
if pf.system() == "Darwin": if pf.system() == "Darwin":
self.ui.shortcut_label.setDisabled(True)
self.ui.shortcut_check.setDisabled(True) self.ui.shortcut_check.setDisabled(True)
self.ui.shortcut_check.setChecked(False) 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_label.setEnabled(False)
self.advanced.ui.install_prereqs_check.setEnabled(False) self.advanced.ui.install_prereqs_check.setEnabled(False)
@ -190,8 +184,16 @@ class InstallDialog(QDialog):
self.__on_verify() self.__on_verify()
self.show() self.show()
@pyqtSlot(str) @pyqtSlot(int)
def setup_sdl_list(self, platform="Windows"): 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: for cb in self.selectable_checks:
cb.disconnect() cb.disconnect()
cb.deleteLater() cb.deleteLater()
@ -223,8 +225,19 @@ class InstallDialog(QDialog):
else: else:
self.selectable.setDisabled(True) 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)
)
else:
self.error_box()
def get_options(self): 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.max_workers = self.advanced.ui.max_workers_spin.value()
self.options.shared_memory = self.advanced.ui.max_memory_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.order_opt = self.advanced.ui.dl_optimizations_check.isChecked()

View file

@ -346,5 +346,5 @@ class DownloadsTab(QWidget):
@pyqtSlot(RareGame, bool, str) @pyqtSlot(RareGame, bool, str)
def __on_uninstall_worker_result(self, rgame: RareGame, success: bool, message: str): def __on_uninstall_worker_result(self, rgame: RareGame, success: bool, message: str):
if not success: 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 rgame.state = RareGame.State.IDLE

View file

@ -1,6 +1,7 @@
from logging import getLogger from logging import getLogger
from PyQt5.QtCore import QSettings, Qt, pyqtSlot from PyQt5.QtCore import QSettings, Qt, pyqtSlot
from PyQt5.QtGui import QShowEvent
from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame from PyQt5.QtWidgets import QStackedWidget, QVBoxLayout, QWidget, QScrollArea, QFrame
from rare.models.game import RareGame from rare.models.game import RareGame
@ -33,8 +34,6 @@ class GamesTab(QStackedWidget):
self.image_manager = ImageManagerSingleton() self.image_manager = ImageManagerSingleton()
self.settings = QSettings() self.settings = QSettings()
self.active_filter: int = 0
self.games_page = QWidget(parent=self) self.games_page = QWidget(parent=self)
games_page_layout = QVBoxLayout(self.games_page) games_page_layout = QVBoxLayout(self.games_page)
self.addWidget(self.games_page) self.addWidget(self.games_page)
@ -69,6 +68,7 @@ class GamesTab(QStackedWidget):
self.icon_view = QWidget(self.icon_view_scroll) self.icon_view = QWidget(self.icon_view_scroll)
icon_view_layout = LibraryLayout(self.icon_view) icon_view_layout = LibraryLayout(self.icon_view)
icon_view_layout.setSpacing(9)
icon_view_layout.setContentsMargins(0, 13, 0, 13) icon_view_layout.setContentsMargins(0, 13, 0, 13)
icon_view_layout.setAlignment(Qt.AlignTop) 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.refresh_list.clicked.connect(self.library_controller.update_list)
self.head_bar.view.toggled.connect(self.toggle_view) self.head_bar.view.toggled.connect(self.toggle_view)
f = self.settings.value("filter", 0, int) self.active_filter: str = self.head_bar.filter.currentData(Qt.UserRole)
if f >= len(self.head_bar.available_filters):
f = 0
self.active_filter = self.head_bar.available_filters[f]
# signals # signals
self.signals.game.installed.connect(self.update_count_games_label) self.signals.game.installed.connect(self.update_count_games_label)
self.signals.game.uninstalled.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.setup_game_list()
self.init = False
return super().showEvent(a0)
@pyqtSlot() @pyqtSlot()
def scroll_to_top(self): def scroll_to_top(self):
@ -149,7 +153,7 @@ class GamesTab(QStackedWidget):
for rgame in self.rcore.games: for rgame in self.rcore.games:
icon_widget, list_widget = self.add_library_widget(rgame) icon_widget, list_widget = self.add_library_widget(rgame)
if not icon_widget or not list_widget: 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 continue
self.icon_view.layout().addWidget(icon_widget) self.icon_view.layout().addWidget(icon_widget)
self.list_view.layout().addWidget(list_widget) self.list_view.layout().addWidget(list_widget)
@ -160,8 +164,7 @@ class GamesTab(QStackedWidget):
try: try:
icon_widget, list_widget = self.library_controller.add_game(rgame) icon_widget, list_widget = self.library_controller.add_game(rgame)
except Exception as e: except Exception as e:
raise e logger.error("Could not add widget for %s to library: %s", rgame.app_name, e)
logger.error(f"{rgame.app_name} is broken. Don't add it to game list: {e}")
return None, None return None, None
icon_widget.show_info.connect(self.show_game_info) icon_widget.show_info.connect(self.show_game_info)
list_widget.show_info.connect(self.show_game_info) list_widget.show_info.connect(self.show_game_info)

View file

@ -144,10 +144,10 @@ class CloudSaves(QWidget, SideTabContents):
self.cloud_save_path_edit.setText("") self.cloud_save_path_edit.setText("")
QMessageBox.warning( QMessageBox.warning(
self, self,
self.tr("Error - {}").format(self.rgame.title), self.tr("Error - {}").format(self.rgame.app_title),
self.tr( self.tr(
"Error while calculating path for <b>{}</b>. Insufficient permissions to create <b>{}</b>" "Error while calculating path for <b>{}</b>. Insufficient permissions to create <b>{}</b>"
).format(self.rgame.title, path), ).format(self.rgame.app_title, path),
) )
return return
if not path: if not path:
@ -217,7 +217,7 @@ class CloudSaves(QWidget, SideTabContents):
self.rgame = rgame self.rgame = rgame
self.set_title.emit(rgame.title) self.set_title.emit(rgame.app_title)
rgame.signals.widget.update.connect(self.__update_widget) rgame.signals.widget.update.connect(self.__update_widget)
self.__update_widget() self.__update_widget()

View file

@ -121,7 +121,7 @@ class GameInfo(QWidget, SideTabContents):
if not os.path.exists(repair_file): if not os.path.exists(repair_file):
QMessageBox.warning( QMessageBox.warning(
self, self,
self.tr("Error - {}").format(self.rgame.title), self.tr("Error - {}").format(self.rgame.app_title),
self.tr( self.tr(
"Repair file does not exist or game does not need a repair. Please verify game first" "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: if rgame.has_update:
ans = QMessageBox.question( ans = QMessageBox.question(
self, self,
self.tr("Repair and update? - {}").format(self.rgame.title), self.tr("Repair and update? - {}").format(self.rgame.app_title),
self.tr( self.tr(
"There is an update for <b>{}</b> from <b>{}</b> to <b>{}</b>. " "There is an update for <b>{}</b> from <b>{}</b> to <b>{}</b>. "
"Do you want to update the game while repairing it?" "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 ) == QMessageBox.Yes
rgame.repair(repair_and_update=ans) rgame.repair(repair_and_update=ans)
@ -147,7 +147,7 @@ class GameInfo(QWidget, SideTabContents):
def __on_worker_error(self, rgame: RareGame, message: str): def __on_worker_error(self, rgame: RareGame, message: str):
QMessageBox.warning( QMessageBox.warning(
self, self,
self.tr("Error - {}").format(rgame.title), self.tr("Error - {}").format(rgame.app_title),
message message
) )
@ -155,11 +155,11 @@ class GameInfo(QWidget, SideTabContents):
def __on_verify(self): def __on_verify(self):
""" This method is to be called from the button only """ """ This method is to be called from the button only """
if not os.path.exists(self.rgame.igame.install_path): 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( QMessageBox.warning(
self, self,
self.tr("Error - {}").format(self.rgame.title), self.tr("Error - {}").format(self.rgame.app_title),
self.tr("Installation path for <b>{}</b> does not exist. Cannot continue.").format(self.rgame.title), self.tr("Installation path for <b>{}</b> does not exist. Cannot continue.").format(self.rgame.app_title),
) )
return return
self.verify_game(self.rgame) self.verify_game(self.rgame)
@ -184,18 +184,18 @@ class GameInfo(QWidget, SideTabContents):
if success: if success:
QMessageBox.information( QMessageBox.information(
self, self,
self.tr("Summary - {}").format(rgame.title), self.tr("Summary - {}").format(rgame.app_title),
self.tr("<b>{}</b> has been verified successfully. " self.tr("<b>{}</b> has been verified successfully. "
"No missing or corrupt files found").format(rgame.title), "No missing or corrupt files found").format(rgame.app_title),
) )
else: else:
ans = QMessageBox.question( ans = QMessageBox.question(
self, self,
self.tr("Summary - {}").format(rgame.title), self.tr("Summary - {}").format(rgame.app_title),
self.tr( self.tr(
"<b>{}</b> failed verification, <b>{}</b> file(s) corrupted, <b>{}</b> file(s) are missing. " "<b>{}</b> failed verification, <b>{}</b> file(s) corrupted, <b>{}</b> file(s) are missing. "
"Do you want to repair them?" "Do you want to repair them?"
).format(rgame.title, failed, missing), ).format(rgame.app_title, failed, missing),
QMessageBox.Yes | QMessageBox.No, QMessageBox.Yes | QMessageBox.No,
QMessageBox.Yes, QMessageBox.Yes,
) )
@ -216,7 +216,7 @@ class GameInfo(QWidget, SideTabContents):
if os.path.basename(self.rgame.install_path) in os.path.basename(item): if os.path.basename(self.rgame.install_path) in os.path.basename(item):
ans = QMessageBox.question( ans = QMessageBox.question(
self, self,
self.tr("Move game? - {}").format(self.rgame.title), self.tr("Move game? - {}").format(self.rgame.app_title),
self.tr( self.tr(
"Destination <b>{}</b> already exists. " "Destination <b>{}</b> already exists. "
"Are you sure you want to overwrite it?" "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): def __on_move_result(self, rgame: RareGame, dst_path: str):
QMessageBox.information( QMessageBox.information(
self, self,
self.tr("Summary - {}").format(rgame.title), self.tr("Summary - {}").format(rgame.app_title),
self.tr("<b>{}</b> successfully moved to <b>{}<b>.").format(rgame.title, dst_path), self.tr("<b>{}</b> successfully moved to <b>{}<b>.").format(rgame.app_title, dst_path),
) )
@pyqtSlot() @pyqtSlot()
@ -284,7 +284,9 @@ class GameInfo(QWidget, SideTabContents):
) )
self.ui.platform.setText( 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( self.ui.lbl_grade.setDisabled(

View file

@ -38,15 +38,15 @@ class LibraryWidgetController(QObject):
elif "hidden" in widget.rgame.metadata.tags: elif "hidden" in widget.rgame.metadata.tags:
visible = False visible = False
elif filter_name == "installed": elif filter_name == "installed":
visible = widget.rgame.is_installed visible = widget.rgame.is_installed and not widget.rgame.is_unreal
elif filter_name == "offline": 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": elif filter_name == "32bit":
visible = widget.rgame.is_win32 visible = widget.rgame.is_win32 and not widget.rgame.is_unreal
elif filter_name == "mac": elif filter_name == "mac":
visible = widget.rgame.is_mac visible = widget.rgame.is_mac and not widget.rgame.is_unreal
elif filter_name == "installable": 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": elif filter_name == "include_ue":
visible = True visible = True
elif filter_name == "all": elif filter_name == "all":

View file

@ -15,7 +15,7 @@ class IconGameWidget(GameWidget):
def __init__(self, rgame: RareGame, parent=None): def __init__(self, rgame: RareGame, parent=None):
super().__init__(rgame, parent) super().__init__(rgame, parent)
self.setObjectName(f"{rgame.app_name}") self.setObjectName(f"{rgame.app_name}")
self.setFixedSize(ImageSize.Display) self.setFixedSize(ImageSize.Library)
self.ui = IconWidget() self.ui = IconWidget()
self.ui.setupUi(self) self.ui.setupUi(self)

View file

@ -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 ( from PyQt5.QtWidgets import (
QLabel, QLabel,
QPushButton, QPushButton,
@ -22,45 +24,28 @@ class GameListHeadBar(QWidget):
def __init__(self, parent=None): def __init__(self, parent=None):
super(GameListHeadBar, self).__init__(parent=parent) super(GameListHeadBar, self).__init__(parent=parent)
self.rcore = RareCore.instance() self.rcore = RareCore.instance()
self.settings = QSettings() self.settings = QSettings(self)
self.filter = QComboBox() self.filter = QComboBox(self)
self.filter.addItems( self.filter.addItem(self.tr("All games"), "all")
[ self.filter.addItem(self.tr("Installed"), "installed")
self.tr("All games"), self.filter.addItem(self.tr("Offline"), "offline")
self.tr("Installed only"), # self.filter.addItem(self.tr("Hidden"), "hidden")
self.tr("Offline Games"),
# self.tr("Hidden")
]
)
self.available_filters = [
"all",
"installed",
"offline",
# "hidden"
]
if self.rcore.bit32_games: if self.rcore.bit32_games:
self.filter.addItem(self.tr("32 Bit Games")) self.filter.addItem(self.tr("32bit games"), "32bit")
self.available_filters.append("32bit")
if self.rcore.mac_games: if self.rcore.mac_games:
self.filter.addItem(self.tr("Mac games")) self.filter.addItem(self.tr("macOS games"), "mac")
self.available_filters.append("mac")
if self.rcore.origin_games: if self.rcore.origin_games:
self.filter.addItem(self.tr("Exclude Origin")) self.filter.addItem(self.tr("Exclude Origin"), "installable")
self.available_filters.append("installable") self.filter.addItem(self.tr("Include Unreal"), "include_ue")
self.filter.addItem(self.tr("Include Unreal Engine"))
self.available_filters.append("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: try:
self.filter.setCurrentIndex(self.settings.value("filter", 0, int)) self.filter.setCurrentIndex(self.settings.value("library_filter", filter_index, int))
except TypeError: except TypeError:
self.settings.setValue("filter", 0) self.settings.setValue("library_filter", filter_index)
self.filter.setCurrentIndex(0) self.filter.setCurrentIndex(filter_index)
self.filter.currentIndexChanged.connect(self.filter_changed) self.filter.currentIndexChanged.connect(self.filter_changed)
integrations_menu = QMenu(self) integrations_menu = QMenu(self)
@ -139,6 +124,6 @@ class GameListHeadBar(QWidget):
self.rcore.fetch() self.rcore.fetch()
@pyqtSlot(int) @pyqtSlot(int)
def filter_changed(self, i: int): def filter_changed(self, index: int):
self.filterChanged.emit(self.available_filters[i]) self.filterChanged.emit(self.filter.itemData(index, Qt.UserRole))
self.settings.setValue("filter", i) self.settings.setValue("library_filter", index)

View file

@ -213,9 +213,7 @@ class EOSGroup(QGroupBox, Ui_EosWidget):
self.enabled_cb.setChecked(enabled) self.enabled_cb.setChecked(enabled)
def install_overlay(self, update=False): def install_overlay(self, update=False):
base_path = os.path.join( base_path = os.path.join(self.core.get_default_install_dir(), ".overlay")
self.core.lgd.config.get("Legendary", "install_dir", fallback=os.path.expanduser("~/legendary")),".overlay"
)
if update: if update:
if not self.overlay: if not self.overlay:
self.overlay_stack.setCurrentIndex(1) self.overlay_stack.setCurrentIndex(1)

View file

@ -72,8 +72,10 @@ class ImportWorker(QRunnable):
def __init__( def __init__(
self, self,
core: LegendaryCore, path: str, core: LegendaryCore,
path: str,
app_name: str = None, app_name: str = None,
platform: Optional[str] = None,
import_folder: bool = False, import_folder: bool = False,
import_dlcs: bool = False, import_dlcs: bool = False,
import_force: bool = False import_force: bool = False
@ -86,6 +88,7 @@ class ImportWorker(QRunnable):
self.path = Path(path) self.path = Path(path)
self.app_name = app_name self.app_name = app_name
self.import_folder = import_folder 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_dlcs = import_dlcs
self.import_force = import_force self.import_force = import_force
@ -110,9 +113,13 @@ class ImportWorker(QRunnable):
result = ImportedGame(ImportResult.ERROR) result = ImportedGame(ImportResult.ERROR)
result.path = str(path) result.path = str(path)
if app_name or (app_name := find_app_name(str(path), self.core)): 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_name = app_name
result.app_title = app_title = self.core.get_game(app_name).app_title result.app_title = game.app_title
success, message = self.__import_game(path, app_name, 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: if not success:
result.result = ImportResult.FAILED result.result = ImportResult.FAILED
result.message = message result.message = message
@ -120,12 +127,13 @@ class ImportWorker(QRunnable):
result.result = ImportResult.SUCCESS result.result = ImportResult.SUCCESS
return result 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) cli = LegendaryCLI(self.core)
status = LgndrIndirectStatus() status = LgndrIndirectStatus()
args = LgndrImportGameArgs( args = LgndrImportGameArgs(
app_path=str(path), app_path=str(path),
app_name=app_name, app_name=app_name,
platform=platform,
disable_check=self.import_force, disable_check=self.import_force,
skip_dlcs=not self.import_dlcs, skip_dlcs=not self.import_dlcs,
with_dlcs=self.import_dlcs, with_dlcs=self.import_dlcs,
@ -192,7 +200,7 @@ class ImportGroup(QGroupBox):
self.__install_dirs: Set[str] = set() self.__install_dirs: Set[str] = set()
self.path_edit = PathEdit( self.path_edit = PathEdit(
self.core.get_default_install_dir(), self.core.get_default_install_dir(self.core.default_platform),
QFileDialog.DirectoryOnly, QFileDialog.DirectoryOnly,
edit_func=self.path_edit_callback, edit_func=self.path_edit_callback,
parent=self, parent=self,
@ -206,6 +214,7 @@ class ImportGroup(QGroupBox):
self.app_name_edit = IndicatorLineEdit( self.app_name_edit = IndicatorLineEdit(
placeholder=self.tr("Use in case the app name was not found automatically"), placeholder=self.tr("Use in case the app name was not found automatically"),
edit_func=self.app_name_edit_callback, edit_func=self.app_name_edit_callback,
save_func=self.app_name_save_callback,
parent=self, parent=self,
) )
self.app_name_edit.textChanged.connect(self.app_name_changed) self.app_name_edit.textChanged.connect(self.app_name_changed)
@ -247,8 +256,10 @@ class ImportGroup(QGroupBox):
def set_game(self, app_name: str): def set_game(self, app_name: str):
if app_name: if app_name:
folder = self.rcore.get_game(app_name).folder_name rgame = self.rcore.get_game(app_name)
self.path_edit.setText(os.path.join(self.core.get_default_install_dir(), folder)) 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) self.app_name_edit.setText(app_name)
def path_edit_callback(self, path) -> Tuple[bool, str, int]: def path_edit_callback(self, path) -> Tuple[bool, str, int]:
@ -279,6 +290,12 @@ class ImportGroup(QGroupBox):
else: else:
return False, text, IndicatorReasonsCommon.NOT_INSTALLED 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) @pyqtSlot(str)
def app_name_changed(self, app_name: str): def app_name_changed(self, app_name: str):
self.info_label.setText("") self.info_label.setText("")
@ -294,6 +311,14 @@ class ImportGroup(QGroupBox):
@pyqtSlot(int) @pyqtSlot(int)
def import_folder_changed(self, state: Qt.CheckState): def import_folder_changed(self, state: Qt.CheckState):
self.app_name_edit.setEnabled(not state) 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_dlcs_check.setCheckState(Qt.Unchecked)
self.ui.import_force_check.setCheckState(Qt.Unchecked) self.ui.import_force_check.setCheckState(Qt.Unchecked)
self.ui.import_dlcs_check.setEnabled( self.ui.import_dlcs_check.setEnabled(
@ -322,10 +347,11 @@ class ImportGroup(QGroupBox):
self.worker = ImportWorker( self.worker = ImportWorker(
self.core, self.core,
path, path,
self.app_name_edit.text(), app_name=self.app_name_edit.text(),
self.ui.import_folder_check.isChecked(), platform=self.ui.platform_combo.currentText() if not self.ui.import_folder_check.isChecked() else None,
self.ui.import_dlcs_check.isChecked(), import_folder=self.ui.import_folder_check.isChecked(),
self.ui.import_force_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.progress.connect(self.__on_import_progress)
self.worker.signals.result.connect(self.__on_import_result) self.worker.signals.result.connect(self.__on_import_result)

View file

@ -74,7 +74,6 @@ class UbiConnectWorker(Worker):
def __init__(self, core: LegendaryCore, ubi_account_id, partner_link_id): def __init__(self, core: LegendaryCore, ubi_account_id, partner_link_id):
super(UbiConnectWorker, self).__init__() super(UbiConnectWorker, self).__init__()
self.signals = UbiConnectWorker.Signals() self.signals = UbiConnectWorker.Signals()
self.setAutoDelete(True)
self.core = core self.core = core
self.ubi_account_id = ubi_account_id self.ubi_account_id = ubi_account_id
self.partner_link_id = partner_link_id self.partner_link_id = partner_link_id

View file

@ -40,8 +40,10 @@ class DefaultGameSettings(QWidget):
if platform.system() != "Windows": if platform.system() != "Windows":
self.linux_settings = LinuxAppSettings() self.linux_settings = LinuxAppSettings()
self.proton_settings = ProtonSettings(self.linux_settings, self.wrapper_settings) if platform.system() != "Darwin":
self.ui.proton_layout.addWidget(self.proton_settings) 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: Remove the spacerItem and margins from the linux settings
# FIXME: This should be handled differently at soem point in the future # 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") lambda active: self.wrapper_settings.add_wrapper("mangohud")
if active else self.wrapper_settings.delete_wrapper("mangohud")) if active else self.wrapper_settings.delete_wrapper("mangohud"))
self.linux_settings.environ_changed.connect(self.env_vars.reset_model) self.linux_settings.environ_changed.connect(self.env_vars.reset_model)
self.proton_settings.environ_changed.connect(self.env_vars.reset_model)
else: else:
self.ui.linux_settings_widget.setVisible(False) self.ui.linux_settings_widget.setVisible(False)
@ -77,7 +77,10 @@ class DefaultGameSettings(QWidget):
proton = self.wrapper_settings.wrappers.get("proton", "") proton = self.wrapper_settings.wrappers.get("proton", "")
if proton: if proton:
proton = proton.text 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: if proton:
self.linux_settings.ui.wine_groupbox.setEnabled(False) self.linux_settings.ui.wine_groupbox.setEnabled(False)
else: else:

View file

@ -1,7 +1,7 @@
import platform import platform as pf
import re import re
from logging import getLogger from logging import getLogger
from typing import Tuple from typing import Tuple, List
from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSettings from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSettings
from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox
@ -19,14 +19,21 @@ class RefreshGameMetaWorker(Worker):
class Signals(QObject): class Signals(QObject):
finished = pyqtSignal() finished = pyqtSignal()
def __init__(self): def __init__(self, platforms: List[str], include_unreal: bool):
super(RefreshGameMetaWorker, self).__init__() super(RefreshGameMetaWorker, self).__init__()
self.signals = RefreshGameMetaWorker.Signals() self.signals = RefreshGameMetaWorker.Signals()
self.setAutoDelete(True)
self.core = LegendaryCoreSingleton() self.core = LegendaryCoreSingleton()
if platforms:
self.platforms = platforms
else:
self.platforms = ["Windows"]
self.skip_ue = not include_unreal
def run_real(self) -> None: 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() self.signals.finished.emit()
@ -34,15 +41,26 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
def __init__(self, parent=None): def __init__(self, parent=None):
super(LegendarySettings, self).__init__(parent=parent) super(LegendarySettings, self).__init__(parent=parent)
self.setupUi(self) self.setupUi(self)
self.settings = QSettings() self.settings = QSettings(self)
self.core = LegendaryCoreSingleton() 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.install_dir = PathEdit(
self.core.get_default_install_dir(), self.core.get_default_install_dir(),
placeholder=self.tr("Default installation folder for Windows games"),
file_mode=QFileDialog.DirectoryOnly, file_mode=QFileDialog.DirectoryOnly,
save_func=self.path_save, save_func=self.__win_path_save,
) )
self.install_dir_layout.addWidget(self.install_dir) 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.locale_layout.addWidget(self.locale_edit)
self.win32_cb.setChecked(self.settings.value("win32_meta", False, bool)) self.fetch_win32_check.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.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.fetch_macos_check.setChecked(self.settings.value("macos_meta", pf.system() == "Darwin", bool))
self.mac_cb.stateChanged.connect(lambda: self.settings.setValue("mac_meta", self.mac_cb.isChecked())) 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_metadata_button.clicked.connect(self.refresh_metadata)
self.refresh_game_meta_btn.setDisabled(True) # FIXME: Disable the button for now because it interferes with RareCore
self.refresh_game_meta_btn.setText(self.tr("Loading")) self.refresh_metadata_button.setEnabled(False)
worker = RefreshGameMetaWorker() self.refresh_metadata_button.setVisible(False)
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"))) 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) QThreadPool.globalInstance().start(worker)
@staticmethod @staticmethod
@ -120,12 +154,20 @@ class LegendarySettings(QWidget, Ui_LegendarySettings):
self.core.lgd.config.remove_option("Legendary", "locale") self.core.lgd.config.remove_option("Legendary", "locale")
self.core.lgd.save_config() self.core.lgd.save_config()
def path_save(self, text: str): def __mac_path_save(self, text: str) -> None:
self.core.lgd.config["Legendary"]["install_dir"] = text self.__path_save(text, "mac_install_dir")
if not text and "install_dir" in self.core.lgd.config["Legendary"].keys():
self.core.lgd.config["Legendary"].pop("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: 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() self.core.lgd.save_config()
def max_worker_save(self, workers: str): def max_worker_save(self, workers: str):

View file

@ -82,8 +82,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.style_select.setCurrentIndex(0) self.style_select.setCurrentIndex(0)
self.style_select.currentIndexChanged.connect(self.on_style_select_changed) self.style_select.currentIndexChanged.connect(self.on_style_select_changed)
self.interface_info.setVisible(False)
self.rpc = RPCSettings(self) self.rpc = RPCSettings(self)
self.right_layout.insertWidget(1, self.rpc, alignment=Qt.AlignTop) 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.settings.setValue("color_scheme", "")
self.style_select.setDisabled(False) self.style_select.setDisabled(False)
set_color_pallete("") set_color_pallete("")
self.interface_info.setVisible(True)
def on_style_select_changed(self, style): def on_style_select_changed(self, style):
if style: if style:
@ -215,7 +212,6 @@ class RareSettings(QWidget, Ui_RareSettings):
self.settings.setValue("style_sheet", "") self.settings.setValue("style_sheet", "")
self.color_select.setDisabled(False) self.color_select.setDisabled(False)
set_style_sheet("") set_style_sheet("")
self.interface_info.setVisible(True)
def open_dir(self): def open_dir(self):
if platform.system() == "Windows": if platform.system() == "Windows":
@ -230,7 +226,6 @@ class RareSettings(QWidget, Ui_RareSettings):
def update_lang(self, i: int): def update_lang(self, i: int):
self.settings.setValue("language", languages[i][0]) self.settings.setValue("language", languages[i][0])
self.interface_info.setVisible(True)
def init_checkboxes(self, checkboxes): def init_checkboxes(self, checkboxes):
for cb in checkboxes: for cb in checkboxes:

View file

@ -43,9 +43,9 @@ class LegendaryCLI(LegendaryCLIReal):
def unlock_installed(func): def unlock_installed(func):
@functools.wraps(func) @functools.wraps(func)
def unlock(self, *args, **kwargs): 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(): 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) # self.core.lgd._installed_lock.release(force=True)
try: try:
ret = func(self, *args, **kwargs) ret = func(self, *args, **kwargs)

View file

@ -3,6 +3,7 @@ import json
import logging import logging
import os import os
from multiprocessing import Queue from multiprocessing import Queue
from sys import platform as sys_platform
from uuid import uuid4 from uuid import uuid4
# On Windows the monkeypatching of `run_real` below doesn't work like on Linux # 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 legendary.models.manifest import ManifestMeta
from rare.lgndr.downloader.mp.manager import DLManager 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.glue.exception import LgndrException, LgndrLogHandler
from rare.lgndr.lfs.lgndry import LGDLFS
legendary.core.DLManager = DLManager legendary.core.DLManager = DLManager
legendary.core.LGDLFS = LGDLFS legendary.core.LGDLFS = LGDLFS
@ -30,6 +31,7 @@ class LegendaryCore(LegendaryCoreReal):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(LegendaryCore, self).__init__(*args, **kwargs) super(LegendaryCore, self).__init__(*args, **kwargs)
self.log.info("Using Rare's LegendaryCore monkey") self.log.info("Using Rare's LegendaryCore monkey")
self.log.info("Using config in %s", self.lgd.path.replace(os.getlogin(), "<username>"))
self.handler = LgndrLogHandler(logging.CRITICAL) self.handler = LgndrLogHandler(logging.CRITICAL)
self.log.addHandler(self.handler) self.log.addHandler(self.handler)
@ -37,9 +39,9 @@ class LegendaryCore(LegendaryCoreReal):
def unlock_installed(func): def unlock_installed(func):
@functools.wraps(func) @functools.wraps(func)
def unlock(self, *args, **kwargs): 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(): 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) # self.lgd._installed_lock.release(force=True)
try: try:
ret = func(self, *args, **kwargs) ret = func(self, *args, **kwargs)
@ -50,6 +52,18 @@ class LegendaryCore(LegendaryCoreReal):
return ret return ret
return unlock 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 # skip_sync defaults to false but since Rare is persistent, skip by default
# def get_installed_game(self, app_name, skip_sync=True) -> InstalledGame: # def get_installed_game(self, app_name, skip_sync=True) -> InstalledGame:
# return super(LegendaryCore, self).get_installed_game(app_name, skip_sync) # return super(LegendaryCore, self).get_installed_game(app_name, skip_sync)

View file

@ -18,6 +18,8 @@ def main() -> int:
sys.stderr = open(os.devnull, 'w') sys.stderr = open(os.devnull, 'w')
os.environ["QT_QPA_PLATFORMTHEME"] = "" 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 # fix cx_freeze
multiprocessing.freeze_support() multiprocessing.freeze_support()

View file

@ -97,15 +97,11 @@ class RareGameBase(QObject):
@property @property
def app_name(self) -> str: 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 @property
def app_title(self) -> str: def app_title(self) -> str:
return self.igame.title if self.igame is not None else self.game.app_title return self.game.app_title
@property
def title(self) -> str:
return self.app_title
@property @property
@abstractmethod @abstractmethod
@ -125,6 +121,10 @@ class RareGameBase(QObject):
""" """
return tuple(self.game.asset_infos.keys()) 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 @property
def is_mac(self) -> bool: def is_mac(self) -> bool:
"""! """!
@ -173,7 +173,7 @@ class RareGameBase(QObject):
@return str The current version of the game @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 @property
def install_path(self) -> Optional[str]: def install_path(self) -> Optional[str]:
@ -234,7 +234,7 @@ class RareGameSlim(RareGameBase):
status, (dt_local, dt_remote) = self.save_game_state status, (dt_local, dt_remote) = self.save_game_state
def _upload(): 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.state = RareGameSlim.State.SYNCING
self.core.upload_save(self.app_name, self.igame.save_path, dt_local) self.core.upload_save(self.app_name, self.igame.save_path, dt_local)
self.state = RareGameSlim.State.IDLE self.state = RareGameSlim.State.IDLE
@ -246,7 +246,7 @@ class RareGameSlim(RareGameBase):
logger.warning("Can't upload non existing save") logger.warning("Can't upload non existing save")
return return
if self.state == RareGameSlim.State.SYNCING: if self.state == RareGameSlim.State.SYNCING:
logger.error(f"{self.title} is already syncing") logger.error(f"{self.app_title} is already syncing")
return return
if thread: if thread:
@ -259,7 +259,7 @@ class RareGameSlim(RareGameBase):
status, (dt_local, dt_remote) = self.save_game_state status, (dt_local, dt_remote) = self.save_game_state
def _download(): 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.state = RareGameSlim.State.SYNCING
self.core.download_saves(self.app_name, self.latest_save.file.manifest_name, self.save_path) self.core.download_saves(self.app_name, self.latest_save.file.manifest_name, self.save_path)
self.state = RareGameSlim.State.IDLE self.state = RareGameSlim.State.IDLE
@ -271,7 +271,7 @@ class RareGameSlim(RareGameBase):
logger.error("Can't download non existing save") logger.error("Can't download non existing save")
return return
if self.state == RareGameSlim.State.SYNCING: if self.state == RareGameSlim.State.SYNCING:
logger.error(f"{self.title} is already syncing") logger.error(f"{self.app_title} is already syncing")
return return
if thread: if thread:

View file

@ -166,7 +166,8 @@ class RareGame(RareGameSlim):
def update_game(self): def update_game(self):
self.game = self.core.get_game( 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): def update_igame(self):
@ -228,7 +229,7 @@ class RareGame(RareGameSlim):
if self.igame is not None: if self.igame is not None:
return self.game.app_version(self.igame.platform) return self.game.app_version(self.igame.platform)
else: else:
return self.game.app_version() return self.game.app_version(self.default_platform)
@property @property
def has_update(self) -> bool: def has_update(self) -> bool:

View file

@ -70,15 +70,15 @@ class ImageSize:
DisplayWide = Preset(1, 1, Orientation.Wide, base=ImageWide) DisplayWide = Preset(1, 1, Orientation.Wide, base=ImageWide)
"""! @brief Size and pixel ratio for wide 16/9 image display""" """! @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""" """! @brief Same as Display"""
Small = Preset(3, 1, base=Image) Small = Preset(3, 1, base=Image)
"""! @brief Small image size for displaying""" """! @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""" """! @brief Small image size for displaying"""
Smaller = Preset(4, 1, base=Image) Smaller = Preset(4, 1, base=Image)

View file

@ -4,7 +4,7 @@ import time
from argparse import Namespace from argparse import Namespace
from itertools import chain from itertools import chain
from logging import getLogger 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 PyQt5.QtCore import QObject, pyqtSignal, QSettings, pyqtSlot, QThreadPool, QRunnable, QTimer
from legendary.lfs.eos import EOSOverlayApp from legendary.lfs.eos import EOSOverlayApp
@ -25,6 +25,7 @@ from .workers import (
) )
from .workers.uninstall import uninstall_game from .workers.uninstall import uninstall_game
from .workers.worker import QueueWorkerInfo, QueueWorkerState from .workers.worker import QueueWorkerInfo, QueueWorkerState
from rare.utils import config_helper
logger = getLogger("RareCore") logger = getLogger("RareCore")
@ -54,9 +55,10 @@ class RareCore(QObject):
self.args(args) self.args(args)
self.signals(init=True) self.signals(init=True)
self.core(init=True) self.core(init=True)
config_helper.init_config_handler(self.__core)
self.image_manager(init=True) self.image_manager(init=True)
self.settings = QSettings() self.settings = QSettings(self)
self.queue_workers: List[QueueWorker] = [] self.queue_workers: List[QueueWorker] = []
self.queue_threadpool = QThreadPool() self.queue_threadpool = QThreadPool()
@ -129,17 +131,44 @@ class RareCore(QObject):
try: try:
self.__core = LegendaryCore() self.__core = LegendaryCore()
except configparser.MissingSectionHeaderError as e: except configparser.MissingSectionHeaderError as e:
logger.warning(f"Config is corrupt: {e}") logger.warning("Config is corrupt: %s", e)
if config_path := os.environ.get("XDG_CONFIG_HOME"): if config_path := os.environ.get('LEGENDARY_CONFIG_PATH'):
path = os.path.join(config_path, "legendary") path = config_path
elif config_path := os.environ.get('XDG_CONFIG_HOME'):
path = os.path.join(config_path, 'legendary')
else: 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: with open(os.path.join(path, "config.ini"), "w") as config_file:
config_file.write("[Legendary]") config_file.write("[Legendary]")
self.__core = LegendaryCore() self.__core = LegendaryCore()
# Initialize sections if they don't exist
for section in ["Legendary", "default", "default.env"]: for section in ["Legendary", "default", "default.env"]:
if section not in self.__core.lgd.config.sections(): if section not in self.__core.lgd.config.sections():
self.__core.lgd.config.add_section(section) 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 # workaround if egl sync enabled, but no programdata_path
# programdata_path might be unset if logging in through the browser # programdata_path might be unset if logging in through the browser
if self.__core.egl_sync_enabled: if self.__core.egl_sync_enabled:
@ -148,6 +177,7 @@ class RareCore(QObject):
else: else:
if not os.path.exists(self.__core.egl.programdata_path): if not os.path.exists(self.__core.egl.programdata_path):
self.__core.lgd.config.remove_option("Legendary", "egl_sync") self.__core.lgd.config.remove_option("Legendary", "egl_sync")
self.__core.lgd.save_config() self.__core.lgd.save_config()
return self.__core return self.__core
@ -176,7 +206,9 @@ class RareCore(QObject):
del self.__args del self.__args
self.__args = None self.__args = None
del self.__eos_overlay # del self.__eos_overlay
self.__eos_overlay = None
RareCore.__instance = None RareCore.__instance = None
super(RareCore, self).deleteLater() super(RareCore, self).deleteLater()
@ -357,7 +389,7 @@ class RareCore(QObject):
yield game.game yield game.game
@property @property
def dlcs(self) -> Dict[str, Game]: def dlcs(self) -> Dict[str, set[RareGame]]:
"""! """!
RareGames that ARE DLCs themselves RareGames that ARE DLCs themselves
""" """

View file

@ -1,9 +1,10 @@
import platform
import time import time
from argparse import Namespace from argparse import Namespace
from enum import IntEnum from enum import IntEnum
from logging import getLogger from logging import getLogger
from PyQt5.QtCore import QObject, pyqtSignal from PyQt5.QtCore import QObject, pyqtSignal, QSettings
from requests.exceptions import ConnectionError, HTTPError from requests.exceptions import ConnectionError, HTTPError
from rare.lgndr.core import LegendaryCore from rare.lgndr.core import LegendaryCore
@ -27,19 +28,54 @@ class FetchWorker(Worker):
self.signals = FetchWorker.Signals() self.signals = FetchWorker.Signals()
self.core = core self.core = core
self.args = args self.args = args
self.settings = QSettings()
def run_real(self): def run_real(self):
# Fetch regular EGL games with assets # Fetch regular EGL games with assets
self.signals.progress.emit(0, self.signals.tr("Updating game metadata"))
start_time = time.time() 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( 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"Games {len(games)}, games with DLCs {len(dlc_dict)}")
logger.debug(f"Request games: {time.time() - start_time} seconds") logger.debug(f"Request games: {time.time() - start_time} seconds")
# Fetch non-asset games # 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() start_time = time.time()
try: try:
na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False) na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)

View file

@ -104,17 +104,17 @@ class OriginWineWorker(QRunnable):
if install_dir: if install_dir:
logger.debug("Found Unix install directory %s", install_dir) logger.debug("Found Unix install directory %s", install_dir)
else: 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: 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 install_dir:
if os.path.isdir(install_dir): if os.path.isdir(install_dir):
install_size = path_size(install_dir) install_size = path_size(install_dir)
rgame.set_origin_attributes(install_dir, install_size) 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: 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: 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) logger.info("Origin worker finished in %ss", time.time() - t)

View file

@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ImportGroup(object): class Ui_ImportGroup(object):
def setupUi(self, ImportGroup): def setupUi(self, ImportGroup):
ImportGroup.setObjectName("ImportGroup") ImportGroup.setObjectName("ImportGroup")
ImportGroup.resize(506, 184) ImportGroup.resize(651, 218)
ImportGroup.setWindowTitle("ImportGroup") ImportGroup.setWindowTitle("ImportGroup")
ImportGroup.setWindowFilePath("") ImportGroup.setWindowFilePath("")
self.import_layout = QtWidgets.QFormLayout(ImportGroup) 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_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label)
self.import_folder_label = QtWidgets.QLabel(ImportGroup) self.import_folder_label = QtWidgets.QLabel(ImportGroup)
self.import_folder_label.setObjectName("import_folder_label") 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) self.import_folder_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont() font = QtGui.QFont()
font.setItalic(True) font.setItalic(True)
self.import_folder_check.setFont(font) self.import_folder_check.setFont(font)
self.import_folder_check.setObjectName("import_folder_check") 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 = QtWidgets.QLabel(ImportGroup)
self.import_dlcs_label.setObjectName("import_dlcs_label") 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) self.import_dlcs_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont() font = QtGui.QFont()
font.setItalic(True) font.setItalic(True)
self.import_dlcs_check.setFont(font) self.import_dlcs_check.setFont(font)
self.import_dlcs_check.setObjectName("import_dlcs_check") 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 = QtWidgets.QLabel(ImportGroup)
self.import_button_label.setText("Error") self.import_button_label.setText("Error")
self.import_button_label.setObjectName("import_button_label") 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 = QtWidgets.QHBoxLayout()
self.button_info_layout.setObjectName("button_info_layout") self.button_info_layout.setObjectName("button_info_layout")
self.import_button = QtWidgets.QPushButton(ImportGroup) self.import_button = QtWidgets.QPushButton(ImportGroup)
@ -58,16 +67,27 @@ class Ui_ImportGroup(object):
self.import_button.setSizePolicy(sizePolicy) self.import_button.setSizePolicy(sizePolicy)
self.import_button.setObjectName("import_button") self.import_button.setObjectName("import_button")
self.button_info_layout.addWidget(self.import_button) self.button_info_layout.addWidget(self.import_button)
self.import_layout.setLayout(5, QtWidgets.QFormLayout.FieldRole, self.button_info_layout) self.import_layout.setLayout(6, QtWidgets.QFormLayout.FieldRole, self.button_info_layout)
self.import_force_label = QtWidgets.QLabel(ImportGroup) self.platform_label = QtWidgets.QLabel(ImportGroup)
self.import_force_label.setObjectName("import_force_label") self.platform_label.setObjectName("platform_label")
self.import_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.import_force_label) self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.platform_label)
self.import_force_check = QtWidgets.QCheckBox(ImportGroup) 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 = QtGui.QFont()
font.setItalic(True) font.setItalic(True)
self.import_force_check.setFont(font) self.platform_tooltip.setFont(font)
self.import_force_check.setObjectName("import_force_check") self.platform_tooltip.setObjectName("platform_tooltip")
self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_force_check) self.platform_layout.addWidget(self.platform_tooltip)
self.import_layout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.platform_layout)
self.retranslateUi(ImportGroup) 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_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_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_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_label.setText(_translate("ImportGroup", "Force import"))
self.import_force_check.setText(_translate("ImportGroup", "Import game despite missing files")) 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__": if __name__ == "__main__":

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>506</width> <width>651</width>
<height>184</height> <height>218</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -37,14 +37,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="3" column="0">
<widget class="QLabel" name="import_folder_label"> <widget class="QLabel" name="import_folder_label">
<property name="text"> <property name="text">
<string>Import all folders</string> <string>Import all folders</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="3" column="1">
<widget class="QCheckBox" name="import_folder_check"> <widget class="QCheckBox" name="import_folder_check">
<property name="font"> <property name="font">
<font> <font>
@ -56,14 +56,14 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="4" column="0">
<widget class="QLabel" name="import_dlcs_label"> <widget class="QLabel" name="import_dlcs_label">
<property name="text"> <property name="text">
<string>Import DLCs</string> <string>Import DLCs</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="4" column="1">
<widget class="QCheckBox" name="import_dlcs_check"> <widget class="QCheckBox" name="import_dlcs_check">
<property name="font"> <property name="font">
<font> <font>
@ -76,13 +76,32 @@
</widget> </widget>
</item> </item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QLabel" name="import_force_label">
<property name="text">
<string>Force import</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QCheckBox" name="import_force_check">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Import game despite missing files</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QLabel" name="import_button_label"> <widget class="QLabel" name="import_button_label">
<property name="text"> <property name="text">
<string notr="true">Error</string> <string notr="true">Error</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="6" column="1">
<layout class="QHBoxLayout" name="button_info_layout"> <layout class="QHBoxLayout" name="button_info_layout">
<item> <item>
<widget class="QPushButton" name="import_button"> <widget class="QPushButton" name="import_button">
@ -99,24 +118,38 @@
</item> </item>
</layout> </layout>
</item> </item>
<item row="4" column="0"> <item row="2" column="0">
<widget class="QLabel" name="import_force_label"> <widget class="QLabel" name="platform_label">
<property name="text"> <property name="text">
<string>Force import</string> <string>Platform</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1"> <item row="2" column="1">
<widget class="QCheckBox" name="import_force_check"> <layout class="QHBoxLayout" name="platform_layout">
<property name="font"> <item>
<font> <widget class="QComboBox" name="platform_combo">
<italic>true</italic> <property name="sizePolicy">
</font> <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
</property> <horstretch>0</horstretch>
<property name="text"> <verstretch>0</verstretch>
<string>Import game despite missing files</string> </sizepolicy>
</property> </property>
</widget> </widget>
</item>
<item>
<widget class="QLabel" name="platform_tooltip">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Select the native platform of the game</string>
</property>
</widget>
</item>
</layout>
</item> </item>
</layout> </layout>
</widget> </widget>

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.ui' # 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 # 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. # 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): class Ui_LegendarySettings(object):
def setupUi(self, LegendarySettings): def setupUi(self, LegendarySettings):
LegendarySettings.setObjectName("LegendarySettings") LegendarySettings.setObjectName("LegendarySettings")
LegendarySettings.resize(595, 334) LegendarySettings.resize(681, 456)
LegendarySettings.setWindowTitle("LegendarySettings") LegendarySettings.setWindowTitle("LegendarySettings")
self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings) self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings)
self.legendary_layout.setObjectName("legendary_layout") 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 = QtWidgets.QPushButton(self.cleanup_group)
self.clean_button.setObjectName("clean_button") self.clean_button.setObjectName("clean_button")
self.cleanup_layout.addWidget(self.clean_button) self.cleanup_layout.addWidget(self.clean_button)
self.right_layout.addWidget(self.cleanup_group, 0, QtCore.Qt.AlignTop) self.right_layout.addWidget(self.cleanup_group)
self.meta_group = QtWidgets.QGroupBox(LegendarySettings) self.metadata_group = QtWidgets.QGroupBox(LegendarySettings)
self.meta_group.setObjectName("meta_group") self.metadata_group.setObjectName("metadata_group")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.meta_group) self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.metadata_group)
self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout_2.setObjectName("verticalLayout_2")
self.win32_cb = QtWidgets.QCheckBox(self.meta_group) self.fetch_win32_check = QtWidgets.QCheckBox(self.metadata_group)
self.win32_cb.setObjectName("win32_cb") self.fetch_win32_check.setObjectName("fetch_win32_check")
self.verticalLayout_2.addWidget(self.win32_cb) self.verticalLayout_2.addWidget(self.fetch_win32_check)
self.mac_cb = QtWidgets.QCheckBox(self.meta_group) self.fetch_macos_check = QtWidgets.QCheckBox(self.metadata_group)
self.mac_cb.setObjectName("mac_cb") self.fetch_macos_check.setObjectName("fetch_macos_check")
self.verticalLayout_2.addWidget(self.mac_cb) self.verticalLayout_2.addWidget(self.fetch_macos_check)
self.refresh_game_meta_btn = QtWidgets.QPushButton(self.meta_group) self.fetch_unreal_check = QtWidgets.QCheckBox(self.metadata_group)
self.refresh_game_meta_btn.setObjectName("refresh_game_meta_btn") self.fetch_unreal_check.setObjectName("fetch_unreal_check")
self.verticalLayout_2.addWidget(self.refresh_game_meta_btn) self.verticalLayout_2.addWidget(self.fetch_unreal_check)
self.right_layout.addWidget(self.meta_group) 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) spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.right_layout.addItem(spacerItem1) self.right_layout.addItem(spacerItem1)
self.legendary_layout.addLayout(self.right_layout) self.legendary_layout.addLayout(self.right_layout)
@ -148,11 +157,11 @@ class Ui_LegendarySettings(object):
def retranslateUi(self, LegendarySettings): def retranslateUi(self, LegendarySettings):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
self.install_dir_group.setTitle(_translate("LegendarySettings", "Default Installation Directory")) self.install_dir_group.setTitle(_translate("LegendarySettings", "Default installation folder"))
self.download_group.setTitle(_translate("LegendarySettings", "Download Settings")) self.download_group.setTitle(_translate("LegendarySettings", "Download settings"))
self.max_workers_label.setText(_translate("LegendarySettings", "Max Workers")) self.max_workers_label.setText(_translate("LegendarySettings", "Max sorkers"))
self.max_workers_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)")) 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_spin.setSuffix(_translate("LegendarySettings", "MiB"))
self.max_memory_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)")) self.max_memory_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)"))
self.preferred_cdn_label.setText(_translate("LegendarySettings", "Preferred CDN")) 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.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup"))
self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests")) self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests"))
self.clean_button.setText(_translate("LegendarySettings", "Remove everything")) self.clean_button.setText(_translate("LegendarySettings", "Remove everything"))
self.meta_group.setTitle(_translate("LegendarySettings", "Game metadata")) self.metadata_group.setTitle(_translate("LegendarySettings", "Platforms"))
self.win32_cb.setText(_translate("LegendarySettings", "Load 32bit data")) self.fetch_win32_check.setText(_translate("LegendarySettings", "Include Win32 games"))
self.mac_cb.setText(_translate("LegendarySettings", "Load MacOS data")) self.fetch_macos_check.setText(_translate("LegendarySettings", "Include macOS games"))
self.refresh_game_meta_btn.setText(_translate("LegendarySettings", "Refresh game meta")) 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__": if __name__ == "__main__":

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>595</width> <width>681</width>
<height>334</height> <height>456</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -19,7 +19,7 @@
<item alignment="Qt::AlignTop"> <item alignment="Qt::AlignTop">
<widget class="QGroupBox" name="install_dir_group"> <widget class="QGroupBox" name="install_dir_group">
<property name="title"> <property name="title">
<string>Default Installation Directory</string> <string>Default installation folder</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -30,7 +30,7 @@
<item alignment="Qt::AlignTop"> <item alignment="Qt::AlignTop">
<widget class="QGroupBox" name="download_group"> <widget class="QGroupBox" name="download_group">
<property name="title"> <property name="title">
<string>Download Settings</string> <string>Download settings</string>
</property> </property>
<property name="alignment"> <property name="alignment">
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
@ -48,7 +48,7 @@
</sizepolicy> </sizepolicy>
</property> </property>
<property name="text"> <property name="text">
<string>Max Workers</string> <string>Max sorkers</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -90,7 +90,7 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="max_memory_label"> <widget class="QLabel" name="max_memory_label">
<property name="text"> <property name="text">
<string>Max Shared Memory</string> <string>Max shared memory</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -200,7 +200,7 @@
<layout class="QVBoxLayout" name="locale_layout"/> <layout class="QVBoxLayout" name="locale_layout"/>
</widget> </widget>
</item> </item>
<item alignment="Qt::AlignTop"> <item>
<widget class="QGroupBox" name="cleanup_group"> <widget class="QGroupBox" name="cleanup_group">
<property name="title"> <property name="title">
<string>Cleanup</string> <string>Cleanup</string>
@ -227,29 +227,48 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QGroupBox" name="meta_group"> <widget class="QGroupBox" name="metadata_group">
<property name="title"> <property name="title">
<string>Game metadata</string> <string>Platforms</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item> <item>
<widget class="QCheckBox" name="win32_cb"> <widget class="QCheckBox" name="fetch_win32_check">
<property name="text"> <property name="text">
<string>Load 32bit data</string> <string>Include Win32 games</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QCheckBox" name="mac_cb"> <widget class="QCheckBox" name="fetch_macos_check">
<property name="text"> <property name="text">
<string>Load MacOS data</string> <string>Include macOS games</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="refresh_game_meta_btn"> <widget class="QCheckBox" name="fetch_unreal_check">
<property name="text"> <property name="text">
<string>Refresh game meta</string> <string>Include Unreal engine</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="metadata_info">
<property name="font">
<font>
<italic>true</italic>
</font>
</property>
<property name="text">
<string>Restart Rare to apply</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="refresh_metadata_button">
<property name="text">
<string>Refresh metadata</string>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/rare.ui' # 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 # 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. # 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): class Ui_RareSettings(object):
def setupUi(self, RareSettings): def setupUi(self, RareSettings):
RareSettings.setObjectName("RareSettings") RareSettings.setObjectName("RareSettings")
RareSettings.resize(517, 434) RareSettings.resize(623, 428)
RareSettings.setWindowTitle("RareSettings") RareSettings.setWindowTitle("RareSettings")
self.rare_layout = QtWidgets.QHBoxLayout(RareSettings) self.rare_layout = QtWidgets.QHBoxLayout(RareSettings)
self.rare_layout.setObjectName("rare_layout") self.rare_layout.setObjectName("rare_layout")
@ -148,25 +148,25 @@ class Ui_RareSettings(object):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
self.interface_group.setTitle(_translate("RareSettings", "Interface")) self.interface_group.setTitle(_translate("RareSettings", "Interface"))
self.lang_label.setText(_translate("RareSettings", "Language")) 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.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.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.settings_group.setTitle(_translate("RareSettings", "Behavior"))
self.save_size.setText(_translate("RareSettings", "Restore window size on application startup")) self.save_size.setText(_translate("RareSettings", "Restore window size on application startup"))
self.notification.setText(_translate("RareSettings", "Show notification on download completion")) self.notification.setText(_translate("RareSettings", "Show notifications when downloads complete"))
self.log_games.setText(_translate("RareSettings", "Show console for game debug")) self.log_games.setText(_translate("RareSettings", "Show console windows when launching games"))
self.sys_tray.setText(_translate("RareSettings", "Exit to System tray")) self.sys_tray.setText(_translate("RareSettings", "Exit to system tray"))
self.auto_update.setText(_translate("RareSettings", "Update games on application startup")) self.auto_update.setText(_translate("RareSettings", "Queue game updates on application startup"))
self.confirm_start.setText(_translate("RareSettings", "Confirm game launch")) self.confirm_start.setText(_translate("RareSettings", "Confirm before launching games"))
self.auto_sync_cloud.setText(_translate("RareSettings", "Automatically sync with cloud")) self.auto_sync_cloud.setText(_translate("RareSettings", "Automatically upload/download cloud saves"))
self.log_dir_group.setTitle(_translate("RareSettings", "Logs")) self.log_dir_group.setTitle(_translate("RareSettings", "Logs"))
self.log_dir_open_button.setText(_translate("RareSettings", "Open Log directory")) self.log_dir_open_button.setText(_translate("RareSettings", "Open log folder"))
self.log_dir_clean_button.setText(_translate("RareSettings", "Clean Log directory")) self.log_dir_clean_button.setText(_translate("RareSettings", "Clean log folder"))
self.groupBox.setTitle(_translate("RareSettings", "Shortcuts")) self.groupBox.setTitle(_translate("RareSettings", "Shortcuts"))
self.desktop_link_btn.setText(_translate("RareSettings", "Create Desktop link")) self.desktop_link_btn.setText(_translate("RareSettings", "Create on desktop"))
self.startmenu_link_btn.setText(_translate("RareSettings", "Create start menu link")) self.startmenu_link_btn.setText(_translate("RareSettings", "Create in menu"))
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -6,8 +6,8 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>517</width> <width>623</width>
<height>434</height> <height>428</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -51,7 +51,7 @@
<item row="1" column="0"> <item row="1" column="0">
<widget class="QLabel" name="color_label"> <widget class="QLabel" name="color_label">
<property name="text"> <property name="text">
<string>Color Scheme</string> <string>Color scheme</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -73,7 +73,7 @@
<item row="2" column="0"> <item row="2" column="0">
<widget class="QLabel" name="style_label"> <widget class="QLabel" name="style_label">
<property name="text"> <property name="text">
<string>Style Sheet</string> <string>Style sheet</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -100,7 +100,7 @@
</font> </font>
</property> </property>
<property name="text"> <property name="text">
<string>Restart Rare to apply.</string> <string>Restart Rare to apply changes.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@ -126,42 +126,42 @@
<item row="4" column="0"> <item row="4" column="0">
<widget class="QCheckBox" name="notification"> <widget class="QCheckBox" name="notification">
<property name="text"> <property name="text">
<string>Show notification on download completion</string> <string>Show notifications when downloads complete</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="0"> <item row="6" column="0">
<widget class="QCheckBox" name="log_games"> <widget class="QCheckBox" name="log_games">
<property name="text"> <property name="text">
<string>Show console for game debug</string> <string>Show console windows when launching games</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="0" column="0"> <item row="0" column="0">
<widget class="QCheckBox" name="sys_tray"> <widget class="QCheckBox" name="sys_tray">
<property name="text"> <property name="text">
<string>Exit to System tray</string> <string>Exit to system tray</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="auto_update"> <widget class="QCheckBox" name="auto_update">
<property name="text"> <property name="text">
<string>Update games on application startup</string> <string>Queue game updates on application startup</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="confirm_start"> <widget class="QCheckBox" name="confirm_start">
<property name="text"> <property name="text">
<string>Confirm game launch</string> <string>Confirm before launching games</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="3" column="0">
<widget class="QCheckBox" name="auto_sync_cloud"> <widget class="QCheckBox" name="auto_sync_cloud">
<property name="text"> <property name="text">
<string>Automatically sync with cloud</string> <string>Automatically upload/download cloud saves</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -207,14 +207,14 @@
<item> <item>
<widget class="QPushButton" name="log_dir_open_button"> <widget class="QPushButton" name="log_dir_open_button">
<property name="text"> <property name="text">
<string>Open Log directory</string> <string>Open log folder</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="log_dir_clean_button"> <widget class="QPushButton" name="log_dir_clean_button">
<property name="text"> <property name="text">
<string>Clean Log directory</string> <string>Clean log folder</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -246,14 +246,14 @@
<item> <item>
<widget class="QPushButton" name="desktop_link_btn"> <widget class="QPushButton" name="desktop_link_btn">
<property name="text"> <property name="text">
<string>Create Desktop link</string> <string>Create on desktop</string>
</property> </property>
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QPushButton" name="startmenu_link_btn"> <widget class="QPushButton" name="startmenu_link_btn">
<property name="text"> <property name="text">
<string>Create start menu link</string> <string>Create in menu</string>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -1,33 +1,55 @@
from typing import Optional from typing import Optional, List, overload
from PyQt5.QtCore import ( from PyQt5.QtCore import Qt, QRect, QSize, QPoint
Qt, from PyQt5.QtWidgets import QLayout, QStyle, QSizePolicy, QLayoutItem, QWidget
QRect,
QSize,
QPoint,
)
from PyQt5.QtWidgets import (
QLayout,
QStyle,
QSizePolicy,
QLayoutItem,
)
class FlowLayout(QLayout): class FlowLayout(QLayout):
def __init__(self, parent=None, margin=-1, hspacing=-1, vspacing=-1): def __init__(self, parent=None):
super(FlowLayout, self).__init__(parent) 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.setObjectName(type(self).__name__)
self._hspacing = -1
self._vspacing = -1
self._items: List[QLayoutItem] = []
def __del__(self): def __del__(self):
del self._items[:] 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: def addItem(self, a0: QLayoutItem) -> None:
self._items.append(a0) 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): def horizontalSpacing(self):
if self._hspacing >= 0: if self._hspacing >= 0:
@ -35,6 +57,10 @@ class FlowLayout(QLayout):
else: else:
return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing) return self.smartSpacing(QStyle.PM_LayoutHorizontalSpacing)
def setVerticalSpacing(self, a0: int) -> None:
self._vspacing = a0
self.invalidate()
def verticalSpacing(self): def verticalSpacing(self):
if self._vspacing >= 0: if self._vspacing >= 0:
return self._vspacing return self._vspacing
@ -51,11 +77,14 @@ class FlowLayout(QLayout):
def takeAt(self, index: int) -> Optional[QLayoutItem]: def takeAt(self, index: int) -> Optional[QLayoutItem]:
if 0 <= index < len(self._items): if 0 <= index < len(self._items):
return self._items.pop(index) item = self._items.pop(index)
self.invalidate()
return item
return None return None
def expandingDirections(self) -> Qt.Orientations: 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: def hasHeightForWidth(self) -> bool:
return True return True
@ -93,8 +122,6 @@ class FlowLayout(QLayout):
if item.isEmpty(): if item.isEmpty():
continue continue
widget = item.widget() widget = item.widget()
if not widget.isVisible():
continue
hspace = self.horizontalSpacing() hspace = self.horizontalSpacing()
if hspace == -1: if hspace == -1:
hspace = widget.style().layoutSpacing( hspace = widget.style().layoutSpacing(

View file

@ -4,7 +4,6 @@ from logging import getLogger
from typing import Callable, Tuple, Optional, Dict, List from typing import Callable, Tuple, Optional, Dict, List
from PyQt5.QtCore import ( from PyQt5.QtCore import (
Qt,
QSize, QSize,
pyqtSignal, pyqtSignal,
QFileInfo, QFileInfo,
@ -135,7 +134,8 @@ class IndicatorLineEdit(QWidget):
# Add line_edit # Add line_edit
self.line_edit = QLineEdit(self) self.line_edit = QLineEdit(self)
self.line_edit.setObjectName(f"{type(self).__name__}Edit") 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) self.line_edit.setSizePolicy(horiz_policy, QSizePolicy.Fixed)
# Add completer # Add completer
self.setCompleter(completer) self.setCompleter(completer)

View file

@ -1,23 +1,18 @@
from typing import Callable from typing import Callable
from PyQt5.QtCore import ( from PyQt5.QtCore import Qt, QRect, QPoint
Qt, from PyQt5.QtWidgets import QSizePolicy
QRect,
QPoint,
)
from PyQt5.QtWidgets import (
QSizePolicy,
)
from .flow_layout import FlowLayout from .flow_layout import FlowLayout
class LibraryLayout(FlowLayout): class LibraryLayout(FlowLayout):
def __init__(self, parent=None, margin=6, spacing=11): def __init__(self, parent=None):
super(LibraryLayout, self).__init__(parent=parent, margin=margin, hspacing=spacing, vspacing=spacing) super(LibraryLayout, self).__init__(parent)
def expandingDirections(self) -> Qt.Orientations: 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: def setGeometry(self, a0: QRect) -> None:
super(FlowLayout, self).setGeometry(a0) super(FlowLayout, self).setGeometry(a0)
@ -127,4 +122,4 @@ class LibraryLayout(FlowLayout):
def sort(self, key: Callable, reverse=False) -> None: def sort(self, key: Callable, reverse=False) -> None:
self._items.sort(key=key, reverse=reverse) self._items.sort(key=key, reverse=reverse)
self.setGeometry(self.parent().contentsRect()) self.setGeometry(self.parent().contentsRect().adjusted(*self.parent().getContentsMargins()))