diff --git a/sync.hh b/sync.hh index f692a1c..12e80b0 100644 --- a/sync.hh +++ b/sync.hh @@ -318,6 +318,8 @@ struct T_SyncManager : public virtual A_MouseCtrl const float initial = 0.f ) noexcept { return values_.addValue( name , initial ); } + T_Array< T_String > const& inputNames( ) const noexcept + { return values_.identifiers; } uint32_t inputPos( T_String const& name ) const noexcept { return values_.indexOf( name ); } T_Array< float > const& inputs( ) const noexcept diff --git a/syncview.cc b/syncview.cc index d31a6c3..c6c5d9f 100644 --- a/syncview.cc +++ b/syncview.cc @@ -8,6 +8,29 @@ using namespace ebcl; +/*= FAKE TABS HELPER ===========================================================*/ + +namespace { + bool FakeTab_( + char const* const name , + const bool disabled , + const float width = 0.f ) + { + using namespace ImGui; + if ( disabled ) { + PushItemFlag( ImGuiItemFlags_Disabled , true ); + PushStyleVar( ImGuiStyleVar_Alpha , + GetStyle( ).Alpha * .5f ); + } + const bool rv( Button( name , ImVec2{ width , 0.f } ) ); + if ( disabled ) { + PopItemFlag( ); + PopStyleVar( ); + } + return rv; + } +} // namespace + /*= T_SyncViewImpl_ ============================================================*/ namespace { @@ -29,11 +52,18 @@ struct T_SyncViewImpl_ bool followTime{ true }; bool display( ) noexcept; + void computeMetrics( float innerWidth ) noexcept; void sequencerWidget( ) noexcept; void sequencerHeader( ImRect const& bb ) noexcept; void sequencerBody( ImRect const& bb ) noexcept; + void displayCurveSelectorWindow( ) noexcept; + void displayCurveSelector( ) noexcept; + + // Misc stuff + T_StringBuilder stringBuffer; // XXX damn this shit to fucking hell + // Computed metrics float barWidth; float cursorPos; @@ -48,10 +78,21 @@ struct T_SyncViewImpl_ bool justZoomed{ false }; float firstZoomPixel; float curZoomPixel; + + // Curve display / edition + enum E_SubWindow { + SW_NONE , + SW_CURVE_SELECTOR , + SW_OVERRIDE_SELECTOR , + }; + E_SubWindow sub{ SW_NONE }; + T_KeyValueTable< T_String , bool > curves; + T_String curveFinder; }; constexpr float T_SyncViewImpl_::BarWidth; +/*------------------------------------------------------------------------------*/ bool T_SyncViewImpl_::display( ) noexcept { @@ -70,6 +111,9 @@ bool T_SyncViewImpl_::display( ) noexcept return false; } + //---------------------------------------------------------------------- + // Toolbar + if ( Button( sync.playing( ) ? ICON_FA_STOP : ICON_FA_PLAY , BtSize ) ) { sync.playing( ) = !sync.playing( ) && !sync.finished( ); } @@ -90,6 +134,8 @@ bool T_SyncViewImpl_::display( ) noexcept EndTooltip( ); } + SameLine( ); + VerticalSeparator( ); SameLine( ); Text( ICON_FA_SEARCH ); @@ -116,14 +162,45 @@ bool T_SyncViewImpl_::display( ) noexcept EndTooltip( ); } + SameLine( ); + VerticalSeparator( ); + SameLine( ); + + if ( Button( ICON_FA_LINE_CHART ) ) { + const bool displaySelector{ sub == SW_CURVE_SELECTOR + || sub == SW_OVERRIDE_SELECTOR }; + sub = displaySelector ? SW_NONE : SW_CURVE_SELECTOR; + curveFinder = T_String{}; + } + if ( IsItemHovered( ) ) { + BeginTooltip( ); + Text( "Select curves or sets thereof to display & edit." ); + EndTooltip( ); + } + + //---------------------------------------------------------------------- + // Sequencer widget & subwindows + PushItemWidth( -1 ); sequencerWidget( ); PopItemWidth( ); - End( ); + + switch ( sub ) { + case SW_NONE: + break; + + case SW_CURVE_SELECTOR: + case SW_OVERRIDE_SELECTOR: + displayCurveSelectorWindow( ); + break; + } + return true; } +/*------------------------------------------------------------------------------*/ + void T_SyncViewImpl_::sequencerWidget( ) noexcept { using namespace ImGui; @@ -346,6 +423,115 @@ void T_SyncViewImpl_::sequencerBody( } } +/*------------------------------------------------------------------------------*/ + +void T_SyncViewImpl_::displayCurveSelectorWindow( ) noexcept +{ + using namespace ImGui; + auto const& dspSize( GetIO( ).DisplaySize ); + + // Window set-up + SetNextWindowSize( ImVec2( dspSize.x * .25f , dspSize.y * .66f - 20 ) , ImGuiSetCond_Appearing ); + SetNextWindowPos( ImVec2( dspSize.x * .75f , 20 ) , ImGuiSetCond_Appearing ); + bool displayed{ true }; + Begin( "Display curves" , &displayed , ImGuiWindowFlags_NoCollapse ); + if ( !displayed ) { + End( ); + sub = SW_NONE; + return; + } + + // "Tabs" + const ImVec2 ws( GetWindowContentRegionMax( ) ); + auto const& style( GetStyle( ) ); + const float innerWidth{ ws.x - 2 * style.FramePadding.x }; + constexpr float nButtons{ 2.f }; + const float buttonWidth{ std::max( 50.f , + ( innerWidth - nButtons * style.FramePadding.x ) / nButtons ) }; + + if ( FakeTab_( "Individual inputs" , sub == SW_CURVE_SELECTOR , buttonWidth ) ) { + sub = SW_CURVE_SELECTOR; + } + SameLine( 0 ); + if ( FakeTab_( "Overrides" , sub == SW_OVERRIDE_SELECTOR , buttonWidth ) ) { + sub = SW_OVERRIDE_SELECTOR; + } + + // Content + switch ( sub ) { + case SW_CURVE_SELECTOR: + displayCurveSelector( ); + break; + case SW_OVERRIDE_SELECTOR: + break; + default: + fprintf( stderr , "unexpected bullshit in sync view\n" ); + std::abort( ); + } + End( ); +} + +void T_SyncViewImpl_::displayCurveSelector( ) noexcept +{ + using namespace ImGui; + T_Array< T_String > names{ Globals::Sync( ).inputNames( ) }; + + // Search box; FIXME, this is utterly hacky + stringBuffer.clear( ) << curveFinder; + while ( stringBuffer.size( ) < 100 ) { + stringBuffer << '\0'; + } + Text( ICON_FA_SEARCH ); + SameLine( ); + PushItemWidth( -1 ); + if ( InputText( "##find" , const_cast< char* >( stringBuffer.data( ) ) , + stringBuffer.size( ) ) ) { + curveFinder = T_String{ stringBuffer.data( ) , + uint32_t( strlen( stringBuffer.data( ) ) ) }; + } + PopItemWidth( ); + if ( curveFinder ) { + for ( auto i = 0u ; i < names.size( ) ; ) { + auto const& n( names[ i ] ); + if ( n.find( curveFinder ) == -1 ) { + names.removeSwap( i ); + } else { + i ++; + } + } + } + names.sort( ); + + // The list + ImGui::BeginChild( "content" ); + for ( auto const& n : names ) { + const bool present{ curves.contains( n ) }; + const bool overriden{ present && *curves.get( n ) }; + + if ( overriden ) { + PushItemFlag( ImGuiItemFlags_Disabled , true ); + PushStyleVar( ImGuiStyleVar_Alpha , + GetStyle( ).Alpha * .5f ); + } + + bool select{ present }; + stringBuffer.clear( ) << n << '\0'; + if ( Checkbox( stringBuffer.data( ) , &select ) ) { + if ( select ) { + curves.add( n , false ); + } else { + curves.remove( n ); + } + } + + if ( overriden ) { + PopItemFlag( ); + PopStyleVar( ); + } + } + ImGui::EndChild( ); +} + } // namespace /*= T_SyncView =================================================================*/