17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-10-26 17:04:53 +01:00

refactor(editor): the parallel track is a tool of its own

The seventh tool out of editor_mode. It reads the selected set of tracks
and the tab shown through the services, digitizes the tracks it lays and
refreshes the plan after it sets one parallel to another. The panel shown
for two selected tracks is a public call of the tool, and the self-test
command parallel moves with it and lays the same tracks as before.
This commit is contained in:
maj00r
2026-10-21 09:54:39 +02:00
parent 6ee771bb22
commit 872e1b5e19
9 changed files with 125 additions and 77 deletions

View File

@@ -1450,7 +1450,7 @@ bool editor_mode::update()
signal_move_update();
draw_signal_overlay();
}
draw_parallel_preview();
m_parallel.draw_overlay();
if (m_track_tab == track_tab::lineside)
{
m_hekto.draw_overlay();

View File

@@ -17,6 +17,7 @@ http://mozilla.org/MPL/2.0/.
#include "application/editormodegauge.h"
#include "application/editormodejoints.h"
#include "application/editormodelineside.h"
#include "application/editormodeparallel.h"
#include "application/editormodespeed.h"
#include "application/editormodevehicle.h"
#include "application/editortool.h"
@@ -715,6 +716,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
std::size_t history_size() const override;
glm::dvec3 camera_position() const override;
track_hover const &hovered_track() const override;
std::vector<TTrack *> const &track_set() const override;
editor_track_tab current_track_tab() const override;
void render_path_ui();
void draw_track_overlay() const;
editor_track::point_ref track_handle_hit() const;
@@ -910,7 +913,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
void record_slip(std::vector<TTrack *> const &Parts, std::string const &Kind, std::string const &Type, double const Radius, double const Angle, std::string const &Base, double const Middle = 0.0);
void render_switch_record(TTrack const &Track) const;
void route_store();
bool digitize_drawn(std::vector<TTrack *> const &Created, bool const Alone = true);
bool digitize_drawn(std::vector<TTrack *> const &Created, bool const Alone = true) override;
bool digitize_chain(editor_track::chain const &Chain, std::string *Reason = nullptr, TTrack **Culprit = nullptr);
int digitize_parts(editor_track::chain const &Chain, std::string *Reason, int &Skipped);
// the lines kept, the paths left out
@@ -1016,7 +1019,7 @@ class editor_mode : public application_mode, private editor_track::observer, pri
void apply_straight_tool();
double straight_tool_radius(editor_track::straight const &Line) const;
void straight_reshape(editor_track::straight const &Line, double const From, double const To, std::function<glm::dvec3(glm::dvec3 const &)> const &Tail, double const Radius);
void straight_refresh();
void straight_refresh() override;
bool start_curve_fit(editor_track::straight const &Line, int const Handle);
void update_curve_fit(glm::dvec3 const &Start, glm::dvec3 const &End);
void add_detour_point();
@@ -1736,40 +1739,6 @@ class editor_mode : public application_mode, private editor_track::observer, pri
std::vector<std::vector<TTrack *>> m_track_similar;
TTrack const *m_track_list_hover{nullptr}; // in the list of the selected tracks
int m_track_list_hover_frame{-1};
// second track alongside the selected path or the line through it, at a spacing, curves included
struct parallel_tool
{
bool open{false};
bool expand{false};
double spacing{4.0};
int side{1}; // 1: to the right, -1: to the left, of the direction of the line
int scope{1}; // 0: the selected path, 1: the line through it, up to the switches
TTrack *built_for{nullptr};
double built_spacing{0.0};
int built_side{0};
int built_scope{-1};
std::size_t built_history{0};
TTrack *pair_src{nullptr};
TTrack *pair_dst{nullptr};
double measured{0.0};
std::vector<segment_data> pieces;
std::vector<TTrack *> styles;
double length{0.0};
std::string error;
std::string status;
};
parallel_tool m_parallel;
TTrack *parallel_source() const;
TTrack *parallel_target() const;
void parallel_update();
void render_parallel_controls(bool const Scope = true);
void render_parallel_ui();
void render_parallel_set_ui();
void parallel_build();
void parallel_apply();
bool parallel_preview_visible() const;
void draw_parallel_preview() const;
using template_item = ::template_item;
using standing_template = ::standing_template;
// includes of the templates whose file names the test accepts, with the location in p2..p4 and the rotation in p5
@@ -2273,7 +2242,8 @@ class editor_mode : public application_mode, private editor_track::observer, pri
vehicle_tool m_vehicle{*this};
hekto_tool m_hekto{*this};
fouling_tool m_fouling{*this};
std::vector<editor_tool *> m_tools{&m_gauge, &m_speed, &m_joints, &m_vehicle, &m_hekto, &m_fouling};
parallel_tool m_parallel{*this};
std::vector<editor_tool *> m_tools{&m_gauge, &m_speed, &m_joints, &m_vehicle, &m_hekto, &m_fouling, &m_parallel};
void infra_rebase();
void render_infra_search();

View File

@@ -8,8 +8,7 @@ http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "application/editormode.h"
#include "application/editoruilayer.h"
#include "application/editormodeparallel.h"
#include "application/editorprojection.h"
#include "application/editormodeshared.h"
#include "editor/editorFormat.hpp"
@@ -209,21 +208,23 @@ double lateral_of(TTrack const &Src, TTrack const &Dst)
} // namespace
TTrack *editor_mode::parallel_source() const
TTrack *parallel_tool::parallel_source() const
{
if (m_track_set.size() >= 2)
return m_track_set.front();
return selected_track();
auto const &set{m_services.track_set()};
if (set.size() >= 2)
return set.front();
return m_services.selected_track();
}
TTrack *editor_mode::parallel_target() const
TTrack *parallel_tool::parallel_target() const
{
if (m_track_set.size() != 2)
auto const &set{m_services.track_set()};
if (set.size() != 2)
return nullptr;
return m_track_set.back() != m_track_set.front() ? m_track_set.back() : nullptr;
return set.back() != set.front() ? set.back() : nullptr;
}
void editor_mode::parallel_update()
void parallel_tool::parallel_update()
{
auto &tool{m_parallel};
auto *track{parallel_source()};
@@ -244,13 +245,13 @@ void editor_mode::parallel_update()
else if (track != nullptr && target != nullptr)
tool.measured = std::abs(lateral_of(*track, *target));
if (track == tool.built_for && tool.spacing == tool.built_spacing && tool.side == tool.built_side && tool.scope == tool.built_scope && m_history.size() == tool.built_history)
if (track == tool.built_for && tool.spacing == tool.built_spacing && tool.side == tool.built_side && tool.scope == tool.built_scope && m_services.history_size() == tool.built_history)
return;
tool.built_for = track;
tool.built_spacing = tool.spacing;
tool.built_side = tool.side;
tool.built_scope = tool.scope;
tool.built_history = m_history.size();
tool.built_history = m_services.history_size();
tool.pieces.clear();
tool.styles.clear();
tool.length = 0.0;
@@ -319,7 +320,7 @@ void editor_mode::parallel_update()
}
}
void editor_mode::parallel_build()
void parallel_tool::parallel_build()
{
auto &tool{m_parallel};
parallel_update();
@@ -329,8 +330,8 @@ void editor_mode::parallel_build()
for (std::size_t i = 0; i < tool.pieces.size(); ++i)
created.push_back(editor_track::create_path(*tool.styles[i], tool.pieces[i]));
editor_track::commit(created);
digitize_drawn(created);
push_track_snapshot({}, created);
m_services.digitize_drawn(created);
m_services.push_track_snapshot({}, created);
tool.status = format(STR_C("Parallel track of %zu paths, %.1f m, %.2f m away; Ctrl+Z takes it back"), created.size(), tool.length, tool.spacing);
if (scene::Layers.active() == null_handle)
tool.status += "\n" + std::string{STR_C("The scenery isn't opened for editing, the new track won't be saved")};
@@ -338,7 +339,7 @@ void editor_mode::parallel_build()
tool.built_for = nullptr;
}
void editor_mode::parallel_apply()
void parallel_tool::parallel_apply()
{
auto &tool{m_parallel};
auto *target{parallel_target()};
@@ -375,14 +376,14 @@ void editor_mode::parallel_apply()
if (joint.other != nullptr)
committed.push_back(joint.other);
editor_track::commit(committed);
push_track_snapshot(std::move(states));
m_services.push_track_snapshot(std::move(states));
tool.status = format(STR_C("%s set parallel to %s, %.2f m away; Ctrl+Z takes it back"), name_of(*target).c_str(), name_of(*parallel_source()).c_str(), tool.spacing);
WriteLog("Editor: " + tool.status, logtype::generic);
tool.built_for = nullptr;
straight_refresh();
m_services.straight_refresh();
}
void editor_mode::render_parallel_controls(bool const Scope)
void parallel_tool::render_parallel_controls(bool const Scope)
{
auto &tool{m_parallel};
if (Scope)
@@ -396,7 +397,7 @@ void editor_mode::render_parallel_controls(bool const Scope)
value_chips("spacings", tool.spacing, {kSpacings[0], kSpacings[1], kSpacings[2], kSpacings[3], kSpacings[4], kSpacings[5]}, "%.2f");
}
void editor_mode::render_parallel_ui()
void parallel_tool::render_options()
{
auto &tool{m_parallel};
ImGui::PushTextWrapPos(0.0f);
@@ -426,7 +427,7 @@ void editor_mode::render_parallel_ui()
ImGui::TextWrapped("%s", tool.status.c_str());
}
void editor_mode::render_parallel_set_ui()
void parallel_tool::render_set_options()
{
auto &tool{m_parallel};
auto *source{parallel_source()};
@@ -450,16 +451,16 @@ void editor_mode::render_parallel_set_ui()
ImGui::TextWrapped("%s", tool.status.c_str());
}
bool editor_mode::parallel_preview_visible() const
bool parallel_tool::parallel_preview_visible() const
{
if (m_parallel.pieces.empty() || parallel_source() != m_parallel.built_for)
return false;
if (m_track_tab == track_tab::parallel)
if (m_services.current_track_tab() == editor_track_tab::parallel)
return true;
return m_track_tab == track_tab::path && parallel_target() != nullptr;
return m_services.current_track_tab() == editor_track_tab::path && parallel_target() != nullptr;
}
void editor_mode::draw_parallel_preview() const
void parallel_tool::draw_overlay() const
{
if (false == parallel_preview_visible())
return;
@@ -488,3 +489,17 @@ void editor_mode::draw_parallel_preview() const
drawlist->AddText(ImVec2(screen.x + 12.0f, screen.y - 8.0f), IM_COL32(90, 255, 120, 255), label.c_str());
}
}
editor_selftest_result parallel_tool::selftest(std::string const &Command, std::istringstream &Words)
{
if (Command == "parallel")
{
Words >> m_parallel.spacing >> m_parallel.side;
m_parallel.scope = 1;
m_parallel.built_for = nullptr;
parallel_build();
WriteLog("SELFTEST parallel: " + m_parallel.status + " " + m_parallel.error);
return editor_selftest_result::handled;
}
return editor_selftest_result::unhandled;
}

View File

@@ -0,0 +1,58 @@
/*
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 <string>
#include <vector>
// second track alongside the selected path or the line through it, at a spacing, curves included
class parallel_tool final : public editor_tool
{
public:
explicit parallel_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 render_set_options();
private:
editor_services &m_services;
tool_tab m_tab;
struct parallel_state
{
double spacing{4.0};
int side{1}; // 1: to the right, -1: to the left, of the direction of the line
int scope{1}; // 0: the selected path, 1: the line through it, up to the switches
TTrack *built_for{nullptr};
double built_spacing{0.0};
int built_side{0};
int built_scope{-1};
std::size_t built_history{0};
TTrack *pair_src{nullptr};
TTrack *pair_dst{nullptr};
double measured{0.0};
std::vector<segment_data> pieces;
std::vector<TTrack *> styles;
double length{0.0};
std::string error;
std::string status;
};
parallel_state m_parallel;
TTrack *parallel_source() const;
TTrack *parallel_target() const;
void parallel_update();
void render_parallel_controls(bool const Scope = true);
void parallel_build();
void parallel_apply();
bool parallel_preview_visible() const;
};

View File

@@ -284,7 +284,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.tab().expand : tab == "hekto" ? m_hekto.tab().expand : tab == "fouling" ? m_fouling.tab().expand : m_parallel.expand) = true;
(tab == "vehicle" ? m_vehicle.tab().expand : tab == "hekto" ? m_hekto.tab().expand : tab == "fouling" ? m_fouling.tab().expand : m_parallel.tab().expand) = true;
return selftest_result::handled;
}
if (command == "bendpanel")

View File

@@ -141,7 +141,7 @@ editor_mode::selftest_result editor_mode::selftest_track(std::string const &comm
m_sweep.expand = tab == 0;
m_hekto.tab().expand = tab == 1;
m_fouling.tab().expand = tab == 2;
m_parallel.expand = tab == 3;
m_parallel.tab().expand = tab == 3;
m_vehicle.tab().expand = tab == 4;
return selftest_result::handled;
}
@@ -782,14 +782,5 @@ editor_mode::selftest_result editor_mode::selftest_track(std::string const &comm
WriteLog(format("SELFTEST digitize %s: %d", nearest != nullptr ? nearest->name().c_str() : "-", kept ? 1 : 0));
return selftest_result::handled;
}
if (command == "parallel")
{
words >> m_parallel.spacing >> m_parallel.side;
m_parallel.scope = 1;
m_parallel.built_for = nullptr;
parallel_build();
WriteLog("SELFTEST parallel: " + m_parallel.status + " " + m_parallel.error);
return selftest_result::handled;
}
return selftest_result::unhandled;
}

View File

@@ -72,6 +72,16 @@ editor_mode::track_hover const &editor_mode::hovered_track() const
return m_hover;
}
std::vector<TTrack *> const &editor_mode::track_set() const
{
return m_track_set;
}
editor_track_tab editor_mode::current_track_tab() const
{
return m_track_tab;
}
void editor_mode::set_current_node(scene::basic_node *Node)
{
m_node = Node;
@@ -558,7 +568,7 @@ void editor_mode::render_track_inspector()
m_sweep.open = false;
m_hekto.tab().open = false;
m_fouling.tab().open = false;
m_parallel.open = false;
m_parallel.tab().open = false;
m_vehicle.tab().open = false;
}
ui()->set_track(m_track_window_open);
@@ -611,7 +621,7 @@ void editor_mode::render_track_tool_options()
render_lay_ui();
break;
case track_tab::parallel:
render_parallel_ui();
m_parallel.render_options();
break;
case track_tab::turnout:
if (track != nullptr && track->eType == tt_Switch)

View File

@@ -1355,7 +1355,7 @@ void editor_mode::render_track_set_ui()
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();
m_parallel.render_set_options();
ImGui::Separator();
}

View File

@@ -92,6 +92,8 @@ class editor_services
virtual std::size_t history_size() const = 0;
virtual glm::dvec3 camera_position() const = 0;
virtual track_hover const &hovered_track() const = 0;
virtual std::vector<TTrack *> const &track_set() const = 0;
virtual editor_track_tab current_track_tab() const = 0;
virtual void first_step_done(editor_first_step const Step) = 0;
virtual void show_track_tab(editor_track_tab const Wanted) = 0;
virtual glm::dvec3 placement_on_ground(glm::dvec3 Location) = 0;
@@ -109,6 +111,8 @@ class editor_services
virtual std::size_t place_templates(std::vector<template_item> const &Items, std::string &Error) = 0;
virtual std::size_t move_templates(std::vector<std::pair<standing_template, template_item>> const &Moves) = 0;
virtual std::size_t remove_templates(std::vector<scene::instance_handle> const &Instances) = 0;
virtual bool digitize_drawn(std::vector<TTrack *> const &Created, bool const Alone = true) = 0;
virtual void straight_refresh() = 0;
virtual void push_track_snapshot(std::vector<std::pair<TTrack *, editor_track::state>> States, std::vector<TTrack *> Created = {}, std::vector<TTrack *> Removed = {}) = 0;
protected: