mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-20 18:34:53 +02:00
- the template list shows the templates of the rail the selected track is laid with (railprofile s60/uic60: 60E1, s49: 49E1, s42: S42), a box shows them all - the words of the catalogue names are translated (movable nose, long, gauge, blades outside), the kind of a slip or a crossing its type says already is left out - shorter hints of the switch tool, of More and of the missing drives
244 lines
9.3 KiB
C++
244 lines
9.3 KiB
C++
/*
|
|
This Source Code Form is subject to the
|
|
terms of the Mozilla Public License, v.
|
|
2.0. If a copy of the MPL was not
|
|
distributed with this file, You can
|
|
obtain one at
|
|
http://mozilla.org/MPL/2.0/.
|
|
*/
|
|
|
|
// the panel of the switch tool: what it places, the templates and the options of that only, and how to place it
|
|
|
|
#include "stdafx.h"
|
|
#include "application/editormode.h"
|
|
#include "application/editormodeshared.h"
|
|
#include "editor/editorConnections.hpp"
|
|
#include "editor/editorFormat.hpp"
|
|
#include "utilities/translation.h"
|
|
#include "world/Track.h"
|
|
|
|
#include "imgui/imgui.h"
|
|
#include <algorithm>
|
|
#include <string>
|
|
|
|
namespace
|
|
{
|
|
|
|
// the next radio button on the same line as the last item, if it fits there
|
|
void same_line_if_fits(char const *Label)
|
|
{
|
|
auto const &style{ImGui::GetStyle()};
|
|
auto const width{ImGui::GetFrameHeight() + style.ItemInnerSpacing.x + ImGui::CalcTextSize(Label, nullptr, true).x};
|
|
auto const end{ImGui::GetItemRectMax().x + style.ItemSpacing.x + width};
|
|
if (end <= ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x)
|
|
ImGui::SameLine();
|
|
}
|
|
|
|
// whether the template is one of those the kind places
|
|
bool of_kind(editor_track::switch_template const &Template, int const Kind)
|
|
{
|
|
switch (Kind)
|
|
{
|
|
case 1: return Template.double_slip && Template.type != "Skrz";
|
|
case 2: return Template.double_slip && Template.type == "Skrz";
|
|
case 3: return false == Template.double_slip && false == Template.twofold();
|
|
default: return false == Template.double_slip;
|
|
}
|
|
}
|
|
|
|
// the rail of the switch templates fitting the track, by the rail profile it's laid with; empty where the profile doesn't tell
|
|
std::string rail_of(TTrack const *Track)
|
|
{
|
|
if (Track == nullptr || (Track->iCategoryFlag & 15) != 1)
|
|
return {};
|
|
auto const &profile{Track->m_profile1.first};
|
|
if (profile == "s60" || profile == "uic60")
|
|
return "60E1";
|
|
if (profile == "s49")
|
|
return "49E1";
|
|
if (profile == "s42")
|
|
return "S42";
|
|
return {};
|
|
}
|
|
|
|
// the name of the template in the language of the editor: the words of the catalogue translated, the kind of a slip or
|
|
// a crossing left out where its type says it
|
|
std::string translated(std::string Title)
|
|
{
|
|
auto const replace = [&](std::string const &From, std::string const &To) {
|
|
for (auto at{Title.find(From)}; at != std::string::npos; at = Title.find(From, at + To.size()))
|
|
Title.replace(at, From.size(), To);
|
|
};
|
|
for (auto const *redundant : {" single slip", " double slip", " crossing"})
|
|
replace(redundant, "");
|
|
for (auto const *word : {"the blades outside of the diamond", "movable nose", "gauge", "long"})
|
|
replace(word, STR(word));
|
|
return Title;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
std::string editor_mode::switch_template_label(editor_track::switch_template const &Template)
|
|
{
|
|
if (Template.source != nullptr)
|
|
return STR("Scenery: ") + Template.title() + " (" + std::to_string(Template.count) + "x)";
|
|
return (Template.own ? STR("Own: ") : std::string{"PLK: "}) + translated(Template.title());
|
|
}
|
|
|
|
editor_mode::switch_kind editor_mode::current_switch_kind() const
|
|
{
|
|
auto const &tool{m_switch};
|
|
if (tool.connection >= 0)
|
|
return switch_kind::connection;
|
|
if (tool.armed >= 0 && tool.armed < static_cast<int>(tool.templates.size()) && tool.templates[tool.armed].double_slip)
|
|
return tool.templates[tool.armed].type == "Skrz" ? switch_kind::crossing : switch_kind::slip;
|
|
return switch_kind::single;
|
|
}
|
|
|
|
bool editor_mode::switch_kind_offered(switch_kind const Kind) const
|
|
{
|
|
auto const &templates{m_switch.templates};
|
|
return std::any_of(templates.begin(), templates.end(), [&](editor_track::switch_template const &Template) { return of_kind(Template, static_cast<int>(Kind)); });
|
|
}
|
|
|
|
void editor_mode::choose_switch_kind(switch_kind const Kind)
|
|
{
|
|
auto &tool{m_switch};
|
|
tool.connection = (Kind == switch_kind::connection ? std::clamp(tool.connection_kind, 0, connection::kind_count - 1) : -1);
|
|
// the template chosen stays if it's of the kind, else the first one of the kind
|
|
auto const fits = [&](int const Index) { return Index >= 0 && Index < static_cast<int>(tool.templates.size()) && of_kind(tool.templates[Index], static_cast<int>(Kind)); };
|
|
if (fits(tool.armed))
|
|
return;
|
|
for (int i = 0; i < static_cast<int>(tool.templates.size()); ++i)
|
|
if (fits(i))
|
|
{
|
|
tool.last = i;
|
|
tool.armed = i;
|
|
tool.status.clear();
|
|
return;
|
|
}
|
|
tool.armed = -1;
|
|
}
|
|
|
|
void editor_mode::render_switch_ui()
|
|
{
|
|
auto &tool{m_switch};
|
|
auto const kind{current_switch_kind()};
|
|
|
|
// what to place, each with the templates and the options of its own only
|
|
struct choice
|
|
{
|
|
switch_kind kind;
|
|
char const *label;
|
|
char const *tooltip;
|
|
};
|
|
choice const choices[] = {{switch_kind::single, "Switch", "A switch in a straight or a curve"},
|
|
{switch_kind::slip, "Slip switch", "Rkp or Rkpd at a crossing of two straights"},
|
|
{switch_kind::crossing, "Crossing", "A crossing of two straights"},
|
|
{switch_kind::connection, "Connection", "Crossover, double, scissors, ladder"}};
|
|
ImGui::TextDisabled("%s", STR_C("What to place"));
|
|
auto first{true};
|
|
for (auto const &entry : choices)
|
|
{
|
|
if (entry.kind != switch_kind::single && false == switch_kind_offered(entry.kind))
|
|
continue;
|
|
if (false == first)
|
|
same_line_if_fits(STR_C(entry.label));
|
|
first = false;
|
|
if (ImGui::RadioButton(STR_C(entry.label), kind == entry.kind) && kind != entry.kind)
|
|
choose_switch_kind(entry.kind);
|
|
item_tooltip(entry.tooltip);
|
|
}
|
|
if (kind == switch_kind::connection)
|
|
{
|
|
for (int i = 0; i < connection::kind_count; ++i)
|
|
{
|
|
if (i > 0)
|
|
same_line_if_fits(connection_name(i));
|
|
ImGui::PushID(i);
|
|
if (ImGui::RadioButton(connection_name(i), tool.connection == i))
|
|
{
|
|
tool.connection = i;
|
|
tool.connection_kind = i;
|
|
}
|
|
ImGui::PopID();
|
|
}
|
|
}
|
|
|
|
// how to place it with the mouse
|
|
char const *how{nullptr};
|
|
switch (kind)
|
|
{
|
|
case switch_kind::slip: how = "Click a crossing of two straights"; break;
|
|
case switch_kind::crossing: how = "Click a crossing of two straights"; break;
|
|
case switch_kind::connection:
|
|
how = tool.connection == static_cast<int>(connection::kind::double_crossover) ? "Drag from a straight onto the other track. Shift+wheel: kind, Ctrl+wheel: R, Alt+wheel: where they meet" :
|
|
"Drag from a straight onto the other track. Shift+wheel: kind, Ctrl+wheel: R";
|
|
break;
|
|
default: how = "Click a track and drag: along for the direction, sideways for the side"; break;
|
|
}
|
|
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.3f, 1.0f));
|
|
ImGui::TextWrapped("%s", STR_C(how));
|
|
ImGui::PopStyleColor();
|
|
|
|
// the templates of the kind, by their names, for the rail of the selected track unless all are asked for; the lengths
|
|
// and the rest of the label in the tooltip
|
|
ImGui::TextDisabled("%s", STR_C(kind == switch_kind::connection ? "The first switch" : "Template"));
|
|
auto const rail{rail_of(selected_track())};
|
|
if (false == rail.empty())
|
|
{
|
|
ImGui::SameLine();
|
|
ImGui::Checkbox(format(STR_C("Rail of the track: %s##railonly"), rail.c_str()).c_str(), &tool.rail_only);
|
|
item_tooltip("Only the templates of the rail the selected track is laid with");
|
|
}
|
|
auto const shown = [&](editor_track::switch_template const &Template) {
|
|
return of_kind(Template, static_cast<int>(kind)) && (rail.empty() || false == tool.rail_only || Template.source != nullptr || Template.rail == rail || Template.rail == "-");
|
|
};
|
|
auto const listed{static_cast<int>(std::count_if(tool.templates.begin(), tool.templates.end(), shown))};
|
|
ImGui::BeginChild("##switchtemplates", ImVec2(0.0f, std::min(240.0f, (listed + 0.5f) * ImGui::GetTextLineHeightWithSpacing() + 8.0f)), true);
|
|
for (int i = 0; i < static_cast<int>(tool.templates.size()); ++i)
|
|
{
|
|
auto const &entry{tool.templates[i]};
|
|
if (false == shown(entry))
|
|
continue;
|
|
if (ImGui::Selectable((switch_template_label(entry) + "##switch" + std::to_string(i)).c_str(), tool.armed == i))
|
|
{
|
|
tool.last = i;
|
|
tool.armed = i;
|
|
}
|
|
if (ImGui::IsItemHovered())
|
|
ImGui::SetTooltip("%s", entry.label.c_str());
|
|
}
|
|
ImGui::EndChild();
|
|
if (kind == switch_kind::connection)
|
|
render_connection_options();
|
|
|
|
// the name and the drive of the next switch; a crossing has no moving parts
|
|
if (kind != switch_kind::crossing)
|
|
{
|
|
ImGui::PushItemWidth(120.0f);
|
|
ImGui::InputTextWithHint(STR_C("Name##switchname"), switch_name_for_new().c_str(), tool.name, sizeof(tool.name));
|
|
ImGui::PopItemWidth();
|
|
item_tooltip("Name of the next switch, its drive events are named after it; empty: the next free z1, z2...; a number at the end goes up with each switch");
|
|
if (render_switch_drive_choice())
|
|
if (auto *track{selected_track()}; track != nullptr && track->eType == tt_Switch && false == track->m_editorremoved)
|
|
apply_switch_drive_choice(*track);
|
|
}
|
|
if (false == tool.status.empty())
|
|
ImGui::TextColored(ImVec4(1.0f, 0.7f, 0.2f, 1.0f), "%s", tool.status.c_str());
|
|
|
|
if (ImGui::SmallButton(STR_C("Collect from the scenery")))
|
|
{
|
|
tool.templates = editor_track::standard_switch_templates();
|
|
auto const found{editor_track::find_switch_templates()};
|
|
tool.templates.insert(tool.templates.end(), found.begin(), found.end());
|
|
tool.collected = true;
|
|
arm_switch();
|
|
}
|
|
item_tooltip("Looks for the switches of the scenery, to use their shapes as the templates");
|
|
ImGui::SameLine();
|
|
if (ImGui::SmallButton(STR_C("Template editor...")))
|
|
m_switch_designer.open = true;
|
|
item_tooltip("Own switch templates: diverging tracks of straights, arcs and transition curves, double switches");
|
|
}
|