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
+
+
+
+
+
+
+
+