Releases: Azzinoth/VisualNodeSystem
Release list
0.2.0: Sub-Area and Link Nodes
0.2.0: Sub-Area and Link Nodes
The main focus of this update was more mature interaction between node areas, and better integration and management of those areas by the node system manager. Along the way its scope grew to include several additional features and many bug fixes, all covered below.
Main Changes
Sub-area nodes
A sub-area node contains its own, fully self-contained node graph (NodeArea), exposed to the parent graph through dedicated input and output boundary nodes. This lets user collapse a complex portion of a graph into a single, reusable, nestable sub-area node, improving readability and letting user build graphs hierarchically.
Link nodes
Sub-area owns and encapsulates its inner (NodeArea), a link node connects two separate node areas by reference, so several places can share and reference the same graph or to be connected to some node in referenced (NodeArea).
Boundary nodes with mirrored sockets
Sub-area and link nodes share a common boundary (mirror) node base. You can add your own sockets to a boundary node, and each one is automatically mirrored to the matching side of the area boundary, so data and execution signals pass through it between the two node areas. Renaming or changing the type of a socket updates its mirrored counterpart as well, keeping both sides consistent.
NodeSystem is now the central owner of all node areas
Because node areas can now reference one another (through link nodes) and nest inside one another (through sub-areas), an individual node area can still be saved on its own, but doing so drops any connections it had to other areas. To preserve those cross-area connections, NodeSystem is therefore now the single owner and manager of every node area, and the entire system, all areas together with their interconnections, can be saved to and loaded from a single JSON file.
Explicit socket direction and multiple types
Previously, whether a socket was an input or an output was defined by a bool, which was ambiguous and easy to misinterpret at call sites. It is now expressed explicitly through the NodeSocket::SocketFlow enum.
Sockets can also hold multiple allowed types.
Dynamic socket types
A socket's allowed types can now be changed at runtime through NodeSocket::SetAllowedTypes. Existing connections are automatically re-validated after the change, and link nodes react appropriately to keep their mirrored sockets consistent.
Expanded test coverage
A large number of additional test cases were added to cover the new sub-area and link functionality, along with regression tests for the bugs fixed in this release.
Changes
Breaking Changes:
Compatibility:
- Saves produced by previous versions are not compatible with this release and there is currently no automatic migration. If enough feedback indicates it is needed, a migration tool may be added later.
- The library now also depends on
imgui_stdlib.h(Dear ImGui's standard-library helpers frommisc/cpp/). Ensuremisc/cpp/imgui_stdlib.cppfrom your Dear ImGui copy is compiled as part of your project.
Behavioral changes:
std::string NodeSocket::GetType() constwas replaced withstd::vector NodeSocket::GetAllowedTypes() const.- Right-clicking a socket now opens a socket context menu instead of immediately breaking all of that socket's connections. (A “break all connections to/from node” option was added to the context menu.)
NodeArea::GetLastExecutedNodes()now returns nodes in execution order (previously it returned them in reverse execution order).NodeArea::RunOnEachConnectedNodeno longer invokes the callback on the starting node itself.Node::CanConnectno longer allows duplicate connections.NodeArea::TryToConnectnow rejects connections when a node has no parent area, when the two nodes belong to different areas, or when the call is made on an area that does not own the nodes.NodeArea::AddNodeandNodeArea::AddGroupCommentnow reject objects that already belong to an area.NodeSocketnow silently ignores an empty ("") socket type.- Static socket-count checks were removed from deserialization, custom nodes should validate their own socket counts on load.
- The base
Nodecopy constructor no longer copies socket data-getters (they typically capture the source node), each custom node type must reinstall its own getters in its copy constructor.
Lifecycle / ownership:
NodeArea's destructor is now private, and its copy constructor and copy-assignment operator were deleted, areas are managed exclusively throughNODE_SYSTEM.NodeSocket's destructor is now private, delete sockets viaNodeSystem::DeleteSocketorNode::DeleteSocket, not directly.- The static area-management functions (
CreateNodeArea,CopyNodesTo,MoveNodesTo, and similar) were moved offNodeArea(where they previously created unregistered, leaking areas) ontoNODE_SYSTEM.
Renames:
- Renamed
NodeArea::SetMainContextMenuFunctoNodeArea::SetMainContextMenuFunction. - Build flag
VISUAL_NODE_SYSTEM_BUILD_STANDARD_NODESwas renamed toVISUAL_NODE_SYSTEM_BUILD_EXECUTION_FLOW_NODES. - Flag
NODE_WITH_PER_SOCKETwas renamed toNODE_HEIGHT_PER_SOCKET. NodeArea::GetNodesByType(std::string)was renamed toNodeArea::GetNodesByStringType(std::string)(the nameGetNodesByTypeis now a template overload).NodeArea::DeleteNode(const Node*)was renamed toNodeArea::Delete(const Node*).NodeArea::Delete(RerouteNode*)was replaced byNodeArea::DeleteRerouteNodeByID(std::string).- Redundant
NodeArea::DeleteGroupComment(GroupComment*)was removed in favor ofNodeArea::Delete(GroupComment*). NodeArea::SetExecutionEntryNode(std::string)was renamed toNodeArea::SetExecutionEntryNodeByID(std::string).NodeSystem::CopyNodesTowas renamed toNodeSystem::CopyElementsTo(it copies both nodes and group comments).- The
NodeflagbCouldBeDestroyedwas renamed tobCouldBeDestroyedByUser. Node::SetSocketAllowedTypeswas moved toNodeSocket::SetAllowedTypes.SubAreaInputNode::GetParentArea(which shadowedNode::GetParentArea) was renamed toSubAreaInputNode::GetOwningParentArea.
Removals:
- The
VISUAL_NODE_SYSTEM_VERSIONmacro was removed, useNODE_SYSTEM.GetVersion()instead. Node::GetSocketByIDInternalwas removed, useNode::GetSocketByID.
Signature / return-type changes:
- The signature of
Node::FromJsonhas changed fromvirtual void FromJson(Json::Value Json)tovirtual bool FromJson(Json::Value Json), any classes inheriting from Node and overriding FromJson must update their signature and return true on success or false on failure (e.g., validation failure). - Socket-direction
boolparameters were replaced by theNodeSocket::SocketFlowenum across the whole system. Node::AddSocketis now virtual and returnsbool(wasvoid).NodeArea::AddNodenow returnsbool(wasvoid).NodeArea::SaveToFilenow returnsbool(wasvoid).NodeArea::Delete(Connection*)now returnsbool(wasvoid).NodeSystem::MoveNodesTonow returnsbool(wasvoid).GroupComment::FromJsonnow returnsbooland validates its input (wasvoid).NodeArea::AddRerouteNodeToConnectionnow returnsRerouteNode*(wasbool).NodeAreacallbacks now takestd::functioninstead of raw function pointers (for better lambda support).
Bug Fixes (selected):
GroupComment::SetPositionnow correctly moves attached nodes, previously, only non-programmatic(mouse-drag) movement worked as expected.- Loading a saved graph could crash or silently drop nodes and group comments (they were read by position rather than by name). Loading now reads members by their real names, validates the JSON, and clears any existing data first; many invalid-JSON edge cases were hardened.
- Fixed numerous crashes and memory leaks around copy, paste, cut, delete, and moving nodes between areas, including a double-free triggered by the
...
v0.1.0
0.1.0: Test Branch and Various Small Refactorings
In this update, I mainly focused on creating a base for continuous integration. I decided not to include the gtest library and tests themselves in the master branch to keep it lightweight. Instead, I created a tests branch to house all the necessary code and used GitHub Actions to ensure CI is properly utilized. The test cases included do not provide full coverage, but they helped me spot a few bugs.
Changes
Bug Fixes:
NodeArea::Clear()was not clearingGroupComments.std::vector<Node*> Node::GetNodesConnectedToOutput()was returning multiple copies of the same node if that node was connected through multiple sockets.
Breaking Changes:
- Renamed function
size_t Node::InputSocketCounttosize_t Node::GetInputSocketCountto better describe its functionality. - Renamed function
size_t Node::OutSocketCounttosize_t Node::GetOutputSocketCountto better describe its functionality. - Made
static void NodeArea::CopyNodesInternal,static bool NodeArea::IsAlreadyConnected, andstatic void NodeArea::ProcessConnectionsfunctions private. - Renamed
static bool NodeArea::EmptyOrFilledByNullstostatic bool NodeArea::IsEmptyOrFilledByNullsand made it private. - Renamed and moved
static bool NodeArea::IsNodeIDInListtostatic bool Node::IsNodeWithIDInList. - Transformed
static NodeArea* NodeArea::FromJson(std::string JsonText)tovoid NodeArea::LoadFromJson(std::string JsonText)to make it more clear when to use the function. This also helped to rewrite loading from a file to avoid node copying, as the previous implementation was inefficient due to legacy issues. - Renamed
NodeArea::SetNodeEventCallbacktoNodeArea::AddNodeEventCallbackto better reflect its functionality and shifted from accepting raw function pointers to acceptingstd::functionfor better support of lambdas.
Other Changes:
- Added
size_t NodeArea::GetGroupCommentCountfunction. - Changed the return type of the
NodeArea::GetNodeCountfunction frominttosize_t. - Added
bool Node::CouldBeDestroyedfunction. - Added
Node* NodeArea::GetNodeByIDfunction. - Added
GroupComment* NodeArea::GetGroupCommentByID(std::string GroupCommentID)andstd::vector<GroupComment*> NodeArea::GetGroupCommentsByName(std::string GroupCommentName)functions. - Added
std::vector<Node*> NodeArea::GetNodesInGroupComment(GroupComment* GroupCommentToCheck),std::vector<RerouteNode*> NodeArea::GetRerouteNodesInGroupComment(GroupComment* GroupCommentToCheck), andstd::vector<GroupComment*> NodeArea::GetGroupCommentsInGroupComment(GroupComment* GroupCommentToCheck)functions. - Added
bool NodeArea::TryToDisconnect(const Node* OutNode, size_t OutNodeSocketIndex, const Node* InNode, size_t InNodeSocketIndex),bool NodeArea::TryToDisconnect(const Node* OutNode, std::string OutSocketID, const Node* InNode, std::string InSocketID),bool NodeArea::IsConnected(const Node* OutNode, size_t OutNodeSocketIndex, const Node* InNode, size_t InNodeSocketIndex), andbool NodeArea::IsConnected(const Node* OutNode, std::string OutSocketID, const Node* InNode, std::string InSocketID)functions to improve work with connections.