From 3c9c90b4681be88247f0bbf7b1ebf0486b554571 Mon Sep 17 00:00:00 2001 From: maj00r Date: Wed, 21 Oct 2026 09:00:59 +0200 Subject: [PATCH] refactor(editor): the structure gauge is a tool of its own The first step of taking the tools out of editor_mode: a tool keeps its own state and reaches the editor through editor_services, the few things it needs from it, instead of through every member of the editor. The editor holds its tools in a list for the hooks they share: a deleted node is forgotten by all of them in one place, and a self-test command the editor doesn't know goes to each of them. The gauge moves with its state, its window and its self-test command; the ImGui ids and the texts stay the same, and the self-test gives the same hits on the test scenery as before. --- application/editormode.cpp | 10 +-- application/editormode.h | 79 ++++------------------ application/editormodegauge.cpp | 87 ++++++++++++++---------- application/editormodegauge.h | 88 +++++++++++++++++++++++++ application/editormodeselftest.cpp | 3 + application/editormodeselftestsweep.cpp | 15 ----- application/editormodetrack.cpp | 15 +++++ application/editormodeviewport.cpp | 6 +- application/editortool.h | 52 +++++++++++++++ 9 files changed, 232 insertions(+), 123 deletions(-) create mode 100644 application/editormodegauge.h create mode 100644 application/editortool.h diff --git a/application/editormode.cpp b/application/editormode.cpp index 0dd4c8ee..9cd2df06 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -873,6 +873,8 @@ void editor_mode::nullify_history_pointers(scene::basic_node *node) if (ui()->node() == node) ui()->set_node(nullptr); infra_forget(node); + for (auto *tool : m_tools) + tool->forget(node); auto const followed = [node](infra::object_state const &State) { return State.saved.node == node; }; for (auto &s : m_history) @@ -1480,8 +1482,8 @@ bool editor_mode::update() bend_drag_update(); draw_bend_overlay(); } - update_gauge(); - render_gauge_window(); + m_gauge.update(); + m_gauge.render_windows(); // roads: trajectories of the lanes, and the tools of the road window update_road_tool(); @@ -3549,8 +3551,8 @@ void editor_mode::render_view_menu() ImGui::MenuItem(STR_C("Show lanes"), nullptr, &m_roadtool.lanes); if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", STR_C("The lanes of the roads drawn as the paths the vehicles take")); - if (ImGui::MenuItem(STR_C("Structure gauge"), nullptr, m_gauge.open)) - m_gauge.open = !m_gauge.open; + if (ImGui::MenuItem(STR_C("Structure gauge"), nullptr, m_gauge.is_open())) + m_gauge.toggle(); if (ImGui::IsItemHovered()) ImGui::SetTooltip("%s", STR_C("Checks which models enter the structure gauge of the tracks and the clearance over the roads (skrajnia budowli)")); ImGui::Separator(); diff --git a/application/editormode.h b/application/editormode.h index 05f2ec4e..7b0b0ade 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -14,6 +14,8 @@ http://mozilla.org/MPL/2.0/. #include "input/editormouseinput.h" #include "input/editorkeyboardinput.h" #include "vehicle/Camera.h" +#include "application/editormodegauge.h" +#include "application/editortool.h" #include "scene/sceneeditor.h" #include "scene/scenenode.h" #include "editor/editorTerrain.hpp" @@ -58,20 +60,10 @@ struct vehicle_desc; struct skin_set; } -class editor_mode : public application_mode, private editor_track::observer +class editor_mode : public application_mode, private editor_track::observer, private editor_services { public: - // model entering the structure gauge, at its deepest place - struct gauge_hit - { - std::string model; - glm::dvec3 point{0.0}; - double depth{0.0}; // m - TTrack const *track{nullptr}; // nearest one, may be gone by now - int path{0}; - glm::dvec2 direction{0.0, 1.0}; // of the track there, in the plan - }; // joint of the paths found wrong by the joints check struct joint_issue { @@ -742,7 +734,10 @@ class editor_mode : public application_mode, private editor_track::observer gizmo_operation m_gizmo_op{gizmo_operation::translate}; // current transform mode (translate/rotate/scale) float m_gizmo_snap{1.0f}; // translation snap step (metres) applied while Ctrl is held - TTrack *selected_track() const; + TTrack *selected_track() const override; + bool track_editing() const override; + std::size_t history_size() const override; + glm::dvec3 camera_position() const override; void render_path_ui(); void draw_track_overlay() const; editor_track::point_ref track_handle_hit() const; @@ -862,55 +857,8 @@ class editor_mode : public application_mode, private editor_track::observer std::string m_track_events_missing; void render_path_events(TTrack &Track); std::string m_track_mode_notice; - // structure gauge along the line of the selected path, shown in the 3d view - struct gauge_state - { - bool open{false}; // window - bool enabled{true}; // tunnel along the selected path - std::vector profiles; - int profile{0}; // railway - int road{-1}; - TTrack const *track{nullptr}; // scanned - std::size_t history{0}; - bool pending{false}; // rescan once the edit ends - struct - { - std::vector surface; // triangles of the tunnel - std::vector edges; // lines - std::vector hits; - } line; // along the selected path - struct - { - bool scanned{false}; - std::size_t history{0}; - std::string profile; - std::vector hits; - } map; // whole scenery - struct - { - std::vector surface; - std::vector edges; - } spot; // tunnel around the hit the camera went to - int current{-1}; // hit the camera went to - bool published{false}; // overlay up to date - std::shared_ptr scan; // of the whole scenery, done in slices over the frames - } m_gauge; - void gauge_load(); - // the chosen railway and road outlines - gauge::choice gauge_choice() const; - std::vector const &gauge_hits() const; - void update_gauge(); - void scan_gauge(TTrack &Track); - void scan_gauge_map(); - void step_gauge_map(); - void finish_gauge_map(); - void gauge_publish(); - void gauge_focus(int Index); - void gauge_spot(gauge_hit const &Hit); - void render_gauge_window(); - void render_gauge_hits(); - bool render_gauge_choice(char const *Label, int &Index, bool Road); - bool render_gauge_outline(int Index); + gauge_tool m_gauge{*this}; + std::vector m_tools{&m_gauge}; struct route_design { TTrack *from{nullptr}; @@ -1673,7 +1621,7 @@ class editor_mode : public application_mode, private editor_track::observer void split_track_at(TTrack &Track, glm::dvec3 const &Point); void focus_track(TTrack &Track, int const Path, glm::dvec3 const &Point); // the camera flies over Duration seconds to the place Distance back from the target along Look, looking along it - void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6); + void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) override; // paths found by their names struct track_search { @@ -2273,12 +2221,7 @@ class editor_mode : public application_mode, private editor_track::observer scripted_input input; }; selftest m_selftest; - enum class selftest_result - { - unhandled, - handled, - pause - }; + using selftest_result = editor_selftest_result; selftest_result selftest_scene(std::string const &command, std::istringstream &words); selftest_result selftest_sleepers(std::string const &command, std::istringstream &words); selftest_result selftest_sweep(std::string const &command, std::istringstream &words); diff --git a/application/editormodegauge.cpp b/application/editormodegauge.cpp index 84af9df3..4c2f2187 100644 --- a/application/editormodegauge.cpp +++ b/application/editormodegauge.cpp @@ -8,7 +8,8 @@ http://mozilla.org/MPL/2.0/. */ #include "stdafx.h" -#include "application/editormode.h" +#include "application/editormodegauge.h" +#include "editor/editorTrack.hpp" #include "application/editoruilayer.h" #include "editor/editorFormat.hpp" #include "editor/editorGauge.hpp" @@ -326,7 +327,7 @@ template void visit_triangles(TSubModel *Submodel, glm::dmat4 } // the triangle enters the gauge when any point of a grid spread over it does; the deepest such point goes to the hit -void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C, editor_mode::gauge_hit &Hit) +void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C, gauge_tool::gauge_hit &Hit) { auto const middle{(A + B + C) / 3.0}; if (false == Space.close(middle, std::max({glm::distance(middle, A), glm::distance(middle, B), glm::distance(middle, C)}))) @@ -353,24 +354,24 @@ void scan_triangle(corridor const &Space, glm::dvec3 const &A, glm::dvec3 const } // the deepest place of the model in the gauge, added to the hits when it enters it -void scan_model(corridor const &Space, TAnimModel &Instance, std::vector &Hits) +void scan_model(corridor const &Space, TAnimModel &Instance, std::vector &Hits) { if (false == Instance.visible() || Instance.Model() == nullptr || Instance.Model()->GetSMRoot() == nullptr) return; if (false == Space.nearby(Instance.location(), Instance.radius())) return; - editor_mode::gauge_hit hit{Instance.name(), Instance.location()}; + gauge_tool::gauge_hit hit{Instance.name(), Instance.location()}; visit_triangles(Instance.Model()->GetSMRoot(), placement(Instance), [&](glm::dvec3 const &A, glm::dvec3 const &B, glm::dvec3 const &C) { scan_triangle(Space, A, B, C, hit); }); if (hit.depth > 0.0) Hits.push_back(std::move(hit)); } // the same for the copies of a model laid along a curve -void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector &Hits) +void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector &Hits) { if (Sweep.m_editorremoved || false == Space.nearby(Sweep.location(), Sweep.radius())) return; - editor_mode::gauge_hit hit{Sweep.name(), Sweep.location()}; + gauge_tool::gauge_hit hit{Sweep.name(), Sweep.location()}; for (auto const &shape : Sweep.create_shapes()) { auto const &vertices{shape.data().vertices}; @@ -381,13 +382,13 @@ void scan_sweep(corridor const &Space, sweep_node &Sweep, std::vector &Hits) +void sort_hits(std::vector &Hits) { std::sort(Hits.begin(), Hits.end(), [](auto const &Left, auto const &Right) { return Left.depth > Right.depth; }); } // the models entering the gauge, the deepest first -void scan_models(corridor const &Space, std::vector &Hits) +void scan_models(corridor const &Space, std::vector &Hits) { for (auto *instance : simulation::Instances.sequence()) if (instance != nullptr) @@ -550,7 +551,7 @@ struct gauge_scan std::chrono::steady_clock::time_point started; }; -void editor_mode::gauge_load() +void gauge_tool::gauge_load() { if (m_gauge.profiles.empty()) m_gauge.profiles = gauge::load_profiles(gauge_file); @@ -568,18 +569,18 @@ void editor_mode::gauge_load() } } -gauge::choice editor_mode::gauge_choice() const +gauge::choice gauge_tool::gauge_choice() const { auto const pick{[&](int const Index) { return Index >= 0 ? &m_gauge.profiles[Index] : nullptr; }}; return {pick(m_gauge.profile), pick(m_gauge.road)}; } -std::vector const &editor_mode::gauge_hits() const +std::vector const &gauge_tool::gauge_hits() const { return m_gauge.map.scanned ? m_gauge.map.hits : m_gauge.line.hits; } -void editor_mode::update_gauge() +void gauge_tool::update() { if (m_gauge.scan) step_gauge_map(); @@ -590,9 +591,9 @@ void editor_mode::update_gauge() m_gauge.published = false; return; } - auto *track{m_gauge.enabled ? selected_track() : nullptr}; + auto *track{m_gauge.enabled ? m_services.selected_track() : nullptr}; // the geometry is rescanned once the edit ends - if (ImGui::IsMouseDown(0) || m_track_gizmo_using || m_dragging) + if (ImGui::IsMouseDown(0) || m_services.track_editing()) m_gauge.pending = true; else if (track == nullptr) { @@ -603,19 +604,19 @@ void editor_mode::update_gauge() m_gauge.published = false; } } - else if (track != m_gauge.track || m_history.size() != m_gauge.history || m_gauge.pending) + else if (track != m_gauge.track || m_services.history_size() != m_gauge.history || m_gauge.pending) { m_gauge.track = track; - m_gauge.history = m_history.size(); + m_gauge.history = m_services.history_size(); m_gauge.pending = false; scan_gauge(*track); m_gauge.published = false; } - if (false == m_gauge.published || glm::distance(Camera.Pos, EditorOverlay.origin) > gauge_origin_range) + if (false == m_gauge.published || glm::distance(m_services.camera_position(), EditorOverlay.origin) > gauge_origin_range) gauge_publish(); } -void editor_mode::scan_gauge(TTrack &Track) +void gauge_tool::scan_gauge(TTrack &Track) { gauge_load(); m_gauge.line = {}; @@ -631,7 +632,7 @@ void editor_mode::scan_gauge(TTrack &Track) m_gauge.current = -1; } -void editor_mode::scan_gauge_map() +void gauge_tool::scan_gauge_map() { gauge_load(); auto scan{std::make_shared()}; @@ -644,7 +645,7 @@ void editor_mode::scan_gauge_map() scan->space.emplace(scan->lines); m_gauge.map = {}; m_gauge.map.scanned = true; - m_gauge.map.history = m_history.size(); + m_gauge.map.history = m_services.history_size(); auto const name{[](gauge::profile const *Profile) { return Profile != nullptr ? Profile->name : std::string{"-"}; }}; m_gauge.map.profile = name(chosen.railway) + ", " + name(chosen.road); m_gauge.current = -1; @@ -652,7 +653,7 @@ void editor_mode::scan_gauge_map() m_gauge.scan = std::move(scan); } -void editor_mode::step_gauge_map() +void gauge_tool::step_gauge_map() { auto &scan{*m_gauge.scan}; auto const &instances{simulation::Instances.sequence()}; @@ -675,7 +676,7 @@ void editor_mode::step_gauge_map() finish_gauge_map(); } -void editor_mode::finish_gauge_map() +void gauge_tool::finish_gauge_map() { auto const scan{std::move(m_gauge.scan)}; auto &hits{m_gauge.map.hits}; @@ -690,11 +691,11 @@ void editor_mode::finish_gauge_map() gauge_focus(0); } -void editor_mode::gauge_publish() +void gauge_tool::gauge_publish() { m_gauge.published = true; EditorOverlay.clear(); - EditorOverlay.origin = Camera.Pos; + EditorOverlay.origin = m_services.camera_position(); auto const batch{[](glm::vec4 const &Color, unsigned int const Type, std::vector const &Points) { gfx::editor_overlay::batch result{Color, Type}; result.points.reserve(Points.size()); @@ -717,7 +718,7 @@ void editor_mode::gauge_publish() batch({0.2f, 1.0f, 0.3f, 0.5f}, GL_LINES, m_gauge.spot.edges)}; } -void editor_mode::gauge_focus(int const Index) +void gauge_tool::gauge_focus(int const Index) { auto const &hits{gauge_hits()}; if (hits.empty()) @@ -729,12 +730,12 @@ void editor_mode::gauge_focus(int const Index) // along the track, tangent to the gauge at the height of the place, from the end nearer to the camera glm::dvec3 look{hit.direction.x, 0.0, hit.direction.y}; look = glm::length(look) > 1e-6 ? glm::normalize(look) : glm::dvec3(0.0, 0.0, 1.0); - if (glm::dot(Camera.Pos - hit.point, look) > 0.0) + if (glm::dot(m_services.camera_position() - hit.point, look) > 0.0) look = -look; - fly_to(hit.point, look, gauge_view_distance); + m_services.fly_to(hit.point, look, gauge_view_distance); } -void editor_mode::gauge_spot(gauge_hit const &Hit) +void gauge_tool::gauge_spot(gauge_hit const &Hit) { m_gauge.spot = {}; auto const &paths{simulation::Paths.sequence()}; @@ -751,7 +752,7 @@ void editor_mode::gauge_spot(gauge_hit const &Hit) build_tunnel(*line, m_gauge.spot.surface, m_gauge.spot.edges); } -void editor_mode::render_gauge_window() +void gauge_tool::render_windows() { if (false == m_gauge.open) return; @@ -798,7 +799,7 @@ void editor_mode::render_gauge_window() m_gauge.current = -1; m_gauge.published = false; } - else if (m_gauge.map.history != m_history.size()) + else if (m_gauge.map.history != m_services.history_size()) ImGui::TextColored(ImVec4(1.0f, 0.75f, 0.3f, 1.0f), STR_C("The scenery changed since the scan (%s)"), m_gauge.map.profile.c_str()); } render_gauge_hits(); @@ -809,7 +810,7 @@ void editor_mode::render_gauge_window() ImGui::End(); } -void editor_mode::render_gauge_hits() +void gauge_tool::render_gauge_hits() { auto const &hits{gauge_hits()}; if (false == m_gauge.map.scanned && (false == m_gauge.enabled || m_gauge.track == nullptr)) @@ -841,7 +842,7 @@ void editor_mode::render_gauge_hits() ImGui::EndChild(); } -bool editor_mode::render_gauge_choice(char const *Label, int &Index, bool const Road) +bool gauge_tool::render_gauge_choice(char const *Label, int &Index, bool const Road) { bool changed{false}; ImGui::PushID(Label); @@ -863,7 +864,7 @@ bool editor_mode::render_gauge_choice(char const *Label, int &Index, bool const return changed; } -bool editor_mode::render_gauge_outline(int const Index) +bool gauge_tool::render_gauge_outline(int const Index) { if (Index < 0) return false; @@ -884,3 +885,23 @@ bool editor_mode::render_gauge_outline(int const Index) ImGui::TreePop(); return edited; } + +editor_selftest_result gauge_tool::selftest(std::string const &Command, std::istringstream &Words) +{ + if (Command == "gauge") + { + std::string name; + Words >> name; + if (auto *track{simulation::Paths.find(name)}) + { + scan_gauge(*track); + WriteLog(format("SELFTEST gauge %s: %d hits", name.c_str(), static_cast(m_gauge.line.hits.size()))); + for (auto const &hit : m_gauge.line.hits) + WriteLog(format("SELFTEST gauge hit %s depth %.3f at %.2f %.2f %.2f", hit.model.c_str(), hit.depth, hit.point.x, hit.point.y, hit.point.z)); + } + else + WriteLog("SELFTEST gauge " + name + ": no such track"); + return editor_selftest_result::handled; + } + return editor_selftest_result::unhandled; +} diff --git a/application/editormodegauge.h b/application/editormodegauge.h new file mode 100644 index 00000000..7e39d8d1 --- /dev/null +++ b/application/editormodegauge.h @@ -0,0 +1,88 @@ +/* +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 "editor/editorGauge.hpp" + +#include +#include +#include + +class gauge_tool final : public editor_tool +{ + public: + // model entering the structure gauge, at its deepest place + struct gauge_hit + { + std::string model; + glm::dvec3 point{0.0}; + double depth{0.0}; // m + TTrack const *track{nullptr}; // nearest one, may be gone by now + int path{0}; + glm::dvec2 direction{0.0, 1.0}; // of the track there, in the plan + }; + explicit gauge_tool(editor_services &Services) : m_services{Services} {} + void update() override; + void render_windows() override; + editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) override; + bool is_open() const { return m_gauge.open; } + void toggle() { m_gauge.open = !m_gauge.open; } + + private: + editor_services &m_services; + // structure gauge along the line of the selected path, shown in the 3d view + struct gauge_state + { + bool open{false}; // window + bool enabled{true}; // tunnel along the selected path + std::vector profiles; + int profile{0}; // railway + int road{-1}; + TTrack const *track{nullptr}; // scanned + std::size_t history{0}; + bool pending{false}; // rescan once the edit ends + struct + { + std::vector surface; // triangles of the tunnel + std::vector edges; // lines + std::vector hits; + } line; // along the selected path + struct + { + bool scanned{false}; + std::size_t history{0}; + std::string profile; + std::vector hits; + } map; // whole scenery + struct + { + std::vector surface; + std::vector edges; + } spot; // tunnel around the hit the camera went to + int current{-1}; // hit the camera went to + bool published{false}; // overlay up to date + std::shared_ptr scan; // of the whole scenery, done in slices over the frames + } m_gauge; + void gauge_load(); + // the chosen railway and road outlines + gauge::choice gauge_choice() const; + std::vector const &gauge_hits() const; + void scan_gauge(TTrack &Track); + void scan_gauge_map(); + void step_gauge_map(); + void finish_gauge_map(); + void gauge_publish(); + void gauge_focus(int Index); + void gauge_spot(gauge_hit const &Hit); + void render_gauge_hits(); + bool render_gauge_choice(char const *Label, int &Index, bool Road); + bool render_gauge_outline(int Index); +}; diff --git a/application/editormodeselftest.cpp b/application/editormodeselftest.cpp index 2a7909bd..dc810c1d 100644 --- a/application/editormodeselftest.cpp +++ b/application/editormodeselftest.cpp @@ -54,6 +54,9 @@ editor_mode::selftest_result editor_mode::selftest_dispatch(std::string const &c for (auto const group : {&editor_mode::selftest_scene, &editor_mode::selftest_sleepers, &editor_mode::selftest_sweep, &editor_mode::selftest_track, &editor_mode::selftest_switch, &editor_mode::selftest_rails, &editor_mode::selftest_join, &editor_mode::selftest_signal, &editor_mode::selftest_terrain, &editor_mode::selftest_props, &editor_mode::selftest_monkey}) if (auto const result{(this->*group)(command, words)}; result != selftest_result::unhandled) return result; + for (auto *tool : m_tools) + if (auto const result{tool->selftest(command, words)}; result != selftest_result::unhandled) + return result; return selftest_result::unhandled; } diff --git a/application/editormodeselftestsweep.cpp b/application/editormodeselftestsweep.cpp index 03ba0e21..814562f3 100644 --- a/application/editormodeselftestsweep.cpp +++ b/application/editormodeselftestsweep.cpp @@ -396,21 +396,6 @@ editor_mode::selftest_result editor_mode::selftest_sweep(std::string const &comm ui()->expand_bend(); return selftest_result::handled; } - if (command == "gauge") - { - std::string name; - words >> name; - if (auto *track{simulation::Paths.find(name)}) - { - scan_gauge(*track); - WriteLog(format("SELFTEST gauge %s: %d hits", name.c_str(), static_cast(m_gauge.line.hits.size()))); - for (auto const &hit : m_gauge.line.hits) - WriteLog(format("SELFTEST gauge hit %s depth %.3f at %.2f %.2f %.2f", hit.model.c_str(), hit.depth, hit.point.x, hit.point.y, hit.point.z)); - } - else - WriteLog("SELFTEST gauge " + name + ": no such track"); - return selftest_result::handled; - } if (command == "ttincludes") { std::string name; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index 73ade052..b84d6bf8 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -52,6 +52,21 @@ TTrack *editor_mode::selected_track() const return dynamic_cast(m_node); } +bool editor_mode::track_editing() const +{ + return m_track_gizmo_using || m_dragging; +} + +std::size_t editor_mode::history_size() const +{ + return m_history.size(); +} + +glm::dvec3 editor_mode::camera_position() const +{ + return Camera.Pos; +} + void editor_mode::select_track(scene::basic_node *Node) { auto *track = dynamic_cast(Node); diff --git a/application/editormodeviewport.cpp b/application/editormodeviewport.cpp index efa81240..7ba759f9 100644 --- a/application/editormodeviewport.cpp +++ b/application/editormodeviewport.cpp @@ -178,7 +178,7 @@ void editor_mode::work_area_tools(std::vector &Buttons) add(track_tab::turnout, false); add(track_tab::parallel, false); auto const advanced{m_track_tab == track_tab::turntable || m_track_tab == track_tab::signals || m_track_tab == track_tab::lineside || m_track_tab == track_tab::profile || m_track_tab == track_tab::speed || - m_track_tab == track_tab::joints || m_gauge.open}; + m_track_tab == track_tab::joints || m_gauge.is_open()}; auto const more{EditorSettings.track_tools_more()}; Buttons.push_back({icon::more, more ? STR_C("Less") : STR_C("More"), nullptr, STR_C("Turntable, signals, objects, trainset, profile, speed, joints, gauge"), more, [more]() { EditorSettings.track_tools_more(false == more); @@ -197,8 +197,8 @@ void editor_mode::work_area_tools(std::vector &Buttons) add(track_tab::profile, true); add(track_tab::speed, false); add(track_tab::joints, false); - Buttons.push_back({icon::gauge, STR_C("Structure gauge"), nullptr, STR_C("Checks which models enter the structure gauge of the tracks and the clearance over the roads (skrajnia budowli)"), m_gauge.open, - [this]() { m_gauge.open = !m_gauge.open; }}); + Buttons.push_back({icon::gauge, STR_C("Structure gauge"), nullptr, STR_C("Checks which models enter the structure gauge of the tracks and the clearance over the roads (skrajnia budowli)"), m_gauge.is_open(), + [this]() { m_gauge.toggle(); }}); Buttons.back().accent = family_colour(2); break; } diff --git a/application/editortool.h b/application/editortool.h new file mode 100644 index 00000000..1ddfc50f --- /dev/null +++ b/application/editortool.h @@ -0,0 +1,52 @@ +/* +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 +#include +#include + +#include + +class TTrack; +namespace scene +{ +class basic_node; +} + +enum class editor_selftest_result +{ + unhandled, + handled, + pause +}; + +class editor_services +{ + public: + virtual TTrack *selected_track() const = 0; + virtual bool track_editing() const = 0; + virtual std::size_t history_size() const = 0; + virtual glm::dvec3 camera_position() const = 0; + virtual void fly_to(glm::dvec3 const &Target, glm::dvec3 const &Look, double const Distance, double const Duration = 0.6) = 0; + + protected: + ~editor_services() = default; +}; + +class editor_tool +{ + public: + virtual ~editor_tool() = default; + virtual void update() {} + virtual void render_windows() {} + virtual void forget(scene::basic_node const *Node) {} + virtual editor_selftest_result selftest(std::string const &Command, std::istringstream &Words) { return editor_selftest_result::unhandled; } +};