337 lines
12 KiB
Python
337 lines
12 KiB
Python
from abc import abstractmethod
|
|
from enum import IntEnum
|
|
from logging import getLogger
|
|
from typing import List, Dict, Tuple, Union, Optional
|
|
|
|
from PyQt5.QtCore import pyqtSignal, Qt
|
|
from PyQt5.QtGui import QIntValidator, QDoubleValidator, QShowEvent
|
|
from PyQt5.QtWidgets import QGroupBox, QCheckBox, QLineEdit, QComboBox
|
|
|
|
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, option: str, placeholder: str, parent=None):
|
|
self.option = option
|
|
super(OverlayLineEdit, self).__init__(parent=parent)
|
|
self.valueChanged = self.textChanged
|
|
|
|
self.setPlaceholderText(placeholder)
|
|
|
|
def setDefault(self):
|
|
self.setText("")
|
|
|
|
def getValue(self) -> Optional[str]:
|
|
return f"{self.option}={text}" if (text := self.text()) else None
|
|
|
|
def setValue(self, options: Dict[str, str]):
|
|
if (value := options.get(self.option, None)) is not None:
|
|
self.setText(value)
|
|
options.pop(self.option)
|
|
else:
|
|
self.setDefault()
|
|
|
|
|
|
class OverlayComboBox(QComboBox):
|
|
def __init__(self, option: str, parent=None):
|
|
self.option = option
|
|
super(OverlayComboBox, self).__init__(parent=parent)
|
|
self.valueChanged = self.currentIndexChanged
|
|
|
|
def setDefault(self):
|
|
self.setCurrentIndex(0)
|
|
|
|
def getValue(self) -> Optional[str]:
|
|
return f"{self.option}={self.currentText()}" if self.currentIndex() > 0 else None
|
|
|
|
def setValue(self, options: Dict[str, str]):
|
|
if (value := options.get(self.option, None)) is not None:
|
|
self.setCurrentText(value)
|
|
options.pop(self.option)
|
|
else:
|
|
self.setDefault()
|
|
|
|
|
|
class OverlayCheckBox(QCheckBox):
|
|
def __init__(self, option: str, title: str, desc: str = "", default_enabled: bool = False, parent=None):
|
|
self.option = option
|
|
super().__init__(title, parent=parent)
|
|
self.setChecked(default_enabled)
|
|
self.default_enabled = default_enabled
|
|
self.setToolTip(desc)
|
|
|
|
def setDefault(self):
|
|
self.setChecked(self.default_enabled)
|
|
|
|
def getValue(self) -> Optional[str]:
|
|
# lk: return the check state in case of non-default, otherwise None
|
|
checked = self.isChecked()
|
|
value = f"{self.option}={int(checked)}" if self.default_enabled else self.option
|
|
return value if checked ^ self.default_enabled else None
|
|
|
|
def setValue(self, options: Dict[str, str]):
|
|
if options.get(self.option, None) is not None:
|
|
self.setChecked(not self.default_enabled)
|
|
options.pop(self.option)
|
|
else:
|
|
self.setChecked(self.default_enabled)
|
|
|
|
|
|
class OverlayStringInput(OverlayLineEdit):
|
|
def __init__(self, option: str, placeholder: str, parent=None):
|
|
super().__init__(option, placeholder, parent=parent)
|
|
|
|
|
|
class OverlayNumberInput(OverlayLineEdit):
|
|
def __init__(self, option: str, placeholder: Union[int, float], parent=None):
|
|
super().__init__(option, str(placeholder), parent=parent)
|
|
validator = QDoubleValidator(self) if isinstance(placeholder, float) else QIntValidator(self)
|
|
self.setValidator(validator)
|
|
|
|
|
|
class OverlaySelectInput(OverlayComboBox):
|
|
def __init__(self, option: str, values: List, parent=None):
|
|
super().__init__(option, parent=parent)
|
|
# self.addItems([str(v) for v in values])
|
|
self.addItems(map(str, values))
|
|
|
|
|
|
class ActivationStates(IntEnum):
|
|
GLOBAL = -1
|
|
DISABLED = 0
|
|
DEFAULTS = 1
|
|
CUSTOM = 2
|
|
|
|
|
|
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.ui.show_overlay_combo.addItem(self.tr("Global"), ActivationStates.GLOBAL)
|
|
self.ui.show_overlay_combo.addItem(self.tr("Disabled"), ActivationStates.DISABLED)
|
|
self.ui.show_overlay_combo.addItem(self.tr("Enabled (defaults)"), ActivationStates.DEFAULTS)
|
|
self.ui.show_overlay_combo.addItem(self.tr("Enabled (custom)"), ActivationStates.CUSTOM)
|
|
|
|
self.envvar: str = None
|
|
self.force_disabled: str = None
|
|
self.force_defaults: str = None
|
|
self.app_name: str = "default"
|
|
|
|
self.option_widgets: List[Union[OverlayCheckBox, OverlayLineEdit, OverlayComboBox]] = []
|
|
# self.checkboxes: Dict[str, OverlayCheckBox] = {}
|
|
# 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,
|
|
grid_map: List[OverlayCheckBox],
|
|
form_map: List[Tuple[Union[OverlayLineEdit, OverlayComboBox], str]],
|
|
envvar: str,
|
|
force_disabled: str,
|
|
force_defaults: str,
|
|
):
|
|
self.envvar = envvar
|
|
self.force_disabled = force_disabled
|
|
self.force_defaults = force_defaults
|
|
|
|
for i, widget in enumerate(grid_map):
|
|
widget.setParent(self.ui.options_group)
|
|
self.ui.options_grid.addWidget(widget, i // 4, i % 4)
|
|
# self.checkboxes[widget.option] = widget
|
|
self.option_widgets.append(widget)
|
|
widget.stateChanged.connect(self.update_settings)
|
|
|
|
for widget, label in form_map:
|
|
widget.setParent(self.ui.options_group)
|
|
self.ui.options_form.addRow(label, widget)
|
|
# self.values[widget.option] = widget
|
|
self.option_widgets.append(widget)
|
|
widget.valueChanged.connect(self.update_settings)
|
|
|
|
@abstractmethod
|
|
def update_settings_override(self, state: ActivationStates):
|
|
raise NotImplementedError
|
|
|
|
def update_settings(self):
|
|
current_state = self.ui.show_overlay_combo.currentData(Qt.UserRole)
|
|
self.ui.options_group.setEnabled(current_state == ActivationStates.CUSTOM)
|
|
|
|
if current_state == ActivationStates.GLOBAL:
|
|
# System default (don't add any env variables)
|
|
config.remove_envvar(self.app_name, self.envvar)
|
|
|
|
elif current_state == ActivationStates.DISABLED:
|
|
# hidden
|
|
config.set_envvar(self.app_name, self.envvar, self.force_disabled)
|
|
|
|
elif current_state == ActivationStates.DEFAULTS:
|
|
config.set_envvar(self.app_name, self.envvar, self.force_defaults)
|
|
|
|
elif current_state == ActivationStates.CUSTOM:
|
|
self.ui.options_group.setDisabled(False)
|
|
# custom options
|
|
options = (name for widget in self.option_widgets if (name := widget.getValue()) is not None)
|
|
|
|
config.set_envvar(self.app_name, self.envvar, ",".join(options))
|
|
|
|
self.environ_changed.emit(self.envvar)
|
|
self.update_settings_override(current_state)
|
|
|
|
def setCurrentState(self, state: ActivationStates):
|
|
self.ui.show_overlay_combo.setCurrentIndex(self.ui.show_overlay_combo.findData(state, Qt.UserRole))
|
|
self.ui.options_group.setEnabled(state == ActivationStates.CUSTOM)
|
|
|
|
def showEvent(self, a0: QShowEvent):
|
|
if a0.spontaneous():
|
|
return super().showEvent(a0)
|
|
self.ui.options_group.blockSignals(True)
|
|
|
|
config_options = config.get_envvar(self.app_name, self.envvar, fallback=None)
|
|
if config_options is None:
|
|
logger.debug("Overlay setting %s is not present", self.envvar)
|
|
self.setCurrentState(ActivationStates.GLOBAL)
|
|
|
|
elif config_options == self.force_disabled:
|
|
self.setCurrentState(ActivationStates.DISABLED)
|
|
|
|
elif config_options == self.force_defaults:
|
|
self.setCurrentState(ActivationStates.DEFAULTS)
|
|
|
|
else:
|
|
self.setCurrentState(ActivationStates.CUSTOM)
|
|
opts = {}
|
|
for o in config_options.split(","):
|
|
if "=" in o:
|
|
k, v = o.split("=")
|
|
opts[k] = v
|
|
else:
|
|
# lk: The value doesn't matter other than not being None
|
|
opts[o] = "enable"
|
|
|
|
for widget in self.option_widgets:
|
|
widget.setValue(opts)
|
|
if opts:
|
|
logger.info("Remaining options without a gui switch: %s", ",".join(opts.keys()))
|
|
|
|
self.ui.options_group.blockSignals(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"))
|
|
grid = [
|
|
OverlayCheckBox("fps", self.tr("FPS")),
|
|
OverlayCheckBox("frametime", self.tr("Frametime")),
|
|
OverlayCheckBox("memory", self.tr("Memory usage")),
|
|
OverlayCheckBox("gpuload", self.tr("GPU usage")),
|
|
OverlayCheckBox("devinfo", self.tr("Device info")),
|
|
OverlayCheckBox("version", self.tr("DXVK version")),
|
|
OverlayCheckBox("api", self.tr("D3D feature level")),
|
|
OverlayCheckBox("compiler", self.tr("Compiler activity")),
|
|
]
|
|
form = [(OverlayNumberInput("scale", 1.0), self.tr("Scale"))]
|
|
self.setupWidget(grid, form, "DXVK_HUD", "0", "1")
|
|
|
|
def update_settings_override(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"))
|
|
grid = [
|
|
OverlayCheckBox("read_cfg", self.tr("Read config")),
|
|
OverlayCheckBox("fps", self.tr("FPS"), default_enabled=True),
|
|
OverlayCheckBox("frame_timing", self.tr("Frame time"), default_enabled=True),
|
|
OverlayCheckBox("cpu_stats", self.tr("CPU load"), default_enabled=True),
|
|
OverlayCheckBox("gpu_stats", self.tr("GPU load"), default_enabled=True),
|
|
OverlayCheckBox("cpu_temp", self.tr("CPU temperature")),
|
|
OverlayCheckBox("gpu_temp", self.tr("GPU temperature")),
|
|
OverlayCheckBox("ram", self.tr("Memory usage")),
|
|
OverlayCheckBox("vram", self.tr("VRAM usage")),
|
|
OverlayCheckBox("time", self.tr("Local time")),
|
|
OverlayCheckBox("version", self.tr("MangoHud version")),
|
|
OverlayCheckBox("arch", self.tr("System architecture")),
|
|
OverlayCheckBox("histogram", self.tr("FPS graph")),
|
|
OverlayCheckBox("gpu_name", self.tr("GPU name")),
|
|
OverlayCheckBox("cpu_power", self.tr("CPU power consumption")),
|
|
OverlayCheckBox("gpu_power", self.tr("GPU power consumption")),
|
|
]
|
|
form = [
|
|
(OverlayNumberInput("font_size", 24), self.tr("Font size")),
|
|
(OverlaySelectInput("position", mangohud_position), self.tr("Position")),
|
|
]
|
|
|
|
self.setupWidget(grid, form, "MANGOHUD_CONFIG", "no_display", "read_cfg")
|
|
|
|
def showEvent(self, a0: QShowEvent):
|
|
if a0.spontaneous():
|
|
return super().showEvent(a0)
|
|
self.ui.options_group.blockSignals(True)
|
|
self.ui.options_group.blockSignals(False)
|
|
return super().showEvent(a0)
|
|
|
|
def update_settings_override(self, state: IntEnum): # pylint: disable=E0202
|
|
if state == ActivationStates.GLOBAL:
|
|
config.remove_envvar(self.app_name, "MANGOHUD")
|
|
|
|
elif state == ActivationStates.DISABLED:
|
|
config.set_envvar(self.app_name, "MANGOHUD", "0")
|
|
|
|
elif state == ActivationStates.DEFAULTS:
|
|
config.set_envvar(self.app_name, "MANGOHUD", "1")
|
|
|
|
elif state == ActivationStates.CUSTOM:
|
|
config.set_envvar(self.app_name, "MANGOHUD", "1")
|
|
|
|
self.environ_changed.emit("MANGOHUD")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
import sys
|
|
from PyQt5.QtWidgets import QApplication, QDialog, QVBoxLayout
|
|
|
|
from legendary.core import LegendaryCore
|
|
|
|
core = LegendaryCore()
|
|
config.init_config_handler(core)
|
|
|
|
app = QApplication(sys.argv)
|
|
dlg = QDialog()
|
|
|
|
dxvk = DxvkSettings(dlg)
|
|
mangohud = MangoHudSettings(dlg)
|
|
|
|
layout = QVBoxLayout(dlg)
|
|
layout.addWidget(dxvk)
|
|
layout.addWidget(mangohud)
|
|
|
|
dlg.show()
|
|
ret = app.exec()
|
|
config.save_config()
|
|
sys.exit(ret)
|