diff --git a/application/editormode.cpp b/application/editormode.cpp index 8b31acf4..a8a92811 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -3058,7 +3058,12 @@ void editor_mode::select_include(scene::instance_handle const Instance) void editor_mode::set_include_directive(scene::instance_handle const Instance, std::string const &Directive) { - if (false == scene::Layers.modify(Instance, Directive)) + std::string file; + std::vector values; + if (scene::Layers.tracked(Instance) && editor_includes::parse_directive(Directive, file, values) && scene::Layers.instance(Instance).file != nullptr && + editor_includes::normalized(file) == editor_includes::normalized(*scene::Layers.instance(Instance).file)) + file.clear(); + if (false == scene::Layers.modify(Instance, Directive, file)) return; std::vector retired; simulation::State.rebuild_include(Instance, retired); diff --git a/application/editormode.h b/application/editormode.h index 86e8b72d..0205ff72 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -1796,8 +1796,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri std::string read; TTrack *track{nullptr}; int list{0}; - signal_spot spot; - bool on_track{false}; }; struct signal_tool { @@ -1821,6 +1819,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri int hover{-1}; scene::instance_handle selected{0}; bool moving{false}; + glm::dvec2 grab{0.0}; + signal_spot home; + bool home_valid{false}; signal_spot moved; bool moved_valid{false}; std::string status; @@ -1836,7 +1837,12 @@ class editor_mode : public application_mode, private editor_track::observer, pri void signal_release(); bool signal_place(signal_spot const &Spot, signal_template const &Template); void signal_move_update(); - void signal_move_finish(); + bool signal_standing_spot(signal_standing const &Standing, signal_spot &Spot) const; + bool signal_drop_at(signal_standing const &Standing, TTrack &Track, int const Path, glm::dvec3 const &Point, int const Side, signal_spot &Spot) const; + 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); + 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); void signal_renamed(std::string const &Before, std::string const &After, EditorSnapshot &Snapshot); diff --git a/application/editormodeselftestsignal.cpp b/application/editormodeselftestsignal.cpp index fe64c7ef..db7c1624 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") + if (command == "signal" || command == "signalmove" || command == "signaldelete" || command == "signalrename" || command == "signalprobe" || command == "signalflip" || command == "signalturn") { auto values{selftest_values(words)}; show_track_tab(track_tab::signals); @@ -107,29 +107,40 @@ editor_mode::selftest_result editor_mode::selftest_signal(std::string const &com else if (command == "signalmove") { auto const *standing{standing_named(values["name"])}; - auto const *item{standing != nullptr ? signal_template_of(standing->include.file) : nullptr}; - if (item == nullptr) + auto *track{simulation::Paths.find(values["track"])}; + if (standing == nullptr || track == nullptr || track->m_paths.empty()) { - WriteLog("SELFTEST signalmove: no signal " + values["name"]); + WriteLog("SELFTEST signalmove: no signal " + values["name"] + " or no track " + values["track"]); return selftest_result::handled; } - auto const yaw{glm::radians(standing->include.yaw + 180.0)}; - glm::dvec2 const travel{std::sin(yaw), std::cos(yaw)}; - signal_spot probe; - if (false == spot_on(*item, 1, 1, probe)) + auto const path{std::clamp(values.count("path") ? std::stoi(values["path"]) : 0, 0, static_cast(track->m_paths.size()) - 1)}; + auto const at{values.count("at") ? std::stod(values["at"]) : 0.5}; + geometry::bezier const curve{track->m_paths[path]}; + auto point{curve.point(at)}; + auto const sided{values.count("side") != 0}; + auto side{values["side"] == "left" ? -1 : 1}; + if (values.count("off")) { - WriteLog("SELFTEST signalmove: no such track " + values["track"]); - return selftest_result::handled; + auto const tangent{glm::normalize(glm::dvec2{curve.first(at).x, curve.first(at).z})}; + auto const off{std::stod(values["off"])}; + point += glm::dvec3{-tangent.y * off, 0.0, tangent.x * off}; + side = 0; } - auto const facing{glm::dot(probe.travel, travel) >= 0.0 ? 1 : -1}; - auto const sideoftravel{glm::dot(geometry::plan_of(standing->include.location) - geometry::plan_of(standing->spot.axis), glm::dvec2{-travel.y, travel.x}) >= 0.0 ? 1 : -1}; + else if (signal_spot home; false == sided && signal_standing_spot(*standing, home)) + side = home.side * (home.list == 2 ? 1 : -1); signal_select(standing->include.instance); tool.moving = true; - tool.moved_valid = spot_on(*item, facing, sideoftravel * facing, tool.moved); + tool.moved_valid = signal_drop_at(*standing, *track, path, point, side, tool.moved); tool.pressed = {-1000.f, -1000.f}; signal_release(); WriteLog("SELFTEST signalmove: " + tool.status); } + else if (command == "signalflip" || command == "signalturn") + { + auto const *standing{standing_named(values["name"])}; + 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 == "signaldelete") { auto const *standing{standing_named(values["name"])}; diff --git a/application/editormodesignal.cpp b/application/editormodesignal.cpp index e9d04354..2e3928a8 100644 --- a/application/editormodesignal.cpp +++ b/application/editormodesignal.cpp @@ -46,6 +46,7 @@ float const kSignalPick{12.0f}; float const kDragStart{6.0f}; double const kDragTravel{1.0}; double const kRefreshPeriod{2.0}; +double const kSignalReach{10.0}; char const *const kKinds[] = {"main", "block", "warning", "shunt", "stop", "substitute", "repeater"}; char const *const kKindLabels[] = {"Semaphore", "Automatic block", "Warning signal", "Shunting signal", "Stop signal", "Substitute signal", "Repeater"}; @@ -88,6 +89,17 @@ glm::dvec2 right_of(glm::dvec2 const &Direction) return {-Direction.y, Direction.x}; } +glm::dvec2 travel_of(double const Yaw) +{ + auto const yaw{glm::radians(Yaw + 180.0)}; + return {std::sin(yaw), std::cos(yaw)}; +} + +int travel_side(int const Side, int const List) +{ + return Side * (List == 2 ? 1 : -1); +} + int lean_wanted(int const Side) { return Side > 0 ? 1 : 2; @@ -430,9 +442,12 @@ void editor_mode::signal_press(track_intent const &Intent) { if (Intent.index < 0 || Intent.index >= static_cast(tool.standing.size())) return; - signal_select(tool.standing[Intent.index].include.instance); + auto const &standing{tool.standing[Intent.index]}; + tool.grab = plan_of(standing.include.location) - plan_of(cursor_level(standing.include.location.y)); + tool.home_valid = signal_standing_spot(standing, tool.home); tool.moving = true; tool.moved_valid = false; + signal_select(standing.include.instance); return; } auto const *armed{signal_armed()}; @@ -473,39 +488,84 @@ void editor_mode::signal_move_update() return; if (false == dragged) return; - auto const found{std::find_if(tool.standing.begin(), tool.standing.end(), [&](signal_standing const &Standing) { return Standing.include.instance == tool.selected; })}; - if (found == tool.standing.end()) + auto const *found{signal_standing_of(tool.selected)}; + if (found == nullptr) { tool.moved_valid = false; return; } - // the track under the cursor; off every track, as it is when the signal is dragged beside its track, the place of the - // track the signal stands by nearest the cursor + auto const &location{found->include.location}; + auto const cursor{cursor_level(location.y)}; + glm::dvec3 const held{cursor.x + tool.grab.x, location.y, cursor.z + tool.grab.y}; + // the track under the cursor; off every track, as it is when the signal is dragged beside its track, the track the + // signal stands by auto *track{m_hover.track}; auto path{m_hover.path}; - auto point{m_hover.point}; - if (track == nullptr && found->track != nullptr && false == found->track->m_editorremoved && false == found->track->m_paths.empty()) + if (track == nullptr && tool.home_valid) { - track = found->track; - path = std::clamp(found->spot.path, 0, static_cast(track->m_paths.size()) - 1); - point = bezier{track->m_paths[path]}.point(nearest_on(*track, path, cursor_level(found->spot.axis.y))); + track = tool.home.track; + path = tool.home.path; } + tool.moved_valid = track != nullptr && signal_drop_at(*found, *track, path, held, 0, tool.moved); +} + +editor_mode::signal_standing const *editor_mode::signal_standing_of(scene::instance_handle const Instance) const +{ + auto const &standing{m_signal.standing}; + auto const found{std::find_if(standing.begin(), standing.end(), [&](signal_standing const &Standing) { return Standing.include.instance == Instance; })}; + return found != standing.end() ? &*found : nullptr; +} + +bool editor_mode::signal_drop_at(signal_standing const &Standing, TTrack &Track, int const Path, glm::dvec3 const &Point, int const Side, signal_spot &Spot) const +{ + auto const *item{signal_template_of(Standing.include.file)}; + if (item == nullptr || Track.m_paths.empty() || Track.m_editorremoved) + return false; + auto const path{std::clamp(Path, 0, static_cast(Track.m_paths.size()) - 1)}; + auto const forward{forward_at(Track, path, nearest_on(Track, path, Point))}; + auto const facing{glm::dot(forward, travel_of(Standing.include.yaw)) >= 0.0 ? 1 : -1}; + return signal_spot_at(Track, path, Point, Point, facing, Side * facing, *item, Spot); +} + +bool editor_mode::signal_standing_spot(signal_standing const &Standing, signal_spot &Spot) const +{ + auto const &location{Standing.include.location}; + TTrack *track{nullptr}; + int path{0}; + auto best{kSignalReach}; + auto const consider = [&](TTrack *Track) { + if (Track == nullptr || Track->m_editorremoved) + return; + for (int p = 0; p < static_cast(Track->m_paths.size()); ++p) + { + bezier const curve{Track->m_paths[p]}; + auto const low{glm::min(glm::min(plan_of(curve.p0), plan_of(curve.p1)), glm::min(plan_of(curve.p2), plan_of(curve.p3)))}; + auto const high{glm::max(glm::max(plan_of(curve.p0), plan_of(curve.p1)), glm::max(plan_of(curve.p2), plan_of(curve.p3)))}; + if (glm::length(glm::max(glm::max(low - plan_of(location), plan_of(location) - high), glm::dvec2{0.0})) >= best) + continue; + auto const distance{geometry::plan_distance(curve.point(nearest_on(*Track, p, location)), location)}; + if (distance < best) + { + best = distance; + track = Track; + path = p; + } + } + }; + consider(Standing.track); if (track == nullptr) - { - tool.moved_valid = false; - return; - } - auto const *item{signal_template_of(found->include.file)}; - if (item == nullptr) - return; - path = std::clamp(path, 0, static_cast(track->m_paths.size()) - 1); - auto const yaw{glm::radians(found->include.yaw + 180.0)}; - glm::dvec2 const travel{std::sin(yaw), std::cos(yaw)}; - auto const parameter{nearest_on(*track, path, point)}; - auto const forward{forward_at(*track, path, parameter)}; - auto const facing{glm::dot(forward, travel) >= 0.0 ? 1 : -1}; - auto const sideoftravel{glm::dot(plan_of(found->include.location) - plan_of(point), right_of(travel)) >= 0.0 ? 1 : -1}; - tool.moved_valid = signal_spot_at(*track, path, point, point, facing, sideoftravel * facing, *item, tool.moved); + for (auto *candidate : simulation::Paths.sequence()) + consider(candidate); + if (track == nullptr) + return false; + auto const axis{bezier{track->m_paths[path]}.point(nearest_on(*track, path, location))}; + auto const side{glm::dot(plan_of(location) - plan_of(axis), right_of(travel_of(Standing.include.yaw))) >= 0.0 ? 1 : -1}; + if (false == signal_drop_at(Standing, *track, path, location, side, Spot)) + return false; + Spot.offset = geometry::plan_distance(location, axis); + Spot.position = location; + Spot.yaw = Standing.include.yaw; + return true; } void editor_mode::signal_release() @@ -530,40 +590,53 @@ void editor_mode::signal_release() return; } tool.moved_valid = false; - auto const found{std::find_if(tool.standing.begin(), tool.standing.end(), [&](signal_standing const &Standing) { return Standing.include.instance == tool.selected; })}; - if (found == tool.standing.end()) - return; - if (false == scene::Layers.tracked(found->include.instance) || false == scene::Layers.removable(found->include.instance)) + if (auto const *found{signal_standing_of(tool.selected)}) + signal_move_to(*found, tool.moved, STR_C("Signal %s moved, read by %s %s of %s, Ctrl+Z takes it back"), STR_C("Signal %s moved, Ctrl+Z takes it back")); +} + +bool editor_mode::signal_move_to(signal_standing const &Standing, signal_spot const &Spot, char const *Read, char const *Unread) +{ + auto &tool{m_signal}; + auto const instance{Standing.include.instance}; + if (false == scene::Layers.tracked(instance) || false == scene::Layers.removable(instance)) { tool.status = STR_C("This signal is in a file the editor doesn't change, it can't be moved"); - return; + return false; } - auto const &spot{tool.moved}; - auto const &included{scene::Layers.instance(found->include.instance)}; - auto values{found->include.values}; - auto const local{spot.position - included.context.offset}; + auto const &included{scene::Layers.instance(instance)}; + auto file{*included.file}; + signal_spot before; + auto const *item{signal_template_of(Standing.include.file)}; + if (item != nullptr && signal_standing_spot(Standing, before) && travel_side(before.side, before.list) != travel_side(Spot.side, Spot.list)) + file = signal_variant(*item, Spot); + auto values{Standing.include.values}; + auto const local{Spot.position - included.context.offset}; values[1] = editor_includes::number(local.x); values[2] = editor_includes::number(local.y); values[3] = editor_includes::number(local.z); - values[4] = editor_includes::number(spot.yaw); - auto before{scene::Layers.directive(found->include.instance)}; + values[4] = editor_includes::number(Spot.yaw); + auto const *next{signal_template_of(file)}; + auto const read{next != nullptr && false == next->read.empty() ? editor_includes::substitute(next->read, values) : Standing.read}; + auto directive{scene::Layers.directive(instance)}; std::vector> states; - if (false == found->read.empty() && spot.track->Dynamics.empty()) + if (false == Standing.read.empty() && Spot.track->Dynamics.empty()) { - signal_detach_events(found->read, states); - if (std::none_of(states.begin(), states.end(), [&](auto const &State) { return State.first == spot.track; })) - states.emplace_back(spot.track, editor_track::capture(*spot.track)); - editor_track::events(*spot.track, spot.list).emplace_back(ToLower(found->read), nullptr); + signal_detach_events(Standing.read, states); + if (std::none_of(states.begin(), states.end(), [&](auto const &State) { return State.first == Spot.track; })) + states.emplace_back(Spot.track, editor_track::capture(*Spot.track)); + editor_track::events(*Spot.track, Spot.list).emplace_back(ToLower(read), nullptr); std::string missing; - editor_track::bind_events(*spot.track, missing); - spot.track->mark_dirty(); + editor_track::bind_events(*Spot.track, missing); + Spot.track->mark_dirty(); } - set_include_directive(found->include.instance, editor_includes::compose_directive(*included.file, values)); + auto const name{Standing.name}; + auto const node{Standing.include.file}; + set_include_directive(instance, editor_includes::compose_directive(file, values)); if (states.empty()) { EditorSnapshot snap; - snap.directives.emplace_back(found->include.instance, std::move(before)); - snap.node_name = found->include.file; + snap.directives.emplace_back(instance, std::move(directive)); + snap.node_name = node; trim_history(); m_history.push_back(std::move(snap)); g_redo.clear(); @@ -571,13 +644,47 @@ void editor_mode::signal_release() else { push_track_snapshot(std::move(states)); - m_history.back().directives.emplace_back(found->include.instance, std::move(before)); + m_history.back().directives.emplace_back(instance, std::move(directive)); } - tool.status = found->read.empty() ? format(STR_C("Signal %s moved, Ctrl+Z takes it back"), found->name.c_str()) - : format(STR_C("Signal %s moved, read by %s %s of %s, Ctrl+Z takes it back"), found->name.c_str(), editor_track::event_keyword(spot.list), found->read.c_str(), name_of(*spot.track).c_str()); - auto const instance{found->include.instance}; signal_refresh(true); signal_select(instance); + auto const *moved{signal_standing_of(instance)}; + tool.status = moved != nullptr && moved->track != nullptr ? format(Read, name.c_str(), editor_track::event_keyword(moved->list), moved->read.c_str(), name_of(*moved->track).c_str()) : format(Unread, name.c_str()); + return true; +} + +bool editor_mode::signal_flip(scene::instance_handle const Instance) +{ + auto const *standing{signal_standing_of(Instance)}; + signal_spot spot; + if (standing == nullptr || false == signal_standing_spot(*standing, spot)) + { + m_signal.status = STR_C("No track by the signal to take it across"); + return false; + } + auto const across{plan_of(spot.position) - plan_of(spot.axis)}; + auto const mirrored{plan_of(spot.axis) + spot.travel * glm::dot(across, spot.travel) - right_of(spot.travel) * glm::dot(across, right_of(spot.travel))}; + spot.side = -spot.side; + spot.position = {mirrored.x, spot.position.y, mirrored.y}; + return signal_move_to(*standing, spot, STR_C("Signal %s moved to the other side of the track, read by %s %s of %s, Ctrl+Z takes it back"), STR_C("Signal %s moved to the other side of the track, Ctrl+Z takes it back")); +} + +bool editor_mode::signal_turn(scene::instance_handle const Instance) +{ + auto const *standing{signal_standing_of(Instance)}; + signal_spot spot; + if (standing == nullptr || false == signal_standing_spot(*standing, spot)) + { + m_signal.status = STR_C("No track by the signal to turn it to"); + return false; + } + auto const *item{signal_template_of(standing->include.file)}; + auto const position{spot.position}; + if (item == nullptr || false == signal_spot_at(*spot.track, spot.path, spot.axis, spot.axis, spot.list == 2 ? -1 : 1, spot.side, *item, spot)) + return false; + spot.position = position; + spot.yaw = std::fmod(standing->include.yaw + 180.0, 360.0); + 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")); } std::string editor_mode::signal_variant(signal_template const &Template, signal_spot const &Spot) const @@ -876,9 +983,8 @@ void editor_mode::render_signal_palette() void editor_mode::render_signal_selected() { - auto &tool{m_signal}; - auto const found{std::find_if(tool.standing.begin(), tool.standing.end(), [&](signal_standing const &Standing) { return Standing.include.instance == tool.selected; })}; - if (found == tool.standing.end()) + auto const *found{signal_standing_of(m_signal.selected)}; + if (found == nullptr) return; ImGui::Separator(); ImGui::TextUnformatted(format(STR_C("Selected: %s (%s)"), found->name.c_str(), found->include.file.c_str()).c_str()); @@ -889,6 +995,15 @@ void editor_mode::render_signal_selected() ImGui::TextDisabled(STR_C("Read by %s %s of %s"), editor_track::event_keyword(found->list), found->read.c_str(), name_of(*found->track).c_str()); 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}; + 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); + item_tooltip("Takes the signal across the track, it keeps facing the same trains. Dragging it over the track does the same"); + ImGui::SameLine(); + if (ImGui::Button(STR_C("Turn around"), ImVec2(width, 0.0f))) + signal_turn(instance); + item_tooltip("Turns the signal to the trains of the other direction, they read it by the other event of the path"); } void editor_mode::render_signal_ui() @@ -1038,10 +1153,7 @@ void editor_mode::draw_signal_overlay() const drawlist->AddText(ImVec2(head.x + 6.0f, head.y - 6.0f), colour, label.c_str()); } if (selected || hovered) - { - auto const yaw{glm::radians(standing.include.yaw + 180.0)}; - arrow(location, glm::dvec2{std::sin(yaw), std::cos(yaw)}, colour); - } + arrow(location, travel_of(standing.include.yaw), colour); } auto const preview = [&](signal_spot const &Spot, ImU32 const Colour) { projection.line(drawlist, Spot.axis + glm::dvec3{0.0, kRailTop, 0.0}, Spot.position, Colour, 2.0f); diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index 45ba31c8..73abd640 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -1641,8 +1641,10 @@ std::vector editor_mode::track_key_hints(bool const All) hints = {{"LMB on a track", "the line the objects go along"}}; else if (m_track_window_open && m_track_tab == track_tab::parallel) hints = {{"LMB on a track", "the new track goes beside it"}, {"Click on a side in the panel", "the side of the new track"}}; - else if (m_track_window_open && m_track_tab == track_tab::signals && (m_signal.placing || m_signal.moving)) - hints = {{"Drag along", m_signal.moving ? "moves the signal along the track" : "the trains it faces run that way"}, {"Release", "done"}, {"Esc", "cancel"}}; + else if (m_track_window_open && m_track_tab == track_tab::signals && m_signal.moving) + hints = {{"Drag along", "moves the signal along the track"}, {"Drag over the track", "to the other side"}, {"Release", "done"}, {"Esc", "cancel"}}; + else if (m_track_window_open && m_track_tab == track_tab::signals && m_signal.placing) + hints = {{"Drag along", "the trains it faces run that way"}, {"Release", "done"}, {"Esc", "cancel"}}; else if (m_track_window_open && m_track_tab == track_tab::signals && signal_armed() == nullptr) hints = {{"List in the panel", "the type of the signal"}, {"Drag a signal", "moves it along the track"}, {"LMB on a signal", "selects it"}}; else if (m_track_window_open && m_track_tab == track_tab::signals) diff --git a/lang/editor_pl.po b/lang/editor_pl.po index bd6fef78..0defa02f 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -9955,3 +9955,36 @@ msgstr "Gdy tor wychodzi poza teren, NMT dobudowuje się wokół kursora na bie msgid "The ends have to be numbers, from 0.1 m to 100 km apart" msgstr "Końce muszą być liczbami, od 0,1 m do 100 km od siebie" + +msgid "To the other side" +msgstr "Na drugą stronę" + +msgid "Takes the signal across the track, it keeps facing the same trains. Dragging it over the track does the same" +msgstr "Przenosi sygnalizator na drugą stronę toru, dalej stoi przodem do tych samych pociągów. To samo robi przeciągnięcie go przez tor" + +msgid "Turns the signal to the trains of the other direction, they read it by the other event of the path" +msgstr "Obraca sygnalizator do pociągów z przeciwnego kierunku, odczytują go przez drugi event toru" + +msgid "No track by the signal to take it across" +msgstr "Przy sygnalizatorze nie ma toru, na którego drugą stronę można go przenieść" + +msgid "No track by the signal to turn it to" +msgstr "Przy sygnalizatorze nie ma toru, do którego można go obrócić" + +msgid "Signal %s moved to the other side of the track, read by %s %s of %s, Ctrl+Z takes it back" +msgstr "Sygnalizator %s przeniesiony na drugą stronę toru, pociąg odczytuje go przez %s %s toru %s, Ctrl+Z cofa" + +msgid "Signal %s moved to the other side of the track, Ctrl+Z takes it back" +msgstr "Sygnalizator %s przeniesiony na drugą stronę toru, Ctrl+Z cofa" + +msgid "Signal %s turned to the trains of the other direction, read by %s %s of %s, Ctrl+Z takes it back" +msgstr "Sygnalizator %s obrócony do pociągów z przeciwnego kierunku, pociąg odczytuje go przez %s %s toru %s, Ctrl+Z cofa" + +msgid "Signal %s turned to the trains of the other direction, Ctrl+Z takes it back" +msgstr "Sygnalizator %s obrócony do pociągów z przeciwnego kierunku, Ctrl+Z cofa" + +msgid "Drag over the track" +msgstr "Przeciągnij przez tor" + +msgid "to the other side" +msgstr "na drugą stronę" diff --git a/scene/scenelayers.cpp b/scene/scenelayers.cpp index 4edc1033..561ccdd0 100644 --- a/scene/scenelayers.cpp +++ b/scene/scenelayers.cpp @@ -1090,13 +1090,17 @@ std::string node_layers::directive(instance_handle const Instance) const } // replaces the directive of specified include, the scenery file receives it on save -bool node_layers::modify(instance_handle const Instance, std::string const &Directive) +bool node_layers::modify(instance_handle const Instance, std::string const &Directive, std::string const &File) { if (false == tracked(Instance) || m_instances[Instance - 1].dead || Directive.empty()) { return false; } m_instances[Instance - 1].directive = Directive; + if (false == File.empty()) + { + m_instances[Instance - 1].file = &(*m_templates.emplace(File).first); + } return true; } diff --git a/scene/scenelayers.h b/scene/scenelayers.h index daf3c587..1eb2e4d5 100644 --- a/scene/scenelayers.h +++ b/scene/scenelayers.h @@ -335,7 +335,7 @@ class node_layers // returns: empty text if the directive can't be read std::string directive(instance_handle Instance) const; // replaces the directive of specified include, the scenery file receives it on save. NOTE: the nodes aren't touched - bool modify(instance_handle Instance, std::string const &Directive); + bool modify(instance_handle Instance, std::string const &Directive, std::string const &File = {}); // takes the models specified include was loaded with out of the scene, once the editor shows its own in their place void rebuilt(instance_handle Instance); // true if specified node was replaced by the editor with a node showing the current state of its include