From d1df48e83759434fe88369983bedbfeef0ae0ad2 Mon Sep 17 00:00:00 2001 From: Dummerle <44114474+Dummerle@users.noreply.github.com> Date: Sun, 27 Feb 2022 00:14:47 +0100 Subject: [PATCH] Update Wrapper settings --- .../tabs/games/game_info/game_settings.py | 35 +-- rare/components/tabs/settings/wrapper.py | 113 ++++++++ .../tabs/games/game_info/game_settings.py | 13 +- .../tabs/games/game_info/game_settings.ui | 246 ++++++++---------- rare/ui/components/tabs/settings/wrapper.py | 62 +++++ rare/ui/components/tabs/settings/wrapper.ui | 56 ++++ 6 files changed, 359 insertions(+), 166 deletions(-) create mode 100644 rare/components/tabs/settings/wrapper.py create mode 100644 rare/ui/components/tabs/settings/wrapper.py create mode 100644 rare/ui/components/tabs/settings/wrapper.ui diff --git a/rare/components/tabs/games/game_info/game_settings.py b/rare/components/tabs/games/game_info/game_settings.py index 56136361..54d1d897 100644 --- a/rare/components/tabs/games/game_info/game_settings.py +++ b/rare/components/tabs/games/game_info/game_settings.py @@ -17,6 +17,7 @@ from legendary.core import LegendaryCore from legendary.models.game import InstalledGame, Game from rare.components.tabs.settings.linux import LinuxSettings +from rare.components.tabs.settings.wrapper import WrapperSettings from rare.ui.components.tabs.games.game_info.game_settings import Ui_GameSettings from rare.utils import config_helper from rare.utils.extra_widgets import PathEdit @@ -64,6 +65,12 @@ class GameSettings(QWidget, Ui_GameSettings): self.core = core self.settings = QSettings() + self.wrapper_settings = WrapperSettings() + + self.launch_settings_groupbox.layout().addRow( + QLabel("Wrapper"), self.wrapper_settings + ) + self.cloud_save_path_edit = PathEdit( "", file_type=QFileDialog.DirectoryOnly, @@ -98,10 +105,6 @@ class GameSettings(QWidget, Ui_GameSettings): self.launch_params.textChanged.connect( lambda x: self.save_line_edit("start_params", x) ) - self.wrapper.textChanged.connect(lambda x: self.save_line_edit("wrapper", x)) - self.override_exe_edit.textChanged.connect( - lambda x: self.save_line_edit("override_exe", x) - ) if platform.system() != "Windows": self.possible_proton_wrappers = find_proton_wrappers() @@ -218,9 +221,9 @@ class GameSettings(QWidget, Ui_GameSettings): def change_proton(self, i): if self.change: - # Dont use Proton + # First combo box entry: Don't use Proton if i == 0: - config_helper.remove_option(self.game.app_name, "wrapper") + self.wrapper_settings.delete_wrapper("proton") config_helper.remove_option(self.game.app_name, "no_wine") config_helper.remove_option(f"{self.game.app_name}.env", "STEAM_COMPAT_DATA_PATH") config_helper.remove_option(f"{self.game.app_name}.env", "STEAM_COMPAT_CLIENT_INSTALL_PATH") @@ -228,20 +231,14 @@ class GameSettings(QWidget, Ui_GameSettings): self.proton_prefix.setEnabled(False) # lk: TODO: This has to be fixed properly. # lk: It happens because of the widget update. Mask it for now behind disabling the save button - self.wrapper.setText( - self.core.lgd.config.get( - f"{self.game.app_name}", "wrapper", fallback="" - ) - ) - self.wrapper.setEnabled(True) + self.linux_settings.wine_groupbox.setEnabled(True) else: self.proton_prefix.setEnabled(True) - self.wrapper.setEnabled(False) self.linux_settings.wine_groupbox.setEnabled(False) wrapper = self.possible_proton_wrappers[i - 1] - config_helper.add_option(self.game.app_name, "wrapper", wrapper) + self.wrapper_settings.add_wrapper(wrapper) config_helper.add_option(self.game.app_name, "no_wine", "true") config_helper.add_option( f"{self.game.app_name}.env", @@ -307,10 +304,8 @@ class GameSettings(QWidget, Ui_GameSettings): else: self.skip_update.setCurrentIndex(0) - wrapper = self.core.lgd.config.get(self.game.app_name, "wrapper", fallback="") - self.wrapper.setText(wrapper) - self.game_title.setText(f"

{self.game.app_title}

") + self.wrapper_settings.load_settings(app_name) if platform.system() != "Windows": self.linux_settings.update_game(app_name) @@ -319,9 +314,7 @@ class GameSettings(QWidget, Ui_GameSettings): else: self.linux_settings_widget.setVisible(True) - proton = self.core.lgd.config.get( - f"{app_name}", "wrapper", fallback="" - ).replace('"', "") + proton = self.wrapper_settings.extra_wrappers.get("proton", "").replace('"', "") if proton and "proton" in proton: self.proton_prefix.setEnabled(True) self.proton_wrapper.setCurrentText( @@ -333,12 +326,10 @@ class GameSettings(QWidget, Ui_GameSettings): fallback=self.tr("Please select path for proton prefix"), ) self.proton_prefix.setText(proton_prefix) - self.wrapper.setEnabled(False) self.linux_settings.wine_groupbox.setEnabled(False) else: self.proton_wrapper.setCurrentIndex(0) self.proton_prefix.setEnabled(False) - self.wrapper.setEnabled(True) self.linux_settings.wine_groupbox.setEnabled(True) if not self.game.supports_cloud_saves: diff --git a/rare/components/tabs/settings/wrapper.py b/rare/components/tabs/settings/wrapper.py new file mode 100644 index 00000000..dd577903 --- /dev/null +++ b/rare/components/tabs/settings/wrapper.py @@ -0,0 +1,113 @@ +import re +from logging import getLogger +from typing import Dict + +from PyQt5.QtCore import pyqtSignal +from PyQt5.QtWidgets import QGroupBox, QHBoxLayout, QLabel, QPushButton, QInputDialog, QFrame, QWidget + +from rare import shared +from rare.ui.components.tabs.settings.wrapper import Ui_WrapperSettings +from rare.utils import config_helper +from rare.utils.extra_widgets import FlowLayout +from rare.utils.utils import icon + +logger = getLogger("Wrapper Settings") + +extra_wrapper_regex = { + "proton": "\".*proton\" run", # proton + "mangohud": "mangohud" # mangohud +} + + +class WrapperWidget(QGroupBox): + delete_wrapper = pyqtSignal(str) + + def __init__(self, text: str): + super(WrapperWidget, self).__init__() + self.setLayout(QHBoxLayout()) + self.text = text + self.layout().addWidget(QLabel(text)) + + self.delete_button = QPushButton(icon("ei.remove"), "") + self.layout().addWidget(self.delete_button) + self.delete_button.clicked.connect(self.delete) + + def delete(self): + self.delete_wrapper.emit(self.text) + + +class WrapperSettings(QGroupBox, Ui_WrapperSettings): + wrappers: Dict[str, WrapperWidget] = dict() + extra_wrappers: Dict[str, str] = dict() + app_name: str + + def __init__(self): + super(WrapperSettings, self).__init__("Wrapper") + self.setupUi(self) + self.widgets.setLayout(FlowLayout()) + self.core = shared.core + + self.add_button.clicked.connect(self.add_button_pressed) + + def get_wrapper_string(self): + return " ".join(list(self.extra_wrappers.values()) + list(self.wrappers.keys())) + + def add_button_pressed(self): + wrapper, done = QInputDialog.getText(self, "Input Dialog", self.tr("Insert name of wrapper")) + if not done: + return + self.add_wrapper(wrapper) + + def add_wrapper(self, text: str): + for key, extra_wrapper in extra_wrapper_regex.items(): + if re.match(extra_wrapper, text): + self.extra_wrappers[key] = text + self.save() + return + widget = WrapperWidget(text) + widget.delete_wrapper.connect(self.delete_wrapper) + self.widgets.layout().addWidget(widget) + self.wrappers[text] = widget + self.widget_stack.setCurrentIndex(0) + + # flow layout bug + self.widgets.update() + self.save() + + def delete_wrapper(self, text: str): + widget = self.wrappers.get(text, None) + if not widget and self.extra_wrappers.get(text, None): + self.extra_wrappers.pop(text) + elif widget: + widget.deleteLater() + self.wrappers.pop(text) + + if len(self.wrappers) == 0: + self.widget_stack.setCurrentIndex(1) + self.save() + + def save(self): + config_helper.add_option(self.app_name, "wrapper", self.get_wrapper_string()) + + def load_settings(self, app_name): + self.app_name = app_name + for i in self.wrappers.values(): + i.deleteLater() + self.wrappers.clear() + self.extra_wrappers.clear() + + wrapper_config = self.core.lgd.config.get(app_name, "wrapper", fallback="") + pattern = re.compile(r'''((?:[^ "']|"[^"]*"|'[^']*')+)''') + wrappers = pattern.split(wrapper_config)[1::2] + if not wrappers: + self.widget_stack.setCurrentIndex(1) + return + else: + self.widget_stack.setCurrentIndex(0) + + for wrapper in wrappers: + if wrapper.strip('"').endswith("proton"): + wrapper = f"{wrapper} run" + if wrapper == "run": + continue + self.add_wrapper(wrapper) diff --git a/rare/ui/components/tabs/games/game_info/game_settings.py b/rare/ui/components/tabs/games/game_info/game_settings.py index 054f9407..a3355858 100644 --- a/rare/ui/components/tabs/games/game_info/game_settings.py +++ b/rare/ui/components/tabs/games/game_info/game_settings.py @@ -80,19 +80,12 @@ class Ui_GameSettings(object): self.launch_params.setMinimumSize(QtCore.QSize(400, 0)) self.launch_params.setObjectName("launch_params") self.launch_settings_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.launch_params) - self.wrapper_label = QtWidgets.QLabel(self.launch_settings_group) - self.wrapper_label.setObjectName("wrapper_label") - self.launch_settings_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.wrapper_label) - self.wrapper = QtWidgets.QLineEdit(self.launch_settings_group) - self.wrapper.setMinimumSize(QtCore.QSize(400, 0)) - self.wrapper.setObjectName("wrapper") - self.launch_settings_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.wrapper) self.override_exe_label = QtWidgets.QLabel(self.launch_settings_group) self.override_exe_label.setObjectName("override_exe_label") - self.launch_settings_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.override_exe_label) + self.launch_settings_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.override_exe_label) self.override_exe_edit = QtWidgets.QLineEdit(self.launch_settings_group) self.override_exe_edit.setObjectName("override_exe_edit") - self.launch_settings_layout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.override_exe_edit) + self.launch_settings_layout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.override_exe_edit) self.game_settings_contents_layout.addWidget(self.launch_settings_group) self.cloud_group = QtWidgets.QGroupBox(self.game_settings_contents) self.cloud_group.setObjectName("cloud_group") @@ -157,8 +150,6 @@ class Ui_GameSettings(object): self.offline.setItemText(2, _translate("GameSettings", "No")) self.launch_params_label.setText(_translate("GameSettings", "Launch parameters")) self.launch_params.setPlaceholderText(_translate("GameSettings", "parameters")) - self.wrapper_label.setText(_translate("GameSettings", "Wrapper")) - self.wrapper.setPlaceholderText(_translate("GameSettings", "e.g. optirun")) self.override_exe_label.setText(_translate("GameSettings", "Override Exe")) self.override_exe_edit.setPlaceholderText(_translate("GameSettings", "Relative path to launch executable")) self.cloud_group.setTitle(_translate("GameSettings", "Cloud Saves")) diff --git a/rare/ui/components/tabs/games/game_info/game_settings.ui b/rare/ui/components/tabs/games/game_info/game_settings.ui index 5c7746c2..2cd0b920 100644 --- a/rare/ui/components/tabs/games/game_info/game_settings.ui +++ b/rare/ui/components/tabs/games/game_info/game_settings.ui @@ -65,141 +65,121 @@ - - - 0 - 0 - + + + 0 + 0 + + + + Launch Settings + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + Skip update check + + + + + + + + 0 + 0 + + + + + Default - - Launch Settings + + + + Yes - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Skip update check - - - - - - - - 0 - 0 - - - - - Default - - - - - Yes - - - - - No - - - - - - - - Offline mode - - - - - - - - 0 - 0 - - - - - Default - - - - - Yes - - - - - No - - - - - - - - Launch parameters - - - - - - - - 400 - 0 - - - - parameters - - - - - - - Wrapper - - - - - - - - 400 - 0 - - - - e.g. optirun - - - - - - - Override Exe - - - - - - - Relative path to launch executable - - - - - - - + + + + No + + + + + + + + Offline mode + + + + + + + + 0 + 0 + + + + + Default + + + + + Yes + + + + + No + + + + + + + + Launch parameters + + + + + + + + 400 + 0 + + + + parameters + + + + + + + Override Exe + + + + + + + Relative path to launch executable + + + + + + + Cloud Saves diff --git a/rare/ui/components/tabs/settings/wrapper.py b/rare/ui/components/tabs/settings/wrapper.py new file mode 100644 index 00000000..3aaa9618 --- /dev/null +++ b/rare/ui/components/tabs/settings/wrapper.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- + +# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/wrapper.ui' +# +# Created by: PyQt5 UI code generator 5.15.6 +# +# WARNING: Any manual changes made to this file will be lost when pyuic5 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt5 import QtCore, QtGui, QtWidgets + + +class Ui_WrapperSettings(object): + def setupUi(self, WrapperSettings): + WrapperSettings.setObjectName("WrapperSettings") + WrapperSettings.resize(435, 123) + WrapperSettings.setWindowTitle("GroupBox") + self.horizontalLayout = QtWidgets.QHBoxLayout(WrapperSettings) + self.horizontalLayout.setObjectName("horizontalLayout") + self.widget_stack = QtWidgets.QStackedWidget(WrapperSettings) + self.widget_stack.setObjectName("widget_stack") + self.widgets = QtWidgets.QWidget() + self.widgets.setObjectName("widgets") + self.widget_stack.addWidget(self.widgets) + self.label_page = QtWidgets.QWidget() + self.label_page.setObjectName("label_page") + self.verticalLayout = QtWidgets.QVBoxLayout(self.label_page) + self.verticalLayout.setObjectName("verticalLayout") + self.no_wrapper_label = QtWidgets.QLabel(self.label_page) + self.no_wrapper_label.setObjectName("no_wrapper_label") + self.verticalLayout.addWidget(self.no_wrapper_label) + self.widget_stack.addWidget(self.label_page) + self.horizontalLayout.addWidget(self.widget_stack) + self.add_button = QtWidgets.QPushButton(WrapperSettings) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Maximum) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.add_button.sizePolicy().hasHeightForWidth()) + self.add_button.setSizePolicy(sizePolicy) + self.add_button.setObjectName("add_button") + self.horizontalLayout.addWidget(self.add_button) + + self.retranslateUi(WrapperSettings) + self.widget_stack.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(WrapperSettings) + + def retranslateUi(self, WrapperSettings): + _translate = QtCore.QCoreApplication.translate + WrapperSettings.setTitle(_translate("WrapperSettings", "Wrapper")) + self.no_wrapper_label.setText(_translate("WrapperSettings", "No wrapper added")) + self.add_button.setText(_translate("WrapperSettings", "Add Wrapper")) + + +if __name__ == "__main__": + import sys + app = QtWidgets.QApplication(sys.argv) + WrapperSettings = QtWidgets.QGroupBox() + ui = Ui_WrapperSettings() + ui.setupUi(WrapperSettings) + WrapperSettings.show() + sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/wrapper.ui b/rare/ui/components/tabs/settings/wrapper.ui new file mode 100644 index 00000000..57cd0ec7 --- /dev/null +++ b/rare/ui/components/tabs/settings/wrapper.ui @@ -0,0 +1,56 @@ + + + WrapperSettings + + + + 0 + 0 + 435 + 123 + + + + GroupBox + + + Wrapper + + + + + + 0 + + + + + + + + No wrapper added + + + + + + + + + + + + 0 + 0 + + + + Add Wrapper + + + + + + + +