From 4f618d35e008fc9721bc72c78a01e2432307a073 Mon Sep 17 00:00:00 2001 From: SimoZ64 Date: Sat, 28 Jun 2025 13:48:18 +0200 Subject: [PATCH] remove stupid abstraction --- src/Discord.hpp | 4 + src/backend/Core.cpp | 1 - src/frontend/AudioSettings.cpp | 37 +++--- src/frontend/AudioSettings.hpp | 8 +- src/frontend/CPUSettings.cpp | 38 +++++- src/frontend/CPUSettings.hpp | 3 +- src/frontend/EmuThread.cpp | 1 + src/frontend/EmuThread.hpp | 4 +- src/frontend/ImGuiImpl/Checkbox.hpp | 16 --- src/frontend/ImGuiImpl/Combobox.hpp | 84 ------------- src/frontend/ImGuiImpl/Menu.hpp | 79 ------------ src/frontend/ImGuiImpl/PopupWindow.hpp | 53 -------- src/frontend/ImGuiImpl/PushButton.hpp | 34 ----- src/frontend/ImGuiImpl/Slider.hpp | 53 -------- src/frontend/ImGuiImpl/StatusBar.hpp | 22 ---- src/frontend/ImGuiImpl/TabBar.hpp | 52 -------- src/frontend/KaizenGui.cpp | 164 ++++++++++++------------- src/frontend/KaizenGui.hpp | 7 -- src/frontend/SettingsWindow.cpp | 101 ++++++++------- src/frontend/SettingsWindow.hpp | 14 +-- 20 files changed, 200 insertions(+), 575 deletions(-) delete mode 100644 src/frontend/ImGuiImpl/Checkbox.hpp delete mode 100644 src/frontend/ImGuiImpl/Combobox.hpp delete mode 100644 src/frontend/ImGuiImpl/Menu.hpp delete mode 100644 src/frontend/ImGuiImpl/PopupWindow.hpp delete mode 100644 src/frontend/ImGuiImpl/PushButton.hpp delete mode 100644 src/frontend/ImGuiImpl/Slider.hpp delete mode 100644 src/frontend/ImGuiImpl/TabBar.hpp diff --git a/src/Discord.hpp b/src/Discord.hpp index 02b92aca..155837c2 100644 --- a/src/Discord.hpp +++ b/src/Discord.hpp @@ -67,6 +67,10 @@ struct RPC { } FORCE_INLINE void Clear() { Discord_ClearPresence(); } + FORCE_INLINE void Shutdown() { + Clear(); + Discord_Shutdown(); + } private: DiscordEventHandlers handlers{}; diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index 22cdfc03..264d3f87 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -8,7 +8,6 @@ Core::Core() : cpu(std::make_unique(parallel)) {} void Core::Stop() { pause = true; romLoaded = false; - rom = {}; cpu->Reset(); } diff --git a/src/frontend/AudioSettings.cpp b/src/frontend/AudioSettings.cpp index 1fc1ed3d..752c08ad 100644 --- a/src/frontend/AudioSettings.cpp +++ b/src/frontend/AudioSettings.cpp @@ -1,17 +1,18 @@ #include +#include AudioSettings::AudioSettings() { - lockChannels.setChecked(Options::GetInstance().GetValue("audio", "lock")); - volumeL.setValue(Options::GetInstance().GetValue("audio", "volumeL") * 100); - volumeR.setValue(Options::GetInstance().GetValue("audio", "volumeR") * 100); + lockChannels = Options::GetInstance().GetValue("audio", "lock"); + volumeL = Options::GetInstance().GetValue("audio", "volumeL") * 100; + volumeR = Options::GetInstance().GetValue("audio", "volumeR") * 100; } bool AudioSettings::render() { - if(lockChannels.render()) { - auto isChecked = lockChannels.isChecked(); - Options::GetInstance().SetValue("audio", "lock", isChecked); - if (isChecked) { - volumeR.setValue(volumeL.getValue()); + 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; @@ -19,12 +20,11 @@ bool AudioSettings::render() { ImGui::SameLine(); - if(volumeL.render()) { - float valueL = volumeL.getValue(); - Options::GetInstance().SetValue("audio", "volumeL", float(valueL) / 100.f); - if (lockChannels.isChecked()) { - volumeR.setValue(valueL); - Options::GetInstance().SetValue("audio", "volumeR", float(valueL) / 100.f); + 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; @@ -32,13 +32,12 @@ bool AudioSettings::render() { ImGui::SameLine(); - if(volumeR.render()) { - if (!lockChannels.isChecked()) { - Options::GetInstance().SetValue("audio", "volumeR", float(volumeR.getValue()) / 100.f); - } - + 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(); return modified; } \ No newline at end of file diff --git a/src/frontend/AudioSettings.hpp b/src/frontend/AudioSettings.hpp index 1a51a6bc..ef34dedf 100644 --- a/src/frontend/AudioSettings.hpp +++ b/src/frontend/AudioSettings.hpp @@ -1,14 +1,12 @@ #pragma once #include -#include -#include class AudioSettings final { - gui::Checkbox lockChannels{"Lock channels:", false}; + bool lockChannels = false; bool modified = false; public: - gui::SliderFloat volumeL{"Volume L", 0.f, 100.f, 0.f}; - gui::SliderFloat volumeR{"Volume R", 0.f, 100.f, 0.f}; + float volumeL{}; + float volumeR{}; explicit AudioSettings(); bool render(); void setModified(bool v) { modified = v; } diff --git a/src/frontend/CPUSettings.cpp b/src/frontend/CPUSettings.cpp index a3f787e6..41d81215 100644 --- a/src/frontend/CPUSettings.cpp +++ b/src/frontend/CPUSettings.cpp @@ -1,24 +1,50 @@ #include #include #include +#include CPUSettings::CPUSettings() { if (Options::GetInstance().GetValue("cpu", "type") == "jit") { - cpuTypes.setCurrentIndex(1); + selectedCpuTypeIndex = 1; } else { - cpuTypes.setCurrentIndex(0); + selectedCpuTypeIndex = 0; } } bool CPUSettings::render() { - if(cpuTypes.render()) { - if(cpuTypes.getCurrentIndex() == 0) { + const char* items[] = { + "Interpreter", + "Dynamic Recompiler" + }; + + const char* combo_preview_value = items[selectedCpuTypeIndex]; + if (ImGui::BeginCombo("CPU Type", combo_preview_value)) { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) { + if(n == 1) // make JIT non-selectable but visible for now. + ImGui::BeginDisabled(true); + + const bool is_selected = (selectedCpuTypeIndex == n); + if (ImGui::Selectable(items[n], is_selected)) { + selectedCpuTypeIndex = n; + modified = true; + } + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + + if(n == 1) // make JIT non-selectable but visible for now. + ImGui::EndDisabled(); + } + ImGui::EndCombo(); + } + + if(modified) { + if(selectedCpuTypeIndex == 0) { Options::GetInstance().SetValue("cpu", "type", "interpreter"); } else { Util::panic("JIT should not be selectable??"); } - - modified = true; } return modified; diff --git a/src/frontend/CPUSettings.hpp b/src/frontend/CPUSettings.hpp index 529afdf3..63f4859c 100644 --- a/src/frontend/CPUSettings.hpp +++ b/src/frontend/CPUSettings.hpp @@ -1,9 +1,8 @@ #pragma once #include -#include class CPUSettings final { - gui::Combobox cpuTypes{"CPU type:", {{"Interpreter"}, {"Dynamic Recompiler", false}}}; + int selectedCpuTypeIndex = 0; bool modified = false; public: bool render(); diff --git a/src/frontend/EmuThread.cpp b/src/frontend/EmuThread.cpp index 8fc6d2c5..9ed2a28b 100644 --- a/src/frontend/EmuThread.cpp +++ b/src/frontend/EmuThread.cpp @@ -56,4 +56,5 @@ void EmuThread::Reset() const noexcept { void EmuThread::Stop() const noexcept { Util::RPC::GetInstance().Update(Util::RPC::Idling); core->Stop(); + core->rom = {}; } diff --git a/src/frontend/EmuThread.hpp b/src/frontend/EmuThread.hpp index 423afbc9..220bbcd7 100644 --- a/src/frontend/EmuThread.hpp +++ b/src/frontend/EmuThread.hpp @@ -13,7 +13,9 @@ class EmuThread final { bool started = false; public: explicit EmuThread(const std::shared_ptr &, double &, RenderWidget &, SettingsWindow &) noexcept; - + ~EmuThread() { + Util::RPC::GetInstance().Shutdown(); + } void run() noexcept; void TogglePause() const noexcept; void Reset() const noexcept; diff --git a/src/frontend/ImGuiImpl/Checkbox.hpp b/src/frontend/ImGuiImpl/Checkbox.hpp deleted file mode 100644 index 306070a7..00000000 --- a/src/frontend/ImGuiImpl/Checkbox.hpp +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once -#include -#include - -namespace gui { -struct Checkbox { - Checkbox(const std::string& label, bool def = false) : val(def), label(label) {} - - void setChecked(bool v) { val = v; } - bool render() { return ImGui::Checkbox(label.c_str(), &val); } - bool isChecked() { return val; } -private: - bool val = false; - std::string label = ""; -}; -} \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/Combobox.hpp b/src/frontend/ImGuiImpl/Combobox.hpp deleted file mode 100644 index d022f17d..00000000 --- a/src/frontend/ImGuiImpl/Combobox.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once -#include -#include -#include - -namespace gui { -struct ComboItem { - ComboItem(const std::string& label, bool enabled = true) : enabled(enabled), label(label) {} - - bool render(bool is_selected) { - ImGui::BeginDisabled(!enabled); - bool ret = ImGui::Selectable(label.c_str(), is_selected); - ImGui::EndDisabled(); - return ret; - } - - const std::string& getLabel() const { return label; } - void setLabel(const std::string& text) { label = text; } -private: - bool enabled = true; - std::string label; -}; - -struct Combobox { - Combobox(const std::string& label, const std::vector& items, const std::string& preview = "", bool enabled = true) : label(label), items(items), preview(preview), enabled(enabled) {} - - void addItem(const ComboItem& item) { - if(std::find_if(items.begin(), items.end(), - [&item](const ComboItem& a) { return a.getLabel() == item.getLabel(); }) != items.end()) - return; - - items.push_back(item); - } - - void removeItem(const std::string& item) { - std::erase_if(items, [&item](ComboItem a) { return a.getLabel() == item; }); - } - - bool render() { - const char* _preview = ""; - - if(preview != "") { - _preview = preview.c_str(); - } else { - _preview = items[current_index].getLabel().c_str(); - } - - bool changed = false; - - ImGui::BeginDisabled(!enabled); - if (ImGui::BeginCombo(label.c_str(), _preview)) { - for (int n = 0; n < items.size(); n++) { - const bool is_selected = ((current_index) == n); - if (items[n].render(is_selected)) - { - current_index = n; - changed = true; - } - // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) - if (is_selected) - ImGui::SetItemDefaultFocus(); - } - ImGui::EndCombo(); - } - ImGui::EndDisabled(); - - return changed; - } - - void setEnabled(bool v) { enabled = v; } - bool isEnabled() { return enabled; } - - const std::string& getCurrentlySelected() { return items[current_index].getLabel(); } - const int& getCurrentlySelectedIndex() { return current_index; } - - void setCurrentIndex(int v) { current_index = v; } - int getCurrentIndex() { return current_index; } -private: - bool enabled = true; - std::vector items; - std::string label, preview; - int current_index = 0; -}; -} \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/Menu.hpp b/src/frontend/ImGuiImpl/Menu.hpp deleted file mode 100644 index 9c68ee84..00000000 --- a/src/frontend/ImGuiImpl/Menu.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace gui { -struct MenuItem { - MenuItem(const std::string& label, std::function&& func = nullptr, bool enabled = true) : label(label), exec(std::move(func)), enabled(enabled) {} - bool render() { - bool ret = false; - ImGui::BeginDisabled(!enabled); - if(ImGui::MenuItem(label.c_str())) { - if(exec) - exec(); - ret = true; - } - ImGui::EndDisabled(); - return ret; - } - - void setLabel(const std::string& label) { this->label = label; } - const std::string& getLabel() { return label; } - - void setFunc(std::function&& func) { exec = func; } - - void setEnabled(bool v) { enabled = v; } -private: - bool enabled = true; - std::string label; - std::function exec; -}; - -struct Menu { - Menu(const std::string& label, const std::vector& items = {}, bool enabled = true) : label(label), items(items), enabled(enabled) {} - void addMenuItem(const MenuItem& item) { items.push_back(item); } - bool render() { - bool ret = false; - ImGui::BeginDisabled(!enabled); - if(ImGui::BeginMenu(label.c_str())) { - for(auto& item : items) { - ret |= item.render(); - } - ImGui::EndMenu(); - } - ImGui::EndDisabled(); - return ret; - } - void setEnabled(bool v) { enabled = v; } -private: - std::vector items{}; - std::string label{}; - bool enabled = true; -}; - -template -struct MenuBar { - MenuBar(bool enabled = true) : enabled(enabled) {} - void addMenu(const Menu& menu) { menus.push_back(menu); } - bool render() { - bool ret = false; - ImGui::BeginDisabled(!enabled); - auto beginMenuBar = main ? &ImGui::BeginMainMenuBar : &ImGui::BeginMenuBar; - auto endMenuBar = main ? &ImGui::EndMainMenuBar : &ImGui::EndMenuBar; - if(beginMenuBar()) { - for(auto& menu : menus) { - ret |= menu.render(); - } - endMenuBar(); - } - ImGui::EndDisabled(); - return ret; - } - void setEnabled(bool v) { enabled = v; } -private: - bool enabled = true; - std::vector menus{}; -}; -} \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/PopupWindow.hpp b/src/frontend/ImGuiImpl/PopupWindow.hpp deleted file mode 100644 index 9b4deed2..00000000 --- a/src/frontend/ImGuiImpl/PopupWindow.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace gui { -struct PopupWindow { - PopupWindow(const std::string& title, std::function&& func = nullptr, bool opened = false) : title(title), exec(func), opened(opened) {} - void setFunc(std::function&& func) { exec = func; } - - void setOpened(bool v) { opened = v; } - void setOnClose(std::function&& func) { onClose = func; } - void setOnOpen(std::function&& func) { onOpen = func; } - - bool render() { - if(!opened) { - if(onClose) - onClose(); - - return false; - } - - if (!ImGui::IsPopupOpen(title.c_str())) - { - if(onOpen) - onOpen(); - ImGui::OpenPopup(title.c_str()); - } - - ImVec2 center = ImGui::GetMainViewport()->GetCenter(); - ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - - if (ImGui::BeginPopupModal(title.c_str(), &opened, ImGuiWindowFlags_AlwaysAutoResize)) - { - if(exec) - exec(); - - ImGui::EndPopup(); - - return true; - } - - return false; - } -private: - std::function exec; - std::function onClose; - std::function onOpen; - std::string title; - bool opened = false; -}; -} \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/PushButton.hpp b/src/frontend/ImGuiImpl/PushButton.hpp deleted file mode 100644 index f25d7015..00000000 --- a/src/frontend/ImGuiImpl/PushButton.hpp +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once -#include -#include - -namespace gui { -struct PushButton { - PushButton(const std::string& label, const std::string& name = "", bool enabled = true) : label(label), name(name), enabled(enabled) {} - - bool render() { - if(name != "") { - ImGui::Text("%s", name.c_str()); - ImGui::SameLine(); - } - - ImGui::BeginDisabled(!enabled); - bool ret = ImGui::Button(label.c_str()); - ImGui::EndDisabled(); - return ret; - } - - void setEnabled(bool v) { enabled = v; } - bool getEnabled() { return enabled; } - - const std::string& getName() { return name; } - void setName(const std::string& v) { name = v; } - - const std::string& getLabel() { return label; } - void setLabel(const std::string& v) { label = v; } -private: - bool enabled = true; - std::string name; - std::string label; -}; -} \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/Slider.hpp b/src/frontend/ImGuiImpl/Slider.hpp deleted file mode 100644 index 6d716ca4..00000000 --- a/src/frontend/ImGuiImpl/Slider.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once -#include -#include - -namespace gui { -template -struct Slider { - Slider(const std::string& label, T min = 0, T max = 0, T initial_value = 0) - : val(initial_value), label(label), min(min), max(max) { } - - void setValue(T v) { val = v; } - bool render() { - return ImGui::SliderScalarN(label.c_str(), type_to_imgui(), (void*)&val, 1, (void*)&min, (void*)&max); - } - T getValue() const { return val; } -private: - constexpr ImGuiDataType_ type_to_imgui() { - if constexpr(std::is_same_v) { - return ImGuiDataType_S8; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_U8; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_S16; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_U16; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_S32; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_U32; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_S64; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_U64; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_Float; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_Double; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_Bool; - } else if constexpr(std::is_same_v) { - return ImGuiDataType_String; - } else { - return ImGuiDataType_COUNT; - } - } - - T val{}, min{}, max{}; - std::string label = ""; -}; - -using SliderFloat = Slider; -using SliderInt = Slider; -} \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/StatusBar.hpp b/src/frontend/ImGuiImpl/StatusBar.hpp index 7d9182aa..bbb9c76d 100644 --- a/src/frontend/ImGuiImpl/StatusBar.hpp +++ b/src/frontend/ImGuiImpl/StatusBar.hpp @@ -40,26 +40,4 @@ inline void EndMainStatusBar() End(); } -} - -namespace gui { -struct StatusBar { - StatusBar(std::function&& func = nullptr, bool enabled = true) : exec(func), enabled(enabled) {} - - void setFunc(std::function&& func) { exec = func; } - - bool render() { - if(ImGui::BeginMainStatusBar()) { - if(exec) - exec(); - ImGui::EndMainStatusBar(); - return true; - } - - return false; - } -private: - std::function exec = nullptr; - bool enabled = true; -}; } \ No newline at end of file diff --git a/src/frontend/ImGuiImpl/TabBar.hpp b/src/frontend/ImGuiImpl/TabBar.hpp deleted file mode 100644 index 4f0abb1f..00000000 --- a/src/frontend/ImGuiImpl/TabBar.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once -#include -#include -#include -#include - -namespace gui { - -struct TabItem { - TabItem(const std::string& label, std::function&& func, bool enabled = true) : exec(std::move(func)), enabled(enabled), label(label) {} - - bool render() { - bool ret = false; - ImGui::BeginDisabled(!enabled); - if(ImGui::BeginTabItem(label.c_str())) { - if(exec) - exec(); - ImGui::EndTabItem(); - ret = true; - } - ImGui::EndDisabled(); - return ret; - } -private: - bool enabled = true; - std::string label; - std::function exec; -}; - -struct TabBar { - TabBar(const std::string& label, const std::vector& items = {}) : label(label), tabs(items) {} - void addTab(TabItem tabItem) { tabs.push_back(tabItem); } - - bool render() { - bool ret = false; - ImGui::BeginDisabled(!enabled); - if(ImGui::BeginTabBar(label.c_str())) { - ret = true; - for(auto& tab : tabs) { - ret &= tab.render(); - } - ImGui::EndTabBar(); - } - ImGui::EndDisabled(); - return ret; - } -private: - bool enabled = true; - std::string label; - std::vector tabs; -}; -} \ No newline at end of file diff --git a/src/frontend/KaizenGui.cpp b/src/frontend/KaizenGui.cpp index 75048837..3302ec6e 100644 --- a/src/frontend/KaizenGui.cpp +++ b/src/frontend/KaizenGui.cpp @@ -1,8 +1,8 @@ #include #include #include -#include #include +#include #include KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_shared()), vulkanWidget(core, window.getHandle()), emuThread(core, fpsCounter, vulkanWidget, settingsWindow) { @@ -10,82 +10,6 @@ KaizenGui::KaizenGui() noexcept : window("Kaizen", 800, 600), core(std::make_sha SDL_InitSubSystem(SDL_INIT_GAMEPAD); SDL_AddGamepadMapping(gamecontrollerdb_str); - - actionPause.setFunc([&]() { - if(ImGui::IsItemClicked()) { - actionPause.setLabel(actionPause.getLabel() == "Pause" ? "Resume" : "Pause"); - core->TogglePause(); - } - }); - - actionStop.setFunc([&]() { - if(ImGui::IsItemClicked()) { - actionStop.setEnabled(false); - actionPause.setEnabled(false); - actionReset.setEnabled(false); - core->Stop(); - } - }); - - about.setFunc([&]() { - ImGui::Text("Kaizen is a Nintendo 64 emulator that strives"); - ImGui::Text("to offer a friendly user experience and compatibility."); - ImGui::Text("Kaizen is licensed under the BSD 3-clause license."); - ImGui::Text("Nintendo 64 is a registered trademark of Nintendo Co., Ltd."); - if(ImGui::Button("OK")) { - about.setOpened(false); - ImGui::CloseCurrentPopup(); - } - }); - - statusBar.setFunc([&]() { - /* TODO: for when I'll separate the GUI and the Core in two threads again - ImGui::Text("GUI FPS: %.2f, Emulation FPS: %s", ImGui::GetIO().Framerate, - fmt::format(fpsCounter > 0 ? fmt::runtime("{0:.2f}") : fmt::runtime("{1}"), fpsCounter, "Not playing").c_str()); - */ - ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate); - }); - - menuBar.addMenu({"File", - { - {"Open", [&]() { - NFD::Guard guard; - NFD::UniquePath path; - static const std::vector filterItems = { - {"Nintendo 64 rom archive", "rar,RAR,tar,TAR,zip,ZIP,7z,7Z"}, - {"Nintendo 64 rom", "n64,z64,v64,N64,Z64,V64"} - }; - - auto result = NFD::OpenDialog(path, filterItems.data(), filterItems.size()); - if(result == NFD_CANCEL) return; - if(result == NFD_ERROR) - Util::panic("Error: {}", NFD::GetError()); - - LoadROM(path.get()); - }}, - {"Exit", [&]() { - quit = true; - emuThread.Stop(); - }} - } - }); - - menuBar.addMenu({ - "Emulation", { - actionPause, - actionStop, - actionReset, - {"Settings", [&]() { - settingsWindow.popup.setOpened(true); - }}, - }}); - - menuBar.addMenu({ - "Help", { - {"About", [&]() { - about.setOpened(true); - }}, - }}); } KaizenGui::~KaizenGui() { @@ -190,10 +114,85 @@ void KaizenGui::HandleInput(SDL_Event event) { void KaizenGui::RenderUI() { gui::StartFrame(); - statusBar.render(); - menuBar.render(); - settingsWindow.render(); - about.render(); + + static bool actionsEnabled = false; + + if(ImGui::BeginMainMenuBar()) { + if(ImGui::BeginMenu("File")) { + if(ImGui::MenuItem("Open")) { + NFD::Guard guard; + NFD::UniquePath path; + static const std::vector filterItems = { + {"Nintendo 64 rom archive", "rar,RAR,tar,TAR,zip,ZIP,7z,7Z"}, + {"Nintendo 64 rom", "n64,z64,v64,N64,Z64,V64"} + }; + + auto result = NFD::OpenDialog(path, filterItems.data(), filterItems.size()); + if(result == NFD_ERROR) + Util::panic("Error: {}", NFD::GetError()); + + if(result != NFD_CANCEL) { + LoadROM(path.get()); + actionsEnabled = true; + } + } + if(ImGui::MenuItem("Exit")) { + quit = true; + emuThread.Stop(); + } + ImGui::EndMenu(); + } + if(ImGui::BeginMenu("Emulation")) { + ImGui::BeginDisabled(!actionsEnabled); + + if(ImGui::MenuItem(core->pause ? "Resume" : "Pause")) { + emuThread.TogglePause(); + } + + if(ImGui::MenuItem("Reset")) { + emuThread.Reset(); + } + + if(ImGui::MenuItem("Stop")) { + emuThread.Stop(); + actionsEnabled = false; + } + + ImGui::EndDisabled(); + + if(ImGui::MenuItem("Settings")) { + settingsWindow.render(); + } + ImGui::EndMenu(); + } + if(ImGui::BeginMenu("Help")) { + if(ImGui::MenuItem("About")) { + ImGui::OpenPopup("About Kaizen"); + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); + + if (ImGui::BeginPopupModal("About Kaizen", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { + ImGui::Text("Kaizen is a Nintendo 64 emulator that strives"); + ImGui::Text("to offer a friendly user experience and compatibility."); + ImGui::Text("Kaizen is licensed under the BSD 3-clause license."); + ImGui::Text("Nintendo 64 is a registered trademark of Nintendo Co., Ltd."); + if(ImGui::Button("OK")) { + ImGui::CloseCurrentPopup(); + } + + ImGui::EndPopup(); + } + } + + ImGui::EndMenu(); + } + ImGui::EndMainMenuBar(); + } + if(ImGui::BeginMainStatusBar()) { + ImGui::Text("FPS: %.2f", ImGui::GetIO().Framerate); + ImGui::EndMainStatusBar(); + } + ImGui::Render(); if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable){ ImGui::UpdatePlatformWindows(); @@ -209,9 +208,6 @@ void KaizenGui::RenderUI() { } void KaizenGui::LoadROM(const std::string &path) noexcept { - actionPause.setEnabled(true); - actionReset.setEnabled(true); - actionStop.setEnabled(true); emuThread.core->LoadROM(path); const auto gameNameDB = emuThread.core->cpu->GetMem().rom.gameNameDB; Util::RPC::GetInstance().Update(Util::RPC::Playing, gameNameDB); diff --git a/src/frontend/KaizenGui.hpp b/src/frontend/KaizenGui.hpp index ba58e62e..852f2063 100644 --- a/src/frontend/KaizenGui.hpp +++ b/src/frontend/KaizenGui.hpp @@ -2,8 +2,6 @@ #include #include #include -#include -#include #include #include #include @@ -16,11 +14,6 @@ public: double fpsCounter = -1.0; - gui::MenuBar menuBar; - gui::MenuItem actionPause{"Pause", nullptr, false}, actionStop{"Stop", nullptr, false}, actionReset{"Reset", nullptr, false}; - gui::PopupWindow about{"About Kaizen"}; - gui::StatusBar statusBar{}; - std::shared_ptr core; RenderWidget vulkanWidget; SettingsWindow settingsWindow; diff --git a/src/frontend/SettingsWindow.cpp b/src/frontend/SettingsWindow.cpp index 187f3cb8..0dd60bd3 100644 --- a/src/frontend/SettingsWindow.cpp +++ b/src/frontend/SettingsWindow.cpp @@ -3,66 +3,73 @@ #include #include #include +#include std::string savePath; -SettingsWindow::SettingsWindow() { - savesFolder.setName(fmt::format("Save path: {}", - Options::GetInstance().GetValue("general", "savePath"))); +bool SettingsWindow::render() { + static bool applyEnabled = false; + ImGui::OpenPopup("Settings", ImGuiPopupFlags_None); + ImVec2 center = ImGui::GetMainViewport()->GetCenter(); + ImGui::SetNextWindowPos(center, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f)); - tabs.addTab({"General", [&]() { - if(savesFolder.render()) { - NFD::Guard guard; - NFD::UniquePath outPath; + if(ImGui::BeginPopupModal("Settings")) { + if(ImGui::BeginTabBar("SettingsTabBar")) { + if(ImGui::BeginTabItem("General")) { + ImGui::BeginDisabled(); + ImGui::InputText("Save Path", (char*)savesPath.c_str(), savesPath.length()); + ImGui::EndDisabled(); + ImGui::SameLine(); + if(ImGui::Button("Pick...")) { + NFD::Guard guard; + NFD::UniquePath outPath; - auto result = NFD::PickFolder(outPath); - if(result == NFD_CANCEL) - return; - if(result == NFD_ERROR) - Util::panic("Error: {}", NFD::GetError()); + auto result = NFD::PickFolder(outPath); + if(result == NFD_ERROR) + Util::panic("Error: {}", NFD::GetError()); - savesFolder.setName(fmt::format("Save path: {}", outPath.get())); - Options::GetInstance().SetValue("general", "savePath", outPath.get()); - apply.setEnabled(true); + if(result != NFD_CANCEL) { + savesPath = outPath.get(); + Options::GetInstance().SetValue("general", "savePath", savesPath); + applyEnabled = true; + } + } + ImGui::EndTabItem(); + } + + if(ImGui::BeginTabItem("Core")) { + if(cpuSettings.render()) { + if(cpuSettings.getModified()) + applyEnabled = true; + } + ImGui::EndTabItem(); + } + + if(ImGui::BeginTabItem("Audio")) { + if(audioSettings.render()) { + if(audioSettings.getModified()) + applyEnabled = true; + } + ImGui::EndTabItem(); + } + + ImGui::EndTabBar(); } - }}); - tabs.addTab({"CPU", [&]() { - if(cpuSettings.render()) { - if(cpuSettings.getModified()) - apply.setEnabled(true); - } - }}); - - tabs.addTab({"Audio", [&]() { - if(audioSettings.render()) { - if(audioSettings.getModified()) - apply.setEnabled(true); - } - }}); - - apply.setEnabled(false); - - popup.setFunc([&]() { - tabs.render(); - - if(apply.render()) { - apply.setEnabled(false); + ImGui::BeginDisabled(!applyEnabled); + if(ImGui::Button("Apply")) { + applyEnabled = false; Options::GetInstance().Apply(); } - + ImGui::EndDisabled(); + ImGui::SameLine(); - + if(ImGui::Button("Cancel")) { - popup.setOpened(false); ImGui::CloseCurrentPopup(); } - }); -} + ImGui::EndPopup(); + } -bool SettingsWindow::render() { - if(popup.render()) - return true; - - return false; + return true; } \ No newline at end of file diff --git a/src/frontend/SettingsWindow.hpp b/src/frontend/SettingsWindow.hpp index c8c66a63..8741c175 100644 --- a/src/frontend/SettingsWindow.hpp +++ b/src/frontend/SettingsWindow.hpp @@ -1,22 +1,16 @@ #pragma once #include #include -#include -#include -#include #include #include class SettingsWindow final { - gui::PushButton apply{"Apply", "", false}, savesFolder{"Open", "Save path: {}"}; CPUSettings cpuSettings; AudioSettings audioSettings; + std::string savesPath; public: - gui::PopupWindow popup{"Emulator Settings"}; bool render(); - SettingsWindow(); - [[nodiscard]] float getVolumeL() const { return audioSettings.volumeL.getValue() / 100.f; } - [[nodiscard]] float getVolumeR() const { return audioSettings.volumeR.getValue() / 100.f; } - - gui::TabBar tabs{"SettingsTabs"}; + SettingsWindow() = default; + [[nodiscard]] float getVolumeL() const { return audioSettings.volumeL / 100.f; } + [[nodiscard]] float getVolumeR() const { return audioSettings.volumeR / 100.f; } };