diff --git a/AnimModel.cpp b/AnimModel.cpp index 30154b57..4f0daba2 100644 --- a/AnimModel.cpp +++ b/AnimModel.cpp @@ -433,12 +433,7 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) { auto &timer { m_lighttimers[ idx ] }; if( ( modeintegral < ls_Blink ) && ( modefractional < 0.01f ) ) { // simple flip modes - auto const transitiontime { ( - m_transition ? - std::min( - 1.f, - std::min( fOnTime, fOffTime ) * 0.9f ) : - 0.01f ) }; + auto const transitiontime { ( m_transition ? std::min( 0.65f, std::min( fOnTime, fOffTime ) * 0.45f ) : 0.01f ) }; switch( mode ) { case ls_Off: { @@ -469,14 +464,9 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) { ( mode == ls_Off ) ? ontime : ( mode == ls_On ) ? ( fOnTime + fOffTime ) - ontime : fOffTime ) }; // fallback - auto const transitiontime { ( - m_transition ? - std::min( - 1.f, - std::min( ontime, offtime ) * 0.9f ) : - 0.01f ) }; + auto const transitiontime { ( m_transition ? std::min(0.65f, std::min( ontime, offtime ) * 0.45f ) : 0.01f ) }; - timer = clamp_circular( timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime ); + timer = fmod(timer + timedelta * ( lsLights[ idx ] > 0.f ? 1.f : -1.f ), ontime + offtime); // set opacity depending on blink stage if( timer < ontime ) { // blink on @@ -500,50 +490,14 @@ void TAnimModel::RaAnimate( unsigned int const Framestamp ) { // aktualizujemy submodele w zaleznosci od aktualnej porty roku void TAnimModel::on_season_update() { - if (Global.Season == "winter:") // pokazujemy wariant zimowy - { - if (this->sm_winter_variant != nullptr) - this->sm_winter_variant->SetVisibilityLevel(1.f, true, false); - if (this->sm_spring_variant != nullptr) - this->sm_spring_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_summer_variant != nullptr) - this->sm_summer_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_autumn_variant != nullptr) - this->sm_autumn_variant->SetVisibilityLevel(0.f, true, false); - } - else if (Global.Season == "spring:") // pokazujemy wariant wiosenny - { - if (this->sm_winter_variant != nullptr) - this->sm_winter_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_spring_variant != nullptr) - this->sm_spring_variant->SetVisibilityLevel(1.f, true, false); - if (this->sm_summer_variant != nullptr) - this->sm_summer_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_autumn_variant != nullptr) - this->sm_autumn_variant->SetVisibilityLevel(0.f, true, false); - } - else if (Global.Season == "summer:") // pokazujemy wariant letni - { - if (this->sm_winter_variant != nullptr) - this->sm_winter_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_spring_variant != nullptr) - this->sm_spring_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_summer_variant != nullptr) - this->sm_summer_variant->SetVisibilityLevel(1.f, true, false); - if (this->sm_autumn_variant != nullptr) - this->sm_autumn_variant->SetVisibilityLevel(0.f, true, false); - } - else if (Global.Season == "autumn:") // pokazujemy wariant jesienny - { - if (this->sm_winter_variant != nullptr) - this->sm_winter_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_spring_variant != nullptr) - this->sm_spring_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_summer_variant != nullptr) - this->sm_summer_variant->SetVisibilityLevel(0.f, true, false); - if (this->sm_autumn_variant != nullptr) - this->sm_autumn_variant->SetVisibilityLevel(1.f, true, false); - } + if (this->sm_winter_variant != nullptr) // pokazujemy wariant zimowy + this->sm_winter_variant->SetVisibilityLevel(Global.Season == "winter:" ? 1 : 0, true, false); + if (this->sm_spring_variant != nullptr) // pokazujemy wariant wiosenny + this->sm_spring_variant->SetVisibilityLevel(Global.Season == "spring:" ? 1 : 0, true, false); + if (this->sm_summer_variant != nullptr) // pokazujemy wariant letni + this->sm_summer_variant->SetVisibilityLevel(Global.Season == "summer:" ? 1 : 0, true, false); + if (this->sm_autumn_variant != nullptr) // pokazujemy wariant jesienny + this->sm_autumn_variant->SetVisibilityLevel(Global.Season == "autumn:" ? 1 : 0, true, false); } void TAnimModel::RaPrepare() diff --git a/CMakeLists.txt b/CMakeLists.txt index cc985830..c78195c9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ set(SOURCES "editoruilayer.cpp" "editoruipanels.cpp" "scenarioloadermode.cpp" +"scenarioloaderuilayer.cpp" "scenenodegroups.cpp" "simulationenvironment.cpp" "simulationstateserializer.cpp" diff --git a/Globals.h b/Globals.h index e5ba38be..ce9cdec8 100644 --- a/Globals.h +++ b/Globals.h @@ -236,7 +236,7 @@ struct global_settings { std::string asVersion; // z opisem motiontelemetry::conf_t motiontelemetry_conf; std::string screenshot_dir; - bool loading_log = true; + bool loading_log = false; bool dds_upper_origin = false; bool captureonstart = true; bool render_cab = true; diff --git a/McZapkie/MOVER.h b/McZapkie/MOVER.h index 939d9d21..38d6e180 100644 --- a/McZapkie/MOVER.h +++ b/McZapkie/MOVER.h @@ -609,6 +609,13 @@ struct TDEScheme double Umax = 0.0; /*napiecie maksymalne*/ double Imax = 0.0; /*prad maksymalny*/ }; +typedef TDEScheme TDESchemeTable[33]; /*tablica WWList dla silnikow spalinowych*/ +struct TFFScheme +{ + double v = 0.0; // parametr wejsciowy + double freq = 0.0; // wyjscie: czestotliwosc falownika +}; +typedef TFFScheme TFFSchemeTable[33]; struct TWiperScheme { @@ -619,8 +626,6 @@ struct TWiperScheme }; typedef TWiperScheme TWiperSchemeTable[16]; - -typedef TDEScheme TDESchemeTable[33]; /*tablica rezystorow rozr.*/ struct TShuntScheme { double Umin = 0.0; @@ -1376,6 +1381,10 @@ class TMoverParameters bool Flat = false; double Vhyp = 1.0; TDESchemeTable DElist; + TFFSchemeTable FFlist; + int FFListSize = 0; + TFFSchemeTable FFEDlist; + int FFEDListSize = 0; TWiperSchemeTable WiperList; int WiperListSize; int modernWpierListSize; @@ -2081,6 +2090,7 @@ private: void LoadFIZ_UCList(std::string const &Input); void LoadFIZ_DList( std::string const &Input ); void LoadFIZ_FFList( std::string const &Input ); + void LoadFIZ_FFEDList( std::string const &Input ); void LoadFIZ_WiperList(std::string const &Input); void LoadFIZ_LightsList( std::string const &Input ); void LoadFIZ_DimmerList(std::string const &Input); @@ -2103,6 +2113,7 @@ private: bool readHTCList(std::string const &line); bool readPmaxList(std::string const &line); bool readFFList( std::string const &line ); + bool readFFEDList( std::string const &line ); bool readWWList( std::string const &line ); bool readWiperList( std::string const &line ); bool readDimmerList(std::string const &line); diff --git a/McZapkie/Mover.cpp b/McZapkie/Mover.cpp index 2d818934..c3466532 100644 --- a/McZapkie/Mover.cpp +++ b/McZapkie/Mover.cpp @@ -6432,21 +6432,24 @@ double TMoverParameters::TractionForce( double dt ) { EnginePower = abs(eimv[eimv_Ic] * eimv[eimv_U] * NPoweredAxles) / 1000; // power inverters auto const tmpV { std::abs( eimv[ eimv_fp ] ) }; + auto const useFFEDList = FFEDListSize > 0 && DynamicBrakeFlag; + auto const list = useFFEDList ? FFEDlist : FFlist; + auto const listSize = useFFEDList ? FFEDListSize : FFListSize; - if( ( RlistSize > 0 ) + if( ( listSize > 0 ) && ( ( std::abs( eimv[ eimv_If ] ) > 1.0 ) && ( tmpV > 0.0001 ) ) ) { int i = 0; - while( ( i < RlistSize - 1 ) - && ( DElist[ i + 1 ].RPM < tmpV ) ) { + while( ( i < listSize - 1 ) + && ( list[ i + 1 ].v < tmpV ) ) { ++i; } InverterFrequency = - ( tmpV - DElist[ i ].RPM ) - / std::max( 1.0, ( DElist[ i + 1 ].RPM - DElist[ i ].RPM ) ) - * ( DElist[ i + 1 ].GenPower - DElist[ i ].GenPower ) - + DElist[ i ].GenPower; + ( tmpV - list[ i ].v ) + / std::max( 1.0, ( list[ i + 1 ].v - list[ i ].v ) ) + * ( list[ i + 1 ].freq - list[ i ].freq ) + + list[ i ].freq; } else { InverterFrequency = 0.0; @@ -8927,7 +8930,7 @@ bool startBPT; bool startMPT, startMPT0; bool startRLIST, startUCLIST; bool startDIZELMOMENTUMLIST, startDIZELV2NMAXLIST, startHYDROTCLIST, startPMAXLIST; -bool startDLIST, startFFLIST, startWWLIST, startWiperList, startDimmerList; +bool startDLIST, startFFLIST, startWWLIST, startWiperList, startDimmerList, startFFEDLIST; bool startLIGHTSLIST; bool startCOMPRESSORLIST; int LISTLINE; @@ -9262,21 +9265,40 @@ bool TMoverParameters::readPmaxList(std::string const &line) { bool TMoverParameters::readFFList( std::string const &line ) { - cParser parser( line ); - if( false == parser.getTokens( 2, false ) ) { - WriteLog( "Read FList: arguments missing in line " + std::to_string( LISTLINE + 1 ) ); - return false; - } - int idx = LISTLINE++; - if( idx >= sizeof( DElist ) / sizeof( TDEScheme ) ) { - WriteLog( "Read FList: number of entries exceeded capacity of the data table" ); - return false; - } - parser - >> DElist[ idx ].RPM - >> DElist[ idx ].GenPower; + cParser parser( line ); + if( false == parser.getTokens( 2, false ) ) { + WriteLog( "Read FList: arguments missing in line " + std::to_string( LISTLINE + 1 ) ); + return false; + } + int idx = LISTLINE++; + if( idx >= sizeof( FFlist ) / sizeof( TFFScheme ) ) { + WriteLog( "Read FList: number of entries exceeded capacity of the data table" ); + return false; + } + parser + >> FFlist[ idx ].v + >> FFlist[ idx ].freq; - return true; + return true; +} + +bool TMoverParameters::readFFEDList( std::string const &line ) { + + cParser parser( line ); + if( false == parser.getTokens( 2, false ) ) { + WriteLog( "Read FList: arguments missing in line " + std::to_string( LISTLINE + 1 ) ); + return false; + } + int idx = LISTLINE++; + if( idx >= sizeof( FFEDlist ) / sizeof( TFFScheme ) ) { + WriteLog( "Read FList: number of entries exceeded capacity of the data table" ); + return false; + } + parser + >> FFEDlist[ idx ].v + >> FFEDlist[ idx ].freq; + + return true; } // parsowanie wiperList @@ -9496,6 +9518,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) startHYDROTCLIST = false; startPMAXLIST = false; startFFLIST = false; + startFFEDLIST = false; startWWLIST = false; startWiperList = false; startDimmerList = false; @@ -9597,6 +9620,7 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) if( issection( "endff", inputline ) ) { startBPT = false; startFFLIST = false; + startFFEDLIST = false; continue; } if (issection("endwl", inputline)) @@ -9893,12 +9917,19 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) continue; } - if( issection( "ffList:", inputline ) ) { - startBPT = false; - startFFLIST = true; LISTLINE = 0; - LoadFIZ_FFList( inputline ); - continue; - } + if( issection( "ffList:", inputline ) ) { + startBPT = false; + startFFLIST = true; LISTLINE = 0; + LoadFIZ_FFList( inputline ); + continue; + } + + if( issection( "ffBrakeList:", inputline ) ) { + startBPT = false; + startFFEDLIST = true; LISTLINE = 0; + LoadFIZ_FFEDList( inputline ); + continue; + } if( issection( "WWList:", inputline ) ) { @@ -9988,10 +10019,14 @@ bool TMoverParameters::LoadFIZ(std::string chkpath) readPmaxList(inputline); continue; } - if( true == startFFLIST ) { - readFFList( inputline ); - continue; - } + if( true == startFFLIST ) { + readFFList( inputline ); + continue; + } + if( true == startFFEDLIST ) { + readFFEDList( inputline ); + continue; + } if( true == startWWLIST ) { readWWList( inputline ); continue; @@ -11354,8 +11389,11 @@ void TMoverParameters::LoadFIZ_DList( std::string const &Input ) { } void TMoverParameters::LoadFIZ_FFList( std::string const &Input ) { + extract_value( FFListSize, "Size", Input, "" ); +} - extract_value( RlistSize, "Size", Input, "" ); +void TMoverParameters::LoadFIZ_FFEDList( std::string const &Input ) { + extract_value( FFEDListSize, "Size", Input, "" ); } void TMoverParameters::LoadFIZ_WiperList(std::string const &Input) diff --git a/Track.cpp b/Track.cpp index e37d0026..9bd3a49a 100644 --- a/Track.cpp +++ b/Track.cpp @@ -2366,6 +2366,19 @@ TTrack::export_as_text_( std::ostream &Output ) const { << "\n"; } +// Returns the tooltip of this Track, which may contain a list of isolations if the track belongs to any. +std::string TTrack::tooltip() const +{ + std::string tooltip = this->name(); + if (!Isolated.empty()) + { + tooltip += "\nIsolated:"; + for (const auto isolation : Isolated) + tooltip += " " + isolation->asName; + } + return tooltip; +} + // locates specified profile in the profile database, potentially loading it from a file // returns: pair std::pair diff --git a/Track.h b/Track.h index c993648c..c156fa7b 100644 --- a/Track.h +++ b/Track.h @@ -316,6 +316,7 @@ public: void ConnectionsLog(); bool DoubleSlip() const; static void fetch_default_profiles(); + std::string tooltip() const override; private: // types diff --git a/application.cpp b/application.cpp index cc50699f..83b88b92 100644 --- a/application.cpp +++ b/application.cpp @@ -81,6 +81,7 @@ void framebuffer_resize_callback( GLFWwindow *, int w, int h ) { void window_resize_callback( GLFWwindow *, int w, int h ) { Global.window_size = glm::ivec2(w, h); + Application.on_window_resize(w, h); } void cursor_pos_callback( GLFWwindow *window, double x, double y ) { @@ -662,19 +663,19 @@ eu07_application::pop_mode() { } bool -eu07_application::push_mode( eu07_application::mode const Mode ) { +eu07_application::push_mode( mode const Mode ) { - if( Mode >= mode::count_ ) + if( Mode >= count_ ) return false; if (!m_modes[Mode]) { - if (Mode == mode::launcher) + if (Mode == launcher) m_modes[Mode] = std::make_shared(); - if (Mode == mode::scenarioloader) + if (Mode == scenarioloader) m_modes[Mode] = std::make_shared(); - if (Mode == mode::driver) + if (Mode == driver) m_modes[Mode] = std::make_shared(); - if (Mode == mode::editor) + if (Mode == editor) m_modes[Mode] = std::make_shared(); if (!m_modes[Mode]->init()) @@ -740,6 +741,13 @@ eu07_application::on_key( int const Key, int const Scancode, int const Action, i if( m_modestack.empty() ) { return; } + if (Key == GLFW_KEY_LEFT_SHIFT || Key == GLFW_KEY_RIGHT_SHIFT) + Global.shiftState = Action == GLFW_PRESS; + if (Key == GLFW_KEY_LEFT_CONTROL || Key == GLFW_KEY_RIGHT_CONTROL) + Global.ctrlState = Action == GLFW_PRESS; + if (Key == GLFW_KEY_LEFT_ALT || Key == GLFW_KEY_RIGHT_ALT) + Global.altState = Action == GLFW_PRESS; + m_modes[ m_modestack.top() ]->on_key( Key, Scancode, Action, Mods ); } @@ -779,12 +787,20 @@ void eu07_application::on_char(unsigned int c) { } void eu07_application::on_focus_change(bool focus) { - if( Global.bInactivePause && !m_network->client) {// jeśli ma być pauzowanie okna w tle + if( Global.bInactivePause && m_network.has_value() && !m_network->client) {// jeśli ma być pauzowanie okna w tle command_relay relay; relay.post(user_command::focuspauseset, focus ? 1.0 : 0.0, 0.0, GLFW_PRESS, 0); } } +void eu07_application::on_window_resize(int w, int h) +{ + if (m_modestack.empty()) + return; + m_modes[m_modestack.top()]->on_window_resize(w, h); +} + + GLFWwindow * eu07_application::window(int const Windowindex, bool visible, int width, int height, GLFWmonitor *monitor, bool keep_ownership , bool share_ctx) { diff --git a/application.h b/application.h index e7d814ec..0c177d77 100644 --- a/application.h +++ b/application.h @@ -70,18 +70,13 @@ public: set_cursor_pos( double const Horizontal, double const Vertical ); void queue_screenshot(); // input handlers - void - on_key( int const Key, int const Scancode, int const Action, int const Mods ); - void - on_char( unsigned int const Char ); - void - on_cursor_pos( double const Horizontal, double const Vertical ); - void - on_mouse_button( int const Button, int const Action, int const Mods ); - void - on_scroll( double const Xoffset, double const Yoffset ); - void - on_focus_change(bool focus); + void on_key( int const Key, int const Scancode, int const Action, int const Mods ); + void on_char( unsigned int const Char ); + void on_cursor_pos( double const Horizontal, double const Vertical ); + void on_mouse_button( int const Button, int const Action, int const Mods ); + void on_scroll( double const Xoffset, double const Yoffset ); + void on_focus_change(bool focus); + void on_window_resize(int w, int h); // gives access to specified window, creates a new window if index == -1 GLFWwindow * window( int const Windowindex = 0, bool visible = false, int width = 1, int height = 1, GLFWmonitor *monitor = nullptr, bool keep_ownership = true, bool share_ctx = true ); diff --git a/applicationmode.h b/applicationmode.h index 35e720e8..39cd4a23 100644 --- a/applicationmode.h +++ b/applicationmode.h @@ -17,65 +17,41 @@ class application_mode { public: // destructor - virtual - ~application_mode() = default; + virtual ~application_mode() = default; // methods; // initializes internal data structures of the mode. returns: true on success, false otherwise - virtual - bool - init() = 0; + virtual bool init() = 0; // mode-specific update of simulation data. returns: false on error, true otherwise - virtual - bool - update() = 0; + virtual bool update() = 0; // draws mode-specific user interface inline - void - render_ui() { + void render_ui() { if( m_userinterface != nullptr ) { m_userinterface->render(); } } inline - void - begin_ui_frame() { + void begin_ui_frame() { if( m_userinterface != nullptr ) { m_userinterface->begin_ui_frame(); } } inline - void - set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) { + void set_progress( float const Progress = 0.f, float const Subtaskprogress = 0.f ) { if( m_userinterface != nullptr ) { m_userinterface->set_progress( Progress, Subtaskprogress ); } } inline - void - set_tooltip( std::string const &Tooltip ) { + void set_tooltip( std::string const &Tooltip ) { if( m_userinterface != nullptr ) { m_userinterface->set_tooltip( Tooltip ); } } // maintenance method, called when the mode is activated - virtual - void - enter() = 0; + virtual void enter() = 0; // maintenance method, called when the mode is deactivated - virtual - void - exit() = 0; + virtual void exit() = 0; // input handlers - virtual - void - on_key( int const Key, int const Scancode, int const Action, int const Mods ) = 0; - virtual - void - on_cursor_pos( double const X, double const Y ) = 0; - virtual - void - on_mouse_button( int const Button, int const Action, int const Mods ) = 0; - virtual - void - on_scroll( double const Xoffset, double const Yoffset ) = 0; - virtual - void - on_event_poll() = 0; - virtual - bool - is_command_processor() const = 0; + virtual void on_key( int Key, int Scancode, int Action, int Mods ) = 0; + virtual void on_cursor_pos( double X, double Y ) = 0; + virtual void on_mouse_button( int Button, int Action, int Mods ) = 0; + virtual void on_scroll( double Xoffset, double Yoffset ) = 0; + virtual void on_window_resize( int w, int h ) = 0; + virtual void on_event_poll() = 0; + virtual bool is_command_processor() const = 0; protected: // members diff --git a/drivermode.cpp b/drivermode.cpp index 784e11a5..3e780bc9 100644 --- a/drivermode.cpp +++ b/drivermode.cpp @@ -341,12 +341,10 @@ driver_mode::update() { set_tooltip( ( cabcontrol ? cabcontrol->pName : "" ) ); } } - if( ( true == Global.ControlPicking ) && ( true == FreeFlyModeFlag ) && ( true == DebugModeFlag ) ) { - auto const scenerynode = GfxRenderer->Pick_Node(); - set_tooltip( - ( scenerynode ? - scenerynode->name() : - "" ) ); + if( Global.ControlPicking && FreeFlyModeFlag && DebugModeFlag ) { + const auto sceneryNode = GfxRenderer->Pick_Node(); + const std::string content = sceneryNode ? sceneryNode->tooltip() : ""; + set_tooltip(content); } runonce = true; @@ -433,10 +431,6 @@ driver_mode::exit() { void driver_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { - Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false; - Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false; - Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false; - bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT); // give the ui first shot at the input processing... diff --git a/drivermode.h b/drivermode.h index 3588af8a..d9c0cffa 100644 --- a/drivermode.h +++ b/drivermode.h @@ -32,30 +32,21 @@ public: // methods // initializes internal data structures of the mode. returns: true on success, false otherwise - bool - init() override; + bool init() override; // mode-specific update of simulation data. returns: false on error, true otherwise - bool - update() override; + bool update() override; // maintenance method, called when the mode is activated - void - enter() override; + void enter() override; // maintenance method, called when the mode is deactivated - void - exit() override; + void exit() override; // input handlers - void - on_key( int const Key, int const Scancode, int const Action, int const Mods ) override; - void - on_cursor_pos( double const Horizontal, double const Vertical ) override; - void - on_mouse_button( int const Button, int const Action, int const Mods ) override; - void - on_scroll( double const Xoffset, double const Yoffset ) override; - void - on_event_poll() override; - bool - is_command_processor() const override; + void on_key( int Key, int Scancode, int Action, int Mods ) override; + void on_cursor_pos( double Horizontal, double Vertical ) override; + void on_mouse_button( int Button, int Action, int Mods ) override; + void on_scroll( double Xoffset, double Yoffset ) override; + void on_window_resize( int w, int h ) override { ; } + void on_event_poll() override; + bool is_command_processor() const override; private: // types diff --git a/editormode.cpp b/editormode.cpp index f2cd69bc..c743957c 100644 --- a/editormode.cpp +++ b/editormode.cpp @@ -155,10 +155,6 @@ editor_mode::exit() { void editor_mode::on_key( int const Key, int const Scancode, int const Action, int const Mods ) { - Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false; - Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false; - Global.altState = ( Mods & GLFW_MOD_ALT ) ? true : false; - bool anyModifier = Mods & (GLFW_MOD_SHIFT | GLFW_MOD_CONTROL | GLFW_MOD_ALT); // give the ui first shot at the input processing... diff --git a/editormode.h b/editormode.h index 2b757867..6e127f5a 100644 --- a/editormode.h +++ b/editormode.h @@ -23,30 +23,21 @@ public: editor_mode(); // methods // initializes internal data structures of the mode. returns: true on success, false otherwise - bool - init() override; + bool init() override; // mode-specific update of simulation data. returns: false on error, true otherwise - bool - update() override; + bool update() override; // maintenance method, called when the mode is activated - void - enter() override; + void enter() override; // maintenance method, called when the mode is deactivated - void - exit() override; + void exit() override; // input handlers - void - on_key( int const Key, int const Scancode, int const Action, int const Mods ) override; - void - on_cursor_pos( double const Horizontal, double const Vertical ) override; - void - on_mouse_button( int const Button, int const Action, int const Mods ) override; - void - on_scroll( double const Xoffset, double const Yoffset ) override { ; } - void - on_event_poll() override; - bool - is_command_processor() const override; + void on_key( int Key, int Scancode, int Action, int Mods ) override; + void on_cursor_pos( double Horizontal, double Vertical ) override; + void on_mouse_button( int Button, int Action, int Mods ) override; + void on_scroll( double const Xoffset, double const Yoffset ) override { ; } + void on_window_resize( int w, int h ) override { ; } + void on_event_poll() override; + bool is_command_processor() const override; private: // types diff --git a/editoruilayer.cpp b/editoruilayer.cpp index 0af6d525..d8ac95fc 100644 --- a/editoruilayer.cpp +++ b/editoruilayer.cpp @@ -30,14 +30,10 @@ editor_ui::update() { set_tooltip( "" ); - if( ( true == Global.ControlPicking ) - && ( true == DebugModeFlag ) ) { - - auto const scenerynode = GfxRenderer->Pick_Node(); - set_tooltip( - ( scenerynode ? - scenerynode->name() : - "" ) ); + if( Global.ControlPicking && DebugModeFlag ) { + const auto sceneryNode = GfxRenderer->Pick_Node(); + const std::string content = sceneryNode ? sceneryNode->tooltip() : ""; + set_tooltip(content); } ui_layer::update(); diff --git a/launcher/keymapper.cpp b/launcher/keymapper.cpp index e3209e1c..f03d3523 100644 --- a/launcher/keymapper.cpp +++ b/launcher/keymapper.cpp @@ -36,69 +36,60 @@ bool ui::keymapper_panel::key(int key) return true; } -void ui::keymapper_panel::render() +void ui::keymapper_panel::render_contents() { - if (!is_open) - return; + if (ImGui::Button(STR_C("Load"))) + keyboard.init(); - auto const panelname{(title.empty() ? m_name : title) + "###" + m_name}; + ImGui::SameLine(); - if (ImGui::Begin(panelname.c_str(), &is_open)) { - if (ImGui::Button(STR_C("Load"))) - keyboard.init(); + if (ImGui::Button(STR_C("Save"))) + keyboard.dump_bindings(); - ImGui::SameLine(); + for (const std::pair> &binding : keyboard.bindings()) { + // Binding ID + ImGui::AlignTextToFramePadding(); + ImGui::Text(simulation::Commands_descriptions[static_cast(binding.first)].name.c_str()); - if (ImGui::Button(STR_C("Save"))) - keyboard.dump_bindings(); + // Binding description + std::string description = std::get(binding.second); + ImGui::SameLine(260); + ImGui::Text((description.size() > 0 ? description : "(No description)").c_str()); - for (const std::pair> &binding : keyboard.bindings()) { - // Binding ID - ImGui::AlignTextToFramePadding(); - ImGui::Text(simulation::Commands_descriptions[static_cast(binding.first)].name.c_str()); + // Binding key button + int keycode = std::get(binding.second); + std::string label; - // Binding description - std::string description = std::get(binding.second); - ImGui::SameLine(260); - ImGui::Text((description.size() > 0 ? description : "(No description)").c_str()); + if (keycode & keyboard_input::keymodifier::control) + label += "ctrl + "; + if (keycode & keyboard_input::keymodifier::shift) + label += "shift + "; - // Binding key button - int keycode = std::get(binding.second); - std::string label; + auto it = keyboard.keytonamemap.find(keycode & 0xFFFF); + if (it != keyboard.keytonamemap.end()) + label += it->second; - if (keycode & keyboard_input::keymodifier::control) - label += "ctrl + "; - if (keycode & keyboard_input::keymodifier::shift) - label += "shift + "; + label = ToUpper(label); - auto it = keyboard.keytonamemap.find(keycode & 0xFFFF); - if (it != keyboard.keytonamemap.end()) - label += it->second; - - label = ToUpper(label); - - bool styles_pushed = false; - if (bind_active == binding.first) { - label = "Press key (F10 to unbind)"; - ImVec4 active_col = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); - ImGui::PushStyleColor(ImGuiCol_Button, active_col); - styles_pushed = true; - } - - label += "##" + std::to_string((int)binding.first); - - ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - 150); - if (ImGui::Button(label.c_str(), ImVec2(150, 0))) { - if (bind_active == binding.first) - bind_active = user_command::none; - else - bind_active = binding.first; - } - - if (styles_pushed) - ImGui::PopStyleColor(); + bool styles_pushed = false; + if (bind_active == binding.first) { + label = "Press key (F10 to unbind)"; + ImVec4 active_col = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive); + ImGui::PushStyleColor(ImGuiCol_Button, active_col); + styles_pushed = true; } - } - ImGui::End(); + label += "##" + std::to_string((int)binding.first); + + ImGui::SameLine(ImGui::GetContentRegionAvailWidth() - 150); + if (ImGui::Button(label.c_str(), ImVec2(150, 0))) { + if (bind_active == binding.first) + bind_active = user_command::none; + else + bind_active = binding.first; + } + + if (styles_pushed) + ImGui::PopStyleColor(); + } } diff --git a/launcher/keymapper.h b/launcher/keymapper.h index bb2a6205..f5eaaa9d 100644 --- a/launcher/keymapper.h +++ b/launcher/keymapper.h @@ -10,12 +10,12 @@ class keymapper_panel : public ui_panel public: keymapper_panel(); - void render() override; + void render_contents() override; bool key(int key); private: driverkeyboard_input keyboard; - user_command bind_active = user_command::none; + const std::string panelname = (title.empty() ? m_name : title) + "###" + m_name; }; } // namespace ui diff --git a/launcher/launchermode.cpp b/launcher/launchermode.cpp index 1d9f5a79..3e5df2a9 100644 --- a/launcher/launchermode.cpp +++ b/launcher/launchermode.cpp @@ -23,9 +23,7 @@ bool launcher_mode::update() void launcher_mode::enter() { Application.set_cursor( GLFW_CURSOR_NORMAL ); - simulation::is_ready = false; - Application.set_title(Global.AppName); } @@ -36,7 +34,10 @@ void launcher_mode::exit() void launcher_mode::on_key(const int Key, const int Scancode, const int Action, const int Mods) { - Global.shiftState = ( Mods & GLFW_MOD_SHIFT ) ? true : false; - Global.ctrlState = ( Mods & GLFW_MOD_CONTROL ) ? true : false; m_userinterface->on_key(Key, Action); } + +void launcher_mode::on_window_resize(const int w, const int h) +{ + m_userinterface->on_window_resize(w, h); +} diff --git a/launcher/launchermode.h b/launcher/launchermode.h index 30d2672c..7cd8d0e9 100644 --- a/launcher/launchermode.h +++ b/launcher/launchermode.h @@ -18,28 +18,19 @@ public: launcher_mode(); // methods // initializes internal data structures of the mode. returns: true on success, false otherwise - bool - init() override; + bool init() override; // mode-specific update of simulation data. returns: false on error, true otherwise - bool - update() override; + bool update() override; // maintenance method, called when the mode is activated - void - enter() override; + void enter() override; // maintenance method, called when the mode is deactivated - void - exit() override; + void exit() override; // input handlers - void - on_key( int const Key, int const Scancode, int const Action, int const Mods ); - void - on_cursor_pos( double const Horizontal, double const Vertical ) override { ; } - void - on_mouse_button( int const Button, int const Action, int const Mods ) override { ; } - void - on_scroll( double const Xoffset, double const Yoffset ) override { ; } - void - on_event_poll() override { ; } - bool - is_command_processor() const override { return false; } + void on_key( int Key, int Scancode, int Action, int Mods ) override; + void on_cursor_pos( double const Horizontal, double const Vertical ) override { ; } + void on_mouse_button( int const Button, int const Action, int const Mods ) override { ; } + void on_scroll( double const Xoffset, double const Yoffset ) override { ; } + void on_window_resize( int w, int h ) override; + void on_event_poll() override { ; } + bool is_command_processor() const override { return false; } }; diff --git a/launcher/launcheruilayer.cpp b/launcher/launcheruilayer.cpp index 0ab9311d..291f612d 100644 --- a/launcher/launcheruilayer.cpp +++ b/launcher/launcheruilayer.cpp @@ -1,10 +1,9 @@ #include "stdafx.h" #include "launcher/launcheruilayer.h" #include "application.h" +#include "translation.h" -#include "Logs.h" -launcher_ui::launcher_ui() - : m_scenery_scanner(m_vehicles_bank), m_scenerylist_panel(m_scenery_scanner) +launcher_ui::launcher_ui() : m_scenery_scanner(m_vehicles_bank), m_scenerylist_panel(m_scenery_scanner) { m_vehicles_bank.scan_textures(); m_scenery_scanner.scan(); @@ -13,33 +12,66 @@ launcher_ui::launcher_ui() add_external_panel(&m_keymapper_panel); add_external_panel(&m_vehiclepicker_panel); + open_panel(&m_vehiclepicker_panel); + m_suppress_menu = true; + load_random_background(); } bool launcher_ui::on_key(const int Key, const int Action) { + if (m_scenerylist_panel.on_key(Key, Action)) + return true; if (m_keymapper_panel.key(Key)) return true; return ui_layer::on_key(Key, Action); } +void launcher_ui::on_window_resize(int w, int h) +{ + open_panel(m_current_panel); +} + void launcher_ui::render_() { - ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse; - ImVec2 display_size = ImGui::GetIO().DisplaySize; - ImGui::SetNextWindowPos(ImVec2(display_size.x * 0.66f, display_size.y / 2.0f)); - ImGui::SetNextWindowSize(ImVec2(200 * Global.ui_scale, -1)); + ImGuiWindowFlags flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove; + const float topbar_height = 50 * Global.ui_scale; + const ImVec2 topbar_button_size = ImVec2(150 * Global.ui_scale, topbar_height - 16); + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(ImVec2(Global.window_size.x, topbar_height)); if (ImGui::Begin(STR_C("Main menu"), nullptr, flags)) { - if (ImGui::Button(STR_C("Scenario list"), ImVec2(-1, 0))) - m_scenerylist_panel.is_open = !m_scenerylist_panel.is_open; - if (ImGui::Button(STR_C("Vehicle list"), ImVec2(-1, 0))) - m_vehiclepicker_panel.is_open = !m_vehiclepicker_panel.is_open; - if (ImGui::Button(STR_C("Keymapper"), ImVec2(-1, 0))) - m_keymapper_panel.is_open = !m_keymapper_panel.is_open; - if (ImGui::Button(STR_C("Quit"), ImVec2(-1, 0))) + if (ImGui::Button(STR_C("Scenario list"), topbar_button_size)) + open_panel(&m_scenerylist_panel); + ImGui::SameLine(); + if (ImGui::Button(STR_C("Vehicle list"), topbar_button_size)) + open_panel(&m_vehiclepicker_panel); + ImGui::SameLine(); + if (ImGui::Button(STR_C("Keymapper"), topbar_button_size)) + open_panel(&m_keymapper_panel); + ImGui::SameLine(); + if (ImGui::Button(STR_C("Quit"), topbar_button_size)) Application.queue_quit(false); } ImGui::End(); } + +void launcher_ui::close_panels() +{ + m_scenerylist_panel.is_open = false; + m_vehiclepicker_panel.is_open = false; + m_keymapper_panel.is_open = false; +} + +void launcher_ui::open_panel(ui_panel* panel) +{ + close_panels(); + const float topbar_height = 50 * Global.ui_scale; + panel->pos = glm::vec2(0, topbar_height); + panel->size = glm::vec2(Global.window_size.x, Global.window_size.y - topbar_height); + panel->no_title_bar = true; + panel->is_open = true; + + m_current_panel = panel; +} diff --git a/launcher/launcheruilayer.h b/launcher/launcheruilayer.h index 9d8cf50d..691802c1 100644 --- a/launcher/launcheruilayer.h +++ b/launcher/launcheruilayer.h @@ -19,10 +19,13 @@ http://mozilla.org/MPL/2.0/. class launcher_ui : public ui_layer { public: launcher_ui(); - bool on_key(const int Key, const int Action) override; + bool on_key(int Key, int Action) override; + void on_window_resize(int w, int h) override; private: void render_() override; + void close_panels(); + void open_panel(ui_panel *panel); ui::vehicles_bank m_vehicles_bank; scenery_scanner m_scenery_scanner; @@ -30,4 +33,6 @@ private: ui::scenerylist_panel m_scenerylist_panel; ui::keymapper_panel m_keymapper_panel; ui::vehiclepicker_panel m_vehiclepicker_panel; + + ui_panel *m_current_panel; }; diff --git a/launcher/scenery_list.cpp b/launcher/scenery_list.cpp index 4340dcba..86c513ed 100644 --- a/launcher/scenery_list.cpp +++ b/launcher/scenery_list.cpp @@ -3,9 +3,10 @@ #include "imgui/imgui.h" #include "utilities.h" #include "renderer.h" -#include "McZapkie/MOVER.h" #include "application.h" #include "Logs.h" +#include "translation.h" + #include ui::scenerylist_panel::scenerylist_panel(scenery_scanner &scanner) @@ -13,34 +14,53 @@ ui::scenerylist_panel::scenerylist_panel(scenery_scanner &scanner) { } +bool ui::scenerylist_panel::on_key(int key, int action) +{ + if (!is_open) + return false; + + auto it = keyboard.keytonamemap.find(key); + if (it == keyboard.keytonamemap.end()) + return false; + + if (Global.ctrlState && it->second == "delete") + purge_selected_trainset(); + + return true; +} + void ui::scenerylist_panel::draw_scenery_list() { - std::string prev_prefix; - bool collapse_open = false; - + // Draw all the scenarios which are not assigned to any category. for (auto &desc : scanner.scenarios) { std::string name = desc.path.stem().string(); - std::string prefix = name.substr(0, name.find_first_of("-_")); + std::string prefix = desc.category; if (prefix.empty()) - prefix = name; - - bool just_opened = false; - if (prefix != prev_prefix) { - collapse_open = ImGui::CollapsingHeader(prefix.c_str()); - just_opened = ImGui::IsItemDeactivated(); - prev_prefix = prefix; - } - - if (collapse_open) { - if (just_opened) - selected_scenery = &desc; - - ImGui::Indent(10.0f); + { if (ImGui::Selectable(name.c_str(), &desc == selected_scenery)) { selected_scenery = &desc; selected_trainset = nullptr; } - ImGui::Unindent(10.0f); + } + } + + // Render all aggregated scenarios inside categories. + bool collapse_open = false; + for (auto category : scanner.categories) + { + collapse_open = ImGui::CollapsingHeader(category.first.c_str()); + if (collapse_open) { + for (auto desc : category.second) + { + std::string name = desc->path.stem().string(); + + ImGui::Indent(10.0f); + if (ImGui::Selectable(name.c_str(), desc == selected_scenery)) { + selected_scenery = desc; + selected_trainset = nullptr; + } + ImGui::Unindent(10.0f); + } } } } @@ -352,6 +372,11 @@ void ui::scenerylist_panel::draw_droptarget(trainset_desc &trainset, int positio } } +void ui::scenerylist_panel::purge_selected_trainset() +{ + selected_trainset->vehicles.clear(); +} + ui::dynamic_edit_popup::dynamic_edit_popup(ui_panel &panel, dynamic_desc &dynamic) : popup(panel), dynamic(dynamic) { diff --git a/launcher/scenery_list.h b/launcher/scenery_list.h index a927a9c4..fbaca275 100644 --- a/launcher/scenery_list.h +++ b/launcher/scenery_list.h @@ -1,5 +1,6 @@ #pragma once +#include "driverkeyboardinput.h" #include "uilayer.h" #include "scenery_scanner.h" #include "widgets/popup.h" @@ -35,8 +36,11 @@ class scenerylist_panel : public ui_panel scenerylist_panel(scenery_scanner &scanner); void render_contents() override; + bool on_key(int key, int action); private: + driverkeyboard_input keyboard; + struct vehicle_moved { trainset_desc &source; dynamic_desc &dynamic; @@ -63,5 +67,6 @@ private: void open_link(const std::string &link); void draw_trainset(trainset_desc &trainset); void draw_droptarget(trainset_desc &trainset, int position); + void purge_selected_trainset(); }; } // namespace ui diff --git a/launcher/scenery_scanner.cpp b/launcher/scenery_scanner.cpp index 2f5a5ad4..22007035 100644 --- a/launcher/scenery_scanner.cpp +++ b/launcher/scenery_scanner.cpp @@ -22,6 +22,8 @@ void scenery_scanner::scan() std::sort(scenarios.begin(), scenarios.end(), [](const scenery_desc &a, const scenery_desc &b) { return a.path < b.path; }); + + build_categories(); } void scenery_scanner::scan_scn(std::filesystem::path path) @@ -57,6 +59,8 @@ void scenery_scanner::scan_scn(std::filesystem::path path) desc.name = win1250_to_utf8(line.substr(5)); else if (line[3] == 'd') desc.description += win1250_to_utf8(line.substr(5)) + '\n'; + else if (line[3] == 'l') + desc.category = win1250_to_utf8(line.substr(5)); else if (line[3] == 'f') { std::string lang; std::string file; @@ -154,3 +158,14 @@ void scenery_scanner::parse_trainset(cParser &parser) trainset.file_bounds.second = parser.Line(); } + +void scenery_scanner::build_categories() +{ + for (auto &desc : scenarios) { + std::string name = desc.path.stem().string(); + std::string prefix = desc.category; + // If the scenario does have a category, add it to the list so we can render it later in a group. + if (!prefix.empty()) + categories[prefix].push_back(&desc); + } +} diff --git a/launcher/scenery_scanner.h b/launcher/scenery_scanner.h index 67648e7f..ebde6062 100644 --- a/launcher/scenery_scanner.h +++ b/launcher/scenery_scanner.h @@ -39,6 +39,7 @@ struct scenery_desc { std::filesystem::path path; std::string name; std::string description; + std::string category; std::string image_path; texture_handle image = 0; @@ -58,12 +59,14 @@ public: scenery_scanner(ui::vehicles_bank &bank); std::vector scenarios; + std::map> categories; void scan(); private: void scan_scn(std::filesystem::path path); void parse_trainset(cParser &parser); + void build_categories(); ui::vehicles_bank &bank; }; diff --git a/launcher/vehicle_picker.cpp b/launcher/vehicle_picker.cpp index 4ab5503a..ac548f40 100644 --- a/launcher/vehicle_picker.cpp +++ b/launcher/vehicle_picker.cpp @@ -1,6 +1,7 @@ #include "stdafx.h" #include "launcher/vehicle_picker.h" #include "renderer.h" +#include "translation.h" ui::vehiclepicker_panel::vehiclepicker_panel() : ui_panel(STR("Select vehicle"), false), placeholder_mini("textures/mini/other") @@ -8,195 +9,170 @@ ui::vehiclepicker_panel::vehiclepicker_panel() bank.scan_textures(); } -void ui::vehiclepicker_panel::render() +void ui::vehiclepicker_panel::render_contents() { - if (!is_open) - return; + ImGui::Columns(3); - static std::map type_names = - { - { vehicle_type::electric_loco, STRN("Electric locos") }, - { vehicle_type::diesel_loco, STRN("Diesel locos") }, - { vehicle_type::steam_loco, STRN("Steam locos") }, - { vehicle_type::railcar, STRN("Railcars") }, - { vehicle_type::emu, STRN("EMU") }, - { vehicle_type::utility, STRN("Utility") }, - { vehicle_type::draisine, STRN("Draisines") }, - { vehicle_type::tram, STRN("Trams") }, - { vehicle_type::carriage, STRN("Carriages") }, - { vehicle_type::truck, STRN("Trucks") }, - { vehicle_type::bus, STRN("Buses") }, - { vehicle_type::car, STRN("Cars") }, - { vehicle_type::man, STRN("People") }, - { vehicle_type::animal, STRN("Animals") }, - { vehicle_type::unknown, STRN("Unknown") } - }; + ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f)); - if (ImGui::Begin(m_name.c_str(), &is_open)) { - ImGui::Columns(3); + if (ImGui::BeginChild("box1")) { + for (auto const &e : type_names) { + deferred_image *image = nullptr; + auto it = bank.category_icons.find(e.first); + if (it != bank.category_icons.end()) + image = &it->second; - ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.0f, 0.5f)); + if (selectable_image(Translations.lookup_s(e.second).c_str(), e.first == selected_type, image)) + selected_type = e.first; + } + } + ImGui::EndChild(); + ImGui::NextColumn(); - if (ImGui::BeginChild("box1")) { - for (auto const &e : type_names) { - deferred_image *image = nullptr; - auto it = bank.category_icons.find(e.first); - if (it != bank.category_icons.end()) - image = &it->second; + ImGui::TextUnformatted(STR_C("Group by: ")); + ImGui::SameLine(); + if (ImGui::RadioButton(STR_C("type"), !display_by_groups)) + display_by_groups = false; + ImGui::SameLine(); + if (ImGui::RadioButton(STR_C("texture group"), display_by_groups)) + display_by_groups = true; - if (selectable_image(Translations.lookup_s(e.second).c_str(), e.first == selected_type, image)) - selected_type = e.first; + std::vector skinset_list; + + if (display_by_groups) { + std::vector model_list; + + for (auto const &kv : bank.group_map) { + const std::string &group = kv.first; + + bool model_added = false; + bool can_break = false; + bool map_sel_eq = (selected_group && group == *selected_group); + + for (auto const &vehicle : kv.second) { + if (vehicle->type != selected_type) + continue; + + for (auto const &skinset : vehicle->matching_skinsets) { + bool map_group_eq = (skinset->group == group); + bool sel_group_eq = (selected_group && skinset->group == *selected_group); + + if (!model_added && map_group_eq) { + model_list.push_back(&group); + model_added = true; + } + + if (map_sel_eq) { + if (sel_group_eq) + skinset_list.push_back(skinset.get()); + } + else if (model_added) { + can_break = true; + break; + } + } + + if (can_break) + break; } } - ImGui::EndChild(); - ImGui::NextColumn(); - ImGui::TextUnformatted(STR_C("Group by: ")); - ImGui::SameLine(); - if (ImGui::RadioButton(STR_C("type"), !display_by_groups)) - display_by_groups = false; - ImGui::SameLine(); - if (ImGui::RadioButton(STR_C("texture group"), display_by_groups)) - display_by_groups = true; + if (ImGui::BeginChild("box2")) { + ImGuiListClipper clipper(model_list.size()); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + auto group = model_list[i]; - std::vector skinset_list; + deferred_image *image = nullptr; + auto it = bank.group_icons.find(*group); + if (it != bank.group_icons.end()) + image = &it->second; - if (display_by_groups) { - std::vector model_list; + if (selectable_image(group->c_str(), group == selected_group, image)) + selected_group = group; + } + } + } + else { + std::vector> model_list; - for (auto const &kv : bank.group_map) { - const std::string &group = kv.first; + for (auto const &v : bank.vehicles) { + auto desc = v.second; - bool model_added = false; - bool can_break = false; - bool map_sel_eq = (selected_group && group == *selected_group); + if (selected_type == desc->type && desc->matching_skinsets.size() > 0) + model_list.push_back(desc); - for (auto const &vehicle : kv.second) { - if (vehicle->type != selected_type) - continue; + if (selected_vehicle == desc && selected_type == desc->type) { + for (auto &skin : desc->matching_skinsets) + skinset_list.push_back(skin.get()); + } + } - for (auto const &skinset : vehicle->matching_skinsets) { - bool map_group_eq = (skinset->group == group); - bool sel_group_eq = (selected_group && skinset->group == *selected_group); + if (ImGui::BeginChild("box2")) { + ImGuiListClipper clipper(model_list.size()); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + auto &desc = model_list[i]; - if (!model_added && map_group_eq) { - model_list.push_back(&group); - model_added = true; - } - - if (map_sel_eq) { - if (sel_group_eq) - skinset_list.push_back(skinset.get()); - } - else if (model_added) { - can_break = true; + const deferred_image *image = nullptr; + for (auto const &skinset : desc->matching_skinsets) { + if (skinset->mini) { + image = &skinset->mini; break; } } - if (can_break) - break; - } - } - - if (ImGui::BeginChild("box2")) { - ImGuiListClipper clipper(model_list.size()); - while (clipper.Step()) - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto group = model_list[i]; - - deferred_image *image = nullptr; - auto it = bank.group_icons.find(*group); - if (it != bank.group_icons.end()) - image = &it->second; - - if (selectable_image(group->c_str(), group == selected_group, image)) - selected_group = group; - } - } - } - else { - std::vector> model_list; - - for (auto const &v : bank.vehicles) { - auto desc = v.second; - - if (selected_type == desc->type && desc->matching_skinsets.size() > 0) - model_list.push_back(desc); - - if (selected_vehicle == desc && selected_type == desc->type) { - for (auto &skin : desc->matching_skinsets) - skinset_list.push_back(skin.get()); - } - } - - if (ImGui::BeginChild("box2")) { - ImGuiListClipper clipper(model_list.size()); - while (clipper.Step()) - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto &desc = model_list[i]; - - const deferred_image *image = nullptr; - for (auto const &skinset : desc->matching_skinsets) { - if (skinset->mini) { - image = &skinset->mini; - break; - } - } - - std::string label = desc->path.stem().string(); - if (selectable_image(label.c_str(), desc == selected_vehicle, image)) - selected_vehicle = desc; - } - } - } - - ImGui::EndChild(); - ImGui::NextColumn(); - - ImGui::SetNextItemWidth(-1); - ImGui::InputText("##search", search_query.data(), search_query.size()); - auto query_info = parse_search_query(search_query.data()); - if (!query_info.empty()) - skinset_list.erase(std::remove_if(skinset_list.begin(), skinset_list.end(), - std::bind(&vehiclepicker_panel::skin_filter, this, std::placeholders::_1, query_info)), - skinset_list.end()); - - if (ImGui::BeginChild("box3")) { - ImGuiListClipper clipper(skinset_list.size()); - while (clipper.Step()) - for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto skin = skinset_list[i]; - - //std::string label = skin->skins[0].stem().string(); - std::string label = skin->skin; - if (skin->meta && !skin->meta->name.empty() && skin->meta->name != "?") - label = skin->meta->name; - - auto mini = skin->mini ? &skin->mini : &placeholder_mini; - if (selectable_image(label.c_str(), skin == selected_skinset, mini, skin)) - selected_skinset = skin; - - if (skin->meta && ImGui::IsItemHovered()) { - ImGui::BeginTooltip(); - ImGui::Text(STR_C("Skin: %s\nType: %s\nCarrier code: %s\nDepot: %s\nMaintenance: %s, by %s\nSkin author: %s\nPhoto author: %s"), - skin->skin.c_str(), - skin->vehicle.lock()->path.string().c_str(), - skin->meta->short_id.c_str(), - skin->meta->location.c_str(), - skin->meta->rev_date.c_str(), - skin->meta->rev_company.c_str(), - skin->meta->texture_author.c_str(), - skin->meta->photo_author.c_str()); - ImGui::EndTooltip(); - } + std::string label = desc->path.stem().string(); + if (selectable_image(label.c_str(), desc == selected_vehicle, image)) + selected_vehicle = desc; } } - ImGui::EndChild(); - - ImGui::PopStyleVar(); } - ImGui::End(); + + ImGui::EndChild(); + ImGui::NextColumn(); + + ImGui::SetNextItemWidth(-1); + ImGui::InputText("##search", search_query.data(), search_query.size()); + auto query_info = parse_search_query(search_query.data()); + if (!query_info.empty()) + skinset_list.erase(std::remove_if(skinset_list.begin(), skinset_list.end(), + std::bind(&vehiclepicker_panel::skin_filter, this, std::placeholders::_1, query_info)), + skinset_list.end()); + + if (ImGui::BeginChild("box3")) { + ImGuiListClipper clipper(skinset_list.size()); + while (clipper.Step()) + for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + auto skin = skinset_list[i]; + + //std::string label = skin->skins[0].stem().string(); + std::string label = skin->skin; + if (skin->meta && !skin->meta->name.empty() && skin->meta->name != "?") + label = skin->meta->name; + + auto mini = skin->mini ? &skin->mini : &placeholder_mini; + if (selectable_image(label.c_str(), skin == selected_skinset, mini, skin)) + selected_skinset = skin; + + if (skin->meta && ImGui::IsItemHovered()) { + ImGui::BeginTooltip(); + ImGui::Text(STR_C("Skin: %s\nType: %s\nCarrier code: %s\nDepot: %s\nMaintenance: %s, by %s\nSkin author: %s\nPhoto author: %s"), + skin->skin.c_str(), + skin->vehicle.lock()->path.string().c_str(), + skin->meta->short_id.c_str(), + skin->meta->location.c_str(), + skin->meta->rev_date.c_str(), + skin->meta->rev_company.c_str(), + skin->meta->texture_author.c_str(), + skin->meta->photo_author.c_str()); + ImGui::EndTooltip(); + } + } + } + ImGui::EndChild(); + + ImGui::PopStyleVar(); } std::vector ui::vehiclepicker_panel::parse_search_query(const std::string &str) diff --git a/launcher/vehicle_picker.h b/launcher/vehicle_picker.h index ed850d11..b44ffefe 100644 --- a/launcher/vehicle_picker.h +++ b/launcher/vehicle_picker.h @@ -2,6 +2,7 @@ #include "uilayer.h" #include "textures_scanner.h" +#include "translation.h" namespace ui { @@ -10,7 +11,7 @@ class vehiclepicker_panel : public ui_panel public: vehiclepicker_panel(); - void render() override; + void render_contents() override; private: bool selectable_image(const char *desc, bool selected, const deferred_image *image, const skin_set *pickable = nullptr); @@ -22,6 +23,24 @@ private: bool display_by_groups = true; deferred_image placeholder_mini; std::array search_query = { 0 }; + std::map type_names = + { + { vehicle_type::electric_loco, STRN("Electric locos") }, + { vehicle_type::diesel_loco, STRN("Diesel locos") }, + { vehicle_type::steam_loco, STRN("Steam locos") }, + { vehicle_type::railcar, STRN("Railcars") }, + { vehicle_type::emu, STRN("EMU") }, + { vehicle_type::utility, STRN("Utility") }, + { vehicle_type::draisine, STRN("Draisines") }, + { vehicle_type::tram, STRN("Trams") }, + { vehicle_type::carriage, STRN("Carriages") }, + { vehicle_type::truck, STRN("Trucks") }, + { vehicle_type::bus, STRN("Buses") }, + { vehicle_type::car, STRN("Cars") }, + { vehicle_type::man, STRN("People") }, + { vehicle_type::animal, STRN("Animals") }, + { vehicle_type::unknown, STRN("Unknown") } + }; vehicles_bank bank; diff --git a/scenarioloadermode.cpp b/scenarioloadermode.cpp index 63a51371..6a47ae68 100644 --- a/scenarioloadermode.cpp +++ b/scenarioloadermode.cpp @@ -14,7 +14,6 @@ http://mozilla.org/MPL/2.0/. #include "simulation.h" #include "simulationtime.h" #include "simulationenvironment.h" -#include "Timer.h" #include "application.h" #include "scenarioloaderuilayer.h" #include "renderer.h" @@ -22,20 +21,17 @@ http://mozilla.org/MPL/2.0/. #include "translation.h" scenarioloader_mode::scenarioloader_mode() { - m_userinterface = std::make_shared(); } // initializes internal data structures of the mode. returns: true on success, false otherwise -bool -scenarioloader_mode::init() { +bool scenarioloader_mode::init() { // nothing to do here return true; } // mode-specific update of simulation data. returns: false on error, true otherwise -bool -scenarioloader_mode::update() { +bool scenarioloader_mode::update() { if (!Global.ready_to_load) // waiting for network connection return true; @@ -69,30 +65,23 @@ scenarioloader_mode::update() { return true; } -bool -scenarioloader_mode::is_command_processor() const { +bool scenarioloader_mode::is_command_processor() const { return false; } // maintenance method, called when the mode is activated -void -scenarioloader_mode::enter() { - +void scenarioloader_mode::enter() { // TBD: hide cursor in fullscreen mode? Application.set_cursor( GLFW_CURSOR_NORMAL ); simulation::is_ready = false; - m_userinterface->set_background( "logo" ); Application.set_title( Global.AppName + " (" + Global.SceneryFile + ")" ); - m_userinterface->set_progress(); m_userinterface->set_progress(STR("Loading scenery")); } // maintenance method, called when the mode is deactivated -void -scenarioloader_mode::exit() { - +void scenarioloader_mode::exit() { simulation::Time.init( Global.starting_timestamp ); simulation::Environment.init(); } diff --git a/scenarioloadermode.h b/scenarioloadermode.h index e6f78db4..5e642582 100644 --- a/scenarioloadermode.h +++ b/scenarioloadermode.h @@ -21,28 +21,19 @@ public: scenarioloader_mode(); // methods // initializes internal data structures of the mode. returns: true on success, false otherwise - bool - init() override; + bool init() override; // mode-specific update of simulation data. returns: false on error, true otherwise - bool - update() override; + bool update() override; // maintenance method, called when the mode is activated - void - enter() override; + void enter() override; // maintenance method, called when the mode is deactivated - void - exit() override; + void exit() override; // input handlers - void - on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; } - void - on_cursor_pos( double const Horizontal, double const Vertical ) override { ; } - void - on_mouse_button( int const Button, int const Action, int const Mods ) override { ; } - void - on_scroll( double const Xoffset, double const Yoffset ) override { ; } - void - on_event_poll() override { ; } - bool - is_command_processor() const override; + void on_key( int const Key, int const Scancode, int const Action, int const Mods ) override { ; } + void on_cursor_pos( double const Horizontal, double const Vertical ) override { ; } + void on_mouse_button( int const Button, int const Action, int const Mods ) override { ; } + void on_scroll( double const Xoffset, double const Yoffset ) override { ; } + void on_window_resize( int w, int h ) override { ; } + void on_event_poll() override { ; } + bool is_command_processor() const override; }; diff --git a/scenarioloaderuilayer.cpp b/scenarioloaderuilayer.cpp new file mode 100644 index 00000000..7353c15d --- /dev/null +++ b/scenarioloaderuilayer.cpp @@ -0,0 +1,109 @@ +/* +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/. +*/ + +#include "scenarioloaderuilayer.h" + +#include "Globals.h" +#include "translation.h" + +scenarioloader_ui::scenarioloader_ui() +{ + m_suppress_menu = true; + load_random_background(); + generate_gradient_tex(); + load_wheel_frames(); + + // Temorary trivia contents + m_trivia.push_back("W trakcie przeprowadzonej rewizji technicznej wagonów kolejowych"); + m_trivia.push_back("sprawdza się również daty ostatnich napraw okresowych. Wagony, dla"); + m_trivia.push_back("których upływa termin dokonania następnej naprawy okresowej pracownik"); + m_trivia.push_back("zespołu rewizji technicznej prowadzący oględziny winien jest przekierować"); + m_trivia.push_back("do odpowiednich Zakładów Naprawczych Taboru Kolejowego lub wagonowni."); +} + +void scenarioloader_ui::render_() +{ + // For some reason, ImGui windows have some padding. Offset it. + // TODO: Find out a way to exactly adjust the position. + constexpr int padding = 12; + ImGui::SetNextWindowPos(ImVec2(-padding, -padding)); + ImGui::SetNextWindowSize(ImVec2(Global.window_size.x + padding * 2, Global.window_size.y + padding * 2)); + ImGui::Begin("Neo Loading Screen", nullptr, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoBackground); + ImDrawList* draw_list = ImGui::GetWindowDrawList(); + ImGui::PushFont(font_loading); + ImGui::SetWindowFontScale(1); + const float font_scale_mult = 48 / ImGui::GetFontSize(); + // Gradient at the lower half of the screen + const auto tex = reinterpret_cast(m_gradient_overlay_tex); + draw_list->AddImage(tex, ImVec2(0, Global.window_size.y / 2), ImVec2(Global.window_size.x, Global.window_size.y), ImVec2(0, 0), ImVec2(1, 1)); + // Loading label + ImGui::SetWindowFontScale(font_scale_mult * 0.8); + draw_list->AddText(ImVec2(200, 885), IM_COL32_WHITE, m_progresstext.c_str()); + // Loading wheel icon + const deferred_image* img = &m_loading_wheel_frames[38]; + const auto loading_tex = img->get(); + const auto loading_size = img->size(); + draw_list->AddImage(reinterpret_cast(loading_tex), ImVec2(35, 850), ImVec2(35 + loading_size.x, 850 + loading_size.y), ImVec2(0, 0), ImVec2(1, 1)); + // Trivia header + ImGui::SetWindowFontScale(font_scale_mult * 1); + draw_list->AddText(ImVec2(1280 - ImGui::CalcTextSize(STR_C("Did you know")).x / 2, 770), IM_COL32_WHITE, STR_C("Did you know")); + // Trivia content + ImGui::SetWindowFontScale(font_scale_mult * 0.6); + for (int i = 0; i < m_trivia.size(); i++) + { + std::string line = m_trivia[i]; + draw_list->AddText(ImVec2(1280 - ImGui::CalcTextSize(line.c_str()).x / 2, 825 + i * 25), IM_COL32_WHITE, line.c_str()); + } + // Progress bar at the bottom of the screen + const auto p1 = ImVec2(0, Global.window_size.y - 2); + const auto p2 = ImVec2(Global.window_size.x * m_progress, Global.window_size.y); + draw_list->AddRectFilled(p1, p2, ImColor(40, 210, 60, 255)); + ImGui::PopFont(); + ImGui::End(); +} + +void scenarioloader_ui::generate_gradient_tex() +{ + constexpr int image_width = 1; + constexpr int image_height = 256; + const auto image_data = new char[image_width * image_height * 4]; + for (int x = 0; x < image_width; x++) + for (int y = 0; y < image_height; y++) + { + image_data[(y * image_width + x) * 4] = 0; + image_data[(y * image_width + x) * 4 + 1] = 0; + image_data[(y * image_width + x) * 4 + 2] = 0; + image_data[(y * image_width + x) * 4 + 3] = clamp(static_cast(pow(y / 255.f, 0.7) * 255), 0, 255); + } + + // Create a OpenGL texture identifier + GLuint image_texture; + glGenTextures(1, &image_texture); + glBindTexture(GL_TEXTURE_2D, image_texture); + + // Setup filtering parameters for display + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + // Upload pixels into texture + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data); + + delete[] image_data; + + m_gradient_overlay_width = image_width; + m_gradient_overlay_height = image_height; + m_gradient_overlay_tex = image_texture; +} + +void scenarioloader_ui::load_wheel_frames() +{ + for (int i = 0; i < 60; i++) + m_loading_wheel_frames[i] = deferred_image("ui/loading_wheel/" + std::to_string(i + 1)); +} \ No newline at end of file diff --git a/scenarioloaderuilayer.h b/scenarioloaderuilayer.h index 3890e8ec..224a8f0e 100644 --- a/scenarioloaderuilayer.h +++ b/scenarioloaderuilayer.h @@ -10,11 +10,18 @@ http://mozilla.org/MPL/2.0/. #pragma once #include "uilayer.h" +#include "launcher/deferred_image.h" class scenarioloader_ui : public ui_layer { + int m_gradient_overlay_width; + int m_gradient_overlay_height; + GLuint m_gradient_overlay_tex; + deferred_image m_loading_wheel_frames[60]; + std::vector m_trivia; public: - scenarioloader_ui() : ui_layer() { - load_random_background(); - } - // TODO: implement mode-specific elements + scenarioloader_ui(); + void render_() override; +private: + void generate_gradient_tex(); + void load_wheel_frames(); }; diff --git a/scenenode.h b/scenenode.h index 02fe05da..155c1d5d 100644 --- a/scenenode.h +++ b/scenenode.h @@ -330,6 +330,7 @@ public: export_as_text( std::string &Output ) const; std::string const & name() const; + virtual std::string tooltip() const; void location( glm::dvec3 const Location ); glm::dvec3 const & @@ -379,6 +380,13 @@ basic_node::name() const { return m_name; } +// Returns the tooltip of this Node when hovered with the mouse cursor. +inline +std::string basic_node::tooltip() const +{ + return m_name; +} + inline void basic_node::location( glm::dvec3 const Location ) { diff --git a/uilayer.cpp b/uilayer.cpp index 9f9b656b..64dea8f4 100644 --- a/uilayer.cpp +++ b/uilayer.cpp @@ -10,10 +10,11 @@ http://mozilla.org/MPL/2.0/. #include "stdafx.h" #include "uilayer.h" +#include + #include "Globals.h" #include "renderer.h" #include "Logs.h" -#include "Timer.h" #include "simulation.h" #include "translation.h" #include "application.h" @@ -26,8 +27,9 @@ GLint ui_layer::m_textureunit { GL_TEXTURE0 }; bool ui_layer::m_cursorvisible; ImFont *ui_layer::font_default{nullptr}; ImFont *ui_layer::font_mono{nullptr}; +ImFont *ui_layer::font_loading{nullptr}; -ui_panel::ui_panel(std::string const &Identifier, bool const Isopen) : m_name(Identifier), is_open(Isopen) {} +ui_panel::ui_panel(std::string Identifier, bool const Isopen) : is_open(Isopen), m_name(std::move(Identifier)) {} void ui_panel::render() { @@ -36,11 +38,16 @@ void ui_panel::render() int flags = window_flags; if (flags == -1) - flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse | - ((size.x > 0) ? ImGuiWindowFlags_NoResize : 0); + flags = ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoCollapse; + if (size.x > 0) + flags |= ImGuiWindowFlags_NoResize; + if (no_title_bar) + flags |= ImGuiWindowFlags_NoTitleBar; - if (size.x > 0) - ImGui::SetNextWindowSize(ImVec2S(size.x, size.y)); + if (pos.x != -1 && pos.y != -1) + ImGui::SetNextWindowPos(ImVec2(pos.x, pos.y), ImGuiCond_Always); + if (size.x > 0) + ImGui::SetNextWindowSize(ImVec2S(size.x, size.y), ImGuiCond_Always); else if (size_min.x == -1) ImGui::SetNextWindowSize(ImVec2(0, 0), ImGuiCond_FirstUseEver); @@ -51,7 +58,7 @@ void ui_panel::render() if (ImGui::Begin(panelname.c_str(), &is_open, flags)) { render_contents(); - popups.remove_if([](std::unique_ptr &popup) + popups.remove_if([](const std::unique_ptr &popup) { return popup->render(); }); @@ -91,6 +98,13 @@ void ui_log_panel::render_contents() ImGui::PopFont(); } +ui_layer::ui_layer() +{ + if (Global.loading_log) + add_external_panel(&m_logpanel); + m_logpanel.size = { 700, 400 }; +} + ui_layer::~ui_layer() {} bool ui_layer::key_callback(int key, int scancode, int action, int mods) @@ -117,14 +131,7 @@ bool ui_layer::mouse_button_callback(int button, int action, int mods) return m_imguiio->WantCaptureMouse; } -ui_layer::ui_layer() -{ - if (Global.loading_log) - add_external_panel(&m_logpanel); - m_logpanel.size = { 700, 400 }; -} - -void::ui_layer::load_random_background() +void ui_layer::load_random_background() { std::vector images; for (auto &f : std::filesystem::directory_iterator("textures/logo")) @@ -222,9 +229,11 @@ bool ui_layer::init(GLFWwindow *Window) }; if (FileExists("fonts/dejavusans.ttf")) - font_default = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusans.ttf", Global.ui_fontsize, nullptr, &ranges[0]); + font_default = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusans.ttf", Global.ui_fontsize, nullptr, &ranges[0]); if (FileExists("fonts/dejavusansmono.ttf")) - font_mono = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusansmono.ttf", Global.ui_fontsize, nullptr, &ranges[0]); + font_mono = m_imguiio->Fonts->AddFontFromFileTTF("fonts/dejavusansmono.ttf", Global.ui_fontsize, nullptr, &ranges[0]); + if (FileExists("fonts/bahnschrift.ttf")) + font_loading = m_imguiio->Fonts->AddFontFromFileTTF("fonts/bahnschrift.ttf", 48, nullptr, &ranges[0]); if (!font_default && !font_mono) font_default = font_mono = m_imguiio->Fonts->AddFontDefault(); @@ -232,6 +241,8 @@ bool ui_layer::init(GLFWwindow *Window) font_default = font_mono; else if (!font_mono) font_mono = font_default; + if (!font_loading) + font_loading = font_default; imgui_style(); @@ -298,6 +309,13 @@ bool ui_layer::on_mouse_button(int const Button, int const Action) return false; } +void ui_layer::on_window_resize(int w, int h) +{ + for (auto *panel : m_panels) + panel->on_window_resize(w, h); +} + + void ui_layer::update() { for (auto *panel : m_panels) @@ -313,7 +331,6 @@ void ui_layer::update() void ui_layer::render() { render_background(); - render_progress(); render_panels(); render_tooltip(); render_menu(); @@ -366,26 +383,20 @@ void ui_layer::set_cursor(int const Mode) m_cursorvisible = (Mode != GLFW_CURSOR_DISABLED); } -void ui_layer::set_progress(float const Progress, float const Subtaskprogress) +void ui_layer::set_progress(std::string const &Text) { - m_progress = Progress * 0.01f; - m_subtaskprogress = Subtaskprogress * 0.01f; + m_progresstext = Text; +} + +void ui_layer::set_progress(float const progress, float const subtaskprogress) +{ + m_progress = progress * 0.01f; + m_subtaskprogress = subtaskprogress * 0.01f; } void ui_layer::set_background(std::string const &Filename) { - if (false == Filename.empty()) - { - m_background = GfxRenderer->Fetch_Texture(Filename); - } - else - { - m_background = null_handle; - } - if (m_background != null_handle) - { - auto const &texture = GfxRenderer->Texture(m_background); - } + m_background = Filename.empty() ? null_handle : GfxRenderer->Fetch_Texture(Filename); } void ui_layer::clear_panels() @@ -406,22 +417,6 @@ void ui_layer::add_owned_panel(ui_panel *Panel) m_ownedpanels.emplace_back( Panel ); } -void ui_layer::render_progress() -{ - if ((m_progress == 0.0f) && (m_subtaskprogress == 0.0f)) - return; - - ImGui::SetNextWindowPos(ImVec2(50, 50)); - ImGui::SetNextWindowSize(ImVec2(0, 0)); - ImGui::Begin(STR_C("Loading"), nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoCollapse); - if (!m_progresstext.empty()) - ImGui::ProgressBar(m_progress, ImVec2(300, 0), m_progresstext.c_str()); - else - ImGui::ProgressBar(m_progress, ImVec2(300, 0)); - ImGui::ProgressBar(m_subtaskprogress, ImVec2(300, 0)); - ImGui::End(); -} - void ui_layer::render_panels() { for (auto *panel : m_panels) @@ -486,7 +481,7 @@ void ui_layer::render_menu() { glm::dvec2 mousepos = Global.cursor_pos; - if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_progress != 0.0f) + if (!((Global.ControlPicking && mousepos.y < 50.0f) || m_imguiio->WantCaptureMouse) || m_suppress_menu) return; if (ImGui::BeginMainMenuBar()) diff --git a/uilayer.h b/uilayer.h index d481d384..3cd80c4d 100644 --- a/uilayer.h +++ b/uilayer.h @@ -11,7 +11,6 @@ http://mozilla.org/MPL/2.0/. #include #include "Texture.h" -#include "translation.h" #include "widgets/popup.h" // GuiLayer -- basic user interface class. draws requested information on top of openGL screen @@ -20,32 +19,31 @@ class ui_panel { public: // constructor - ui_panel( std::string const &Identifier, bool const Isopen ); + ui_panel( std::string Identifier, bool Isopen ); virtual ~ui_panel() = default; // methods - virtual void update() {}; + virtual void update() {} + virtual void on_window_resize(int w, int h) {} virtual void render(); virtual void render_contents(); // temporary access // types struct text_line { - std::string data; glm::vec4 color; - - text_line( std::string const &Data, glm::vec4 const &Color) - : data(Data), color(Color) - {} + text_line( std::string const &Data, glm::vec4 const &Color) : data(Data), color(Color) {} }; // members std::string title; bool is_open; + glm::ivec2 pos { -1, -1 }; glm::ivec2 size { -1, -1 }; glm::ivec2 size_min { -1, -1 }; glm::ivec2 size_max { -1, -1 }; std::deque text_lines; int window_flags = -1; + bool no_title_bar = false; const std::string& name() { return m_name; } void register_popup(std::unique_ptr &&popup); @@ -59,19 +57,16 @@ protected: class ui_expandable_panel : public ui_panel { public: using ui_panel::ui_panel; - bool is_expanded { false }; - void render_contents() override; }; class ui_log_panel : public ui_panel { using ui_panel::ui_panel; - void render_contents() override; }; -class ImFont; +struct ImFont; class ui_layer { public: @@ -81,68 +76,40 @@ public: virtual ~ui_layer(); // methods - static - bool - init( GLFWwindow *Window ); - - static - void - imgui_style(); + static bool init( GLFWwindow *Window ); + static void imgui_style(); // assign texturing hardware unit - static - void - set_unit( GLint const Textureunit ) { m_textureunit = GL_TEXTURE0 + Textureunit; } - static - void - shutdown(); + static void set_unit( GLint const Textureunit ) { m_textureunit = GL_TEXTURE0 + Textureunit; } + static void shutdown(); // potentially processes provided input key. returns: true if the input was processed, false otherwise - virtual - bool - on_key( int const Key, int const Action ); + virtual bool on_key( int Key, int Action ); // potentially processes provided mouse movement. returns: true if the input was processed, false otherwise - virtual - bool - on_cursor_pos( double const Horizontal, double const Vertical ); + virtual bool on_cursor_pos( double Horizontal, double Vertical ); // potentially processes provided mouse button. returns: true if the input was processed, false otherwise - virtual - bool - on_mouse_button( int const Button, int const Action ); + virtual bool on_mouse_button( int Button, int Action ); + // processes window resize. + virtual void on_window_resize(int w, int h); // updates state of UI elements - virtual - void - update(); + virtual void update(); // draws requested UI elements - void - render(); - static void - render_internal(); + void render(); + static void render_internal(); // begins new UI frame // (this is separate from render() to allow for debug GUI outside of proper UI framework) - void - begin_ui_frame(); - static void - begin_ui_frame_internal(); + void begin_ui_frame(); + static void begin_ui_frame_internal(); // - static - void - set_cursor( int const Mode ); - // stores operation progress - void - set_progress( float const Progress = 0.0f, float const Subtaskprogress = 0.0f ); - void - set_progress( std::string const &Text ) { m_progresstext = Text; } + static void set_cursor( int Mode ); + // loading + void set_progress(std::string const &Text); + void set_progress(float progress, float subtaskprogress); // sets the ui background texture, if any - void - set_background( std::string const &Filename = "" ); - void - set_tooltip( std::string const &Tooltip ) { m_tooltip = Tooltip; } - void - clear_panels(); - void - add_external_panel( ui_panel *Panel ) { m_panels.emplace_back( Panel ); } - void - add_owned_panel( ui_panel *Panel ); + void set_background( std::string const &Filename = "" ); + void set_tooltip( std::string const &Tooltip ) { m_tooltip = Tooltip; } + void clear_panels(); + void add_external_panel( ui_panel *Panel ) { m_panels.emplace_back( Panel ); } + void add_owned_panel( ui_panel *Panel ); // callback functions for imgui input // returns true if input is consumed @@ -153,48 +120,38 @@ public: static ImFont *font_default; static ImFont *font_mono; + static ImFont *font_loading; protected: // members static GLFWwindow *m_window; static ImGuiIO *m_imguiio; - static bool m_cursorvisible; + static bool m_cursorvisible; void load_random_background(); virtual void render_menu_contents(); ui_log_panel m_logpanel { "Log", true }; + bool m_suppress_menu = false; // if `true`, the menu at the top of the window will not be present + // progress bar config + float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. + float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. + std::string m_progresstext; // label placed over the progress bar -private: + private: // methods // render() subclass details - virtual - void - render_() {}; + virtual void render_() {} // draws background quad with specified earlier texture - void - render_background(); - // draws a progress bar in defined earlier state - void - render_progress(); - void - render_tooltip(); + void render_background(); + void render_tooltip(); void render_panels(); - - void render_menu(); - - void render_quit_widget(); - + void render_menu(); + void render_quit_widget(); // draws a quad between coordinates x,y and z,w with uv-coordinates spanning 0-1 - void - quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ); + void quad( glm::vec4 const &Coordinates, glm::vec4 const &Color ); // members static GLint m_textureunit; - // progress bar config. TODO: put these together into an object - float m_progress { 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. - float m_subtaskprogress{ 0.0f }; // percentage of filled progres bar, to indicate lengthy operations. - std::string m_progresstext; // label placed over the progress bar - texture_handle m_background { null_handle }; // path to texture used as the background. size depends on mAspect. std::vector m_panels; std::vector> m_ownedpanels; diff --git a/widgets/cameraview_extcam.cpp b/widgets/cameraview_extcam.cpp index e9e17982..ce2dc35c 100644 --- a/widgets/cameraview_extcam.cpp +++ b/widgets/cameraview_extcam.cpp @@ -6,7 +6,7 @@ #include "widgets/cameraview_extcam.h" #include "stb/stb_image.h" #include "Globals.h" -#include "Logs.h" +#include "translation.h" #include "extras/piped_proc.h" ui::cameraview_panel::cameraview_panel() diff --git a/widgets/perfgraphs.cpp b/widgets/perfgraphs.cpp index 9e5a6d0a..277f93f0 100644 --- a/widgets/perfgraphs.cpp +++ b/widgets/perfgraphs.cpp @@ -1,12 +1,9 @@ #include "stdafx.h" #include "widgets/perfgraphs.h" #include "Timer.h" +#include "translation.h" -perfgraph_panel::perfgraph_panel() - : ui_panel(STR("Performance"), false) -{ - -} +perfgraph_panel::perfgraph_panel() : ui_panel(STR("Performance"), false) {} void perfgraph_panel::render_contents() { if (ImGui::BeginCombo(STR_C("Timer"), timer_label[current_timer].c_str())) // The second parameter is the label previewed before opening the combo.