17#include <imgui_node_editor.h>
46bool unsavedChanges =
false;
48constexpr int loadingFramesToWait = 2;
50std::string currentFilename;
51std::filesystem::path programRootPath;
54size_t currentRotatedParentFolderNumber;
65 if (currentFilename.empty())
77 std::ofstream filestream(filepath);
79 if (!filestream.good())
81 std::cerr <<
"Save Flow error: Could not open file: " << filepath;
88 j[
"nodes"][
"node-" + std::to_string(
size_t(node->id))] = *node;
89 j[
"nodes"][
"node-" + std::to_string(
size_t(node->id))][
"data"] = node->save();
91 for (
const auto& outputPin : node->outputPins)
93 for (
const auto& link : outputPin.links)
95 auto& jLink = j[
"links"][
"link-" + std::to_string(
size_t(link.linkId))];
96 jLink[
"id"] = size_t(link.linkId);
97 jLink[
"startPinId"] = size_t(outputPin.id);
98 jLink[
"endPinId"] = size_t(link.connectedPinId);
104 j[
"implot"][
"style"] = ImPlot::GetStyle();
108 j[
"fonts"][
"useBigDefaultFont"] = gui::NodeEditorApplication::isUsingBigDefaultFont();
109 j[
"fonts"][
"useBigWindowFont"] = gui::NodeEditorApplication::isUsingBigWindowFont();
110 j[
"fonts"][
"useBigPanelFont"] = gui::NodeEditorApplication::isUsingBigPanelFont();
111 j[
"fonts"][
"useBigMonoFont"] = gui::NodeEditorApplication::isUsingBigMonoFont();
118 j[
"gridLinesEnabled"] = ed::GetStyle().Colors[ed::StyleColor_Grid].w;
119 j[
"transparentWindows"] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w;
130 filestream << std::setw(4) << j << std::endl;
132 unsavedChanges =
false;
137 LOG_TRACE(
"called for path {}", filepath);
138 bool loadSuccessful =
true;
142 std::ifstream filestream(filepath);
144 if (!filestream.good())
146 LOG_ERROR(
"Load Flow error: Could not open file: {}", filepath);
163 nm::CallPreInitCallback();
172 loadSuccessful =
false;
185 unsavedChanges =
false;
187 currentFilename = filepath;
195 std::string path = filepath;
199 if (path.starts_with(
'\\') || path.starts_with(
'/')) { path = path.substr(1); }
202 LOG_INFO(
"Loaded flow file: {}", path);
204 catch (
const std::exception& e)
206 LOG_ERROR(
"Loading flow file failed with error: {}", e.what());
207 loadSuccessful =
false;
210 return loadSuccessful;
215 bool loadSuccessful =
true;
217 if (j.contains(
"implot"))
221 if (j.at(
"implot").contains(
"prefereFlowOverGlobal"))
228 inputPath.is_relative())
230 filepath /= inputPath;
234 filepath = inputPath;
241 if (j.at(
"implot").contains(
"style"))
243 j.at(
"implot").at(
"style").get_to(ImPlot::GetStyle());
253 if (j.contains(
"colormaps"))
265 if (j.contains(
"fonts"))
267 if (j.at(
"fonts").contains(
"useBigDefaultFont"))
269 gui::NodeEditorApplication::swapDefaultFont(j.at(
"fonts").at(
"useBigDefaultFont").get<
bool>());
271 if (j.at(
"fonts").contains(
"useBigWindowFont"))
273 gui::NodeEditorApplication::swapWindowFont(j.at(
"fonts").at(
"useBigWindowFont").get<
bool>());
275 if (j.at(
"fonts").contains(
"useBigPanelFont"))
277 gui::NodeEditorApplication::swapPanelFont(j.at(
"fonts").at(
"useBigPanelFont").get<
bool>());
279 if (j.at(
"fonts").contains(
"useBigMonoFont"))
281 gui::NodeEditorApplication::swapMonoFont(j.at(
"fonts").at(
"useBigMonoFont").get<
bool>());
284 if (j.contains(
"leftPane"))
292 if (j.contains(
"lightMode"))
297 if (j.contains(
"gridLinesEnabled")) { j.at(
"gridLinesEnabled").get_to(ed::GetStyle().Colors[ed::StyleColor_Grid].w); }
298 if (j.contains(
"transparentWindows")) { j.at(
"transparentWindows").get_to(ImGui::GetStyle().Colors[ImGuiCol_WindowBg].w); }
301 if (j.contains(
"nodes"))
303 for (
const auto& nodeJson : j.at(
"nodes"))
305 if (!nodeJson.contains(
"type"))
307 LOG_ERROR(
"Node does not contain a type");
310 Node* node =
nullptr;
313 for (
const auto& nodeInfo : registeredNode.second)
315 if (nodeInfo.type == nodeJson.at(
"type").get<std::string>())
317 node = nodeInfo.constructor();
328 LOG_ERROR(
"Node type ({}) is not a valid type.", nodeJson.at(
"type").get<std::string>());
329 loadSuccessful =
false;
334 auto newNodeId = node->
id;
336 nodeJson.get_to<
Node>(*node);
337 if (nodeJson.contains(
"data"))
339 node->
restore(nodeJson.at(
"data"));
342 nodeJson.get_to<
Node>(*node);
346 node->
id = newNodeId;
361 ed::SetNodePosition(node->
id, nodeJson.at(
"pos").get<ImVec2>());
365 ed::SetGroupSize(node->
id, node->
getSize());
372 std::set<Node*> newlyLinkedNodes;
374 if (j.contains(
"links"))
376 for (
size_t i = 0; i < 2; i++)
378 for (
const auto& linkJson : j.at(
"links"))
380 auto linkId = linkJson.at(
"id").get<
size_t>();
381 auto startPinId = linkJson.at(
"startPinId").get<
size_t>();
382 auto endPinId = linkJson.at(
"endPinId").get<
size_t>();
390 for (
auto& inputPin : node->inputPins)
392 if (endPinId ==
size_t(inputPin.id)) { endPin = &inputPin; }
397 for (
auto& outputPin : node->outputPins)
399 if (startPinId ==
size_t(outputPin.id)) { startPin = &outputPin; }
402 if (startPin && endPin) {
break; }
404 if (startPin && endPin)
408 loadSuccessful =
false;
411 newlyLinkedNodes.insert(startPin->
parentNode);
412 newlyLinkedNodes.insert(endPin->parentNode);
417 if (j.contains(
"nodes"))
419 for (
auto* node : newlyLinkedNodes)
421 if (j.at(
"nodes").contains(
"node-" + std::to_string(
size_t(node->id))))
423 LOG_DEBUG(
"Calling restoreAtferLink() for new node '{}'", node->nameId());
425 const auto& nodeJson = j.at(
"nodes").at(
"node-" + std::to_string(
size_t(node->id)));
426 if (nodeJson.contains(
"data"))
428 node->restoreAtferLink(nodeJson.at(
"data"));
434 return loadSuccessful;
439 return unsavedChanges;
445 if (ImGui::GetCurrentContext() && ImGui::GetFrameCount() -
loadingFrameCount >= loadingFramesToWait)
447 unsavedChanges =
true;
457 unsavedChanges =
false;
462 return currentFilename;
467 currentFilename = newFilename;
472 return programRootPath;
477 LOG_DEBUG(
"Program root path set to {}", newRootPath);
478 programRootPath = newRootPath;
486 outputPath.is_relative())
488 filepath /= outputPath;
492 filepath = outputPath;
497 filepath /= fmt::format(
"{:04d}", currentRotatedParentFolderNumber);
505 currentRotatedParentFolderNumber = 0;
506 for (
int i = 10000; i >= 0; --i)
508 std::filesystem::path outputDir{ programRootPath };
511 outputPath.is_relative())
513 outputDir /= outputPath;
517 outputDir = outputPath;
519 outputDir /= fmt::format(
"{:04d}", i);
520 if (std::filesystem::exists(outputDir))
522 currentRotatedParentFolderNumber =
static_cast<size_t>(i + 1);
534 inputPath.is_relative())
536 filepath /= inputPath;
540 filepath = inputPath;
551 inputPath.is_relative())
553 filepath /= inputPath;
557 filepath = inputPath;
Common logging variables like time into run and local positions.
Config management for the Project.
nlohmann::json json
json namespace
GlobalActions
Possible Global Actions to perform in the GUI.
@ SaveAs
Save the flow as filename.
ImPlot style editor window.
Defines how to save certain datatypes to json.
#define LOG_DEBUG
Debug information. Should not be called on functions which receive observations (spamming)
#define LOG_ERROR
Error occurred, which stops part of the program to work, but not everything.
#define LOG_INFO
Info to the user on the state of the program.
#define LOG_TRACE
Detailled info to trace the execution of the program. Should not be called on functions which receive...
Utility class which specifies available nodes.
static void restore(const json &j)
Read info from a json object.
static json save()
Returns a json object of the common log.
Abstract parent class for all nodes.
virtual void restore(const json &j)
Restores the node from a json object.
const ImVec2 & getSize() const
Get the size of the node.
std::vector< OutputPin > outputPins
List of output pins.
std::vector< InputPin > inputPins
List of input pins.
ax::NodeEditor::NodeId id
Unique Id of the Node.
bool createLink(InputPin &endPin, ax::NodeEditor::LinkId linkId=0)
Creates a link from this pin to another, calling all node specific callbacks.
Node * parentNode
Reference to the parent node.
static float bottomViewHeight
Height of the log viewer.
static float leftPaneWidth
Width of the left pane.
static std::vector< ImVec4 > m_colors
Color settings.
static bool hideLeftPane
Hide left pane.
static float rightPaneWidth
Width of the right pane.
static bool hideFPS
Hide FPS counter.
const T & Get(const std::string &key, const T &&defaultValue)
Retrieves the value of a corresponding key from the configuration, if one exists.
bool isRunning() noexcept
Checks if the thread is running.
void stop()
Stops the Thread.
void InitializeAllNodesAsync()
Initializes all nodes in a separate thread.
void UpdateNode(Node *node)
Update the provided node object.
bool InitializeAllNodes()
Initializes all nodes.
void DeleteAllNodes()
Delete all nodes.
const std::vector< Node * > & m_Nodes()
List of all registered Nodes.
void AddNode(Node *node)
Add the provided node object to the list of nodes.
ax::NodeEditor::PinId GetNextPinId()
Generates a new pin id.
const std::map< std::string, std::vector< NodeInfo > > & RegisteredNodes()
Reference to List of all registered Nodes.
bool saveLastActions
Whether actions should be saved to the last actions list.
void SetProgramRootPath(const std::filesystem::path &newRootPath)
Set the program root path.
bool LoadJson(const json &j, bool requestNewIds=false)
Loads the nodes and links from the specified json object.
void SetCurrentFilename(const std::string &newFilename)
Set the current filename of the open flow.
bool LoadFlow(const std::string &filepath)
Loads the flow from the specified file.
int loadingFrameCount
Frame Count when changes were loaded to prevent nodes moving from triggering unsaved changes.
std::filesystem::path GetConfigPath()
Get the path where config files are searched.
std::filesystem::path GetOutputPath()
Get the path where logs and outputs are stored.
void SaveFlowAs(const std::string &filepath)
Saves the current flow into the specified file.
std::filesystem::path GetInputPath()
Get the path where data files are searched.
void DiscardChanges()
Discards the unsaved changes flag. Does not really discard the changes.
std::string GetCurrentFilename()
Get the current filename of the open flow.
void ApplyChanges()
Signals that there have been changes to the flow.
std::filesystem::path GetFlowPath()
Get the path where flow files are searched.
std::filesystem::path GetProgramRootPath()
Get the program root path.
bool HasUnsavedChanges()
Checks if the currently open flow has unsaved changes.
void SaveFlow(GlobalActions &globalAction)
Saves the current flow into a file.
void SetOutputPath()
Set the path where logs and outputs are stored.
void ApplyDarkLightMode(std::vector< ImVec4 > &colors)
bool prefereFlowOverGlobal
If true, the ImPlot config from the flow file will be preferred over the global settings file.
bool nodeEditorLightMode
If true, light mode is selected.
bool saveConfigInFlow
If true, the ImPlot config will be saved into the flow file.
void clearLastActionList()
Clears the list of last actions.
void saveLastAction()
Saves the last action to the action list.
std::vector< Colormap > ColormapsFlow
Flow colormaps.