| @ -0,0 +1,112 @@ | |||
| #pragma once | |||
| #include <string> | |||
| #include <vector> | |||
| #define IMGUI_DEFINE_MATH_OPERATORS | |||
| #include <imgui.h> | |||
| #include <imgui_internal.h> | |||
| #include "../geom.h" | |||
| class GuiNode { | |||
| public: | |||
| GuiNode(std::string name, Rect bbox) | |||
| : name(name), bbox(bbox) | |||
| {} | |||
| protected: | |||
| friend class NodeEditor; | |||
| std::string name; | |||
| Rect bbox; | |||
| }; | |||
| class NodeEditor { | |||
| public: | |||
| NodeEditor() { | |||
| nodeList.emplace_back("hi", Rect(10, 10, 60, 60)); | |||
| nodeList.emplace_back("hi2", Rect(10, 80, 60, 60)); | |||
| } | |||
| void draw_window(const char *title, bool *opened) { | |||
| ImGui::SetNextWindowSize(ImVec2(700,600), ImGuiSetCond_FirstUseEver); | |||
| if (ImGui::Begin(title, opened)) { | |||
| // -- Create child canvas | |||
| ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(1,1)); | |||
| ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0,0)); | |||
| ImGui::PushStyleColor(ImGuiCol_ChildWindowBg, ImColor(60,60,70,200)); | |||
| ImGui::BeginChild("nodes_region", ImVec2(0, 0), true, ImGuiWindowFlags_NoScrollbar|ImGuiWindowFlags_NoMove); | |||
| // -- Prepare to draw | |||
| // Get the draw list for this canvas | |||
| ImDrawList* draw_list = ImGui::GetWindowDrawList(); | |||
| draw_list->ChannelsSplit(2); | |||
| // this gets the offset to the upper-right corner of the child canvas. | |||
| // Note: here, cursor means "draw cursor", not "mouse pointing cursor". | |||
| ImVec2 canvas_pos = ImGui::GetCursorScreenPos(); | |||
| ImVec2 canvas_size = ImGui::GetWindowSize(); | |||
| ImVec2 offset = canvas_pos - scrolling; // TODO: add scrolling | |||
| // -- Draw the grid | |||
| if (show_grid) { | |||
| ImVec2 local_offset = ImGui::GetCursorPos() - scrolling; | |||
| float spacing = 32.0f; ImU32 color = IM_COL32(200, 200, 200, 40); | |||
| for (float x = fmodf(local_offset.x, spacing); x < canvas_size.x; x += spacing) | |||
| draw_list->AddLine(ImVec2(x, 0.0f)+canvas_pos, | |||
| ImVec2(x, canvas_size.y)+canvas_pos, color); | |||
| for (float y = fmodf(local_offset.y, spacing); y < canvas_size.y; y += spacing) | |||
| draw_list->AddLine(ImVec2(0.0f, y)+canvas_pos, | |||
| ImVec2(canvas_size.x, y)+canvas_pos, color); | |||
| } | |||
| Rect viewportRect = Rect(scrolling, canvas_size); | |||
| for (const auto &node : nodeList) { | |||
| bool visible = viewportRect.intersects(node.bbox); | |||
| if (visible) { | |||
| // -- Draw the node boxes | |||
| draw_list->ChannelsSetCurrent(0); // Switch to the background layer | |||
| ImVec2 upper_left = offset + node.bbox.pos; | |||
| ImVec2 lower_right = upper_left + node.bbox.size; | |||
| draw_list->AddRectFilled(upper_left, lower_right, ImColor(60, 60, 60), 4.0f); | |||
| draw_list->AddRect(upper_left, lower_right, ImColor(100, 100, 100), 4.0f); | |||
| // for (int i=0; i<N; i++) { | |||
| // auto position = node.bbox.pos; | |||
| // position.y += (i+1) * (node.bbox.size.y)/(N+1); | |||
| // draw_list->AddCircleFilled(offset + position, 4.0f, ImColor(150, 150, 150, 150)); | |||
| // } | |||
| } | |||
| } | |||
| // -- merge channels back together | |||
| draw_list->ChannelsMerge(); | |||
| // -- scrolling! | |||
| // [ pointer over neditor ] [ not interacting ctrls ] [ middle mouse dragging ] | |||
| if (ImGui::IsWindowHovered() && !ImGui::IsAnyItemActive() && ImGui::IsMouseDragging(2, 0.0f)) | |||
| scrolling = scrolling - ImGui::GetIO().MouseDelta; | |||
| // -- clean up | |||
| ImGui::EndChild(); // end :nodes_region | |||
| ImGui::PopStyleColor(); // pop ChildWindowBg | |||
| ImGui::PopStyleVar(2); // pop FramePadding, WindowPadding | |||
| } | |||
| ImGui::End(); | |||
| } | |||
| private: | |||
| std::vector<GuiNode> nodeList; | |||
| ImVec2 scrolling = ImVec2(0.0f, 0.0f); | |||
| bool show_grid = true; | |||
| }; | |||