diff --git a/Driver.cpp b/Driver.cpp index 52a62e7b..5fc4ee24 100644 --- a/Driver.cpp +++ b/Driver.cpp @@ -6595,17 +6595,18 @@ std::string TController::NextStop() const // dodać godzinę odjazdu if (!TrainParams) return ""; // tu nie powinno nigdy wejść - std::string nextstop = asNextStop; + std::string nextstop = Bezogonkow( asNextStop, true ); TMTableLine *t = TrainParams->TimeTable + TrainParams->StationIndex; if( t->Ah >= 0 ) { // przyjazd - nextstop += " przyj." + std::to_string( t->Ah ) + ":" - + ( t->Am < 10 ? "0" : "" ) + std::to_string( t->Am ); + nextstop += " przyj." + std::to_string( t->Ah ) + ":" + + to_minutes_str( t->Am, true, 3 ); + } if( t->Dh >= 0 ) { // jeśli jest godzina odjazdu nextstop += " odj." + std::to_string( t->Dh ) + ":" - + ( t->Dm < 10 ? "0" : "" ) + std::to_string( t->Dm ); + + to_minutes_str( t->Dm, true, 3 ); } return nextstop; }; diff --git a/driveruipanels.cpp b/driveruipanels.cpp index 03d44f38..6a482e81 100644 --- a/driveruipanels.cpp +++ b/driveruipanels.cpp @@ -229,6 +229,7 @@ timetable_panel::update() { if( false == is_open ) { return; } text_lines.clear(); + m_tablelines.clear(); auto const *train { simulation::Train }; auto const *controlled { ( train ? train->Dynamic() : nullptr ) }; @@ -239,7 +240,7 @@ timetable_panel::update() { std::snprintf( m_buffer.data(), m_buffer.size(), locale::strings[ locale::string::driver_timetable_header ].c_str(), - 40, 40, + 37, 37, locale::strings[ locale::string::driver_timetable_name ].c_str(), time.wHour, time.wMinute, @@ -274,7 +275,7 @@ timetable_panel::update() { } { // next station - auto const nextstation = Bezogonkow( owner->NextStop(), true ); + auto const nextstation = owner->NextStop(); if( false == nextstation.empty() ) { // jeśli jest podana relacja, to dodajemy punkt następnego zatrzymania auto textline = " -> " + nextstation; @@ -317,67 +318,126 @@ timetable_panel::update() { } else { + auto const loadingcolor { glm::vec4( 164.0f / 255.0f, 84.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; + auto const waitcolor { glm::vec4( 164.0f / 255.0f, 132.0f / 255.0f, 84.0f / 255.0f, 1.f ) }; auto const readycolor { glm::vec4( 84.0f / 255.0f, 164.0f / 255.0f, 132.0f / 255.0f, 1.f ) }; // header - text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + m_tablelines.emplace_back( u8"┌─────┬────────────────────────────────────┬─────────┬─────┐", Global.UITextColor ); TMTableLine const *tableline; for( int i = owner->iStationStart; i <= table->StationCount; ++i ) { // wyświetlenie pozycji z rozkładu tableline = table->TimeTable + i; // linijka rozkładu - std::string vmax = - " " - + to_string( tableline->vmax, 0 ); - vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej - std::string const station = ( + bool vmaxchange { true }; + if( i > owner->iStationStart ) { + auto const *previoustableline { tableline - 1 }; + if( tableline->vmax == previoustableline->vmax ) { + vmaxchange = false; + } + } + std::string vmax { " " }; + if( true == vmaxchange ) { + vmax += to_string( tableline->vmax, 0 ); + vmax = vmax.substr( vmax.size() - 3, 3 ); // z wyrównaniem do prawej + } + auto const station { ( Bezogonkow( tableline->StationName, true ) + " " ) - .substr( 0, 34 ); - std::string const location = ( + .substr( 0, 34 ) }; + auto const location { ( ( tableline->km > 0.0 ? to_string( tableline->km, 2 ) : "" ) + " " ) - .substr( 0, 34 - tableline->StationWare.size() ); - std::string const arrival = ( + .substr( 0, 34 - tableline->StationWare.size() ) }; + auto const arrival { ( tableline->Ah >= 0 ? - to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Am ) ).substr( 1, 2 ) : - " | " ); - std::string const departure = ( + to_string( int( 100 + tableline->Ah ) ).substr( 1, 2 ) + ":" + to_minutes_str( tableline->Am, true, 3 ) : + u8" │ " ) }; + auto const departure { ( tableline->Dh >= 0 ? - to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_string( int( 100 + tableline->Dm ) ).substr( 1, 2 ) : - " | " ); - auto const candeparture = ( + to_string( int( 100 + tableline->Dh ) ).substr( 1, 2 ) + ":" + to_minutes_str( tableline->Dm, true, 3 ) : + u8" │ " ) }; + auto const candeparture { ( ( owner->iStationStart < table->StationIndex ) && ( i < table->StationIndex ) && ( ( tableline->Ah < 0 ) // pass-through, always valid - || ( time.wHour * 60 + time.wMinute + time.wSecond * 0.0167 >= tableline->Dh * 60 + tableline->Dm ) ) ); - auto traveltime = - " " - + ( i < 2 ? "" : - tableline->Ah >= 0 ? to_string( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), 0 ) : - to_string( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), 0 ) ); - traveltime = traveltime.substr( traveltime.size() - 3, 3 ); // z wyrównaniem do prawej - - text_lines.emplace_back( - ( "| " + vmax + " | " + station + " | " + arrival + " | " + traveltime + " |" ), - ( candeparture ? - readycolor :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global.UITextColor ) ); - text_lines.emplace_back( - ( "| | " + location + tableline->StationWare + " | " + departure + " | |" ), - ( candeparture ? - readycolor :// czas minął i odjazd był, to nazwa stacji będzie na zielono - Global.UITextColor ) ); + || ( time.wHour * 60 + time.wMinute + time.wSecond * 0.0167 >= tableline->Dh * 60 + tableline->Dm ) ) ) }; + auto const loadchangeinprogress { ( ( static_cast( std::ceil( -1.0 * owner->fStopTime ) ) ) > 0 ) }; + auto const isatpassengerstop { ( true == owner->IsAtPassengerStop ) && ( vehicle->MoverParameters->Vel < 1.0 ) }; + auto const traveltime { ( + i < 2 ? " " : + tableline->Ah >= 0 ? to_minutes_str( CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Ah, tableline->Am ), false, 3 ) : + to_minutes_str( std::max( 0.0, CompareTime( table->TimeTable[ i - 1 ].Dh, table->TimeTable[ i - 1 ].Dm, tableline->Dh, tableline->Dm ) - 0.5 ), false, 3 ) ) }; + auto const linecolor { ( + ( i != owner->iStationStart ) ? Global.UITextColor : + loadchangeinprogress ? loadingcolor : + candeparture ? readycolor : // czas minął i odjazd był, to nazwa stacji będzie na zielono + isatpassengerstop ? waitcolor : + Global.UITextColor ) }; + m_tablelines.emplace_back( + ( u8"│ " + vmax + u8" │ " + station + u8" │ " + arrival + u8" │ " + traveltime + u8" │" ), + linecolor ); + m_tablelines.emplace_back( + ( u8"│ │ " + location + tableline->StationWare + u8" │ " + departure + u8" │ │" ), + linecolor ); // divider/footer - text_lines.emplace_back( "+-----+------------------------------------+-------+-----+", Global.UITextColor ); + if( i < table->StationCount ) { + auto const *nexttableline { tableline + 1 }; + if( tableline->vmax == nexttableline->vmax ) { + m_tablelines.emplace_back( u8"│ ├────────────────────────────────────┼─────────┼─────┤", Global.UITextColor ); + } + else { + m_tablelines.emplace_back( u8"├─────┼────────────────────────────────────┼─────────┼─────┤", Global.UITextColor ); + } + } + else { + m_tablelines.emplace_back( u8"└─────┴────────────────────────────────────┴─────────┴─────┘", Global.UITextColor ); + } } } } // is_expanded } +void +timetable_panel::render() { + + if( false == is_open ) { return; } + if( true == text_lines.empty() ) { return; } + + 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 ) ) { + 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() ); + } + if( is_expanded ) { + ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( 1, 0 ) ); + for( auto const &line : m_tablelines ) { + ImGui::TextColored( ImVec4( line.color.r, line.color.g, line.color.b, line.color.a ), line.data.c_str() ); + } + ImGui::PopStyleVar(); + } + } + ImGui::End(); +} + void debug_panel::update() { diff --git a/driveruipanels.h b/driveruipanels.h index 28363796..7c075562 100644 --- a/driveruipanels.h +++ b/driveruipanels.h @@ -50,12 +50,14 @@ public: : ui_panel( Name, Isopen ) {} void update() override; + void render() override; bool is_expanded{ false }; private: - // members +// members std::array m_buffer; + std::vector m_tablelines; }; class debug_panel : public ui_panel { diff --git a/mtable.cpp b/mtable.cpp index 3d207cdb..957a4f8d 100644 --- a/mtable.cpp +++ b/mtable.cpp @@ -480,14 +480,14 @@ bool TTrainParameters::LoadTTfile(std::string scnpath, int iPlus, double vmax) { if ((TimeTable[i].Ah >= 0)) { - adjustedtime = clamp_circular( TimeTable[i].Ah * 60 + TimeTable[i].Am + timeoffset, 24.0 * 60.0 ); // nowe minuty - TimeTable[i].Am = (int(60 * adjustedtime) % 3600) / 60.0; + adjustedtime = clamp_circular( TimeTable[i].Ah * 60 + TimeTable[i].Am + timeoffset, 24 * 60 ); // nowe minuty + TimeTable[i].Am = (int(60 * adjustedtime) % 3600) / 60.f; TimeTable[i].Ah = int((adjustedtime) / 60) % 24; } if ((TimeTable[i].Dh >= 0)) { - adjustedtime = clamp_circular( TimeTable[i].Dh * 60 + TimeTable[i].Dm + timeoffset, 24.0 * 60.0 ); // nowe minuty - TimeTable[i].Dm = (int(60 * adjustedtime) % 3600) / 60.0; + adjustedtime = clamp_circular( TimeTable[i].Dh * 60 + TimeTable[i].Dm + timeoffset, 24 * 60 ); // nowe minuty + TimeTable[i].Dm = (int(60 * adjustedtime) % 3600) / 60.f; TimeTable[i].Dh = int((adjustedtime) / 60) % 24; } } diff --git a/mtable.h b/mtable.h index 17191ff1..b0bea8bd 100644 --- a/mtable.h +++ b/mtable.h @@ -24,18 +24,18 @@ static char const *hrsd = "."; struct TMTableLine { - double km; // kilometraz linii - double vmax; // predkosc rozkladowa przed przystankiem + float km; // kilometraz linii + float vmax; // predkosc rozkladowa przed przystankiem // StationName:string[32]; //nazwa stacji ('_' zamiast spacji) // StationWare:string[32]; //typ i wyposazenie stacji, oddz. przecinkami} std::string StationName; // nazwa stacji ('_' zamiast spacji) std::string StationWare; // typ i wyposazenie stacji, oddz. przecinkami} int TrackNo; // ilosc torow szlakowych int Ah; - double Am; // godz. i min. przyjazdu, -1 gdy bez postoju + float Am; // godz. i min. przyjazdu, -1 gdy bez postoju int Dh; - double Dm; // godz. i min. odjazdu - double tm; // czas jazdy do tej stacji w min. (z kolumny) + float Dm; // godz. i min. odjazdu + float tm; // czas jazdy do tej stacji w min. (z kolumny) TMTableLine() { km = 0; diff --git a/simulationstateserializer.cpp b/simulationstateserializer.cpp index e28992a0..10f20e2e 100644 --- a/simulationstateserializer.cpp +++ b/simulationstateserializer.cpp @@ -179,7 +179,7 @@ state_serializer::deserialize_atmo( cParser &Input, scene::scratch_data &Scratch Global.fFogEnd = clamp( Random( std::min( fograngestart, fograngeend ), std::max( fograngestart, fograngeend ) ), - 100.0, 2000.0 ); + 10.0, 2000.0 ); } std::string token { Input.getToken() }; diff --git a/uilayer.cpp b/uilayer.cpp index 6ad6929f..c5aea330 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -74,8 +74,15 @@ ui_layer::init( GLFWwindow *Window ) { IMGUI_CHECKVERSION(); ImGui::CreateContext(); + + static ImWchar const glyphranges[] = { + 0x0020, 0x00FF, // ascii + extension + 0x2070, 0x2079, // superscript + 0x2500, 0x256C, // box drawings + 0, + }; m_imguiio = &ImGui::GetIO(); -// m_imguiio->Fonts->AddFontFromFileTTF( "c:/windows/fonts/lucon.ttf", 13.0f ); + m_imguiio->Fonts->AddFontFromFileTTF( "fonts/dejavusansmono.ttf", 13.0f, nullptr, &glyphranges[ 0 ] ); ImGui_ImplGlfw_InitForOpenGL( m_window, false ); #ifdef EU07_USEIMGUIIMPLOPENGL2 diff --git a/utilities.cpp b/utilities.cpp index 971b034d..4c9953b1 100644 --- a/utilities.cpp +++ b/utilities.cpp @@ -1,4 +1,4 @@ -/* +/* 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 @@ -246,6 +246,24 @@ std::string to_hex_str( int const Value, int const Width ) return converter.str(); }; +char * const fractionlabels[] = { " ", u8"¹", u8"²", u8"³", u8"⁴", u8"⁵", u8"⁶", u8"⁷", u8"⁸", u8"⁹" }; + +std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ) { + + float minutesintegral; + auto const minutesfractional { std::modf( Minutes, &minutesintegral ) }; + auto const width { Width - 1 }; + auto minutes = ( + std::string( width - 1, ' ' ) + + ( Leadingzero ? + to_string( 100 + minutesintegral ).substr( 1, 2 ) : + to_string( minutesintegral, 0 ) ) ); + return ( + minutes.substr( minutes.size() - width, width ) + + fractionlabels[ static_cast( std::floor( minutesfractional * 10 + 0.1 ) ) ] ); +} + + int stol_def(const std::string &str, const int &DefaultValue) { int result { DefaultValue }; diff --git a/utilities.h b/utilities.h index 400f12df..1c930f7a 100644 --- a/utilities.h +++ b/utilities.h @@ -107,6 +107,7 @@ std::string to_string(double Value); std::string to_string(double Value, int precision); std::string to_string(double Value, int precision, int width); std::string to_hex_str( int const Value, int const width = 4 ); +std::string to_minutes_str( float const Minutes, bool const Leadingzero, int const Width ); inline std::string to_string(bool Value) { diff --git a/version.h b/version.h index 5ee96a7f..f3ad8c74 100644 --- a/version.h +++ b/version.h @@ -1,5 +1,5 @@ #pragma once #define VERSION_MAJOR 19 -#define VERSION_MINOR 504 +#define VERSION_MINOR 514 #define VERSION_REVISION 0