#include "externals.hh" #include "common.hh" #include "ui.hh" #include "ui-actions.hh" #include "ui-app.hh" #include "ui-overrides.hh" #include "ui-sync.hh" #include "ui-utilities.hh" /*= T_SyncInputData_ =========================================================*/ namespace { class T_SyncInputData_ : public sov::A_SyncData { private: T_AutoArray< float* , 16 > ptr_; public: void setFromOverride( A_SyncOverride const& sov ) noexcept; float operator[]( uint32_t index ) const noexcept override; bool set( uint32_t index , float value ) noexcept override; T_OwnPtr< sov::A_SyncData > clone( ) const noexcept override; }; void T_SyncInputData_::setFromOverride( A_SyncOverride const& sov ) noexcept { auto const& iPos{ sov.inputPositions() }; const auto np{ iPos.size( ) }; ptr_.ensureCapacity( np ); ptr_.clear( ); auto& inputs{ Common::Sync( ).inputs( ) }; for ( auto i = 0u ; i < np ; i ++ ) { ptr_.add( &inputs[ iPos[ i ] ] ); } } float T_SyncInputData_::operator[]( const uint32_t index ) const noexcept { return *ptr_[ index ]; } bool T_SyncInputData_::set( const uint32_t index , const float value ) noexcept { *ptr_[ index ] = value; return true; } T_OwnPtr< sov::A_SyncData > T_SyncInputData_::clone( ) const noexcept { return NewOwned< T_SyncInputData_ >( *this ); } } // namespace /*= T_UISync =================================================================*/ T_UISync::T_UISync( ) { UI::Main( ).addAction( T_UIAction{ "Save curves" , []() { if ( Common::Sync( ).curvesFileChanged( ) ) { UI::Main( ).msgbox( "Curves file changed" , "The file containing the curves has been modified " "on the disk. These changes will be overwritten. " "Do you want to continue?" , []( auto b ) { if ( b == T_MessageBox::BT_YES ) { Common::Sync( ).saveCurves( ); } } , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } ); } else { Common::Sync( ).saveCurves( ); } } }.setEnabledCheck( []() { return Common::Sync( ).curvesModified( ); } ).setIcon( ICON_FA_FLOPPY_O ) .setShortcut( T_KeyboardShortcut{ 's' , E_KbdMod::CTRL } ) ); //----------------------------------------------------------------------------- UI::Main( ).addAction( T_UIAction{ "Reload curves" , []() { UI::Main( ).msgbox( "Reload curves?" , "Changes you made to the curves will be lost. Do you " "want to continue?" , []( auto b ) { if ( b == T_MessageBox::BT_YES ) { Common::Sync( ).loadCurves( ); } } , { T_MessageBox::BT_YES , T_MessageBox::BT_NO } ); } }.setEnabledCheck( []() { return Common::Sync( ).curvesModified( ); } ).setIcon( ICON_FA_DOWNLOAD ) .setShortcut( T_KeyboardShortcut{ 'r' , { E_KbdMod::CTRL , E_KbdMod::SHIFT } } ) ); //----------------------------------------------------------------------------- const auto addui{ [this]( char const* type , F_Override ov ) { const bool ok{ sovuis_.add( T_String{ type } , std::move( ov ) ) }; assert( ok ); (void)ok; } }; addui( "float" , sov::UIFloat ); addui( "float2" , sov::UIFloat2 ); addui( "float3" , sov::UIFloat3 ); addui( "float4" , sov::UIFloat4 ); addui( "int" , sov::UIInteger ); addui( "int2" , sov::UIInteger2 ); addui( "int3" , sov::UIInteger3 ); addui( "int4" , sov::UIInteger4 ); addui( "cg" , sov::UIColorGrading ); addui( "cam" , sov::UICamera ); } T_UISync::~T_UISync( ) { UI::Main( ).clearMouseDelegate( ); } /*----------------------------------------------------------------------------*/ namespace { bool HandleOverrideSection_( T_SyncOverrideSection& sos , bool exit , T_AutoArray< bool , 32 >& stack ) { if ( exit ) { assert( !stack.empty( ) ); if ( stack.last( ) && stack.size( ) > 1 ) { ImGui::TreePop( ); } stack.removeLast( ); return true; } const bool display( stack.empty( ) ? ImGui::CollapsingHeader( &sos.cTitle[ 0 ] ) : ImGui::TreeNode( &sos.cTitle[ 0 ] ) ); stack.add( display ); return display; } void HandleOverride_( A_SyncOverride& ov , T_SyncInputData_& data , uint32_t& counter , T_StringBuilder& sb ) noexcept { using namespace ImGui; bool& enabled{ ov.enabled( ) }; if ( Checkbox( &ov.title( )[ 0 ] , &enabled ) ) { auto const& ipos( ov.inputPositions( ) ); Common::Sync( ).setOverridesActive( ov.enabled( ) , ipos.size( ) , &ipos[ 0 ] ); } if ( !enabled ) { PushDisabled( ); } Indent( ); PushItemWidth( -1 ); data.setFromOverride( ov ); (UI::Sync( ).uiFor( ov ))( ov , data , counter , sb ); PopItemWidth( ); Unindent( ); if ( !enabled ) { PopDisabled( ); } } } // namespace T_UISync::F_Override T_UISync::uiFor( A_SyncOverride& target ) const noexcept { auto const* const rv{ sovuis_.get( target.type( ) ) }; return rv ? *rv : []( A_SyncOverride& , sov::A_SyncData& , uint32_t& , T_StringBuilder& ) { ImGui::Text( "(missing UI)" ); return false; }; } void T_UISync::makeOverridesWindow( ) { if ( !ovWindow_ ) { return; } using namespace ImGui; auto const& dspSize( GetIO( ).DisplaySize ); SetNextWindowSize( ImVec2( dspSize.x * .25f , dspSize.y * .66f - 20 ) , ImGuiSetCond_Appearing ); SetNextWindowPos( ImVec2( 0 , 20 ) , ImGuiSetCond_Appearing ); Begin( "Input overrides" , &ovWindow_ , ImGuiWindowFlags_NoCollapse ); T_AutoArray< bool , 32 > stack; T_SyncInputData_ data; T_StringBuilder temp; uint32_t counter{ 0 }; bool found{ false }; using T_Ove_ = T_SyncOverrideVisitor::T_Element; Common::Sync( ).visitOverrides( [&]( T_Ove_ element , bool exit ) { // Display sections if ( element.hasType< T_SyncOverrideSection* >( ) ) { auto& sos( *element.value< T_SyncOverrideSection* >( ) ); if ( sos.title == "*root*" ) { return true; } found = true; return HandleOverrideSection_( sos , exit , stack ); } if ( exit ) { HandleOverride_( *element.value< A_SyncOverride* >( ) , data , counter , temp ); found = true; } return true; } ); if ( !found ) { Text( "No overrides have been defined." ); } End( ); } /*----------------------------------------------------------------------------*/ void T_UISync::updateTime( ) noexcept { auto& s{ Common::Sync( ) }; if ( s.playing( ) ) { const float time( SDL_GetTicks( ) * 1e-3f ); if ( playingPrevious_ ) { s.timeDelta( time - lastFrame_ ); } lastFrame_ = time; } playingPrevious_ = s.playing( ); } /*----------------------------------------------------------------------------*/ void T_UISync::delegateMouse( T_String const& id , P_MouseCtrl delegate ) noexcept { mouseDelegateName_ = id; mouseDelegate_ = std::move( delegate ); UI::Main( ).setMouseDelegate( this ); } void T_UISync::clearMouseDelegate( ) noexcept { mouseDelegateName_ = T_String{ }; mouseDelegate_ = P_MouseCtrl{ }; UI::Main( ).clearMouseDelegate( ); } void T_UISync::handleDragAndDrop( ImVec2 const& move , T_KbdMods modifiers , T_MouseButtons buttons ) noexcept { if ( mouseDelegate_ ) { mouseDelegate_->handleDragAndDrop( move , modifiers , buttons ); } } void T_UISync::handleWheel( const float wheel , T_KbdMods modifiers , T_MouseButtons buttons ) noexcept { if ( mouseDelegate_ ) { mouseDelegate_->handleWheel( wheel , modifiers , buttons ); } }