From ed83abaeefd402e7c7fb9c658e5a9599ea28024c Mon Sep 17 00:00:00 2001 From: Ryzerth Date: Thu, 22 Apr 2021 19:18:19 +0200 Subject: [PATCH] meteor demodulator now saves the recording path --- core/src/core.cpp | 10 ++ core/src/gui/theme_manager.cpp | 175 ++++++++++++++++++++++++++++++++ core/src/gui/theme_manager.h | 77 ++++++++++++++ meteor_demodulator/src/main.cpp | 37 ++++++- 4 files changed, 295 insertions(+), 4 deletions(-) create mode 100644 core/src/gui/theme_manager.cpp create mode 100644 core/src/gui/theme_manager.h diff --git a/core/src/core.cpp b/core/src/core.cpp index b13b8f83..f43445c3 100644 --- a/core/src/core.cpp +++ b/core/src/core.cpp @@ -207,6 +207,11 @@ int sdrpp_main(int argc, char *argv[]) { json bandColors = core::configManager.conf["bandColors"]; core::configManager.release(); + if (!std::filesystem::is_directory(resDir)) { + spdlog::error("Resource directory doesn't exist! Please make sure that you've configured it correctly in config.json (check readme for details)"); + return 1; + } + // Create window with graphics context GLFWmonitor* monitor = glfwGetPrimaryMonitor(); GLFWwindow* window = glfwCreateWindow(winWidth, winHeight, "SDR++ v" VERSION_STR " (Built at " __TIME__ ", " __DATE__ ")", NULL, NULL); @@ -223,6 +228,11 @@ int sdrpp_main(int argc, char *argv[]) { #endif // Load app icon + if (!std::filesystem::is_regular_file(resDir + "/icons/sdrpp.png")) { + spdlog::error("Icon file '{0}' doesn't exist!", resDir + "/icons/sdrpp.png"); + return 1; + } + GLFWimage icons[10]; icons[0].pixels = stbi_load(((std::string)(resDir + "/icons/sdrpp.png")).c_str(), &icons[0].width, &icons[0].height, 0, 4); icons[1].pixels = (unsigned char*)malloc(16 * 16 * 4); icons[1].width = icons[1].height = 16; diff --git a/core/src/gui/theme_manager.cpp b/core/src/gui/theme_manager.cpp new file mode 100644 index 00000000..5f872c90 --- /dev/null +++ b/core/src/gui/theme_manager.cpp @@ -0,0 +1,175 @@ +#include +#include +#include +#include +#include +#include + +using nlohmann::json; + +bool ThemeManager::loadThemesFromDir(std::string path) { + if (!std::filesystem::is_directory(path)) { + spdlog::error("Theme directory doesn't exist: {0}", path); + return false; + } + themes.clear(); + for (const auto & file : std::filesystem::directory_iterator(path)) { + std::string _path = file.path().generic_string(); + if (file.path().extension().generic_string() != ".json") { + continue; + } + loadTheme(_path); + } + return true; +} + +bool ThemeManager::loadTheme(std::string path) { + if (!std::filesystem::is_regular_file(path)) { + spdlog::error("Theme file doesn't exist: {0}", path); + return false; + } + + // Load defaults in theme + Theme thm; + + // Load JSON + std::ifstream file(path.c_str()); + json data; + file >> data; + file.close(); + + // Load theme + uint8_t val[4]; + if (data.contains("Text")) { if (decodeRGBA(data["Text"], val)) { thm.Text = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TextDisabled")) { if (decodeRGBA(data["TextDisabled"], val)) { thm.TextDisabled = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("WindowBg")) { if (decodeRGBA(data["WindowBg"], val)) { thm.WindowBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ChildBg")) { if (decodeRGBA(data["ChildBg"], val)) { thm.ChildBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("PopupBg")) { if (decodeRGBA(data["PopupBg"], val)) { thm.PopupBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("Border")) { if (decodeRGBA(data["Border"], val)) { thm.Border = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("BorderShadow")) { if (decodeRGBA(data["BorderShadow"], val)) { thm.BorderShadow = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("FrameBg")) { if (decodeRGBA(data["FrameBg"], val)) { thm.FrameBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("FrameBgHovered")) { if (decodeRGBA(data["FrameBgHovered"], val)) { thm.FrameBgHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("FrameBgActive")) { if (decodeRGBA(data["FrameBgActive"], val)) { thm.FrameBgActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TitleBg")) { if (decodeRGBA(data["TitleBg"], val)) { thm.TitleBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TitleBgActive")) { if (decodeRGBA(data["TitleBgActive"], val)) { thm.TitleBgActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TitleBgCollapsed")) { if (decodeRGBA(data["TitleBgCollapsed"], val)) { thm.TitleBgCollapsed = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("MenuBarBg")) { if (decodeRGBA(data["MenuBarBg"], val)) { thm.MenuBarBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ScrollbarBg")) { if (decodeRGBA(data["ScrollbarBg"], val)) { thm.ScrollbarBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ScrollbarGrab")) { if (decodeRGBA(data["ScrollbarGrab"], val)) { thm.ScrollbarGrab = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ScrollbarGrabHovered")) { if (decodeRGBA(data["ScrollbarGrabHovered"], val)) { thm.ScrollbarGrabHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ScrollbarGrabActive")) { if (decodeRGBA(data["ScrollbarGrabActive"], val)) { thm.ScrollbarGrabActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("CheckMark")) { if (decodeRGBA(data["CheckMark"], val)) { thm.CheckMark = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("SliderGrab")) { if (decodeRGBA(data["SliderGrab"], val)) { thm.SliderGrab = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TeSliderGrabActivext")) { if (decodeRGBA(data["SliderGrabActive"], val)) { thm.SliderGrabActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("Button")) { if (decodeRGBA(data["Button"], val)) { thm.Button = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ButtonHovered")) { if (decodeRGBA(data["ButtonHovered"], val)) { thm.ButtonHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ButtonActive")) { if (decodeRGBA(data["ButtonActive"], val)) { thm.ButtonActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("Header")) { if (decodeRGBA(data["Header"], val)) { thm.Header = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("HeaderHovered")) { if (decodeRGBA(data["HeaderHovered"], val)) { thm.HeaderHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("HeaderActive")) { if (decodeRGBA(data["HeaderActive"], val)) { thm.HeaderActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("Separator")) { if (decodeRGBA(data["Separator"], val)) { thm.Separator = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("SeparatorHovered")) { if (decodeRGBA(data["SeparatorHovered"], val)) { thm.SeparatorHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("SeparatorActive")) { if (decodeRGBA(data["SeparatorActive"], val)) { thm.SeparatorActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ResizeGrip")) { if (decodeRGBA(data["ResizeGrip"], val)) { thm.ResizeGrip = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ResizeGripHovered")) { if (decodeRGBA(data["ResizeGripHovered"], val)) { thm.ResizeGripHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ResizeGripActive")) { if (decodeRGBA(data["ResizeGripActive"], val)) { thm.ResizeGripActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("Tab")) { if (decodeRGBA(data["Tab"], val)) { thm.Tab = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TabHovered")) { if (decodeRGBA(data["TabHovered"], val)) { thm.TabHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TabActive")) { if (decodeRGBA(data["TabActive"], val)) { thm.TabActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TabUnfocused")) { if (decodeRGBA(data["TabUnfocused"], val)) { thm.TabUnfocused = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TabUnfocusedActive")) { if (decodeRGBA(data["TabUnfocusedActive"], val)) { thm.TabUnfocusedActive = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("PlotLines")) { if (decodeRGBA(data["PlotLines"], val)) { thm.PlotLines = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("PlotLinesHovered")) { if (decodeRGBA(data["PlotLinesHovered"], val)) { thm.PlotLinesHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("PlotHistogram")) { if (decodeRGBA(data["PlotHistogram"], val)) { thm.PlotHistogram = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("PlotHistogramHovered")) { if (decodeRGBA(data["PlotHistogramHovered"], val)) { thm.PlotHistogramHovered = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TableHeaderBg")) { if (decodeRGBA(data["TableHeaderBg"], val)) { thm.TableHeaderBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TableBorderStrong")) { if (decodeRGBA(data["TableBorderStrong"], val)) { thm.TableBorderStrong = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TableBorderLight")) { if (decodeRGBA(data["TableBorderLight"], val)) { thm.TableBorderLight = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TableRowBg")) { if (decodeRGBA(data["TableRowBg"], val)) { thm.TableRowBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TableRowBgAlt")) { if (decodeRGBA(data["TableRowBgAlt"], val)) { thm.TableRowBgAlt = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("TextSelectedBg")) { if (decodeRGBA(data["TextSelectedBg"], val)) { thm.TextSelectedBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("DragDropTarget")) { if (decodeRGBA(data["DragDropTarget"], val)) { thm.DragDropTarget = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("NavHighlight")) { if (decodeRGBA(data["NavHighlight"], val)) { thm.NavHighlight = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("NavWindowingHighlight")) { if (decodeRGBA(data["NavWindowingHighlight"], val)) { thm.NavWindowingHighlight = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("NavWindowingDimBg")) { if (decodeRGBA(data["NavWindowingDimBg"], val)) { thm.NavWindowingDimBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + if (data.contains("ModalWindowDimBg")) { if (decodeRGBA(data["ModalWindowDimBg"], val)) { thm.ModalWindowDimBg = ImVec4((float)val[0]/255.0f, (float)val[1]/255.0f, (float)val[2]/255.0f, (float)val[3]/255.0f); } } + + return true; +} + +bool ThemeManager::applyTheme(std::string name) { + if (themes.find(name) == themes.end()) { + spdlog::error("Unknown theme: {0}", name); + return false; + } + + auto& style = ImGui::GetStyle(); + ImVec4* colors = style.Colors; + Theme thm = themes[name]; + colors[ImGuiCol_Text] = thm.Text; + colors[ImGuiCol_TextDisabled] = thm.TextDisabled; + colors[ImGuiCol_WindowBg] = thm.WindowBg; + colors[ImGuiCol_ChildBg] = thm.ChildBg; + colors[ImGuiCol_PopupBg] = thm.PopupBg; + colors[ImGuiCol_Border] = thm.Border; + colors[ImGuiCol_BorderShadow] = thm.BorderShadow; + colors[ImGuiCol_FrameBg] = thm.FrameBg; + colors[ImGuiCol_FrameBgHovered] = thm.FrameBgHovered; + colors[ImGuiCol_FrameBgActive] = thm.FrameBgActive; + colors[ImGuiCol_TitleBg] = thm.TitleBg; + colors[ImGuiCol_TitleBgActive] = thm.TitleBgActive; + colors[ImGuiCol_TitleBgCollapsed] = thm.TitleBgCollapsed; + colors[ImGuiCol_MenuBarBg] = thm.MenuBarBg; + colors[ImGuiCol_ScrollbarBg] = thm.ScrollbarBg; + colors[ImGuiCol_ScrollbarGrab] = thm.ScrollbarGrab; + colors[ImGuiCol_ScrollbarGrabHovered] = thm.ScrollbarGrabHovered; + colors[ImGuiCol_ScrollbarGrabActive] = thm.ScrollbarGrabActive; + colors[ImGuiCol_CheckMark] = thm.CheckMark; + colors[ImGuiCol_SliderGrab] = thm.SliderGrab; + colors[ImGuiCol_SliderGrabActive] = thm.SliderGrabActive; + colors[ImGuiCol_Button] = thm.Button; + colors[ImGuiCol_ButtonHovered] = thm.ButtonHovered; + colors[ImGuiCol_ButtonActive] = thm.ButtonActive; + colors[ImGuiCol_Header] = thm.Header; + colors[ImGuiCol_HeaderHovered] = thm.HeaderHovered; + colors[ImGuiCol_HeaderActive] = thm.HeaderActive; + colors[ImGuiCol_Separator] = thm.Separator; + colors[ImGuiCol_SeparatorHovered] = thm.SeparatorHovered; + colors[ImGuiCol_SeparatorActive] = thm.SeparatorActive; + colors[ImGuiCol_ResizeGrip] = thm.ResizeGrip; + colors[ImGuiCol_ResizeGripHovered] = thm.ResizeGripHovered; + colors[ImGuiCol_ResizeGripActive] = thm.ResizeGripActive; + colors[ImGuiCol_Tab] = thm.Tab; + colors[ImGuiCol_TabHovered] = thm.TabHovered; + colors[ImGuiCol_TabActive] = thm.TabActive; + colors[ImGuiCol_TabUnfocused] = thm.TabUnfocused; + colors[ImGuiCol_TabUnfocusedActive] = thm.TabUnfocusedActive; + colors[ImGuiCol_PlotLines] = thm.PlotLines; + colors[ImGuiCol_PlotLinesHovered] = thm.PlotLinesHovered; + colors[ImGuiCol_PlotHistogram] = thm.PlotHistogram; + colors[ImGuiCol_PlotHistogramHovered] = thm.PlotHistogramHovered; + colors[ImGuiCol_TableHeaderBg] = thm.TableHeaderBg; + colors[ImGuiCol_TableBorderStrong] = thm.TableBorderStrong; + colors[ImGuiCol_TableBorderLight] = thm.TableBorderLight; + colors[ImGuiCol_TableRowBg] = thm.TableRowBg; + colors[ImGuiCol_TableRowBgAlt] = thm.TableRowBgAlt; + colors[ImGuiCol_TextSelectedBg] = thm.TextSelectedBg; + colors[ImGuiCol_DragDropTarget] = thm.DragDropTarget; + colors[ImGuiCol_NavHighlight] = thm.NavHighlight; + colors[ImGuiCol_NavWindowingHighlight] = thm.NavWindowingHighlight; + colors[ImGuiCol_NavWindowingDimBg] = thm.NavWindowingDimBg; + colors[ImGuiCol_ModalWindowDimBg] = thm.ModalWindowDimBg; + + return true; +} + +bool ThemeManager::decodeRGBA(std::string str, uint8_t out[4]) { + if (str[0] != '#' || !std::all_of(str.begin() + 1, str.end(), ::isxdigit) || str.length() != 9) { + return false; + } + out[0] = std::stoi(str.substr(1, 2), NULL, 16); + out[1] = std::stoi(str.substr(3, 2), NULL, 16); + out[2] = std::stoi(str.substr(5, 2), NULL, 16); + out[3] = std::stoi(str.substr(7, 2), NULL, 16); + return true; +} \ No newline at end of file diff --git a/core/src/gui/theme_manager.h b/core/src/gui/theme_manager.h new file mode 100644 index 00000000..41a61599 --- /dev/null +++ b/core/src/gui/theme_manager.h @@ -0,0 +1,77 @@ +#pragma once +#include +#include +#include +#include + +struct Theme { + std::string author; + ImVec4 Text; + ImVec4 TextDisabled; + ImVec4 WindowBg; + ImVec4 ChildBg; + ImVec4 PopupBg; + ImVec4 Border; + ImVec4 BorderShadow; + ImVec4 FrameBg; + ImVec4 FrameBgHovered; + ImVec4 FrameBgActive; + ImVec4 TitleBg; + ImVec4 TitleBgActive; + ImVec4 TitleBgCollapsed; + ImVec4 MenuBarBg; + ImVec4 ScrollbarBg; + ImVec4 ScrollbarGrab; + ImVec4 ScrollbarGrabHovered; + ImVec4 ScrollbarGrabActive; + ImVec4 CheckMark; + ImVec4 SliderGrab; + ImVec4 SliderGrabActive; + ImVec4 Button; + ImVec4 ButtonHovered; + ImVec4 ButtonActive; + ImVec4 Header; + ImVec4 HeaderHovered; + ImVec4 HeaderActive; + ImVec4 Separator; + ImVec4 SeparatorHovered; + ImVec4 SeparatorActive; + ImVec4 ResizeGrip; + ImVec4 ResizeGripHovered; + ImVec4 ResizeGripActive; + ImVec4 Tab; + ImVec4 TabHovered; + ImVec4 TabActive; + ImVec4 TabUnfocused; + ImVec4 TabUnfocusedActive; + ImVec4 PlotLines; + ImVec4 PlotLinesHovered; + ImVec4 PlotHistogram; + ImVec4 PlotHistogramHovered; + ImVec4 TableHeaderBg; + ImVec4 TableBorderStrong; + ImVec4 TableBorderLight; + ImVec4 TableRowBg; + ImVec4 TableRowBgAlt; + ImVec4 TextSelectedBg; + ImVec4 DragDropTarget; + ImVec4 NavHighlight; + ImVec4 NavWindowingHighlight; + ImVec4 NavWindowingDimBg; + ImVec4 ModalWindowDimBg; +}; + +class ThemeManager { +public: + bool loadThemesFromDir(std::string path); + bool loadTheme(std::string path); + bool applyTheme(std::string name); + + std::vector getThemeNames(); + +private: + static bool decodeRGBA(std::string str, uint8_t out[4]); + + std::map themes; + +}; \ No newline at end of file diff --git a/meteor_demodulator/src/main.cpp b/meteor_demodulator/src/main.cpp index f6a5caf0..d99c7465 100644 --- a/meteor_demodulator/src/main.cpp +++ b/meteor_demodulator/src/main.cpp @@ -6,7 +6,7 @@ #include #include #include - +#include #include #include #include @@ -31,6 +31,8 @@ SDRPP_MOD_INFO { /* Max instances */ -1 }; +ConfigManager config; + std::string genFileName(std::string prefix, std::string suffix) { time_t now = time(0); tm *ltm = localtime(&now); @@ -48,6 +50,16 @@ public: writeBuffer = new int8_t[STREAM_BUFFER_SIZE]; + // Load config + config.aquire(); + bool created = false; + if (!config.conf.contains(name)) { + config.conf[name]["recPath"] = "%ROOT%/recordings"; + created = true; + } + folderSelect.setPath(config.conf[name]["recPath"]); + config.release(created); + vfo = sigpath::vfoManager.createVFO(name, ImGui::WaterfallVFO::REF_CENTER, 0, 150000, INPUT_SAMPLE_RATE, 150000, 150000, true); demod.init(vfo->output, INPUT_SAMPLE_RATE, 72000.0f, 32, 0.6f, 0.1f, 0.005f); split.init(demod.out); @@ -112,7 +124,13 @@ private: ImGui::SetNextItemWidth(menuWidth); _this->constDiagram.draw(); - _this->folderSelect.render("##meteor-recorder-" + _this->name); + if (_this->folderSelect.render("##meteor-recorder-" + _this->name)) { + if (_this->folderSelect.pathIsValid()) { + config.aquire(); + config.conf[_this->name]["recPath"] = _this->folderSelect.path; + config.release(true); + } + } if (!_this->folderSelect.pathIsValid() && _this->enabled) { style::beginDisabled(); } @@ -197,7 +215,17 @@ private: }; MOD_EXPORT void _INIT_() { - // Nothing + // Create default recording directory + if (!std::filesystem::exists(options::opts.root + "/recordings")) { + spdlog::warn("Recordings directory does not exist, creating it"); + if (!std::filesystem::create_directory(options::opts.root + "/recordings")) { + spdlog::error("Could not create recordings directory"); + } + } + json def = json({}); + config.setPath(options::opts.root + "/meteor_demodulator_config.json"); + config.load(def); + config.enableAutoSave(); } MOD_EXPORT ModuleManager::Instance* _CREATE_INSTANCE_(std::string name) { @@ -209,5 +237,6 @@ MOD_EXPORT void _DELETE_INSTANCE_(void* instance) { } MOD_EXPORT void _END_() { - // Nothing either + config.disableAutoSave(); + config.save(); } \ No newline at end of file