diff --git a/application/editormode.h b/application/editormode.h index 7e18f2f5..385b10c5 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1405,6 +1405,8 @@ class editor_mode : public application_mode, private editor_track::observer }; // includes of the templates whose file names the test accepts, with the location in p2..p4 and the rotation in p5 std::vector standing_templates(std::function const &Accept) const; + bool find_switch_drive(TTrack const &Switch, standing_template &Drive, int &Family, int &Index); + bool replace_switch_drive(TTrack &Switch, int Family, bool Flip); // places them in the active layer, as one step of the undo. returns: how many were placed std::size_t place_templates(std::vector const &Items, std::string &Error); // moves them, as one step of the undo diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index 38092bf2..bb2f2d21 100644 --- a/application/editormodeselftest.cpp +++ b/application/editormodeselftest.cpp @@ -427,6 +427,15 @@ void editor_mode::selftest_step() auto const done{track != nullptr && flip_switch_drive(*track)}; WriteLog("SELFTEST driveflip " + name + ": " + (done ? "done " : "failed ") + m_switch.status); } + else if (command == "driveput" || command == "drivefamily") + { + std::string name; + int family{-1}; + words >> name >> family; + auto *track{simulation::Paths.find(name)}; + auto const done{track != nullptr && (command == "driveput" ? place_switch_drive(*track) : replace_switch_drive(*track, family, false))}; + WriteLog("SELFTEST " + command + " " + name + ": " + (done ? "done " : "failed ") + m_switch.status); + } else if (command == "drivetilt") { std::string name; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index fed57e3a..3d67dd99 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -1926,13 +1926,34 @@ void editor_mode::render_turnout_ui() ImGui::Text(STR_C("Length %.3f m, diverging %s, end offset %.3f m"), length, offset > 0.0 ? STR_C("right") : STR_C("left"), std::abs(offset)); render_track_name(*track); render_switch_record(*track); - if ((simulation::Events.FindEvent(track->name() + "+") != nullptr && simulation::Events.FindEvent(track->name() + "-") != nullptr) || (m_track_name.track == track && m_track_name.uses.includes > 0)) + standing_template drive; + int family{-1}; + int variant{0}; + if (find_switch_drive(*track, drive, family, variant)) { ImGui::TextDisabled(STR_C("Drive: events %s+ and %s- switch it, also in the map"), track->name().c_str(), track->name().c_str()); - if (ImGui::Button(STR_C("Drive to the other side"))) + ImGui::PushItemWidth(200.0f); + if (ImGui::BeginCombo(STR_C("Drive##standing"), m_switch.drives[family].name.c_str())) + { + for (int i = 0; i < static_cast(m_switch.drives.size()); ++i) + if (ImGui::Selectable(m_switch.drives[i].name.c_str(), family == i) && i != family) + replace_switch_drive(*track, i, false); + ImGui::EndCombo(); + } + ImGui::PopItemWidth(); + item_tooltip("Puts another drive in place of the drive of this switch, on the same side"); + int side{((variant >> 1) == (variant & 1)) ? 0 : 1}; + ImGui::SameLine(); + auto const before{side}; + ImGui::RadioButton(STR_C("diverging side##standing"), &side, 0); + ImGui::SameLine(); + ImGui::RadioButton(STR_C("other side##standing"), &side, 1); + if (side != before) flip_switch_drive(*track); item_tooltip("Puts the drive of the switch on the other side of the track: the same drive, its variant for the other side"); } + else if ((simulation::Events.FindEvent(track->name() + "+") != nullptr && simulation::Events.FindEvent(track->name() + "-") != nullptr) || (m_track_name.track == track && m_track_name.uses.includes > 0)) + ImGui::TextDisabled(STR_C("Drive: events %s+ and %s- switch it, also in the map"), track->name().c_str(), track->name().c_str()); else { ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.2f, 1.0f), "%s", STR_C("No drive: the switch can't be switched during the game")); @@ -6666,6 +6687,11 @@ bool editor_mode::place_switch_drive(TTrack &Switch) if (Global.bRollFix) item.location.y += 0.75 * std::abs(std::sin(glm::radians(roll))); } + standing_template standing; + int present{-1}; + int variant{0}; + if (find_switch_drive(Switch, standing, present, variant)) + return replace_switch_drive(Switch, tool.drive, (variant & 1) != (driveright ? 1 : 0)); std::string error; if (place_templates({item}, error) == 0) { @@ -6676,15 +6702,21 @@ bool editor_mode::place_switch_drive(TTrack &Switch) return true; } -bool editor_mode::flip_switch_drive(TTrack &Switch) +namespace +{ +std::string drive_file(std::string Text) +{ + std::replace(Text.begin(), Text.end(), '\\', '/'); + std::transform(Text.begin(), Text.end(), Text.begin(), [](unsigned char Character) { return static_cast(std::tolower(Character)); }); + return Text; +} +} // namespace + +bool editor_mode::find_switch_drive(TTrack const &Switch, standing_template &Drive, int &Family, int &Index) { auto &tool{m_switch}; scan_switch_drives(); - auto const plain = [](std::string Text) { - std::replace(Text.begin(), Text.end(), '\\', '/'); - std::transform(Text.begin(), Text.end(), Text.begin(), [](unsigned char Character) { return static_cast(std::tolower(Character)); }); - return Text; - }; + auto const &plain{drive_file}; std::map> variants; for (int family = 0; family < static_cast(tool.drives.size()); ++family) for (int index = 0; index < 4; ++index) @@ -6692,32 +6724,55 @@ bool editor_mode::flip_switch_drive(TTrack &Switch) variants[plain(tool.drives[family].files[index])] = {family, index}; auto const name{plain(Switch.name())}; auto const standing{standing_templates([&](std::string const &File) { return variants.count(File) > 0; })}; - auto const found{std::find_if(standing.begin(), standing.end(), [&](standing_template const &Drive) { return plain(Drive.values[0]) == name; })}; + auto const found{std::find_if(standing.begin(), standing.end(), [&](standing_template const &Standing) { return plain(Standing.values[0]) == name; })}; if (found == standing.end()) + return false; + Drive = *found; + std::tie(Family, Index) = variants[found->file]; + return true; +} + +bool editor_mode::flip_switch_drive(TTrack &Switch) +{ + return replace_switch_drive(Switch, -1, true); +} + +bool editor_mode::replace_switch_drive(TTrack &Switch, int const Family, bool const Flip) +{ + auto &tool{m_switch}; + standing_template found; + int family{-1}; + int index{0}; + if (false == find_switch_drive(Switch, found, family, index)) { tool.status = format(STR_C("No drive of the switch %s among the described drives"), Switch.name().c_str()); return false; } - auto const [family, index]{variants[found->file]}; + if (Family >= 0) + family = Family; + if (Flip) + index ^= 1; template_item item; - item.file = tool.drives[family].files[index ^ 1]; + item.file = tool.drives[family].files[index]; if (item.file.empty()) { - tool.status = format(STR_C("The drive %s has no variant with the drive on the other side"), tool.drives[family].name.c_str()); + tool.status = Flip ? format(STR_C("The drive %s has no variant with the drive on the other side"), tool.drives[family].name.c_str()) : format(STR_C("The drive %s has no variant for a %s switch with the drive on the %s"), tool.drives[family].name.c_str(), index & 2 ? STR_C("right") : STR_C("left"), index & 1 ? STR_C("right") : STR_C("left")); return false; } - item.location = found->location; - item.yaw = found->yaw; + if (drive_file(item.file) == found.file) + return false; + item.location = found.location; + item.yaw = found.yaw; item.described = true; item.track = Switch.name(); auto const angle = [&](std::size_t const Index) { double value{0.0}; - if (Index < found->values.size()) - std::sscanf(found->values[Index].c_str(), "%lf", &value); + if (Index < found.values.size()) + std::sscanf(found.values[Index].c_str(), "%lf", &value); return value; }; item.tilt = {angle(5), angle(6)}; - if (remove_templates({found->instance}) == 0) + if (remove_templates({found.instance}) == 0) { tool.status = STR_C("The drive of this switch can't be changed in its file"); return false; @@ -6725,13 +6780,13 @@ bool editor_mode::flip_switch_drive(TTrack &Switch) std::string error; if (place_templates({item}, error) == 0) { - scene::Layers.removed(found->instance, false); + scene::Layers.removed(found.instance, false); m_history.pop_back(); tool.status = STR_C("The drive couldn't be placed: ") + error; return false; } join_last_steps(); - tool.status = format((index ^ 1) & 1 ? STR_C("Switch %s: the drive %s, on the right now") : STR_C("Switch %s: the drive %s, on the left now"), Switch.name().c_str(), item.file.c_str()); + tool.status = format(index & 1 ? STR_C("Switch %s: the drive %s, on the right now") : STR_C("Switch %s: the drive %s, on the left now"), Switch.name().c_str(), item.file.c_str()); return true; } diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 05d5bfca..d2b44bda 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -5422,8 +5422,17 @@ msgstr "Miejsce na prostej: %.2f m do tyłu, %.2f m do przodu" msgid "Click: edit this switch, drag: slide it along the straight" msgstr "Klik: edytuj ten rozjazd, przeciągnij: przesuń go wzdłuż prostej" -msgid "Drive to the other side" -msgstr "Napęd na drugą stronę" +msgid "Drive##standing" +msgstr "Napęd##standing" + +msgid "Puts another drive in place of the drive of this switch, on the same side" +msgstr "Stawia inny napęd w miejsce napędu tej zwrotnicy, po tej samej stronie" + +msgid "diverging side##standing" +msgstr "od toru zwrotnego##standing" + +msgid "other side##standing" +msgstr "z drugiej strony##standing" msgid "Puts the drive of the switch on the other side of the track: the same drive, its variant for the other side" msgstr "Stawia napęd zwrotnicy po drugiej stronie toru: ten sam napęd, jego wariant na drugą stronę" @@ -5442,3 +5451,4 @@ msgstr "Zwrotnica %s: napęd %s, teraz po prawej" msgid "Switch %s: the drive %s, on the left now" msgstr "Zwrotnica %s: napęd %s, teraz po lewej" + diff --git a/tools/editor/drive_headers.py b/tools/editor/drive_headers.py index 2f550917..7c95a0f9 100644 --- a/tools/editor/drive_headers.py +++ b/tools/editor/drive_headers.py @@ -16,7 +16,7 @@ LINEMARK = '//$e' FOLDER = 'scenery/tory/napedy' PATTERN = re.compile(r'^(ele1?|mech[12]?)-rz([lp])-([lp])((?:_[a-z]+)*)\.inc$') KINDS = {'ele': 'elektryczny', 'mech': 'mechaniczny'} -DEFAULT = 'mech_komin' +DEFAULT = 'ele' def examine(path, file):