17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-06 16:18:35 +01:00

feat(editor): the parallel track is a tool of its own (N) in the toolbar, its green preview only shows there, Shift+click on a straight in L opens it with that track; the norms are two buttons at the top of the Lay panel and of the Curve tool, shared by both, free hides the recommendations of the curve and its norm warnings, the duplicate transitions checkbox is gone; the Lay panel starts with the radius, the speed and the shape; the Tracks toolbar shows the tools that lay track, the ones that correct a line are under More (remembered); First steps ends with driving the track laid; self-test command tracktab

This commit is contained in:
maj00r
2026-10-12 01:52:28 +02:00
parent 7fea51ad06
commit c9f381a9c9
14 changed files with 187 additions and 57 deletions

View File

@@ -4612,7 +4612,8 @@ void editor_mode::render_first_steps()
"Joining: press on a free end (magenta ring) and drag onto another free end", "Joining: press on a free end (magenta ring) and drag onto another free end",
"T: switch. Click a straight, then press on it and drag: along sets the direction, sideways the side", "T: switch. Click a straight, then press on it and drag: along sets the direction, sideways the side",
"Ctrl+Z takes a step back, Backspace while laying takes back the last piece", "Ctrl+Z takes a step back, Backspace while laying takes back the last piece",
"Ctrl+S saves the scenery"}; "Ctrl+S saves the scenery",
"Drive it: Vehicle in the toolbar, pick a locomotive from the list, LMB on the track, then Place and drive"};
ImGui::SetNextWindowSize(ImVec2(440.0f * Global.ui_scale, 0.0f), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(440.0f * Global.ui_scale, 0.0f), ImGuiCond_FirstUseEver);
ImGui::SetNextWindowPos(ImVec2(8.0f, ImGui::GetIO().DisplaySize.y - 8.0f), ImGuiCond_FirstUseEver, ImVec2(0.0f, 1.0f)); ImGui::SetNextWindowPos(ImVec2(8.0f, ImGui::GetIO().DisplaySize.y - 8.0f), ImGuiCond_FirstUseEver, ImVec2(0.0f, 1.0f));
ImGui::SetNextWindowBgAlpha(1.0f); ImGui::SetNextWindowBgAlpha(1.0f);
@@ -4706,7 +4707,8 @@ void editor_mode::render_shortcuts_window()
{"Shift+wheel", "Laying: arc then straight, straight then arc, arc, straight; at a free end: another way to join"}, {"Shift+wheel", "Laying: arc then straight, straight then arc, arc, straight; at a free end: another way to join"},
{"0-9 while laying", "Type the length (or the radius) of the next piece, Enter lays it"}, {"0-9 while laying", "Type the length (or the radius) of the next piece, Enter lays it"},
{"Alt held while laying", "The direction in steps of 15 degrees"}, {"Alt held while laying", "The direction in steps of 15 degrees"},
{"Shift+LMB on a track in L", "Choose it for a parallel track"}, {"N", "Parallel track: LMB on a straight, then the side and the spacing"},
{"Shift+LMB on a track in L", "The Parallel tool (N) with it"},
{"Enter / Backspace", "Laying track: lay up to the cursor / take the last piece back"}, {"Enter / Backspace", "Laying track: lay up to the cursor / take the last piece back"},
{"Del", "Delete the selected tracks"}}}, {"Del", "Delete the selected tracks"}}},
{"Roads", {"Roads",

View File

@@ -252,7 +252,7 @@ class editor_mode : public application_mode, private editor_track::observer
void render_help_menu(); void render_help_menu();
void render_shortcuts_window(); void render_shortcuts_window();
bool m_shortcuts_open{false}; bool m_shortcuts_open{false};
enum class first_step { tracks, lay, laid, wheel, join, turnout, undo, save, count }; enum class first_step { tracks, lay, laid, wheel, join, turnout, undo, save, drive, count };
void render_first_steps(); void render_first_steps();
void first_step_done(first_step const Step); void first_step_done(first_step const Step);
bool m_first_steps_open{false}; bool m_first_steps_open{false};
@@ -837,7 +837,11 @@ class editor_mode : public application_mode, private editor_track::observer
bool digitize_drawn(std::vector<TTrack *> const &Created, bool const Alone = true); bool digitize_drawn(std::vector<TTrack *> const &Created, bool const Alone = true);
bool digitize_chain(editor_track::chain const &Chain); bool digitize_chain(editor_track::chain const &Chain);
void render_route_stored(); void render_route_stored();
void route_update() { m_route.result = alignment::compute(m_route.design); } void route_update()
{
m_route.design.norms.checked = false == m_norms_free;
m_route.result = alignment::compute(m_route.design);
}
void route_apply(); void route_apply();
bool route_relay_through_switches(editor_track::chain const &Chain, std::vector<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Created, TTrack *&Last); bool route_relay_through_switches(editor_track::chain const &Chain, std::vector<std::pair<TTrack *, editor_track::state>> &States, std::vector<TTrack *> &Created, TTrack *&Last);
void route_recommend(alignment::vertex &Vertex) const; void route_recommend(alignment::vertex &Vertex) const;
@@ -1108,6 +1112,7 @@ class editor_mode : public application_mode, private editor_track::observer
lay_tool m_lay; lay_tool m_lay;
bool m_norms_free{true}; bool m_norms_free{true};
alignment::limits laying_norms() const; alignment::limits laying_norms() const;
bool render_norms_choice();
glm::dvec3 lay_angle_snap(glm::dvec3 const &Mouse) const; glm::dvec3 lay_angle_snap(glm::dvec3 const &Mouse) const;
void lay_after_history(bool const Undo); void lay_after_history(bool const Undo);
void lay_back(); void lay_back();
@@ -1193,7 +1198,7 @@ class editor_mode : public application_mode, private editor_track::observer
void update_build_tools(); void update_build_tools();
void draw_build_overlay() const; void draw_build_overlay() const;
// modes of the track editor, one at a time: path is the plain selection // modes of the track editor, one at a time: path is the plain selection
enum class track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, signals }; enum class track_tab { straights, route, path, turnout, profile, speed, joints, infra, lay, lineside, turntable, signals, parallel };
struct track_mode struct track_mode
{ {
char const *label; char const *label;
@@ -1201,7 +1206,7 @@ class editor_mode : public application_mode, private editor_track::observer
track_tab tab; track_tab tab;
char const *tooltip; char const *tooltip;
}; };
static std::array<track_mode, 12> const &track_modes(); static std::array<track_mode, 13> const &track_modes();
// the objects along the track: a tab for each tool // the objects along the track: a tab for each tool
int m_lineside_tab{0}; int m_lineside_tab{0};
void render_lineside_ui(); void render_lineside_ui();

View File

@@ -373,11 +373,9 @@ bool editor_mode::parallel_preview_visible() const
{ {
if (m_parallel.pieces.empty() || parallel_source() != m_parallel.built_for) if (m_parallel.pieces.empty() || parallel_source() != m_parallel.built_for)
return false; return false;
if (m_track_tab == track_tab::lay) if (m_track_tab == track_tab::parallel)
return m_lay.points.empty();
if (m_track_tab == track_tab::path)
return true; return true;
return m_track_tab == track_tab::lineside && m_parallel.open; return m_track_tab == track_tab::path && parallel_target() != nullptr;
} }
void editor_mode::draw_parallel_preview() const void editor_mode::draw_parallel_preview() const

View File

@@ -722,7 +722,7 @@ editor_mode::selftest_result editor_mode::selftest_sweep(std::string const &comm
{ {
std::string tab; std::string tab;
words >> tab; words >> tab;
show_track_tab(track_tab::lineside); show_track_tab(tab == "parallel" ? track_tab::parallel : track_tab::lineside);
(tab == "vehicle" ? m_vehicle.expand : tab == "hekto" ? m_hekto.expand : tab == "fouling" ? m_fouling.expand : m_parallel.expand) = true; (tab == "vehicle" ? m_vehicle.expand : tab == "hekto" ? m_hekto.expand : tab == "fouling" ? m_fouling.expand : m_parallel.expand) = true;
return selftest_result::handled; return selftest_result::handled;
} }
@@ -1711,6 +1711,16 @@ editor_mode::selftest_result editor_mode::selftest_join(std::string const &comma
WriteLog(format("SELFTEST %s end: %.3f m from the target", command.c_str(), geometry::plan_distance(previous, b))); WriteLog(format("SELFTEST %s end: %.3f m from the target", command.c_str(), geometry::plan_distance(previous, b)));
return selftest_result::handled; return selftest_result::handled;
} }
if (command == "tracktab")
{
std::string key;
words >> key;
for (auto const &mode : track_modes())
if (key == mode.key)
show_track_tab(mode.tab);
WriteLog(format("SELFTEST tracktab %s: %s", key.c_str(), track_mode_name().c_str()));
return selftest_result::handled;
}
if (command == "laychain") if (command == "laychain")
{ {
int layout{0}; int layout{0};

View File

@@ -522,12 +522,13 @@ void editor_mode::restore_track_snapshot(EditorSnapshot const &Snapshot, std::ve
profile_restore(); profile_restore();
} }
std::array<editor_mode::track_mode, 12> const &editor_mode::track_modes() std::array<editor_mode::track_mode, 13> const &editor_mode::track_modes()
{ {
static std::array<track_mode, 12> const modes{{ static std::array<track_mode, 13> const modes{{
{"Select", "Esc", track_tab::path, "LMB on a path selects it: its points, control vectors and parameters"}, {"Select", "Esc", track_tab::path, "LMB on a path selects it: its points, control vectors and parameters"},
{"Lay track", "L", track_tab::lay, "Lays new track through the clicked points, on the ground or from a free end of a track"}, {"Lay track", "L", track_tab::lay, "Lays new track through the clicked points, on the ground or from a free end of a track"},
{"Switch", "T", track_tab::turnout, "Puts switches into the selected straight or curve, edits the geometry of the selected switch"}, {"Switch", "T", track_tab::turnout, "Puts switches into the selected straight or curve, edits the geometry of the selected switch"},
{"Parallel", "N", track_tab::parallel, "A second track beside a straight: LMB on the straight, then the side and the spacing"},
{"Turntable", "U", track_tab::turntable, "Places a turntable, leads tracks out of it and fits the tracks around to it"}, {"Turntable", "U", track_tab::turntable, "Places a turntable, leads tracks out of it and fits the tracks around to it"},
{"Straight", "G", track_tab::straights, "The whole straight through the selected path: drag its ends or the middle, break it, shift it"}, {"Straight", "G", track_tab::straights, "The whole straight through the selected path: drag its ends or the middle, break it, shift it"},
{"Curve", "C", track_tab::route, "The line through the path, switch to switch: vertices with the radii, transitions and cant of the curves"}, {"Curve", "C", track_tab::route, "The line through the path, switch to switch: vertices with the radii, transitions and cant of the curves"},
@@ -659,6 +660,7 @@ std::string editor_mode::track_mode_name() const
case track_tab::lineside: case track_tab::lineside:
return STR_C("Objects along the track"); return STR_C("Objects along the track");
case track_tab::infra: return STR_C("Infrastructure along the track"); case track_tab::infra: return STR_C("Infrastructure along the track");
case track_tab::parallel: return m_parallel.pieces.empty() ? STR_C("Parallel track: LMB on a straight") : STR_C("Parallel track: the side and the spacing in the panel, then Lay");
case track_tab::signals: case track_tab::signals:
if (m_signal.moving) if (m_signal.moving)
return STR_C("Signal: drag along the track, release to put it there"); return STR_C("Signal: drag along the track, release to put it there");
@@ -734,6 +736,9 @@ void editor_mode::render_track_tool_options()
case track_tab::lay: case track_tab::lay:
render_lay_ui(); render_lay_ui();
break; break;
case track_tab::parallel:
render_parallel_ui();
break;
case track_tab::turnout: case track_tab::turnout:
if (track != nullptr && track->eType == tt_Switch) if (track != nullptr && track->eType == tt_Switch)
render_turnout_ui(); render_turnout_ui();
@@ -2340,6 +2345,8 @@ void editor_mode::render_route_gizmo()
void editor_mode::render_route_ui() void editor_mode::render_route_ui()
{ {
auto &route{m_route}; auto &route{m_route};
render_norms_choice();
ImGui::Separator();
if (false == route.error.empty()) if (false == route.error.empty())
ImGui::TextColored(ImVec4(1.0f, 0.35f, 0.3f, 1.0f), "%s", route.error.c_str()); ImGui::TextColored(ImVec4(1.0f, 0.35f, 0.3f, 1.0f), "%s", route.error.c_str());
if (route.chain.tracks.empty()) if (route.chain.tracks.empty())
@@ -2489,15 +2496,17 @@ bool editor_mode::render_route_vertex(int const Index)
vertex.transition_in = std::max(0.0, vertex.transition_in); vertex.transition_in = std::max(0.0, vertex.transition_in);
vertex.transition_out = std::max(0.0, vertex.transition_out); vertex.transition_out = std::max(0.0, vertex.transition_out);
vertex.cant = std::max(0.0, vertex.cant); vertex.cant = std::max(0.0, vertex.cant);
if (ImGui::SmallButton(STR_C("Apply recommended for V"))) if (false == m_norms_free)
{ {
route_recommend(vertex); if (ImGui::SmallButton(STR_C("Apply recommended for V")))
changed = true; {
route_recommend(vertex);
changed = true;
}
item_tooltip("Cant and transitions recommended for the design speed and the radius");
auto const recommended{alignment::recommend(design.speed, vertex.radius, design.norms)};
ImGui::TextDisabled(STR_C("For %.0f km/h: R min %.0f m, cant %.0f mm (equilibrium %.0f, min %.0f), transition %.0f m"), design.speed, recommended.radius_min, recommended.cant, recommended.cant_equilibrium, recommended.cant_min, recommended.transition);
} }
item_tooltip("Cant and transitions recommended for the design speed and the radius");
auto const recommended{alignment::recommend(design.speed, vertex.radius, design.norms)};
ImGui::TextDisabled(STR_C("For %.0f km/h: R min %.0f m, cant %.0f mm (equilibrium %.0f, min %.0f), transition %.0f m"), design.speed, recommended.radius_min, recommended.cant, recommended.cant_equilibrium, recommended.cant_min, recommended.transition);
if (ImGui::TreeNode(STR_C("Details"))) if (ImGui::TreeNode(STR_C("Details")))
{ {
for (auto const &curve : route.result.curves) for (auto const &curve : route.result.curves)
@@ -3653,7 +3662,7 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
if (m_lay.active) if (m_lay.active)
{ {
if (m_lay.points.empty()) if (m_lay.points.empty())
hints = {{"LMB", "start of the new track, on the ground or at a free end"}, {"Drag from a free end", "the shape chosen towards the cursor, to a free end: joins it"}, {"Shift+click a straight", "a parallel track beside it, in the panel"}, {"Alt", "the direction in steps of 15 degrees"}, {"Esc", "stop laying"}}; hints = {{"LMB", "start of the new track, on the ground or at a free end"}, {"Drag from a free end", "the shape chosen towards the cursor, to a free end: joins it"}, {"Shift+click a straight", "the Parallel tool (N) with it"}, {"Alt", "the direction in steps of 15 degrees"}, {"Esc", "stop laying"}};
else else
{ {
bool const chained{m_lay.start.track != nullptr}; bool const chained{m_lay.start.track != nullptr};
@@ -3697,6 +3706,8 @@ std::vector<editor_mode::key_hint> editor_mode::track_key_hints(bool const All)
hints = {{"LMB on a row", "show the path"}}; hints = {{"LMB on a row", "show the path"}};
else if (m_track_window_open && m_track_tab == track_tab::lineside) else if (m_track_window_open && m_track_tab == track_tab::lineside)
hints = {{"LMB on a track", "the line the objects go along"}}; 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 straight", "the track the new one goes beside, green in the view"}, {"Esc", "back to Select"}};
else if (m_track_window_open && m_track_tab == track_tab::signals && (m_signal.placing || m_signal.moving)) 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"}}; 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) else if (m_track_window_open && m_track_tab == track_tab::signals)
@@ -4614,9 +4625,6 @@ void editor_mode::render_extend_ui()
ImGui::SameLine(); ImGui::SameLine();
if (ImGui::Button(STR_C("Curve right##extend"), ImVec2(100.0f, 0.0f))) if (ImGui::Button(STR_C("Curve right##extend"), ImVec2(100.0f, 0.0f)))
extend_add(-1); extend_add(-1);
ImGui::PushID("extend");
render_layout_combo();
ImGui::PopID();
} }
void editor_mode::render_layout_combo() void editor_mode::render_layout_combo()
@@ -5042,47 +5050,61 @@ alignment::limits editor_mode::laying_norms() const
return norms; return norms;
} }
bool editor_mode::render_norms_choice()
{
ImGui::AlignTextToFramePadding();
ImGui::TextUnformatted(STR_C("Norms:"));
auto changed{false};
char const *names[]{STR_C("free"), STR_C("PKP PLK")};
for (int i = 0; i < 2; ++i)
{
ImGui::SameLine();
auto const chosen{m_norms_free == (i == 0)};
if (chosen)
ImGui::PushStyleColor(ImGuiCol_Button, ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive));
if (ImGui::Button(names[i], ImVec2(90.0f, 0.0f)) && false == chosen)
{
m_norms_free = i == 0;
m_lay.transitions = false == m_norms_free;
changed = true;
}
if (chosen)
ImGui::PopStyleColor();
item_tooltip(i == 0 ? "Plain arcs with no transition curves and no cant, no warnings about the norms: the track goes where it's clicked"
: "Transition curves and cant for the design speed, warnings when the radius, the cant or the transitions don't meet the norms");
}
if (changed && false == m_route.chain.tracks.empty())
route_update();
return changed;
}
void editor_mode::render_lay_ui() void editor_mode::render_lay_ui()
{ {
auto &tool{m_lay}; auto &tool{m_lay};
{ render_norms_choice();
int norms{m_norms_free ? 0 : 1}; ImGui::Separator();
char const *names[]{STR_C("free"), STR_C("PKP PLK")}; ImGui::PushItemWidth(120.0f);
ImGui::PushItemWidth(120.0f); ImGui::DragScalar(STR_C("Curve radius (m)"), ImGuiDataType_Double, &tool.radius, 5.0f, nullptr, nullptr, "%.0f");
if (ImGui::Combo(STR_C("Norms"), &norms, names, IM_ARRAYSIZE(names))) item_tooltip("Drag to change, Ctrl+click to type the value. While laying: Ctrl+wheel");
{ tool.radius = std::max(10.0, tool.radius);
m_norms_free = norms == 0; ImGui::DragScalar(STR_C("Speed (km/h)"), ImGuiDataType_Double, &tool.style.velocity, 1.0f, nullptr, nullptr, "%.0f");
tool.transitions = false == m_norms_free; tool.style.velocity = std::clamp(tool.style.velocity, 0.0, 400.0);
} item_tooltip(m_norms_free ? "Speed limit of the new paths; the speed of the track joined comes first"
ImGui::PopItemWidth(); : "Speed limit of the new paths, and the design speed of the transition curves and of the cant; the speed of the track joined comes first, and none higher than the radius allows");
item_tooltip("Free: plain arcs with no transition curves and no cant, no warnings about the norms, the track goes where it's clicked.\nPKP PLK: transition curves and cant for the design speed, warnings when the radius, the cant or the transitions don't meet the norms"); ImGui::PopItemWidth();
} render_layout_combo();
if (auto *track{selected_track()}; track != nullptr) if (auto *track{selected_track()}; track != nullptr)
{ {
std::string reason; std::string reason;
if (editor_track::can_edit_geometry(*track, reason)) if (editor_track::can_edit_geometry(*track, reason))
render_extend_ui(); render_extend_ui();
} }
if (ImGui::CollapsingHeader(STR_C("Parallel track"), ImGuiTreeNodeFlags_DefaultOpen))
render_parallel_ui();
ImGui::Separator();
ImGui::PushItemWidth(120.0f);
ImGui::DragScalar(STR_C("Curve radius (m)"), ImGuiDataType_Double, &tool.radius, 5.0f, nullptr, nullptr, "%.0f");
item_tooltip("Drag to change, Ctrl+click to type the value");
tool.radius = std::max(10.0, tool.radius);
ImGui::DragScalar(STR_C("Speed (km/h)"), ImGuiDataType_Double, &tool.style.velocity, 1.0f, nullptr, nullptr, "%.0f");
tool.style.velocity = std::clamp(tool.style.velocity, 0.0, 400.0);
item_tooltip("Speed limit of the new paths, and the design speed of the transition curves and of the cant; the speed of the track joined comes first, and none higher than the radius allows");
ImGui::PopItemWidth();
render_layout_combo();
if (false == ImGui::TreeNode(STR_C("More settings"))) if (false == ImGui::TreeNode(STR_C("More settings")))
{ {
render_lay_status(); render_lay_status();
return; return;
} }
ImGui::PushItemWidth(120.0f); ImGui::PushItemWidth(120.0f);
ImGui::Checkbox(STR_C("Transition curves and cant"), &tool.transitions);
item_tooltip("Lengths and the cant recommended for the speed and the radius; off: plain circular arcs with no cant");
ImGui::DragScalar(STR_C("Longest path (m)"), ImGuiDataType_Double, &tool.piece_length, 1.0f, nullptr, nullptr, "%.0f"); ImGui::DragScalar(STR_C("Longest path (m)"), ImGuiDataType_Double, &tool.piece_length, 1.0f, nullptr, nullptr, "%.0f");
tool.piece_length = std::clamp(tool.piece_length, 5.0, 1000.0); tool.piece_length = std::clamp(tool.piece_length, 5.0, 1000.0);
ImGui::PopItemWidth(); ImGui::PopItemWidth();

View File

@@ -222,7 +222,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
intent.track = under.track; intent.track = under.track;
intent.path = under.path; intent.path = under.path;
if (shift) if (shift)
return make(kind::select, "Click: choose this track, the parallel track goes beside it"); return make(kind::select, "Click: the Parallel tool (N) with this track");
return make(kind::lay, "Click: start on the ground beside this track. Shift+click: a parallel track to it, T: a switch into it"); return make(kind::lay, "Click: start on the ground beside this track. Shift+click: a parallel track to it, T: a switch into it");
} }
return make(kind::lay, lay.points.empty() ? "Click: start of the new track" : "Click: lay the track to here"); return make(kind::lay, lay.points.empty() ? "Click: start of the new track" : "Click: lay the track to here");
@@ -381,6 +381,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
case track_tab::turnout: return make(kind::select, m_hover.track->eType == tt_Switch ? "Click: edit this switch" : m_switch.armed < 0 ? "Click: choose this track, then the type of the switch" : "Click: choose this track, then press and drag on it for the switch"); case track_tab::turnout: return make(kind::select, m_hover.track->eType == tt_Switch ? "Click: edit this switch" : m_switch.armed < 0 ? "Click: choose this track, then the type of the switch" : "Click: choose this track, then press and drag on it for the switch");
case track_tab::profile: return make(kind::select, "Click: the grade line through this track"); case track_tab::profile: return make(kind::select, "Click: the grade line through this track");
case track_tab::lineside: return make(kind::select, "Click: the line the objects go along"); case track_tab::lineside: return make(kind::select, "Click: the line the objects go along");
case track_tab::parallel: return make(kind::select, "Click: the straight the new track goes beside");
default: return make(kind::select, "Click: select"); default: return make(kind::select, "Click: select");
} }
} }
@@ -498,6 +499,8 @@ void editor_mode::track_press(track_intent const &Intent)
} }
} }
select_track(track != nullptr ? track : node); select_track(track != nullptr ? track : node);
if (m_track_tab == track_tab::lay && track != nullptr)
show_track_tab(track_tab::parallel);
}); });
return; return;
} }
@@ -1422,10 +1425,9 @@ void editor_mode::render_lineside_ui()
bool *expand; bool *expand;
std::function<void()> render; std::function<void()> render;
}; };
std::array<tab, 4> const tabs{{ std::array<tab, 3> const tabs{{
{"Hectometre posts", &m_hekto.open, &m_hekto.expand, [this]() { render_hekto_ui(); }}, {"Hectometre posts", &m_hekto.open, &m_hekto.expand, [this]() { render_hekto_ui(); }},
{"Fouling points", &m_fouling.open, &m_fouling.expand, [this]() { render_fouling_ui(); }}, {"Fouling points", &m_fouling.open, &m_fouling.expand, [this]() { render_fouling_ui(); }},
{"Parallel track", &m_parallel.open, &m_parallel.expand, [this]() { render_parallel_ui(); }},
{"Vehicle", &m_vehicle.open, &m_vehicle.expand, [this]() { render_vehicle_ui(); }}, {"Vehicle", &m_vehicle.open, &m_vehicle.expand, [this]() { render_vehicle_ui(); }},
}}; }};
if (selected_track() == nullptr) if (selected_track() == nullptr)

View File

@@ -174,6 +174,7 @@ bool editor_mode::vehicle_place()
return false; return false;
} }
tool.placed = head; tool.placed = head;
first_step_done(first_step::drive);
tool.status = format(STR_C("%s and %d vehicle(s) behind it stand on %s. It isn't saved with the scenery"), head.c_str(), static_cast<int>(vehicles.size()) - 1, tool.track->name().empty() ? "(noname)" : tool.track->name().c_str()); tool.status = format(STR_C("%s and %d vehicle(s) behind it stand on %s. It isn't saved with the scenery"), head.c_str(), static_cast<int>(vehicles.size()) - 1, tool.track->name().empty() ? "(noname)" : tool.track->name().c_str());
WriteLog("Editor: " + tool.status, logtype::generic); WriteLog("Editor: " + tool.status, logtype::generic);
return true; return true;

View File

@@ -14,6 +14,7 @@ http://mozilla.org/MPL/2.0/.
#include "application/editormode.h" #include "application/editormode.h"
#include "application/editoruilayer.h" #include "application/editoruilayer.h"
#include "editor/editorIcons.hpp" #include "editor/editorIcons.hpp"
#include "editor/editorSettings.hpp"
#include "rendering/renderer.h" #include "rendering/renderer.h"
#include "utilities/Globals.h" #include "utilities/Globals.h"
#include "utilities/translation.h" #include "utilities/translation.h"
@@ -168,8 +169,7 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
add(track_tab::path, icon::select, false); add(track_tab::path, icon::select, false);
add(track_tab::lay, icon::lay_track, false); add(track_tab::lay, icon::lay_track, false);
add(track_tab::turnout, icon::turnout, false); add(track_tab::turnout, icon::turnout, false);
add(track_tab::straights, icon::straight, false); add(track_tab::parallel, icon::parallel, false);
add(track_tab::route, icon::curve, false);
add(track_tab::turntable, icon::turntable, false); add(track_tab::turntable, icon::turntable, false);
add(track_tab::signals, icon::signal, true); add(track_tab::signals, icon::signal, true);
add(track_tab::lineside, icon::objects, false); add(track_tab::lineside, icon::objects, false);
@@ -177,7 +177,17 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
show_track_tab(vehicle ? track_tab::path : track_tab::lineside); show_track_tab(vehicle ? track_tab::path : track_tab::lineside);
m_vehicle.expand = false == vehicle; m_vehicle.expand = false == vehicle;
}}); }});
add(track_tab::profile, icon::profile, true); auto const advanced{m_track_tab == track_tab::straights || m_track_tab == track_tab::route || m_track_tab == track_tab::profile || m_track_tab == track_tab::speed || m_track_tab == track_tab::joints || m_track_tab == track_tab::infra || m_gauge.open};
auto const more{EditorSettings.track_tools_more()};
Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("The tools that correct a line already laid: straight, curve, profile, speed, joints, infrastructure, structure gauge"), more, [more]() {
EditorSettings.track_tools_more(false == more);
EditorSettings.save();
}, true});
if (false == more && false == advanced)
break;
add(track_tab::straights, icon::straight, true);
add(track_tab::route, icon::curve, false);
add(track_tab::profile, icon::profile, false);
add(track_tab::speed, icon::speed, false); add(track_tab::speed, icon::speed, false);
add(track_tab::joints, icon::joints, false); add(track_tab::joints, icon::joints, false);
add(track_tab::infra, icon::infra, false); add(track_tab::infra, icon::infra, false);

View File

@@ -50,6 +50,8 @@ enum class icon
infra, infra,
gauge, gauge,
turntable, turntable,
parallel,
more,
// the fields of work // the fields of work
work_surroundings, work_surroundings,
work_tracks, work_tracks,

View File

@@ -104,6 +104,8 @@ bool editorSettings::load()
parse(value, m_palette); parse(value, m_palette);
else if (key == "first_steps") else if (key == "first_steps")
m_first_steps = (value == "1"); m_first_steps = (value == "1");
else if (key == "track_tools_more")
m_track_tools_more = (value == "1");
else if (key.rfind(origin_prefix, 0) == 0) else if (key.rfind(origin_prefix, 0) == 0)
{ {
// northing;easting // northing;easting
@@ -148,6 +150,7 @@ bool editorSettings::save()
stream << "nodebank_card " << m_nodebank_card << "\n"; stream << "nodebank_card " << m_nodebank_card << "\n";
stream << "colours " << m_palette << "\n"; stream << "colours " << m_palette << "\n";
stream << "first_steps " << (m_first_steps ? 1 : 0) << "\n"; stream << "first_steps " << (m_first_steps ? 1 : 0) << "\n";
stream << "track_tools_more " << (m_track_tools_more ? 1 : 0) << "\n";
stream << std::fixed << std::setprecision(3); stream << std::fixed << std::setprecision(3);
for (auto const &origin : m_orthophoto_origins) for (auto const &origin : m_orthophoto_origins)
stream << origin.first << " " << origin.second.first << ";" << origin.second.second << "\n"; stream << origin.first << " " << origin.second.first << ";" << origin.second.second << "\n";

View File

@@ -56,6 +56,8 @@ public:
bool first_steps() const { return m_first_steps; } bool first_steps() const { return m_first_steps; }
void first_steps(bool Show) { m_first_steps = Show; } void first_steps(bool Show) { m_first_steps = Show; }
bool track_tools_more() const { return m_track_tools_more; }
void track_tools_more(bool Show) { m_track_tools_more = Show; }
private: private:
movement_scheme m_movement{movement_scheme::wsad}; movement_scheme m_movement{movement_scheme::wsad};
@@ -67,6 +69,7 @@ private:
int m_nodebank_card{96}; int m_nodebank_card{96};
int m_palette{0}; int m_palette{0};
bool m_first_steps{true}; bool m_first_steps{true};
bool m_track_tools_more{false};
}; };
// global editor settings instance // global editor settings instance

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -321,6 +321,21 @@ def turntable(d):
line(d, [(32 + math.cos(r) * 24, 32 + math.sin(r) * 24), (32 + math.cos(r) * 31, 32 + math.sin(r) * 31)], W - 4) line(d, [(32 + math.cos(r) * 24, 32 + math.sin(r) * 24), (32 + math.cos(r) * 31, 32 + math.sin(r) * 31)], W - 4)
def parallel(d):
# a track and a second one beside it, with the spacing between them
for x in (8, 22):
line(d, [(x, 60), (x, 4)], W - 6)
for x in (42, 56):
dashed(d, (x, 60), (x, 4), 8, 6, W - 6)
line(d, [(26, 32), (38, 32)], W - 8)
arrowhead(d, 40, 32, 0, 10)
def more(d):
for x in (12, 32, 52):
circle(d, x, 32, 6)
# the fields of work of the editor, in the row over the toolbar # the fields of work of the editor, in the row over the toolbar
@@ -366,7 +381,7 @@ def work_terrain(d):
ICONS = [select, insert, brush, area_fill, copy_to_bank, translate, rotate, scale, ICONS = [select, insert, brush, area_fill, copy_to_bank, translate, rotate, scale,
local_space, ortho, perspective, sculpt, smooth, chunks, orthophoto, road, local_space, ortho, perspective, sculpt, smooth, chunks, orthophoto, road,
place, lanes, lay_track, switch, straight, curve, signal, objects, place, lanes, lay_track, switch, straight, curve, signal, objects,
vehicle, profile, speed, joints, infra, gauge, turntable, work_surroundings, vehicle, profile, speed, joints, infra, gauge, turntable, parallel, more, work_surroundings,
work_tracks, work_roads, work_terrain] work_tracks, work_roads, work_terrain]

View File

@@ -5634,3 +5634,60 @@ msgstr "Shift+LPM na torze w L"
msgid "Choose it for a parallel track" msgid "Choose it for a parallel track"
msgstr "Wybiera go pod tor równoległy" msgstr "Wybiera go pod tor równoległy"
msgid "A second track beside a straight: LMB on the straight, then the side and the spacing"
msgstr "Drugi tor obok prostej: LPM na prostej, potem strona i rozstaw"
msgid "Parallel track: LMB on a straight"
msgstr "Tor równoległy: LPM na prostej"
msgid "Parallel track: the side and the spacing in the panel, then Lay"
msgstr "Tor równoległy: strona i rozstaw w panelu, potem Ułóż"
msgid "LMB on a straight"
msgstr "LPM na prostej"
msgid "the track the new one goes beside, green in the view"
msgstr "tor, obok którego pójdzie nowy, zielony w widoku"
msgid "Click: the straight the new track goes beside"
msgstr "Klik: prosta, obok której pójdzie nowy tor"
msgid "More"
msgstr "Więcej"
msgid "Less"
msgstr "Mniej"
msgid "The tools that correct a line already laid: straight, curve, profile, speed, joints, infrastructure, structure gauge"
msgstr "Narzędzia do poprawiania ułożonej linii: prosta, łuk, profil, prędkość, styki, infrastruktura, skrajnia"
msgid "Norms:"
msgstr "Normy:"
msgid "Plain arcs with no transition curves and no cant, no warnings about the norms: the track goes where it's clicked"
msgstr "Zwykłe łuki bez krzywych przejściowych i przechyłki, bez ostrzeżeń o normach: tor idzie tam, gdzie klikniesz"
msgid "Transition curves and cant for the design speed, warnings when the radius, the cant or the transitions don't meet the norms"
msgstr "Krzywe przejściowe i przechyłka dla prędkości projektowej, ostrzeżenia, gdy promień, przechyłka albo przejściówki nie spełniają norm"
msgid "Drag to change, Ctrl+click to type the value. While laying: Ctrl+wheel"
msgstr "Przeciągnij, by zmienić, Ctrl+klik, by wpisać. W trakcie układania: Ctrl+kółko"
msgid "Speed limit of the new paths; the speed of the track joined comes first"
msgstr "Ograniczenie prędkości nowych odcinków; pierwszeństwo ma prędkość dołączanego toru"
msgid "Drive it: Vehicle in the toolbar, pick a locomotive from the list, LMB on the track, then Place and drive"
msgstr "Przejedź się: Pojazd na pasku narzędzi, wybierz lokomotywę z listy, LPM na torze, potem Postaw i jedź"
msgid "the Parallel tool (N) with it"
msgstr "narzędzie Równoległy (N) z nią"
msgid "Parallel track: LMB on a straight, then the side and the spacing"
msgstr "Tor równoległy: LPM na prostej, potem strona i rozstaw"
msgid "The Parallel tool (N) with it"
msgstr "Narzędzie Równoległy (N) z tym torem"
msgid "Click: the Parallel tool (N) with this track"
msgstr "Klik: narzędzie Równoległy (N) z tym torem"