Skip to content

Commit

Permalink
Load/save settings to a settings.toml file
Browse files Browse the repository at this point in the history
  • Loading branch information
aceiii committed Apr 19, 2024
1 parent df358df commit a47d0b9
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 48 deletions.
56 changes: 56 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#pragma once

#include <fstream>
#include <functional>
#include <string>
#include <iostream>
#include <system_error>
#include <tl/expected.hpp>
#include <toml++/toml.hpp>

template <typename Settings>
class Config {
public:
Settings settings;

tl::expected<void, std::string> load(const std::string& filename) {
auto result = toml::parse_file(filename);
if (!result) {
return tl::unexpected(std::string { result.error().description() });
}
table = std::move(result).table();
return {};
}

tl::expected<void, std::string> save(const std::string& filename) const {
try {
std::ofstream file(filename);
file << toml::toml_formatter { table };
file.close();
} catch (std::exception e) {
return tl::unexpected(e.what());
}
return {};
}

tl::expected<void, std::string> serialize(std::function<void(const Settings &settings, toml::table&)> serialize_func) {
try {
serialize_func(settings, table);
} catch (std::exception e) {
return tl::unexpected(e.what());
}
return {};
}

tl::expected<void, std::string> deserialize(std::function<void(const toml::table&, Settings &settings)> deserialize_func) {
try {
deserialize_func(table, settings);
} catch (std::exception e) {
return tl::unexpected(e.what());
}
return {};
}

private:
toml::table table;
};
142 changes: 107 additions & 35 deletions src/interface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
#include <fstream>
#include <imgui.h>
#include <imgui_internal.h>
#include <mach_debug/zone_info.h>
#include <memory>
#include <mutex>
#include <nfd.h>
#include <rlImGui.h>
#include <spdlog/spdlog.h>
#include <toml++/impl/table.hpp>

namespace fs = std::filesystem;

Expand All @@ -26,6 +28,8 @@ constexpr int kMaxSamplesPerUpdate = 4096;
constexpr int kAudioSampleRate = 44100;
constexpr int kDefaultScreenPixelSize = 4;

const char* const kSettingsFile = "settings.toml";

AudioStream stream;

bool play_sound = false;
Expand All @@ -43,10 +47,64 @@ float square(float val) {
return 0;
}

static void deserialize_settings(const toml::table &table, interface_settings &settings) {
settings.lock_fps = table["editor"]["lock_fps"].value_or(settings.lock_fps);
settings.show_fps = table["editor"]["show_fps"].value_or(settings.show_fps);
settings.show_demo = table["window"]["demo"].value_or(settings.show_demo);
settings.show_screen = table["window"]["screen"].value_or(settings.show_screen);
settings.show_memory = table["window"]["memory"].value_or(settings.show_memory);
settings.show_registers = table["window"]["registers"].value_or(settings.show_registers);
settings.show_logs = table["window"]["logs"].value_or(settings.show_logs);
settings.show_emulation = table["window"]["emulation"].value_or(settings.show_emulation);
settings.show_misc = table["window"]["misc"].value_or(settings.show_misc);
settings.show_instructions = table["window"]["instructions"].value_or(settings.show_instructions);
settings.show_keyboard = table["window"]["keyboard"].value_or(settings.show_keyboard);
}

static void serialize_settings(const interface_settings &settings, toml::table &table) {
toml::table *editor;
if (table.get("editor")) {
editor = table.get("editor")->as_table();
} else {
table.insert("editor", toml::table {});
editor = table.get("editor")->as_table();
}

editor->insert_or_assign("lock_fps", settings.lock_fps);
editor->insert_or_assign("show_fps", settings.show_fps);

toml::table *window;
if (table.get("window")) {
window = table.get("window")->as_table();
} else {
table.insert("window", toml::table {});
window = table.get("window")->as_table();
}

window->insert_or_assign("demo", settings.show_demo);
window->insert_or_assign("screen", settings.show_screen);
window->insert_or_assign("memory", settings.show_memory);
window->insert_or_assign("registers", settings.show_registers);
window->insert_or_assign("logs", settings.show_logs);
window->insert_or_assign("emulation", settings.show_emulation);
window->insert_or_assign("misc", settings.show_misc);
window->insert_or_assign("instructions", settings.show_instructions);
window->insert_or_assign("keyboard", settings.show_keyboard);
}

Interface::Interface(std::shared_ptr<registers> regs, Interpreter *interpreter)
: interpreter{interpreter}, regs(std::move(regs)) {}

void Interface::initialize() {
if (auto result = config.load(kSettingsFile); !result.has_value()) {
spdlog::trace("Settings.toml does not exist, using defaults: {}", result.error());
} else {
config.deserialize(deserialize_settings);
init_dock = false;
}

interface_settings &settings = config.settings;

NFD_Init();

int width = 1200;
Expand Down Expand Up @@ -81,7 +139,7 @@ void Interface::initialize() {
});
PlayAudioStream(stream);

if (lock_fps) {
if (settings.lock_fps) {
SetTargetFPS(kDefaultFPS);
}

Expand Down Expand Up @@ -128,6 +186,7 @@ void Interface::initialize() {
}

bool Interface::update() {
interface_settings &settings = config.settings;

if (IsFileDropped()) {
FilePathList droppedFiles = LoadDroppedFiles();
Expand Down Expand Up @@ -203,12 +262,12 @@ bool Interface::update() {

render_main_menu();

if (show_demo) {
ImGui::ShowDemoWindow(&show_demo);
if (settings.show_demo) {
ImGui::ShowDemoWindow(&settings.show_demo);
}

if (show_registers) {
if (ImGui::Begin("Registers", &show_registers)) {
if (settings.show_registers) {
if (ImGui::Begin("Registers", &settings.show_registers)) {
ImGui::BeginTable("general_registers", 4, ImGuiTableFlags_Borders);
{

Expand Down Expand Up @@ -279,8 +338,8 @@ bool Interface::update() {
ImGui::End();
}

if (show_misc) {
if (ImGui::Begin("Miscellaneous", &show_misc)) {
if (settings.show_misc) {
if (ImGui::Begin("Miscellaneous", &settings.show_misc)) {
ImGui::Text("ST: %04x (%05d)", regs->st, regs->st);
ImGui::Text("DT: %04x (%05d)", regs->dt, regs->dt);
ImGui::Text("I: %04x (%05d)", regs->i, regs->i);
Expand Down Expand Up @@ -322,8 +381,8 @@ bool Interface::update() {
ImGui::End();
}

if (show_emulation) {
if (ImGui::Begin("Emulation", &show_emulation)) {
if (settings.show_emulation) {
if (ImGui::Begin("Emulation", &settings.show_emulation)) {
ImGuiStyle &style = ImGui::GetStyle();

auto push_disabled_btn_flags = []() {
Expand Down Expand Up @@ -414,44 +473,44 @@ bool Interface::update() {
ImGui::End();
}

if (show_screen) {
if (ImGui::Begin("Screen", &show_screen)) {
if (settings.show_screen) {
if (ImGui::Begin("Screen", &settings.show_screen)) {
screen.draw();
}
ImGui::End();
}

if (show_memory) {
if (ImGui::Begin("Memory", &show_memory)) {
if (settings.show_memory) {
if (ImGui::Begin("Memory", &settings.show_memory)) {
mem_editor.DrawContents(regs->mem.data(), regs->mem.size());
}
ImGui::End();
}

if (show_instructions) {
if (ImGui::Begin("Instructions", &show_instructions)) {
if (settings.show_instructions) {
if (ImGui::Begin("Instructions", &settings.show_instructions)) {
assembly.draw();
}
ImGui::End();
}

if (show_logs) {
if (ImGui::Begin("Logs", &show_logs)) {
if (settings.show_logs) {
if (ImGui::Begin("Logs", &settings.show_logs)) {
app_log.draw();
}
ImGui::End();
}

if (show_keyboard) {
if (ImGui::Begin("Keyboard", &show_keyboard)) {
if (settings.show_keyboard) {
if (ImGui::Begin("Keyboard", &settings.show_keyboard)) {
keyboard.draw();
}
ImGui::End();
}

rlImGuiEnd();

if (show_fps) {
if (settings.show_fps) {
DrawFPS(10, GetScreenHeight() - 24);
}

Expand All @@ -461,6 +520,8 @@ bool Interface::update() {
}

void Interface::render_main_menu() {
interface_settings &settings = config.settings;

if (ImGui::BeginMainMenuBar()) {
if (ImGui::BeginMenu("File")) {

Expand Down Expand Up @@ -495,24 +556,24 @@ void Interface::render_main_menu() {
ImGui::EndMenu();
}
if (ImGui::BeginMenu("View")) {
ImGui::MenuItem("Emulation", nullptr, &show_emulation);
ImGui::MenuItem("Keyboard", nullptr, &show_keyboard);
ImGui::MenuItem("Screen", nullptr, &show_screen);
ImGui::MenuItem("Memory", nullptr, &show_memory);
ImGui::MenuItem("Registers", nullptr, &show_registers);
ImGui::MenuItem("Miscellaneous", nullptr, &show_misc);
ImGui::MenuItem("Emulation", nullptr, &settings.show_emulation);
ImGui::MenuItem("Keyboard", nullptr, &settings.show_keyboard);
ImGui::MenuItem("Screen", nullptr, &settings.show_screen);
ImGui::MenuItem("Memory", nullptr, &settings.show_memory);
ImGui::MenuItem("Registers", nullptr, &settings.show_registers);
ImGui::MenuItem("Miscellaneous", nullptr, &settings.show_misc);
ImGui::Separator();
if (ImGui::MenuItem("Lock FPS", nullptr, &lock_fps)) {
if (lock_fps) {
if (ImGui::MenuItem("Lock FPS", nullptr, &settings.lock_fps)) {
if (settings.lock_fps) {
spdlog::debug("Locking FPS");
SetTargetFPS(kDefaultFPS);
} else {
spdlog::debug("Unlocking FPS");
SetTargetFPS(0);
}
}
ImGui::MenuItem("Show FPS", nullptr, &show_fps);
ImGui::MenuItem("ImGui Demo", nullptr, &show_demo);
ImGui::MenuItem("Show FPS", nullptr, &settings.show_fps);
ImGui::MenuItem("ImGui Demo", nullptr, &settings.show_demo);
ImGui::Separator();
if (ImGui::MenuItem("Reset All Windows")) {
reset_windows();
Expand All @@ -524,11 +585,12 @@ void Interface::render_main_menu() {
}

void Interface::reset_windows() {
show_demo = false;
show_fps = false;
show_memory = true;
show_registers = true;
show_screen = true;
interface_settings &settings = config.settings;
settings.show_demo = false;
settings.show_fps = false;
settings.show_memory = true;
settings.show_registers = true;
settings.show_screen = true;
init_dock = true;
}

Expand All @@ -539,6 +601,16 @@ void Interface::cleanup() {
CloseAudioDevice();
CloseWindow();
NFD_Quit();

spdlog::info("Saving settings to file");

if (auto result = config.serialize(serialize_settings); !result.has_value()) {
spdlog::warn("Failed to serialize settings: {}", result.error());
}

if (auto result = config.save(kSettingsFile); !result.has_value()) {
spdlog::warn("Failed to write settings.toml: {}", result.error());
}
}

void Interface::open_load_rom_dialog() {
Expand Down
32 changes: 19 additions & 13 deletions src/interface.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include "config.h"
#include "interpreter.h"
#include "applog.h"
#include "screen.h"
Expand All @@ -12,13 +13,27 @@
#include <raylib.h>
#include <vector>

struct interface_settings {
bool lock_fps = true;
bool show_demo = false;
bool show_fps = false;
bool show_screen = true;
bool show_memory = true;
bool show_registers = true;
bool show_logs = true;
bool show_emulation = true;
bool show_misc = false;
bool show_instructions = true;
bool show_keyboard = true;
};

class Interface {
public:
Interface(std::shared_ptr<registers> regs, Interpreter *interpreter);

void initialize();
bool update();
static void cleanup();
void cleanup();

private:
void open_load_rom_dialog();
Expand All @@ -37,17 +52,8 @@ class Interface {

std::vector<uint8_t> rom;

bool lock_fps = true;
bool init_dock = true;
Config<interface_settings> config;

bool should_close = false;
bool show_demo = false;
bool show_fps = false;
bool show_screen = true;
bool show_memory = true;
bool show_registers = true;
bool show_logs = true;
bool show_emulation = true;
bool show_misc = false;
bool show_instructions = true;
bool show_keyboard = true;
bool init_dock = true;
};

0 comments on commit a47d0b9

Please sign in to comment.