From edb4f7c60d59ab6b1a3398186dd11a0eae8d6fe1 Mon Sep 17 00:00:00 2001 From: maj00r Date: Thu, 22 Oct 2026 18:55:13 +0200 Subject: [PATCH] feat(editor): the panel of a signal picked swaps its template for another of its kind and mount, the name, the plate, the place and the read event kept, a head leaning to one side for its counterpart leaning towards the track; one step of undo, the selftest signalswap --- application/editormode.h | 1 + application/editormodeselftestsignal.cpp | 20 ++++++++++- application/editormodesignal.cpp | 43 ++++++++++++++++++++++++ lang/editor_pl.po | 12 +++++++ 4 files changed, 75 insertions(+), 1 deletion(-) diff --git a/application/editormode.h b/application/editormode.h index 13d42f3a..12efab27 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1987,6 +1987,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri bool signal_move_to(signal_standing const &Standing, signal_spot const &Spot, char const *Read, char const *Unread); bool signal_flip(scene::instance_handle const Instance); bool signal_turn(scene::instance_handle const Instance); + bool signal_swap(scene::instance_handle const Instance, std::string const &File); signal_standing const *signal_standing_of(scene::instance_handle const Instance) const; bool signal_delete(scene::instance_handle const Instance); void signal_detach_events(std::string const &Read, std::vector> &States); diff --git a/application/editormodeselftestsignal.cpp b/application/editormodeselftestsignal.cpp index db7c1624..aab2d651 100644 --- a/application/editormodeselftestsignal.cpp +++ b/application/editormodeselftestsignal.cpp @@ -50,7 +50,7 @@ http://mozilla.org/MPL/2.0/. editor_mode::selftest_result editor_mode::selftest_signal(std::string const &command, std::istringstream &words) { - if (command == "signal" || command == "signalmove" || command == "signaldelete" || command == "signalrename" || command == "signalprobe" || command == "signalflip" || command == "signalturn") + if (command == "signal" || command == "signalmove" || command == "signaldelete" || command == "signalrename" || command == "signalprobe" || command == "signalflip" || command == "signalturn" || command == "signalselect" || command == "signalswap") { auto values{selftest_values(words)}; show_track_tab(track_tab::signals); @@ -141,6 +141,24 @@ editor_mode::selftest_result editor_mode::selftest_signal(std::string const &com auto const done{standing != nullptr && (command == "signalflip" ? signal_flip(standing->include.instance) : signal_turn(standing->include.instance))}; WriteLog("SELFTEST " + command + " " + values["name"] + (done ? ": " : ": failed, ") + tool.status); } + else if (command == "signalselect" || command == "signalswap") + { + auto const *standing{standing_named(values["name"])}; + if (standing == nullptr) + { + WriteLog("SELFTEST " + command + ": no signal " + values["name"]); + return selftest_result::handled; + } + auto const instance{standing->include.instance}; + signal_select(instance); + if (command == "signalswap") + { + auto const done{signal_swap(instance, values["file"])}; + WriteLog("SELFTEST signalswap " + values["name"] + (done ? ": " : ": failed, ") + tool.status); + } + else + WriteLog("SELFTEST signalselect " + values["name"] + ": " + standing->include.file); + } else if (command == "signaldelete") { auto const *standing{standing_named(values["name"])}; diff --git a/application/editormodesignal.cpp b/application/editormodesignal.cpp index 189bf092..c8181c35 100644 --- a/application/editormodesignal.cpp +++ b/application/editormodesignal.cpp @@ -689,6 +689,30 @@ bool editor_mode::signal_turn(scene::instance_handle const Instance) return signal_move_to(*standing, spot, STR_C("Signal %s turned to the trains of the other direction, read by %s %s of %s, Ctrl+Z takes it back"), STR_C("Signal %s turned to the trains of the other direction, Ctrl+Z takes it back")); } +bool editor_mode::signal_swap(scene::instance_handle const Instance, std::string const &File) +{ + auto &tool{m_signal}; + auto const *standing{signal_standing_of(Instance)}; + if (standing == nullptr) + return false; + auto const name{standing->name}; + auto const before{standing->include.file}; + signal_changes changes; + changes.files.emplace_back(Instance, File); + std::string error; + signal_batch(changes, {}, {}, error); + signal_refresh(true); + auto const *swapped{signal_standing_of(Instance)}; + if (false == error.empty() || swapped == nullptr || swapped->include.file == before) + { + tool.status = error.empty() ? format(STR_C("Signal %s can't take the template %s"), name.c_str(), File.c_str()) : error; + return false; + } + signal_select(Instance); + tool.status = format(STR_C("Signal %s got the template %s, Ctrl+Z takes it back"), name.c_str(), swapped->include.file.c_str()); + return true; +} + std::string editor_mode::signal_variant(signal_template const &Template, signal_spot const &Spot) const { auto file{Template.file}; @@ -1217,6 +1241,25 @@ void editor_mode::render_signal_selected() else ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.3f, 1.0f), STR_C("No path has %s among its events: the train doesn't see it"), found->read.c_str()); auto const instance{found->include.instance}; + if (auto const *item{signal_template_of(found->include.file)}; item != nullptr) + { + auto const shown = [](signal_template const &Template) { return Template.lamps.empty() ? Template.name : Template.name + " " + Template.lamps; }; + std::string swap; + ImGui::SetNextItemWidth(-1.0f); + if (ImGui::BeginCombo("##signalswap", format(STR_C("Template: %s"), shown(*item).c_str()).c_str(), ImGuiComboFlags_HeightLarge)) + { + for (auto const &other : m_signal.templates) + if (other.kind == item->kind && other.mount == item->mount && ImGui::Selectable((shown(other) + "##" + other.file).c_str(), other.file == item->file) && other.file != item->file) + swap = other.file; + ImGui::EndCombo(); + } + item_tooltip("Another template of its kind and mount for the signal: the name, the plate, the place and the event the train reads it by stay. A head leaning to one side is swapped for its counterpart leaning towards the track. Ctrl+Z takes it back"); + if (false == swap.empty()) + { + signal_swap(instance, swap); + return; + } + } auto const width{(ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ItemSpacing.x) * 0.5f}; if (ImGui::Button(STR_C("To the other side"), ImVec2(width, 0.0f))) signal_flip(instance); diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 4202c641..10f5d0f8 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -11065,3 +11065,15 @@ msgstr[0] "%zu semafor dostał potrzebne światła, Ctrl+Z cofa" msgstr[1] "%zu semafory dostały potrzebne światła, Ctrl+Z cofa" msgstr[2] "%zu semaforów dostało potrzebne światła, Ctrl+Z cofa" + +msgid "Template: %s" +msgstr "Szablon: %s" + +msgid "Another template of its kind and mount for the signal: the name, the plate, the place and the event the train reads it by stay. A head leaning to one side is swapped for its counterpart leaning towards the track. Ctrl+Z takes it back" +msgstr "Inny szablon tego samego rodzaju i mocowania dla semafora: nazwa, tablica, miejsce i event, po którym pociąg go odczytuje, zostają. Głowica pochylona w bok zamienia się na odpowiednik pochylony ku torowi. Ctrl+Z cofa" + +msgid "Signal %s got the template %s, Ctrl+Z takes it back" +msgstr "Semafor %s dostał szablon %s, Ctrl+Z cofa" + +msgid "Signal %s can't take the template %s" +msgstr "Semafor %s nie może dostać szablonu %s"