From 2cfc80a6e437400b289cd5e833861af105320781 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= Date: Sat, 25 Nov 2017 16:30:46 +0100 Subject: [PATCH] Sequencer - Very primitive track display There are pieces of disabled mouse handling code in the display code. --- ui-sequencer.cc | 218 +++++++++++++++++++++++++++++++++++++++++++----- ui-utilities.cc | 14 ++++ ui-utilities.hh | 8 ++ 3 files changed, 220 insertions(+), 20 deletions(-) diff --git a/ui-sequencer.cc b/ui-sequencer.cc index 4888278..ce24036 100644 --- a/ui-sequencer.cc +++ b/ui-sequencer.cc @@ -135,8 +135,10 @@ bool T_ChangeDurationDialog_::onButton( struct T_SyncViewImpl_ { - static constexpr float SeqHeaderHeight = 24; - static constexpr float BarWidth = 40; + static constexpr float SeqHeaderHeight = 24.f; + static constexpr float BarWidth = 40.f; + static constexpr float TrackHeight = 15.f; + static constexpr float TrackPadding = 2.f; bool display( ) noexcept; @@ -148,9 +150,17 @@ struct T_SyncViewImpl_ void computeMetrics( float innerWidth ) noexcept; void sequencerWidget( ) noexcept; void sequencerHeader( ImRect const& bb ) noexcept; - void sequencerBody( ImRect const& bb ) noexcept; - void sequencerCurves( ) noexcept; - void sequencerCurve( T_SyncCurve const& curve ) noexcept; + bool sequencerBody( ImRect const& bb ) noexcept; + bool sequencerTracks( + float& hue , + ImRect& bb , + ImRect const& container ) noexcept; + bool sequencerTrack( + float& hue , + ImRect const& bb , + ImRect const& container , + T_String const& name , + T_SyncCurve const* curve ) noexcept; void displayCurveSelectorWindow( ) noexcept; void displayCurveSelector( ) noexcept; @@ -225,12 +235,9 @@ bool T_SyncViewImpl_::display( ) noexcept //---------------------------------------------------------------------- // Sequencer widget & subwindows - BeginChild( "##sequencer" , ImVec2{ 0 , 0 } , false , - ImGuiWindowFlags_NoScrollWithMouse ); PushItemWidth( -1 ); sequencerWidget( ); PopItemWidth( ); - EndChild( ); End( ); switch ( sub ) { @@ -380,12 +387,17 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept sequencerHeader( bbHeader ); PopID( ); } + bool mouseConsumed{ false }; if ( bbDisplay.Min.y < bbDisplay.Max.y && ItemAdd( bbDisplay , dspId ) ) { PushID( dspId ); - sequencerBody( bbDisplay ); + mouseConsumed = sequencerBody( bbDisplay ); PopID( ); } PopID( ); + if ( mouseConsumed ) { + EndGroup( ); + return; + } auto& io( GetIO( ) ); if ( hovered && ( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) ) { @@ -528,7 +540,7 @@ void T_SyncViewImpl_::sequencerHeader( PopFont( ); } -void T_SyncViewImpl_::sequencerBody( +bool T_SyncViewImpl_::sequencerBody( ImRect const& bb ) noexcept { using namespace ImGui; @@ -562,11 +574,18 @@ void T_SyncViewImpl_::sequencerBody( } // Display the curve / override controls + bool mouseConsumed{ false }; if ( sCurves.size( ) != 0 ) { - BeginGroup( ); + + ImRect subBb{ inner }; + // FIXME scroll + subBb.Min.y += TrackPadding; + subBb.Max.y = subBb.Min.y + TrackHeight; + + float hue{ 0.12f }; + // TODO: display overrides - sequencerCurves( ); - EndGroup( ); + mouseConsumed = sequencerTracks( hue , subBb , inner ) || mouseConsumed; } if ( cursorPos >= 0 && cursorPos <= inner.GetWidth( ) ) { @@ -575,26 +594,185 @@ void T_SyncViewImpl_::sequencerBody( ImVec2{ inner.Min.x + cursorPos , inner.Max.y - 1 } , 0xffffffff ); } + + return mouseConsumed; } -void T_SyncViewImpl_::sequencerCurves( ) noexcept +bool T_SyncViewImpl_::sequencerTracks( + float& hue , + ImRect& subBb , + ImRect const& container ) noexcept { auto& sync{ Common::Sync( ) }; const auto nc{ sCurves.size( ) }; + bool mouseConsumed{ false }; for ( auto i = 0u ; i < nc ; i ++ ) { if ( sCurves.values( )[ i ] ) { continue; } - auto* const curve{ sync.getCurve( sCurves.keys( )[ i ] ) }; - assert( curve ); - sequencerCurve( *curve ); + + auto const& name{ sCurves.keys( )[ i ] }; + auto* const curve{ sync.getCurve( name ) }; + mouseConsumed = sequencerTrack( hue , subBb , container , name , curve ) + || mouseConsumed; + subBb.Min.y += TrackHeight + 2 * TrackPadding; + subBb.Max.y += TrackHeight + 2 * TrackPadding; + hue = fmodf( hue + .17f , 1.f ); } + return mouseConsumed; } -void T_SyncViewImpl_::sequencerCurve( - T_SyncCurve const& curve ) noexcept +bool T_SyncViewImpl_::sequencerTrack( + float& hue , + ImRect const& bb , + ImRect const& container , + T_String const& name , + T_SyncCurve const* curve ) noexcept { -#warning implement the fuck + using namespace ImGui; + if ( !container.Overlaps( bb ) ) { + return false; + } + auto* const dl{ GetWindowDrawList( ) }; + + // Compute colors + const auto bgColor{ ColorHSVAToU32( hue , .25f , 1.f , .25f ) } , + borderColor{ ColorHSVAToU32( hue , .12f , 1.f , 1.f ) }; + const uint32_t segColors[ 2 ] = { + ColorHSVAToU32( hue - .03f , .4f , 1.f , 1.f ) , + ColorHSVAToU32( hue + .03f , .4f , 1.f , 1.f ) , + }; + + // Draw the bar itself + const ImRect bar{ + ImVec2{ ImFloor( bb.Min.x ) , + ImFloor( ImMax( container.Min.y , bb.Min.y ) ) } , + ImVec2{ ImFloor( bb.Max.x ) - 1 , + ImFloor( ImMin( container.Max.y , bb.Max.y ) ) } + }; + dl->AddRectFilled( bar.Min , bar.Max , bgColor ); + if ( container.Contains( bb.GetTL( ) ) ) { + dl->AddLine( bar.GetTL( ) , bar.GetTR( ) , borderColor ); + } + if ( container.Contains( bb.GetBL( ) ) ) { + dl->AddLine( bar.GetBL( ) , bar.GetBR( ) , borderColor ); + } + // Left only has a border if this is the start + if ( startPos == 0.f ) { + dl->AddLine( bar.GetTL( ) , bar.GetBL( ) , borderColor ); + } + // Right has a border if the end is being displayed. + if ( startPixel + container.GetWidth( ) >= totalPixels ) { + dl->AddLine( bar.GetTR( ) , bar.GetBR( ) , borderColor ); + } + dl->PushClipRect( bar.Min , bar.Max ); + +#if 0 + // We'll need to display the right pop-up + auto& io( GetIO( ) ); + const auto mPos{ io.MousePos }; + bool mousePosUsed{ false } , mouseConsumed{ false }; +#endif + + // If there's a curve, go through all segments + const auto units{ Common::Sync( ).durationUnits( ) }; + const auto nSeg{ curve ? curve->segments.size( ) : 0u }; + uint32_t segStart{ 0 }; + for ( auto i = 0u ; i < nSeg ; i ++ ) { + const auto color{ segColors[ i % 2 ] }; + auto const& seg{ curve->segments[ i ] }; + const auto segDur{ [&](){ + auto t{ 0u }; + for ( auto d : seg.durations ) { + t += d; + } + return t; + }() }; + const float xStart{ ImFloor( container.Min.x + ( segStart - startPos ) * totalPixels / units ) }; + const float xEnd{ xStart + ImFloor( segDur * totalPixels / units ) }; + const ImRect segFull{ + ImVec2{ xStart , bar.Min.y + 1 } , + ImVec2{ xEnd , bar.Max.y } + }; + segStart += segDur; + if ( !segFull.Overlaps( bar ) ) { + continue; + } + + const ImRect segBar{ + ImVec2{ ImMax( bar.Min.x , segFull.Min.x ) , segFull.Min.y } , + ImVec2{ ImMin( bar.Max.x , segFull.Max.x ) , segFull.Max.y } + }; + dl->AddRectFilled( segBar.Min , segBar.Max , color ); + dl->PushClipRect( segBar.Min , segBar.Max ); + + const auto nd{ seg.durations.size( ) }; + const auto radius{ ( TrackHeight - 2.f ) * .5f }; + const auto ym{ bb.Min.y + radius + 1 }; + auto cDur{ 0 }; + for ( auto j = 0u ; j < nd + 1 ; j ++ ) { + const ImVec2 ctr{ + std::roundf( xStart + cDur * totalPixels / units ) , + ym + }; + dl->AddCircleFilled( ctr , radius , 0x7f000000 ); // XXX color +#if 0 + if ( ImLengthSqr( mPos - ctr ) <= radius * radius ) { + if ( ! mousePosUsed ) { + BeginTooltip( ); + stringBuffer.clear( ) << name << " (input)\nIn " + << seg.type << " segment\nAt " << segDur + << " units\nValue: " << seg.values[ j ]; + Text( "%s" , stringBuffer.data( ) ); + EndTooltip( ); + mousePosUsed = true; + } + if ( !mouseConsumed && io.MouseDown[ 0 ] ) { + printf( "fuck yeah!\n" ); + mouseConsumed = true; + } + } +#endif + cDur += j < nd ? seg.durations[ j ] : 0; + } + dl->PopClipRect( ); + +#if 0 + if ( segBar.Contains( mPos ) && !mousePosUsed ) { + BeginTooltip( ); + stringBuffer.clear( ) << name << " (input)\nIn " + << seg.type << " segment\nDuration: " + << segDur << " units (from " << ( segStart - segDur ) + << " to " << ( segStart - 1 ) + << ")\n"; + Text( "%s" , stringBuffer.data( ) ); + EndTooltip( ); + mousePosUsed = true; + } +#endif + } + +#if 0 + if ( bar.Contains( mPos ) && !mousePosUsed ) { + const float time{ ( io.MousePos.x - container.Min.x + startPixel ) + * units / totalPixels }; + const float msf{ fmod( time , 1.f ) }; + const float sf{ fmod( time - msf , 60.f ) }; + char buffer[ 12 ]; + snprintf( buffer , sizeof( buffer ) , "%02d:%02d.%03d" , + uint32_t( ( time - msf - sf ) / 60.f ) , + uint32_t( sf ) , uint32_t( msf * 1000.f ) ); + BeginTooltip( ); + stringBuffer.clear( ) << name << " (input)\nNot defined at " + << buffer << '\0'; + Text( "%s" , stringBuffer.data( ) ); + EndTooltip( ); + mousePosUsed = true; + } +#endif + dl->PopClipRect( ); + + return false; } /*----------------------------------------------------------------------------*/ diff --git a/ui-utilities.cc b/ui-utilities.cc index 16de7ed..db310e6 100644 --- a/ui-utilities.cc +++ b/ui-utilities.cc @@ -60,6 +60,20 @@ void ImGui::ToolbarSeparator( ) noexcept SameLine( ); } +/*------------------------------------------------------------------------------*/ + +uint32_t ImGui::ColorHSVAToU32( + float hue , + float saturation , + float value , + float alpha ) noexcept +{ + ImVec4 out{ 0, 0, 0, alpha }; + ColorConvertHSVtoRGB( hue , saturation , value , + out.x , out.y , out.z ); + return GetColorU32( out ); +} + /*= T_CameraMouseControl =======================================================*/ diff --git a/ui-utilities.hh b/ui-utilities.hh index e23a685..e4451a4 100644 --- a/ui-utilities.hh +++ b/ui-utilities.hh @@ -30,6 +30,14 @@ namespace ImGui { char const* const tooltip = nullptr , bool enabled = true ) noexcept; + /*--------------------------------------------------------------------*/ + + uint32_t ColorHSVAToU32( + float hue , + float saturation , + float value , + float alpha ) noexcept; + } // namespace ImGui /*----------------------------------------------------------------------------*/