From b92d1283acff01b70ca22c25c1cbb8fa9d92faa5 Mon Sep 17 00:00:00 2001 From: maj00r Date: Thu, 22 Oct 2026 19:26:25 +0200 Subject: [PATCH] feat(editor): a block signal template knows its aspects, 4 where its events give S3, the green light flashing with the next signal at S5, else 3; one step of the signalling takes includes away too, the signals among them with their read events, Ctrl+Z bringing them back with the rest of it --- application/editormode.h | 1 + application/editormodesignal.cpp | 27 +++++++++++++++++++++++++-- application/editortool.h | 2 ++ editor/editorIncludeInfo.cpp | 19 +++++++++++++++++++ editor/editorIncludeInfo.hpp | 3 +++ 5 files changed, 50 insertions(+), 2 deletions(-) diff --git a/application/editormode.h b/application/editormode.h index 12efab27..7060ab7d 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1920,6 +1920,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri bool plate{false}; bool linked{false}; std::vector speeds; + int aspects{0}; // of a block signal, 3 or 4 }; struct signal_spot { diff --git a/application/editormodesignal.cpp b/application/editormodesignal.cpp index c8181c35..2261dd47 100644 --- a/application/editormodesignal.cpp +++ b/application/editormodesignal.cpp @@ -265,6 +265,8 @@ bool editor_mode::signal_scan(bool const Wait) item.linked = true; } editor_includes::signal_speeds(entry.file, item.speeds); + if (item.kind == "block") + item.aspects = editor_includes::block_aspects(entry.file); tool.templates.push_back(std::move(item)); } std::sort(tool.templates.begin(), tool.templates.end(), [](signal_template const &A, signal_template const &B) { @@ -936,7 +938,7 @@ bool editor_mode::signal_heads(std::vector &Heads, bool const Wait) if (item.lamps.empty()) continue; auto const kind{kind_index(item.kind)}; - Heads.push_back({item.file, item.name, item.kind, item.mount, item.lamps, item.speeds, kind >= 0 && m_signal.chosen[kind] == index}); + Heads.push_back({item.file, item.name, item.kind, item.mount, item.lamps, item.speeds, kind >= 0 && m_signal.chosen[kind] == index, item.aspects}); } return true; } @@ -1072,6 +1074,27 @@ std::size_t editor_mode::signal_batch(signal_changes const &Changes, std::vector if (false == read_before.empty() && false == read_after.empty() && ToLower(read_before) != ToLower(read_after)) signal_renamed(read_before, read_after, step); } + std::unordered_set const created(Created.begin(), Created.end()); + std::vector removed; + for (auto const instance : Changes.removed) + { + if (false == scene::Layers.tracked(instance) || false == scene::Layers.removable(instance) || scene::Layers.instance(instance).removed) + continue; + auto const *standing{signal_standing_of(instance)}; + auto const *item{standing != nullptr ? signal_template_of(standing->include.file) : nullptr}; + std::string file; + std::vector values; + if (item != nullptr && false == item->read.empty() && editor_includes::parse_directive(scene::Layers.directive(instance), file, values)) + { + std::vector> states; + signal_detach_events(editor_includes::substitute(item->read, values), states); + for (auto &state : states) + if (created.count(state.first) == 0 && std::none_of(step.tracks.begin(), step.tracks.end(), [&](auto const &Taken) { return Taken.first == state.first; })) + step.tracks.push_back(std::move(state)); + } + scene::Layers.removed(instance, true); + removed.push_back(instance); + } std::vector instances; if (Error.empty() && false == items.empty()) { @@ -1086,7 +1109,6 @@ std::size_t editor_mode::signal_batch(signal_changes const &Changes, std::vector } else reads.clear(); - std::unordered_set const created(Created.begin(), Created.end()); for (auto const &[spot, read] : reads) { if (read.empty() || false == spot.track->Dynamics.empty() || false == scene::Layers.editable(spot.track)) @@ -1099,6 +1121,7 @@ std::size_t editor_mode::signal_batch(signal_changes const &Changes, std::vector spot.track->mark_dirty(); } auto const count{instances.size()}; + instances.insert(instances.end(), removed.begin(), removed.end()); if (step.tracks.empty() && Created.empty() && instances.empty() && directives.empty()) return 0; if (step.tracks.empty() && Created.empty()) diff --git a/application/editortool.h b/application/editortool.h index 70a8eaef..69114202 100644 --- a/application/editortool.h +++ b/application/editortool.h @@ -116,6 +116,7 @@ struct signal_head std::string lamps; // its chambers from the top: z green, c red, p orange, b white, n blue, x blind std::vector speeds; // of the signal itself, km/h: -1 the highest allowed, 20 the substitute signal bool chosen{false}; // the Signals tool places it for its kind + int aspects{0}; // of a block signal: 3, or 4 with the warning two signals ahead }; // one step of the history of the signalling: signals placed, standing ones renamed, other templates placed with them, the values // of standing ones replaced @@ -126,6 +127,7 @@ struct signal_changes std::vector others; std::vector>> values; std::vector> files; // standing signals given another template, of the same kind, their values kept + std::vector removed; // includes taken away, the signals among them with their read events }; struct nmt_place diff --git a/editor/editorIncludeInfo.cpp b/editor/editorIncludeInfo.cpp index 11092df2..670bd935 100644 --- a/editor/editorIncludeInfo.cpp +++ b/editor/editorIncludeInfo.cpp @@ -537,6 +537,25 @@ bool signal_speeds(std::string const &File, std::vector &Speeds) return true; } +int block_aspects(std::string const &File) +{ + template_text text; + std::string error; + if (false == read_template(File, text, error)) + { + return 0; + } + auto const tokens{tokenize(text.content)}; + for (std::size_t idx = 0; idx + 1 < tokens.size(); ++idx) + { + if (tokens[idx] == "event" && tokens[idx + 1].size() > 3 && tokens[idx + 1].ends_with("_s3")) + { + return 4; + } + } + return 3; +} + void suggest(std::string const &File, include_info &Info) { template_text text; diff --git a/editor/editorIncludeInfo.hpp b/editor/editorIncludeInfo.hpp index d5340c03..09f77daf 100644 --- a/editor/editorIncludeInfo.hpp +++ b/editor/editorIncludeInfo.hpp @@ -71,6 +71,9 @@ int parameter_count(std::string const &File); // the speeds the events of a signal template set it to show, by their SetVelocity: of the signal itself, km/h, -1 the highest // allowed, 20 the substitute signal. returns: false if the file can't be read bool signal_speeds(std::string const &File, std::vector &Speeds); +// the aspects of a block signal of the template: 4 where its events give S3, the green light flashing with the next signal at S5, +// the warning two signals ahead, else 3. returns: 0 if the file can't be read +int block_aspects(std::string const &File); // sets roles of the parameters whose use in the template makes their meaning clear. roles already set are left alone void suggest(std::string const &File, include_info &Info); // true if value of a parameter with specified role is supplied by the editor when the template is placed