From eb5b2e891914973d0ee686770562cd456d4fce52 Mon Sep 17 00:00:00 2001 From: maj00r Date: Sun, 4 Oct 2026 00:48:00 +0200 Subject: [PATCH] refactor(editor): split the infrastructure window --- application/editormode.h | 4 ++ application/editormodeinfra.cpp | 99 +++++++++++++++++++-------------- 2 files changed, 62 insertions(+), 41 deletions(-) diff --git a/application/editormode.h b/application/editormode.h index 6a868119..4207a117 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -607,6 +607,10 @@ class editor_mode : public application_mode, private editor_track::observer void infra_move(infra::binding &Binding); void infra_attach(EditorSnapshot &Snapshot); void render_infra_window(); + void infra_rebase(); + void render_infra_search(); + void render_infra_candidates(); + void render_infra_bound(); void draw_infra_overlay() const; bool m_route_gizmo_using{false}; diff --git a/application/editormodeinfra.cpp b/application/editormodeinfra.cpp index 6630b8d9..c099bdb8 100644 --- a/application/editormodeinfra.cpp +++ b/application/editormodeinfra.cpp @@ -1137,31 +1137,7 @@ void editor_mode::render_infra_window() { state.follow = follow; if (follow) - { - // what changed in the meantime becomes the new starting point - for (auto &binding : m_bindings) - { - std::vector points; - std::optional yaw; - if (false == alive(binding) || false == object_points(binding, points, yaw) || points.size() != binding.anchors.size()) - continue; - for (std::size_t i = 0; i < points.size(); ++i) - { - auto &anchor{binding.anchors[i]}; - if (anchor.at.track == nullptr || anchor.at.track->m_editorremoved || anchor.at.path >= static_cast(anchor.at.track->m_paths.size())) - { - binding.lost = true; - continue; - } - double s; - bool interior; - infra::project(anchor.at.track->m_paths[anchor.at.path], points[i], s, interior); - anchor = infra::make_anchor({anchor.at.track, anchor.at.path, s}, points[i]); - } - if (binding.turns && yaw.has_value()) - binding.yaw = turn_of(binding, *yaw); - } - } + infra_rebase(); } if (ImGui::IsItemHovered()) ImGui::SetTooltip("Bound objects keep their chainage along the path, the offset from its axis and the height above the rail top;\n" @@ -1176,6 +1152,46 @@ void editor_mode::render_infra_window() } ImGui::Separator(); + render_infra_search(); + render_infra_candidates(); + render_infra_bound(); + if (false == state.error.empty()) + ImGui::TextColored(ImVec4(1.f, 0.4f, 0.35f, 1.f), "%s", state.error.c_str()); + else if (false == state.status.empty()) + ImGui::TextWrapped("%s", state.status.c_str()); + ImGui::End(); +} + +// what changed while the bindings did not follow the track becomes their new starting point +void editor_mode::infra_rebase() +{ + for (auto &binding : m_bindings) + { + std::vector points; + std::optional yaw; + if (false == alive(binding) || false == object_points(binding, points, yaw) || points.size() != binding.anchors.size()) + continue; + for (std::size_t i = 0; i < points.size(); ++i) + { + auto &anchor{binding.anchors[i]}; + if (anchor.at.track == nullptr || anchor.at.track->m_editorremoved || anchor.at.path >= static_cast(anchor.at.track->m_paths.size())) + { + binding.lost = true; + continue; + } + double s; + bool interior; + infra::project(anchor.at.track->m_paths[anchor.at.path], points[i], s, interior); + anchor = infra::make_anchor({anchor.at.track, anchor.at.path, s}, points[i]); + } + if (binding.turns && yaw.has_value()) + binding.yaw = turn_of(binding, *yaw); + } +} + +void editor_mode::render_infra_search() +{ + auto &state{m_infra}; static char const *const scopes[] = {"Selected path", "Line through the selected path", "Route of the vertical profile", "Whole scenery"}; ImGui::SetNextItemWidth(260.f); ImGui::Combo("Look along", &state.scope, scopes, IM_ARRAYSIZE(scopes)); @@ -1209,7 +1225,17 @@ void editor_mode::render_infra_window() if (ImGui::Button("Find objects")) infra_recognize(); +} + +void editor_mode::render_infra_candidates() +{ + auto &state{m_infra}; auto &candidates{state.candidates}; + auto const choose = [&](std::optional const Group, bool const Chosen) { + for (auto &candidate : candidates) + if (false == Group.has_value() || candidate.binding.group == *Group) + candidate.chosen = Chosen && false == candidate.bound; + }; state.hovered = -1; if (false == candidates.empty()) { @@ -1221,12 +1247,10 @@ void editor_mode::render_infra_window() infra_bind_chosen(); ImGui::SameLine(); if (ImGui::SmallButton("All")) - for (auto &candidate : candidates) - candidate.chosen = (false == candidate.bound); + choose({}, true); ImGui::SameLine(); if (ImGui::SmallButton("None")) - for (auto &candidate : candidates) - candidate.chosen = false; + choose({}, false); ImGui::BeginChild("##infracandidates", ImVec2(0.f, 260.f), true); for (auto const group : infra::categories()) @@ -1239,14 +1263,10 @@ void editor_mode::render_infra_window() ImGui::PopStyleColor(); ImGui::SameLine(); if (ImGui::SmallButton((std::string{"all##g"} + infra::name(group)).c_str())) - for (auto &candidate : candidates) - if (candidate.binding.group == group) - candidate.chosen = (false == candidate.bound); + choose(group, true); ImGui::SameLine(); if (ImGui::SmallButton((std::string{"none##g"} + infra::name(group)).c_str())) - for (auto &candidate : candidates) - if (candidate.binding.group == group) - candidate.chosen = false; + choose(group, false); if (false == open) continue; // the candidates are sorted by the category @@ -1282,7 +1302,10 @@ void editor_mode::render_infra_window() } ImGui::EndChild(); } +} +void editor_mode::render_infra_bound() +{ if (ImGui::TreeNode("Bound objects along the scope")) { auto const scope{infra_scope()}; @@ -1323,12 +1346,6 @@ void editor_mode::render_infra_window() infra_unbind({*unbind}); ImGui::TreePop(); } - - if (false == state.error.empty()) - ImGui::TextColored(ImVec4(1.f, 0.4f, 0.35f, 1.f), "%s", state.error.c_str()); - else if (false == state.status.empty()) - ImGui::TextWrapped("%s", state.status.c_str()); - ImGui::End(); } void editor_mode::draw_infra_overlay() const