mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-10-26 15:54:53 +01:00
refactor(editor): the trainset is a tool of its own
The fourth tool out of editor_mode. The track under the cursor and the first steps of the tutorial become types of their own, which the editor gives to the tools, and a tool shown as a tab of the lineside panel keeps its open and expanded flags in a tool_tab. The trainsets waiting for the save are handed to the editor by the tool, which hears back when they were written. The self-test command trainset moves with it.
This commit is contained in:
@@ -1286,9 +1286,8 @@ bool editor_mode::update()
|
||||
{
|
||||
Global.editor_tracks = (current_work_area() == work_area::tracks);
|
||||
selftest_step();
|
||||
if (m_vehicle.leave)
|
||||
if (m_vehicle.take_leave())
|
||||
{
|
||||
m_vehicle.leave = false;
|
||||
Application.pop_mode();
|
||||
return true;
|
||||
}
|
||||
@@ -1456,7 +1455,7 @@ bool editor_mode::update()
|
||||
{
|
||||
draw_hekto_overlay();
|
||||
draw_fouling_overlay();
|
||||
draw_vehicle_marker();
|
||||
m_vehicle.draw_overlay();
|
||||
}
|
||||
render_track_context();
|
||||
update_build_tools();
|
||||
@@ -2937,13 +2936,7 @@ bool editor_mode::save()
|
||||
auto const controls{turntable_controls(rootstatements)};
|
||||
auto const noses{nose_controls(rootstatements)};
|
||||
std::vector<std::string> trailing;
|
||||
std::erase_if(m_vehicle.trainsets, [](auto const &Trainset) {
|
||||
auto const *track{simulation::Paths.find(Trainset.track)};
|
||||
return track == nullptr || track->m_editorremoved;
|
||||
});
|
||||
auto const placed{m_vehicle.trainsets.size()};
|
||||
for (auto const &trainset : m_vehicle.trainsets)
|
||||
trailing.insert(trailing.end(), trainset.lines.begin(), trainset.lines.end());
|
||||
auto const placed{m_vehicle.trainset_lines(trailing)};
|
||||
if (placed == 0)
|
||||
starter_trainset(trailing);
|
||||
auto const result = scene::Layers.save(rootstatements, trailing);
|
||||
@@ -2952,10 +2945,7 @@ bool editor_mode::save()
|
||||
if (result.success && noses)
|
||||
m_nose_included = true;
|
||||
if (result.success && placed > 0)
|
||||
{
|
||||
m_vehicle.trainsets.clear();
|
||||
m_vehicle.status = format(STR_C("%d trainset(s) written to the scenery"), static_cast<int>(placed));
|
||||
}
|
||||
m_vehicle.trainsets_written();
|
||||
if (result.success && placed == 0 && trailing.size() == 3)
|
||||
{
|
||||
std::istringstream header{trailing.front()};
|
||||
@@ -5301,12 +5291,12 @@ void editor_mode::render_first_steps()
|
||||
}
|
||||
case trial::trainset:
|
||||
{
|
||||
ImGui::BeginDisabled(ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::lineside && m_vehicle.open);
|
||||
ImGui::BeginDisabled(ui()->mode() == nodebank_panel::TRACK && m_track_tab == track_tab::lineside && m_vehicle.tab().open);
|
||||
if (ImGui::Button(STR_C("The trainset tool")))
|
||||
{
|
||||
choose_work_area(work_area::tracks);
|
||||
show_track_tab(track_tab::lineside);
|
||||
m_vehicle.expand = true;
|
||||
m_vehicle.tab().expand = true;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
break;
|
||||
|
||||
@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
#include "application/editormodegauge.h"
|
||||
#include "application/editormodejoints.h"
|
||||
#include "application/editormodespeed.h"
|
||||
#include "application/editormodevehicle.h"
|
||||
#include "application/editortool.h"
|
||||
#include "scene/sceneeditor.h"
|
||||
#include "scene/scenenode.h"
|
||||
@@ -55,12 +56,6 @@ class TAnimModel;
|
||||
// a tool of a field of work of the editor, a button in the toolbar and over the 3d view
|
||||
struct editor_tool_button;
|
||||
class TTrack;
|
||||
namespace ui
|
||||
{
|
||||
class vehicles_bank;
|
||||
struct vehicle_desc;
|
||||
struct skin_set;
|
||||
}
|
||||
|
||||
class editor_mode : public application_mode, private editor_track::observer, private editor_services
|
||||
{
|
||||
@@ -240,9 +235,9 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
void render_help_menu();
|
||||
void render_shortcuts_window();
|
||||
bool m_shortcuts_open{false};
|
||||
enum class 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 };
|
||||
using first_step = editor_first_step;
|
||||
void render_first_steps();
|
||||
void first_step_done(first_step const Step);
|
||||
void first_step_done(first_step const Step) override;
|
||||
bool m_first_steps_open{false};
|
||||
std::array<bool, static_cast<std::size_t>(first_step::count)> m_first_steps_done{};
|
||||
int m_tutorial_page{0};
|
||||
@@ -718,6 +713,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
bool track_editing() const override;
|
||||
std::size_t history_size() const override;
|
||||
glm::dvec3 camera_position() const override;
|
||||
track_hover const &hovered_track() const override;
|
||||
void render_path_ui();
|
||||
void draw_track_overlay() const;
|
||||
editor_track::point_ref track_handle_hit() const;
|
||||
@@ -1516,13 +1512,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
// a scenery with no tracks yet: in the middle of the view, how the first one is laid
|
||||
void draw_empty_scenery_hint();
|
||||
// path under the cursor, outlined before a click so it's known which one the click takes
|
||||
struct track_hover
|
||||
{
|
||||
TTrack *track{nullptr};
|
||||
int path{0};
|
||||
glm::dvec3 point{0.0};
|
||||
double since{0.0};
|
||||
};
|
||||
using track_hover = ::track_hover;
|
||||
track_hover m_hover;
|
||||
track_hover track_under_cursor(TTrack const *Only = nullptr, float const Pixels = 0.0f) const;
|
||||
track_hover split_spot() const;
|
||||
@@ -1925,49 +1915,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
void render_fouling_ui();
|
||||
void draw_fouling_overlay() const;
|
||||
|
||||
// a trainset put on the selected path, written to the scenery on save, or only to be driven
|
||||
struct vehicle_tool
|
||||
{
|
||||
bool open{false};
|
||||
bool expand{false};
|
||||
std::shared_ptr<ui::vehicles_bank> bank;
|
||||
char search[64]{};
|
||||
bool controllable_only{true};
|
||||
std::shared_ptr<ui::vehicle_desc> vehicle;
|
||||
std::shared_ptr<ui::skin_set> skin;
|
||||
int driver{0}; // 0: a driver, to be driven; 1: nobody, parked
|
||||
TTrack *track{nullptr};
|
||||
glm::dvec3 point{0.0};
|
||||
std::string placed;
|
||||
std::string status;
|
||||
bool leave{false}; // the editor gives way to the driving at the start of the next frame
|
||||
struct consist_vehicle
|
||||
{
|
||||
std::shared_ptr<ui::vehicle_desc> vehicle;
|
||||
std::shared_ptr<ui::skin_set> skin;
|
||||
bool turned{false};
|
||||
};
|
||||
std::vector<consist_vehicle> consist;
|
||||
int picked{-1}; // vehicle of the train whose buttons are shown
|
||||
std::set<ui::skin_set const *> minis; // skins whose side view was asked for
|
||||
int facing{1};
|
||||
bool write{true};
|
||||
char timetable[64]{"none"};
|
||||
double velocity{0.0};
|
||||
struct trainset
|
||||
{
|
||||
std::string head;
|
||||
std::string track;
|
||||
std::vector<std::string> lines;
|
||||
};
|
||||
std::vector<trainset> trainsets;
|
||||
};
|
||||
vehicle_tool m_vehicle;
|
||||
void vehicle_start(TTrack &Track, glm::dvec3 const &Point);
|
||||
bool vehicle_place();
|
||||
void render_vehicle_ui();
|
||||
void draw_vehicle_marker() const;
|
||||
|
||||
struct signal_template
|
||||
{
|
||||
std::string file;
|
||||
@@ -2445,7 +2392,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
|
||||
gauge_tool m_gauge{*this};
|
||||
speed_tool m_speed{*this};
|
||||
joints_tool m_joints{*this};
|
||||
std::vector<editor_tool *> m_tools{&m_gauge, &m_speed, &m_joints};
|
||||
vehicle_tool m_vehicle{*this};
|
||||
std::vector<editor_tool *> m_tools{&m_gauge, &m_speed, &m_joints, &m_vehicle};
|
||||
|
||||
void infra_rebase();
|
||||
void render_infra_search();
|
||||
|
||||
@@ -293,29 +293,6 @@ editor_mode::selftest_result editor_mode::selftest_scene(std::string const &comm
|
||||
WriteLog(format("SELFTEST mapstate orthophoto %d top %d extent %.0f mark %s camera %.1f %.1f %.1f", m_orthophoto.enabled() ? 1 : 0, Global.EditorOrtho ? 1 : 0, Global.EditorOrthoExtent, marked.empty() ? "-" : marked.front().c_str(), Camera.Pos.x, Camera.Pos.y, Camera.Pos.z));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "trainset")
|
||||
{
|
||||
std::string name;
|
||||
std::string vehicle;
|
||||
std::string skin;
|
||||
int facing{1};
|
||||
words >> name >> vehicle >> skin >> facing >> m_vehicle.velocity;
|
||||
auto *track{simulation::Paths.find(name)};
|
||||
if (track == nullptr)
|
||||
return selftest_result::handled;
|
||||
auto desc{std::make_shared<ui::vehicle_desc>()};
|
||||
desc->path = vehicle;
|
||||
auto set{std::make_shared<ui::skin_set>()};
|
||||
set->skin = skin;
|
||||
m_vehicle.consist.clear();
|
||||
m_vehicle.vehicle = desc;
|
||||
m_vehicle.skin = set;
|
||||
vehicle_start(*track, geometry::bezier{track->m_paths.front()}.point(0.5));
|
||||
m_vehicle.facing = facing;
|
||||
auto const placed{vehicle_place()};
|
||||
WriteLog(format("SELFTEST trainset %s placed %d pending %d: %s", name.c_str(), placed ? 1 : 0, static_cast<int>(m_vehicle.trainsets.size()), m_vehicle.status.c_str()));
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "selectmodel")
|
||||
{
|
||||
glm::dvec3 point{0.0};
|
||||
|
||||
@@ -388,7 +388,7 @@ editor_mode::selftest_result editor_mode::selftest_sweep(std::string const &comm
|
||||
std::string tab;
|
||||
words >> tab;
|
||||
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.tab().expand : tab == "hekto" ? m_hekto.expand : tab == "fouling" ? m_fouling.expand : m_parallel.expand) = true;
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "bendpanel")
|
||||
|
||||
@@ -142,7 +142,7 @@ editor_mode::selftest_result editor_mode::selftest_track(std::string const &comm
|
||||
m_hekto.expand = tab == 1;
|
||||
m_fouling.expand = tab == 2;
|
||||
m_parallel.expand = tab == 3;
|
||||
m_vehicle.expand = tab == 4;
|
||||
m_vehicle.tab().expand = tab == 4;
|
||||
return selftest_result::handled;
|
||||
}
|
||||
if (command == "curve")
|
||||
|
||||
@@ -67,6 +67,11 @@ glm::dvec3 editor_mode::camera_position() const
|
||||
return Camera.Pos;
|
||||
}
|
||||
|
||||
editor_mode::track_hover const &editor_mode::hovered_track() const
|
||||
{
|
||||
return m_hover;
|
||||
}
|
||||
|
||||
void editor_mode::set_current_node(scene::basic_node *Node)
|
||||
{
|
||||
m_node = Node;
|
||||
@@ -554,7 +559,7 @@ void editor_mode::render_track_inspector()
|
||||
m_hekto.open = false;
|
||||
m_fouling.open = false;
|
||||
m_parallel.open = false;
|
||||
m_vehicle.open = false;
|
||||
m_vehicle.tab().open = false;
|
||||
}
|
||||
ui()->set_track(m_track_window_open);
|
||||
if (false == m_track_window_open)
|
||||
|
||||
@@ -793,7 +793,7 @@ void editor_mode::render_track_context()
|
||||
if (ImGui::MenuItem(STR_C("Place a vehicle here")))
|
||||
{
|
||||
show_track_tab(track_tab::lineside);
|
||||
vehicle_start(*track, point);
|
||||
m_vehicle.start(*track, point);
|
||||
}
|
||||
if (ImGui::MenuItem(STR_C("Hectometre posts from here")))
|
||||
{
|
||||
@@ -1479,7 +1479,7 @@ void editor_mode::render_lineside_ui()
|
||||
std::array<tab, 3> const tabs{{
|
||||
{"Hectometre posts", &m_hekto.open, &m_hekto.expand, [this]() { render_hekto_ui(); }},
|
||||
{"Fouling points", &m_fouling.open, &m_fouling.expand, [this]() { render_fouling_ui(); }},
|
||||
{"Trainset", &m_vehicle.open, &m_vehicle.expand, [this]() { render_vehicle_ui(); }},
|
||||
{"Trainset", &m_vehicle.tab().open, &m_vehicle.tab().expand, [this]() { m_vehicle.render_options(); }},
|
||||
}};
|
||||
if (selected_track() == nullptr)
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", STR_C("LMB on a track: the line the objects go along"));
|
||||
|
||||
@@ -8,8 +8,7 @@ http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "application/editormode.h"
|
||||
#include "application/editoruilayer.h"
|
||||
#include "application/editormodevehicle.h"
|
||||
#include "application/editorprojection.h"
|
||||
#include "application/editormodeshared.h"
|
||||
#include "application/application.h"
|
||||
@@ -154,18 +153,18 @@ double distance_along(TTrack const &Track, int const Path, glm::dvec3 const &Poi
|
||||
|
||||
} // namespace
|
||||
|
||||
void editor_mode::vehicle_start(TTrack &Track, glm::dvec3 const &Point)
|
||||
void vehicle_tool::start(TTrack &Track, glm::dvec3 const &Point)
|
||||
{
|
||||
m_vehicle.track = &Track;
|
||||
m_vehicle.point = Point;
|
||||
m_vehicle.expand = true;
|
||||
m_tab.expand = true;
|
||||
m_vehicle.status.clear();
|
||||
auto const heading{heading_at(Track, Track.eType == tt_Switch ? path_under(Track, Point) : 0, Point)};
|
||||
glm::dvec2 const away{Point.x - Global.pCamera.Pos.x, Point.z - Global.pCamera.Pos.z};
|
||||
m_vehicle.facing = glm::dot(heading, away) >= 0.0 ? 1 : -1;
|
||||
}
|
||||
|
||||
bool editor_mode::vehicle_place()
|
||||
bool vehicle_tool::place()
|
||||
{
|
||||
auto &tool{m_vehicle};
|
||||
if (tool.track == nullptr || tool.track->m_editorremoved)
|
||||
@@ -210,7 +209,7 @@ bool editor_mode::vehicle_place()
|
||||
return false;
|
||||
}
|
||||
tool.placed = head;
|
||||
first_step_done(first_step::drive);
|
||||
m_services.first_step_done(editor_first_step::drive);
|
||||
auto const trackname{tool.track->name().empty() ? std::string{STR("(no name)")} : tool.track->name()};
|
||||
auto const behind{static_cast<int>(vehicles.size()) - 1};
|
||||
tool.status = behind > 0 ? format(STR_P("%s and %d vehicle behind it stand on %s", "%s and %d vehicles behind it stand on %s", behind), head.c_str(), behind, trackname.c_str()) : format(STR_C("%s stands on %s"), head.c_str(), trackname.c_str());
|
||||
@@ -220,7 +219,7 @@ bool editor_mode::vehicle_place()
|
||||
{
|
||||
std::string timetable{tool.timetable};
|
||||
timetable.erase(std::remove_if(timetable.begin(), timetable.end(), [](unsigned char const Character) { return std::isspace(Character) != 0; }), timetable.end());
|
||||
vehicle_tool::trainset entry{head, tool.track->name(), {}};
|
||||
vehicle_state::trainset entry{head, tool.track->name(), {}};
|
||||
entry.lines.push_back("trainset " + (timetable.empty() ? std::string{"none"} : timetable) + " " + tool.track->name() + " " + to_string(offset, 2) + " " + to_string(tool.velocity, 0));
|
||||
if (against)
|
||||
entry.lines.push_back("reversed");
|
||||
@@ -238,14 +237,15 @@ bool editor_mode::vehicle_place()
|
||||
return true;
|
||||
}
|
||||
|
||||
void editor_mode::render_vehicle_ui()
|
||||
void vehicle_tool::render_options()
|
||||
{
|
||||
auto &tool{m_vehicle};
|
||||
auto *selected{selected_track()};
|
||||
if (selected != nullptr && selected == tool.track && m_hover.track == selected && ImGui::IsMouseClicked(0) && false == ImGui::GetIO().WantCaptureMouse)
|
||||
vehicle_start(*selected, m_hover.point);
|
||||
auto *selected{m_services.selected_track()};
|
||||
auto const &hover{m_services.hovered_track()};
|
||||
if (selected != nullptr && selected == tool.track && hover.track == selected && ImGui::IsMouseClicked(0) && false == ImGui::GetIO().WantCaptureMouse)
|
||||
start(*selected, hover.point);
|
||||
else if (selected != nullptr && selected != tool.track)
|
||||
vehicle_start(*selected, m_hover.track == selected ? m_hover.point : bezier{selected->m_paths.front()}.point(0.5));
|
||||
start(*selected, hover.track == selected ? hover.point : bezier{selected->m_paths.front()}.point(0.5));
|
||||
if (tool.track == nullptr)
|
||||
{
|
||||
ImGui::TextColored(ImVec4(1.0f, 0.8f, 0.3f, 1.0f), "%s", STR_C("LMB on a track: where the vehicle stands"));
|
||||
@@ -430,11 +430,11 @@ void editor_mode::render_vehicle_ui()
|
||||
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.2f, 0.55f, 0.25f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.25f, 0.65f, 0.3f, 1.0f));
|
||||
if (ImGui::Button(STR_C("Place"), ImVec2(half, tall)))
|
||||
vehicle_place();
|
||||
place();
|
||||
item_tooltip("A trainset on the track, placed where the track was clicked, or in the middle of the path");
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(STR_C("Place and drive"), ImVec2(-1.0f, tall)) && vehicle_place())
|
||||
if (ImGui::Button(STR_C("Place and drive"), ImVec2(-1.0f, tall)) && place())
|
||||
{
|
||||
Global.editor_enter_vehicle = tool.placed;
|
||||
tool.leave = true;
|
||||
@@ -461,10 +461,10 @@ void editor_mode::render_vehicle_ui()
|
||||
tool.trainsets.erase(tool.trainsets.begin() + static_cast<std::ptrdiff_t>(*drop));
|
||||
}
|
||||
|
||||
void editor_mode::draw_vehicle_marker() const
|
||||
void vehicle_tool::draw_overlay() const
|
||||
{
|
||||
auto const &tool{m_vehicle};
|
||||
if (false == tool.open || tool.track == nullptr)
|
||||
if (false == m_tab.open || tool.track == nullptr)
|
||||
return;
|
||||
screen_projection const projection;
|
||||
ImVec2 screen;
|
||||
@@ -490,3 +490,53 @@ void editor_mode::draw_vehicle_marker() const
|
||||
ImVec2 const side{-unit.y, unit.x};
|
||||
drawlist->AddTriangleFilled(ImVec2(end.x + unit.x * 10.0f, end.y + unit.y * 10.0f), ImVec2(end.x + side.x * 7.0f, end.y + side.y * 7.0f), ImVec2(end.x - side.x * 7.0f, end.y - side.y * 7.0f), colour);
|
||||
}
|
||||
|
||||
bool vehicle_tool::take_leave()
|
||||
{
|
||||
return std::exchange(m_vehicle.leave, false);
|
||||
}
|
||||
|
||||
std::size_t vehicle_tool::trainset_lines(std::vector<std::string> &Lines)
|
||||
{
|
||||
std::erase_if(m_vehicle.trainsets, [](auto const &Trainset) {
|
||||
auto const *track{simulation::Paths.find(Trainset.track)};
|
||||
return track == nullptr || track->m_editorremoved;
|
||||
});
|
||||
for (auto const &trainset : m_vehicle.trainsets)
|
||||
Lines.insert(Lines.end(), trainset.lines.begin(), trainset.lines.end());
|
||||
return m_vehicle.trainsets.size();
|
||||
}
|
||||
|
||||
void vehicle_tool::trainsets_written()
|
||||
{
|
||||
m_vehicle.status = format(STR_C("%d trainset(s) written to the scenery"), static_cast<int>(m_vehicle.trainsets.size()));
|
||||
m_vehicle.trainsets.clear();
|
||||
}
|
||||
|
||||
editor_selftest_result vehicle_tool::selftest(std::string const &Command, std::istringstream &Words)
|
||||
{
|
||||
if (Command == "trainset")
|
||||
{
|
||||
std::string name;
|
||||
std::string vehicle;
|
||||
std::string skin;
|
||||
int facing{1};
|
||||
Words >> name >> vehicle >> skin >> facing >> m_vehicle.velocity;
|
||||
auto *track{simulation::Paths.find(name)};
|
||||
if (track == nullptr)
|
||||
return editor_selftest_result::handled;
|
||||
auto desc{std::make_shared<ui::vehicle_desc>()};
|
||||
desc->path = vehicle;
|
||||
auto set{std::make_shared<ui::skin_set>()};
|
||||
set->skin = skin;
|
||||
m_vehicle.consist.clear();
|
||||
m_vehicle.vehicle = desc;
|
||||
m_vehicle.skin = set;
|
||||
start(*track, geometry::bezier{track->m_paths.front()}.point(0.5));
|
||||
m_vehicle.facing = facing;
|
||||
auto const placed{place()};
|
||||
WriteLog(format("SELFTEST trainset %s placed %d pending %d: %s", name.c_str(), placed ? 1 : 0, static_cast<int>(m_vehicle.trainsets.size()), m_vehicle.status.c_str()));
|
||||
return editor_selftest_result::handled;
|
||||
}
|
||||
return editor_selftest_result::unhandled;
|
||||
}
|
||||
|
||||
79
application/editormodevehicle.h
Normal file
79
application/editormodevehicle.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
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/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "application/editortool.h"
|
||||
|
||||
#include <memory>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace ui
|
||||
{
|
||||
class vehicles_bank;
|
||||
struct vehicle_desc;
|
||||
struct skin_set;
|
||||
}
|
||||
|
||||
// a trainset put on the selected path, written to the scenery on save, or only to be driven
|
||||
class vehicle_tool final : public editor_tool
|
||||
{
|
||||
public:
|
||||
explicit vehicle_tool(editor_services &Services) : m_services{Services} {}
|
||||
void draw_overlay() const override;
|
||||
void render_options() override;
|
||||
editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) override;
|
||||
tool_tab &tab() { return m_tab; }
|
||||
void start(TTrack &Track, glm::dvec3 const &Point);
|
||||
bool take_leave();
|
||||
std::size_t trainset_lines(std::vector<std::string> &Lines);
|
||||
void trainsets_written();
|
||||
|
||||
private:
|
||||
editor_services &m_services;
|
||||
tool_tab m_tab;
|
||||
struct vehicle_state
|
||||
{
|
||||
std::shared_ptr<ui::vehicles_bank> bank;
|
||||
char search[64]{};
|
||||
bool controllable_only{true};
|
||||
std::shared_ptr<ui::vehicle_desc> vehicle;
|
||||
std::shared_ptr<ui::skin_set> skin;
|
||||
int driver{0}; // 0: a driver, to be driven; 1: nobody, parked
|
||||
TTrack *track{nullptr};
|
||||
glm::dvec3 point{0.0};
|
||||
std::string placed;
|
||||
std::string status;
|
||||
bool leave{false}; // the editor gives way to the driving at the start of the next frame
|
||||
struct consist_vehicle
|
||||
{
|
||||
std::shared_ptr<ui::vehicle_desc> vehicle;
|
||||
std::shared_ptr<ui::skin_set> skin;
|
||||
bool turned{false};
|
||||
};
|
||||
std::vector<consist_vehicle> consist;
|
||||
int picked{-1}; // vehicle of the train whose buttons are shown
|
||||
std::set<ui::skin_set const *> minis; // skins whose side view was asked for
|
||||
int facing{1};
|
||||
bool write{true};
|
||||
char timetable[64]{"none"};
|
||||
double velocity{0.0};
|
||||
struct trainset
|
||||
{
|
||||
std::string head;
|
||||
std::string track;
|
||||
std::vector<std::string> lines;
|
||||
};
|
||||
std::vector<trainset> trainsets;
|
||||
};
|
||||
vehicle_state m_vehicle;
|
||||
bool place();
|
||||
};
|
||||
@@ -160,7 +160,7 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
||||
}
|
||||
case work_area::tracks:
|
||||
{
|
||||
auto const vehicle{m_track_tab == track_tab::lineside && m_vehicle.open};
|
||||
auto const vehicle{m_track_tab == track_tab::lineside && m_vehicle.tab().open};
|
||||
auto const add = [&](track_tab const Tab, bool const Group) {
|
||||
auto const &modes{track_modes()};
|
||||
auto const found{std::find_if(modes.begin(), modes.end(), [&](track_mode const &Mode) { return Mode.tab == Tab; })};
|
||||
@@ -191,7 +191,7 @@ void editor_mode::work_area_tools(std::vector<tool_button> &Buttons)
|
||||
add(track_tab::lineside, false);
|
||||
Buttons.push_back({icon::vehicle, STR_C("Trainset"), nullptr, STR_C("A trainset on the selected track: written to the scenery on save, and to drive at once"), vehicle, [this, vehicle]() {
|
||||
show_track_tab(vehicle ? track_tab::path : track_tab::lineside);
|
||||
m_vehicle.expand = false == vehicle;
|
||||
m_vehicle.tab().expand = false == vehicle;
|
||||
}});
|
||||
Buttons.back().accent = family_colour(1);
|
||||
add(track_tab::profile, true);
|
||||
|
||||
@@ -34,6 +34,22 @@ enum class editor_selftest_result
|
||||
again
|
||||
};
|
||||
|
||||
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 };
|
||||
|
||||
struct track_hover
|
||||
{
|
||||
TTrack *track{nullptr};
|
||||
int path{0};
|
||||
glm::dvec3 point{0.0};
|
||||
double since{0.0};
|
||||
};
|
||||
|
||||
struct tool_tab
|
||||
{
|
||||
bool open{false};
|
||||
bool expand{false};
|
||||
};
|
||||
|
||||
struct nmt_place
|
||||
{
|
||||
glm::dvec3 position{0.0}; // on the axis of the path
|
||||
@@ -52,6 +68,8 @@ class editor_services
|
||||
virtual bool track_editing() const = 0;
|
||||
virtual std::size_t history_size() const = 0;
|
||||
virtual glm::dvec3 camera_position() const = 0;
|
||||
virtual track_hover const &hovered_track() const = 0;
|
||||
virtual void first_step_done(editor_first_step const Step) = 0;
|
||||
virtual void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) = 0;
|
||||
virtual void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point) = 0;
|
||||
virtual void set_current_node(scene::basic_node *Node) = 0;
|
||||
|
||||
Reference in New Issue
Block a user