Qt6 frontend

Reviewed-on: #1
Co-authored-by: iris <iris.kaizen@pm.me>
Co-committed-by: iris <iris.kaizen@pm.me>
This commit was merged in pull request #1.
This commit is contained in:
2026-06-09 17:14:08 +02:00
committed by iris
parent 3080d4d45a
commit 430139dc9f
315 changed files with 860 additions and 140860 deletions
+18 -34
View File
@@ -1,38 +1,22 @@
#include <AudioSettings.hpp>
#include <imgui.h>
#include <Options.hpp>
AudioSettings::AudioSettings() {
lockChannels = Options::GetInstance().GetValue<bool>("audio", "lock");
volumeL = Options::GetInstance().GetValue<float>("audio", "volumeL") * 100;
volumeR = Options::GetInstance().GetValue<float>("audio", "volumeR") * 100;
AudioSettings::AudioSettings() : settings(QSettings::UserScope) {
volumePercent = new QLabel();
volumePercent->setText(std::format("Volume: {:.2f}%", Options::GetVolume() * 100.f).c_str());
volume = new QSlider(Qt::Horizontal);
volume->setRange(0, 100);
volume->setValue(Options::GetVolume() * 100.f);
connect(volume, &QSlider::valueChanged, this, [&] {
float newValue = float(volume->value()) / 100.f;
volumePercent->setText(std::format("Volume: {:.2f}%", Options::GetVolume() * 100.f).c_str());
Options::SetVolume(newValue);
settings.setValue("audio/volume", newValue);
settings.sync();
});
v = new QVBoxLayout();
v->addWidget(volume);
v->addWidget(volumePercent);
setLayout(v);
}
void AudioSettings::render() {
if(ImGui::Checkbox("Lock channels:", &lockChannels)) {
Options::GetInstance().SetValue("audio", "lock", lockChannels);
if(lockChannels) {
volumeR = volumeL;
Options::GetInstance().SetValue("audio", "volumeR", volumeR / 100.f);
}
modified = true;
}
if(ImGui::SliderFloat("Volume L", &volumeL, 0.f, 100.f, "%.2f")) {
Options::GetInstance().SetValue("audio", "volumeL", volumeL / 100.f);
if (lockChannels) {
volumeR = volumeL;
Options::GetInstance().SetValue("audio", "volumeR", volumeR / 100.f);
}
modified = true;
}
ImGui::BeginDisabled(lockChannels);
if(ImGui::SliderFloat("Volume R", &volumeR, 0.f, 100.f, "%.2f")) {
Options::GetInstance().SetValue("audio", "volumeR", volumeR / 100.f);
modified = true;
}
ImGui::EndDisabled();
}
+13 -7
View File
@@ -1,11 +1,17 @@
#pragma once
#include <SettingsTab.hpp>
#include <QWidget>
#include <QVBoxLayout>
#include <QSlider>
#include <QSettings>
#include <QLabel>
struct AudioSettings final : SettingsTab {
bool lockChannels = false;
float volumeL{};
float volumeR{};
class AudioSettings final : public QWidget {
Q_OBJECT
QVBoxLayout *v;
QSlider *volume;
QLabel *volumePercent;
QSettings settings;
explicit AudioSettings();
void render() override;
public:
explicit AudioSettings();
};
+44 -45
View File
@@ -1,56 +1,55 @@
#include <CPUSettings.hpp>
#include <Options.hpp>
#include <log.hpp>
#include <imgui.h>
#include <Core.hpp>
CPUSettings::CPUSettings() {
auto selectedCpuType = Options::GetInstance().GetValue<std::string>("cpu", "type");
if (selectedCpuType == "cached_interpreter") {
selectedCpuTypeIndex = 1;
CPUSettings::CPUSettings() : settings(QSettings::UserScope) {
types = new QComboBox();
idleSkip = new QCheckBox("Idle skipping");
idleSkip->setToolTip("Whether to enable idle skipping.<br><br>"
"Note: idle skipping is a technique used in emulators<br>"
"that enables skipping the execution of certain blocks of guest code<br>"
"when it's determined that the aforementioned is used to wait on a certain<br>"
"event to occur; the code gets skipped, the event is executed immediately by<br>"
"the emulator so that the game never actually waits, progressing immediately and making "
"emulation much faster.<br><br>"
"This feature is not available when the pure interpreter is selected<br>"
"because the information regarding instructions would be too limited to<br>"
"perform the evaluation described above.");
idleSkip->setChecked(settings.value("cpu/idle_skip", false).value<bool>());
v = new QVBoxLayout();
h = new QHBoxLayout();
types->addItems({"Interpreter", "Cached Interpreter"});
if (Options::GetCpuType() == 0) {
idleSkip->hide();
} else {
selectedCpuTypeIndex = 0;
idleSkip->show();
}
types->setCurrentIndex(Options::GetCpuType());
idleSkip = Options::GetInstance().GetValue<bool>("cpu", "idleSkip");
}
connect(types, &QComboBox::currentIndexChanged, this, [&] {
int index = types->currentIndex();
if (index == 0)
idleSkip->hide();
else
idleSkip->show();
void CPUSettings::render() {
const char *items[] = {"Interpreter", "Cached Interpreter"};
Options::SetCpuType(index);
settings.setValue("cpu/type", index);
settings.sync();
emit cpuTypeChanged();
});
const char *combo_preview_value = items[selectedCpuTypeIndex];
if (ImGui::BeginCombo("CPU Type", combo_preview_value)) {
for (int n = 0; n < IM_ARRAYSIZE(items); n++) {
const bool is_selected = (selectedCpuTypeIndex == n);
if (ImGui::Selectable(items[n], is_selected)) {
selectedCpuTypeIndex = n;
modified = true;
}
connect(idleSkip, &QCheckBox::checkStateChanged, this, [&] {
Options::SetIdleSkip(idleSkip->checkState());
settings.setValue("cpu/idle_skip", idleSkip->checkState());
settings.sync();
emit idleSkipChanged();
});
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
ImGui::SetItemDefaultFocus();
}
ImGui::EndCombo();
}
bool showIdleSkipping = std::string(items[selectedCpuTypeIndex]) == "Cached Interpreter";
if (showIdleSkipping)
if (ImGui::Checkbox("Idle skipping", &idleSkip))
modified = true;
if (modified) {
if (selectedCpuTypeIndex == 0) {
Options::GetInstance().SetValue<std::string>("cpu", "type", "interpreter");
idleSkip = false;
Options::GetInstance().SetValue<bool>("cpu", "idleSkip", idleSkip);
n64::Core::GetInstance().cpuType = n64::Core::PlainInterpreter;
n64::Core::GetInstance().idleSkip = idleSkip;
} else {
Options::GetInstance().SetValue<std::string>("cpu", "type", "cached_interpreter");
Options::GetInstance().SetValue<bool>("cpu", "idleSkip", idleSkip);
n64::Core::GetInstance().cpuType = n64::Core::CachedInterpreter;
n64::Core::GetInstance().idleSkip = idleSkip;
}
}
h->addWidget(idleSkip);
v->addWidget(types);
v->addLayout(h);
setLayout(v);
}
+18 -5
View File
@@ -1,9 +1,22 @@
#pragma once
#include <SettingsTab.hpp>
#include <QWidget>
#include <QComboBox>
#include <QCheckBox>
#include <QVBoxLayout>
#include <QLabel>
#include <QSettings>
struct CPUSettings final : SettingsTab {
int selectedCpuTypeIndex = 0;
bool idleSkip = false;
void render() override;
class CPUSettings final : public QWidget {
Q_OBJECT
QComboBox *types;
QCheckBox *idleSkip;
QVBoxLayout *v;
QHBoxLayout *h;
QSettings settings;
public:
explicit CPUSettings();
signals:
void cpuTypeChanged();
void idleSkipChanged();
};
+28 -30
View File
@@ -1,35 +1,33 @@
#include <GeneralSettings.hpp>
#include <Options.hpp>
#include <imgui.h>
#include <QFileDialog>
#include <QCoreApplication>
#include <log.hpp>
GeneralSettings::GeneralSettings(gui::NativeWindow& window) : window(window) {
savesPath = Options::GetInstance().GetValue<std::string>("general", "savePath");
GeneralSettings::GeneralSettings() : settings(QSettings::UserScope) {
description = new QLabel("Path:");
description->setToolTip("Path where game saves are stored.");
selectedFolderLabel = new QLabel(Options::GetSavesPath().c_str());
selectedFolderLabel->setDisabled(true);
folderSelectButton = new QPushButton("Choose...");
connect(folderSelectButton, &QPushButton::clicked, this, [&] {
auto dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"), QCoreApplication::applicationDirPath(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks |
QFileDialog::DontUseNativeDialog);
selectedFolderLabel->setText(dir);
Options::SetSavesPath(dir.toStdString());
settings.setValue("general/saves_path", dir);
settings.sync();
});
h = new QHBoxLayout();
h->addWidget(description);
h->addWidget(selectedFolderLabel);
h->addWidget(folderSelectButton);
v = new QVBoxLayout(this);
v->addLayout(h);
setLayout(v);
}
void GeneralSettings::render() {
if(ImGui::Button("Pick...")) {
SDL_ShowOpenFolderDialog([](void *userdata, const char * const *filelist, int _) {
auto* general = static_cast<GeneralSettings*>(userdata);
if (!filelist) {
panic("An error occurred: {}", SDL_GetError());
}
if (!*filelist) {
warn("The user did not select any file.");
warn("Most likely, the dialog was canceled.");
general->modified = false;
return;
}
general->savesPath = fs::absolute(*filelist).string();
Options::GetInstance().SetValue<std::string>("general", "savePath", general->savesPath);
general->modified = true;
}, this, window.getHandle(), nullptr, false);
}
ImGui::SameLine();
ImGui::BeginDisabled();
ImGui::InputText("Save Path", const_cast<char*>(savesPath.c_str()), savesPath.length());
ImGui::EndDisabled();
}
+17 -9
View File
@@ -1,11 +1,19 @@
#pragma once
#include <SettingsTab.hpp>
#include <NativeWindow.hpp>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QSettings>
struct GeneralSettings final : SettingsTab {
void render() override;
explicit GeneralSettings(gui::NativeWindow&);
private:
gui::NativeWindow& window;
std::string savesPath;
};
class GeneralSettings final : public QWidget {
Q_OBJECT
QLabel *description;
QPushButton *folderSelectButton;
QLabel *selectedFolderLabel;
QVBoxLayout *v;
QHBoxLayout *h;
QSettings settings;
public:
explicit GeneralSettings();
};