1
0
Fork 0
mirror of synced 2024-05-24 14:29:58 +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
name: Rare
icon: Rare
version: 1.10.7
version: 1.10.9
exec: usr/bin/python3
exec_args: $APPDIR/usr/src/rare/main.py $@
apt:

View file

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

View file

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

View file

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

View file

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

View file

@ -346,5 +346,5 @@ class DownloadsTab(QWidget):
@pyqtSlot(RareGame, bool, str)
def __on_uninstall_worker_result(self, rgame: RareGame, success: bool, message: str):
if not success:
QMessageBox.warning(None, self.tr("Uninstall - {}").format(rgame.title), message, QMessageBox.Close)
QMessageBox.warning(None, self.tr("Uninstall - {}").format(rgame.app_title), message, QMessageBox.Close)
rgame.state = RareGame.State.IDLE

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -43,9 +43,9 @@ class LegendaryCLI(LegendaryCLIReal):
def unlock_installed(func):
@functools.wraps(func)
def unlock(self, *args, **kwargs):
self.logger.debug("Using unlock decorator")
self.logger.debug("%s: Using unlock decorator", func.__name__)
if not self.core.lgd.lock_installed():
self.logger.info("Data is locked, trying to forcufully release it")
self.logger.info("Data is locked, trying to forcefully release it")
# self.core.lgd._installed_lock.release(force=True)
try:
ret = func(self, *args, **kwargs)

View file

@ -3,6 +3,7 @@ import json
import logging
import os
from multiprocessing import Queue
from sys import platform as sys_platform
from uuid import uuid4
# On Windows the monkeypatching of `run_real` below doesn't work like on Linux
@ -17,8 +18,8 @@ from legendary.models.game import Game, InstalledGame
from legendary.models.manifest import ManifestMeta
from rare.lgndr.downloader.mp.manager import DLManager
from rare.lgndr.lfs.lgndry import LGDLFS
from rare.lgndr.glue.exception import LgndrException, LgndrLogHandler
from rare.lgndr.lfs.lgndry import LGDLFS
legendary.core.DLManager = DLManager
legendary.core.LGDLFS = LGDLFS
@ -30,6 +31,7 @@ class LegendaryCore(LegendaryCoreReal):
def __init__(self, *args, **kwargs):
super(LegendaryCore, self).__init__(*args, **kwargs)
self.log.info("Using Rare's LegendaryCore monkey")
self.log.info("Using config in %s", self.lgd.path.replace(os.getlogin(), "<username>"))
self.handler = LgndrLogHandler(logging.CRITICAL)
self.log.addHandler(self.handler)
@ -37,9 +39,9 @@ class LegendaryCore(LegendaryCoreReal):
def unlock_installed(func):
@functools.wraps(func)
def unlock(self, *args, **kwargs):
self.log.debug("Using unlock decorator")
self.log.debug("%s: Using unlock decorator", func.__name__)
if not self.lgd.lock_installed():
self.log.info("Data is locked, trying to forcufully release it")
self.log.info("Data is locked, trying to forcefully release it")
# self.lgd._installed_lock.release(force=True)
try:
ret = func(self, *args, **kwargs)
@ -50,6 +52,18 @@ class LegendaryCore(LegendaryCoreReal):
return ret
return unlock
@property
def default_platform(self) -> str:
os_default = "Mac" if sys_platform == "darwin" else "Windows"
usr_platform = self.lgd.config.get("Legendary", "default_platform", fallback=os_default)
return usr_platform if usr_platform in ("Windows", "Win32", "Mac") else os_default
def update_check_enabled(self):
return False
def update_notice_enabled(self):
return False
# skip_sync defaults to false but since Rare is persistent, skip by default
# def get_installed_game(self, app_name, skip_sync=True) -> InstalledGame:
# return super(LegendaryCore, self).get_installed_game(app_name, skip_sync)

View file

@ -18,6 +18,8 @@ def main() -> int:
sys.stderr = open(os.devnull, 'w')
os.environ["QT_QPA_PLATFORMTHEME"] = ""
if "LEGENDARY_CONFIG_PATH" in os.environ:
os.environ["LEGENDARY_CONFIG_PATH"] = os.path.expanduser(os.environ["LEGENDARY_CONFIG_PATH"])
# fix cx_freeze
multiprocessing.freeze_support()

View file

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

View file

@ -166,7 +166,8 @@ class RareGame(RareGameSlim):
def update_game(self):
self.game = self.core.get_game(
self.app_name, update_meta=False, platform=self.igame.platform if self.igame else "Windows"
self.app_name, update_meta=False,
platform=self.igame.platform if self.igame else self.default_platform
)
def update_igame(self):
@ -228,7 +229,7 @@ class RareGame(RareGameSlim):
if self.igame is not None:
return self.game.app_version(self.igame.platform)
else:
return self.game.app_version()
return self.game.app_version(self.default_platform)
@property
def has_update(self) -> bool:

View file

@ -70,15 +70,15 @@ class ImageSize:
DisplayWide = Preset(1, 1, Orientation.Wide, base=ImageWide)
"""! @brief Size and pixel ratio for wide 16/9 image display"""
Wide = DisplayWide
LibraryWide = Preset(1.21, 1, Orientation.Wide, base=ImageWide)
Normal = Display
Library = Preset(1.21, 1, base=Image)
"""! @brief Same as Display"""
Small = Preset(3, 1, base=Image)
"""! @brief Small image size for displaying"""
SmallWide = Preset(1, 1, Orientation.Wide, base=ImageWide)
SmallWide = Preset(3, 1, Orientation.Wide, base=ImageWide)
"""! @brief Small image size for displaying"""
Smaller = Preset(4, 1, base=Image)

View file

@ -4,7 +4,7 @@ import time
from argparse import Namespace
from itertools import chain
from logging import getLogger
from typing import Dict, Iterator, Callable, Optional, List, Union, Iterable, Tuple
from typing import Dict, Iterator, Callable, Optional, List, Union, Iterable, Tuple, Set
from PyQt5.QtCore import QObject, pyqtSignal, QSettings, pyqtSlot, QThreadPool, QRunnable, QTimer
from legendary.lfs.eos import EOSOverlayApp
@ -25,6 +25,7 @@ from .workers import (
)
from .workers.uninstall import uninstall_game
from .workers.worker import QueueWorkerInfo, QueueWorkerState
from rare.utils import config_helper
logger = getLogger("RareCore")
@ -54,9 +55,10 @@ class RareCore(QObject):
self.args(args)
self.signals(init=True)
self.core(init=True)
config_helper.init_config_handler(self.__core)
self.image_manager(init=True)
self.settings = QSettings()
self.settings = QSettings(self)
self.queue_workers: List[QueueWorker] = []
self.queue_threadpool = QThreadPool()
@ -129,17 +131,44 @@ class RareCore(QObject):
try:
self.__core = LegendaryCore()
except configparser.MissingSectionHeaderError as e:
logger.warning(f"Config is corrupt: {e}")
if config_path := os.environ.get("XDG_CONFIG_HOME"):
path = os.path.join(config_path, "legendary")
logger.warning("Config is corrupt: %s", e)
if config_path := os.environ.get('LEGENDARY_CONFIG_PATH'):
path = config_path
elif config_path := os.environ.get('XDG_CONFIG_HOME'):
path = os.path.join(config_path, 'legendary')
else:
path = os.path.expanduser("~/.config/legendary")
path = os.path.expanduser('~/.config/legendary')
logger.info("Creating config in path: %s", config_path)
with open(os.path.join(path, "config.ini"), "w") as config_file:
config_file.write("[Legendary]")
self.__core = LegendaryCore()
# Initialize sections if they don't exist
for section in ["Legendary", "default", "default.env"]:
if section not in self.__core.lgd.config.sections():
self.__core.lgd.config.add_section(section)
# Set some platform defaults if unset
def check_config(option: str, accepted: Set = None) -> bool:
_exists = self.__core.lgd.config.has_option("Legendary", option)
_value = self.__core.lgd.config.get("Legendary", option, fallback="")
_accepted = _value in accepted if accepted is not None else True
return _exists and bool(_value) and _accepted
if not check_config("default_platform", {"Windows", "Win32", "Mac"}):
self.__core.lgd.config.set("Legendary", "default_platform", self.__core.default_platform)
if not check_config("install_dir"):
self.__core.lgd.config.set(
"Legendary", "install_dir", self.__core.get_default_install_dir()
)
if not check_config("mac_install_dir"):
self.__core.lgd.config.set(
"Legendary", "mac_install_dir", self.__core.get_default_install_dir(self.__core.default_platform)
)
# Always set these options
# Avoid falling back to Windows games on macOS
self.__core.lgd.config.set("Legendary", "install_platform_fallback", 'false')
# workaround if egl sync enabled, but no programdata_path
# programdata_path might be unset if logging in through the browser
if self.__core.egl_sync_enabled:
@ -148,6 +177,7 @@ class RareCore(QObject):
else:
if not os.path.exists(self.__core.egl.programdata_path):
self.__core.lgd.config.remove_option("Legendary", "egl_sync")
self.__core.lgd.save_config()
return self.__core
@ -176,7 +206,9 @@ class RareCore(QObject):
del self.__args
self.__args = None
del self.__eos_overlay
# del self.__eos_overlay
self.__eos_overlay = None
RareCore.__instance = None
super(RareCore, self).deleteLater()
@ -357,7 +389,7 @@ class RareCore(QObject):
yield game.game
@property
def dlcs(self) -> Dict[str, Game]:
def dlcs(self) -> Dict[str, set[RareGame]]:
"""!
RareGames that ARE DLCs themselves
"""

View file

@ -1,9 +1,10 @@
import platform
import time
from argparse import Namespace
from enum import IntEnum
from logging import getLogger
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtCore import QObject, pyqtSignal, QSettings
from requests.exceptions import ConnectionError, HTTPError
from rare.lgndr.core import LegendaryCore
@ -27,19 +28,54 @@ class FetchWorker(Worker):
self.signals = FetchWorker.Signals()
self.core = core
self.args = args
self.settings = QSettings()
def run_real(self):
# Fetch regular EGL games with assets
self.signals.progress.emit(0, self.signals.tr("Updating game metadata"))
start_time = time.time()
want_unreal = self.settings.value("unreal_meta", False, bool) or self.args.debug
want_win32 = self.settings.value("win32_meta", False, bool)
want_macos = self.settings.value("macos_meta", False, bool)
need_macos = platform.system() == "Darwin"
need_windows = not any([want_win32, want_macos, need_macos, self.args.debug])
if want_win32 or self.args.debug:
logger.info(
"Requesting Win32 metadata due to %s, %s Unreal engine",
"settings" if want_win32 else "debug",
"with" if want_unreal else "without"
)
self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
self.core.get_game_and_dlc_list(
update_assets=not self.args.offline, platform="Win32", skip_ue=not want_unreal
)
if need_macos or want_macos or self.args.debug:
logger.info(
"Requesting macOS metadata due to %s, %s Unreal engine",
"platform" if need_macos else "settings" if want_macos else "debug",
"with" if want_unreal else "without"
)
self.signals.progress.emit(15, self.signals.tr("Updating game metadata for macOS"))
self.core.get_game_and_dlc_list(
update_assets=not self.args.offline, platform="Mac", skip_ue=not want_unreal
)
if need_windows:
self.signals.progress.emit(00, self.signals.tr("Updating game metadata for Windows"))
logger.info(
"Requesting Windows metadata, %s Unreal engine",
"with" if want_unreal else "without"
)
games, dlc_dict = self.core.get_game_and_dlc_list(
update_assets=not self.args.offline, platform="Windows", skip_ue=False
update_assets=need_windows, platform="Windows", skip_ue=not want_unreal
)
logger.debug(f"Games {len(games)}, games with DLCs {len(dlc_dict)}")
logger.debug(f"Request games: {time.time() - start_time} seconds")
# Fetch non-asset games
self.signals.progress.emit(10, self.signals.tr("Updating non-asset metadata"))
self.signals.progress.emit(30, self.signals.tr("Updating non-asset game metadata"))
start_time = time.time()
try:
na_games, na_dlc_dict = self.core.get_non_asset_library_items(force_refresh=False, skip_ue=False)

View file

@ -104,17 +104,17 @@ class OriginWineWorker(QRunnable):
if install_dir:
logger.debug("Found Unix install directory %s", install_dir)
else:
logger.info("Could not find Unix install directory for %s", rgame.title)
logger.info("Could not find Unix install directory for %s", rgame.app_title)
else:
logger.info("Could not find Wine install directory for %s", rgame.title)
logger.info("Could not find Wine install directory for %s", rgame.app_title)
if install_dir:
if os.path.isdir(install_dir):
install_size = path_size(install_dir)
rgame.set_origin_attributes(install_dir, install_size)
logger.info("Origin game %s (%s, %s)", rgame.title, install_dir, format_size(install_size))
logger.info("Origin game %s (%s, %s)", rgame.app_title, install_dir, format_size(install_size))
else:
logger.warning("Origin game %s (%s does not exist)", rgame.title, install_dir)
logger.warning("Origin game %s (%s does not exist)", rgame.app_title, install_dir)
else:
logger.info("Origin game %s is not installed", rgame.title)
logger.info("Origin game %s is not installed", rgame.app_title)
logger.info("Origin worker finished in %ss", time.time() - t)

View file

@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ImportGroup(object):
def setupUi(self, ImportGroup):
ImportGroup.setObjectName("ImportGroup")
ImportGroup.resize(506, 184)
ImportGroup.resize(651, 218)
ImportGroup.setWindowTitle("ImportGroup")
ImportGroup.setWindowFilePath("")
self.import_layout = QtWidgets.QFormLayout(ImportGroup)
@ -28,26 +28,35 @@ class Ui_ImportGroup(object):
self.import_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.app_name_label)
self.import_folder_label = QtWidgets.QLabel(ImportGroup)
self.import_folder_label.setObjectName("import_folder_label")
self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.import_folder_label)
self.import_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.import_folder_label)
self.import_folder_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
self.import_folder_check.setFont(font)
self.import_folder_check.setObjectName("import_folder_check")
self.import_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.import_folder_check)
self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.import_folder_check)
self.import_dlcs_label = QtWidgets.QLabel(ImportGroup)
self.import_dlcs_label.setObjectName("import_dlcs_label")
self.import_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.import_dlcs_label)
self.import_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.import_dlcs_label)
self.import_dlcs_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
self.import_dlcs_check.setFont(font)
self.import_dlcs_check.setObjectName("import_dlcs_check")
self.import_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.import_dlcs_check)
self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_dlcs_check)
self.import_force_label = QtWidgets.QLabel(ImportGroup)
self.import_force_label.setObjectName("import_force_label")
self.import_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.import_force_label)
self.import_force_check = QtWidgets.QCheckBox(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
self.import_force_check.setFont(font)
self.import_force_check.setObjectName("import_force_check")
self.import_layout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.import_force_check)
self.import_button_label = QtWidgets.QLabel(ImportGroup)
self.import_button_label.setText("Error")
self.import_button_label.setObjectName("import_button_label")
self.import_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.import_button_label)
self.import_layout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.import_button_label)
self.button_info_layout = QtWidgets.QHBoxLayout()
self.button_info_layout.setObjectName("button_info_layout")
self.import_button = QtWidgets.QPushButton(ImportGroup)
@ -58,16 +67,27 @@ class Ui_ImportGroup(object):
self.import_button.setSizePolicy(sizePolicy)
self.import_button.setObjectName("import_button")
self.button_info_layout.addWidget(self.import_button)
self.import_layout.setLayout(5, QtWidgets.QFormLayout.FieldRole, self.button_info_layout)
self.import_force_label = QtWidgets.QLabel(ImportGroup)
self.import_force_label.setObjectName("import_force_label")
self.import_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.import_force_label)
self.import_force_check = QtWidgets.QCheckBox(ImportGroup)
self.import_layout.setLayout(6, QtWidgets.QFormLayout.FieldRole, self.button_info_layout)
self.platform_label = QtWidgets.QLabel(ImportGroup)
self.platform_label.setObjectName("platform_label")
self.import_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.platform_label)
self.platform_layout = QtWidgets.QHBoxLayout()
self.platform_layout.setObjectName("platform_layout")
self.platform_combo = QtWidgets.QComboBox(ImportGroup)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.platform_combo.sizePolicy().hasHeightForWidth())
self.platform_combo.setSizePolicy(sizePolicy)
self.platform_combo.setObjectName("platform_combo")
self.platform_layout.addWidget(self.platform_combo)
self.platform_tooltip = QtWidgets.QLabel(ImportGroup)
font = QtGui.QFont()
font.setItalic(True)
self.import_force_check.setFont(font)
self.import_force_check.setObjectName("import_force_check")
self.import_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.import_force_check)
self.platform_tooltip.setFont(font)
self.platform_tooltip.setObjectName("platform_tooltip")
self.platform_layout.addWidget(self.platform_tooltip)
self.import_layout.setLayout(2, QtWidgets.QFormLayout.FieldRole, self.platform_layout)
self.retranslateUi(ImportGroup)
@ -80,9 +100,11 @@ class Ui_ImportGroup(object):
self.import_folder_check.setText(_translate("ImportGroup", "Scan the installation path for game folders and import them"))
self.import_dlcs_label.setText(_translate("ImportGroup", "Import DLCs"))
self.import_dlcs_check.setText(_translate("ImportGroup", "If a game has DLCs, try to import them too"))
self.import_button.setText(_translate("ImportGroup", "Import Game"))
self.import_force_label.setText(_translate("ImportGroup", "Force import"))
self.import_force_check.setText(_translate("ImportGroup", "Import game despite missing files"))
self.import_button.setText(_translate("ImportGroup", "Import Game"))
self.platform_label.setText(_translate("ImportGroup", "Platform"))
self.platform_tooltip.setText(_translate("ImportGroup", "Select the native platform of the game"))
if __name__ == "__main__":

View file

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

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/legendary.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_LegendarySettings(object):
def setupUi(self, LegendarySettings):
LegendarySettings.setObjectName("LegendarySettings")
LegendarySettings.resize(595, 334)
LegendarySettings.resize(681, 456)
LegendarySettings.setWindowTitle("LegendarySettings")
self.legendary_layout = QtWidgets.QHBoxLayout(LegendarySettings)
self.legendary_layout.setObjectName("legendary_layout")
@ -125,21 +125,30 @@ class Ui_LegendarySettings(object):
self.clean_button = QtWidgets.QPushButton(self.cleanup_group)
self.clean_button.setObjectName("clean_button")
self.cleanup_layout.addWidget(self.clean_button)
self.right_layout.addWidget(self.cleanup_group, 0, QtCore.Qt.AlignTop)
self.meta_group = QtWidgets.QGroupBox(LegendarySettings)
self.meta_group.setObjectName("meta_group")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.meta_group)
self.right_layout.addWidget(self.cleanup_group)
self.metadata_group = QtWidgets.QGroupBox(LegendarySettings)
self.metadata_group.setObjectName("metadata_group")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.metadata_group)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.win32_cb = QtWidgets.QCheckBox(self.meta_group)
self.win32_cb.setObjectName("win32_cb")
self.verticalLayout_2.addWidget(self.win32_cb)
self.mac_cb = QtWidgets.QCheckBox(self.meta_group)
self.mac_cb.setObjectName("mac_cb")
self.verticalLayout_2.addWidget(self.mac_cb)
self.refresh_game_meta_btn = QtWidgets.QPushButton(self.meta_group)
self.refresh_game_meta_btn.setObjectName("refresh_game_meta_btn")
self.verticalLayout_2.addWidget(self.refresh_game_meta_btn)
self.right_layout.addWidget(self.meta_group)
self.fetch_win32_check = QtWidgets.QCheckBox(self.metadata_group)
self.fetch_win32_check.setObjectName("fetch_win32_check")
self.verticalLayout_2.addWidget(self.fetch_win32_check)
self.fetch_macos_check = QtWidgets.QCheckBox(self.metadata_group)
self.fetch_macos_check.setObjectName("fetch_macos_check")
self.verticalLayout_2.addWidget(self.fetch_macos_check)
self.fetch_unreal_check = QtWidgets.QCheckBox(self.metadata_group)
self.fetch_unreal_check.setObjectName("fetch_unreal_check")
self.verticalLayout_2.addWidget(self.fetch_unreal_check)
self.metadata_info = QtWidgets.QLabel(self.metadata_group)
font = QtGui.QFont()
font.setItalic(True)
self.metadata_info.setFont(font)
self.metadata_info.setObjectName("metadata_info")
self.verticalLayout_2.addWidget(self.metadata_info)
self.refresh_metadata_button = QtWidgets.QPushButton(self.metadata_group)
self.refresh_metadata_button.setObjectName("refresh_metadata_button")
self.verticalLayout_2.addWidget(self.refresh_metadata_button)
self.right_layout.addWidget(self.metadata_group)
spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
self.right_layout.addItem(spacerItem1)
self.legendary_layout.addLayout(self.right_layout)
@ -148,11 +157,11 @@ class Ui_LegendarySettings(object):
def retranslateUi(self, LegendarySettings):
_translate = QtCore.QCoreApplication.translate
self.install_dir_group.setTitle(_translate("LegendarySettings", "Default Installation Directory"))
self.download_group.setTitle(_translate("LegendarySettings", "Download Settings"))
self.max_workers_label.setText(_translate("LegendarySettings", "Max Workers"))
self.install_dir_group.setTitle(_translate("LegendarySettings", "Default installation folder"))
self.download_group.setTitle(_translate("LegendarySettings", "Download settings"))
self.max_workers_label.setText(_translate("LegendarySettings", "Max sorkers"))
self.max_workers_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)"))
self.max_memory_label.setText(_translate("LegendarySettings", "Max Shared Memory"))
self.max_memory_label.setText(_translate("LegendarySettings", "Max shared memory"))
self.max_memory_spin.setSuffix(_translate("LegendarySettings", "MiB"))
self.max_memory_info_label.setText(_translate("LegendarySettings", "Less is slower (0: Default)"))
self.preferred_cdn_label.setText(_translate("LegendarySettings", "Preferred CDN"))
@ -162,10 +171,12 @@ class Ui_LegendarySettings(object):
self.cleanup_group.setTitle(_translate("LegendarySettings", "Cleanup"))
self.clean_keep_manifests_button.setText(_translate("LegendarySettings", "Clean, but keep manifests"))
self.clean_button.setText(_translate("LegendarySettings", "Remove everything"))
self.meta_group.setTitle(_translate("LegendarySettings", "Game metadata"))
self.win32_cb.setText(_translate("LegendarySettings", "Load 32bit data"))
self.mac_cb.setText(_translate("LegendarySettings", "Load MacOS data"))
self.refresh_game_meta_btn.setText(_translate("LegendarySettings", "Refresh game meta"))
self.metadata_group.setTitle(_translate("LegendarySettings", "Platforms"))
self.fetch_win32_check.setText(_translate("LegendarySettings", "Include Win32 games"))
self.fetch_macos_check.setText(_translate("LegendarySettings", "Include macOS games"))
self.fetch_unreal_check.setText(_translate("LegendarySettings", "Include Unreal engine"))
self.metadata_info.setText(_translate("LegendarySettings", "Restart Rare to apply"))
self.refresh_metadata_button.setText(_translate("LegendarySettings", "Refresh metadata"))
if __name__ == "__main__":

View file

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

View file

@ -2,7 +2,7 @@
# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/rare.ui'
#
# Created by: PyQt5 UI code generator 5.15.6
# Created by: PyQt5 UI code generator 5.15.10
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
@ -14,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_RareSettings(object):
def setupUi(self, RareSettings):
RareSettings.setObjectName("RareSettings")
RareSettings.resize(517, 434)
RareSettings.resize(623, 428)
RareSettings.setWindowTitle("RareSettings")
self.rare_layout = QtWidgets.QHBoxLayout(RareSettings)
self.rare_layout.setObjectName("rare_layout")
@ -148,25 +148,25 @@ class Ui_RareSettings(object):
_translate = QtCore.QCoreApplication.translate
self.interface_group.setTitle(_translate("RareSettings", "Interface"))
self.lang_label.setText(_translate("RareSettings", "Language"))
self.color_label.setText(_translate("RareSettings", "Color Scheme"))
self.color_label.setText(_translate("RareSettings", "Color scheme"))
self.color_select.setItemText(0, _translate("RareSettings", "None"))
self.style_label.setText(_translate("RareSettings", "Style Sheet"))
self.style_label.setText(_translate("RareSettings", "Style sheet"))
self.style_select.setItemText(0, _translate("RareSettings", "None"))
self.interface_info.setText(_translate("RareSettings", "Restart Rare to apply."))
self.interface_info.setText(_translate("RareSettings", "Restart Rare to apply changes."))
self.settings_group.setTitle(_translate("RareSettings", "Behavior"))
self.save_size.setText(_translate("RareSettings", "Restore window size on application startup"))
self.notification.setText(_translate("RareSettings", "Show notification on download completion"))
self.log_games.setText(_translate("RareSettings", "Show console for game debug"))
self.sys_tray.setText(_translate("RareSettings", "Exit to System tray"))
self.auto_update.setText(_translate("RareSettings", "Update games on application startup"))
self.confirm_start.setText(_translate("RareSettings", "Confirm game launch"))
self.auto_sync_cloud.setText(_translate("RareSettings", "Automatically sync with cloud"))
self.notification.setText(_translate("RareSettings", "Show notifications when downloads complete"))
self.log_games.setText(_translate("RareSettings", "Show console windows when launching games"))
self.sys_tray.setText(_translate("RareSettings", "Exit to system tray"))
self.auto_update.setText(_translate("RareSettings", "Queue game updates on application startup"))
self.confirm_start.setText(_translate("RareSettings", "Confirm before launching games"))
self.auto_sync_cloud.setText(_translate("RareSettings", "Automatically upload/download cloud saves"))
self.log_dir_group.setTitle(_translate("RareSettings", "Logs"))
self.log_dir_open_button.setText(_translate("RareSettings", "Open Log directory"))
self.log_dir_clean_button.setText(_translate("RareSettings", "Clean Log directory"))
self.log_dir_open_button.setText(_translate("RareSettings", "Open log folder"))
self.log_dir_clean_button.setText(_translate("RareSettings", "Clean log folder"))
self.groupBox.setTitle(_translate("RareSettings", "Shortcuts"))
self.desktop_link_btn.setText(_translate("RareSettings", "Create Desktop link"))
self.startmenu_link_btn.setText(_translate("RareSettings", "Create start menu link"))
self.desktop_link_btn.setText(_translate("RareSettings", "Create on desktop"))
self.startmenu_link_btn.setText(_translate("RareSettings", "Create in menu"))
if __name__ == "__main__":

View file

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

View file

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

View file

@ -4,7 +4,6 @@ from logging import getLogger
from typing import Callable, Tuple, Optional, Dict, List
from PyQt5.QtCore import (
Qt,
QSize,
pyqtSignal,
QFileInfo,
@ -135,7 +134,8 @@ class IndicatorLineEdit(QWidget):
# Add line_edit
self.line_edit = QLineEdit(self)
self.line_edit.setObjectName(f"{type(self).__name__}Edit")
self.line_edit.setPlaceholderText(placeholder if placeholder else self.tr("Default"))
self.line_edit.setPlaceholderText(placeholder if placeholder else self.tr("Use global/default setting"))
self.line_edit.setToolTip(placeholder if placeholder else "")
self.line_edit.setSizePolicy(horiz_policy, QSizePolicy.Fixed)
# Add completer
self.setCompleter(completer)

View file

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