From f9a0b940550f15fcfee6db0b398400d757b27c8a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Emmanuel=20Beno=C3=AEt?= <tseeker@nocternity.net>
Date: Wed, 22 Nov 2017 07:38:27 +0100
Subject: [PATCH] Sequencer - Overrides selector

---
 sync.cc     | 19 ++++++++++---
 sync.hh     | 20 +++++++++++++-
 syncview.cc | 77 ++++++++++++++++++++++++++++++++++++++++++++++++-----
 3 files changed, 106 insertions(+), 10 deletions(-)

diff --git a/sync.cc b/sync.cc
index 119061a..e0c23a2 100644
--- a/sync.cc
+++ b/sync.cc
@@ -381,13 +381,19 @@ void A_SyncOverride::setup( ) noexcept
 	assert( ni != 0 );
 	assert( inputPos_.size( ) == 0 );
 
+	T_StringBuilder sb;
 	inputPos_.ensureCapacity( ni );
 	for ( auto i = 0u ; i < ni ; i ++ ) {
 		// FIXME: insufficient; the manager should be made aware of
 		// the presence of an override for that value (and it should
 		// fail for missing values).
 		inputPos_.add( Globals::Sync( ).inputPos( inputs_[ i ] ) );
+		if ( sb.size( ) ) {
+			sb << ';';
+		}
+		sb << inputs_[ i ];
 	}
+	id_ = std::move( sb );
 }
 
 char const* A_SyncOverride::buildLabel(
@@ -676,6 +682,7 @@ void T_SyncManager::clearOverrides( ) noexcept
 	mouseDelegate_ = nullptr;
 	soRoot_.subsections.clear( );
 	soRoot_.overrides.clear( );
+	soTable_.clear( );
 }
 
 void T_SyncManager::mergeOverrides(
@@ -684,14 +691,14 @@ void T_SyncManager::mergeOverrides(
 	assert( overrides.overrides.empty( ) );
 	soRoot_.merge( overrides );
 
-	T_SyncOverrideVisitor v;
-	v.visitor.visit( &soRoot_ ,
-		[]( T_SyncOverrideVisitor::T_Element node , bool exit ) -> bool {
+	soVisitor_.visitor.visit( &soRoot_ ,
+		[this]( T_SyncOverrideVisitor::T_Element node , bool exit ) -> bool {
 			if ( exit || node.hasType< T_SyncOverrideSection* >( ) ) {
 				return true;
 			}
 			auto& ovr( *node.value< A_SyncOverride* >( ) );
 			ovr.setup( );
+			soTable_.add( ovr.id( ) , &ovr );
 			return false;
 		}
 	);
@@ -717,6 +724,12 @@ void T_SyncManager::setOverridesActive(
 	}
 }
 
+void T_SyncManager::visitOverrides(
+		T_SyncOverrideVisitor::F_NodeAction visitor )
+{
+	soVisitor_.visitor.visit( &soRoot_ , visitor );
+}
+
 /*------------------------------------------------------------------------------*/
 
 void T_SyncManager::makeOverridesWindow( )
diff --git a/sync.hh b/sync.hh
index 12e80b0..0bf4b0e 100644
--- a/sync.hh
+++ b/sync.hh
@@ -173,6 +173,7 @@ class A_SyncOverride
 	const T_String type_;
 	bool enabled_{ false };
 	ebcl::T_SRDLocation location_;
+	T_String id_;
 
     protected:
 	ebcl::T_Buffer< char > title_;
@@ -208,6 +209,11 @@ class A_SyncOverride
 	bool enabled( ) const noexcept
 		{ return enabled_; }
 
+	T_String const& id( ) const noexcept
+		{ return id_; }
+	char const* title( ) const noexcept
+		{ return &title_[ 0 ]; }
+
 	ebcl::T_SRDLocation& location( ) noexcept
 		{ return location_; }
 	ebcl::T_SRDLocation const& location( ) const noexcept
@@ -265,10 +271,12 @@ struct T_SyncOverrideVisitor
 		T_SyncOverrideSection* ,
 		A_SyncOverride* >;
 	using T_OpElement = T_Optional< T_Element >;
+	using T_Visitor = ebcl::T_Visitor< T_Element , T_Element >;
+	using F_NodeAction = T_Visitor::F_NodeAction;
 
 	static T_OpElement nodeBrowser( T_Element element , uint32_t child );
 
-	ebcl::T_Visitor< T_Element , T_Element > visitor{ nodeBrowser };
+	T_Visitor visitor{ nodeBrowser };
 };
 
 /*============================================================================*/
@@ -352,6 +360,9 @@ struct T_SyncManager : public virtual A_MouseCtrl
 			uint32_t n ,
 			uint32_t const* pos );
 
+	// Visit the overrides tree
+	void visitOverrides( T_SyncOverrideVisitor::F_NodeAction visitor );
+
 	// ---------------------------------------------------------------------
 	// Update
 
@@ -389,14 +400,21 @@ struct T_SyncManager : public virtual A_MouseCtrl
     private:
 	ebcl::T_SRDParserConfig pConfig_;		// Parser config for curves
 	P_WatchedFiles watcher_;			// Curves file watcher
+
 	T_SyncTime time_;				// Duration/time information
 	bool playing_{ false };				// Is it playing?
 	bool playingPrevious_{ false };			// Was it playing before?
 	float lastFrame_{ 0 };				// Time of last frame
+
 	T_SyncValues values_;				// Value storage
 	T_SyncCurves curves_;				// Curves storage
 	T_Array< P_SyncCurveCache > curveCaches_;	// Cache for curve segments
+
 	bool ovWindow_{ false };			// Overrides window
 	T_SyncOverrideSection soRoot_;			// Root for overrides
+	T_SyncOverrideVisitor soVisitor_;
+	T_KeyValueTable< T_String , A_SyncOverride* > soTable_;
+							// Table of sync overrides, by ID
+
 	A_MouseCtrl* mouseDelegate_{ nullptr };		// Delegate for mouse actions
 };
diff --git a/syncview.cc b/syncview.cc
index c6c5d9f..9aae7dc 100644
--- a/syncview.cc
+++ b/syncview.cc
@@ -60,6 +60,7 @@ struct T_SyncViewImpl_
 
 	void displayCurveSelectorWindow( ) noexcept;
 	void displayCurveSelector( ) noexcept;
+	void displayOverrideSelector( ) noexcept;
 
 	// Misc stuff
 	T_StringBuilder stringBuffer;	// XXX damn this shit to fucking hell
@@ -86,7 +87,8 @@ struct T_SyncViewImpl_
 		SW_OVERRIDE_SELECTOR ,
 	};
 	E_SubWindow sub{ SW_NONE };
-	T_KeyValueTable< T_String , bool > curves;
+	T_KeyValueTable< T_String , bool > sCurves;
+	T_Set< T_String > sOverrides;
 	T_String curveFinder;
 };
 
@@ -463,6 +465,7 @@ void T_SyncViewImpl_::displayCurveSelectorWindow( ) noexcept
 		displayCurveSelector( );
 		break;
 	    case SW_OVERRIDE_SELECTOR:
+		displayOverrideSelector( );
 		break;
 	    default:
 		fprintf( stderr , "unexpected bullshit in sync view\n" );
@@ -505,8 +508,8 @@ void T_SyncViewImpl_::displayCurveSelector( ) noexcept
 	// The list
 	ImGui::BeginChild( "content" );
 	for ( auto const& n : names ) {
-		const bool present{ curves.contains( n ) };
-		const bool overriden{ present && *curves.get( n ) };
+		const bool present{ sCurves.contains( n ) };
+		const bool overriden{ present && *sCurves.get( n ) };
 
 		if ( overriden ) {
 			PushItemFlag( ImGuiItemFlags_Disabled , true );
@@ -518,9 +521,9 @@ void T_SyncViewImpl_::displayCurveSelector( ) noexcept
 		stringBuffer.clear( ) << n << '\0';
 		if ( Checkbox( stringBuffer.data( ) , &select ) ) {
 			if ( select ) {
-				curves.add( n , false );
+				sCurves.add( n , false );
 			} else {
-				curves.remove( n );
+				sCurves.remove( n );
 			}
 		}
 
@@ -529,7 +532,69 @@ void T_SyncViewImpl_::displayCurveSelector( ) noexcept
 			PopStyleVar( );
 		}
 	}
-	ImGui::EndChild( );
+	EndChild( );
+}
+
+void T_SyncViewImpl_::displayOverrideSelector( ) noexcept
+{
+	using namespace ImGui;
+
+	BeginChild( "content" );
+	Globals::Sync( ).visitOverrides( [&]( T_SyncOverrideVisitor::T_Element element , const bool exit ) {
+		if ( element.hasType< T_SyncOverrideSection* >( ) ) {
+			auto const& sos{ *element.value< T_SyncOverrideSection* >( ) };
+			if ( sos.title == "*root*" ) {
+				return true;
+			}
+			if ( exit ) {
+				TreePop( );
+			} else {
+				return TreeNodeEx( &sos.cTitle[ 0 ] ,
+						ImGuiTreeNodeFlags_DefaultOpen );
+			}
+		} else if ( exit ) {
+			auto const& ov{ *element.value< A_SyncOverride* >( ) };
+			auto const& id{ ov.id( ) };
+			auto const& in{ ov.inputNames( ) };
+			const bool present{ sOverrides.contains( id ) };
+			const bool hasCurves{ !present && [&](){
+				for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
+					if ( sCurves.contains( in[ i ] ) ) {
+						return true;
+					}
+				}
+				return false;
+			}() };
+
+			if ( hasCurves ) {
+				PushItemFlag( ImGuiItemFlags_Disabled , true );
+				PushStyleVar( ImGuiStyleVar_Alpha ,
+						GetStyle( ).Alpha * .5f );
+			}
+
+			bool select{ present };
+			if ( Checkbox( ov.title( ) , &select ) ) {
+				if ( select ) {
+					sOverrides.add( id );
+					for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
+						sCurves.add( in[ i ] , true );
+					}
+				} else {
+					sOverrides.remove( id );
+					for ( auto i = 0u ; i < in.size( ) ; i ++ ) {
+						sCurves.remove( in[ i ] );
+					}
+				}
+			}
+
+			if ( hasCurves ) {
+				PopItemFlag( );
+				PopStyleVar( );
+			}
+		}
+		return true;
+	} );
+	EndChild( );
 }