diff --git a/include/views/view_data_processor.hpp b/include/views/view_data_processor.hpp index fb0d839d5..caadce176 100644 --- a/include/views/view_data_processor.hpp +++ b/include/views/view_data_processor.hpp @@ -37,6 +37,9 @@ namespace hex { void eraseLink(u32 id); void eraseNodes(const std::vector &ids); void processNodes(); + + std::string saveNodes(); + void loadNodes(std::string_view data); }; } \ No newline at end of file diff --git a/plugins/libimhex/include/hex/api/content_registry.hpp b/plugins/libimhex/include/hex/api/content_registry.hpp index 7bd3aff03..27f2850fe 100644 --- a/plugins/libimhex/include/hex/api/content_registry.hpp +++ b/plugins/libimhex/include/hex/api/content_registry.hpp @@ -160,7 +160,13 @@ namespace hex { template T, typename ... Args> static void add(std::string_view unlocalizedCategory, std::string_view unlocalizedName, Args&& ... args) { - add(Entry{ unlocalizedCategory.data(), unlocalizedName.data(), [args...]{ return new T(std::forward(args)...); } }); + add(Entry{ unlocalizedCategory.data(), unlocalizedName.data(), + [args..., name = std::string(unlocalizedName)]{ + auto node = new T(std::forward(args)...); + node->setUnlocalizedName(name); + return node; + } + }); } static void addSeparator(); diff --git a/plugins/libimhex/include/hex/data_processor/attribute.hpp b/plugins/libimhex/include/hex/data_processor/attribute.hpp index 564d76461..59c1d5262 100644 --- a/plugins/libimhex/include/hex/data_processor/attribute.hpp +++ b/plugins/libimhex/include/hex/data_processor/attribute.hpp @@ -16,7 +16,7 @@ namespace hex::dp { In, Out }; - Attribute(IOType ioType, Type type, std::string_view unlocalizedName) : m_id(SharedData::dataProcessorNodeIdCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(unlocalizedName) { + Attribute(IOType ioType, Type type, std::string_view unlocalizedName) : m_id(SharedData::dataProcessorAttrIdCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(unlocalizedName) { } @@ -26,6 +26,8 @@ namespace hex::dp { } [[nodiscard]] u32 getID() const { return this->m_id; } + void setID(u32 id) { this->m_id = id; } + [[nodiscard]] IOType getIOType() const { return this->m_ioType; } [[nodiscard]] Type getType() const { return this->m_type; } [[nodiscard]] std::string_view getUnlocalizedName() const { return this->m_unlocalizedName; } diff --git a/plugins/libimhex/include/hex/data_processor/link.hpp b/plugins/libimhex/include/hex/data_processor/link.hpp index 290282184..d095824f4 100644 --- a/plugins/libimhex/include/hex/data_processor/link.hpp +++ b/plugins/libimhex/include/hex/data_processor/link.hpp @@ -4,9 +4,11 @@ namespace hex::dp { class Link { public: - Link(u32 from, u32 to) : m_id(SharedData::dataProcessorNodeIdCounter++), m_from(from), m_to(to) { } + Link(u32 from, u32 to) : m_id(SharedData::dataProcessorLinkIdCounter++), m_from(from), m_to(to) { } [[nodiscard]] u32 getID() const { return this->m_id; } + void setID(u32 id) { this->m_id = id; } + [[nodiscard]] u32 getFromID() const { return this->m_from; } [[nodiscard]] u32 getToID() const { return this->m_to; } diff --git a/plugins/libimhex/include/hex/data_processor/node.hpp b/plugins/libimhex/include/hex/data_processor/node.hpp index 1fab2b429..a3bf70b28 100644 --- a/plugins/libimhex/include/hex/data_processor/node.hpp +++ b/plugins/libimhex/include/hex/data_processor/node.hpp @@ -9,7 +9,7 @@ namespace hex::dp { class Node { public: - Node(std::string_view unlocalizedName, std::vector attributes) : m_id(SharedData::dataProcessorNodeIdCounter++), m_unlocalizedName(unlocalizedName), m_attributes(std::move(attributes)) { + Node(std::string_view unlocalizedTitle, std::vector attributes) : m_id(SharedData::dataProcessorNodeIdCounter++), m_unlocalizedTitle(unlocalizedTitle), m_attributes(std::move(attributes)) { for (auto &attr : this->m_attributes) attr.setParentNode(this); } @@ -17,7 +17,12 @@ namespace hex::dp { virtual ~Node() = default; [[nodiscard]] u32 getID() const { return this->m_id; } + void setID(u32 id) { this->m_id = id; } + [[nodiscard]] std::string_view getUnlocalizedName() const { return this->m_unlocalizedName; } + void setUnlocalizedName(std::string_view unlocalizedName) { this->m_unlocalizedName = unlocalizedName; } + + [[nodiscard]] std::string_view getUnlocalizedTitle() const { return this->m_unlocalizedTitle; } [[nodiscard]] std::vector& getAttributes() { return this->m_attributes; } void setCurrentOverlay(prv::Overlay *overlay) { @@ -40,7 +45,7 @@ namespace hex::dp { private: u32 m_id; - std::string m_unlocalizedName; + std::string m_unlocalizedTitle, m_unlocalizedName; std::vector m_attributes; std::set m_processedInputs; prv::Overlay *m_overlay = nullptr; diff --git a/plugins/libimhex/include/hex/helpers/shared_data.hpp b/plugins/libimhex/include/hex/helpers/shared_data.hpp index 0cd2b141a..cd4cc03d9 100644 --- a/plugins/libimhex/include/hex/helpers/shared_data.hpp +++ b/plugins/libimhex/include/hex/helpers/shared_data.hpp @@ -71,6 +71,8 @@ namespace hex { static std::vector dataProcessorNodes; static u32 dataProcessorNodeIdCounter; + static u32 dataProcessorLinkIdCounter; + static u32 dataProcessorAttrIdCounter; static std::list recentFilePaths; diff --git a/plugins/libimhex/source/helpers/shared_data.cpp b/plugins/libimhex/source/helpers/shared_data.cpp index 50a2d3fa8..f78249f37 100644 --- a/plugins/libimhex/source/helpers/shared_data.cpp +++ b/plugins/libimhex/source/helpers/shared_data.cpp @@ -25,6 +25,8 @@ namespace hex { std::vector SharedData::dataProcessorNodes; u32 SharedData::dataProcessorNodeIdCounter = 1; + u32 SharedData::dataProcessorLinkIdCounter = 1; + u32 SharedData::dataProcessorAttrIdCounter = 1; std::list SharedData::recentFilePaths; diff --git a/source/views/view_data_processor.cpp b/source/views/view_data_processor.cpp index f8c2ce3d6..f7ac43daa 100644 --- a/source/views/view_data_processor.cpp +++ b/source/views/view_data_processor.cpp @@ -3,6 +3,7 @@ #include #include +#include namespace hex { @@ -252,7 +253,7 @@ namespace hex { imnodes::BeginNode(node->getID()); imnodes::BeginNodeTitleBar(); - ImGui::TextUnformatted(LangEntry(node->getUnlocalizedName())); + ImGui::TextUnformatted(LangEntry(node->getUnlocalizedTitle())); imnodes::EndNodeTitleBar(); node->drawNode(); @@ -367,4 +368,123 @@ namespace hex { } + std::string ViewDataProcessor::saveNodes() { + using json = nlohmann::json; + json output; + + output["nodes"] = json::object(); + for (auto &node : this->m_nodes) { + auto id = node->getID(); + auto &currNodeOutput = output["nodes"][std::to_string(id)]; + auto pos = imnodes::GetNodeGridSpacePos(id); + + currNodeOutput["type"] = node->getUnlocalizedName(); + currNodeOutput["pos"] = { { "x", pos.x }, { "y", pos.y } }; + currNodeOutput["attrs"] = json::array(); + currNodeOutput["id"] = id; + + u32 attrIndex = 0; + for (auto &attr : node->getAttributes()) { + currNodeOutput["attrs"][attrIndex] = attr.getID(); + attrIndex++; + } + } + + output["links"] = json::object(); + for (auto &link : this->m_links) { + auto id = link.getID(); + auto &currOutput = output["links"][std::to_string(id)]; + + currOutput["id"] = id; + currOutput["from"] = link.getFromID(); + currOutput["to"] = link.getToID(); + } + + return output.dump(); + } + + void ViewDataProcessor::loadNodes(std::string_view data) { + using json = nlohmann::json; + + json input = json::parse(data); + + u32 maxId = 0; + + for (auto &node : this->m_nodes) + delete node; + + this->m_nodes.clear(); + this->m_endNodes.clear(); + this->m_links.clear(); + + auto &nodeEntries = ContentRegistry::DataProcessorNode::getEntries(); + for (auto &node : input["nodes"]) { + dp::Node *newNode = nullptr; + for (auto &entry : nodeEntries) { + if (entry.name == node["type"]) + newNode = entry.creatorFunction(); + } + + if (newNode == nullptr) + continue; + + u32 id = node["id"]; + maxId = std::max(id, maxId); + + newNode->setID(id); + + bool hasOutput = false; + bool hasInput = false; + u32 attrIndex = 0; + for (auto &attr : newNode->getAttributes()) { + if (attr.getIOType() == dp::Attribute::IOType::Out) + hasOutput = true; + + if (attr.getIOType() == dp::Attribute::IOType::In) + hasInput = true; + + attr.setID(node["attrs"][attrIndex]); + attrIndex++; + } + + if (hasInput && !hasOutput) + this->m_endNodes.push_back(newNode); + + this->m_nodes.push_back(newNode); + imnodes::SetNodeGridSpacePos(id, ImVec2(node["pos"]["x"], node["pos"]["y"])); + } + + for (auto &link : input["links"]) { + dp::Link newLink(link["from"], link["to"]); + + newLink.setID(link["id"]); + this->m_links.push_back(newLink); + + dp::Attribute *fromAttr, *toAttr; + for (auto &node : this->m_nodes) { + for (auto &attribute : node->getAttributes()) { + if (attribute.getID() == newLink.getFromID()) + fromAttr = &attribute; + else if (attribute.getID() == newLink.getToID()) + toAttr = &attribute; + } + } + + if (fromAttr == nullptr || toAttr == nullptr) + break; + + if (fromAttr->getType() != toAttr->getType()) + break; + + if (fromAttr->getIOType() == toAttr->getIOType()) + break; + + if (!toAttr->getConnectedAttributes().empty()) + break; + + fromAttr->addConnectedAttribute(newLink.getID(), toAttr); + toAttr->addConnectedAttribute(newLink.getID(), fromAttr); + } + } + } \ No newline at end of file