2025-03-09 10:16:40 +01:00
|
|
|
#include "dsp_flowgraph_handler.h"
|
2026-01-25 10:24:19 +01:00
|
|
|
#include "common/widgets/menuitem_tooltip.h"
|
2026-01-14 17:16:33 +01:00
|
|
|
#include "core/backend.h"
|
2026-01-16 18:16:43 +01:00
|
|
|
#include "dsp/flowgraph/dsp_flowgraph_register.h"
|
2026-01-14 17:16:33 +01:00
|
|
|
#include "imgui/imgui.h"
|
2026-01-24 00:04:14 +01:00
|
|
|
#include "imgui/imgui_flags.h"
|
2025-03-09 10:16:40 +01:00
|
|
|
#include "imgui/imnodes/imnodes.h"
|
|
|
|
|
#include "logger.h"
|
|
|
|
|
#include "nlohmann/json_utils.h"
|
2025-06-06 08:12:02 +02:00
|
|
|
#include <complex.h>
|
2025-04-15 19:06:12 +01:00
|
|
|
|
2025-03-09 10:16:40 +01:00
|
|
|
namespace satdump
|
|
|
|
|
{
|
2025-05-19 22:26:32 +02:00
|
|
|
namespace handlers
|
2025-03-09 10:16:40 +01:00
|
|
|
{
|
2026-01-22 19:11:05 +01:00
|
|
|
DSPFlowGraphHandler::DSPFlowGraphHandler(std::string file)
|
2025-03-09 10:16:40 +01:00
|
|
|
{
|
2025-05-04 17:27:35 +02:00
|
|
|
handler_tree_icon = u8"\uf92f";
|
2025-03-09 10:16:40 +01:00
|
|
|
|
2026-03-10 18:04:18 +01:00
|
|
|
ndsp::flowgraph::registerNodesInFlowgraph(flowgraph);
|
2026-01-22 19:11:05 +01:00
|
|
|
|
|
|
|
|
if (file != "")
|
|
|
|
|
flowgraph.setJSON(loadCborFile(file));
|
|
|
|
|
current_file = file;
|
2025-03-09 10:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DSPFlowGraphHandler::~DSPFlowGraphHandler()
|
|
|
|
|
{
|
|
|
|
|
if (flow_thread.joinable())
|
|
|
|
|
flow_thread.join();
|
2026-01-24 15:51:27 +01:00
|
|
|
|
|
|
|
|
if (imnode_ctx != nullptr)
|
|
|
|
|
ImNodes::DestroyContext(imnode_ctx);
|
2025-03-09 10:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DSPFlowGraphHandler::drawMenu()
|
|
|
|
|
{
|
2026-03-10 18:04:18 +01:00
|
|
|
bool running = flowgraph.isRunning();
|
2025-03-09 10:16:40 +01:00
|
|
|
|
2026-03-11 11:03:20 +01:00
|
|
|
if (ImGui::CollapsingHeader("Flowgraph"))
|
|
|
|
|
{
|
|
|
|
|
ImGui::Checkbox("Debug Mode", &flowgraph.debug_mode);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-09 20:21:34 +01:00
|
|
|
if (ImGui::CollapsingHeader("Variables", ImGuiTreeNodeFlags_DefaultOpen))
|
2025-03-09 10:16:40 +01:00
|
|
|
{
|
2026-01-19 20:35:21 +01:00
|
|
|
for (auto &v : flowgraph.variables)
|
|
|
|
|
{
|
2026-03-10 22:16:41 +01:00
|
|
|
ImGui::SeparatorText(v.first.c_str());
|
2026-01-19 20:35:21 +01:00
|
|
|
ImGui::InputDouble(std::string("##" + v.first).c_str(), &v.second);
|
2026-03-10 22:16:41 +01:00
|
|
|
ImGui::SameLine();
|
|
|
|
|
|
|
|
|
|
if (ImGui::Button(("Delete##" + v.first).c_str()))
|
|
|
|
|
{
|
|
|
|
|
flowgraph.variables.erase(v.first);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2026-01-19 20:35:21 +01:00
|
|
|
}
|
|
|
|
|
|
2026-03-09 20:21:34 +01:00
|
|
|
if (running)
|
|
|
|
|
style::beginDisabled();
|
|
|
|
|
|
2026-03-10 22:16:41 +01:00
|
|
|
if (flowgraph.variables.size())
|
|
|
|
|
ImGui::SeparatorText("Add/Update");
|
|
|
|
|
|
2026-01-19 20:35:21 +01:00
|
|
|
ImGui::InputText("##addvarname", &to_add_var_name);
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
|
if (ImGui::Button("Add##addnewvariable") && to_add_var_name.size())
|
|
|
|
|
{
|
|
|
|
|
flowgraph.variables.emplace(to_add_var_name, 0);
|
|
|
|
|
to_add_var_name.clear();
|
|
|
|
|
}
|
2025-03-09 10:16:40 +01:00
|
|
|
|
|
|
|
|
if (running)
|
|
|
|
|
style::endDisabled();
|
2026-03-09 20:21:34 +01:00
|
|
|
|
|
|
|
|
if (ImGui::Button("Update"))
|
|
|
|
|
flowgraph.updateVars();
|
2025-03-09 10:16:40 +01:00
|
|
|
}
|
2026-01-29 23:10:31 +01:00
|
|
|
|
2026-03-11 11:03:20 +01:00
|
|
|
if (ImGui::CollapsingHeader("Blocks"))
|
2026-01-29 23:10:31 +01:00
|
|
|
{
|
2026-03-11 19:36:24 +01:00
|
|
|
ImGui::SetNextItemWidth(ImGui::GetWindowSize().x);
|
|
|
|
|
ImGui::InputTextWithHint("##SearchBlocks", "Search Blocks", &node_search);
|
|
|
|
|
flowgraph.renderAddMenuList(node_search);
|
2026-01-29 23:10:31 +01:00
|
|
|
}
|
2025-03-09 10:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
2026-01-14 17:16:33 +01:00
|
|
|
void DSPFlowGraphHandler::drawMenuBar()
|
|
|
|
|
{
|
2026-03-10 18:04:18 +01:00
|
|
|
bool running = flowgraph.isRunning();
|
2026-01-23 17:56:57 +01:00
|
|
|
|
|
|
|
|
if (running)
|
|
|
|
|
{
|
2026-03-04 08:05:13 +01:00
|
|
|
if (widgets::MenuItemTooltip(u8"\ufc62", "Stop flowgraph"))
|
2026-01-23 17:56:57 +01:00
|
|
|
flowgraph.stop();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2026-03-04 08:05:13 +01:00
|
|
|
if (widgets::MenuItemTooltip(u8"\uf909", "Start flowgraph"))
|
2026-01-23 17:56:57 +01:00
|
|
|
{
|
|
|
|
|
if (flow_thread.joinable())
|
|
|
|
|
flow_thread.join();
|
|
|
|
|
auto fun = [&]() { flowgraph.run(); };
|
|
|
|
|
flow_thread = std::thread(fun);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-23 17:31:19 +01:00
|
|
|
bool is_save_as = false;
|
2026-03-04 08:05:13 +01:00
|
|
|
if (widgets::MenuItemTooltip(u8"\ueb4b", "Save file", NULL, false, current_file != "") || //
|
|
|
|
|
(is_save_as = widgets::MenuItemTooltip(u8"\ueb4a", "Save file as")) || //
|
2026-01-23 17:31:19 +01:00
|
|
|
(ImGui::IsKeyDown(ImGuiKey_ReservedForModCtrl) && ImGui::IsKeyPressed(ImGuiKey_S)))
|
2026-01-14 17:16:33 +01:00
|
|
|
{
|
2026-03-09 20:21:34 +01:00
|
|
|
if (current_file == "")
|
|
|
|
|
is_save_as = true;
|
|
|
|
|
|
2026-01-23 17:31:19 +01:00
|
|
|
auto fun = [this, is_save_as]()
|
2026-01-14 17:16:33 +01:00
|
|
|
{
|
2026-01-23 17:31:19 +01:00
|
|
|
std::string save_at = is_save_as ? backend::saveFileDialog({{"SatDump DSP Flowgraph", "satdump_dsp_flowgraph"}}, "", "flowgraph.satdump_dsp_flowgraph") : current_file;
|
2026-01-14 17:16:33 +01:00
|
|
|
|
2026-01-22 19:11:05 +01:00
|
|
|
logger->info("Saving flowgraph : " + save_at);
|
2026-01-14 17:16:33 +01:00
|
|
|
if (save_at == "")
|
|
|
|
|
return;
|
|
|
|
|
|
2026-01-22 19:11:05 +01:00
|
|
|
saveCborFile(save_at, flowgraph.getJSON());
|
2026-01-23 17:31:19 +01:00
|
|
|
current_file = save_at;
|
2026-01-14 17:16:33 +01:00
|
|
|
};
|
|
|
|
|
tq.push(fun);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-04 08:05:13 +01:00
|
|
|
if (widgets::MenuItemTooltip(u8"\uea7f", "Load a file"))
|
2026-01-14 17:16:33 +01:00
|
|
|
{
|
|
|
|
|
auto fun = [this]()
|
|
|
|
|
{
|
2026-01-22 19:11:05 +01:00
|
|
|
std::string load_at = backend::selectFileDialog({{"SatDump DSP Flowgraph", "satdump_dsp_flowgraph"}}, "");
|
2026-01-14 17:16:33 +01:00
|
|
|
|
2026-01-20 13:08:46 +01:00
|
|
|
logger->info("Loading flowgraph : " + load_at);
|
2026-01-14 17:16:33 +01:00
|
|
|
if (load_at == "")
|
|
|
|
|
return;
|
|
|
|
|
|
2026-01-22 19:11:05 +01:00
|
|
|
flowgraph.setJSON(loadCborFile(load_at));
|
2026-01-14 17:16:33 +01:00
|
|
|
};
|
|
|
|
|
tq.push(fun);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-24 00:04:14 +01:00
|
|
|
void DSPFlowGraphHandler::drawContents(ImVec2 win_size)
|
|
|
|
|
{
|
2026-01-24 15:51:27 +01:00
|
|
|
if (imnode_ctx == nullptr)
|
|
|
|
|
imnode_ctx = ImNodes::CreateContext();
|
|
|
|
|
ImNodes::SetCurrentContext(imnode_ctx);
|
|
|
|
|
|
2026-01-24 00:04:14 +01:00
|
|
|
ctx.config().color = ImGui::GetColorU32(ImGuiCol_WindowBg);
|
|
|
|
|
|
|
|
|
|
ctx.begin();
|
|
|
|
|
|
|
|
|
|
float f = 15;
|
|
|
|
|
ImGui::SetNextWindowPos({-f / ctx.scale(), -f / ctx.scale()});
|
|
|
|
|
ImGui::SetNextWindowSize({(float)(win_size.x / ctx.scale()) + 2 * (f / ctx.scale()), (float)(win_size.y / ctx.scale()) + 2 * (f / ctx.scale())});
|
2026-03-02 22:28:31 +01:00
|
|
|
ImGui::Begin("FlowGraph", nullptr, NOWINDOW_FLAGS | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoScrollWithMouse);
|
2026-01-24 00:04:14 +01:00
|
|
|
flowgraph.render();
|
|
|
|
|
ImGui::End();
|
|
|
|
|
|
|
|
|
|
ctx.end();
|
2026-03-09 20:21:34 +01:00
|
|
|
|
2026-03-10 18:04:18 +01:00
|
|
|
flowgraph.renderWindows();
|
2026-01-24 00:04:14 +01:00
|
|
|
}
|
2025-05-19 22:26:32 +02:00
|
|
|
} // namespace handlers
|
2026-01-19 20:35:21 +01:00
|
|
|
} // namespace satdump
|