This commit is contained in:
Connor
2026-02-24 17:22:41 +09:00
parent 1b7fd1c7f8
commit bee5aa0e8f
8 changed files with 1113 additions and 123 deletions

View File

@@ -248,6 +248,7 @@ static const std::vector<NodeMenuItem> NODE_MENU = {
{ "QueryTile", "Query", [] { return std::make_unique<QueryTileNode>(0, -1, 1); } },
{ "QueryRange", "Query", [] { return std::make_unique<QueryRangeNode>(-1, -1, 1, 1, 1); } },
{ "QueryDistance", "Query", [] { return std::make_unique<QueryDistanceNode>(1, 4); } },
{ "QueryLiquid", "Query", [] { return std::make_unique<LiquidNode>(8, 4); } },
// ── Noise ───────────────────────────────────────────────────────────────
{ "Random", "Noise", [] { return std::make_unique<RandomNode>(); } },
{ "PerlinNoise", "Noise", [] { return std::make_unique<PerlinNoiseNode>(0.01f); } },
@@ -678,13 +679,19 @@ private:
ImNodes::SetNodeGridSpacePos(WORLD_OUTPUT_IMNODES_ID, ImVec2(400.0f, 0.0f));
}
// IsLinkHovered must be called outside BeginNodeEditor/EndNodeEditor.
// s_linkWasHovered carries the previous frame's result so the canvas
// right-click menu can be suppressed when the cursor is over a link.
static bool s_linkWasHovered = false;
ImNodes::BeginNodeEditor();
// Right-click blank canvas → add node menu
if (ImGui::IsWindowHovered(ImGuiFocusedFlags_RootAndChildWindows) &&
ImNodes::IsEditorHovered() &&
ImGui::IsMouseReleased(ImGuiMouseButton_Right) &&
!ImGui::IsAnyItemHovered())
!ImGui::IsAnyItemHovered() &&
!s_linkWasHovered)
{
ImGui::OpenPopup("##add_node_menu");
}
@@ -778,6 +785,11 @@ private:
ImNodes::EndNodeEditor();
// Query link hover state here — must be outside Begin/End editor.
int hoveredLink = -1;
bool linkIsHovered = ImNodes::IsLinkHovered(&hoveredLink);
s_linkWasHovered = linkIsHovered;
// ── Handle new connections ────────────────────────────────────────────
int fromAttr, toAttr;
@@ -834,11 +846,9 @@ private:
// ── Handle link deletion ──────────────────────────────────────────────
int destroyedLink;
if (ImNodes::IsLinkDestroyed(&destroyedLink)) {
if (destroyedLink >= WORLD_OUTPUT_LINK_BASE) {
// World Output link
int passIdx = destroyedLink - WORLD_OUTPUT_LINK_BASE;
auto destroyLink = [&](int linkId) {
if (linkId >= WORLD_OUTPUT_LINK_BASE) {
int passIdx = linkId - WORLD_OUTPUT_LINK_BASE;
if (passIdx >= 0 && passIdx < static_cast<int>(tab.worldOutputPasses.size())) {
tab.worldOutputPasses[passIdx] = Graph::INVALID_ID;
tab.worldOutputDirty = true;
@@ -853,7 +863,7 @@ private:
if (!node) continue;
for (int slot = 0; slot < static_cast<int>(node->GetInputCount()); ++slot) {
if (tab.graph.GetInput(id, slot).has_value()) {
if (idx == destroyedLink) {
if (idx == linkId) {
tab.graph.Disconnect(id, slot);
MarkAllDirty();
found = true;
@@ -864,6 +874,25 @@ private:
}
}
}
};
int destroyedLink;
if (ImNodes::IsLinkDestroyed(&destroyedLink))
destroyLink(destroyedLink);
// ── Right-click a link → disconnect popup ─────────────────────────────
static int s_rightClickedLink = -1;
if (linkIsHovered && ImGui::IsMouseReleased(ImGuiMouseButton_Right)) {
s_rightClickedLink = hoveredLink;
ImGui::OpenPopup("##link_ctx");
}
if (ImGui::BeginPopup("##link_ctx")) {
if (ImGui::MenuItem("Disconnect") && s_rightClickedLink >= 0) {
destroyLink(s_rightClickedLink);
s_rightClickedLink = -1;
}
ImGui::EndPopup();
}
// ── Delete selected nodes ─────────────────────────────────────────────
@@ -1101,6 +1130,19 @@ private:
return changed;
}
static bool DrawLiquidNodeParams(NodeEditorApp& /*app*/, Node* node)
{
auto* n = static_cast<LiquidNode*>(node);
bool changed = false;
ImGui::PushItemWidth(70);
ImGui::Text("max width");
changed |= ImGui::DragInt("##lw", &n->maxWidth, 1, 1, 64);
ImGui::Text("max depth");
changed |= ImGui::DragInt("##ld", &n->maxDepth, 1, 1, 64);
ImGui::PopItemWidth();
return changed;
}
static bool DrawMapParams(NodeEditorApp& /*app*/, Node* node)
{
auto* n = static_cast<MapNode*>(node);
@@ -1139,6 +1181,7 @@ private:
{ typeid(QueryTileNode), DrawQueryTileParams },
{ typeid(QueryRangeNode), DrawQueryRangeParams },
{ typeid(QueryDistanceNode), DrawQueryDistanceParams },
{ typeid(LiquidNode), DrawLiquidNodeParams },
{ typeid(MapNode), DrawMapParams },
{ typeid(PerlinNoiseNode), DrawPerlinNoiseParams },
{ typeid(SimplexNoiseNode), DrawSimplexNoiseParams },