From ce778ed674a73551389c00d6ddd796fda3ccf020 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Wed, 6 May 2026 03:12:45 -0700 Subject: [PATCH] feat(editor): patrol waypoint reorder (up/dn) + insert-after-cursor (+after) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously waypoints could only be appended or removed; reordering meant clearing and re-adding the whole path. Now each waypoint row has up/dn swap buttons and a +after that inserts a new waypoint at the current brush cursor right after this index — slicing long segments doesn't require redoing the rest of the path. --- tools/editor/editor_ui.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/editor/editor_ui.cpp b/tools/editor/editor_ui.cpp index 6057fb02..f2260c83 100644 --- a/tools/editor/editor_ui.cpp +++ b/tools/editor/editor_ui.cpp @@ -2013,12 +2013,22 @@ void EditorUI::renderNpcPanel(EditorApp& app) { totalDist += glm::length(sel->position - prev); ImGui::TextDisabled("Loop length: %.0f units", totalDist); - ImGui::BeginChild("PatrolList", ImVec2(0, 110), true); + ImGui::BeginChild("PatrolList", ImVec2(0, 130), true); for (int pi = 0; pi < static_cast(sel->patrolPath.size()); pi++) { auto& pp = sel->patrolPath[pi]; ImGui::PushID(pi); ImGui::Text("P%d (%.0f,%.0f,%.0f)", pi, pp.position.x, pp.position.y, pp.position.z); + // Reorder + delete buttons in one row. + ImGui::SameLine(); + if (pi > 0 && ImGui::SmallButton("up")) { + std::swap(sel->patrolPath[pi], sel->patrolPath[pi - 1]); + } + ImGui::SameLine(); + if (pi + 1 < static_cast(sel->patrolPath.size()) && + ImGui::SmallButton("dn")) { + std::swap(sel->patrolPath[pi], sel->patrolPath[pi + 1]); + } ImGui::SameLine(); if (ImGui::SmallButton("X")) { sel->patrolPath.erase(sel->patrolPath.begin() + pi--); @@ -2029,6 +2039,16 @@ void EditorUI::renderNpcPanel(EditorApp& app) { float waitS = pp.waitTimeMs / 1000.0f; if (ImGui::DragFloat("wait s", &waitS, 0.25f, 0.0f, 60.0f, "%.1fs")) pp.waitTimeMs = std::max(0.0f, waitS) * 1000.0f; + // Insert-after at brush cursor — useful for slicing + // a long segment into two. + ImGui::SameLine(); + auto& brush2 = app.getTerrainEditor().brush(); + if (brush2.isActive() && ImGui::SmallButton("+after")) { + PatrolPoint np; + np.position = brush2.getPosition(); + np.waitTimeMs = 2000.0f; + sel->patrolPath.insert(sel->patrolPath.begin() + pi + 1, np); + } ImGui::PopID(); } ImGui::EndChild();