From cb4849d89ea800446d9cb7c6ca14c42b3dd009ec Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Tue, 21 Nov 2017 12:27:23 +0100
Subject: [PATCH] Sequencer - Computation for the display

Various metrics to use along with zoom levels and all that shit. Mostly
useless for now, except for a moving cursor.
---
 syncview.cc | 74 ++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 65 insertions(+), 9 deletions(-)

diff --git a/syncview.cc b/syncview.cc
index 4b0beec..b3cf1e7 100644
--- a/syncview.cc
+++ b/syncview.cc
@@ -15,7 +15,7 @@ namespace {
 struct T_SyncViewImpl_
 {
 	static constexpr float SeqHeaderHeight = 24;
-	static constexpr float MinUnitWidth = 80;
+	static constexpr float BarWidth = 40;
 
 	const uint32_t ColFrame{ ImGui::GetColorU32( ImVec4{ 0 , 0 , 0 , .8 } ) };
 	const uint32_t ColHeader{ ImGui::GetColorU32( ImVec4{ .5 , .5 , .5 , .8 } ) };
@@ -23,10 +23,13 @@ struct T_SyncViewImpl_
 	const uint32_t ColMain{ ImGui::GetColorU32( ImVec4{ .4 , .4 , .4 , .8 } ) };
 
 	float zoomLevel{ 1.f };
+	float startPos{ 100.895f };
+	bool followTime{ true };
 
 	bool display( ) noexcept;
 	void sequencerWidget( ) noexcept;
 	void sequencerHeader( ImRect const& bb ) noexcept;
+	void sequencerBody( ImRect const& bb ) noexcept;
 };
 
 
@@ -47,6 +50,11 @@ bool T_SyncViewImpl_::display( ) noexcept
 		return false;
 	}
 
+	PushItemWidth( 100 );
+	SliderFloat( "Zoom" , &zoomLevel , 0 , 1 , "%.2f" );
+	PopItemWidth( );
+	SameLine( );
+
 	PushID( "playing" );
 	if ( Button( sync.playing( ) ? "Stop" : "Play" ) ) {
 		sync.playing( ) = !sync.playing( ) && !sync.finished( );
@@ -109,18 +117,51 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
 	 */
 
 	auto& sync( Globals::Sync( ) );
+	const float innerWidth{ width - 2 };
 	const uint32_t units{ sync.durationUnits( ) };
-	const float maxZoomUnits{ width / MinUnitWidth };
-	const float slope{ maxZoomUnits - units };
-	const float dUnits{ units + zoomLevel * slope };
-printf( "%d units ; %f/screen at max zoom ; slope %f ; display %f units at ZL %f\n" , units , maxZoomUnits , slope , dUnits , zoomLevel );
+	zoomLevel = ImSaturate( zoomLevel );
+	const float zoom1Pixels{ std::max( units * BarWidth , innerWidth ) };
+	const float totalPixels{ zoomLevel * ( zoom1Pixels - innerWidth ) + innerWidth };
+	const uint32_t totalBars{ [=](){
+			const float b{ std::max( std::min( totalPixels / BarWidth , float( units ) ) , 1.f ) };
+			const float mod{ fmod( b , 1.f ) };
+			return uint32_t( b + ( mod ? ( 1  - mod ) : 0 ) );
+		}() };
+	const float unitsPerBar{ float( units ) / totalBars };
+	const float barWidth{ totalPixels / totalBars };
+	const float absCursorPos{ sync.time( ) * totalPixels / sync.duration( ) };
+	if ( followTime ) {
+		const float dispUnits{ innerWidth * units / totalPixels };
+		const float uSize{ sync.durationUnitSize( ) };
+		const float endPos{ std::min( startPos + dispUnits , float( units ) ) };
+		startPos = endPos - dispUnits;
+		const float spp{ startPos * totalPixels / units };
+		const float epp{ endPos * totalPixels / units };
+		if ( absCursorPos < spp || absCursorPos > epp ) {
+			startPos = std::max( 0.f , sync.time( ) / uSize - unitsPerBar * .5f );
+		}
+	}
+	const float unadjustedStartPixel{ totalPixels * startPos / units };
+	if ( unadjustedStartPixel + innerWidth > totalPixels ) {
+		startPos = std::max( 0.f , totalPixels - innerWidth );
+	}
+	const float startPixel{ totalPixels * startPos / units };
+	const uint32_t startBar{ [=](){
+			const float b{ startPixel * totalBars / totalPixels };
+			const float mod{ fmod( b , 1.f ) };
+			return uint32_t( std::max( 0 , int32_t( b - ( mod ? mod : 1 ) ) ) );
+		}() };
+	const float startBarPos{ startBar * barWidth - startPixel };
+	const float cursorPos{ absCursorPos - startPixel };
+	printf( "Z: %f; P@zl1: %f; Pt: %f; Bt: %d; U/B: %f; Bw: %f; Sp: %f; Sb: %d, SbP: %f\n" , zoomLevel , zoom1Pixels , totalPixels , totalBars , unitsPerBar , barWidth , startPixel , startBar , startBarPos );
+	assert( startBarPos <= 0 );
+	assert( totalPixels >= innerWidth );
 
 	PushID( seqId );
 	BeginGroup( );
 
 	const auto hdrId{ win->GetID( "##header" ) };
 	const auto dspId{ win->GetID( "##display" ) };
-	auto* const dl( GetWindowDrawList( ) );
 
 	if ( ItemAdd( bbHeader , hdrId ) ) {
 		PushID( hdrId );
@@ -128,9 +169,15 @@ printf( "%d units ; %f/screen at max zoom ; slope %f ; display %f units at ZL %f
 		PopID( );
 	}
 	if ( bbDisplay.Min.y < bbDisplay.Max.y && ItemAdd( bbDisplay , dspId ) ) {
-		// XXX display main area
-		dl->AddRectFilled( bbDisplay.Min , bbDisplay.Max ,
-				ImGui::GetColorU32( ImVec4( .4 , .4 , .4 , .8 ) ) );
+		PushID( dspId );
+		sequencerBody( bbDisplay );
+		PopID( );
+	}
+	if ( cursorPos >= 0 && cursorPos <= width ) {
+		auto* const dl( GetWindowDrawList( ) );
+		dl->AddLine( bbAll.Min + ImVec2{ cursorPos + 1 , 0 } ,
+				ImVec2{ bbAll.Min.x + cursorPos + 1 , bbAll.Max.y } ,
+				0xffffffff );
 	}
 
 	EndGroup( );
@@ -156,6 +203,15 @@ void T_SyncViewImpl_::sequencerHeader(
 	PopFont( );
 }
 
+void T_SyncViewImpl_::sequencerBody(
+		ImRect const& bb ) noexcept
+{
+	using namespace ImGui;
+	auto* const dl( GetWindowDrawList( ) );
+
+	dl->AddRectFilled( bb.Min , bb.Max , ColMain );
+}
+
 
 } // namespace
 /*= T_SyncView =================================================================*/