This commit is contained in:
2022-07-05 22:15:43 +02:00
commit a616970ce2
27 changed files with 55257 additions and 0 deletions

269
ImguiNodes/ImguiNodes.cpp Normal file
View File

@@ -0,0 +1,269 @@
//Disables console window
#if !_DEBUG
#pragma comment(linker, "/SUBSYSTEM:windows /ENTRY:mainCRTStartup")
#endif
#include <iostream>
#include <algorithm>
#include "ImguiBase.h"
#include "ImguiNodes.h"
int main()
{
CustomDrawData customDrawData{};
startImgui(&customDrawData, init, draw);
}
/// <summary>
/// Setup before first draw.
/// </summary>
void init()
{
ImGuiIO& io = ImGui::GetIO();
io.Fonts->AddFontFromFileTTF("Montserrat-Regular.ttf", 16.0f);
}
/// <summary>
/// Draw main application content.
/// </summary>
void draw(DrawData& drawData, void* customDataVoid)
{
CustomDrawData* customData = static_cast<CustomDrawData*>(customDataVoid);
bool isDraggingLine = false;
ImVec2 lineStartPos = ImVec2{};
// Top menu bar
ImGui::BeginMainMenuBar();
if (ImGui::Button("Add Node"))
{
std::string name{ "Node " };
name.append(std::to_string(customData->nodes.size() + 1));
customData->nodes.push_back(NodeWindow(name));
}
ImGui::EndMainMenuBar();
// Draw all node windows
auto nodeIterator = customData->nodes.begin();
while (nodeIterator != customData->nodes.end())
{
NodeWindow& node = *nodeIterator;
bool nodeOpen;
ImGui::Begin(node.title.c_str(), &nodeOpen, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize);
if (!nodeOpen)
{
auto triggerIterator = node.triggers.begin();
while (triggerIterator != node.triggers.end())
{
triggerIterator = cleanEraseElement(node.triggers, triggerIterator, customData);
}
auto alertIterator = node.alerts.begin();
while (alertIterator != node.alerts.end())
{
alertIterator = cleanEraseElement(node.alerts, alertIterator, customData);
}
nodeIterator = customData->nodes.erase(nodeIterator);
ImGui::End();
break; // TODO: contine will create problems with closing too many windows?
}
// Expand clip rect to allow circles on edges
ImVec2 contentMin = ImGui::GetWindowPos();
ImVec2 contentMax = ImVec2{ contentMin.x + ImGui::GetWindowWidth(), contentMin.y + ImGui::GetWindowHeight() };
ImGui::PushClipRect(ImVec2{ contentMin.x - 15, contentMin.y }, ImVec2{ contentMax.x + 15, contentMax.y }, false);
auto alertIterator = node.alerts.begin();
while (alertIterator != node.alerts.end())
{
if (drawCircle(0, CircleDragType::Source, alertIterator._Ptr, &alertIterator->position))
{
isDraggingLine = true;
lineStartPos = alertIterator->position;
ImGui::Text(alertIterator->name.c_str());
ConnectionPayload payload{ alertIterator->id };
ImGui::SetDragDropPayload("NODE_CONNECTION", (void*)&payload, sizeof(ConnectionPayload));
ImGui::EndDragDropSource();
}
ImGui::Text(alertIterator->name.c_str());
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
{
if (inlineButton("x", alertIterator._Ptr))
{
alertIterator = cleanEraseElement(node.alerts, alertIterator, customData);
continue;
}
}
alertIterator++;
}
auto triggerIterator = node.triggers.begin();
while (triggerIterator != node.triggers.end())
{
if (drawCircle(-ImGui::GetStyle().WindowPadding.x, CircleDragType::Target, triggerIterator._Ptr, &triggerIterator->position))
{
if (const ImGuiPayload* payload = ImGui::AcceptDragDropPayload("NODE_CONNECTION"))
{
ConnectionPayload* payloadData = static_cast<ConnectionPayload*>(payload->Data);
customData->connections.push_back(NodeConnection { payloadData->sourceID, triggerIterator->id });
}
ImGui::EndDragDropTarget();
}
ImGui::Text(triggerIterator->name.c_str());
if (ImGui::IsWindowHovered() || ImGui::IsWindowFocused())
{
if (inlineButton("x", triggerIterator._Ptr))
{
triggerIterator = cleanEraseElement(node.triggers, triggerIterator, customData);
continue;
}
}
triggerIterator++;
}
if (ImGui::Button("New Alert"))
{
node.alerts.push_back(NodeElement("Today, 18:00"));
}
if (ImGui::Button("New Trigger"))
{
node.triggers.push_back(NodeElement("Doot"));
}
ImGui::PopClipRect();
ImGui::End();
nodeIterator++;
}
// Draw drag line in foreground
if (isDraggingLine)
{
ImDrawList* drawList = ImGui::GetForegroundDrawList();
drawList->AddLine(lineStartPos, ImGui::GetMousePos(), IM_COL32(200, 200, 200, 255), 3.0f);
}
// Draw connected lines in background
ImDrawList* bgDrawList = ImGui::GetBackgroundDrawList();
for (NodeConnection& nodeConnection : customData->connections)
{
ImVec2 sourcePos = ImVec2{ 0, 0 };
ImVec2 targetPos = ImVec2{ 0, 0 };
for (auto node : customData->nodes)
{
for (auto alert : node.alerts)
{
if (alert.id == nodeConnection.sourceID)
{
targetPos = alert.position;
}
}
for (auto trigger : node.triggers)
{
if (trigger.id == nodeConnection.targetID)
{
sourcePos = trigger.position;
}
}
}
bgDrawList->AddLine(sourcePos, targetPos, IM_COL32_WHITE, 2.0f);
}
}
/// <summary>
/// Draws a small circle in the same row.
/// </summary>
/// <param name="outCirclePos">Returns the position of the circle.</param>
/// <returns>True if an event matching the dragType has occurred.</returns>
bool drawCircle(float xOffset, CircleDragType dragType, const void* id, ImVec2* outCirclePos)
{
auto cursor = ImGui::GetCursorScreenPos();
ImDrawList* drawList = ImGui::GetWindowDrawList();
float circleRadius = 5;
float yCircleOffset = ImGui::GetTextLineHeight() / 2.;
ImVec2 circlePos = ImVec2{ cursor.x + xOffset, cursor.y + yCircleOffset };
drawList->AddCircleFilled(circlePos, 5, IM_COL32_WHITE);
ImVec2 originalPos = ImGui::GetCursorPos();
ImGui::SetCursorPosX(xOffset);
ImGui::PushID(id);
ImGui::InvisibleButton("", ImVec2{ 15, 15 });
ImGui::PopID();
ImGui::SetCursorPos(originalPos);
if (outCirclePos != nullptr)
{
*outCirclePos = circlePos;
}
if (dragType == CircleDragType::Source && ImGui::BeginDragDropSource())
{
return true;
}
if (dragType == CircleDragType::Target && ImGui::BeginDragDropTarget())
{
return true;
}
return false;
}
/// <summary>
/// Draws a small button in the same row.
/// </summary>
bool inlineButton(const char* title, const void* id)
{
ImGui::SameLine();
ImGui::PushID(id);
if (ImGui::SmallButton(title))
{
ImGui::PopID();
return true;
}
else
{
ImGui::PopID();
return false;
}
}
/// <summary>
/// Removes any attached connections before erasing this NodeElement from a vector.
/// </summary>
/// <returns>Continued iterator</returns>
std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& elements, std::vector<NodeElement>::iterator toErase, CustomDrawData* data)
{
auto connectionIterator = data->connections.begin();
while (connectionIterator != data->connections.end())
{
if (connectionIterator->sourceID == toErase->id || connectionIterator->targetID == toErase->id)
{
connectionIterator = data->connections.erase(connectionIterator);
continue;
}
connectionIterator++;
}
return elements.erase(toErase);
}
NodeElement::NodeElement(std::string name)
{
this->id = nodeIdCounter;
nodeIdCounter++;
this->name = name;
this->position = ImVec2{ 0, 0 };
}
NodeWindow::NodeWindow(std::string title)
{
this->title = title;
this->alerts = std::vector<NodeElement>();
this->triggers = std::vector<NodeElement>();
}

51
ImguiNodes/ImguiNodes.h Normal file
View File

@@ -0,0 +1,51 @@
#pragma once
#include <string>
#include <vector>
int nodeIdCounter = 0;
class NodeElement {
public:
int id;
std::string name;
ImVec2 position;
NodeElement(std::string name);
};
class NodeWindow {
public:
std::string title;
std::vector<NodeElement> alerts;
std::vector<NodeElement> triggers;
NodeWindow(std::string title);
};
typedef struct NodeConnection {
int sourceID;
int targetID;
};
typedef struct ConnectionPayload {
int sourceID;
};
class CustomDrawData {
public:
std::vector<NodeWindow> nodes;
std::vector<NodeConnection> connections;
};
enum class CircleDragType
{
None,
Source,
Target
};
void init();
void draw(DrawData& drawData, void* customDataVoid);
bool drawCircle(float xOffset, CircleDragType dragType, const void* id, ImVec2* outCirclePos = nullptr);
bool inlineButton(const char* title, const void* id);
std::vector<NodeElement>::iterator cleanEraseElement(std::vector<NodeElement>& vector, std::vector<NodeElement>::iterator toErase, CustomDrawData* data);

View File

@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{be4e5cfb-c93f-41d7-b474-721ad43d51a3}</ProjectGuid>
<RootNamespace>ImguiNodes</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v143</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(IncludePath)</IncludePath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
<IncludePath>E:\Code\AsuroImgui\ImguiBase;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="ImguiNodes.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\ImguiBase\ImguiBase.vcxproj">
<Project>{bb8a1ca3-7660-49e9-baf1-a99f733f7db6}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ImguiNodes.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="ImguiNodes.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ImguiNodes.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

Binary file not shown.