Skip to content

Commit

Permalink
Add a node editor.
Browse files Browse the repository at this point in the history
linuscu committed Aug 28, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent cede21d commit f94b771
Showing 9 changed files with 245 additions and 47 deletions.
16 changes: 10 additions & 6 deletions packages/rendering/include/rendering/ui/UIContainer.h
Original file line number Diff line number Diff line change
@@ -183,8 +183,6 @@ namespace l::ui {
class UIContainer;
class UISplit;

int32_t CreateUniqueId();

template<class T, class = std::enable_if_t<std::is_base_of_v<UIContainer, T>>>
std::string CreateUniqueStringId() {
static uint32_t mStringId = 0;
@@ -286,7 +284,8 @@ namespace l::ui {
public:
UIContainer(uint32_t flags = 0, UIRenderType renderType = UIRenderType::Rect, UIAlignH alignH = UIAlignH::Left, UIAlignV alignV = UIAlignV::Top, UILayoutH layoutH = UILayoutH::Fixed, UILayoutV layoutV = UILayoutV::Fixed) :
mId(0),
mSubId(0),
mNodeId(0),
mChannelId(0),
mConfigFlags(flags),
mNotificationFlags(0),
mParent(nullptr),
@@ -336,7 +335,8 @@ namespace l::ui {
std::string_view GetDisplayName() { return mDisplayName; }
std::string_view GetStringId() { return mStringId; }
int32_t GetId() { return mId; }
int32_t GetSubId() { return mSubId; }
int32_t GetNodeId() { return mNodeId; }
int32_t GetChannelId() { return mChannelId; }

void SetColor(ImVec4 color) { mDisplayArea.mRender.mColor = ImColor(color); }
void SetScale(float scale) {mDisplayArea.mScale = scale;}
@@ -346,7 +346,9 @@ namespace l::ui {
void SetLayoutSize(ImVec2 s) {mLayoutArea.mSize = s;}
void SetDisplayName(std::string_view displayName) {mDisplayName = displayName;}
void SetStringId(std::string_view id) {mStringId = id;}
void SetId(int32_t id, int32_t subId = 0) { mId = id; mSubId = subId; }
void SetId(int32_t id) { mId = id; }
void SetNodeId(int32_t nodeId) { mNodeId = nodeId; }
void SetChannelId(int32_t channelId) { mChannelId = channelId; }

void SetContainerArea(const ContainerArea& area) {mDisplayArea = area;}
void SetLayoutArea(const ContainerArea& transformedLayoutArea) {mLayoutArea = transformedLayoutArea;}
@@ -356,7 +358,8 @@ namespace l::ui {
void DebugLog() { LOG(LogDebug) << "UIContainer: " << mDisplayName << ", [" << mDisplayArea.mScale << "][" << mDisplayArea.mPosition.x << ", " << mDisplayArea.mPosition.y << "][" << mDisplayArea.mSize.x << ", " << mDisplayArea.mSize.y << "]"; }
protected:
int32_t mId = 0;
int32_t mSubId = 0;
int32_t mNodeId = 0;
int32_t mChannelId = 0;
std::string mStringId;
std::string mDisplayName;
uint32_t mConfigFlags = 0; // Active visitor flags
@@ -404,6 +407,7 @@ namespace l::ui {
void Remove(int32_t id);
protected:
std::unordered_map<uint32_t, std::unique_ptr<UIContainer>> mContainers;
int32_t mIdCounter = 1;
};

UIHandle CreateContainer(UIStorage& uiStorage, uint32_t flags, UIRenderType renderType = UIRenderType::Rect, UIAlignH alignH = UIAlignH::Left, UIAlignV alignV = UIAlignV::Top, UILayoutH layoutH = UILayoutH::Fixed, UILayoutV layoutV = UILayoutV::Fixed);
138 changes: 138 additions & 0 deletions packages/rendering/include/rendering/ui/UINodeEditor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
#pragma once

#include "logging/LoggingAll.h"

#include "rendering/ui/UIContainer.h"
#include "rendering/ui/UIVisitors.h"
#include "rendering/ui/UIWindow.h"
#include "rendering/ui/UICreator.h"

#include "nodegraph/NodeGraph.h"
#include "nodegraph/NodeGraphOperations.h"
#include "nodegraph/NodeGraphSchema.h"

#include <functional>
#include <vector>
#include <set>
#include <string>

namespace l::ui {

struct UINodeDesc {
std::string_view GetTypeName() {
return mTypeName;
}
std::string_view GetName() {
return mName;
}
int32_t GetId() {
return mId;
}

int32_t mId;
std::string mName;
std::string mTypeName;
};

class UINodeEditor : public UIBase {
public:
UINodeEditor(std::string_view editorName) : mUIWindow(editorName), mLinkIOVisitor(mUIStorage, mNGSchema) {
mUIRoot = CreateContainer(mUIStorage, l::ui::UIContainer_DragFlag | l::ui::UIContainer_ZoomFlag);

mRegisteredNodeTypes.push_back({ 0, "Add", "Numerical" });
mRegisteredNodeTypes.push_back({ 1, "Subtract", "Numerical" });
mRegisteredNodeTypes.push_back({ 2, "Negate", "Numerical" });
mRegisteredNodeTypes.push_back({ 3, "Multiply", "Numerical" });
mRegisteredNodeTypes.push_back({ 4, "Integral", "Numerical" });
mRegisteredNodeTypes.push_back({ 20, "And", "Logical" });
mRegisteredNodeTypes.push_back({ 21, "Or", "Logical" });
mRegisteredNodeTypes.push_back({ 22, "Xor", "Logical" });
mRegisteredNodeTypes.push_back({ 40, "Lowpass Filter", "" });


mUIWindow.SetContentWindow([&]() {
ImGui::PushItemWidth(400);

UIDraw uiDrawVisitor(ImGui::GetWindowDrawList());
UIUpdate updateVisitor;

mUIRoot->SetLayoutSize(mUIWindow.GetSize());
mUIRoot->SetLayoutPosition(mUIWindow.GetPosition());
mUIRoot->Accept(updateVisitor, mUIInput, l::ui::UITraversalMode::BFS);
mUIRoot->Accept(uiDrawVisitor, mUIInput, l::ui::UITraversalMode::BFS);

ImGui::PopItemWidth();

});

mUIWindow.SetPointerPopup([&]() {
ImGui::Text("Node picker");
ImGui::Separator();

std::set<std::string> nodeTypes;
for (auto nodeType : mRegisteredNodeTypes) {
nodeTypes.emplace(nodeType.GetTypeName());
}

for (auto it = nodeTypes.rbegin(); it != nodeTypes.rend(); it++) {
if (it->empty() || ImGui::TreeNode(it->c_str())) {
for (auto& nodedesc : mRegisteredNodeTypes) {
if (*it != nodedesc.GetTypeName()) {
continue;
}

if (ImGui::MenuItem(nodedesc.GetName().data())) {
ImVec2 p = ImVec2(mUIInput.mCurPos.x - mUIWindow.GetPosition().x, mUIInput.mCurPos.y - mUIWindow.GetPosition().y);
p.x -= mUIRoot->GetPosition().x;
p.y -= mUIRoot->GetPosition().y;
p.x /= mUIRoot->GetScale();
p.y /= mUIRoot->GetScale();
p.x -= 3.0f;
p.y -= 3.0f;
auto nodeId = mNGSchema.NewNode(nodedesc.GetId());
auto node = mNGSchema.GetNode(nodeId);
if (node != nullptr) {
auto uiNode = l::ui::CreateUINode(mUIStorage, *node, p);
mUIRoot->Add(uiNode);
}
}
}
if (!it->empty()) {
ImGui::TreePop();
}
}
}

});


}
~UINodeEditor() = default;

void Show() override;
bool IsShowing() override;

void Open();
void Close();

void Update();

protected:
UIWindow mUIWindow;
UIStorage mUIStorage;
UIHandle mUIRoot;
InputState mUIInput;

l::nodegraph::NodeGraphSchema mNGSchema;

std::vector<UINodeDesc> mRegisteredNodeTypes;

UIZoom mZoomVisitor;
UIDrag mDragVisitor;
UIMove mMoveVisitor;
UIResize mResizeVisitor;
UILinkIO mLinkIOVisitor;

};

}
10 changes: 0 additions & 10 deletions packages/rendering/include/rendering/ui/UIVisitors.h
Original file line number Diff line number Diff line change
@@ -3,16 +3,6 @@
#include "rendering/ui/UIContainer.h"
#include "nodegraph/NodeGraphSchema.h"

#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

#include "imgui/imgui.h"
#include "imgui/imgui_internal.h"
#include "imgui/imgui_impl_glfw.h"
#include "imgui/imgui_impl_opengl3.h"
#include "implot/implot.h"
#include "implot/implot_internal.h"

namespace l::ui {

class UIUpdate : public UIVisitor {
34 changes: 21 additions & 13 deletions packages/rendering/include/rendering/ui/UIWindow.h
Original file line number Diff line number Diff line change
@@ -16,34 +16,42 @@

namespace l::ui {

class UIWindow {
class UIBase {
public:
UIWindow() : mWindowPtr(nullptr), mOpened(false), mIsHovered(false), mWindowFunction(nullptr), mContentScale(1.0f), mMoving(false) {}
UIBase() = default;
virtual ~UIBase() = default;

virtual void Show() = 0;
virtual bool IsShowing() = 0;
};

class UIWindow final : public UIBase {
public:
UIWindow(std::string_view windowName) : mWindowName(windowName) {}
~UIWindow() = default;

void Show() override;
bool IsShowing() override;

void SetContentWindow(std::function<void()> action);
void SetPointerPopup(std::function<void()> popup);

void Open();
bool IsShowing();
void Close();
bool IsHovered();
ImVec2 GetPosition();
ImVec2 GetSize();
void Show();
void SetBgColor(ImVec4 bgColor);
protected:
ImGuiWindow* mWindowPtr;
bool mOpened;
bool mIsHovered;
std::function<void()> mWindowFunction;
std::function<void()> mPointerPopupMenu;
float mContentScale;
bool mMoving;
std::string mWindowName;
ImGuiWindow* mWindowPtr = nullptr;
bool mOpened = false;
bool mIsHovered = false;
std::function<void()> mWindowFunction = nullptr;
std::function<void()> mPointerPopupMenu = nullptr;
bool mPointerPopupOpen = false;

ImVec4 mBgColor = ImVec4(0.01f, 0.01f, 0.01f, 1.0f);

ImVec2 mContentPan;
};

}
12 changes: 2 additions & 10 deletions packages/rendering/source/common/ui/UIContainer.cpp
Original file line number Diff line number Diff line change
@@ -257,14 +257,10 @@ namespace l::ui {
return false;
}

int32_t CreateUniqueId() {
static int32_t mId = 1;
return mId++;
}

UIHandle UIStorage::Add(std::unique_ptr<UIContainer> container) {
auto id = container->GetId();
auto id = mIdCounter++;
auto stringId = container->GetStringId();
container->SetId(id);
mContainers.insert({ id, std::move(container) });
return UIHandle{ id, stringId, mContainers.at(id).get() };
}
@@ -276,9 +272,7 @@ namespace l::ui {
UIHandle CreateContainer(UIStorage& uiStorage, uint32_t flags, UIRenderType renderType, UIAlignH alignH, UIAlignV alignV, UILayoutH layoutH, UILayoutV layoutV) {
std::unique_ptr<UIContainer> container = std::make_unique<UIContainer>(flags, renderType, alignH, alignV, layoutH, layoutV);

auto id = CreateUniqueId();
auto stringId = CreateUniqueStringId<UIContainer>();
container->SetId(id);
container->SetStringId(stringId);

return uiStorage.Add(std::move(container));
@@ -287,9 +281,7 @@ namespace l::ui {
UIHandle CreateSplit(UIStorage& uiStorage, uint32_t flags, UIRenderType renderType, UISplitMode splitMode, UILayoutH layoutH, UILayoutV layoutV) {
std::unique_ptr<UISplit> container = std::make_unique<UISplit>(flags, renderType, splitMode, layoutH, layoutV);

auto id = CreateUniqueId();
auto stringId = CreateUniqueStringId<UIContainer>();
container->SetId(id);
container->SetStringId(stringId);

return uiStorage.Add(std::move(container));
6 changes: 4 additions & 2 deletions packages/rendering/source/common/ui/UICreator.cpp
Original file line number Diff line number Diff line change
@@ -41,7 +41,8 @@ namespace l::ui {
in->SetPosition(ImVec2(-ioSize, ioSize * ioOffsetV));
in->SetSize(ImVec2(ioSize, ioSize));
in->GetContainerArea().mMargin = 0.0f;
in->SetId(node.GetId(), i);
in->SetNodeId(node.GetId());
in->SetChannelId(i);
row->Add(in);
auto inText = CreateContainer(uiStorage, l::ui::UIContainer_DrawFlag, l::ui::UIRenderType::Text, l::ui::UIAlignH::Left);
inText->SetPosition(ImVec2(0.0f, 0.0f));
@@ -54,7 +55,8 @@ namespace l::ui {
out->SetPosition(ImVec2(ioSize * 2.0f, ioSize * ioOffsetV));
out->SetSize(ImVec2(ioSize, ioSize));
out->GetContainerArea().mMargin = 0.0f;
out->SetId(node.GetId(), i);
out->SetNodeId(node.GetId());
out->SetChannelId(i);
row->Add(out);
auto outText = CreateContainer(uiStorage, l::ui::UIContainer_DrawFlag, l::ui::UIRenderType::Text, l::ui::UIAlignH::Right);
outText->SetPosition(ImVec2(0.0f, 0.0f));
49 changes: 49 additions & 0 deletions packages/rendering/source/common/ui/UINodeEditor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#include "rendering/ui/UINodeEditor.h"

#include <memory>

namespace l::ui {

bool UINodeEditor::IsShowing() {
return mUIWindow.IsShowing();
}

void UINodeEditor::Show() {
mUIWindow.Show();
}

void UINodeEditor::Open() {
mUIWindow.Open();
}

void UINodeEditor::Close() {
mUIWindow.Close();
}

void UINodeEditor::Update() {
if (mUIWindow.IsShowing()) {
ImGuiIO& io = ImGui::GetIO();
io.ConfigWindowsMoveFromTitleBarOnly = true;

mUIInput.mCurPos = io.MousePos;
mUIInput.mPrevPos = io.MousePosPrev;
mUIInput.mScroll = io.MouseWheel;
mUIInput.mStarted = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
mUIInput.mStopped = ImGui::IsMouseReleased(ImGuiMouseButton_Left);

if (mUIWindow.IsHovered()) {
if (mUIRoot->Accept(mLinkIOVisitor, mUIInput, l::ui::UITraversalMode::DFS)) {
}
else if (mUIRoot->Accept(mResizeVisitor, mUIInput, l::ui::UITraversalMode::DFS)) {
}
else if (mUIRoot->Accept(mMoveVisitor, mUIInput, l::ui::UITraversalMode::DFS)) {
}
else if (mUIRoot->Accept(mZoomVisitor, mUIInput, l::ui::UITraversalMode::DFS)) {
}
else if (mUIRoot->Accept(mDragVisitor, mUIInput, l::ui::UITraversalMode::DFS)) {
}
}
}
}

}
17 changes: 14 additions & 3 deletions packages/rendering/source/common/ui/UIVisitors.cpp
Original file line number Diff line number Diff line change
@@ -48,7 +48,18 @@ namespace l::ui {
return false;
}
if (input.mStarted && !mDragging) {
if (input.GetLocalPos().x >= 0.0f && input.GetLocalPos().y >= 0.0f) {
auto& layoutArea = container.GetLayoutArea();
ImVec2 layoutPosition = layoutArea.mPosition;
ImVec2 layoutSize = layoutArea.mSize;
layoutPosition.x -= 6.0f;
layoutPosition.y -= 8.0f;
layoutSize.x -= 14.0f;
layoutSize.y -= 14.0f;

ImVec2 localMousePos = input.GetLocalPos();
localMousePos.x -= layoutPosition.x;
localMousePos.y -= layoutPosition.y;
if (Overlap(localMousePos, ImVec2(), layoutSize)) {
mDragging = true;
mSourceContainer = &container;
}
@@ -315,7 +326,7 @@ namespace l::ui {
ImVec2 pT = layoutArea.Transform(pCenter);

if (OverlapCircle(input.mCurPos, pT, size.x * layoutArea.mScale)) {
if (LinkHandler(container.GetId(), mLinkContainer->GetParent()->GetId(), container.GetSubId(), mLinkContainer->GetParent()->GetSubId(), true)) {
if (LinkHandler(container.GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), container.GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), true)) {
mLinkContainer->SetNotification(UIContainer_LinkFlag);
mLinkContainer->SetCoParent(&container);
}
@@ -324,7 +335,7 @@ namespace l::ui {
}
}
else if (mLinkContainer->GetCoParent() == &container) {
LinkHandler(container.GetId(), mLinkContainer->GetParent()->GetId(), container.GetSubId(), mLinkContainer->GetParent()->GetSubId(), false);
LinkHandler(container.GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), container.GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), false);
mLinkContainer->SetCoParent(nullptr);
mLinkContainer->ClearNotifications();
}
10 changes: 7 additions & 3 deletions packages/rendering/source/common/ui/UIWindow.cpp
Original file line number Diff line number Diff line change
@@ -4,6 +4,10 @@

namespace l::ui {

bool UIWindow::IsShowing() {
return mWindowPtr && mOpened;
}

void UIWindow::SetContentWindow(std::function<void()> action) {
mWindowFunction = action;
}
@@ -16,8 +20,8 @@ namespace l::ui {
mOpened = true;
}

bool UIWindow::IsShowing() {
return mWindowPtr && mOpened;
void UIWindow::Close() {
mOpened = false;
}

bool UIWindow::IsHovered() {
@@ -35,7 +39,7 @@ namespace l::ui {
void UIWindow::Show() {
if (mOpened) {
ImGui::PushStyleColor(ImGuiCol_WindowBg, mBgColor);
if (ImGui::Begin("Test primitive rendering", &mOpened)) {
if (ImGui::Begin(mWindowName.c_str(), &mOpened, ImGuiWindowFlags_MenuBar)) {
if (mOpened) {
mWindowPtr = ImGui::GetCurrentWindowRead();
mIsHovered = ImGui::IsWindowHovered();;

0 comments on commit f94b771

Please sign in to comment.