mirror of
https://github.com/thejerf/baijiSteamVR.git
synced 2026-10-19 12:01:49 +02:00
550 lines
18 KiB
C++
550 lines
18 KiB
C++
// Copyright 2026 Dolphin Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#include "DolphinQt/Config/VRConfigWidget.h"
|
|
|
|
#include <algorithm>
|
|
#include <cctype>
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QDoubleSpinBox>
|
|
#include <QFormLayout>
|
|
#include <QGroupBox>
|
|
#include <QHBoxLayout>
|
|
#include <QLabel>
|
|
#include <QStyle>
|
|
#include <QTabWidget>
|
|
#include <QVBoxLayout>
|
|
|
|
#include "Common/CommonPaths.h"
|
|
#include "Common/FileUtil.h"
|
|
#include "Common/IniFile.h"
|
|
#include "Common/StringUtil.h"
|
|
|
|
#include "Core/Config/GraphicsSettings.h"
|
|
#include "Core/ConfigManager.h"
|
|
#include "DolphinQt/Config/GameConfigEdit.h"
|
|
#include "DolphinQt/QtUtils/QtUtils.h"
|
|
|
|
namespace
|
|
{
|
|
constexpr std::string_view VR_SECTION_NAME = "Graphics.VR";
|
|
constexpr std::string_view LEGACY_VR_SECTION_NAME = "GFX.VR";
|
|
constexpr double VR_GAME_UPM_MIN = 0.01;
|
|
constexpr double VR_GAME_UPM_MAX = 1000.0;
|
|
constexpr double VR_GAME_UPM_STEP = 0.01;
|
|
|
|
void ResetTabPages(QTabWidget* tab)
|
|
{
|
|
while (tab->count() > 0)
|
|
{
|
|
QWidget* const page = tab->widget(0);
|
|
tab->removeTab(0);
|
|
delete page;
|
|
}
|
|
}
|
|
} // namespace
|
|
|
|
VRConfigWidget::VRConfigWidget(std::string game_id, QWidget* parent)
|
|
: QWidget(parent), m_game_id(std::move(game_id))
|
|
{
|
|
CreateWidgets();
|
|
LoadFromFile();
|
|
}
|
|
|
|
void VRConfigWidget::CreateWidgets()
|
|
{
|
|
auto* general_layout = new QVBoxLayout;
|
|
|
|
auto* description = new QLabel(
|
|
tr("Configure per-game VR overrides saved to GameSettingsVR/<GameID>.ini."));
|
|
description->setWordWrap(true);
|
|
general_layout->addWidget(description);
|
|
|
|
auto* override_group = new QGroupBox(tr("Overrides"));
|
|
auto* form = new QFormLayout;
|
|
override_group->setLayout(form);
|
|
|
|
auto* units_row = new QWidget;
|
|
auto* units_layout = new QHBoxLayout;
|
|
units_layout->setContentsMargins(0, 0, 0, 0);
|
|
units_row->setLayout(units_layout);
|
|
|
|
m_override_units_per_meter = new QCheckBox(tr("Override"));
|
|
m_units_per_meter = new QDoubleSpinBox;
|
|
m_units_per_meter->setRange(VR_GAME_UPM_MIN, VR_GAME_UPM_MAX);
|
|
m_units_per_meter->setSingleStep(VR_GAME_UPM_STEP);
|
|
m_units_per_meter->setDecimals(2);
|
|
m_units_per_meter->setSuffix(tr(" units/m"));
|
|
units_layout->addWidget(m_override_units_per_meter);
|
|
units_layout->addWidget(m_units_per_meter, 1);
|
|
|
|
auto* lean_back_row = new QWidget;
|
|
auto* lean_back_layout = new QHBoxLayout;
|
|
lean_back_layout->setContentsMargins(0, 0, 0, 0);
|
|
lean_back_row->setLayout(lean_back_layout);
|
|
|
|
m_override_lean_back_angle = new QCheckBox(tr("Override"));
|
|
m_lean_back_angle = new QDoubleSpinBox;
|
|
m_lean_back_angle->setRange(Config::GFX_VR_LEAN_BACK_ANGLE_MIN, Config::GFX_VR_LEAN_BACK_ANGLE_MAX);
|
|
m_lean_back_angle->setSingleStep(Config::GFX_VR_LEAN_BACK_ANGLE_STEP);
|
|
m_lean_back_angle->setDecimals(1);
|
|
m_lean_back_angle->setSuffix(tr(" deg"));
|
|
lean_back_layout->addWidget(m_override_lean_back_angle);
|
|
lean_back_layout->addWidget(m_lean_back_angle, 1);
|
|
|
|
auto* camera_forward_row = new QWidget;
|
|
auto* camera_forward_layout = new QHBoxLayout;
|
|
camera_forward_layout->setContentsMargins(0, 0, 0, 0);
|
|
camera_forward_row->setLayout(camera_forward_layout);
|
|
|
|
m_override_camera_forward = new QCheckBox(tr("Override"));
|
|
m_camera_forward = new QDoubleSpinBox;
|
|
m_camera_forward->setRange(Config::GFX_VR_CAMERA_FORWARD_MIN, Config::GFX_VR_CAMERA_FORWARD_MAX);
|
|
m_camera_forward->setSingleStep(Config::GFX_VR_CAMERA_FORWARD_STEP);
|
|
m_camera_forward->setDecimals(1);
|
|
m_camera_forward->setSuffix(tr(" m"));
|
|
camera_forward_layout->addWidget(m_override_camera_forward);
|
|
camera_forward_layout->addWidget(m_camera_forward, 1);
|
|
|
|
auto* head_locked_curvature_row = new QWidget;
|
|
auto* head_locked_curvature_layout = new QHBoxLayout;
|
|
head_locked_curvature_layout->setContentsMargins(0, 0, 0, 0);
|
|
head_locked_curvature_row->setLayout(head_locked_curvature_layout);
|
|
|
|
m_override_head_locked_curvature = new QCheckBox(tr("Override"));
|
|
m_head_locked_curvature = new QDoubleSpinBox;
|
|
m_head_locked_curvature->setRange(Config::GFX_VR_HEAD_LOCKED_CURVATURE_MIN,
|
|
Config::GFX_VR_HEAD_LOCKED_CURVATURE_MAX);
|
|
m_head_locked_curvature->setSingleStep(Config::GFX_VR_HEAD_LOCKED_CURVATURE_STEP);
|
|
m_head_locked_curvature->setDecimals(2);
|
|
head_locked_curvature_layout->addWidget(m_override_head_locked_curvature);
|
|
head_locked_curvature_layout->addWidget(m_head_locked_curvature, 1);
|
|
|
|
auto* element_depth_row = new QWidget;
|
|
auto* element_depth_layout = new QHBoxLayout;
|
|
element_depth_layout->setContentsMargins(0, 0, 0, 0);
|
|
element_depth_row->setLayout(element_depth_layout);
|
|
|
|
m_override_element_depth = new QCheckBox(tr("Override"));
|
|
m_element_depth = new QDoubleSpinBox;
|
|
m_element_depth->setRange(Config::GFX_VR_ELEMENT_DEPTH_MIN, Config::GFX_VR_ELEMENT_DEPTH_MAX);
|
|
m_element_depth->setSingleStep(Config::GFX_VR_ELEMENT_DEPTH_STEP);
|
|
m_element_depth->setDecimals(4);
|
|
element_depth_layout->addWidget(m_override_element_depth);
|
|
element_depth_layout->addWidget(m_element_depth, 1);
|
|
|
|
m_virtual_screen_mode = new QComboBox;
|
|
m_dont_clear_screen_mode = new QComboBox;
|
|
m_force_vbi_90hz_mode = new QComboBox;
|
|
PopulateBoolModeCombo(m_virtual_screen_mode);
|
|
PopulateBoolModeCombo(m_dont_clear_screen_mode);
|
|
PopulateBoolModeCombo(m_force_vbi_90hz_mode);
|
|
|
|
form->addRow(tr("Units per Meter"), units_row);
|
|
form->addRow(tr("Lean Back Angle"), lean_back_row);
|
|
form->addRow(tr("Camera Forward"), camera_forward_row);
|
|
form->addRow(tr("Head Locked Curvature"), head_locked_curvature_row);
|
|
form->addRow(tr("Element Depth"), element_depth_row);
|
|
form->addRow(tr("Virtual Screen"), m_virtual_screen_mode);
|
|
form->addRow(tr("Don't Clear Screen"), m_dont_clear_screen_mode);
|
|
form->addRow(tr("Force VBI Frequency to 90 Hz in VR"), m_force_vbi_90hz_mode);
|
|
|
|
general_layout->addWidget(override_group);
|
|
general_layout->addStretch();
|
|
|
|
auto* const general_widget = new QWidget;
|
|
general_widget->setLayout(general_layout);
|
|
|
|
auto* editor_layout = new QVBoxLayout;
|
|
|
|
auto* local_group = new QGroupBox(tr("VR User Config"));
|
|
auto* local_layout = new QVBoxLayout;
|
|
m_local_tab = new QTabWidget;
|
|
local_layout->addWidget(m_local_tab);
|
|
local_group->setLayout(local_layout);
|
|
|
|
editor_layout->addWidget(local_group);
|
|
|
|
auto* const editor_widget = new QWidget;
|
|
editor_widget->setLayout(editor_layout);
|
|
|
|
auto* const tabs = new QTabWidget;
|
|
tabs->addTab(general_widget, tr("General"));
|
|
const int editor_index = tabs->addTab(editor_widget, tr("Editor"));
|
|
|
|
auto* const root_layout = new QVBoxLayout;
|
|
auto* const help_label = new QLabel(tr("These VR settings override core Dolphin settings."));
|
|
auto* const help_widget =
|
|
QtUtils::CreateIconWarning(this, QStyle::SP_MessageBoxQuestion, help_label);
|
|
root_layout->addWidget(help_widget);
|
|
root_layout->addWidget(tabs);
|
|
setLayout(root_layout);
|
|
|
|
connect(m_override_units_per_meter, &QCheckBox::toggled, this, [this](bool checked) {
|
|
m_units_per_meter->setEnabled(checked);
|
|
SaveToFile();
|
|
});
|
|
connect(m_units_per_meter, &QDoubleSpinBox::valueChanged, this,
|
|
[this](double) { SaveToFile(); });
|
|
connect(m_override_lean_back_angle, &QCheckBox::toggled, this, [this](bool checked) {
|
|
m_lean_back_angle->setEnabled(checked);
|
|
SaveToFile();
|
|
});
|
|
connect(m_lean_back_angle, &QDoubleSpinBox::valueChanged, this,
|
|
[this](double) { SaveToFile(); });
|
|
connect(m_override_camera_forward, &QCheckBox::toggled, this, [this](bool checked) {
|
|
m_camera_forward->setEnabled(checked);
|
|
SaveToFile();
|
|
});
|
|
connect(m_camera_forward, &QDoubleSpinBox::valueChanged, this,
|
|
[this](double) { SaveToFile(); });
|
|
connect(m_override_head_locked_curvature, &QCheckBox::toggled, this, [this](bool checked) {
|
|
m_head_locked_curvature->setEnabled(checked);
|
|
SaveToFile();
|
|
});
|
|
connect(m_head_locked_curvature, &QDoubleSpinBox::valueChanged, this,
|
|
[this](double) { SaveToFile(); });
|
|
connect(m_override_element_depth, &QCheckBox::toggled, this, [this](bool checked) {
|
|
m_element_depth->setEnabled(checked);
|
|
SaveToFile();
|
|
});
|
|
connect(m_element_depth, &QDoubleSpinBox::valueChanged, this,
|
|
[this](double) { SaveToFile(); });
|
|
connect(m_virtual_screen_mode, &QComboBox::currentIndexChanged, this,
|
|
[this](int) { SaveToFile(); });
|
|
connect(m_dont_clear_screen_mode, &QComboBox::currentIndexChanged, this,
|
|
[this](int) { SaveToFile(); });
|
|
connect(m_force_vbi_90hz_mode, &QComboBox::currentIndexChanged, this,
|
|
[this](int) { SaveToFile(); });
|
|
|
|
connect(tabs, &QTabWidget::currentChanged, this, [this, editor_index](int index) {
|
|
// Sync editor content with current file after changes from General.
|
|
if (index == editor_index)
|
|
RefreshEditorTabs();
|
|
|
|
// Reload controls after raw INI edits.
|
|
if (m_prev_tab_index == editor_index)
|
|
{
|
|
LoadFromFile();
|
|
if (SConfig::GetInstance().GetGameID() == m_game_id)
|
|
SConfig::GetInstance().ReloadGameVRConfigOverrides();
|
|
}
|
|
|
|
m_prev_tab_index = index;
|
|
});
|
|
|
|
RefreshEditorTabs();
|
|
}
|
|
|
|
void VRConfigWidget::LoadFromFile()
|
|
{
|
|
const ValueMap values = ReadVRSectionValues(GetINIPath());
|
|
|
|
m_updating = true;
|
|
|
|
const auto units_it = values.find("UnitsPerMeter");
|
|
const bool units_overridden = units_it != values.end();
|
|
m_override_units_per_meter->setChecked(units_overridden);
|
|
m_units_per_meter->setEnabled(units_overridden);
|
|
|
|
double units_per_meter = Config::GetBase(Config::GFX_VR_UNITS_PER_METER);
|
|
if (units_overridden)
|
|
{
|
|
double parsed = units_per_meter;
|
|
if (TryParse(units_it->second, &parsed))
|
|
units_per_meter = parsed;
|
|
}
|
|
units_per_meter =
|
|
std::clamp(units_per_meter, VR_GAME_UPM_MIN, VR_GAME_UPM_MAX);
|
|
m_units_per_meter->setValue(units_per_meter);
|
|
|
|
const auto lean_back_it = values.find("LeanBackAngle");
|
|
const bool lean_back_overridden = lean_back_it != values.end();
|
|
m_override_lean_back_angle->setChecked(lean_back_overridden);
|
|
m_lean_back_angle->setEnabled(lean_back_overridden);
|
|
|
|
double lean_back_angle = Config::GetBase(Config::GFX_VR_LEAN_BACK_ANGLE);
|
|
if (lean_back_overridden)
|
|
{
|
|
double parsed = lean_back_angle;
|
|
if (TryParse(lean_back_it->second, &parsed))
|
|
lean_back_angle = parsed;
|
|
}
|
|
lean_back_angle =
|
|
std::clamp(lean_back_angle, static_cast<double>(Config::GFX_VR_LEAN_BACK_ANGLE_MIN),
|
|
static_cast<double>(Config::GFX_VR_LEAN_BACK_ANGLE_MAX));
|
|
m_lean_back_angle->setValue(lean_back_angle);
|
|
|
|
const auto camera_forward_it = values.find("CameraForward");
|
|
const bool camera_forward_overridden = camera_forward_it != values.end();
|
|
m_override_camera_forward->setChecked(camera_forward_overridden);
|
|
m_camera_forward->setEnabled(camera_forward_overridden);
|
|
|
|
double camera_forward = Config::GetBase(Config::GFX_VR_CAMERA_FORWARD);
|
|
if (camera_forward_overridden)
|
|
{
|
|
double parsed = camera_forward;
|
|
if (TryParse(camera_forward_it->second, &parsed))
|
|
camera_forward = parsed;
|
|
}
|
|
camera_forward =
|
|
std::clamp(camera_forward, static_cast<double>(Config::GFX_VR_CAMERA_FORWARD_MIN),
|
|
static_cast<double>(Config::GFX_VR_CAMERA_FORWARD_MAX));
|
|
m_camera_forward->setValue(camera_forward);
|
|
|
|
const auto head_locked_curvature_it = values.find("HeadLockedCurvature");
|
|
const bool head_locked_curvature_overridden = head_locked_curvature_it != values.end();
|
|
m_override_head_locked_curvature->setChecked(head_locked_curvature_overridden);
|
|
m_head_locked_curvature->setEnabled(head_locked_curvature_overridden);
|
|
|
|
double head_locked_curvature = Config::GetBase(Config::GFX_VR_HEAD_LOCKED_CURVATURE);
|
|
if (head_locked_curvature_overridden)
|
|
{
|
|
double parsed = head_locked_curvature;
|
|
if (TryParse(head_locked_curvature_it->second, &parsed))
|
|
head_locked_curvature = parsed;
|
|
}
|
|
head_locked_curvature =
|
|
std::clamp(head_locked_curvature, static_cast<double>(Config::GFX_VR_HEAD_LOCKED_CURVATURE_MIN),
|
|
static_cast<double>(Config::GFX_VR_HEAD_LOCKED_CURVATURE_MAX));
|
|
m_head_locked_curvature->setValue(head_locked_curvature);
|
|
|
|
const auto element_depth_it = values.find("ElementDepth");
|
|
const bool element_depth_overridden = element_depth_it != values.end();
|
|
m_override_element_depth->setChecked(element_depth_overridden);
|
|
m_element_depth->setEnabled(element_depth_overridden);
|
|
|
|
double element_depth = Config::GetBase(Config::GFX_VR_ELEMENT_DEPTH);
|
|
if (element_depth_overridden)
|
|
{
|
|
double parsed = element_depth;
|
|
if (TryParse(element_depth_it->second, &parsed))
|
|
element_depth = parsed;
|
|
}
|
|
element_depth =
|
|
std::clamp(element_depth, static_cast<double>(Config::GFX_VR_ELEMENT_DEPTH_MIN),
|
|
static_cast<double>(Config::GFX_VR_ELEMENT_DEPTH_MAX));
|
|
m_element_depth->setValue(element_depth);
|
|
|
|
SetBoolMode(m_virtual_screen_mode, ParseBoolMode(values, "VirtualScreen"));
|
|
SetBoolMode(m_dont_clear_screen_mode, ParseBoolMode(values, "DontClearScreen"));
|
|
SetBoolMode(m_force_vbi_90hz_mode, ParseBoolMode(values, "AutoVBIFromHMD"));
|
|
|
|
m_updating = false;
|
|
}
|
|
|
|
void VRConfigWidget::SaveToFile()
|
|
{
|
|
if (m_updating || m_game_id.empty())
|
|
return;
|
|
|
|
std::vector<std::pair<std::string, std::string>> entries;
|
|
if (m_override_units_per_meter->isChecked())
|
|
{
|
|
entries.emplace_back("UnitsPerMeter",
|
|
QString::number(m_units_per_meter->value(), 'f', 2).toStdString());
|
|
}
|
|
if (m_override_lean_back_angle->isChecked())
|
|
{
|
|
entries.emplace_back("LeanBackAngle",
|
|
QString::number(m_lean_back_angle->value(), 'f', 1).toStdString());
|
|
}
|
|
if (m_override_camera_forward->isChecked())
|
|
{
|
|
entries.emplace_back("CameraForward",
|
|
QString::number(m_camera_forward->value(), 'f', 1).toStdString());
|
|
}
|
|
if (m_override_head_locked_curvature->isChecked())
|
|
{
|
|
entries.emplace_back("HeadLockedCurvature",
|
|
QString::number(m_head_locked_curvature->value(), 'f', 2).toStdString());
|
|
}
|
|
if (m_override_element_depth->isChecked())
|
|
{
|
|
entries.emplace_back("ElementDepth",
|
|
QString::number(m_element_depth->value(), 'f', 4).toStdString());
|
|
}
|
|
|
|
const auto append_bool = [&entries](const char* key, BoolMode mode) {
|
|
if (mode == BoolMode::Inherit)
|
|
return;
|
|
entries.emplace_back(key, mode == BoolMode::Enabled ? "True" : "False");
|
|
};
|
|
append_bool("VirtualScreen", GetBoolMode(m_virtual_screen_mode));
|
|
append_bool("DontClearScreen", GetBoolMode(m_dont_clear_screen_mode));
|
|
append_bool("AutoVBIFromHMD", GetBoolMode(m_force_vbi_90hz_mode));
|
|
|
|
const std::string path = GetINIPath();
|
|
std::string base = ReadFileWithoutVRSection(path);
|
|
while (!base.empty() &&
|
|
(base.back() == '\n' || base.back() == '\r' ||
|
|
std::isspace(static_cast<unsigned char>(base.back()))))
|
|
base.pop_back();
|
|
|
|
std::ostringstream out;
|
|
if (!base.empty())
|
|
out << base << "\n";
|
|
|
|
if (!entries.empty())
|
|
{
|
|
out << '[' << VR_SECTION_NAME << "]\n";
|
|
for (const auto& [key, value] : entries)
|
|
out << key << " = " << value << "\n";
|
|
}
|
|
|
|
const std::string output = out.str();
|
|
if (output.empty())
|
|
{
|
|
File::Delete(path, File::IfAbsentBehavior::NoConsoleWarning);
|
|
}
|
|
else
|
|
{
|
|
File::CreateFullPath(path);
|
|
std::ofstream file(path, std::ios::trunc);
|
|
file << output;
|
|
}
|
|
|
|
if (SConfig::GetInstance().GetGameID() == m_game_id)
|
|
SConfig::GetInstance().ReloadGameVRConfigOverrides();
|
|
}
|
|
|
|
void VRConfigWidget::RefreshEditorTabs()
|
|
{
|
|
if (!m_local_tab || m_game_id.empty())
|
|
return;
|
|
|
|
ResetTabPages(m_local_tab);
|
|
|
|
const std::string local_path = GetINIPath();
|
|
m_local_tab->addTab(new GameConfigEdit(nullptr, QString::fromStdString(local_path), false),
|
|
QString::fromStdString(m_game_id + ".ini"));
|
|
}
|
|
|
|
std::string VRConfigWidget::GetINIPath() const
|
|
{
|
|
return File::GetUserPath(D_GAMESETTINGSVR_IDX) + m_game_id + ".ini";
|
|
}
|
|
|
|
bool VRConfigWidget::IsVRSectionHeader(std::string_view line)
|
|
{
|
|
const std::string_view trimmed = StripWhitespace(line);
|
|
if (trimmed.size() < 3 || trimmed.front() != '[' || trimmed.back() != ']')
|
|
return false;
|
|
|
|
const std::string_view section_name = trimmed.substr(1, trimmed.size() - 2);
|
|
return Common::CaseInsensitiveEquals(section_name, VR_SECTION_NAME) ||
|
|
Common::CaseInsensitiveEquals(section_name, LEGACY_VR_SECTION_NAME);
|
|
}
|
|
|
|
std::string VRConfigWidget::ReadFileWithoutVRSection(const std::string& path)
|
|
{
|
|
std::ifstream file(path);
|
|
if (!file.is_open())
|
|
return {};
|
|
|
|
std::ostringstream out;
|
|
bool skipping = false;
|
|
std::string line;
|
|
while (std::getline(file, line))
|
|
{
|
|
if (!line.empty() && line.back() == '\r')
|
|
line.pop_back();
|
|
|
|
const std::string_view trimmed = StripWhitespace(line);
|
|
if (IsVRSectionHeader(trimmed))
|
|
{
|
|
skipping = true;
|
|
continue;
|
|
}
|
|
|
|
if (skipping && !trimmed.empty() && trimmed.front() == '[')
|
|
skipping = false;
|
|
|
|
if (!skipping)
|
|
out << line << "\n";
|
|
}
|
|
|
|
return out.str();
|
|
}
|
|
|
|
VRConfigWidget::ValueMap VRConfigWidget::ReadVRSectionValues(const std::string& path)
|
|
{
|
|
ValueMap values;
|
|
|
|
std::ifstream file(path);
|
|
if (!file.is_open())
|
|
return values;
|
|
|
|
bool in_section = false;
|
|
std::string line;
|
|
while (std::getline(file, line))
|
|
{
|
|
if (!line.empty() && line.back() == '\r')
|
|
line.pop_back();
|
|
|
|
const std::string_view trimmed = StripWhitespace(line);
|
|
if (trimmed.empty())
|
|
continue;
|
|
|
|
if (IsVRSectionHeader(trimmed))
|
|
{
|
|
in_section = true;
|
|
continue;
|
|
}
|
|
|
|
if (in_section && trimmed.front() == '[')
|
|
break;
|
|
|
|
if (!in_section)
|
|
continue;
|
|
|
|
std::string key;
|
|
std::string value;
|
|
Common::IniFile::ParseLine(trimmed, &key, &value);
|
|
if (!key.empty())
|
|
values.insert_or_assign(std::move(key), std::move(value));
|
|
}
|
|
|
|
return values;
|
|
}
|
|
|
|
VRConfigWidget::BoolMode VRConfigWidget::ParseBoolMode(const ValueMap& values, const char* key)
|
|
{
|
|
const auto it = values.find(key);
|
|
if (it == values.end())
|
|
return BoolMode::Inherit;
|
|
|
|
bool parsed = false;
|
|
if (TryParse(it->second, &parsed))
|
|
return parsed ? BoolMode::Enabled : BoolMode::Disabled;
|
|
return BoolMode::Inherit;
|
|
}
|
|
|
|
void VRConfigWidget::SetBoolMode(QComboBox* combo, BoolMode mode)
|
|
{
|
|
combo->setCurrentIndex(static_cast<int>(mode));
|
|
}
|
|
|
|
VRConfigWidget::BoolMode VRConfigWidget::GetBoolMode(const QComboBox* combo)
|
|
{
|
|
const int index = combo->currentIndex();
|
|
if (index == static_cast<int>(BoolMode::Enabled))
|
|
return BoolMode::Enabled;
|
|
if (index == static_cast<int>(BoolMode::Disabled))
|
|
return BoolMode::Disabled;
|
|
return BoolMode::Inherit;
|
|
}
|
|
|
|
void VRConfigWidget::PopulateBoolModeCombo(QComboBox* combo)
|
|
{
|
|
combo->addItem(QObject::tr("Inherit"));
|
|
combo->addItem(QObject::tr("Enabled"));
|
|
combo->addItem(QObject::tr("Disabled"));
|
|
}
|