diff --git a/rare/components/tabs/games/__init__.py b/rare/components/tabs/games/__init__.py index a31daecd..aa48d7f4 100644 --- a/rare/components/tabs/games/__init__.py +++ b/rare/components/tabs/games/__init__.py @@ -139,8 +139,8 @@ class GamesTab(QStackedWidget): @pyqtSlot(RareGame) def show_game_info(self, rgame): - self.setCurrentWidget(self.game_info_page) self.game_info_page.update_game(rgame) + self.setCurrentWidget(self.game_info_page) @pyqtSlot() def update_count_games_label(self): diff --git a/rare/components/tabs/games/game_info/__init__.py b/rare/components/tabs/games/game_info/__init__.py index 3f9f7a7f..9f2480d3 100644 --- a/rare/components/tabs/games/game_info/__init__.py +++ b/rare/components/tabs/games/game_info/__init__.py @@ -1,6 +1,6 @@ from typing import Optional -from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot +from PyQt5.QtCore import Qt, pyqtSignal from PyQt5.QtGui import QKeyEvent from PyQt5.QtWidgets import QTreeView diff --git a/rare/components/tabs/games/game_info/game_settings.py b/rare/components/tabs/games/game_info/game_settings.py index c5e49a19..c1f22532 100644 --- a/rare/components/tabs/games/game_info/game_settings.py +++ b/rare/components/tabs/games/game_info/game_settings.py @@ -1,63 +1,104 @@ import os.path -import platform +import platform as pf from logging import getLogger from typing import Tuple -from PyQt5.QtCore import Qt -from PyQt5.QtWidgets import QLabel, QFileDialog, QFormLayout +from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtGui import QShowEvent +from PyQt5.QtWidgets import QFileDialog, QComboBox, QLineEdit from legendary.models.game import Game, InstalledGame -from rare.components.tabs.settings import DefaultGameSettings -from rare.components.tabs.settings.widgets.pre_launch import PreLaunchSettings +from rare.components.tabs.settings.widgets.wrappers import WrapperSettings +from rare.components.tabs.settings.widgets.game import GameSettingsBase +from rare.components.tabs.settings.widgets.env_vars import EnvVars +from rare.components.tabs.settings.widgets.launch import LaunchSettingsBase +from rare.components.tabs.settings.widgets.overlay import MangoHudSettings, DxvkSettings +from rare.components.tabs.settings.widgets.proton import ProtonSettings +from rare.components.tabs.settings.widgets.wine import WineSettings from rare.models.game import RareGame -from rare.utils import config_helper -from rare.widgets.side_tab import SideTabContents +from rare.utils import config_helper as config from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon logger = getLogger("GameSettings") -class GameSettings(DefaultGameSettings, SideTabContents): +class GameWrapperSettings(WrapperSettings): def __init__(self, parent=None): - super(GameSettings, self).__init__(False, parent=parent) + super().__init__(parent=parent) - self.ui.skip_update.currentIndexChanged.connect( - lambda x: self.update_combobox("skip_update_check", x) - ) - self.ui.offline.currentIndexChanged.connect( - lambda x: self.update_combobox("offline", x) - ) - self.ui.launch_params.textChanged.connect( - lambda x: self.line_edit_save_callback("start_params", x) - ) + def load_settings(self, app_name: str): + self.app_name = app_name - self.override_exe_edit = PathEdit( - file_mode=QFileDialog.ExistingFile, - name_filters=["*.exe", "*.app"], - placeholder=self.tr("Relative path to launch executable"), - edit_func=self.override_exe_edit_callback, - save_func=self.override_exe_save_callback, - parent=self - ) - self.ui.launch_settings_layout.setWidget( - self.ui.launch_settings_layout.getWidgetPosition(self.ui.override_exe_label)[0], - QFormLayout.FieldRole, - self.override_exe_edit - ) - self.pre_launch_settings = PreLaunchSettings(parent=self) - self.ui.launch_settings_layout.setWidget( - self.ui.launch_settings_layout.getWidgetPosition(self.ui.pre_launch_label)[0], - QFormLayout.FieldRole, - self.pre_launch_settings - ) +class GameLaunchSettings(LaunchSettingsBase): - self.ui.game_settings_layout.setAlignment(Qt.AlignTop) + def __init__(self, parent=None): + super(GameLaunchSettings, self).__init__(GameWrapperSettings, parent=parent) self.game: Game = None self.igame: InstalledGame = None - def override_exe_edit_callback(self, path: str) -> Tuple[bool, str, int]: + self.skip_update_combo = QComboBox(self) + self.skip_update_combo.addItem(self.tr("Default"), None) + self.skip_update_combo.addItem(self.tr("No"), "false") + self.skip_update_combo.addItem(self.tr("Yes"), "true") + self.skip_update_combo.currentIndexChanged.connect(self.__skip_update_changed) + + self.offline_combo = QComboBox(self) + self.offline_combo.addItem(self.tr("Default"), None) + self.offline_combo.addItem(self.tr("No"), "false") + self.offline_combo.addItem(self.tr("Yes"), "true") + self.offline_combo.currentIndexChanged.connect(self.__offline_changed) + + self.override_exe_edit = PathEdit( + file_mode=QFileDialog.ExistingFile, + name_filters=["*.exe", "*.app"], + placeholder=self.tr("Relative path to the replacement executable"), + edit_func=self.__override_exe_edit_callback, + save_func=self.__override_exe_save_callback, + parent=self + ) + + self.launch_params_edit = QLineEdit(self) + self.launch_params_edit.setPlaceholderText(self.tr("Game specific command line arguments")) + self.launch_params_edit.textChanged.connect(self.__launch_params_changed) + + self.main_layout.insertRow(0, self.tr("Skip update check"), self.skip_update_combo) + self.main_layout.insertRow(1, self.tr("Offline mode"), self.offline_combo) + self.main_layout.insertRow(2, self.tr("Launch parameters"), self.launch_params_edit) + self.main_layout.insertRow(3, self.tr("Override executable"), self.override_exe_edit) + + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + + skip_update = config.get_option(self.app_name, "skip_update_check", fallback=None) + self.skip_update_combo.setCurrentIndex(self.offline_combo.findData(skip_update, Qt.UserRole)) + + offline = config.get_option(self.app_name, "offline", fallback=None) + self.offline_combo.setCurrentIndex(self.offline_combo.findData(offline, Qt.UserRole)) + + if self.igame: + self.offline_combo.setEnabled(self.igame.can_run_offline) + self.override_exe_edit.set_root(self.igame.install_path) + else: + self.offline_combo.setEnabled(False) + self.override_exe_edit.set_root("") + + launch_params = config.get_option(self.app_name, "start_params", "") + self.launch_params_edit.setText(launch_params) + + override_exe = config.get_option(self.app_name, "override_exe", fallback="") + self.override_exe_edit.setText(override_exe) + + return super().showEvent(a0) + + @pyqtSlot(int) + def __skip_update_changed(self, index): + data = self.skip_update_combo.itemData(index, Qt.UserRole) + config.save_option(self.app_name, "skip_update_check", data) + + def __override_exe_edit_callback(self, path: str) -> Tuple[bool, str, int]: if not path or self.igame is None: return True, path, IndicatorReasonsCommon.VALID if not os.path.isabs(path): @@ -72,72 +113,65 @@ class GameSettings(DefaultGameSettings, SideTabContents): path = os.path.relpath(path, self.igame.install_path) return True, path, IndicatorReasonsCommon.VALID - def override_exe_save_callback(self, path: str): - self.line_edit_save_callback("override_exe", path) + def __override_exe_save_callback(self, path: str): + config.save_option(self.app_name, "override_exe", path) - def line_edit_save_callback(self, option, value) -> None: - if value: - config_helper.add_option(self.game.app_name, option, value) - else: - config_helper.remove_option(self.game.app_name, option) - config_helper.save_config() + @pyqtSlot(int) + def __offline_changed(self, index): + data = self.skip_update_combo.itemData(index, Qt.UserRole) + config.save_option(self.app_name, "offline", data) - def update_combobox(self, option, index): - if self.change: - # remove section - if index: - if index == 1: - config_helper.add_option(self.game.app_name, option, "true") - if index == 2: - config_helper.add_option(self.game.app_name, option, "false") - else: - config_helper.remove_option(self.game.app_name, option) - config_helper.save_config() + def __launch_params_changed(self, value) -> None: + config.save_option(self.app_name, "start_params", value) def load_settings(self, rgame: RareGame): - self.change = False - # FIXME: Use RareGame for the rest of the code - app_name = rgame.app_name - super(GameSettings, self).load_settings(app_name) self.game = rgame.game self.igame = rgame.igame - if self.igame: - if self.igame.can_run_offline: - offline = self.core.lgd.config.get(self.game.app_name, "offline", fallback="unset") - if offline == "true": - self.ui.offline.setCurrentIndex(1) - elif offline == "false": - self.ui.offline.setCurrentIndex(2) - else: - self.ui.offline.setCurrentIndex(0) + self.app_name = rgame.app_name + self.wrappers_widget.load_settings(rgame.app_name) - self.ui.offline.setEnabled(True) - else: - self.ui.offline.setEnabled(False) - self.override_exe_edit.set_root(self.igame.install_path) - else: - self.ui.offline.setEnabled(False) - self.override_exe_edit.set_root("") - skip_update = self.core.lgd.config.get(self.game.app_name, "skip_update_check", fallback="unset") - if skip_update == "true": - self.ui.skip_update.setCurrentIndex(1) - elif skip_update == "false": - self.ui.skip_update.setCurrentIndex(2) - else: - self.ui.skip_update.setCurrentIndex(0) +class GameWineSettings(WineSettings): + def load_settings(self, app_name): + self.app_name = app_name - self.set_title.emit(self.game.app_title) - if platform.system() != "Windows": - if self.igame and self.igame.platform == "Mac": - self.linux_settings.setVisible(False) - else: - self.linux_settings.setVisible(True) - self.ui.launch_params.setText(self.core.lgd.config.get(self.game.app_name, "start_params", fallback="")) - self.override_exe_edit.setText( - self.core.lgd.config.get(self.game.app_name, "override_exe", fallback="") +class GameProtonSettings(ProtonSettings): + def load_settings(self, app_name: str): + self.app_name = app_name + + +class GameDxvkSettings(DxvkSettings): + def load_settings(self, app_name: str): + self.app_name = app_name + + +class GameMangoHudSettings(MangoHudSettings): + def load_settings(self, app_name: str): + self.app_name = app_name + + +class GameEnvVars(EnvVars): + def load_settings(self, app_name): + self.app_name = app_name + + +class GameSettings(GameSettingsBase): + def __init__(self, parent=None): + super(GameSettings, self).__init__( + GameLaunchSettings, GameWineSettings, GameProtonSettings, + GameDxvkSettings, GameMangoHudSettings, GameEnvVars, + parent=parent ) - self.pre_launch_settings.load_settings(app_name) - self.change = True + def load_settings(self, rgame: RareGame): + self.set_title.emit(rgame.app_title) + self.app_name = rgame.app_name + self.launch.load_settings(rgame) + if pf.system() != "Windows": + self.wine.load_settings(rgame.app_name) + if pf.system() == "Linux": + self.proton_tool.load_settings(rgame.app_name) + self.mangohud.load_settings(rgame.app_name) + self.dxvk.load_settings(rgame.app_name) + self.env_vars.load_settings(rgame.app_name) diff --git a/rare/components/tabs/settings/__init__.py b/rare/components/tabs/settings/__init__.py index 9142e426..41db9cf2 100644 --- a/rare/components/tabs/settings/__init__.py +++ b/rare/components/tabs/settings/__init__.py @@ -1,9 +1,8 @@ -from rare.components.tabs.settings.widgets.wine import LinuxSettings from rare.shared import ArgumentsSingleton from rare.widgets.side_tab import SideTabWidget from .about import About from .debug import DebugSettings -from .game import DefaultGameSettings +from .settings import GameSettings from .legendary import LegendarySettings from .rare import RareSettings @@ -19,7 +18,7 @@ class SettingsTab(SideTabWidget): legendary_settings = LegendarySettings(self) self.legendary_index = self.addTab(legendary_settings, "Legendary") - game_settings = DefaultGameSettings(True, self) + game_settings = GameSettings(self) self.settings_index = self.addTab(game_settings, self.tr("Defaults")) self.about = About(self) diff --git a/rare/components/tabs/settings/game.py b/rare/components/tabs/settings/game.py deleted file mode 100644 index b31d5f07..00000000 --- a/rare/components/tabs/settings/game.py +++ /dev/null @@ -1,95 +0,0 @@ -import platform as pf -from logging import getLogger - -from PyQt5.QtCore import QSettings, Qt -from PyQt5.QtGui import QShowEvent -from PyQt5.QtWidgets import ( - QWidget, - QLabel, QFormLayout -) - -from components.tabs.settings.widgets.dxvk import DxvkSettings -from components.tabs.settings.widgets.mangohud import MangoHudSettings -from rare.components.tabs.settings.widgets.env_vars import EnvVars -from rare.components.tabs.settings.widgets.wine import LinuxSettings -from rare.components.tabs.settings.widgets.proton import ProtonSettings -from rare.components.tabs.settings.widgets.wrapper import WrapperSettings -from rare.shared import LegendaryCoreSingleton -from rare.ui.components.tabs.settings.game import Ui_GameSettings - -logger = getLogger("GameSettings") - - -class DefaultGameSettings(QWidget): - # variable to no update when changing game - change = False - app_name: str - - def __init__(self, is_default, parent=None): - super(DefaultGameSettings, self).__init__(parent=parent) - self.ui = Ui_GameSettings() - self.ui.setupUi(self) - self.core = LegendaryCoreSingleton() - self.settings = QSettings(self) - - self.wrapper_settings = WrapperSettings(self) - self.ui.launch_layout.setWidget( - self.ui.launch_layout.getWidgetPosition(self.ui.wrapper_label)[0], - QFormLayout.FieldRole, - self.wrapper_settings - ) - - self.env_vars = EnvVars(self) - # dxvk - self.dxvk = DxvkSettings(self) - self.dxvk.environ_changed.connect(self.env_vars.reset_model) - self.dxvk.load_settings(self.app_name) - - self.mangohud = MangoHudSettings(self) - self.mangohud.environ_changed.connect(self.environ_changed) - self.mangohud.load_settings(self.name) - - if pf.system() != "Windows": - self.linux_settings = LinuxAppSettings(self) - self.ui.game_settings_layout.addWidget(self.linux_settings) - - self.linux_settings.mangohud.set_wrapper_activated.connect( - 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) - - if pf.system() != "Darwin": - self.proton_settings = ProtonSettings(self.linux_settings, self.wrapper_settings) - self.linux_settings.ui.linux_settings_layout.insertWidget(0, self.proton_settings) - self.proton_settings.environ_changed.connect(self.env_vars.reset_model) - - self.ui.game_settings_layout.setAlignment(Qt.AlignTop) - - self.ui.main_layout.addWidget(self.dxvk) - self.ui.main_layout.addWidget(self.mangohud) - self.ui.main_layout.addWidget(self.env_vars) - - if is_default: - self.ui.launch_layout.removeRow(self.ui.skip_update_label) - self.ui.launch_layout.removeRow(self.ui.offline_label) - self.ui.launch_layout.removeRow(self.ui.launch_params_label) - self.ui.launch_layout.removeRow(self.ui.override_exe_label) - self.ui.launch_layout.removeRow(self.ui.pre_launch_label) - self.load_settings("default") - - def load_settings(self, app_name): - self.app_name = app_name - self.wrapper_settings.load_settings(app_name) - - if pf.system() != "Windows": - self.linux_settings.update_game(app_name) - if pf.system() != "Darwin": - proton = self.wrapper_settings.wrappers.get("proton", "") - if proton: - proton = proton.text - self.proton_settings.load_settings(app_name, proton) - else: - proton = "" - self.linux_settings.ui.wine_groupbox.setDisabled(bool(proton)) - - self.env_vars.update_game(app_name) diff --git a/rare/components/tabs/settings/legendary.py b/rare/components/tabs/settings/legendary.py index c88594dd..efac9157 100644 --- a/rare/components/tabs/settings/legendary.py +++ b/rare/components/tabs/settings/legendary.py @@ -4,6 +4,7 @@ from logging import getLogger from typing import Tuple, List from PyQt5.QtCore import QObject, pyqtSignal, QThreadPool, QSettings +from PyQt5.QtGui import QShowEvent, QHideEvent from PyQt5.QtWidgets import QSizePolicy, QWidget, QFileDialog, QMessageBox from rare.models.options import options @@ -132,6 +133,17 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): self.refresh_metadata_button.setEnabled(False) self.refresh_metadata_button.setVisible(False) + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + return super().showEvent(a0) + + def hideEvent(self, a0: QHideEvent): + if a0.spontaneous(): + return super().hideEvent(a0) + self.core.lgd.save_config() + return super().hideEvent(a0) + def refresh_metadata(self): self.refresh_metadata_button.setDisabled(True) platforms = [] @@ -163,7 +175,6 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): else: if self.core.lgd.config.has_option("Legendary", "locale"): self.core.lgd.config.remove_option("Legendary", "locale") - self.core.lgd.save_config() def __mac_path_save(self, text: str) -> None: self.__path_save(text, "mac_install_dir") @@ -179,34 +190,29 @@ class LegendarySettings(QWidget, Ui_LegendarySettings): self.core.lgd.config["Legendary"].pop(option) else: logger.debug(f"Set %s option in config to %s", option, text) - self.core.lgd.save_config() def max_worker_save(self, workers: str): if workers := int(workers): self.core.lgd.config.set("Legendary", "max_workers", str(workers)) else: self.core.lgd.config.remove_option("Legendary", "max_workers") - self.core.lgd.save_config() def max_memory_save(self, memory: str): if memory := int(memory): self.core.lgd.config.set("Legendary", "max_memory", str(memory)) else: self.core.lgd.config.remove_option("Legendary", "max_memory") - self.core.lgd.save_config() def preferred_cdn_save(self, cdn: str): if cdn: self.core.lgd.config.set("Legendary", "preferred_cdn", cdn.strip()) else: self.core.lgd.config.remove_option("Legendary", "preferred_cdn") - self.core.lgd.save_config() def disable_https_save(self, checked: int): self.core.lgd.config.set( "Legendary", "disable_https", str(bool(checked)).lower() ) - self.core.lgd.save_config() def cleanup(self, keep_manifests: bool): before = self.core.lgd.get_dir_size() diff --git a/rare/components/tabs/settings/settings.py b/rare/components/tabs/settings/settings.py new file mode 100644 index 00000000..a638a705 --- /dev/null +++ b/rare/components/tabs/settings/settings.py @@ -0,0 +1,24 @@ +from logging import getLogger + +from .widgets.env_vars import EnvVars +from .widgets.game import GameSettingsBase +from .widgets.launch import LaunchSettingsBase +from .widgets.overlay import MangoHudSettings, DxvkSettings +from .widgets.proton import ProtonSettings +from .widgets.wine import WineSettings +from .widgets.wrappers import WrapperSettings + +logger = getLogger("GameSettings") + + +class LaunchSettings(LaunchSettingsBase): + def __init__(self, parent=None): + super(LaunchSettings, self).__init__(WrapperSettings, parent=parent) + + +class GameSettings(GameSettingsBase): + def __init__(self, parent=None): + super(GameSettings, self).__init__( + LaunchSettings, WineSettings, ProtonSettings, DxvkSettings, MangoHudSettings, EnvVars, + parent=parent + ) diff --git a/rare/components/tabs/settings/widgets/dxvk.py b/rare/components/tabs/settings/widgets/dxvk.py deleted file mode 100644 index 372b0bac..00000000 --- a/rare/components/tabs/settings/widgets/dxvk.py +++ /dev/null @@ -1,27 +0,0 @@ -from PyQt5.QtCore import QCoreApplication - -from .overlays import OverlaySettings, CustomOption - - -class DxvkSettings(OverlaySettings): - def __init__(self, parent=None): - super(DxvkSettings, self).__init__( - [ - ("fps", QCoreApplication.translate("DxvkSettings", "FPS")), - ("frametime", QCoreApplication.translate("DxvkSettings", "Frametime")), - ("memory", QCoreApplication.translate("DxvkSettings", "Memory usage")), - ("gpuload", QCoreApplication.translate("DxvkSettings", "GPU usage")), - ("devinfo", QCoreApplication.translate("DxvkSettings", "Show Device info")), - ("version", QCoreApplication.translate("DxvkSettings", "DXVK Version")), - ("api", QCoreApplication.translate("DxvkSettings", "D3D feature level")), - ("compiler", QCoreApplication.translate("DxvkSettings", "Compiler activity")), - ], - [ - (CustomOption.number_input("scale", 1, True), QCoreApplication.translate("DxvkSettings", "Scale")) - ], - "DXVK_HUD", "0", - parent=parent - ) - - self.setTitle(self.tr("DXVK Settings")) - self.gb_options.setTitle(self.tr("Custom options")) diff --git a/rare/components/tabs/settings/widgets/env_vars.py b/rare/components/tabs/settings/widgets/env_vars.py index f2e066a6..1b55fb56 100644 --- a/rare/components/tabs/settings/widgets/env_vars.py +++ b/rare/components/tabs/settings/widgets/env_vars.py @@ -1,6 +1,7 @@ from logging import getLogger from PyQt5.QtCore import QFileSystemWatcher, Qt +from PyQt5.QtGui import QShowEvent from PyQt5.QtWidgets import ( QGroupBox, QHeaderView, @@ -20,6 +21,7 @@ class EnvVars(QGroupBox): self.setTitle(self.tr("Environment variables")) self.core = LegendaryCoreSingleton() + self.app_name: str = "default" self.table_model = EnvVarsTableModel(self.core) self.table_view = QTableView(self) @@ -44,6 +46,12 @@ class EnvVars(QGroupBox): layout = QVBoxLayout(self) layout.addWidget(self.table_view) + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + self.table_model.load(self.app_name) + return super().showEvent(a0) + def keyPressEvent(self, a0): if a0.key() in {Qt.Key_Delete, Qt.Key_Backspace}: indexes = self.table_view.selectedIndexes() @@ -59,6 +67,3 @@ class EnvVars(QGroupBox): def reset_model(self): self.table_model.reset() - - def update_game(self, app_name): - self.table_model.load(app_name) diff --git a/rare/components/tabs/settings/widgets/game.py b/rare/components/tabs/settings/widgets/game.py new file mode 100644 index 00000000..88d1944a --- /dev/null +++ b/rare/components/tabs/settings/widgets/game.py @@ -0,0 +1,76 @@ +import platform as pf +from typing import Type + +from PyQt5.QtCore import QSettings, Qt +from PyQt5.QtGui import QHideEvent +from PyQt5.QtWidgets import ( + QWidget, + QVBoxLayout +) + +from rare.shared import LegendaryCoreSingleton +from rare.widgets.side_tab import SideTabContents +from rare.utils import config_helper as config +from .env_vars import EnvVars +from .launch import LaunchSettingsType +from .overlay import MangoHudSettings, DxvkSettings +from .proton import ProtonSettings +from .wine import WineSettings + + +class GameSettingsBase(QWidget, SideTabContents): + + def __init__( + self, + launch_widget: Type[LaunchSettingsType], + wine_widget: Type[WineSettings], + proton_widget: Type[ProtonSettings], + dxvk_widget: Type[DxvkSettings], + mangohud_widget: Type[MangoHudSettings], + envvar_widget: Type[EnvVars], + parent=None + ): + super(GameSettingsBase, self).__init__(parent=parent) + + self.core = LegendaryCoreSingleton() + self.settings = QSettings(self) + self.app_name: str = "default" + + self.launch = launch_widget(self) + self.env_vars = envvar_widget(self) + + if pf.system() != "Windows": + self.wine = wine_widget(self) + self.wine.environ_changed.connect(self.env_vars.reset_model) + + if pf.system() == "Linux": + self.proton_tool = proton_widget(self) + self.proton_tool.environ_changed.connect(self.env_vars.reset_model) + self.proton_tool.tool_enabled.connect(self.wine.tool_enabled) + self.proton_tool.tool_enabled.connect(self.launch.tool_enabled) + + self.mangohud = mangohud_widget(self) + self.mangohud.environ_changed.connect(self.env_vars.reset_model) + + self.dxvk = dxvk_widget(self) + self.dxvk.environ_changed.connect(self.env_vars.reset_model) + + self.main_layout = QVBoxLayout(self) + self.main_layout.addWidget(self.launch) + if pf.system() != "Windows": + self.main_layout.addWidget(self.wine) + if pf.system() == "Linux": + self.main_layout.addWidget(self.proton_tool) + self.main_layout.addWidget(self.mangohud) + self.main_layout.addWidget(self.dxvk) + if pf.system() == "Linux": + self.main_layout.addWidget(self.mangohud) + self.main_layout.addWidget(self.env_vars) + + self.main_layout.setAlignment(Qt.AlignTop) + + def hideEvent(self, a0: QHideEvent): + if a0.spontaneous(): + return super().hideEvent(a0) + config.save_config() + return super().hideEvent(a0) diff --git a/rare/components/tabs/settings/widgets/launch.py b/rare/components/tabs/settings/widgets/launch.py new file mode 100644 index 00000000..72d3defe --- /dev/null +++ b/rare/components/tabs/settings/widgets/launch.py @@ -0,0 +1,91 @@ +import os +import shutil +from typing import Tuple, Type, TypeVar + +from PyQt5.QtCore import Qt, pyqtSlot +from PyQt5.QtGui import QShowEvent +from PyQt5.QtWidgets import QCheckBox, QFileDialog, QFormLayout, QVBoxLayout, QGroupBox + +from rare.shared import LegendaryCoreSingleton +import rare.utils.config_helper as config +from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon +from .wrappers import WrapperSettings + + +class LaunchSettingsBase(QGroupBox): + + def __init__( + self, + wrapper_widget: Type[WrapperSettings], + parent=None + ): + super(LaunchSettingsBase, self).__init__(parent=parent) + self.setTitle(self.tr("Launch Settings")) + + self.core = LegendaryCoreSingleton() + self.app_name: str = "default" + + self.prelaunch_edit = PathEdit( + path="", + placeholder=self.tr("Path to script or program to run before the game launches"), + file_mode=QFileDialog.ExistingFile, + edit_func=self.__prelaunch_edit_callback, + save_func=self.__prelaunch_save_callback, + ) + + self.wrappers_widget = wrapper_widget(self) + + self.prelaunch_check = QCheckBox(self.tr("Wait for command to finish before starting the game")) + font = self.font() + font.setItalic(True) + self.prelaunch_check.setFont(font) + self.prelaunch_check.stateChanged.connect(self.__prelauch_check_changed) + + prelaunch_layout = QVBoxLayout() + prelaunch_layout.addWidget(self.prelaunch_edit) + prelaunch_layout.addWidget(self.prelaunch_check) + + self.main_layout = QFormLayout(self) + self.main_layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow) + self.main_layout.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter) + self.main_layout.setFormAlignment(Qt.AlignLeading | Qt.AlignTop) + + self.main_layout.addRow(self.tr("Wrappers"), self.wrappers_widget) + self.main_layout.addRow(self.tr("Prelaunch"), prelaunch_layout) + + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + command = config.get_option(self.app_name, "pre_launch_command", fallback="") + wait = config.get_boolean(self.app_name, "pre_launch_wait", fallback=False) + + self.prelaunch_edit.setText(command) + self.prelaunch_check.setChecked(wait) + self.prelaunch_check.setEnabled(bool(command)) + + return super().showEvent(a0) + + @pyqtSlot() + def tool_enabled(self): + self.wrappers_widget.update_state() + + @staticmethod + def __prelaunch_edit_callback(text: str) -> Tuple[bool, str, int]: + if not text.strip(): + return True, text, IndicatorReasonsCommon.VALID + if not os.path.isfile(text.split()[0]) and not shutil.which(text.split()[0]): + return False, text, IndicatorReasonsCommon.FILE_NOT_EXISTS + else: + return True, text, IndicatorReasonsCommon.VALID + + def __prelaunch_save_callback(self, text): + config.save_option(self.app_name, "pre_launch_command", text) + self.prelaunch_check.setEnabled(bool(text)) + if not text: + config.remove_option(self.app_name, "pre_launch_wait") + + def __prelauch_check_changed(self): + config.set_boolean(self.app_name, "pre_launch_wait", self.prelaunch_check.isChecked()) + + +LaunchSettingsType = TypeVar("LaunchSettingsType", bound=LaunchSettingsBase) diff --git a/rare/components/tabs/settings/widgets/mangohud.py b/rare/components/tabs/settings/widgets/mangohud.py deleted file mode 100644 index a9394c4e..00000000 --- a/rare/components/tabs/settings/widgets/mangohud.py +++ /dev/null @@ -1,108 +0,0 @@ -import shutil -from enum import Enum - -from PyQt5.QtCore import QCoreApplication, pyqtSignal -from PyQt5.QtWidgets import QMessageBox - -from rare.shared import LegendaryCoreSingleton -from rare.utils import config_helper -from .overlays import OverlaySettings, CustomOption, ActivationStates - -position_values = ["default", "top-left", "top-right", "middle-left", "middle-right", "bottom-left", - "bottom-right", "top-center"] - - -class MangoHudSettings(OverlaySettings): - set_wrapper_activated = pyqtSignal(bool) - - def __init__(self, parent=None): - super(MangoHudSettings, self).__init__( - [ - ("fps", QCoreApplication.translate("MangoSettings", "FPS")), - ("frame_timing", QCoreApplication.translate("MangoSettings", "Frame Time")), - ("cpu_stats", QCoreApplication.translate("MangoSettings", "CPU Load")), - ("gpu_stats", QCoreApplication.translate("MangoSettings", "GPU Load")), - ("cpu_temp", QCoreApplication.translate("MangoSettings", "CPU Temp")), - ("gpu_temp", QCoreApplication.translate("MangoSettings", "GPU Temp")), - ("ram", QCoreApplication.translate("MangoSettings", "Memory usage")), - ("vram", QCoreApplication.translate("MangoSettings", "VRAM usage")), - ("time", QCoreApplication.translate("MangoSettings", "Local Time")), - ("version", QCoreApplication.translate("MangoSettings", "MangoHud Version")), - ("arch", QCoreApplication.translate("MangoSettings", "System architecture")), - ("histogram", QCoreApplication.translate("MangoSettings", "FPS Graph")), - ("gpu_name", QCoreApplication.translate("MangoSettings", "GPU Name")), - ("cpu_power", QCoreApplication.translate("MangoSettings", "CPU Power consumption")), - ("gpu_power", QCoreApplication.translate("MangoSettings", "GPU Power consumption")), - ], - [ - ( - CustomOption.number_input("font_size", 24, is_float=False), - QCoreApplication.translate("MangoSettings", "Font size") - ), - ( - CustomOption.select_input("position", position_values), - QCoreApplication.translate("MangoSettings", "Position") - ) - ], - "MANGOHUD_CONFIG", "no_display", set_activation_state=self.set_activation_state, - parent=parent - ) - self.core = LegendaryCoreSingleton() - self.setTitle(self.tr("MangoHud Settings")) - self.gb_options.setTitle(self.tr("Custom options")) - - def load_settings(self, name: str): - self.settings_updatable = False - self.name = name - # override - cfg = self.core.lgd.config.get(f"{name}.env", "MANGOHUD_CONFIG", fallback="") - activated = "mangohud" in self.core.lgd.config.get(name, "wrapper", fallback="") - if not activated: - self.settings_updatable = False - self.gb_options.setDisabled(True) - for i, checkbox in enumerate(list(self.checkboxes.values())): - checkbox.setChecked(i < 4) - self.show_overlay_combo.setCurrentIndex(0) - self.settings_updatable = True - return - super(MangoHudSettings, self).load_settings(name) - self.settings_updatable = False - self.show_overlay_combo.setCurrentIndex(2) - self.gb_options.setDisabled(False) - for var_name, checkbox in list(self.checkboxes.items())[:4]: - checkbox.setChecked(f"{var_name}=0" not in cfg) - self.settings_updatable = True - - def set_activation_state(self, state: Enum): # pylint: disable=E0202 - if state in [ActivationStates.DEFAULT, ActivationStates.HIDDEN]: - self.set_wrapper_activated.emit(False) - self.gb_options.setDisabled(True) - - elif state == ActivationStates.ACTIVATED: - if not shutil.which("mangohud"): - self.show_overlay_combo.setCurrentIndex(0) - QMessageBox.warning(self, "Error", self.tr("Mangohud is not installed or not in path")) - return - - cfg = self.core.lgd.config.get(f"{self.name}.env", "MANGOHUD_CONFIG", fallback="") - - split_config = cfg.split(",") - for name in list(self.checkboxes.keys())[:4]: - if name in split_config: - split_config.remove(name) - cfg = ",".join(split_config) - - for var_name, checkbox in list(self.checkboxes.items())[:4]: # first three are by default activated - if not checkbox.isChecked(): - if cfg: - cfg += f",{var_name}=0" - else: - cfg = f"{var_name}=0" - if cfg: - config_helper.add_option(f"{self.name}.env", "MANGOHUD_CONFIG", cfg) - self.environ_changed.emit(self.config_env_var_name) - else: - config_helper.remove_option(f"{self.name}.env", "MANGOHUD_CONFIG") - self.environ_changed.emit(self.config_env_var_name) - - self.set_wrapper_activated.emit(True) diff --git a/rare/components/tabs/settings/widgets/overlay.py b/rare/components/tabs/settings/widgets/overlay.py new file mode 100644 index 00000000..eaf2658e --- /dev/null +++ b/rare/components/tabs/settings/widgets/overlay.py @@ -0,0 +1,333 @@ +from abc import abstractmethod +from enum import Enum, IntEnum +from logging import getLogger +from typing import List, Dict, Tuple, Any, Union + +from PyQt5.QtCore import QCoreApplication, pyqtSignal +from PyQt5.QtGui import QIntValidator, QDoubleValidator, QShowEvent +from PyQt5.QtWidgets import QGroupBox, QCheckBox, QLineEdit, QComboBox + +from rare.shared import LegendaryCoreSingleton +from rare.ui.components.tabs.settings.widgets.overlay import Ui_OverlaySettings +from rare.utils import config_helper as config + +logger = getLogger("GameOverlays") + + +class OverlayLineEdit(QLineEdit): + def __init__(self, parent=None): + super(OverlayLineEdit, self).__init__(parent=parent) + self.valueChanged = self.textChanged + self.setValue = self.setText + + def setDefault(self): + self.setText("") + + def getValue(self): + return self.text() + + +class OverlayComboBox(QComboBox): + def __init__(self, parent=None): + super(OverlayComboBox, self).__init__(parent=parent) + self.valueChanged = self.currentIndexChanged + self.getValue = self.currentText + self.setValue = self.setCurrentText + + def setDefault(self): + self.setCurrentIndex(0) + + +class CustomOption: + option: str + widget: Union[OverlayLineEdit, OverlayComboBox] + + @classmethod + def string_input(cls, option: str, placeholder: str): + tmp = cls() + tmp.option = option + tmp.widget = OverlayLineEdit() + tmp.widget.setPlaceholderText(placeholder) + return tmp + + @classmethod + def number_input(cls, option: str, placeholder: Any, is_float: bool = False): + tmp = cls() + tmp.option = option + tmp.widget = OverlayLineEdit() + tmp.widget.setPlaceholderText(str(placeholder)) + validator = QDoubleValidator() if is_float else QIntValidator() + tmp.widget.setValidator(validator) + return tmp + + @classmethod + def select_input(cls, option: str, values: List[str]): + """options: default value in options[0]""" + tmp = cls() + tmp.option = option + tmp.widget = OverlayComboBox() + tmp.widget.addItems(values) + return tmp + + +class ActivationStates(IntEnum): + DEFAULT = -1 + HIDDEN = 0 + ENABLED = 1 + + +class OverlaySettings(QGroupBox): + # str: option key + environ_changed = pyqtSignal(str) + + def __init__(self, parent=None): + super(OverlaySettings, self).__init__(parent=parent) + self.ui = Ui_OverlaySettings() + self.ui.setupUi(self) + + self.core = LegendaryCoreSingleton() + self.envvar_name: str = None + self.force_disabled: str = None + self.app_name: str = "default" + self.checkboxes: Dict[str, QCheckBox] = {} + self.values: Dict[str, Union[OverlayLineEdit, OverlayComboBox]] = {} + + self.ui.options_group.setTitle(self.tr("Custom options")) + self.ui.show_overlay_combo.currentIndexChanged.connect(self.update_settings) + + def setupWidget( + self, + checkbox_map: List[Tuple[str, str]], + custom_map: List[Tuple[CustomOption, str]], + envvar_name: str, + force_disabled: str, + ): + self.envvar_name = envvar_name + self.force_disabled = force_disabled + + for i, (variable, text) in enumerate(checkbox_map): + checkbox = QCheckBox(text) + self.ui.options_grid.addWidget(checkbox, i // 4, i % 4) + self.checkboxes[variable] = checkbox + checkbox.stateChanged.connect(self.update_settings) + + for option, text in custom_map: + widget = option.widget + self.ui.options_form.addRow(text, widget) + self.values[option.option] = widget + widget.valueChanged.connect(self.update_settings) + + @abstractmethod + def set_activation_state(self, state: ActivationStates): + raise NotImplemented + + def update_settings(self): + + if self.ui.show_overlay_combo.currentIndex() == 0: + # System default + config.remove_envvar(self.app_name, self.envvar_name) + self.environ_changed.emit(self.envvar_name) + self.ui.options_group.setDisabled(True) + self.set_activation_state(ActivationStates.DEFAULT) + return + + elif self.ui.show_overlay_combo.currentIndex() == 1: + # hidden + config.set_envvar(self.app_name, self.envvar_name, self.force_disabled) + self.environ_changed.emit(self.envvar_name) + self.ui.options_group.setDisabled(True) + self.set_activation_state(ActivationStates.HIDDEN) + return + elif self.ui.show_overlay_combo.currentIndex() == 2: + self.ui.options_group.setDisabled(False) + # custom options + var_names = [] + for var_name, cb in self.checkboxes.items(): + if cb.isChecked(): + var_names.append(var_name) + + for var_name, widget in self.values.items(): + text = widget.getValue() + if text not in ["default", ""]: + var_names.append(f"{var_name}={text}") + + if not var_names: + list(self.checkboxes.values())[0].setChecked(True) + var_names.append(list(self.checkboxes.keys())[0]) + + config.set_envvar(self.app_name, self.envvar_name, ",".join(var_names)) + self.environ_changed.emit(self.envvar_name) + self.set_activation_state(ActivationStates.ENABLED) + + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + + for checkbox in self.checkboxes.values(): + checkbox.setChecked(False) + for widget in self.values.values(): + widget.setDefault() + + options = config.get_envvar(self.app_name, self.envvar_name, fallback=None) + if options is None: + logger.debug(f"No Overlay settings found {self.envvar_name}") + self.ui.show_overlay_combo.setCurrentIndex(0) + self.ui.options_group.setDisabled(True) + + elif options == self.force_disabled: + # not visible + self.ui.options_group.setDisabled(True) + self.ui.show_overlay_combo.setCurrentIndex(1) + + else: + self.ui.show_overlay_combo.setCurrentIndex(2) + for option in options.split(","): + try: + if "=" in option: + key, value = option.split("=") + if key in self.checkboxes.keys(): + self.checkboxes[key].setChecked(False) + else: + self.values[key].setValue(value) + else: + self.checkboxes[option].setChecked(True) + except Exception as e: + logger.warning(e) + + self.ui.options_group.setDisabled(False) + + return super().showEvent(a0) + + +class DxvkSettings(OverlaySettings): + def __init__(self, parent=None): + super(DxvkSettings, self).__init__(parent=parent) + self.setTitle(self.tr("DXVK Settings")) + self.setupWidget( + [ + ("fps", QCoreApplication.translate("DxvkSettings", "FPS")), + ("frametime", QCoreApplication.translate("DxvkSettings", "Frametime")), + ("memory", QCoreApplication.translate("DxvkSettings", "Memory usage")), + ("gpuload", QCoreApplication.translate("DxvkSettings", "GPU usage")), + ("devinfo", QCoreApplication.translate("DxvkSettings", "Show Device info")), + ("version", QCoreApplication.translate("DxvkSettings", "DXVK Version")), + ("api", QCoreApplication.translate("DxvkSettings", "D3D feature level")), + ("compiler", QCoreApplication.translate("DxvkSettings", "Compiler activity")), + ], + [ + ( + CustomOption.number_input("scale", 1, True), + QCoreApplication.translate("DxvkSettings", "Scale"), + ) + ], + "DXVK_HUD", + "0", + ) + + def set_activation_state(self, state: ActivationStates): + pass + + +mangohud_position = [ + "default", + "top-left", + "top-right", + "middle-left", + "middle-right", + "bottom-left", + "bottom-right", + "top-center", +] + + +class MangoHudSettings(OverlaySettings): + def __init__(self, parent=None): + super(MangoHudSettings, self).__init__(parent=parent) + self.setTitle(self.tr("MangoHud Settings")) + self.setupWidget( + [ + ("fps", QCoreApplication.translate("MangoSettings", "FPS")), + ("frame_timing", QCoreApplication.translate("MangoSettings", "Frame Time")), + ("cpu_stats", QCoreApplication.translate("MangoSettings", "CPU Load")), + ("gpu_stats", QCoreApplication.translate("MangoSettings", "GPU Load")), + ("cpu_temp", QCoreApplication.translate("MangoSettings", "CPU Temp")), + ("gpu_temp", QCoreApplication.translate("MangoSettings", "GPU Temp")), + ("ram", QCoreApplication.translate("MangoSettings", "Memory usage")), + ("vram", QCoreApplication.translate("MangoSettings", "VRAM usage")), + ("time", QCoreApplication.translate("MangoSettings", "Local Time")), + ("version", QCoreApplication.translate("MangoSettings", "MangoHud Version")), + ("arch", QCoreApplication.translate("MangoSettings", "System architecture")), + ("histogram", QCoreApplication.translate("MangoSettings", "FPS Graph")), + ("gpu_name", QCoreApplication.translate("MangoSettings", "GPU Name")), + ("cpu_power", QCoreApplication.translate("MangoSettings", "CPU Power consumption")), + ("gpu_power", QCoreApplication.translate("MangoSettings", "GPU Power consumption")), + ], + [ + ( + CustomOption.number_input("font_size", 24, is_float=False), + QCoreApplication.translate("MangoSettings", "Font size"), + ), + ( + CustomOption.select_input("position", mangohud_position), + QCoreApplication.translate("MangoSettings", "Position"), + ), + ], + "MANGOHUD_CONFIG", + "no_display", + ) + + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + + # override + activated = bool(config.get_envvar(self.app_name, "MANGOHUD", None)) + mango_config = config.get_envvar(self.app_name, "MANGOHUD_CONFIG", fallback="") + if not activated: + self.ui.options_group.setDisabled(True) + for i, checkbox in enumerate(list(self.checkboxes.values())): + checkbox.setChecked(i < 4) + self.ui.show_overlay_combo.setCurrentIndex(0) + return + self.ui.show_overlay_combo.setCurrentIndex(2) + self.ui.options_group.setDisabled(False) + for var_name, checkbox in list(self.checkboxes.items())[:4]: + checkbox.setChecked(f"{var_name}=0" not in mango_config) + + return super().showEvent(a0) + + def set_activation_state(self, state: IntEnum): # pylint: disable=E0202 + if state == ActivationStates.DEFAULT: + config.remove_envvar(self.app_name, "MANGOHUD") + config.remove_envvar(self.app_name, "MANGOHUD_CONFIG") + self.ui.options_group.setDisabled(True) + + elif state == ActivationStates.HIDDEN: + config.set_envvar(self.app_name, "MANGOHUD", "1") + config.set_envvar(self.app_name, "MANGOHUD_CONFIG", self.force_disabled) + + elif state == ActivationStates.ENABLED: + + mango_config = config.get_envvar(self.app_name, "MANGOHUD_CONFIG", fallback="") + + split_config = mango_config.split(",") + for name in list(self.checkboxes.keys())[:4]: + if name in split_config: + split_config.remove(name) + mango_config = ",".join(split_config) + + # first three are activated by default + for var_name, checkbox in list(self.checkboxes.items())[:4]: + if not checkbox.isChecked(): + if mango_config: + mango_config += f",{var_name}=0" + else: + mango_config = f"{var_name}=0" + if mango_config: + config.set_envvar(self.app_name, "MANGOHUD", "1") + config.set_envvar(self.app_name, "MANGOHUD_CONFIG", mango_config) + else: + config.remove_envvar(self.app_name, "MANGOHUD") + config.remove_envvar(self.app_name, "MANGOHUD_CONFIG") + self.environ_changed.emit("MANGOHUD") + self.environ_changed.emit("MANGOHUD_CONFIG") diff --git a/rare/components/tabs/settings/widgets/overlays.py b/rare/components/tabs/settings/widgets/overlays.py deleted file mode 100644 index 5fd85bf5..00000000 --- a/rare/components/tabs/settings/widgets/overlays.py +++ /dev/null @@ -1,190 +0,0 @@ -from enum import Enum -from logging import getLogger -from typing import List, Dict, Tuple, Any, Callable - -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtGui import QIntValidator, QDoubleValidator -from PyQt5.QtWidgets import QGroupBox, QCheckBox, QWidget, QLineEdit, QLabel, QComboBox - -from rare.shared import LegendaryCoreSingleton -from rare.ui.components.tabs.settings.widgets.overlay import Ui_OverlaySettings -from rare.utils import config_helper - -logger = getLogger("GameOverlays") - - -class TextInputField(QLineEdit): - def __init__(self): - super(TextInputField, self).__init__() - self.value_changed = self.textChanged - self.set_value = self.setText - self.set_default = lambda: self.setText("") - - def get_value(self): - return self.text() - - -class ComboBox(QComboBox): - def __init__(self): - super(ComboBox, self).__init__() - self.value_changed = self.currentIndexChanged - self.get_value = self.currentText - self.set_value = self.setCurrentText - self.set_default = lambda: self.setCurrentIndex(0) - - -class CustomOption: - input_field: QWidget - var_name: str - - @classmethod - def string_input(cls, var_name: str, placeholder: str): - tmp = cls() - tmp.input_field = TextInputField() - tmp.var_name = var_name - tmp.input_field.setPlaceholderText(placeholder) - return tmp - - @classmethod - def number_input(cls, var_name: str, placeholder: Any, is_float: bool = False): - tmp = cls() - tmp.input_field = TextInputField() - tmp.var_name = var_name - tmp.input_field.setPlaceholderText(str(placeholder)) - if is_float: - validator = QDoubleValidator() - else: - validator = QIntValidator() - tmp.input_field.setValidator(validator) - return tmp - - @classmethod - def select_input(cls, var_name: str, options: List[str]): - """options: default value in options[0]""" - tmp = cls() - tmp.input_field = ComboBox() - tmp.var_name = var_name - tmp.input_field.addItems(options) - return tmp - - -class ActivationStates(Enum): - DEFAULT = 0 - HIDDEN = 1 - ACTIVATED = 2 - - -class OverlaySettings(QGroupBox, Ui_OverlaySettings): - # str: option key - environ_changed = pyqtSignal(str) - name: str = "default" - settings_updatable = True - - def __init__(self, checkboxes_map: List[Tuple[str, str]], value_map: List[Tuple[CustomOption, str]], - config_env_var_name: str, no_display_value: str, - set_activation_state: Callable[[Enum], None] = lambda x: None, parent=None): - super(OverlaySettings, self).__init__(parent=parent) - self.setupUi(self) - self.core = LegendaryCoreSingleton() - self.config_env_var_name = config_env_var_name - self.no_display_value = no_display_value - self.set_activation_state = set_activation_state - - self.checkboxes: Dict[str, QCheckBox] = {} - - for i, (var_name, translated_text) in enumerate(checkboxes_map): - cb = QCheckBox(translated_text) - self.options_grid.addWidget(cb, i // 4, i % 4) - self.checkboxes[var_name] = cb - cb.stateChanged.connect(self.update_settings) - - self.values: Dict[str, QWidget] = {} - - num_rows = len(checkboxes_map) // 4 - for custom_option, translated_text in value_map: - input_field = custom_option.input_field - self.options_form.addRow(QLabel(translated_text), input_field) - self.values[custom_option.var_name] = input_field - input_field.value_changed.connect(self.update_settings) - num_rows += 1 - - self.show_overlay_combo.currentIndexChanged.connect(self.update_settings) - - def update_settings(self): - if not self.settings_updatable: - return - if self.show_overlay_combo.currentIndex() == 0: - # System default - config_helper.remove_option(f"{self.name}.env", self.config_env_var_name) - self.environ_changed.emit(self.config_env_var_name) - self.gb_options.setDisabled(True) - self.set_activation_state(ActivationStates.DEFAULT) - return - - elif self.show_overlay_combo.currentIndex() == 1: - # hidden - config_helper.add_option(f"{self.name}.env", self.config_env_var_name, self.no_display_value) - self.environ_changed.emit(self.config_env_var_name) - self.gb_options.setDisabled(True) - self.set_activation_state(ActivationStates.HIDDEN) - return - elif self.show_overlay_combo.currentIndex() == 2: - self.gb_options.setDisabled(False) - # custom options - var_names = [] - for var_name, cb in self.checkboxes.items(): - if cb.isChecked(): - var_names.append(var_name) - - for var_name, input_field in self.values.items(): - text = input_field.get_value() - if text not in ["default", ""]: - var_names.append(f"{var_name}={text}") - - if not var_names: - list(self.checkboxes.values())[0].setChecked(True) - var_names.append(list(self.checkboxes.keys())[0]) - - config_helper.add_option(f"{self.name}.env", self.config_env_var_name, ",".join(var_names)) - self.environ_changed.emit(self.config_env_var_name) - self.set_activation_state(ActivationStates.ACTIVATED) - - def load_settings(self, name: str): - self.settings_updatable = False - # load game specific - self.name = name - - for checkbox in self.checkboxes.values(): - checkbox.setChecked(False) - for input_field in self.values.values(): - input_field.set_default() - - options = self.core.lgd.config.get(f"{self.name}.env", self.config_env_var_name, fallback=None) - if options is None: - logger.debug(f"No Overlay settings found {self.config_env_var_name}") - self.show_overlay_combo.setCurrentIndex(0) - self.gb_options.setDisabled(True) - - elif options == self.no_display_value: - # not visible - self.gb_options.setDisabled(True) - self.show_overlay_combo.setCurrentIndex(1) - - else: - self.show_overlay_combo.setCurrentIndex(2) - for option in options.split(","): - try: - if "=" in option: - var_name, value = option.split("=") - if var_name in self.checkboxes.keys(): - self.checkboxes[var_name].setChecked(False) - else: - self.values[var_name].set_value(value) - else: - self.checkboxes[option].setChecked(True) - except Exception as e: - logger.warning(e) - - self.gb_options.setDisabled(False) - - self.settings_updatable = True diff --git a/rare/components/tabs/settings/widgets/pre_launch.py b/rare/components/tabs/settings/widgets/pre_launch.py deleted file mode 100644 index 411e9ce1..00000000 --- a/rare/components/tabs/settings/widgets/pre_launch.py +++ /dev/null @@ -1,64 +0,0 @@ -import os -import shutil -from typing import Tuple - -from PyQt5.QtWidgets import QHBoxLayout, QCheckBox, QFileDialog, QWidget - -from rare.shared import LegendaryCoreSingleton -from rare.utils import config_helper -from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon - - -class PreLaunchSettings(QWidget): - app_name: str - - def __init__(self, parent=None): - super(PreLaunchSettings, self).__init__(parent=parent) - self.core = LegendaryCoreSingleton() - self.edit = PathEdit( - path="", - placeholder=self.tr("Path to script"), - file_mode=QFileDialog.ExistingFile, - edit_func=self.edit_command, - save_func=self.save_pre_launch_command, - ) - - self.wait_check = QCheckBox(self.tr("Wait for finish")) - self.wait_check.stateChanged.connect(self.save_wait_finish) - - layout = QHBoxLayout(self) - layout.setContentsMargins(0, 0, 0, 0) - layout.addWidget(self.edit) - layout.addWidget(self.wait_check) - - def edit_command(self, text: str) -> Tuple[bool, str, int]: - if not text.strip(): - return True, text, IndicatorReasonsCommon.VALID - - if not os.path.isfile(text.split()[0]) and not shutil.which(text.split()[0]): - return False, text, IndicatorReasonsCommon.FILE_NOT_EXISTS - else: - return True, text, IndicatorReasonsCommon.VALID - - def save_pre_launch_command(self, text): - if text: - config_helper.add_option(self.app_name, "pre_launch_command", text) - self.wait_check.setDisabled(False) - else: - config_helper.remove_option(self.app_name, "pre_launch_command") - self.wait_check.setDisabled(True) - config_helper.remove_option(self.app_name, "pre_launch_wait") - - def save_wait_finish(self): - config_helper.add_option(self.app_name, "pre_launch_wait", str(self.wait_check.isChecked()).lower()) - - def load_settings(self, app_name): - self.app_name = app_name - - command = self.core.lgd.config.get(app_name, "pre_launch_command", fallback="") - self.edit.setText(command) - - wait = self.core.lgd.config.getboolean(app_name, "pre_launch_wait", fallback=False) - self.wait_check.setChecked(wait) - - self.wait_check.setEnabled(bool(command)) diff --git a/rare/components/tabs/settings/widgets/proton.py b/rare/components/tabs/settings/widgets/proton.py index 4505bcfe..1c2baf5e 100644 --- a/rare/components/tabs/settings/widgets/proton.py +++ b/rare/components/tabs/settings/widgets/proton.py @@ -2,14 +2,13 @@ import os from logging import getLogger from typing import Tuple, Union, Optional -from PyQt5.QtCore import pyqtSignal +from PyQt5.QtCore import pyqtSignal, Qt from PyQt5.QtGui import QShowEvent -from PyQt5.QtWidgets import QGroupBox, QFileDialog +from PyQt5.QtWidgets import QGroupBox, QFileDialog, QFormLayout, QComboBox, QLabel from rare.models.wrapper import Wrapper, WrapperType from rare.shared import RareCore from rare.shared.wrappers import Wrappers -from rare.ui.components.tabs.settings.proton import Ui_ProtonSettings from rare.utils import config_helper as config from rare.utils.runners import proton from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon @@ -25,17 +24,25 @@ class ProtonSettings(QGroupBox): def __init__(self, parent=None): super(ProtonSettings, self).__init__(parent=parent) - self.ui = Ui_ProtonSettings() - self.ui.setupUi(self) + self.setTitle(self.tr("Proton Settings")) - self.ui.proton_combo.currentIndexChanged.connect(self.__on_proton_changed) - self.proton_prefix = PathEdit( + self.tool_combo = QComboBox(self) + self.tool_combo.currentIndexChanged.connect(self.__on_proton_changed) + + self.tool_prefix = PathEdit( file_mode=QFileDialog.DirectoryOnly, edit_func=self.proton_prefix_edit, save_func=self.proton_prefix_save, placeholder=self.tr("Please select path for proton prefix"), + parent=self ) - self.ui.prefix_layout.addWidget(self.proton_prefix) + + layout = QFormLayout(self) + layout.addRow(self.tr("Proton tool"), self.tool_combo) + layout.addRow(self.tr("Compat data"), self.tool_prefix) + layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow) + layout.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter) + layout.setFormAlignment(Qt.AlignLeading | Qt.AlignTop) self.app_name: str = "default" self.core = RareCore.instance().core() @@ -45,39 +52,39 @@ class ProtonSettings(QGroupBox): def showEvent(self, a0: QShowEvent) -> None: if a0.spontaneous(): return super().showEvent(a0) - self.ui.proton_combo.blockSignals(True) - self.ui.proton_combo.clear() - self.ui.proton_combo.addItem(self.tr("Don't use a compatibility tool"), None) + + self.tool_combo.blockSignals(True) + self.tool_combo.clear() + self.tool_combo.addItem(self.tr("Don't use a compatibility tool"), None) tools = proton.find_tools() for tool in tools: - self.ui.proton_combo.addItem(tool.name, tool) + self.tool_combo.addItem(tool.name, tool) try: wrapper = next( filter(lambda w: w.is_compat_tool, self.wrappers.get_game_wrapper_list(self.app_name)) ) self.tool_wrapper = wrapper tool = next(filter(lambda t: t.checksum == wrapper.checksum, tools)) - index = self.ui.proton_combo.findData(tool) + index = self.tool_combo.findData(tool) except StopIteration: index = 0 - self.ui.proton_combo.setCurrentIndex(index) - self.ui.proton_combo.blockSignals(False) - enabled = bool(self.ui.proton_combo.currentIndex()) - self.proton_prefix.blockSignals(True) - self.proton_prefix.setText(config.get_envvar(self.app_name, "STEAM_COMPAT_DATA_PATH", fallback="")) - self.proton_prefix.setEnabled(enabled) - self.proton_prefix.blockSignals(False) + self.tool_combo.setCurrentIndex(index) + self.tool_combo.blockSignals(False) + + enabled = bool(self.tool_combo.currentData(Qt.UserRole)) + self.tool_prefix.blockSignals(True) + self.tool_prefix.setText(config.get_proton_compatdata(self.app_name, fallback="")) + self.tool_prefix.setEnabled(enabled) + self.tool_prefix.blockSignals(False) + super().showEvent(a0) def __on_proton_changed(self, index): - steam_tool: Union[proton.ProtonTool, proton.CompatibilityTool] = self.ui.proton_combo.itemData(index) + steam_tool: Union[proton.ProtonTool, proton.CompatibilityTool] = self.tool_combo.itemData(index) steam_environ = proton.get_steam_environment(steam_tool) for key, value in steam_environ.items(): - if not value: - config.remove_envvar(self.app_name, key) - else: - config.add_envvar(self.app_name, key, value) + config.save_envvar(self.app_name, key, value) self.environ_changed.emit(key) wrappers = self.wrappers.get_game_wrapper_list(self.app_name) @@ -93,11 +100,11 @@ class ProtonSettings(QGroupBox): self.tool_wrapper = wrapper self.wrappers.set_game_wrapper_list(self.app_name, wrappers) - self.proton_prefix.setEnabled(steam_tool is not None) - self.proton_prefix.setText(os.path.expanduser("~/.proton") if steam_tool is not None else "") + self.tool_prefix.setEnabled(steam_tool is not None) + if steam_tool and not config.get_proton_compatdata(self.app_name, fallback=""): + self.tool_prefix.setText(os.path.expanduser("~/.proton")) self.tool_enabled.emit(steam_tool is not None) - config.save_config() @staticmethod def proton_prefix_edit(text: str) -> Tuple[bool, str, int]: @@ -109,9 +116,6 @@ class ProtonSettings(QGroupBox): def proton_prefix_save(self, text: str): if not text: return - config.add_envvar(self.app_name, "STEAM_COMPAT_DATA_PATH", text) + config.save_proton_compatdata(self.app_name, text) self.environ_changed.emit("STEAM_COMPAT_DATA_PATH") - config.save_config() - def load_settings(self, app_name: str): - self.app_name = app_name diff --git a/rare/components/tabs/settings/widgets/unix.py b/rare/components/tabs/settings/widgets/unix.py deleted file mode 100644 index 28c9f21a..00000000 --- a/rare/components/tabs/settings/widgets/unix.py +++ /dev/null @@ -1,15 +0,0 @@ -from components.tabs.settings import LinuxSettings - - -class LinuxAppSettings(LinuxSettings): - def __init__(self, parent=None): - super(LinuxAppSettings, self).__init__(parent=parent) - - def update_game(self, app_name): - self.name = app_name - self.wine_prefix.setText(self.load_prefix()) - self.wine_exec.setText(self.load_setting(self.name, "wine_executable")) - - self.dxvk.load_settings(self.name) - - self.mangohud.load_settings(self.name) \ No newline at end of file diff --git a/rare/components/tabs/settings/widgets/wine.py b/rare/components/tabs/settings/widgets/wine.py index cf7a8d27..c110dfcc 100644 --- a/rare/components/tabs/settings/widgets/wine.py +++ b/rare/components/tabs/settings/widgets/wine.py @@ -1,83 +1,92 @@ import os -import shutil from logging import getLogger +from typing import Optional -from PyQt5.QtCore import pyqtSignal -from PyQt5.QtWidgets import QFileDialog, QWidget, QFormLayout, QGroupBox +from PyQt5.QtCore import pyqtSignal, Qt, QSignalBlocker +from PyQt5.QtGui import QShowEvent +from PyQt5.QtWidgets import QFileDialog, QFormLayout, QGroupBox from rare.shared import LegendaryCoreSingleton, GlobalSignalsSingleton -from rare.ui.components.tabs.settings.widgets.wine import Ui_WineSettings +from rare.utils import config_helper as config from rare.widgets.indicator_edit import PathEdit, IndicatorReasonsCommon -from rare.utils import config_helper -logger = getLogger("LinuxSettings") +logger = getLogger("WineSettings") class WineSettings(QGroupBox): # str: option key environ_changed = pyqtSignal(str) - def __init__(self, name=None, parent=None): + def __init__(self, parent=None): super(WineSettings, self).__init__(parent=parent) - self.ui = Ui_WineSettings() - self.ui.setupUi(self) + self.setTitle(self.tr("Wine Setings")) self.core = LegendaryCoreSingleton() self.signals = GlobalSignalsSingleton() - self.app_name: str = "default" + self.app_name: Optional[str] = "default" # Wine prefix self.wine_prefix = PathEdit( - self.load_prefix(), + path="", file_mode=QFileDialog.DirectoryOnly, edit_func=lambda path: (os.path.isdir(path) or not path, path, IndicatorReasonsCommon.DIR_NOT_EXISTS), save_func=self.save_prefix, ) - self.ui.main_layout.setWidget( - self.ui.main_layout.getWidgetPosition(self.ui.prefix_label)[0], - QFormLayout.FieldRole, - self.wine_prefix - ) # Wine executable self.wine_exec = PathEdit( - self.load_setting(self.app_name, "wine_executable"), + path="", file_mode=QFileDialog.ExistingFile, name_filters=["wine", "wine64"], edit_func=lambda text: (os.path.exists(text) or not text, text, IndicatorReasonsCommon.DIR_NOT_EXISTS), - save_func=lambda text: self.save_setting( - text, section=self.app_name, setting="wine_executable" - ), - ) - self.ui.main_layout.setWidget( - self.ui.main_layout.getWidgetPosition(self.ui.exec_label)[0], - QFormLayout.FieldRole, - self.wine_exec + save_func=self.save_exec, ) + layout = QFormLayout(self) + layout.addRow(self.tr("Prefix"), self.wine_prefix) + layout.addRow(self.tr("Executable"), self.wine_exec) + layout.setFieldGrowthPolicy(QFormLayout.FieldGrowthPolicy.ExpandingFieldsGrow) + layout.setLabelAlignment(Qt.AlignRight | Qt.AlignVCenter) + layout.setFormAlignment(Qt.AlignLeading | Qt.AlignTop) + + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + + _ = QSignalBlocker(self.wine_prefix) + self.wine_prefix.setText(self.load_prefix()) + _ = QSignalBlocker(self.wine_exec) + self.wine_exec.setText(self.load_exec()) + self.setDisabled(config.get_boolean(self.app_name, "no_wine", fallback=False)) + + return super().showEvent(a0) + + def tool_enabled(self, enabled: bool): + if enabled: + config.set_boolean(self.app_name, "no_wine", True) + else: + config.remove_option(self.app_name, "no_wine") + self.setDisabled(enabled) + def load_prefix(self) -> str: - return self.load_setting( - f"{self.app_name}.env", - "WINEPREFIX", - fallback=self.load_setting(self.app_name, "wine_prefix"), - ) + if self.app_name is None: + raise RuntimeError + return config.get_wine_prefix(self.app_name, "") - def save_prefix(self, text: str): - self.save_setting(text, f"{self.app_name}.env", "WINEPREFIX") + def save_prefix(self, path: str) -> None: + if self.app_name is None: + raise RuntimeError + config.save_wine_prefix(self.app_name, path) self.environ_changed.emit("WINEPREFIX") - self.save_setting(text, self.app_name, "wine_prefix") self.signals.application.prefix_updated.emit() - def load_setting(self, section: str, setting: str, fallback: str = ""): - return self.core.lgd.config.get(section, setting, fallback=fallback) + def load_exec(self) -> str: + if self.app_name is None: + raise RuntimeError + return config.get_option(self.app_name, "wine_executable", "") - @staticmethod - def save_setting(text: str, section: str, setting: str): - if text: - config_helper.add_option(section, setting, text) - logger.debug(f"Set {setting} in {f'[{section}]'} to {text}") - else: - config_helper.remove_option(section, setting) - logger.debug(f"Unset {setting} from {f'[{section}]'}") - config_helper.save_config() + def save_exec(self, text: str) -> None: + if self.app_name is None: + raise RuntimeError + config.save_option(self.app_name, "wine_executable", text) diff --git a/rare/components/tabs/settings/widgets/wrapper.py b/rare/components/tabs/settings/widgets/wrappers.py similarity index 88% rename from rare/components/tabs/settings/widgets/wrapper.py rename to rare/components/tabs/settings/widgets/wrappers.py index def0af39..786ac709 100644 --- a/rare/components/tabs/settings/widgets/wrapper.py +++ b/rare/components/tabs/settings/widgets/wrappers.py @@ -4,7 +4,7 @@ from logging import getLogger from typing import Optional from PyQt5.QtCore import pyqtSignal, QSize, Qt, QMimeData, pyqtSlot, QCoreApplication -from PyQt5.QtGui import QDrag, QDropEvent, QDragEnterEvent, QDragMoveEvent, QFont, QMouseEvent +from PyQt5.QtGui import QDrag, QDropEvent, QDragEnterEvent, QDragMoveEvent, QFont, QMouseEvent, QShowEvent from PyQt5.QtWidgets import ( QHBoxLayout, QLabel, @@ -16,21 +16,16 @@ from PyQt5.QtWidgets import ( QScrollArea, QAction, QToolButton, - QMenu, QDialog, + QMenu, QDialog, QStackedWidget, QPushButton, ) from rare.models.wrapper import Wrapper from rare.shared import RareCore -from rare.ui.components.tabs.settings.widgets.wrapper import Ui_WrapperSettings from rare.utils.misc import icon from rare.utils.runners import proton logger = getLogger("WrapperSettings") -# extra_wrapper_regex = { -# "proton": "\".*proton\" run", # proton -# } - class WrapperDialog(QDialog): pass @@ -122,37 +117,54 @@ class WrapperWidget(QFrame): class WrapperSettings(QWidget): def __init__(self, parent=None): super(WrapperSettings, self).__init__(parent=parent) - self.ui = Ui_WrapperSettings() - self.ui.setupUi(self) + self.widget_stack = QStackedWidget(self) - self.wrapper_scroll = QScrollArea(self.ui.widget_stack) - self.wrapper_scroll.setWidgetResizable(True) + self.wrapper_scroll = QScrollArea(self.widget_stack) self.wrapper_scroll.setSizeAdjustPolicy(QScrollArea.AdjustToContents) self.wrapper_scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) + self.wrapper_scroll.setWidgetResizable(True) self.wrapper_scroll.setProperty("no_kinetic_scroll", True) self.wrapper_container = WrapperContainer(parent=self.wrapper_scroll) self.wrapper_container.orderChanged.connect(self.__on_order_changed) self.wrapper_scroll.setWidget(self.wrapper_container) - self.ui.widget_stack.insertWidget(0, self.wrapper_scroll) - self.ui.add_button.clicked.connect(self.__on_add_button_pressed) + self.no_wrapper_label = QLabel(self.tr("No wrappers defined"), self.widget_stack) + + self.widget_stack.addWidget(self.wrapper_scroll) + self.widget_stack.addWidget(self.no_wrapper_label) + + self.add_button = QPushButton(self.tr("Add wrapper"), self) + self.add_button.clicked.connect(self.__on_add_button_pressed) + self.wrapper_scroll.horizontalScrollBar().rangeChanged.connect(self.adjust_scrollarea) # lk: set object names for the stylesheet - self.setObjectName(type(self).__name__) - self.ui.no_wrapper_label.setObjectName(f"{self.objectName()}Label") + self.setObjectName("WrapperSettings") + self.no_wrapper_label.setObjectName(f"{self.objectName()}Label") self.wrapper_scroll.setObjectName(f"{self.objectName()}Scroll") self.wrapper_scroll.horizontalScrollBar().setObjectName( f"{self.wrapper_scroll.objectName()}Bar") self.wrapper_scroll.verticalScrollBar().setObjectName( f"{self.wrapper_scroll.objectName()}Bar") - self.ui.wrapper_settings_layout.setAlignment(Qt.AlignTop) + main_layout = QHBoxLayout(self) + main_layout.addWidget(self.widget_stack) + main_layout.addWidget(self.add_button, alignment=Qt.AlignTop) + main_layout.setContentsMargins(0, 0, 0, 0) + main_layout.setAlignment(Qt.AlignTop) + + self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) self.app_name: str = "default" self.core = RareCore.instance().core() self.wrappers = RareCore.instance().wrappers() + def showEvent(self, a0: QShowEvent): + if a0.spontaneous(): + return super().showEvent(a0) + self.update_state() + return super().showEvent(a0) + @pyqtSlot(int, int) def adjust_scrollarea(self, minh: int, maxh: int): wrapper_widget = self.wrapper_container.findChild(WrapperWidget) @@ -195,7 +207,7 @@ class WrapperSettings(QWidget): self.add_user_wrapper(wrapper) def __add_wrapper(self, wrapper: Wrapper, position: int = -1): - self.ui.widget_stack.setCurrentIndex(0) + self.widget_stack.setCurrentWidget(self.wrapper_scroll) widget = WrapperWidget(wrapper, self.wrapper_container) if position < 0: self.wrapper_container.addWidget(widget) @@ -230,15 +242,6 @@ class WrapperSettings(QWidget): ) return - # if text == "mangohud" and self.wrappers.get("mangohud"): - # return - # show_text = "" - # for key, extra_wrapper in extra_wrapper_regex.items(): - # if re.match(extra_wrapper, text): - # show_text = key - # if not show_text: - # show_text = text.split()[0] - if wrapper.checksum in self.wrappers.get_game_md5sum_list(self.app_name): QMessageBox.warning( self, self.tr("Warning"), self.tr("Wrapper {0} is already in the list").format(wrapper.command) @@ -264,8 +267,8 @@ class WrapperSettings(QWidget): wrappers.remove(wrapper) self.wrappers.set_game_wrapper_list(self.app_name, wrappers) if not wrappers: - self.wrapper_scroll.setMaximumHeight(self.ui.label_page.sizeHint().height()) - self.ui.widget_stack.setCurrentIndex(1) + self.wrapper_scroll.setMaximumHeight(self.no_wrapper_label.sizeHint().height()) + self.widget_stack.setCurrentWidget(self.no_wrapper_label) @pyqtSlot(object, object) def __update_wrapper(self, old: Wrapper, new: Wrapper): @@ -282,17 +285,13 @@ class WrapperSettings(QWidget): w.deleteLater() wrappers = self.wrappers.get_game_wrapper_list(self.app_name) if not wrappers: - self.wrapper_scroll.setMaximumHeight(self.ui.label_page.sizeHint().height()) - self.ui.widget_stack.setCurrentIndex(1) + self.wrapper_scroll.setMaximumHeight(self.no_wrapper_label.sizeHint().height()) + self.widget_stack.setCurrentWidget(self.no_wrapper_label) else: - self.ui.widget_stack.setCurrentIndex(0) + self.widget_stack.setCurrentWidget(self.wrapper_scroll) for wrapper in wrappers: self.__add_wrapper(wrapper) - def load_settings(self, app_name: str): - self.app_name = app_name - self.update_state() - class WrapperContainer(QWidget): # QWidget: moving widget, int: new index diff --git a/rare/models/game.py b/rare/models/game.py index 94b31f08..a0d2a1a2 100644 --- a/rare/models/game.py +++ b/rare/models/game.py @@ -19,7 +19,7 @@ from rare.shared.game_process import GameProcess from rare.shared.image_manager import ImageManager from rare.utils.paths import data_dir, get_rare_executable from rare.utils.steam_grades import get_rating -from rare.utils.config_helper import add_envvar +from rare.utils.config_helper import set_envvar logger = getLogger("RareGame") @@ -448,9 +448,9 @@ class RareGame(RareGameSlim): def set_steam_grade(self, appid: int, grade: str) -> None: if appid and self.steam_appid is None: - add_envvar(self.app_name, "SteamAppId", str(appid)) - add_envvar(self.app_name, "SteamGameId", str(appid)) - add_envvar(self.app_name, "STEAM_COMPAT_APP_ID", str(appid)) + set_envvar(self.app_name, "SteamAppId", str(appid)) + set_envvar(self.app_name, "SteamGameId", str(appid)) + set_envvar(self.app_name, "STEAM_COMPAT_APP_ID", str(appid)) self.metadata.steam_appid = appid self.metadata.steam_grade = grade self.metadata.steam_date = datetime.utcnow() diff --git a/rare/shared/wrappers.py b/rare/shared/wrappers.py index 3d146919..707c8438 100644 --- a/rare/shared/wrappers.py +++ b/rare/shared/wrappers.py @@ -102,11 +102,7 @@ class Wrappers: def __save_config(self, app_name: str): command_string = self.get_game_wrapper_string(app_name) - if command_string: - config.add_option(app_name, "wrapper", command_string) - else: - config.remove_option(app_name, "wrapper") - config.save_config() + config.save_option(app_name, "wrapper", command_string) def __save_wrappers(self): existing = {wrap_id for wrap_id in self.__wrappers.keys()} @@ -132,7 +128,7 @@ if __name__ == "__main__": config_dir = os.getcwd global config config = Namespace() - config.add_option = lambda x, y, z: print(x, y, z) + config.set_option = lambda x, y, z: print(x, y, z) config.remove_option = lambda x, y: print(x, y) config.save_config = lambda: print() diff --git a/rare/ui/components/tabs/settings/game.py b/rare/ui/components/tabs/settings/game.py deleted file mode 100644 index ee43ea14..00000000 --- a/rare/ui/components/tabs/settings/game.py +++ /dev/null @@ -1,103 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/game_settings.ui' -# -# 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. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_GameSettings(object): - def setupUi(self, GameSettings): - GameSettings.setObjectName("GameSettings") - GameSettings.resize(393, 202) - self.main_layout = QtWidgets.QVBoxLayout(GameSettings) - self.main_layout.setObjectName("main_layout") - self.launch_settings_group = QtWidgets.QGroupBox(GameSettings) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.launch_settings_group.sizePolicy().hasHeightForWidth()) - self.launch_settings_group.setSizePolicy(sizePolicy) - self.launch_settings_group.setObjectName("launch_settings_group") - self.launch_layout = QtWidgets.QFormLayout(self.launch_settings_group) - self.launch_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.launch_layout.setObjectName("launch_layout") - self.skip_update_label = QtWidgets.QLabel(self.launch_settings_group) - self.skip_update_label.setObjectName("skip_update_label") - self.launch_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.skip_update_label) - self.skip_update_combo = QtWidgets.QComboBox(self.launch_settings_group) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.skip_update_combo.sizePolicy().hasHeightForWidth()) - self.skip_update_combo.setSizePolicy(sizePolicy) - self.skip_update_combo.setObjectName("skip_update_combo") - self.skip_update_combo.addItem("") - self.skip_update_combo.addItem("") - self.skip_update_combo.addItem("") - self.launch_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.skip_update_combo) - self.offline_label = QtWidgets.QLabel(self.launch_settings_group) - self.offline_label.setObjectName("offline_label") - self.launch_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.offline_label) - self.offline_combo = QtWidgets.QComboBox(self.launch_settings_group) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.offline_combo.sizePolicy().hasHeightForWidth()) - self.offline_combo.setSizePolicy(sizePolicy) - self.offline_combo.setObjectName("offline_combo") - self.offline_combo.addItem("") - self.offline_combo.addItem("") - self.offline_combo.addItem("") - self.launch_layout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.offline_combo) - self.launch_params_label = QtWidgets.QLabel(self.launch_settings_group) - self.launch_params_label.setObjectName("launch_params_label") - self.launch_layout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.launch_params_label) - self.launch_params_edit = QtWidgets.QLineEdit(self.launch_settings_group) - self.launch_params_edit.setObjectName("launch_params_edit") - self.launch_layout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.launch_params_edit) - self.pre_launch_label = QtWidgets.QLabel(self.launch_settings_group) - self.pre_launch_label.setObjectName("pre_launch_label") - self.launch_layout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.pre_launch_label) - self.override_exe_label = QtWidgets.QLabel(self.launch_settings_group) - self.override_exe_label.setObjectName("override_exe_label") - self.launch_layout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.override_exe_label) - self.wrapper_label = QtWidgets.QLabel(self.launch_settings_group) - self.wrapper_label.setObjectName("wrapper_label") - self.launch_layout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.wrapper_label) - self.main_layout.addWidget(self.launch_settings_group) - - self.retranslateUi(GameSettings) - - def retranslateUi(self, GameSettings): - _translate = QtCore.QCoreApplication.translate - GameSettings.setWindowTitle(_translate("GameSettings", "GameSettings")) - self.launch_settings_group.setTitle(_translate("GameSettings", "Launch Settings")) - self.skip_update_label.setText(_translate("GameSettings", "Skip update check")) - self.skip_update_combo.setItemText(0, _translate("GameSettings", "Default")) - self.skip_update_combo.setItemText(1, _translate("GameSettings", "Yes")) - self.skip_update_combo.setItemText(2, _translate("GameSettings", "No")) - self.offline_label.setText(_translate("GameSettings", "Offline mode")) - self.offline_combo.setItemText(0, _translate("GameSettings", "Default")) - self.offline_combo.setItemText(1, _translate("GameSettings", "Yes")) - self.offline_combo.setItemText(2, _translate("GameSettings", "No")) - self.launch_params_label.setText(_translate("GameSettings", "Launch parameters")) - self.launch_params_edit.setPlaceholderText(_translate("GameSettings", "parameters")) - self.pre_launch_label.setText(_translate("GameSettings", "Pre-launch command")) - self.override_exe_label.setText(_translate("GameSettings", "Override executable")) - self.wrapper_label.setText(_translate("GameSettings", "Wrappers")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - GameSettings = QtWidgets.QWidget() - ui = Ui_GameSettings() - ui.setupUi(GameSettings) - GameSettings.show() - sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/game.ui b/rare/ui/components/tabs/settings/game.ui deleted file mode 100644 index 88c26201..00000000 --- a/rare/ui/components/tabs/settings/game.ui +++ /dev/null @@ -1,138 +0,0 @@ - - - GameSettings - - - - 0 - 0 - 393 - 202 - - - - GameSettings - - - - - - - 0 - 0 - - - - Launch Settings - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Skip update check - - - - - - - - 0 - 0 - - - - - Default - - - - - Yes - - - - - No - - - - - - - - Offline mode - - - - - - - - 0 - 0 - - - - - Default - - - - - Yes - - - - - No - - - - - - - - Launch parameters - - - - - - - parameters - - - - - - - Pre-launch command - - - - - - - Override executable - - - - - - - Wrappers - - - - - - - - - - - diff --git a/rare/ui/components/tabs/settings/widgets/dxvk.py b/rare/ui/components/tabs/settings/widgets/dxvk.py deleted file mode 100644 index 2f76cd82..00000000 --- a/rare/ui/components/tabs/settings/widgets/dxvk.py +++ /dev/null @@ -1,97 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/widgets/dxvk.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_DxvkSettings(object): - def setupUi(self, DxvkSettings): - DxvkSettings.setObjectName("DxvkSettings") - DxvkSettings.resize(419, 185) - self.dxvk_layout = QtWidgets.QGridLayout(DxvkSettings) - self.dxvk_layout.setObjectName("dxvk_layout") - self.gb_dxvk_options = QtWidgets.QGroupBox(DxvkSettings) - self.gb_dxvk_options.setObjectName("gb_dxvk_options") - self.layout_dxvk_options = QtWidgets.QGridLayout(self.gb_dxvk_options) - self.layout_dxvk_options.setObjectName("layout_dxvk_options") - self.version = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.version.setObjectName("version") - self.layout_dxvk_options.addWidget(self.version, 0, 2, 1, 1) - self.fps = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.fps.setObjectName("fps") - self.layout_dxvk_options.addWidget(self.fps, 1, 0, 1, 1) - self.memory = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.memory.setObjectName("memory") - self.layout_dxvk_options.addWidget(self.memory, 0, 1, 1, 1) - self.devinfo = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.devinfo.setObjectName("devinfo") - self.layout_dxvk_options.addWidget(self.devinfo, 0, 0, 1, 1) - self.gpuload = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.gpuload.setObjectName("gpuload") - self.layout_dxvk_options.addWidget(self.gpuload, 1, 1, 1, 1) - self.frametime = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.frametime.setObjectName("frametime") - self.layout_dxvk_options.addWidget(self.frametime, 2, 0, 1, 1) - spacerItem = QtWidgets.QSpacerItem(0, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.layout_dxvk_options.addItem(spacerItem, 0, 3, 3, 1) - self.api = QtWidgets.QCheckBox(self.gb_dxvk_options) - self.api.setObjectName("api") - self.layout_dxvk_options.addWidget(self.api, 1, 2, 1, 1) - self.dxvk_layout.addWidget(self.gb_dxvk_options, 2, 0, 1, 3) - self.lbl_show_dxvk = QtWidgets.QLabel(DxvkSettings) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lbl_show_dxvk.sizePolicy().hasHeightForWidth()) - self.lbl_show_dxvk.setSizePolicy(sizePolicy) - self.lbl_show_dxvk.setObjectName("lbl_show_dxvk") - self.dxvk_layout.addWidget(self.lbl_show_dxvk, 0, 0, 1, 1) - self.show_dxvk = QtWidgets.QComboBox(DxvkSettings) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.show_dxvk.sizePolicy().hasHeightForWidth()) - self.show_dxvk.setSizePolicy(sizePolicy) - self.show_dxvk.setObjectName("show_dxvk") - self.show_dxvk.addItem("") - self.show_dxvk.addItem("") - self.show_dxvk.addItem("") - self.show_dxvk.addItem("") - self.dxvk_layout.addWidget(self.show_dxvk, 0, 1, 1, 2) - - self.retranslateUi(DxvkSettings) - - def retranslateUi(self, DxvkSettings): - _translate = QtCore.QCoreApplication.translate - DxvkSettings.setWindowTitle(_translate("DxvkSettings", "DxvkSettings")) - DxvkSettings.setTitle(_translate("DxvkSettings", "DXVK Settings")) - self.gb_dxvk_options.setTitle(_translate("DxvkSettings", "DXVK HUD Options")) - self.version.setText(_translate("DxvkSettings", "DXVK Version")) - self.fps.setText(_translate("DxvkSettings", "FPS")) - self.memory.setText(_translate("DxvkSettings", "Memory Usage")) - self.devinfo.setText(_translate("DxvkSettings", "Device Info")) - self.gpuload.setText(_translate("DxvkSettings", "GPU Usage")) - self.frametime.setText(_translate("DxvkSettings", "Frame Time graph")) - self.api.setText(_translate("DxvkSettings", "D3D Version")) - self.lbl_show_dxvk.setText(_translate("DxvkSettings", "Show HUD")) - self.show_dxvk.setItemText(0, _translate("DxvkSettings", "System Default")) - self.show_dxvk.setItemText(1, _translate("DxvkSettings", "Hidden")) - self.show_dxvk.setItemText(2, _translate("DxvkSettings", "Visible")) - self.show_dxvk.setItemText(3, _translate("DxvkSettings", "Custom Options")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - DxvkSettings = QtWidgets.QGroupBox() - ui = Ui_DxvkSettings() - ui.setupUi(DxvkSettings) - DxvkSettings.show() - sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/widgets/dxvk.ui b/rare/ui/components/tabs/settings/widgets/dxvk.ui deleted file mode 100644 index 5da74df7..00000000 --- a/rare/ui/components/tabs/settings/widgets/dxvk.ui +++ /dev/null @@ -1,138 +0,0 @@ - - - DxvkSettings - - - - 0 - 0 - 419 - 185 - - - - DxvkSettings - - - DXVK Settings - - - - - - DXVK HUD Options - - - - - - DXVK Version - - - - - - - FPS - - - - - - - Memory Usage - - - - - - - Device Info - - - - - - - GPU Usage - - - - - - - Frame Time graph - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - D3D Version - - - - - - - - - - - 0 - 0 - - - - Show HUD - - - - - - - - 0 - 0 - - - - - System Default - - - - - Hidden - - - - - Visible - - - - - Custom Options - - - - - - - - - diff --git a/rare/ui/components/tabs/settings/widgets/overlay.py b/rare/ui/components/tabs/settings/widgets/overlay.py index 30617b63..075320a4 100644 --- a/rare/ui/components/tabs/settings/widgets/overlay.py +++ b/rare/ui/components/tabs/settings/widgets/overlay.py @@ -2,7 +2,7 @@ # Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/widgets/overlay.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. @@ -17,16 +17,16 @@ class Ui_OverlaySettings(object): OverlaySettings.resize(555, 188) OverlaySettings.setWindowTitle("Overlay Settings") OverlaySettings.setTitle("") - self.dxvk_layout = QtWidgets.QGridLayout(OverlaySettings) - self.dxvk_layout.setObjectName("dxvk_layout") - self.lbl_show_overlay = QtWidgets.QLabel(OverlaySettings) + self.main_layout = QtWidgets.QGridLayout(OverlaySettings) + self.main_layout.setObjectName("main_layout") + self.show_overlay_label = QtWidgets.QLabel(OverlaySettings) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.lbl_show_overlay.sizePolicy().hasHeightForWidth()) - self.lbl_show_overlay.setSizePolicy(sizePolicy) - self.lbl_show_overlay.setObjectName("lbl_show_overlay") - self.dxvk_layout.addWidget(self.lbl_show_overlay, 0, 0, 1, 1) + sizePolicy.setHeightForWidth(self.show_overlay_label.sizePolicy().hasHeightForWidth()) + self.show_overlay_label.setSizePolicy(sizePolicy) + self.show_overlay_label.setObjectName("show_overlay_label") + self.main_layout.addWidget(self.show_overlay_label, 0, 0, 1, 1) self.show_overlay_combo = QtWidgets.QComboBox(OverlaySettings) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) @@ -37,27 +37,28 @@ class Ui_OverlaySettings(object): self.show_overlay_combo.addItem("") self.show_overlay_combo.addItem("") self.show_overlay_combo.addItem("") - self.dxvk_layout.addWidget(self.show_overlay_combo, 0, 1, 1, 2) - self.gb_options = QtWidgets.QGroupBox(OverlaySettings) - self.gb_options.setTitle("") - self.gb_options.setObjectName("gb_options") - self.gridLayout = QtWidgets.QGridLayout(self.gb_options) - self.gridLayout.setObjectName("gridLayout") + self.main_layout.addWidget(self.show_overlay_combo, 0, 1, 1, 2) + self.options_group = QtWidgets.QGroupBox(OverlaySettings) + self.options_group.setTitle("") + self.options_group.setObjectName("options_group") + self.options_layout = QtWidgets.QGridLayout(self.options_group) + self.options_layout.setObjectName("options_layout") self.options_form = QtWidgets.QFormLayout() + self.options_form.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) self.options_form.setObjectName("options_form") - self.gridLayout.addLayout(self.options_form, 1, 0, 1, 1) + self.options_layout.addLayout(self.options_form, 1, 0, 1, 1) self.options_grid = QtWidgets.QGridLayout() self.options_grid.setObjectName("options_grid") - self.gridLayout.addLayout(self.options_grid, 0, 0, 1, 1) + self.options_layout.addLayout(self.options_grid, 0, 0, 1, 1) spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.gridLayout.addItem(spacerItem, 0, 1, 2, 1) - self.dxvk_layout.addWidget(self.gb_options, 2, 0, 1, 3) + self.options_layout.addItem(spacerItem, 0, 1, 2, 1) + self.main_layout.addWidget(self.options_group, 2, 0, 1, 3) self.retranslateUi(OverlaySettings) def retranslateUi(self, OverlaySettings): _translate = QtCore.QCoreApplication.translate - self.lbl_show_overlay.setText(_translate("OverlaySettings", "Show HUD")) + self.show_overlay_label.setText(_translate("OverlaySettings", "Show HUD")) self.show_overlay_combo.setItemText(0, _translate("OverlaySettings", "System Default")) self.show_overlay_combo.setItemText(1, _translate("OverlaySettings", "Hidden")) self.show_overlay_combo.setItemText(2, _translate("OverlaySettings", "Visible")) diff --git a/rare/ui/components/tabs/settings/widgets/overlay.ui b/rare/ui/components/tabs/settings/widgets/overlay.ui index bee9256c..b8ba286a 100644 --- a/rare/ui/components/tabs/settings/widgets/overlay.ui +++ b/rare/ui/components/tabs/settings/widgets/overlay.ui @@ -1,90 +1,94 @@ - OverlaySettings - - - - 0 - 0 - 555 - 188 - - - - Overlay Settings - - - - - - - - - - 0 - 0 - - - - Show HUD - - - - - - - - 0 - 0 - - - - - System Default - - - - - Hidden - - - - - Visible - - - - - - - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - + OverlaySettings + + + + 0 + 0 + 555 + 188 + + + + Overlay Settings + + + + + + + + + + 0 + 0 + + + + Show HUD + - - - \ No newline at end of file + + + + + + 0 + 0 + + + + + System Default + + + + + Hidden + + + + + Visible + + + + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + diff --git a/rare/ui/components/tabs/settings/widgets/proton.py b/rare/ui/components/tabs/settings/widgets/proton.py deleted file mode 100644 index d40bfd2a..00000000 --- a/rare/ui/components/tabs/settings/widgets/proton.py +++ /dev/null @@ -1,55 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/proton.ui' -# -# 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. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_ProtonSettings(object): - def setupUi(self, ProtonSettings): - ProtonSettings.setObjectName("ProtonSettings") - ProtonSettings.resize(180, 84) - ProtonSettings.setWindowTitle("ProtonSettings") - self.main_layout = QtWidgets.QFormLayout(ProtonSettings) - self.main_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.main_layout.setObjectName("main_layout") - self.proton_wrapper_label = QtWidgets.QLabel(ProtonSettings) - self.proton_wrapper_label.setObjectName("proton_wrapper_label") - self.main_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.proton_wrapper_label) - self.proton_combo = QtWidgets.QComboBox(ProtonSettings) - sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed) - sizePolicy.setHorizontalStretch(0) - sizePolicy.setVerticalStretch(0) - sizePolicy.setHeightForWidth(self.proton_combo.sizePolicy().hasHeightForWidth()) - self.proton_combo.setSizePolicy(sizePolicy) - self.proton_combo.setObjectName("proton_combo") - self.proton_combo.addItem("") - self.main_layout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.proton_combo) - self.proton_prefix_label = QtWidgets.QLabel(ProtonSettings) - self.proton_prefix_label.setObjectName("proton_prefix_label") - self.main_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.proton_prefix_label) - - self.retranslateUi(ProtonSettings) - - def retranslateUi(self, ProtonSettings): - _translate = QtCore.QCoreApplication.translate - ProtonSettings.setTitle(_translate("ProtonSettings", "Proton Settings")) - self.proton_wrapper_label.setText(_translate("ProtonSettings", "Proton")) - self.proton_combo.setItemText(0, _translate("ProtonSettings", "Don\'t use Proton")) - self.proton_prefix_label.setText(_translate("ProtonSettings", "Prefix")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - ProtonSettings = QtWidgets.QGroupBox() - ui = Ui_ProtonSettings() - ui.setupUi(ProtonSettings) - ProtonSettings.show() - sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/widgets/proton.ui b/rare/ui/components/tabs/settings/widgets/proton.ui deleted file mode 100644 index d25ac65e..00000000 --- a/rare/ui/components/tabs/settings/widgets/proton.ui +++ /dev/null @@ -1,56 +0,0 @@ - - - ProtonSettings - - - - 0 - 0 - 180 - 84 - - - - ProtonSettings - - - Proton Settings - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Proton - - - - - - - - 0 - 0 - - - - - Don't use Proton - - - - - - - - Prefix - - - - - - - - diff --git a/rare/ui/components/tabs/settings/widgets/wine.py b/rare/ui/components/tabs/settings/widgets/wine.py deleted file mode 100644 index 6696e5f4..00000000 --- a/rare/ui/components/tabs/settings/widgets/wine.py +++ /dev/null @@ -1,47 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/wine.ui' -# -# 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. - - -from PyQt5 import QtCore, QtGui, QtWidgets - - -class Ui_WineSettings(object): - def setupUi(self, WineSettings): - WineSettings.setObjectName("WineSettings") - WineSettings.resize(104, 72) - WineSettings.setWindowTitle("WIneSettings") - self.main_layout = QtWidgets.QFormLayout(WineSettings) - self.main_layout.setLabelAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.main_layout.setObjectName("main_layout") - self.prefix_label = QtWidgets.QLabel(WineSettings) - self.prefix_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.prefix_label.setObjectName("prefix_label") - self.main_layout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.prefix_label) - self.exec_label = QtWidgets.QLabel(WineSettings) - self.exec_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) - self.exec_label.setObjectName("exec_label") - self.main_layout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.exec_label) - - self.retranslateUi(WineSettings) - - def retranslateUi(self, WineSettings): - _translate = QtCore.QCoreApplication.translate - WineSettings.setTitle(_translate("WineSettings", "Wine Settings")) - self.prefix_label.setText(_translate("WineSettings", "Prefix")) - self.exec_label.setText(_translate("WineSettings", "Executable")) - - -if __name__ == "__main__": - import sys - app = QtWidgets.QApplication(sys.argv) - WineSettings = QtWidgets.QGroupBox() - ui = Ui_WineSettings() - ui.setupUi(WineSettings) - WineSettings.show() - sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/widgets/wine.ui b/rare/ui/components/tabs/settings/widgets/wine.ui deleted file mode 100644 index ce3d5044..00000000 --- a/rare/ui/components/tabs/settings/widgets/wine.ui +++ /dev/null @@ -1,47 +0,0 @@ - - - WineSettings - - - - 0 - 0 - 104 - 72 - - - - WIneSettings - - - Wine Settings - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - Prefix - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - Executable - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - - diff --git a/rare/ui/components/tabs/settings/widgets/wrapper.py b/rare/ui/components/tabs/settings/widgets/wrapper.py deleted file mode 100644 index 3987a9f5..00000000 --- a/rare/ui/components/tabs/settings/widgets/wrapper.py +++ /dev/null @@ -1,59 +0,0 @@ -# -*- coding: utf-8 -*- - -# Form implementation generated from reading ui file 'rare/ui/components/tabs/settings/widgets/wrapper.ui' -# -# Created by: PyQt5 UI code generator 5.15.9 -# -# 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(199, 30) - WrapperSettings.setWindowTitle("WrapperSettings") - self.wrapper_settings_layout = QtWidgets.QHBoxLayout(WrapperSettings) - self.wrapper_settings_layout.setContentsMargins(0, 0, 0, 0) - self.wrapper_settings_layout.setObjectName("wrapper_settings_layout") - self.widget_stack = QtWidgets.QStackedWidget(WrapperSettings) - self.widget_stack.setObjectName("widget_stack") - self.label_page = QtWidgets.QWidget() - self.label_page.setObjectName("label_page") - self.label_page_layout = QtWidgets.QVBoxLayout(self.label_page) - self.label_page_layout.setContentsMargins(0, 0, 0, 0) - self.label_page_layout.setObjectName("label_page_layout") - self.no_wrapper_label = QtWidgets.QLabel(self.label_page) - self.no_wrapper_label.setObjectName("no_wrapper_label") - self.label_page_layout.addWidget(self.no_wrapper_label) - self.widget_stack.addWidget(self.label_page) - self.wrapper_settings_layout.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.wrapper_settings_layout.addWidget(self.add_button, 0, QtCore.Qt.AlignTop) - - self.retranslateUi(WrapperSettings) - self.widget_stack.setCurrentIndex(0) - - def retranslateUi(self, WrapperSettings): - _translate = QtCore.QCoreApplication.translate - 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.QWidget() - ui = Ui_WrapperSettings() - ui.setupUi(WrapperSettings) - WrapperSettings.show() - sys.exit(app.exec_()) diff --git a/rare/ui/components/tabs/settings/widgets/wrapper.ui b/rare/ui/components/tabs/settings/widgets/wrapper.ui deleted file mode 100644 index 00906677..00000000 --- a/rare/ui/components/tabs/settings/widgets/wrapper.ui +++ /dev/null @@ -1,76 +0,0 @@ - - - WrapperSettings - - - - 0 - 0 - 199 - 30 - - - - WrapperSettings - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - 0 - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - No wrapper added - - - - - - - - - - - - 0 - 0 - - - - Add wrapper - - - - - - - - diff --git a/rare/utils/config_helper.py b/rare/utils/config_helper.py index 66b7ac5e..3df17867 100644 --- a/rare/utils/config_helper.py +++ b/rare/utils/config_helper.py @@ -20,16 +20,28 @@ def save_config(): _save_config() -def add_option(app_name: str, option: str, value: str) -> None: +def set_option(app_name: str, option: str, value: str) -> None: value = value.replace("%%", "%").replace("%", "%%") if not _config.has_section(app_name): _config[app_name] = {} _config.set(app_name, option, value) - save_config() + # save_config() -def add_envvar(app_name: str, envvar: str, value: str) -> None: - add_option(f"{app_name}.env", envvar, value) +def set_boolean(app_name: str, option: str, value: bool) -> None: + set_option(app_name, option, str(value).lower()) + + +def set_envvar(app_name: str, envvar: str, value: str) -> None: + set_option(f"{app_name}.env", envvar, value) + + +def remove_section(app_name: str) -> None: + return + # Disabled due to env variables implementation + # if _config.has_section(app_name): + # _config.remove_section(app_name) + # save_config() def remove_option(app_name: str, option: str) -> None: @@ -37,56 +49,82 @@ def remove_option(app_name: str, option: str) -> None: _config.remove_option(app_name, option) # if _config.has_section(app_name) and not _config[app_name]: # _config.remove_section(app_name) - save_config() + # save_config() def remove_envvar(app_name: str, option: str) -> None: remove_option(f"{app_name}.env", option) +def save_option(app_name: str, option: str, value: str) -> None: + if value: + set_option(app_name, option, value) + else: + remove_option(app_name, option) + + def get_option(app_name: str, option: str, fallback: Any = None) -> str: return _config.get(app_name, option, fallback=fallback) +def get_option_fallback(option: str, app_name: str, fallback: Any = None) -> str: + _option = get_option("default", option, fallback=fallback) + _option = get_option(app_name, option, fallback=_option) + return _option + + +def get_boolean(option: str, app_name: str, fallback: bool = False) -> bool: + return _config.getboolean(option, app_name, fallback=fallback) + + +def save_envvar(app_name: str, option: str, value: str) -> None: + if value: + set_envvar(app_name, option, value) + else: + remove_envvar(app_name, option) + + def get_envvar(app_name: str, option: str, fallback: Any = None) -> str: return get_option(f"{app_name}.env", option, fallback=fallback) -def remove_section(app_name: str) -> None: - return - # Disabled due to env variables implementation - if _config.has_section(app_name): - _config.remove_section(app_name) - save_config() - - -def get_game_option(option: str, app_name: Optional[str] = None, fallback: Any = None) -> str: - _option = _config.get("default", option, fallback=fallback) - if app_name is not None: - _option = _config.get(app_name, option, fallback=_option) - return _option - - -def get_game_envvar(option: str, app_name: Optional[str] = None, fallback: Any = None) -> str: +def get_envvar_fallback(option: str, app_name: str, fallback: Any = None) -> str: _option = _config.get("default.env", option, fallback=fallback) - if app_name is not None: - _option = _config.get(f'{app_name}.env', option, fallback=_option) + _option = _config.get(f'{app_name}.env', option, fallback=_option) return _option -def get_proton_compat_data(app_name: Optional[str] = None, fallback: Any = None) -> str: - _compat = get_game_envvar("STEAM_COMPAT_DATA_PATH", app_name, fallback=fallback) +def save_wine_prefix(app_name: str, value: str) -> None: + save_envvar(app_name, "WINEPREFIX", value) + save_option(app_name, "wine_prefix", value) + + +def get_wine_prefix(app_name: str, fallback: Any = None): + _prefix = get_envvar(app_name, 'WINEPREFIX', fallback=fallback) + _prefix = get_option(app_name, 'wine_prefix', fallback=_prefix) + return _prefix + + +def get_wine_prefix_fallback(app_name: str, fallback: Any = None) -> str: + _prefix = get_wine_prefix("default", fallback) + _prefix = get_wine_prefix(app_name, fallback=_prefix) + return _prefix + + +def save_proton_compatdata(app_name: str, value: str) -> None: + save_envvar(app_name, "STEAM_COMPAT_DATA_PATH", value) + + +def get_proton_compatdata(app_name: Optional[str] = None, fallback: Any = None) -> str: + _compat = get_envvar(app_name, "STEAM_COMPAT_DATA_PATH", fallback=fallback) # return os.path.join(_compat, "pfx") if _compat else fallback return _compat -def get_wine_prefix(app_name: Optional[str] = None, fallback: Any = None) -> str: - _prefix = _config.get("default.env", "WINEPREFIX", fallback=fallback) - _prefix = _config.get("default", "wine_prefix", fallback=_prefix) - if app_name is not None: - _prefix = _config.get(f'{app_name}.env', 'WINEPREFIX', fallback=_prefix) - _prefix = _config.get(app_name, 'wine_prefix', fallback=_prefix) - return _prefix +def get_proton_compatdata_fallback(app_name: Optional[str] = None, fallback: Any = None) -> str: + _compat = get_envvar_fallback(app_name, "STEAM_COMPAT_DATA_PATH", fallback=fallback) + # return os.path.join(_compat, "pfx") if _compat else fallback + return _compat def get_wine_prefixes() -> Set[str]: diff --git a/rare/widgets/indicator_edit.py b/rare/widgets/indicator_edit.py index 9c31a737..93132126 100644 --- a/rare/widgets/indicator_edit.py +++ b/rare/widgets/indicator_edit.py @@ -134,7 +134,7 @@ 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("Use global/default setting")) + self.line_edit.setPlaceholderText(placeholder if placeholder else self.tr("Use global/default settings")) self.line_edit.setToolTip(placeholder if placeholder else "") self.line_edit.setSizePolicy(horiz_policy, QSizePolicy.Fixed) # Add completer diff --git a/rare/widgets/path_input_dialog.py b/rare/widgets/path_input_dialog.py deleted file mode 100644 index d6d379dc..00000000 --- a/rare/widgets/path_input_dialog.py +++ /dev/null @@ -1,52 +0,0 @@ -from PyQt5.QtCore import Qt, QCoreApplication -from PyQt5.QtWidgets import ( - QHBoxLayout, - QPushButton, - QVBoxLayout, - QLabel, - QDialog, - QFileDialog, -) - -from rare.widgets.indicator_edit import PathEdit - - -class PathInputDialog(QDialog): - def __init__(self, title_text, text, path="Select Directory", parent=None): - super(PathInputDialog, self).__init__(parent=parent) - self.path = "" - self.setAttribute(Qt.WA_DeleteOnClose, True) - self.setWindowTitle(f'{title_text} - {QCoreApplication.instance().applicationName()}') - self.info_label = QLabel(text) - self.info_label.setWordWrap(True) - - self.input = PathEdit(path, QFileDialog.DirectoryOnly) - - self.layout = QVBoxLayout() - self.layout.addWidget(self.info_label) - self.layout.addWidget(self.input) - - self.child_layout = QHBoxLayout() - self.ok_button = QPushButton("Ok") - self.ok_button.clicked.connect(self.ok) - self.cancel_button = QPushButton(self.tr("Cancel")) - self.cancel_button.clicked.connect(self.cancel) - self.child_layout.addStretch() - self.child_layout.addWidget(self.ok_button) - self.child_layout.addWidget(self.cancel_button) - - self.layout.addLayout(self.child_layout) - - self.setLayout(self.layout) - - def get_path(self): - self.exec_() - return self.path - - def cancel(self): - self.path = "" - self.close() - - def ok(self): - self.path = self.input.text() - self.close() diff --git a/requirements-flatpak.txt b/requirements-flatpak.txt index 893a7e2f..696d1426 100644 --- a/requirements-flatpak.txt +++ b/requirements-flatpak.txt @@ -2,5 +2,5 @@ requests<3.0 QtAwesome setuptools legendary-gl>=0.20.34 -orjson +# orjson # needs the binary release, use req2flatpak pypresence