1
0
Fork 0
mirror of synced 2024-06-02 02:34:40 +12:00
Rare/rare/components/tabs/settings/widgets/overlay.py
2024-02-12 21:52:08 +02:00

344 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)
print(f"{self.envvar} = {config.get_envvar(self.app_name, self.envvar)}")
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:
print(opts)
widget.setValue(opts)
if opts:
logger.info("Remaining options without a gui switch: %s", ",".join(opts.keys()))
print(opts)
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")
print(f"MANGOHUD = {config.get_envvar(self.app_name, '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)