From 9cb268042bcbdd218ec2abf580bf611f404de50b Mon Sep 17 00:00:00 2001 From: tmj-fstate Date: Tue, 5 Mar 2019 19:45:15 +0100 Subject: [PATCH] scenario ui panel --- Driver.cpp | 51 +++++++++++++++++++-- Driver.h | 6 ++- Train.h | 2 + driveruilayer.cpp | 12 +++++ driveruilayer.h | 1 + driveruipanels.cpp | 86 +++++++++++++++++++++++++++++++++-- driveruipanels.h | 15 ++++++ scene.h | 1 + simulationstateserializer.cpp | 20 ++++++++ simulationstateserializer.h | 1 + translation.cpp | 36 +++++++++++++++ translation.h | 18 ++++++++ 12 files changed, 241 insertions(+), 8 deletions(-) diff --git a/Driver.cpp b/Driver.cpp index 3ba88202..c8783c5e 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -15,8 +15,9 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "Driver.h" -#include +//#include #include "Globals.h" +#include "translation.h" #include "Logs.h" #include "Train.h" #include "mtable.h" @@ -1696,9 +1697,54 @@ std::string TController::Order2Str(TOrders Order) const { } } +std::array orderbuffer; + std::string TController::OrderCurrent() const { // pobranie aktualnego rozkazu celem wyświetlenia - return "[" + std::to_string(OrderPos) + "] " + Order2Str(OrderList[OrderPos]); + auto const order { OrderCurrentGet() }; + if( order & Change_direction ) { + return locale::strings[ locale::string::driver_scenario_changedirection ]; + } + + switch( OrderList[ OrderPos ] ) { + case Wait_for_orders: { return locale::strings[ locale::string::driver_scenario_waitfororders ]; } + case Prepare_engine: { return locale::strings[ locale::string::driver_scenario_prepareengine ]; } + case Release_engine: { return locale::strings[ locale::string::driver_scenario_releaseengine ]; } + case Change_direction: { return locale::strings[ locale::string::driver_scenario_changedirection ]; } + case Connect: { return locale::strings[ locale::string::driver_scenario_connect ]; } + case Disconnect: { + if( iVehicleCount < 0 ) { + // done with uncoupling, order should update shortly + return locale::strings[ locale::string::driver_scenario_waitfororders ]; + } + // try to provide some task details + auto const count { iVehicleCount }; + + if( iVehicleCount > 1 ) { + std::snprintf( + orderbuffer.data(), orderbuffer.size(), + ( iVehicleCount < 5 ? + locale::strings[ locale::string::driver_scenario_fewvehicles ].c_str() : // 2-4 + locale::strings[ locale::string::driver_scenario_somevehicles ].c_str() ), // 5+ + count ); + } + auto const countstring { ( + count == 0 ? locale::strings[ locale::string::driver_scenario_allvehicles ] : + count == 1 ? locale::strings[ locale::string::driver_scenario_onevehicle ] : + orderbuffer.data() ) }; + + std::snprintf( + orderbuffer.data(), orderbuffer.size(), + locale::strings[ locale::string::driver_scenario_disconnect ].c_str(), + countstring.c_str() ); + return orderbuffer.data(); + } + case Shunt: { return locale::strings[ locale::string::driver_scenario_shunt ]; } + case Loose_shunt: { return locale::strings[ locale::string::driver_scenario_looseshunt ]; } + case Obey_train: { return locale::strings[ locale::string::driver_scenario_obeytrain ]; } + case Bank: { return locale::strings[ locale::string::driver_scenario_bank ]; } + default: { return{}; } + } }; void TController::OrdersClear() @@ -4699,7 +4745,6 @@ TController::UpdateSituation(double dt) { n = 0; // nie ma co dalej sprawdzać, doczepianie zakończone } } while (n--); - // write down what vehicle we're uncoupling, we might need to fiddle with remainder of the consist afterwards if( ( p == nullptr ) || ( p->MoverParameters->Couplers[ d ].Connected == nullptr ) ) { // no target, or already just virtual coupling diff --git a/Driver.h b/Driver.h index d55c4869..53f8900a 100644 --- a/Driver.h +++ b/Driver.h @@ -312,6 +312,10 @@ private: public: void PutCommand(std::string NewCommand, double NewValue1, double NewValue2, const TLocation &NewLocation, TStopReason reason = stopComm); bool PutCommand( std::string NewCommand, double NewValue1, double NewValue2, glm::dvec3 const *NewLocation, TStopReason reason = stopComm ); + // defines assignment data + inline auto assignment() -> std::string & { return m_assignment; } + inline auto assignment() const -> std::string const & { return m_assignment; } + std::string OrderCurrent() const; private: void RecognizeCommand(); // odczytuje komende przekazana lokomotywie void JumpToNextOrder(); @@ -324,9 +328,9 @@ private: void OrdersInit(double fVel); void OrdersClear(); void OrdersDump(); - std::string OrderCurrent() const; std::string Order2Str(TOrders Order) const; // members + std::string m_assignment; Math3D::vector3 vCommandLocation; // polozenie wskaznika, sygnalizatora lub innego obiektu do ktorego odnosi sie komenda // NOTE: not used TOrders OrderList[ maxorders ]; // lista rozkazów int OrderPos = 0, diff --git a/Train.h b/Train.h index e47002fb..056bdd1b 100644 --- a/Train.h +++ b/Train.h @@ -17,6 +17,8 @@ http://mozilla.org/MPL/2.0/. #include "PyInt.h" #include "command.h" +#undef snprintf // pyint.h->python + // typedef enum {st_Off, st_Starting, st_On, st_ShuttingDown} T4State; const int maxcab = 2; diff --git a/driveruilayer.cpp b/driveruilayer.cpp index 7a30dcde..2f5f138e 100644 --- a/driveruilayer.cpp +++ b/driveruilayer.cpp @@ -23,12 +23,17 @@ driver_ui::driver_ui() { clear_panels(); // bind the panels with ui object. maybe not the best place for this but, eh push_back( &m_aidpanel ); + push_back( &m_scenariopanel ); push_back( &m_timetablepanel ); push_back( &m_debugpanel ); push_back( &m_transcriptspanel ); m_aidpanel.title = locale::strings[ locale::string::driver_aid_header ]; + m_scenariopanel.title = locale::strings[ locale::string::driver_scenario_header ]; + m_scenariopanel.size_min = { 435, 85 }; + m_scenariopanel.size_max = { Global.iWindowWidth * 0.95, Global.iWindowHeight * 0.95 }; + m_timetablepanel.title = locale::strings[ locale::string::driver_timetable_header ]; m_timetablepanel.size_min = { 435, 110 }; m_timetablepanel.size_max = { 435, Global.iWindowHeight * 0.95 }; @@ -65,6 +70,7 @@ driver_ui::on_key_( int const Key, int const Scancode, int const Action, int con case GLFW_KEY_F1: case GLFW_KEY_F2: + case GLFW_KEY_F3: case GLFW_KEY_F10: case GLFW_KEY_F12: { // ui mode selectors @@ -112,6 +118,12 @@ driver_ui::on_key_( int const Key, int const Scancode, int const Action, int con return true; } + case GLFW_KEY_F3: { + // debug panel + m_scenariopanel.is_open = !m_scenariopanel.is_open; + return true; + } + case GLFW_KEY_F12: { // debug panel m_debugpanel.is_open = !m_debugpanel.is_open; diff --git a/driveruilayer.h b/driveruilayer.h index f90beccb..fae3b02f 100644 --- a/driveruilayer.h +++ b/driveruilayer.h @@ -41,6 +41,7 @@ private: on_mouse_button_( int const Button, int const Action, int const Mods ) override; // members drivingaid_panel m_aidpanel { "Driving Aid", true }; + scenario_panel m_scenariopanel { "Scenario", true }; timetable_panel m_timetablepanel { "Timetable", false }; debug_panel m_debugpanel { "Debug Data", false }; transcripts_panel m_transcriptspanel { "Transcripts", true }; // voice transcripts diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 0098a6fa..62a89990 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -27,8 +27,6 @@ http://mozilla.org/MPL/2.0/. #include "utilities.h" #include "Logs.h" -#undef snprintf // defined by train.h->pyint.h->python - void drivingaid_panel::update() { @@ -152,6 +150,79 @@ drivingaid_panel::update() { size = { sizex, 85 }; } +void +scenario_panel::update() { + + if( false == is_open ) { return; } + + text_lines.clear(); + + auto const *train { simulation::Train }; + auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; + auto const &camera { Global.pCamera }; + m_nearest = ( + false == FreeFlyModeFlag ? controlled : + camera.m_owner != nullptr ? camera.m_owner : + std::get( simulation::Region->find_vehicle( camera.Pos, 20, false, false ) ) ); // w trybie latania lokalizujemy wg mapy + if( m_nearest == nullptr ) { return; } + auto const *owner { ( + ( ( m_nearest->Mechanik != nullptr ) && ( m_nearest->Mechanik->Primary() ) ) ? + m_nearest->Mechanik : + m_nearest->ctOwner ) }; + if( owner == nullptr ) { return; } + + std::string textline = + locale::strings[ locale::string::driver_scenario_currenttask ] + "\n " + + owner->OrderCurrent(); + + text_lines.emplace_back( textline, Global.UITextColor ); +} + +void +scenario_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + if( m_nearest == nullptr ) { return; } // possibly superfluous given the above but, eh + + auto flags = + ImGuiWindowFlags_NoFocusOnAppearing + | ImGuiWindowFlags_NoCollapse + | ( size.x > 0 ? ImGuiWindowFlags_NoResize : 0 ); + + if( size.x > 0 ) { + ImGui::SetNextWindowSize( ImVec2( size.x, size.y ) ); + } + if( size_min.x > 0 ) { + ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); + } + auto const panelname { ( + title.empty() ? + name : + title ) + + "###" + name }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { + // potential assignment section + auto const *owner { ( + ( ( m_nearest->Mechanik != nullptr ) && ( m_nearest->Mechanik->Primary() ) ) ? + m_nearest->Mechanik : + m_nearest->ctOwner ) }; + if( owner != nullptr ) { + auto const assignmentheader { locale::strings[ locale::string::driver_scenario_assignment ] }; + if( ( false == owner->assignment().empty() ) + && ( true == ImGui::CollapsingHeader( assignmentheader.c_str() ) ) ) { + ImGui::TextWrapped( owner->assignment().c_str() ); + ImGui::Separator(); + } + } + // current task + for( auto const &line : text_lines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + } + ImGui::End(); +} + void timetable_panel::update() { @@ -370,7 +441,12 @@ debug_panel::render() { if( size_min.x > 0 ) { ImGui::SetNextWindowSizeConstraints( ImVec2( size_min.x, size_min.y ), ImVec2( size_max.x, size_max.y ) ); } - if( true == ImGui::Begin( name.c_str(), &is_open, flags ) ) { + auto const panelname { ( + title.empty() ? + name : + title ) + + "###" + name }; + if( true == ImGui::Begin( panelname.c_str(), &is_open, flags ) ) { // header section for( auto const &line : text_lines ) { ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); @@ -676,7 +752,9 @@ debug_panel::update_section_ai( std::vector &Output ) { auto const &mechanik{ *m_input.mechanik }; // biezaca komenda dla AI - auto textline = "Current order: " + mechanik.OrderCurrent(); + auto textline = + "Current order: [" + std::to_string( mechanik.OrderPos ) + "] " + + mechanik.OrderCurrent(); if( mechanik.fStopTime < 0.0 ) { textline += "\n stop time: " + to_string( std::abs( mechanik.fStopTime ), 1 ); diff --git a/driveruipanels.h b/driveruipanels.h index f0ab88a8..28363796 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -28,6 +28,21 @@ private: std::array m_buffer; }; +class scenario_panel : public ui_panel { + +public: + scenario_panel( std::string const &Name, bool const Isopen ) + : ui_panel( Name, Isopen ) {} + + void update() override; + void render() override; + +private: +// members +// std::array m_buffer; + TDynamicObject const *m_nearest { nullptr }; +}; + class timetable_panel : public ui_panel { public: diff --git a/scene.h b/scene.h index c3028820..8a439ee1 100644 --- a/scene.h +++ b/scene.h @@ -51,6 +51,7 @@ struct scratch_data { std::vector couplings; TDynamicObject * driver { nullptr }; bool is_open { false }; + std::unordered_map assignment; } trainset; std::string name; diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index da714c66..2cbfdbcc 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -70,6 +70,7 @@ state_serializer::deserialize( cParser &Input, scene::scratch_data &Scratchpad ) std::string, deserializefunction> > functionlist = { { "area", &state_serializer::deserialize_area }, + { "assignment", &state_serializer::deserialize_assignment }, { "atmo", &state_serializer::deserialize_atmo }, { "camera", &state_serializer::deserialize_camera }, { "config", &state_serializer::deserialize_config }, @@ -142,6 +143,20 @@ state_serializer::deserialize_area( cParser &Input, scene::scratch_data &Scratch } } +void +state_serializer::deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad ) { + + std::string token { Input.getToken() }; + while( ( false == token.empty() ) + && ( token != "endassignment" ) ) { + // assignment is expected to come as string pairs: language id and the actual assignment enclosed in quotes to form a single token + auto assignment{ Input.getToken() }; + win1250_to_ascii( assignment ); + Scratchpad.trainset.assignment.emplace( token, assignment ); + token = Input.getToken(); + } +} + void state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ) { @@ -628,6 +643,11 @@ state_serializer::deserialize_endtrainset( cParser &Input, scene::scratch_data & && ( vehicle->Mechanik->Primary() ) ) { // primary driver will receive the timetable for this trainset Scratchpad.trainset.driver = vehicle; + // they'll also receive assignment data if there's any + auto const lookup { Scratchpad.trainset.assignment.find( Global.asLang ) }; + if( lookup != Scratchpad.trainset.assignment.end() ) { + vehicle->Mechanik->assignment() = lookup->second; + } } if( vehicleindex > 0 ) { // from second vehicle on couple it with the previous one diff --git a/simulationstateserializer.h b/simulationstateserializer.h index 58c8058f..ef39056e 100644 --- a/simulationstateserializer.h +++ b/simulationstateserializer.h @@ -30,6 +30,7 @@ private: // restores class data from provided stream void deserialize( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_area( cParser &Input, scene::scratch_data &Scratchpad ); + void deserialize_assignment( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_atmo( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_camera( cParser &Input, scene::scratch_data &Scratchpad ); void deserialize_config( cParser &Input, scene::scratch_data &Scratchpad ); diff --git a/translation.cpp b/translation.cpp index a774082c..8bfe7b1a 100644 --- a/translation.cpp +++ b/translation.cpp @@ -38,6 +38,24 @@ init() { " Loading/unloading in progress (%d s left)", " Another vehicle ahead (distance: %.1f m)", + "Scenario", + "Assignment", + "Current task:", + "Wait for orders", + "Start the engine", + "Shut down the engine", + "Change direction", + "Couple to consist ahead", + "Uncouple %s", + "the engine", + "the engine plus the next vehicle", + "the engine plus %d next vehicles", + "the engine plus %d next vehicles", + "Shunt according to signals", + "Loose shunt according to signals", + "Drive according to signals and timetable", + "Bank consist ahead", + "Timetable", "Time: %d:%02d:%02d", "(no timetable)", @@ -183,6 +201,24 @@ init() { " Wsiadanie/wysiadanie pasazerow (do zakonczenia %d s)", " Inny pojazd na drodze (odleglosc: %.1f m)", + "Scenariusz", + "Zlecenie", + "Biezace zadanie:", + "Oczekiwac dalszych polecen", + "Przygotowac pojazd do jazdy", + "Wylaczyc pojazd", + "Zmienic kierunek jazdy", + "Sprzac sie ze skladem z przodu", + "Odpiac %s", + "pojazd prowadzacy", + "pojazd prowadzacy plus kolejny", + "pojazd prowadzacy plus %d kolejne", + "pojazd prowadzacy plus %d kolejnych", + "Prowadzic manewry wedlug sygnalow", + "Prowadzic manewry przetaczania odrzutem", + "Prowadzic sklad wedlug sygnalow i rozkladu", + "Popychac sklad z przodu", + "Rozklad jazdy", "Godzina: %d:%02d:%02d", "(brak rozkladu)", diff --git a/translation.h b/translation.h index 8a7a056d..ce6624c4 100644 --- a/translation.h +++ b/translation.h @@ -27,6 +27,24 @@ enum string { driver_aid_loadinginprogress, driver_aid_vehicleahead, + driver_scenario_header, + driver_scenario_assignment, + driver_scenario_currenttask, + driver_scenario_waitfororders, + driver_scenario_prepareengine, + driver_scenario_releaseengine, + driver_scenario_changedirection, + driver_scenario_connect, + driver_scenario_disconnect, + driver_scenario_allvehicles, + driver_scenario_onevehicle, + driver_scenario_fewvehicles, + driver_scenario_somevehicles, + driver_scenario_shunt, + driver_scenario_looseshunt, + driver_scenario_obeytrain, + driver_scenario_bank, + driver_timetable_header, driver_timetable_time, driver_timetable_notimetable,