@@ -0,0 +1,63 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "DolphinQt/Config/GameConfigHighlighter.h"

struct HighlightingRule
{
QRegularExpression pattern;
QTextCharFormat format;
};

GameConfigHighlighter::~GameConfigHighlighter() = default;

GameConfigHighlighter::GameConfigHighlighter(QTextDocument* parent) : QSyntaxHighlighter(parent)
{
QTextCharFormat equal_format;
equal_format.setForeground(Qt::red);

QTextCharFormat section_format;
section_format.setFontWeight(QFont::Bold);

QTextCharFormat comment_format;
comment_format.setForeground(Qt::darkGreen);
comment_format.setFontItalic(true);

QTextCharFormat const_format;
const_format.setFontWeight(QFont::Bold);
const_format.setForeground(Qt::blue);

QTextCharFormat num_format;
num_format.setForeground(Qt::darkBlue);

m_rules.emplace_back(HighlightingRule{QRegularExpression(QStringLiteral("=")), equal_format});
m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("^\\[.*?\\]")), section_format});
m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("\\bTrue\\b")), const_format});
m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("\\bFalse\\b")), const_format});
m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("\\b[0-9a-fA-F]+\\b")), num_format});

m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("^#.*")), comment_format});
m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("^\\$.*")), comment_format});
m_rules.emplace_back(
HighlightingRule{QRegularExpression(QStringLiteral("^\\*.*")), comment_format});
}

void GameConfigHighlighter::highlightBlock(const QString& text)
{
for (const auto& rule : m_rules)
{
auto it = rule.pattern.globalMatch(text);
while (it.hasNext())
{
auto match = it.next();
setFormat(match.capturedStart(), match.capturedLength(), rule.format);
}
}
}
@@ -0,0 +1,28 @@
// Copyright 2018 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#pragma once

#include <vector>

#include <QRegularExpression>
#include <QSyntaxHighlighter>
#include <QTextCharFormat>

struct HighlightingRule;

class GameConfigHighlighter : public QSyntaxHighlighter
{
Q_OBJECT

public:
explicit GameConfigHighlighter(QTextDocument* parent = nullptr);
~GameConfigHighlighter();

protected:
void highlightBlock(const QString& text) override;

private:
std::vector<HighlightingRule> m_rules;
};
@@ -6,16 +6,12 @@

#include <QCheckBox>
#include <QComboBox>
#include <QDesktopServices>
#include <QFile>
#include <QGridLayout>
#include <QGroupBox>
#include <QHBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSlider>
#include <QSpinBox>
#include <QUrl>
#include <QTabWidget>
#include <QVBoxLayout>

#include "Common/CommonPaths.h"
@@ -24,6 +20,7 @@
#include "Core/ConfigLoaders/GameConfigLoader.h"
#include "Core/ConfigManager.h"

#include "DolphinQt/Config/GameConfigEdit.h"
#include "DolphinQt/Config/Graphics/GraphicsSlider.h"

#include "UICommon/GameFile.h"
@@ -38,22 +35,51 @@ constexpr const char* DETERMINISM_AUTO_STRING = "auto";
constexpr const char* DETERMINISM_NONE_STRING = "none";
constexpr const char* DETERMINISM_FAKE_COMPLETION_STRING = "fake-completion";

static void PopulateTab(QTabWidget* tab, const std::string& path, std::string game_id,
bool read_only)
{
while (!game_id.empty())
{
const std::string ini_path = path + game_id + ".ini";
if (File::Exists(ini_path))
{
auto* edit =
new GameConfigEdit(nullptr, QString::fromStdString(path + game_id + ".ini"), read_only);
tab->addTab(edit, QString::fromStdString(game_id));
}

game_id = game_id.substr(0, game_id.size() - 1);
}
}

GameConfigWidget::GameConfigWidget(const UICommon::GameFile& game) : m_game(game)
{
m_game_id = m_game.GetGameID();

m_gameini_local_path =
QString::fromStdString(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini");

CreateWidgets();
LoadSettings();
ConnectWidgets();

PopulateTab(m_default_tab, File::GetSysDirectory() + "GameSettings/", m_game_id, true);
PopulateTab(m_local_tab, File::GetUserPath(D_GAMESETTINGS_IDX), m_game_id, false);

// Always give the user the opportunity to create a new INI
if (m_local_tab->count() == 0)
{
auto* edit = new GameConfigEdit(
nullptr, QString::fromStdString(File::GetUserPath(D_GAMESETTINGS_IDX) + m_game_id + ".ini"),
false);
m_local_tab->addTab(edit, QString::fromStdString(m_game_id));
}
}

void GameConfigWidget::CreateWidgets()
{
// General
m_refresh_config = new QPushButton(tr("Refresh"));
m_edit_user_config = new QPushButton(tr("Edit User Config"));
m_view_default_config = new QPushButton(tr("View Default Config"));

// Core
auto* core_box = new QGroupBox(tr("Core"));
@@ -128,32 +154,58 @@ void GameConfigWidget::CreateWidgets()
settings_layout->addWidget(core_box);
settings_layout->addWidget(stereoscopy_box);

auto* layout = new QGridLayout;

layout->addWidget(settings_box, 0, 0, 1, -1);

auto* button_layout = new QHBoxLayout;
button_layout->setMargin(0);
auto* general_layout = new QGridLayout;

layout->addLayout(button_layout, 1, 0, 1, -1);
general_layout->addWidget(settings_box, 0, 0, 1, -1);

button_layout->addWidget(m_refresh_config);
button_layout->addWidget(m_edit_user_config);
button_layout->addWidget(m_view_default_config);
general_layout->addWidget(m_refresh_config, 1, 0, 1, -1);

for (QCheckBox* item : {m_enable_dual_core, m_enable_mmu, m_enable_fprf, m_sync_gpu,
m_enable_fast_disc, m_use_dsp_hle, m_use_monoscopic_shadows})
item->setTristate(true);

auto* general_widget = new QWidget;
general_widget->setLayout(general_layout);

// Advanced
auto* advanced_layout = new QVBoxLayout;

auto* default_group = new QGroupBox(tr("Default Config (Read Only)"));
auto* default_layout = new QVBoxLayout;
m_default_tab = new QTabWidget;

default_group->setLayout(default_layout);
default_layout->addWidget(m_default_tab);

auto* local_group = new QGroupBox(tr("User Config"));
auto* local_layout = new QVBoxLayout;
m_local_tab = new QTabWidget;

local_group->setLayout(local_layout);
local_layout->addWidget(m_local_tab);

advanced_layout->addWidget(default_group);
advanced_layout->addWidget(local_group);

auto* advanced_widget = new QWidget;

advanced_widget->setLayout(advanced_layout);

auto* layout = new QVBoxLayout;
auto* tab_widget = new QTabWidget;

tab_widget->addTab(general_widget, tr("General"));
tab_widget->addTab(advanced_widget, tr("Editor"));

layout->addWidget(tab_widget);

setLayout(layout);
}

void GameConfigWidget::ConnectWidgets()
{
// Buttons
connect(m_refresh_config, &QPushButton::pressed, this, &GameConfigWidget::LoadSettings);
connect(m_edit_user_config, &QPushButton::pressed, this, &GameConfigWidget::EditUserConfig);
connect(m_view_default_config, &QPushButton::pressed, this, &GameConfigWidget::ViewDefaultConfig);

for (QCheckBox* box : {m_enable_dual_core, m_enable_mmu, m_enable_fprf, m_sync_gpu,
m_enable_fast_disc, m_use_dsp_hle, m_use_monoscopic_shadows})
@@ -347,29 +399,3 @@ void GameConfigWidget::SaveSettings()
if (success && File::GetSize(m_gameini_local_path.toStdString()) == 0)
File::Delete(m_gameini_local_path.toStdString());
}

void GameConfigWidget::EditUserConfig()
{
QFile file(m_gameini_local_path);

if (!file.exists())
{
file.open(QIODevice::WriteOnly);
file.close();
}

QDesktopServices::openUrl(QUrl::fromLocalFile(m_gameini_local_path));
}

void GameConfigWidget::ViewDefaultConfig()
{
for (const std::string& filename :
ConfigLoaders::GetGameIniFilenames(m_game_id, m_game.GetRevision()))
{
QString path =
QString::fromStdString(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename);

if (QFile(path).exists())
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
}
}
@@ -18,12 +18,10 @@ class GameFile;

class QCheckBox;
class QComboBox;
class QGroupBox;
class QLineEdit;
class QPushButton;
class QSlider;
class QSpinBox;
class QVBoxLayout;
class QTabWidget;

class GameConfigWidget : public QWidget
{
@@ -34,38 +32,40 @@ class GameConfigWidget : public QWidget
private:
void CreateWidgets();
void ConnectWidgets();

void LoadSettings();
void SaveSettings();

void EditUserConfig();
void ViewDefaultConfig();

void LoadCheckBox(QCheckBox* checkbox, const std::string& section, const std::string& key);
void SaveCheckBox(QCheckBox* checkbox, const std::string& section, const std::string& key);
void LoadCheckBox(QCheckBox* checkbox, const std::string& section, const std::string& key);

QPushButton* m_refresh_config;
QPushButton* m_edit_user_config;
QPushButton* m_view_default_config;
QString m_gameini_sys_path;
QString m_gameini_local_path;

QTabWidget* m_default_tab;
QTabWidget* m_local_tab;

// Core
QCheckBox* m_enable_dual_core;
QCheckBox* m_enable_mmu;
QCheckBox* m_enable_fprf;
QCheckBox* m_sync_gpu;
QCheckBox* m_enable_fast_disc;
QCheckBox* m_use_dsp_hle;
QCheckBox* m_use_monoscopic_shadows;

QPushButton* m_refresh_config;

QComboBox* m_deterministic_dual_core;

// Stereoscopy
QSlider* m_depth_slider;

QSpinBox* m_convergence_spin;
QCheckBox* m_use_monoscopic_shadows;

QString m_gameini_local_path;
const UICommon::GameFile& m_game;
std::string m_game_id;

IniFile m_gameini_local;
IniFile m_gameini_default;

const UICommon::GameFile& m_game;
std::string m_game_id;
};
@@ -63,6 +63,8 @@
<QtMoc Include="Config\CheatWarningWidget.h" />
<QtMoc Include="Config\ControllersWindow.h" />
<QtMoc Include="Config\FilesystemWidget.h" />
<QtMoc Include="Config\GameConfigEdit.h" />
<QtMoc Include="Config\GameConfigHighlighter.h" />
<QtMoc Include="Config\GameConfigWidget.h" />
<QtMoc Include="Config\GeckoCodeWidget.h" />
<QtMoc Include="Config\Mapping\GCKeyboardEmu.h" />
@@ -194,6 +196,8 @@
<ClCompile Include="$(QtMocOutPrefix)GCPadEmu.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GCPadWiiUConfigDialog.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GCTASInputWindow.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GameConfigEdit.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GameConfigHighlighter.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GameConfigWidget.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GameCubePane.cpp" />
<ClCompile Include="$(QtMocOutPrefix)GameList.cpp" />
@@ -275,6 +279,8 @@
<ClCompile Include="Config\CheatWarningWidget.cpp" />
<ClCompile Include="Config\ControllersWindow.cpp" />
<ClCompile Include="Config\FilesystemWidget.cpp" />
<ClCompile Include="Config\GameConfigEdit.cpp" />
<ClCompile Include="Config\GameConfigHighlighter.cpp" />
<ClCompile Include="Config\GameConfigWidget.cpp" />
<ClCompile Include="Config\GeckoCodeWidget.cpp" />
<ClCompile Include="Config\Graphics\AdvancedWidget.cpp" />