#pragma once #include #include #define IMGUI_DEFINE_MATH_OPERATORS #include #include #include "../geom.h" class GuiNode { public: GuiNode(std::string name, Rect bbox, uint n_slots_in, uint n_slots_out) : name(name), bbox(bbox), n_slots_in(n_slots_in), n_slots_out(n_slots_out) {} enum SlotDirection { IN, OUT, }; ImVec2 slot_location(SlotDirection direction, uint i) const { uint n_slots; switch (direction) { case IN: n_slots = n_slots_in; break; case OUT: n_slots = n_slots_out; break; } auto x_stride = bbox.size.y/(n_slots+1); ImVec2 base; switch(direction) { case IN: base = bbox.pos; break; case OUT: base = bbox.pos + ImVec2(bbox.size.x, 0); break; } return base + ImVec2(0, (i + 1) * x_stride); } uint n_slots_in; uint n_slots_out; std::string name; Rect bbox; }; class GuiEdge { public: GuiEdge(GuiNode *lhs, GuiNode *rhs, uint fromSlot, uint toSlot) : lhs(lhs), rhs(rhs), fromSlot(fromSlot), toSlot(toSlot) {} GuiNode *lhs; GuiNode *rhs; uint fromSlot; uint toSlot; }; class NodeEditor { public: NodeEditor() { nodeList.emplace_back("hi", Rect(10, 10, 60, 60), 3, 1); nodeList.emplace_back("hi2", Rect(80, 10, 60, 60), 1, 1); edgeList.emplace_back(&nodeList[0], &nodeList[1], 0, 0); } 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 draw_list->ChannelsSetCurrent(0); 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); } draw_list->ChannelsSetCurrent(0); for (const auto &edge : edgeList) { auto head = offset + edge.lhs->slot_location(GuiNode::OUT, edge.fromSlot); auto tail = offset + edge.rhs->slot_location(GuiNode::IN, edge.fromSlot); draw_list->AddBezierCurve(head, head+ImVec2(50, 0), tail+ImVec2(-50, 0), tail, ImColor(200, 200, 200), 3.0f); } 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; iAddCircleFilled(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 nodeList; std::vector edgeList; ImVec2 scrolling = ImVec2(0.0f, 0.0f); bool show_grid = true; };