17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-27 22:17:28 +01:00

feat(editor): the Signals tool goes into the signalling one: its templates under Signals in the SRK panel, the ones the station's signals are placed with too; a click on a tile or Place by a track arms placing, Esc or a click on the armed tile stops it, a click on a track else opening its station; a signal picked in 3D or in Signal heads shows its card at the top of the panel, its template, to the other side, turn around; H no longer a tool

This commit is contained in:
maj00r
2026-10-23 12:26:07 +02:00
parent 2d9be3ae10
commit eab3dca700
12 changed files with 168 additions and 119 deletions

View File

@@ -1502,7 +1502,7 @@ bool editor_mode::update()
draw_switch_slide();
if (m_track_tab == track_tab::turntable)
draw_turntable_overlay();
if (m_track_tab == track_tab::signals)
if (m_track_tab == track_tab::srk)
{
signal_refresh();
signal_move_update();
@@ -5232,7 +5232,7 @@ void editor_mode::render_first_steps()
trial::turnout},
{"Signals and posts",
nullptr,
{{"H", "The signals tool: the type of the signal in the panel, from the templates of the scenery"},
{{"I", "The signalling tool: click a type of signal in its Signals, from the templates of the scenery"},
{"LMB", "A click by a track places the signal on that side"},
{"LMB + move", "Press by the track and drag along it: the trains running that way see the signal"},
{"LMB + move", "Drag a standing signal: it moves along its track"},
@@ -5382,11 +5382,11 @@ void editor_mode::render_first_steps()
}
case trial::signals:
{
ImGui::BeginDisabled(ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::signals);
if (ImGui::Button(STR_C("The signals tool (H)")))
ImGui::BeginDisabled(ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::srk);
if (ImGui::Button(STR_C("The signalling tool (I)")))
{
choose_work_area(work_area::tracks);
show_track_tab(track_tab::signals);
show_track_tab(track_tab::srk);
}
ImGui::EndDisabled();
break;
@@ -5657,7 +5657,7 @@ void editor_mode::render_gizmo_options()
if (ImGui::IsItemHovered())
ImGui::SetTooltip("%s", STR_C("Off: the top view draws the rails and sleepers of the tracks without the ballast, so the ground under them shows"));
}
if (ui()->mode() == nodebank_panel::TRACK && m_track_tab != track_tab::path && m_track_tab != track_tab::turnout && m_track_tab != track_tab::turntable && m_track_tab != track_tab::signals &&
if (ui()->mode() == nodebank_panel::TRACK && m_track_tab != track_tab::path && m_track_tab != track_tab::turnout && m_track_tab != track_tab::turntable && m_track_tab != track_tab::srk &&
m_track_tab != track_tab::lineside)
return;
int op{m_gizmo_enabled ? static_cast<int>(m_gizmo_op) : -1};
@@ -5911,7 +5911,7 @@ void editor_mode::render_include_gizmo(glm::mat4 const &View, glm::mat4 const &P
// in the signal tool a press on the mast drags the signal along its track: the gizmo, whose up axis runs along the
// mast, gives way over a signal and while one is dragged
auto const yield{ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::signals && false == ImGuizmo::IsUsing() && (m_signal.moving || m_signal.placing || signal_hit() >= 0)};
auto const yield{ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::srk && false == ImGuizmo::IsUsing() && (m_signal.moving || m_signal.placing || signal_hit() >= 0)};
ImGuizmo::Enable(false == yield);
ImGuizmo::Manipulate(glm::value_ptr(View), glm::value_ptr(Projection), static_cast<ImGuizmo::OPERATION>(operation), mode, glm::value_ptr(matrix), nullptr, snap);
ImGuizmo::Enable(true);
@@ -6505,6 +6505,8 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in
cancel_track_tools();
m_straights.tool = 0;
}
else if (m_track_tab == track_tab::srk && m_signal.armed)
m_signal.armed = false;
else if (m_track_tab == track_tab::path && m_track_set.size() >= 2)
select_tracks({});
else if (m_track_tab != track_tab::path)

View File

@@ -1557,7 +1557,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
editor_icons::icon picture;
int family; // 0 builds the track, 1 equips it, 2 checks it
};
static std::array<track_mode, 13> const &track_modes();
static std::array<track_mode, 12> const &track_modes();
bool track_plan_tab() const { return m_track_tab == track_tab::straights || m_track_tab == track_tab::route; }
track_tab plan_tab_for(TTrack const *Track) const;
// the objects along the track: a tab for each tool
@@ -1906,6 +1906,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
std::size_t signal_batch(signal_changes const &Changes, std::vector<std::pair<TTrack *, editor_track::state>> States, std::vector<TTrack *> Created, std::string &Error) override;
bool signal_heads(std::vector<signal_head> &Heads, bool const Wait) override;
std::size_t signal_reattach(std::vector<scene::instance_handle> const &Instances) override;
void select_signal(scene::instance_handle const Instance) override;
void render_signal_templates() override;
struct signal_template
{
@@ -1950,6 +1952,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
int revision{-1};
int kind{0};
std::array<int, 7> chosen{-1, -1, -1, -1, -1, -1, -1};
bool armed{false}; // a click by a track places the chosen template
char filter[64]{};
char name[64]{"A"};
char plate[64]{};
@@ -1975,6 +1978,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
};
signal_tool m_signal;
bool signal_scan(bool Wait = true);
signal_template const *signal_current() const;
signal_template const *signal_armed() const;
signal_template const *signal_template_of(std::string const &File) const;
bool signal_spot_at(TTrack &Track, int const Path, glm::dvec3 const &Point, glm::dvec3 const &Cursor, int const Facing, int const Side, signal_template const &Template, signal_spot &Spot) const;

View File

@@ -82,7 +82,7 @@ editor_mode::selftest_result editor_mode::selftest_monkey(std::string const &com
lines.push_back(std::string{"button "} + Button + " release");
lines.emplace_back("wait 2");
};
char const *const tools[]{"esc", "l", "g", "c", "t", "n", "u", "h", "i", "b", "p", "v", "j", "k", "o", "q", "w", "e"};
char const *const tools[]{"esc", "l", "g", "c", "t", "n", "u", "i", "b", "p", "v", "j", "k", "o", "q", "w", "e"};
char const *const modifiers[]{"", "ctrl", "shift", "alt"};
for (int step = 0; step < steps; ++step)
{

View File

@@ -53,7 +53,7 @@ editor_mode::selftest_result editor_mode::selftest_signal(std::string const &com
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);
show_track_tab(track_tab::srk);
signal_scan();
signal_refresh(true);
auto &tool{m_signal};
@@ -96,12 +96,12 @@ editor_mode::selftest_result editor_mode::selftest_signal(std::string const &com
auto const side{values["side"] == "left" ? -1 : 1};
auto const facing{values["facing"] == "along" ? 1 : values["facing"] == "against" ? -1 : 0};
signal_spot spot;
if (false == spot_on(*signal_armed(), facing, side, spot))
if (false == spot_on(*signal_current(), facing, side, spot))
{
WriteLog("SELFTEST signal: no such track " + values["track"]);
return selftest_result::handled;
}
auto const placed{signal_place(spot, *signal_armed())};
auto const placed{signal_place(spot, *signal_current())};
WriteLog(format("SELFTEST signal %s: %s", placed ? "placed" : "failed", tool.status.c_str()));
}
else if (command == "signalmove")

View File

@@ -350,7 +350,7 @@ bool editor_mode::signal_scan(bool const Wait)
return true;
}
editor_mode::signal_template const *editor_mode::signal_armed() const
editor_mode::signal_template const *editor_mode::signal_current() const
{
auto const &tool{m_signal};
if (tool.kind < 0 || tool.kind >= kKindCount)
@@ -359,6 +359,11 @@ editor_mode::signal_template const *editor_mode::signal_armed() const
return index >= 0 && index < static_cast<int>(tool.templates.size()) ? &tool.templates[index] : nullptr;
}
editor_mode::signal_template const *editor_mode::signal_armed() const
{
return m_signal.armed ? signal_current() : nullptr;
}
editor_mode::signal_template const *editor_mode::signal_template_of(std::string const &File) const
{
auto const file{ToLower(File)};
@@ -980,7 +985,7 @@ void editor_mode::orphans_take_over(std::vector<TTrack *> const &Created, std::v
for (int list = 0; list < 6; ++list)
for (auto const &event : editor_track::events(*track, list))
carried.insert(ToLower(event.first));
// not the list of the Signals tool, nor its templates once found: the step taken may hold one of them; looked for once an event
// not the signals standing as last listed, nor the templates once found: the step taken may hold one of them; looked for once an event
// waits
std::vector<signal_standing> signals;
std::unordered_map<std::string, signal_standing const *> readers;
@@ -1504,7 +1509,7 @@ void editor_mode::render_signal_palette()
ImGui::SetNextItemWidth(-1.0f);
ImGui::InputTextWithHint("##signalfilter", STR_C("filter: name, w24, sbl..."), tool.filter, sizeof(tool.filter));
auto const filter{ToLower(tool.filter)};
auto const *armed{signal_armed()};
auto const *current{signal_current()};
std::vector<std::vector<int>> groups;
std::vector<std::string> keys;
for (int i = 0; i < static_cast<int>(tool.templates.size()); ++i)
@@ -1538,20 +1543,24 @@ void editor_mode::render_signal_palette()
{
auto const &group{groups[g]};
auto const &first{tool.templates[group.front()]};
auto const chosen{armed != nullptr && group_of(armed->mount, armed->lamps) == keys[g] && armed->kind == first.kind};
auto const chosen{current != nullptr && group_of(current->mount, current->lamps) == keys[g] && current->kind == first.kind};
if (g % columns != 0)
ImGui::SameLine();
ImGui::PushID(g);
auto const origin{ImGui::GetCursorScreenPos()};
if (ImGui::InvisibleButton("##tile", tile))
{
auto pick{group.front()};
if (armed != nullptr && chosen)
pick = tool.chosen[tool.kind];
tool.chosen[tool.kind] = pick;
if (chosen && tool.armed)
tool.armed = false;
else
{
tool.chosen[tool.kind] = chosen ? tool.chosen[tool.kind] : group.front();
tool.armed = true;
}
}
auto const hovered{ImGui::IsItemHovered()};
draw->AddRectFilled(origin, ImVec2(origin.x + tile.x, origin.y + tile.y), chosen ? IM_COL32(60, 90, 140, 255) : hovered ? IM_COL32(60, 60, 60, 255) : IM_COL32(40, 40, 40, 255), 4.0f);
auto const armed{chosen && tool.armed};
draw->AddRectFilled(origin, ImVec2(origin.x + tile.x, origin.y + tile.y), armed ? IM_COL32(45, 110, 60, 255) : chosen ? IM_COL32(60, 90, 140, 255) : hovered ? IM_COL32(60, 60, 60, 255) : IM_COL32(40, 40, 40, 255), 4.0f);
draw_signal_icon(draw, origin, ImVec2(tile.x, tile.y - 14.0f), first.mount, first.lamps, chosen ? overlay_color::selected : IM_COL32(120, 120, 120, 255));
auto const caption{first.lamps.empty() ? first.name : first.lamps};
auto const captionsize{ImGui::CalcTextSize(caption.c_str())};
@@ -1564,24 +1573,25 @@ void editor_mode::render_signal_palette()
ImGui::TextUnformatted(first.description.empty() ? first.name.c_str() : first.description.c_str());
ImGui::TextDisabled(STR_C("%zu variants, e.g. %s"), group.size(), first.file.c_str());
ImGui::TextDisabled("%s", first.read.empty() ? STR_C("The train doesn't read it") : STR_C("The train reads it by an event of the path"));
ImGui::TextDisabled("%s", armed ? STR_C("Click: stop placing") : STR_C("Click: place it by a track, the signalling of the station places its signals of this kind with it too"));
ImGui::EndTooltip();
}
ImGui::PopID();
}
ImGui::EndChild();
if (armed == nullptr)
if (current == nullptr)
return;
auto const key{group_of(armed->mount, armed->lamps)};
auto const key{group_of(current->mount, current->lamps)};
ImGui::SetNextItemWidth(-1.0f);
if (ImGui::BeginCombo("##signalvariant", armed->name.c_str()))
if (ImGui::BeginCombo("##signalvariant", current->name.c_str()))
{
for (int i = 0; i < static_cast<int>(tool.templates.size()); ++i)
{
auto const &item{tool.templates[i]};
if (item.kind != armed->kind || group_of(item.mount, item.lamps) != key)
if (item.kind != current->kind || group_of(item.mount, item.lamps) != key)
continue;
auto const label{item.name + (item.lean == "left" ? std::string{" \xE2\x86\x96"} : item.lean == "right" ? std::string{" \xE2\x86\x97"} : std::string{}) + "##" + item.file};
if (ImGui::Selectable(label.c_str(), &item == armed))
if (ImGui::Selectable(label.c_str(), &item == current))
tool.chosen[tool.kind] = i;
if (ImGui::IsItemHovered() && false == item.description.empty())
ImGui::SetTooltip("%s\n%s", item.description.c_str(), item.file.c_str());
@@ -1590,20 +1600,27 @@ void editor_mode::render_signal_palette()
}
if (ImGui::IsItemHovered())
{
auto const read{armed->read.empty() ? std::string{armed->kind == "warning" || armed->kind == "repeater" ? STR_C("The train doesn't read it: it repeats what the signal ahead of it shows") : STR_C("The train doesn't read it")}
: format(STR_C("The train reads it by %s on the path it stands by"), editor_includes::substitute(armed->read, {tool.name[0] != '\0' ? std::string{tool.name} : std::string{"?"}}).c_str())};
auto const read{current->read.empty() ? std::string{current->kind == "warning" || current->kind == "repeater" ? STR_C("The train doesn't read it: it repeats what the signal ahead of it shows") : STR_C("The train doesn't read it")}
: format(STR_C("The train reads it by %s on the path it stands by"), editor_includes::substitute(current->read, {tool.name[0] != '\0' ? std::string{tool.name} : std::string{"?"}}).c_str())};
ImGui::SetTooltip("%s\n%s", STR_C("Variant of the chosen type. A head leaning to one side is swapped for its counterpart leaning towards the track on the other side"), read.c_str());
}
if (false == armed->description.empty())
ImGui::TextWrapped("%s", armed->description.c_str());
if (false == current->description.empty())
ImGui::TextWrapped("%s", current->description.c_str());
if (tool.armed)
{
if (ImGui::Button(STR_C("Stop placing (Esc)"), ImVec2(-1.0f, 0.0f)))
tool.armed = false;
}
else if (main_button(STR_C("Place by a track"), ImVec2(-1.0f, 0.0f)))
tool.armed = true;
item_tooltip("A click by a track places the chosen signal on that side, a press dragged along it turns it to the trains running that way. The signalling of the station places its signals of each kind with the template chosen here");
}
void editor_mode::render_signal_selected()
{
auto const *found{signal_standing_of(m_signal.selected)};
auto const *found{m_signal.selected == m_instance ? signal_standing_of(m_signal.selected) : nullptr};
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());
item_tooltip("Name, plate and the linked signal: in the node properties. Del removes it with its event");
if (found->read.empty())
@@ -1640,6 +1657,22 @@ void editor_mode::render_signal_selected()
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");
ImGui::Separator();
}
void editor_mode::select_signal(scene::instance_handle const Instance)
{
signal_refresh(true);
signal_select(Instance);
}
void editor_mode::render_signal_templates()
{
ImGui::Spacing();
if (ImGui::CollapsingHeader(format("%s###srksignals", STR_C("Signals")).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
render_signal_ui();
else
m_signal.armed = false;
}
void editor_mode::render_signal_ui()
@@ -1669,8 +1702,7 @@ void editor_mode::render_signal_ui()
tool.kind = kinds.front().value;
choice_chips("signalkinds", tool.kind, kinds);
render_signal_palette();
auto const *armed{signal_armed()};
ImGui::Separator();
auto const *armed{signal_current()};
if (begin_fields("##signalnames", 0.3f))
{
field_row("Name");
@@ -1746,7 +1778,6 @@ void editor_mode::render_signal_ui()
ImGui::PopID();
if (false == tool.status.empty())
ImGui::TextWrapped("%s", tool.status.c_str());
render_signal_selected();
}
void editor_mode::draw_signal_overlay() const

View File

@@ -630,7 +630,7 @@ int resonator_at(std::vector<station::approach_point> const &Way, double const W
return best;
}
// the template of a block signal of the aspects wanted, Like: the one standing, empty for the one chosen in the Signals tool, taken
// the template of a block signal of the aspects wanted, Like: the one standing, empty for the one chosen in Signals, taken
// where it has them, else the one of their mount with them, its counterpart by the name first, then of its lights; not the first of
// a line, whose events tell a station signal; Wrong: of a wrong-track one, standing on the left, its head leaning right where one
// does, a head leaning so only for it; empty for none
@@ -1135,12 +1135,11 @@ void srk_tool::render_options()
if (false == m_layout.has_value())
{
ImGui::TextDisabled("%s", STR_C("The signalling of a station: its schematic, the numbers of the switches and the tracks, the track circuits and the signals"));
ImGui::Spacing();
gesture_rows({{"LMB on a switch", "opens its station"}});
if (false == m_status.empty())
ImGui::TextColored(kDoubtful, "%s", m_status.c_str());
ImGui::Spacing();
render_found();
m_signals.render_signal_templates();
return;
}
auto const &layout{*m_layout};
@@ -1253,7 +1252,7 @@ void srk_tool::render_options()
"each line, A, B... from the start of the km, Z, Y... from the end, the circuit from 15 m beyond it to the station bpd_ita; "
"an exit signal 15 m before the joint at the end of each station track a train is sent out of, F1, G2 towards the start, R1, "
"P2 towards the end; a shunting signal Tm1, Tm2... at the end of a shorter track. A signal standing by the place of one gets "
"its name, none is doubled. The kinds of signals chosen in the Signals tool. One step of undo");
"its name, none is doubled. Each kind with its template chosen in Signals below. One step of undo");
step_heading(4, STR_C("Lines"));
render_lines();
if (ImGui::Button(STR_C("Set the line signals"), ImVec2(-1.0f, 0.0f)))
@@ -1303,6 +1302,7 @@ void srk_tool::render_options()
}
if (false == m_status.empty())
ImGui::TextColored(kDoubtful, "%s", m_status.c_str());
m_signals.render_signal_templates();
ImGui::Spacing();
m_length_hover = -1;
if (ImGui::CollapsingHeader(format("%s (%zu)###srklengths", STR_C("Track lengths"), m_lengths.size()).c_str(), ImGuiTreeNodeFlags_DefaultOpen))
@@ -1499,7 +1499,7 @@ void srk_tool::render_lines()
"warning disc, of 3 or 4 aspects, the templates of the block signals standing swapped for those of the aspects. "
"Semi-automatic: a warning disc ToA the braking distance before the entry signal. By itself: the automatic one where "
"block signals stand along the line, of their aspects, or it's double-track, of the aspects of the block signal "
"chosen in the Signals tool, else the semi-automatic one");
"chosen in Signals below, else the semi-automatic one");
ImGui::PopID();
}
ImGui::EndTable();
@@ -1818,7 +1818,10 @@ void srk_tool::render_heads()
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::Selectable((head.name + "##srkhead" + std::to_string(index)).c_str(), static_cast<int>(index) == m_head_hover, ImGuiSelectableFlags_SpanAllColumns))
{
m_view.fly_to(head.position + glm::dvec3{0.0, 4.0, 0.0}, glm::normalize(glm::dvec3{head.travel.x, -0.3, head.travel.y}), 30.0);
m_signals.select_signal(head.instance);
}
if (ImGui::IsItemHovered())
{
m_head_hover = static_cast<int>(index);
@@ -2541,7 +2544,7 @@ void srk_tool::set_signals()
std::string names;
for (auto const &name : unfit)
names += (names.empty() ? "" : ", ") + name;
m_status += "\n" + format(STR_C("No template has the lights %s need, they got the one chosen in the Signals tool: see Signal heads"), names.c_str());
m_status += "\n" + format(STR_C("No template has the lights %s need, they got the one chosen in Signals: see Signal heads"), names.c_str());
}
}

View File

@@ -328,7 +328,7 @@ class srk_tool final : public editor_tool
// the standing ones; false with the reason while it has none
bool lines_of_open(std::vector<standing_signal> const &Standing, std::vector<station::line> &Lines, std::vector<station::signal> &Entries, std::vector<std::size_t> &Owners, std::string &Problem) const;
// the block of the line: as set by hand for its entry signal, else the automatic one where block signals stand along it, of four
// aspects where one of them has, else on a double-track line, of the aspects of the block signal chosen in the Signals tool, else
// aspects where one of them has, else on a double-track line, of the aspects of the block signal chosen in Signals, else
// the semi-automatic one; Own: the block it has by itself
block_kind block_of(station::line const &Line, std::string const &Entry, std::vector<standing_signal> const &Standing, std::vector<signal_head> const &Heads, block_reason &Why, block_kind &Own, block_reason &Own_why, std::size_t &Blocks) const;
// the automatic block of the double-track line both ways: as set by hand for its entry signal, else where block signals stand

View File

@@ -453,17 +453,16 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve
profile_restore();
}
std::array<editor_mode::track_mode, 13> const &editor_mode::track_modes()
std::array<editor_mode::track_mode, 12> const &editor_mode::track_modes()
{
static std::array<track_mode, 13> const modes{{
static std::array<track_mode, 12> const modes{{
{"Select", "Esc", track_tab::path, "LMB on a path selects it: its points, control vectors and parameters", editor_icons::icon::select, 0},
{"Lay track", "L", track_tab::lay, "Lays new track through the clicked points, on the ground or from a free end of a track", editor_icons::icon::lay_track, 0},
{"Plan", "G", track_tab::straights, "The plan of the line laid: LMB on a straight drags its ends or the middle, on a curve its vertex and radius. C works too", editor_icons::icon::curve, 0},
{"Switch", "T", track_tab::turnout, "Puts switches into the selected straight or curve, edits the geometry of the selected switch", editor_icons::icon::turnout, 0},
{"Parallel", "N", track_tab::parallel, "A second track beside a track: LMB on it, then the side and the spacing", editor_icons::icon::parallel, 0},
{"Turntable", "U", track_tab::turntable, "Places a turntable, leads tracks out of it and fits the tracks around to it", editor_icons::icon::turntable, 1},
{"Signals", "H", track_tab::signals, "Signals by the track, from the templates of the scenery, with the event the train reads them by", editor_icons::icon::signal, 1},
{"Signalling", "I", track_tab::srk, "The signalling of a station: LMB on a switch lays its station out as a schematic", editor_icons::icon::station, 1},
{"Signalling", "I", track_tab::srk, "The signals and the signalling of the stations: LMB on a switch lays its station out as a schematic, the signals placed by hand from the templates in the panel", editor_icons::icon::signal, 1},
{"Kilometrage", "X", track_tab::kilometrage, "The km of the railway lines: LMB on a track puts a point of the km there, a jump of the km too", editor_icons::icon::kilometrage, 1},
{"Objects", "B", track_tab::lineside, "Along the track: hectometre posts, fouling point markers, trainsets", editor_icons::icon::objects, 1},
{"Profile", "P", track_tab::profile, "Vertical profile (grade line) along the line", editor_icons::icon::profile, 2},
@@ -492,6 +491,7 @@ void editor_mode::show_track_tab(track_tab const Wanted)
m_lay.status.clear();
m_lay.active = Tab == track_tab::lay;
m_switch.armed = -1;
m_signal.armed = false;
m_track_tab = Tab;
if ((Tab == track_tab::lay || Tab == track_tab::straights || Tab == track_tab::route) && false == m_norms_asked && EditorSettings.norms() == editorSettings::track_norms::ask && std::getenv("EU07_EDITOR_SELFTEST") == nullptr)
{
@@ -525,7 +525,7 @@ void editor_mode::show_track_tab(track_tab const Wanted)
scan_turntables(false);
turntable_read(track);
break;
case track_tab::signals:
case track_tab::srk:
signal_refresh(true);
break;
default:
@@ -608,7 +608,6 @@ std::string editor_mode::track_mode_name() const
case track_tab::lineside: return STR_C("Objects along the track");
case track_tab::infra: return STR_C("Infrastructure");
case track_tab::parallel: return STR_C("Parallel track");
case track_tab::signals: return STR_C("Signal");
case track_tab::srk: return STR_C("Signalling");
case track_tab::kilometrage: return STR_C("Kilometrage");
case track_tab::turntable: return STR_C("Turntable");
@@ -707,8 +706,10 @@ void editor_mode::render_track_tool_options()
ImGui::TextDisabled("%s", STR_C("What the check finds is listed in its window"));
break;
case track_tab::lineside: render_lineside_ui(); break;
case track_tab::signals: render_signal_ui(); break;
case track_tab::srk: m_srk.render_options(); break;
case track_tab::srk:
render_signal_selected();
m_srk.render_options();
break;
case track_tab::kilometrage: m_km.render_options(); break;
case track_tab::turntable: render_turntable_ui(); break;
default:
@@ -1711,16 +1712,17 @@ std::vector<editor_mode::key_hint> 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.moving)
else if (m_track_window_open && m_track_tab == track_tab::srk && 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)
else if (m_track_window_open && m_track_tab == track_tab::srk && 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)
else if (m_track_window_open && m_track_tab == track_tab::srk && false == m_srk.drawing())
{
hints = {{"LMB by a track", "places the signal on that side"}, {"Press+drag along", "the trains it faces run that way"}, {"Drag a signal", "moves it along the track"}, {"LMB on a signal", "selects it"}};
if (m_signal.selected != 0)
if (signal_armed() != nullptr)
hints = {{"LMB by a track", "places the signal on that side"}, {"Press+drag along", "the trains it faces run that way"}, {"Esc", "stops placing"}};
else
hints = {{"LMB on a switch", "opens its station"}, {"List in the panel", "the type of the signal"}, {"Drag a signal", "moves it along the track"}, {"LMB on a signal", "selects it"}};
if (m_signal.selected != 0 && m_signal.selected == m_instance)
hints.push_back({"Del", "removes the selected signal with its event"});
}
else if (m_track_window_open && m_track_tab == track_tab::turntable && m_turntable.placing)

View File

@@ -424,40 +424,6 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
}
if (m_track_tab == track_tab::turntable)
return turntable_intent(ground, shift);
if (m_track_tab == track_tab::signals)
{
if (auto const hit{signal_hit()}; hit >= 0)
{
auto const &standing{m_signal.standing[hit]};
intent.index = hit;
intent.position = standing.include.location;
intent.action = format(STR_C("Click: select the signal %s, drag: move it along the track"), standing.name.c_str());
intent.what = kind::signal_move;
return intent;
}
auto const *armed{signal_armed()};
if (m_hover.track != nullptr && armed != nullptr)
{
signal_spot spot;
if (signal_spot_at(*m_hover.track, m_hover.path, m_hover.point, cursor_level(m_hover.point.y), 0, 0, *armed, spot))
{
intent.track = m_hover.track;
intent.path = m_hover.path;
intent.position = spot.position;
intent.action = signal_intent_label(*armed, spot);
intent.what = kind::signal_place;
return intent;
}
}
if (m_hover.track != nullptr)
{
intent.track = m_hover.track;
intent.path = m_hover.path;
intent.position = m_hover.point;
return make(kind::select, "Choose the type of the signal in the Tracks window first");
}
return intent;
}
if (m_track_tab == track_tab::srk && m_srk.drawing())
{
bool valid{false};
@@ -468,12 +434,38 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
intent.what = kind::srk_boundary;
return intent;
}
if (m_track_tab == track_tab::srk && m_hover.track != nullptr)
if (m_track_tab == track_tab::srk)
{
intent.track = m_hover.track;
intent.path = m_hover.path;
intent.position = m_hover.point;
return make(kind::select, m_hover.track->eType != tt_Normal ? "Click: the station of this switch" : "Click: the station of the switch nearest along this track");
if (auto const hit{signal_hit()}; hit >= 0)
{
auto const &standing{m_signal.standing[hit]};
intent.index = hit;
intent.position = standing.include.location;
intent.action = format(STR_C("Click: select the signal %s, drag: move it along the track"), standing.name.c_str());
intent.what = kind::signal_move;
return intent;
}
if (auto const *armed{signal_armed()}; armed != nullptr)
{
signal_spot spot;
if (m_hover.track != nullptr && signal_spot_at(*m_hover.track, m_hover.path, m_hover.point, cursor_level(m_hover.point.y), 0, 0, *armed, spot))
{
intent.track = m_hover.track;
intent.path = m_hover.path;
intent.position = spot.position;
intent.action = signal_intent_label(*armed, spot);
intent.what = kind::signal_place;
}
return intent;
}
if (m_hover.track != nullptr)
{
intent.track = m_hover.track;
intent.path = m_hover.path;
intent.position = m_hover.point;
return make(kind::select, m_hover.track->eType != tt_Normal ? "Click: the station of this switch" : "Click: the station of the switch nearest along this track");
}
return intent;
}
if (m_track_tab == track_tab::kilometrage && m_hover.track != nullptr)
{

View File

@@ -177,17 +177,16 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
add(track_tab::straights, false);
add(track_tab::turnout, false);
add(track_tab::parallel, false);
auto const advanced{m_track_tab == track_tab::turntable || m_track_tab == track_tab::signals || m_track_tab == track_tab::srk || m_track_tab == track_tab::kilometrage || m_track_tab == track_tab::lineside || m_track_tab == track_tab::profile || m_track_tab == track_tab::speed ||
auto const advanced{m_track_tab == track_tab::turntable || m_track_tab == track_tab::srk || m_track_tab == track_tab::kilometrage || m_track_tab == track_tab::lineside || m_track_tab == track_tab::profile || m_track_tab == track_tab::speed ||
m_track_tab == track_tab::joints || m_gauge.is_open()};
auto const more{EditorSettings.track_tools_more()};
Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("Turntable, signals, signalling, kilometrage, objects, trainset, profile, speed, joints, gauge"), more, [more]() {
Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("Turntable, signalling and signals, kilometrage, objects, trainset, profile, speed, joints, gauge"), more, [more]() {
EditorSettings.track_tools_more(false == more);
EditorSettings.save();
}, true});
if (false == more && false == advanced)
break;
add(track_tab::turntable, true);
add(track_tab::signals, false);
add(track_tab::srk, false);
add(track_tab::kilometrage, false);
add(track_tab::lineside, false);

View File

@@ -36,7 +36,7 @@ enum class editor_selftest_result
enum class editor_first_step { tracks, lay, laid, wheel, join, turnout, undo, save, drive, look, top, select, shape, profile, profile_point, profile_apply, terrain, nmt, plan, plan_band, plan_apply, signal, posts, count };
enum class editor_track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, signals, parallel, srk, kilometrage };
enum class editor_track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, parallel, srk, kilometrage };
struct track_hover
{
@@ -116,7 +116,7 @@ struct signal_head
std::string mount;
std::string lamps; // its chambers from the top: z green, c red, p orange, b white, n blue, x blind
std::vector<int> 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
bool chosen{false}; // chosen for its kind among the templates of the signals, placed by hand and with the signalling
int aspects{0}; // of a block signal: 3, or 4 with the warning two signals ahead
std::string lean; // its head leans towards the track: left, standing on the right of it, right, or none
};
@@ -219,6 +219,10 @@ class editor_signals
virtual bool signal_heads(std::vector<signal_head> &Heads, bool const Wait) = 0;
// the signals given which no track reads, read again by the track they stand by: one step of the history. returns: how many
virtual std::size_t signal_reattach(std::vector<scene::instance_handle> const &Instances) = 0;
// the signal picked, its card at the top of the panel
virtual void select_signal(scene::instance_handle const Instance) = 0;
// the templates of the signals: the one of each kind placed by hand and with the signalling of a station
virtual void render_signal_templates() = 0;
protected:
~editor_signals() = default;

View File

@@ -3570,8 +3570,8 @@ msgstr "krawędź peronu od osi toru"
msgid "Signals"
msgstr "Sygnalizatory"
msgid "Signals by the track, from the templates of the scenery, with the event the train reads them by"
msgstr "Sygnalizatory przy torze, z szablonów scenerii, z eventem, którym pociąg je odczytuje"
msgid "Click: stop placing"
msgstr "Klik: koniec stawiania"
msgid "moves the signal along the track"
msgstr "przesuwa sygnalizator wzdłuż toru"
@@ -3600,8 +3600,20 @@ msgstr "usuwa zaznaczony sygnalizator razem z jego eventem"
msgid "Click: select the signal %s, drag: move it along the track"
msgstr "LPM: zaznacz sygnalizator %s, przeciągnij: przesuń go wzdłuż toru"
msgid "Choose the type of the signal in the Tracks window first"
msgstr "Najpierw wybierz typ sygnalizatora w oknie Tory"
msgid "Click: place it by a track, the signalling of the station places its signals of this kind with it too"
msgstr "Klik: stawiaj go przy torze; SRK stacji stawia nim też swoje sygnalizatory tego rodzaju"
msgid "Stop placing (Esc)"
msgstr "Zakończ stawianie (Esc)"
msgid "Place by a track"
msgstr "Stawiaj przy torze"
msgid "stops placing"
msgstr "kończy stawianie"
msgid "A click by a track places the chosen signal on that side, a press dragged along it turns it to the trains running that way. The signalling of the station places its signals of each kind with the template chosen here"
msgstr "Klik przy torze stawia wybrany sygnalizator po tej stronie, wciśnięcie przeciągnięte wzdłuż toru obraca go do pociągów jadących w tę stronę. SRK stacji stawia swoje sygnalizatory każdego rodzaju szablonem wybranym tutaj"
msgid "Semaphore"
msgstr "Semafor"
@@ -5981,8 +5993,8 @@ msgstr "Rozjazd krzyżowy pojedynczy (Rkp) albo podwójny (Rkpd) na skrzyżowani
msgid "Crossover, double, scissors, ladder"
msgstr "Przejście rozjazdowe, podwójne przejście rozjazdowe, nożyce, ulica zwrotnicowa"
msgid "Turntable, signals, signalling, kilometrage, objects, trainset, profile, speed, joints, gauge"
msgstr "Obrotnica, sygnalizatory, SRK, kilometraż, obiekty, skład, profil, prędkość, styki, skrajnia"
msgid "Turntable, signalling and signals, kilometrage, objects, trainset, profile, speed, joints, gauge"
msgstr "Obrotnica, SRK i sygnalizatory, kilometraż, obiekty, skład, profil, prędkość, styki, skrajnia"
msgid "No switch drive models"
msgstr "Brak modeli napędów"
@@ -7499,8 +7511,8 @@ msgstr "B: słupki hektometrowe całej linii naraz"
msgid "Signals and posts"
msgstr "Sygnalizatory i słupki"
msgid "The signals tool: the type of the signal in the panel, from the templates of the scenery"
msgstr "Narzędzie Sygnalizatory: typ sygnalizatora w panelu, z szablonów scenerii"
msgid "The signalling tool: click a type of signal in its Signals, from the templates of the scenery"
msgstr "Narzędzie SRK: kliknij typ sygnalizatora w sekcji Sygnalizatory, z szablonów scenerii"
msgid "A click by a track places the signal on that side"
msgstr "Klik przy torze stawia sygnalizator po tej stronie"
@@ -7520,8 +7532,8 @@ msgstr "Postaw sygnalizator"
msgid "Place the hectometre posts of a line"
msgstr "Postaw słupki hektometrowe linii"
msgid "The signals tool (H)"
msgstr "Narzędzie Sygnalizatory (H)"
msgid "The signalling tool (I)"
msgstr "Narzędzie SRK (I)"
msgid "\nPaths off the route brought to its height:"
msgstr "\nTory obok trasy doprowadzone do jej wysokości:"
@@ -10281,8 +10293,8 @@ msgstr "Wyłączone: tor kładziony od innego toru albo dołączany do niego jes
msgid "Signalling"
msgstr "SRK"
msgid "The signalling of a station: LMB on a switch lays its station out as a schematic"
msgstr "Sterowanie ruchem na stacji: LPM na rozjazd rozkłada jego stację w schemat"
msgid "The signals and the signalling of the stations: LMB on a switch lays its station out as a schematic, the signals placed by hand from the templates in the panel"
msgstr "Sygnalizatory i sterowanie ruchem na stacjach: LPM na rozjazd rozkłada jego stację w schemat, sygnalizatory stawia się ręcznie z szablonów w panelu"
msgid "Click: the station of this switch"
msgstr "Klik: stacja tego rozjazdu"
@@ -10464,8 +10476,8 @@ msgstr "Tor %s ma teraz numer %s"
msgid "Set the signals"
msgstr "Ustaw semafory"
msgid "Places the signals of the station, as on the lines of PKP PLK, and names them after its code: an entry signal 300 m out on each line, A, B... from the start of the km, Z, Y... from the end, the circuit from 15 m beyond it to the station bpd_ita; an exit signal 15 m before the joint at the end of each station track a train is sent out of, F1, G2 towards the start, R1, P2 towards the end; a shunting signal Tm1, Tm2... at the end of a shorter track. A signal standing by the place of one gets its name, none is doubled. The kinds of signals chosen in the Signals tool. One step of undo"
msgstr "Stawia semafory stacji jak na liniach PKP PLK i nazywa je od jej skrótu: wjazdowy 300 m przed stacją na każdej linii, A, B... od początku km, Z, Y... od końca, a odcinek od 15 m za nim do stacji to bpd_ita; wyjazdowy 15 m przed stykiem na końcu każdego toru, z którego wyprawia się pociągi, F1, G2 w stronę początku, R1, P2 w stronę końca; tarcza manewrowa Tm1, Tm2... na końcu krótszego toru. Semafor, który już stoi w miejscu któregoś z nich, dostaje tylko jego nazwę, nic się nie dubluje. Modele semaforów te wybrane w narzędziu Sygnalizatory. Jeden krok cofania"
msgid "Places the signals of the station, as on the lines of PKP PLK, and names them after its code: an entry signal 300 m out on each line, A, B... from the start of the km, Z, Y... from the end, the circuit from 15 m beyond it to the station bpd_ita; an exit signal 15 m before the joint at the end of each station track a train is sent out of, F1, G2 towards the start, R1, P2 towards the end; a shunting signal Tm1, Tm2... at the end of a shorter track. A signal standing by the place of one gets its name, none is doubled. Each kind with its template chosen in Signals below. One step of undo"
msgstr "Stawia semafory stacji jak na liniach PKP PLK i nazywa je od jej skrótu: wjazdowy 300 m przed stacją na każdej linii, A, B... od początku km, Z, Y... od końca, a odcinek od 15 m za nim do stacji to bpd_ita; wyjazdowy 15 m przed stykiem na końcu każdego toru, z którego wyprawia się pociągi, F1, G2 w stronę początku, R1, P2 w stronę końca; tarcza manewrowa Tm1, Tm2... na końcu krótszego toru. Semafor, który już stoi w miejscu któregoś z nich, dostaje tylko jego nazwę, nic się nie dubluje. Każdy rodzaj szablonem wybranym niżej w Sygnalizatorach. Jeden krok cofania"
msgid "Give the station its code first: the signals are named after it"
msgstr "Najpierw wpisz skrót stacji: od niego biorą się nazwy semaforów"
@@ -11038,8 +11050,8 @@ msgstr "Daje każdemu zaznaczonemu semaforowi szablon tego samego rodzaju i moco
msgid "The lights go by the routes of the trains: 40 km/h through the switches 1:9, 60 through 1:12 and 1:14, 100 through 1:18.5, by their radii, for these a lower orange light, with an orange strip for 60, a green one for 100, Ie-1; an upper orange one where the next signal can show stop; the white one of the substitute signal. A signal telling of the next one standing nearer than the braking distance slows the trains with it at stop, Ie-4 § 8 ust. 5"
msgstr "Światła wynikają z przebiegów pociągów: 40 km/h przez rozjazdy 1:9, 60 przez 1:12 i 1:14, 100 przez 1:18,5, liczone z ich promieni; dla nich dolne światło pomarańczowe, z pomarańczowym pasem dla 60 i zielonym dla 100, Ie-1; górne pomarańczowe, gdy następny semafor może pokazać stój; białe dla sygnału zastępczego. Semafor zapowiadający następny, który stoi bliżej niż droga hamowania, zmniejsza prędkość pociągów, gdy tamten pokazuje stój, Ie-4 § 8 ust. 5"
msgid "No template has the lights %s need, they got the one chosen in the Signals tool: see Signal heads"
msgstr "Żaden szablon nie ma świateł potrzebnych dla %s, dostały ten wybrany w narzędziu Sygnalizatory: zobacz Komory semaforów"
msgid "No template has the lights %s need, they got the one chosen in Signals: see Signal heads"
msgstr "Żaden szablon nie ma świateł potrzebnych dla %s, dostały ten wybrany w Sygnalizatorach: zobacz Komory semaforów"
msgid "No main signal within %.0f m ahead of it to tell of"
msgstr "Na %.0f m przed nią nie ma semafora do zapowiadania"
@@ -11278,8 +11290,8 @@ msgstr "ze scenerii"
msgid "Block signals stand along the line, none of them switched by a block section of the editor: the line keeps the block of the scenery as it stands"
msgstr "Na szlaku stoją semafory SBL, ale żadnego nie przełącza odstęp edytora: szlak zostaje z blokadą scenerii, tak jak stoi"
msgid "The block of the line, both tracks of a double-track one alike. Automatic (SBL): block signals with block sections, no warning disc, of 3 or 4 aspects, the templates of the block signals standing swapped for those of the aspects. Semi-automatic: a warning disc ToA the braking distance before the entry signal. By itself: the automatic one where block signals stand along the line, of their aspects, or it's double-track, of the aspects of the block signal chosen in the Signals tool, else the semi-automatic one"
msgstr "Blokada szlaku, na obu torach dwutorowego taka sama. Samoczynna (SBL): semafory SBL z odstępami, bez tarczy ostrzegawczej, trzy- albo czterostawna; szablony stojących semaforów SBL zostają podmienione na te o właściwej liczbie stawności. Półsamoczynna: tarcza ostrzegawcza ToA w drodze hamowania przed semaforem wjazdowym. Auto: samoczynna, gdy na szlaku stoją semafory SBL (stawność jak u nich) albo szlak jest dwutorowy (stawność jak u semafora SBL wybranego w narzędziu Sygnalizatory), inaczej półsamoczynna"
msgid "The block of the line, both tracks of a double-track one alike. Automatic (SBL): block signals with block sections, no warning disc, of 3 or 4 aspects, the templates of the block signals standing swapped for those of the aspects. Semi-automatic: a warning disc ToA the braking distance before the entry signal. By itself: the automatic one where block signals stand along the line, of their aspects, or it's double-track, of the aspects of the block signal chosen in Signals below, else the semi-automatic one"
msgstr "Blokada szlaku, na obu torach dwutorowego taka sama. Samoczynna (SBL): semafory SBL z odstępami, bez tarczy ostrzegawczej, trzy- albo czterostawna; szablony stojących semaforów SBL zostają podmienione na te o właściwej liczbie stawności. Półsamoczynna: tarcza ostrzegawcza ToA w drodze hamowania przed semaforem wjazdowym. Auto: samoczynna, gdy na szlaku stoją semafory SBL (stawność jak u nich) albo szlak jest dwutorowy (stawność jak u semafora SBL wybranego niżej w Sygnalizatorach), inaczej półsamoczynna"
msgid "Draw the block boundaries"
msgstr "Rysuj granice odstępów"