mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-21 07:13:19 +02:00
feat(track): 3D sleepers and switch timbers, blade heel and throw from templates, one rail carving pass
- sleepers3d / sleepers3dplain / sleepers3dbed in eu07.ini: timbers put together from the begin, main and end parts of a model and stretched to their length, plain sleepers of their own model; tracks whose plain sleepers would touch are laid as one cluster, lines of timbers led by priority and turned to the bisectors of frogs and crossings at a limited rate, whole timbers under crossings, split ones between tracks with room to part them, gaps filled per rail and overlaps shortened or dropped; clusters worked out in a background thread while driving, on demand in the editor - the ballast can be left out under the beams (sleepers3dbed no) - blades get their heel and throw from the switch template or blades <heel> <throw> in the scenery; blades of double switches run on into the track linking them to the next switch - rail cutting at frogs, wing rails, movable noses and switch crossings done by one carving pass (RailCarve) - tint of the rail treads applied to the colour only, without the matte band at the frog - a switch trailed through with a movable nose set the other way derails the vehicle - self-tests: sleepercheck, sharedzones, beamsnear, throw, sleepersbg
This commit is contained in:
@@ -212,7 +212,7 @@ void editor_mode::draw_track_hover() const
|
||||
{
|
||||
using kind = track_intent::kind;
|
||||
auto const *track{m_hover.track};
|
||||
if (track == nullptr || (m_intent.what != kind::select && m_intent.what != kind::box && m_intent.what != kind::straight_set) || m_intent.track != track)
|
||||
if (track == nullptr || (m_intent.what != kind::select && m_intent.what != kind::box && m_intent.what != kind::straight_set && m_intent.what != kind::pick_style) || m_intent.track != track)
|
||||
return;
|
||||
screen_projection const projection;
|
||||
if (track != selected_track())
|
||||
@@ -319,6 +319,13 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
if (m_track_style.picking && (m_track_tab == track_tab::path || m_track_tab == track_tab::turnout))
|
||||
{
|
||||
intent.track = m_hover.track;
|
||||
if (m_hover.track != nullptr)
|
||||
intent.position = m_hover.point;
|
||||
return make(kind::pick_style, m_hover.track != nullptr ? "Click: take the properties of this track" : "Click a track to take its properties, Esc: cancel");
|
||||
}
|
||||
if (m_track_tab == track_tab::path)
|
||||
{
|
||||
if (shift && control && m_hover.track != nullptr && rail(*m_hover.track))
|
||||
@@ -333,7 +340,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
if (shift && false == gizmo_frame::over())
|
||||
{
|
||||
intent.track = m_hover.track;
|
||||
return make(kind::box, m_hover.track == nullptr ? "Drag: the tracks in a box join the selection" : in_track_set(m_hover.track) ? "Click: take out of the selection, drag: a box" : "Click: add to the selection, drag: a box");
|
||||
return make(kind::box, m_hover.track == nullptr ? "Drag: the tracks in a box join the selection" : track_selected(m_hover.track) ? "Click: take out of the selection, drag: a box" : "Click: add to the selection, drag: a box");
|
||||
}
|
||||
if (auto const hit{track_handle_hit()}; hit.valid() && selected != nullptr)
|
||||
{
|
||||
@@ -356,6 +363,11 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
return make(kind::extend_end, diverging ? "Drag: the curve of the switch goes on; Ctrl+drag: move the end" : "Drag: a new track out of this end, as in laying; Ctrl+drag: move the end");
|
||||
}
|
||||
}
|
||||
if (control && false == alt && m_hover.track != nullptr && false == gizmo_frame::over())
|
||||
{
|
||||
intent.track = m_hover.track;
|
||||
return make(kind::box, track_selected(m_hover.track) ? "Click: take out of the selection" : "Click: add to the selection");
|
||||
}
|
||||
}
|
||||
if (m_track_tab == track_tab::straights)
|
||||
{
|
||||
@@ -413,7 +425,7 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
intent.track = m_hover.track;
|
||||
intent.path = m_hover.path;
|
||||
intent.position = m_hover.point;
|
||||
return make(kind::switch_slide, "Click: edit this switch, drag: slide it along the straight");
|
||||
return make(kind::switch_slide, m_track_tab == track_tab::path ? "Click: select this switch, drag: slide it along the straight" : "Click: edit this switch, drag: slide it along the straight");
|
||||
}
|
||||
if (selected != nullptr && false == selected->m_paths.empty())
|
||||
{
|
||||
@@ -441,6 +453,12 @@ editor_mode::track_intent editor_mode::track_intent_at(int const Mods)
|
||||
default: return make(kind::select, "Click: select");
|
||||
}
|
||||
}
|
||||
// a drag on the empty ground selects the tracks in a box, a click there clears the selection
|
||||
if (m_track_tab == track_tab::path && false == alt)
|
||||
{
|
||||
intent.index = 1;
|
||||
intent.what = kind::box;
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
|
||||
@@ -462,6 +480,10 @@ void editor_mode::update_track_intent()
|
||||
case kind::straight_handle:
|
||||
case kind::route_vertex:
|
||||
case kind::route_grip: ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll); break;
|
||||
case kind::box:
|
||||
if (m_intent.track != nullptr)
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
|
||||
break;
|
||||
default: ImGui::SetMouseCursor(ImGuiMouseCursor_Hand); break;
|
||||
}
|
||||
}
|
||||
@@ -482,7 +504,15 @@ void editor_mode::track_press(track_intent const &Intent)
|
||||
});
|
||||
return;
|
||||
case kind::sweep: sweep_press(); return;
|
||||
case kind::box: start_track_box(); return;
|
||||
case kind::box: start_track_box(Intent.index == 1); return;
|
||||
case kind::pick_style:
|
||||
if (Intent.track != nullptr)
|
||||
{
|
||||
copy_track_style(*Intent.track);
|
||||
m_track_style.picking = false;
|
||||
m_track_style.open = true;
|
||||
}
|
||||
return;
|
||||
case kind::spread:
|
||||
if (Intent.track != nullptr)
|
||||
track_spread_apply(*Intent.track);
|
||||
@@ -541,31 +571,31 @@ void editor_mode::track_press(track_intent const &Intent)
|
||||
}
|
||||
return;
|
||||
case kind::select:
|
||||
case kind::none:
|
||||
{
|
||||
auto *hovered{Intent.track};
|
||||
GfxRenderer->Pick_Node_Callback([this, hovered](scene::basic_node *node) {
|
||||
if (false == viewport_click())
|
||||
return;
|
||||
auto *track{hovered != nullptr ? hovered : dynamic_cast<TTrack *>(node)};
|
||||
if (m_track_tab == track_tab::path)
|
||||
case kind::none: track_click_select(Intent.track); return;
|
||||
}
|
||||
}
|
||||
|
||||
void editor_mode::track_click_select(TTrack *Hovered)
|
||||
{
|
||||
GfxRenderer->Pick_Node_Callback([this, Hovered](scene::basic_node *node) {
|
||||
if (false == viewport_click())
|
||||
return;
|
||||
auto *track{Hovered != nullptr ? Hovered : dynamic_cast<TTrack *>(node)};
|
||||
if (m_track_tab == track_tab::path)
|
||||
{
|
||||
m_track_set.clear();
|
||||
if (track == nullptr)
|
||||
{
|
||||
m_track_set.clear();
|
||||
if (track == nullptr)
|
||||
{
|
||||
m_node = nullptr;
|
||||
m_track_point = {};
|
||||
ui()->set_node(nullptr);
|
||||
return;
|
||||
}
|
||||
m_node = nullptr;
|
||||
m_track_point = {};
|
||||
ui()->set_node(nullptr);
|
||||
return;
|
||||
}
|
||||
select_track(track != nullptr ? track : node);
|
||||
if (m_track_tab == track_tab::lay && track != nullptr)
|
||||
show_track_tab(track_tab::parallel);
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
select_track(track != nullptr ? track : node);
|
||||
if (m_track_tab == track_tab::lay && track != nullptr)
|
||||
show_track_tab(track_tab::parallel);
|
||||
});
|
||||
}
|
||||
|
||||
void editor_mode::draw_track_intent() const
|
||||
@@ -688,7 +718,9 @@ void editor_mode::render_track_context()
|
||||
context.pending = false;
|
||||
if (track != nullptr && false == track->m_editorremoved)
|
||||
{
|
||||
select_track(track);
|
||||
// a track of the set keeps the set, the menu acts on all of them
|
||||
if (false == (m_track_set.size() >= 2 && in_track_set(track)))
|
||||
select_track(track);
|
||||
ImGui::OpenPopup("##trackcontext");
|
||||
ImGui::SetNextWindowPos(ImVec2(context.mouse.x, context.mouse.y));
|
||||
}
|
||||
@@ -703,7 +735,32 @@ void editor_mode::render_track_context()
|
||||
}
|
||||
auto const point{context.target.point};
|
||||
bool const normal{track->eType == tt_Normal && editor_track::is_supported(*track)};
|
||||
auto const tracks{selected_tracks()};
|
||||
auto const many{tracks.size() >= 2};
|
||||
ImGui::TextDisabled("%s (%s, %.1f m)", name_of(*track).c_str(), STR_C(type_of(*track)), track->Length());
|
||||
if (many)
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.65f, 0.2f, 1.0f), STR_P("one of %d selected tracks", "one of %d selected tracks", static_cast<long long>(tracks.size())), static_cast<int>(tracks.size()));
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(STR_C("Copy its properties"), "Ctrl+Shift+C"))
|
||||
copy_track_style(*track);
|
||||
auto const paste{many ? format(STR_P("Paste the properties on %d track", "Paste the properties on %d tracks", static_cast<long long>(tracks.size())), static_cast<int>(tracks.size())) : std::string{STR_C("Paste the properties")}};
|
||||
if (ImGui::MenuItem(paste.c_str(), "Ctrl+Shift+V", false, false == m_track_style.values.empty()))
|
||||
paste_track_style(tracks);
|
||||
if (false == m_track_style.values.empty() && ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip(STR_C("Properties of %s"), m_track_style.from.c_str());
|
||||
if (ImGui::BeginMenu(STR_C("Select alike")))
|
||||
{
|
||||
char const *const keys[] = {"rails", "trackbed", "speed", "environment", "circuits"};
|
||||
char const *const labels[] = {"The same rails", "The same trackbed", "The same speed", "The same environment", "The same track circuits"};
|
||||
for (std::size_t i = 0; i < std::size(keys); ++i)
|
||||
if (ImGui::MenuItem(STR_C(labels[i])))
|
||||
{
|
||||
auto const found{similar_tracks(track_property_index(keys[i]), {track})};
|
||||
select_tracks(found);
|
||||
ui()->set_status(format(STR_P("%s: %d track selected in the scenery", "%s: %d tracks selected in the scenery", static_cast<long long>(found.size())), STR_C(labels[i]), static_cast<int>(found.size())), false);
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(STR_C("Split here"), "K", false, normal))
|
||||
split_track_at(*track, point);
|
||||
@@ -743,14 +800,19 @@ void editor_mode::render_track_context()
|
||||
speed_start();
|
||||
}
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(in_track_set(track) ? STR_C("Take out of the selection") : STR_C("Add to the selection"), "Shift+LMB"))
|
||||
if (ImGui::MenuItem(track_selected(track) ? STR_C("Take out of the selection") : STR_C("Add to the selection"), "Shift+LMB"))
|
||||
track_set_toggle(*track);
|
||||
if (ImGui::MenuItem(STR_C("Look at it")))
|
||||
focus_track(*track, context.target.path, point);
|
||||
if (ImGui::MenuItem(STR_C("Copy the name"), nullptr, false, false == track->name().empty()))
|
||||
ImGui::SetClipboardText(track->name().c_str());
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem(STR_C("Delete"), "Del"))
|
||||
if (many)
|
||||
{
|
||||
if (ImGui::MenuItem(format(STR_P("Delete %d track", "Delete %d tracks", static_cast<long long>(tracks.size())), static_cast<int>(tracks.size())).c_str(), "Del"))
|
||||
track_set_delete();
|
||||
}
|
||||
else if (ImGui::MenuItem(STR_C("Delete"), "Del"))
|
||||
delete_selected_track();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
@@ -907,14 +969,30 @@ bool editor_mode::in_track_set(TTrack const *Track) const
|
||||
return std::find(m_track_set.begin(), m_track_set.end(), Track) != m_track_set.end();
|
||||
}
|
||||
|
||||
bool editor_mode::track_selected(TTrack const *Track) const
|
||||
{
|
||||
return Track != nullptr && (m_track_set.size() >= 2 ? in_track_set(Track) : Track == m_node);
|
||||
}
|
||||
|
||||
void editor_mode::track_set_prune()
|
||||
{
|
||||
m_track_set.erase(std::remove_if(m_track_set.begin(), m_track_set.end(), [](TTrack const *Track) { return Track == nullptr || Track->m_editorremoved; }), m_track_set.end());
|
||||
// the set is the selection only together with the selected track, another one chosen elsewhere ends it
|
||||
if (false == m_track_set.empty() && false == in_track_set(selected_track()))
|
||||
m_track_set.clear();
|
||||
}
|
||||
|
||||
void editor_mode::track_set_toggle(TTrack &Track)
|
||||
{
|
||||
track_set_prune();
|
||||
// the set is the selection only with the selected track in it, a set left from before is forgotten
|
||||
if (m_track_set.size() < 2 || false == in_track_set(selected_track()))
|
||||
m_track_set.clear();
|
||||
if (m_track_set.empty() && &Track == selected_track())
|
||||
{
|
||||
select_tracks({});
|
||||
return;
|
||||
}
|
||||
if (m_track_set.empty())
|
||||
if (auto *selected{selected_track()}; selected != nullptr && selected != &Track)
|
||||
m_track_set.push_back(selected);
|
||||
@@ -927,10 +1005,11 @@ void editor_mode::track_set_toggle(TTrack &Track)
|
||||
ui()->set_node(m_node);
|
||||
}
|
||||
|
||||
void editor_mode::start_track_box()
|
||||
void editor_mode::start_track_box(bool const Replace)
|
||||
{
|
||||
auto const &io{ImGui::GetIO()};
|
||||
m_track_box.active = true;
|
||||
m_track_box.replace = Replace;
|
||||
m_track_box.to = {io.MousePos.x, io.MousePos.y};
|
||||
m_track_box.from = m_track_box.to;
|
||||
m_track_box.hovered = m_hover.track;
|
||||
@@ -946,7 +1025,10 @@ void editor_mode::finish_track_box()
|
||||
box.to = {io.MousePos.x, io.MousePos.y};
|
||||
if (glm::length(box.to - box.from) < 6.0f)
|
||||
{
|
||||
if (box.hovered != nullptr && false == box.hovered->m_editorremoved)
|
||||
// a click on the empty ground: what the renderer finds there, a part of a track seen close up, or nothing
|
||||
if (box.replace)
|
||||
track_click_select(nullptr);
|
||||
else if (box.hovered != nullptr && false == box.hovered->m_editorremoved)
|
||||
track_set_toggle(*box.hovered);
|
||||
return;
|
||||
}
|
||||
@@ -954,7 +1036,9 @@ void editor_mode::finish_track_box()
|
||||
glm::vec2 const high{std::max(box.from.x, box.to.x), std::max(box.from.y, box.to.y)};
|
||||
screen_projection const projection;
|
||||
track_set_prune();
|
||||
if (m_track_set.empty())
|
||||
if (m_track_set.size() < 2 || false == in_track_set(selected_track()) || box.replace)
|
||||
m_track_set.clear();
|
||||
if (m_track_set.empty() && false == box.replace)
|
||||
if (auto *selected{selected_track()}; selected != nullptr)
|
||||
m_track_set.push_back(selected);
|
||||
for (auto *track : simulation::Paths.sequence())
|
||||
@@ -977,12 +1061,8 @@ void editor_mode::finish_track_box()
|
||||
if (inside)
|
||||
m_track_set.push_back(track);
|
||||
}
|
||||
if (false == m_track_set.empty())
|
||||
{
|
||||
m_node = m_track_set.back();
|
||||
m_track_point = {};
|
||||
ui()->set_node(m_node);
|
||||
}
|
||||
auto const found{m_track_set};
|
||||
select_tracks(found);
|
||||
}
|
||||
|
||||
std::vector<TTrack *> editor_mode::track_spread_from(TTrack &Start) const
|
||||
@@ -1063,6 +1143,8 @@ std::vector<TTrack *> const &editor_mode::track_spread_preview(TTrack &Start) co
|
||||
void editor_mode::track_spread_apply(TTrack &Start)
|
||||
{
|
||||
track_set_prune();
|
||||
if (m_track_set.size() < 2 || false == in_track_set(selected_track()))
|
||||
m_track_set.clear();
|
||||
if (m_track_set.empty())
|
||||
if (auto *selected{selected_track()}; selected != nullptr && selected != &Start)
|
||||
m_track_set.push_back(selected);
|
||||
@@ -1077,9 +1159,8 @@ void editor_mode::track_spread_apply(TTrack &Start)
|
||||
if (false == in_track_set(track))
|
||||
m_track_set.push_back(track);
|
||||
m_spread.from = nullptr;
|
||||
m_node = m_track_set.empty() ? nullptr : m_track_set.back();
|
||||
m_track_point = {};
|
||||
ui()->set_node(m_node);
|
||||
auto const found{m_track_set};
|
||||
select_tracks(found);
|
||||
}
|
||||
|
||||
void editor_mode::track_set_grow()
|
||||
@@ -1158,7 +1239,21 @@ void editor_mode::draw_track_set() const
|
||||
drawlist->AddRectFilled(from, io.MousePos, IM_COL32(255, 160, 40, 40));
|
||||
drawlist->AddRect(from, io.MousePos, IM_COL32(255, 160, 40, 220), 0.0f, 0, 1.5f);
|
||||
}
|
||||
if (m_track_set.size() < 2)
|
||||
auto const *listed{m_track_list_hover_frame >= ImGui::GetFrameCount() - 1 ? m_track_list_hover : nullptr};
|
||||
if (listed != nullptr && false == listed->m_editorremoved)
|
||||
for (auto const &path : listed->m_paths)
|
||||
{
|
||||
bezier const curve{path};
|
||||
auto const count{std::clamp(static_cast<int>(curve.plan_length() / 3.0), 6, 64)};
|
||||
auto previous{curve.point(0.0)};
|
||||
for (int k = 1; k <= count; ++k)
|
||||
{
|
||||
auto const next{curve.point(static_cast<double>(k) / count)};
|
||||
projection.line(drawlist, previous, next, IM_COL32(255, 255, 255, 240), 6.0f);
|
||||
previous = next;
|
||||
}
|
||||
}
|
||||
if (m_track_set.size() < 2 || false == in_track_set(selected_track()))
|
||||
return;
|
||||
for (auto const *track : m_track_set)
|
||||
{
|
||||
@@ -1179,41 +1274,6 @@ void editor_mode::draw_track_set() const
|
||||
}
|
||||
}
|
||||
|
||||
void editor_mode::track_set_apply(std::function<bool(TTrack &)> const &Change, bool const Rebuild, char const *What)
|
||||
{
|
||||
track_set_prune();
|
||||
std::vector<std::pair<TTrack *, editor_track::state>> states;
|
||||
std::vector<TTrack *> changed;
|
||||
std::size_t locked{0};
|
||||
for (auto *track : m_track_set)
|
||||
{
|
||||
if (false == scene::Layers.editable(track))
|
||||
{
|
||||
++locked;
|
||||
continue;
|
||||
}
|
||||
auto const before{editor_track::capture(*track)};
|
||||
if (false == Change(*track))
|
||||
continue;
|
||||
states.emplace_back(track, before);
|
||||
changed.push_back(track);
|
||||
}
|
||||
if (changed.empty())
|
||||
return;
|
||||
push_track_snapshot(std::move(states));
|
||||
for (auto *track : changed)
|
||||
{
|
||||
if (Rebuild)
|
||||
editor_track::commit_parameters(*track);
|
||||
else
|
||||
track->mark_dirty();
|
||||
}
|
||||
auto status{format(STR_C("%s set on %zu paths, Ctrl+Z takes it back"), STR_C(What), changed.size())};
|
||||
if (locked > 0)
|
||||
status += format(STR_C(", %zu in the files which can't be changed are left as they are"), locked);
|
||||
ui()->set_status(status, false);
|
||||
}
|
||||
|
||||
void editor_mode::track_set_delete()
|
||||
{
|
||||
track_set_prune();
|
||||
@@ -1246,93 +1306,13 @@ void editor_mode::track_set_delete()
|
||||
void editor_mode::render_track_set_ui()
|
||||
{
|
||||
track_set_prune();
|
||||
if (m_track_set.size() < 2)
|
||||
if (m_track_set.size() < 2 || false == in_track_set(selected_track()))
|
||||
return;
|
||||
auto &fields{m_track_set_fields};
|
||||
double length{0.0};
|
||||
for (auto const *track : m_track_set)
|
||||
length += track->Length();
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.65f, 0.2f, 1.0f), STR_C("%zu paths selected, %.1f m"), m_track_set.size(), length);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::SmallButton(STR_C("Clear")))
|
||||
{
|
||||
m_track_set.clear();
|
||||
return;
|
||||
}
|
||||
ImGui::TextDisabled("%s", STR_C("The gizmo moves them together; Shift+LMB adds or takes out a path"));
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.65f, 0.2f, 1.0f), STR_P("%d track selected", "%d tracks selected", static_cast<long long>(m_track_set.size())), static_cast<int>(m_track_set.size()));
|
||||
ImGui::PushTextWrapPos(0.0f);
|
||||
ImGui::TextDisabled("%s", STR_C("Their properties are in the inspector, the gizmo moves them together"));
|
||||
ImGui::PopTextWrapPos();
|
||||
render_parallel_set_ui();
|
||||
if (ImGui::SmallButton(STR_C("Grow by the neighbours")))
|
||||
track_set_grow();
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("%s", STR_C("Adds the paths joined to the set, by the rules of the spread"));
|
||||
auto const button_width{90.0f};
|
||||
ImGui::PushItemWidth(-button_width - ImGui::GetStyle().ItemSpacing.x);
|
||||
ImGui::InputDouble("##setvelocity", &fields.velocity, 0.0, 0.0, "%.0f");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(format("%s##setv", STR_C("Velocity")).c_str(), ImVec2(button_width, 0.0f)))
|
||||
{
|
||||
auto const velocity{fields.velocity};
|
||||
track_set_apply([velocity](TTrack &Track) { editor_track::velocity(Track, velocity); return true; }, false, "Velocity");
|
||||
}
|
||||
ImGui::InputTextWithHint("##setrail", STR_C("texture of the rails"), fields.rail, sizeof(fields.rail));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(format("%s##setr", STR_C("Rails")).c_str(), ImVec2(button_width, 0.0f)) && fields.rail[0] != '\0')
|
||||
{
|
||||
auto const material{editor_track::fetch_material(fields.rail)};
|
||||
track_set_apply([material](TTrack &Track) {
|
||||
Track.m_material1 = material;
|
||||
if (Track.eType == tt_Switch)
|
||||
Track.m_material2 = material;
|
||||
return true;
|
||||
}, true, "Rails");
|
||||
}
|
||||
ImGui::InputTextWithHint("##settrackbed", STR_C("texture of the trackbed"), fields.trackbed, sizeof(fields.trackbed));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(format("%s##setb", STR_C("Trackbed")).c_str(), ImVec2(button_width, 0.0f)) && fields.trackbed[0] != '\0')
|
||||
{
|
||||
auto const material{editor_track::fetch_material(fields.trackbed)};
|
||||
track_set_apply([material](TTrack &Track) {
|
||||
if (Track.eType == tt_Switch)
|
||||
{
|
||||
if (Track.SwitchExtension == nullptr)
|
||||
return false;
|
||||
Track.SwitchExtension->m_material3 = material;
|
||||
}
|
||||
else
|
||||
Track.m_material2 = material;
|
||||
return true;
|
||||
}, true, "Trackbed");
|
||||
}
|
||||
ImGui::InputTextWithHint("##setcircuits", STR_C("track circuits, separated by spaces"), fields.circuits, sizeof(fields.circuits));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(format("%s##setc", STR_C("Circuits")).c_str(), ImVec2(button_width, 0.0f)))
|
||||
{
|
||||
std::vector<std::string> names;
|
||||
std::string const text{fields.circuits};
|
||||
std::size_t at{0};
|
||||
while (at < text.size())
|
||||
{
|
||||
auto const end{text.find(' ', at)};
|
||||
auto const word{text.substr(at, end == std::string::npos ? std::string::npos : end - at)};
|
||||
if (false == word.empty())
|
||||
names.push_back(word);
|
||||
if (end == std::string::npos)
|
||||
break;
|
||||
at = end + 1;
|
||||
}
|
||||
track_set_apply([names](TTrack &Track) { editor_track::isolated(Track, names); return true; }, false, "Circuits");
|
||||
}
|
||||
char const *environments[] = {"flat", "mountains", "canyon", "tunnel", "bridge", "bank"};
|
||||
ImGui::Combo("##setenvironment", &fields.environment, environments, IM_ARRAYSIZE(environments));
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(format("%s##sete", STR_C("Environment")).c_str(), ImVec2(button_width, 0.0f)))
|
||||
{
|
||||
auto const environment{static_cast<TEnvironmentType>(fields.environment)};
|
||||
track_set_apply([environment](TTrack &Track) { Track.eEnvironment = environment; return true; }, false, "Environment");
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
if (ImGui::Button(format(STR_C("Delete %zu paths"), m_track_set.size()).c_str()))
|
||||
track_set_delete();
|
||||
ImGui::Separator();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user