diff --git a/ui-overrides.cc b/ui-overrides.cc
index 2f587af..24fc29b 100644
--- a/ui-overrides.cc
+++ b/ui-overrides.cc
@@ -35,11 +35,15 @@ M_DECL_SOVUI( Float )
 	using namespace ImGui;
 	auto& ov{ dynamic_cast< T_Float& >( ovp ) };
 	char const* const label( BuildLabel_( counter , sb ) );
+	float v{ data[ 0 ] };
 	const bool changed( ov.slider( )
-			? SliderFloat( label , &data[ 0 ] , ov.min( ) , ov.max( ) ,
+			? SliderFloat( label , &v , ov.min( ) , ov.max( ) ,
 				ov.decimals( ) , ov.power( ) )
-			: DragFloat( label , &data[ 0 ] , ov.step( ) , ov.min( ) ,
+			: DragFloat( label , &v , ov.step( ) , ov.min( ) ,
 				ov.max( ) , ov.decimals( ) , ov.power( ) ) );
+	if ( changed ) {
+		data.set( 0 , v );
+	}
 	return changed;
 }
 
@@ -60,7 +64,7 @@ M_DECL_SOVUI( Float2 )
 				ov.max( ) , ov.decimals( ) , ov.power( ) ) );
 	if ( changed ) {
 		for ( auto i = 0 ; i < 2 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i , v[ i ] );
 		}
 	}
 	return changed;
@@ -83,7 +87,7 @@ M_DECL_SOVUI( Float3 )
 				ov.max( ) , ov.decimals( ) , ov.power( ) ) );
 	if ( changed ) {
 		for ( auto i = 0 ; i < 3 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i ,v[ i ]);
 		}
 	}
 	return changed;
@@ -106,7 +110,7 @@ M_DECL_SOVUI( Float4 )
 				ov.max( ) , ov.decimals( ) , ov.power( ) ) );
 	if ( changed ) {
 		for ( auto i = 0 ; i < 4 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i ,v[ i ]);
 		}
 	}
 	return changed;
@@ -126,7 +130,7 @@ M_DECL_SOVUI( Integer )
 			? SliderInt( label , &v , ov.min( ) , ov.max( ) )
 			: DragInt( label , &v , ov.step( ) , ov.min( ) , ov.max( ) ) );
 	if ( changed ) {
-		data[ 0 ] = v;
+		data.set( 0 ,v);
 	}
 	return changed;
 }
@@ -146,7 +150,7 @@ M_DECL_SOVUI( Integer2 )
 			: DragInt2( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) );
 	if ( changed ) {
 		for ( auto i = 0 ; i < 2 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i ,v[ i ]);
 		}
 	}
 	return changed;
@@ -167,7 +171,7 @@ M_DECL_SOVUI( Integer3 )
 			: DragInt3( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) );
 	if ( changed ) {
 		for ( auto i = 0 ; i < 3 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i ,v[ i ]);
 		}
 	}
 	return changed;
@@ -188,7 +192,7 @@ M_DECL_SOVUI( Integer4 )
 			: DragInt4( label , v , ov.step( ) , ov.min( ) , ov.max( ) ) );
 	if ( changed ) {
 		for ( auto i = 0 ; i < 4 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i ,v[ i ]);
 		}
 	}
 	return changed;
@@ -214,7 +218,7 @@ M_DECL_SOVUI( ColorGrading )
 
 	if ( changed ) {
 		for ( auto i = 0 ; i < 3 ; i ++ ) {
-			data[ i ] = v[ i ];
+			data.set( i ,v[ i ]);
 		}
 	}
 	return changed;
@@ -237,9 +241,9 @@ void InputsFromVector_(
 		A_SyncData& data ,
 		glm::vec3 const& v ) noexcept
 {
-	data[ vc.x ] = v.x;
-	data[ vc.y ] = v.y;
-	data[ vc.z ] = v.z;
+	data.set( vc.x ,v.x);
+	data.set( vc.y ,v.y);
+	data.set( vc.z ,v.z);
 }
 
 /*------------------------------------------------------------------------------*/
@@ -285,7 +289,7 @@ void T_MouseCam_::handleDragAndDrop(
 	InputsFromVector_( ov.target( ) , *data , cam.lookAt( ) );
 	if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) {
 		InputsFromVector_( ov.angles( ) , *data , cam.angles( ) );
-		(*data)[ ov.distance( ) ] = cam.distance( );
+		data->set( ov.distance( ) ,cam.distance( ));
 	} else {
 		InputsFromVector_( ov.position( ) , *data , cam.position( ) );
 		InputsFromVector_( ov.up( ) , *data , cam.upVector( ) );
@@ -308,15 +312,15 @@ void T_MouseCam_::handleWheel(
 	if ( modifiers & E_KbdMod::SHIFT ) {
 		auto const& fc( ov.fovConfig( ) );
 		if ( fc.mode == T_CamOverride::FM_FOV ) {
-			(*data)[ fc.inputIndex ] = cam.fieldOfView( );
+			data->set( fc.inputIndex ,cam.fieldOfView( ));
 		} else {
-			(*data)[ fc.inputIndex ] = cam.nearPlane( );
+			data->set( fc.inputIndex ,cam.nearPlane( ));
 		}
 	} else {
 		InputsFromVector_( ov.target( ) , *data , cam.lookAt( ) );
 		if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) {
 			InputsFromVector_( ov.angles( ) , *data , cam.angles( ) );
-			(*data)[ ov.distance( ) ] = cam.distance( );
+			data->set( ov.distance( ) ,cam.distance( ));
 		} else {
 			InputsFromVector_( ov.position( ) , *data , cam.position( ) );
 			InputsFromVector_( ov.up( ) , *data , cam.upVector( ) );
@@ -383,16 +387,16 @@ M_DECL_SOVUI( Camera )
 	// Update values
 	if ( changes & E_CameraChange::FOV ) {
 		if ( fc.mode == T_CamOverride::FM_FOV ) {
-			data[ fc.inputIndex ]  = camera.fieldOfView( );
+			data.set( fc.inputIndex ,camera.fieldOfView( ));
 		} else {
-			data[ fc.inputIndex ]  = camera.nearPlane( );
+			data.set( fc.inputIndex ,camera.nearPlane( ));
 		}
 	}
 	if ( changes & E_CameraChange::MATRIX ) {
 		InputsFromVector_( ov.target( ) , data , camera.lookAt( ) );
 		if ( ov.mode( ) == T_CamOverride::CM_ANGLES ) {
 			InputsFromVector_( ov.angles( ) , data , camera.angles( ) );
-			data[ ov.distance( ) ]  = camera.distance( );
+			data.set( ov.distance( ) ,camera.distance( ));
 		} else {
 			InputsFromVector_( ov.position( ) , data , camera.position( ) );
 			InputsFromVector_( ov.up( ) , data , camera.upVector( ) );
diff --git a/ui-overrides.hh b/ui-overrides.hh
index 1d0edbc..68b9fc0 100644
--- a/ui-overrides.hh
+++ b/ui-overrides.hh
@@ -15,7 +15,8 @@ namespace sov {
 		virtual ~A_SyncData( ) = 0;
 
 		virtual float operator[]( uint32_t index ) const noexcept = 0;
-		virtual float& operator[]( uint32_t index ) noexcept = 0;
+		virtual bool set( uint32_t index ,
+				float value ) noexcept = 0;
 
 		virtual T_OwnPtr< A_SyncData > clone( ) const noexcept = 0;
 	};
diff --git a/ui-sequencer.cc b/ui-sequencer.cc
index 8c7c1e6..6ce193c 100644
--- a/ui-sequencer.cc
+++ b/ui-sequencer.cc
@@ -6,7 +6,9 @@
 
 #include "ui.hh"
 #include "ui-app.hh"
+#include "ui-overrides.hh"
 #include "ui-sequencer.hh"
+#include "ui-sync.hh"
 #include "ui-utilities.hh"
 
 #include "ui-imgui-sdl.hh"
@@ -145,6 +147,114 @@ bool T_ChangeDurationDialog_::onButton(
 }
 
 
+/*= T_PointData_ =============================================================*/
+
+using T_TempCurveStorage_ = T_AutoArray< T_SyncCurve , 16 >;
+
+class T_PointData_ : public sov::A_SyncData
+{
+    private:
+	T_Optional< T_SyncTrackId > const& selId_;
+	T_Optional< uint32_t > const& selSegment_;
+	T_Optional< uint32_t > const& selPoint_;
+	T_TempCurveStorage_& cOriginals_;
+	T_TempCurveStorage_& cCopies_;
+
+	T_String useId_;
+	uint32_t useSegment_;
+	uint32_t usePoint_;
+
+	A_SyncOverride* ovr_;
+
+    public:
+	T_PointData_( T_Optional< T_SyncTrackId > const& selId ,
+			T_Optional< uint32_t > const& selSegment ,
+			T_Optional< uint32_t > const& selPoint ,
+			T_TempCurveStorage_& cOriginals ,
+			T_TempCurveStorage_& cCopies ) noexcept
+		: selId_( selId ) , selSegment_( selSegment ) ,
+			selPoint_( selPoint ) , cOriginals_( cOriginals ) ,
+			cCopies_( cCopies )
+	{ }
+
+	void use( ) 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_PointData_::use( ) noexcept
+{
+	assert( selId_ && selSegment_ && selPoint_ );
+	assert( selId_->isOverride );
+
+	useId_ = selId_->id;
+	useSegment_ = *selSegment_;
+	usePoint_ = *selPoint_;
+	ovr_ = Common::Sync( ).getOverride( useId_ );
+}
+
+float T_PointData_::operator[](
+		const uint32_t index ) const noexcept
+{
+	if ( !( selId_ && selSegment_ && selPoint_ && selId_->isOverride )
+			|| useId_ != selId_->id || useSegment_ != *selSegment_
+			|| usePoint_ != *selPoint_ ) {
+		return 0.f;
+	}
+
+	auto const& iNames{ ovr_->inputNames( ) };
+	if ( cCopies_.size( ) != iNames.size( )
+			|| cCopies_[ 0 ].name != iNames[ 0 ] ) {
+		auto const& curve{ *Common::Sync( ).getCurve( iNames[ index ] ) };
+		return curve.segments[ useSegment_ ].values[ usePoint_ ];
+	}
+	return cCopies_[ index ].segments[ useSegment_ ].values[ usePoint_ ];
+}
+
+bool T_PointData_::set(
+		const uint32_t index ,
+		const float value ) noexcept
+{
+	if ( !( selId_ && selSegment_ && selPoint_ && selId_->isOverride )
+			|| useId_ != selId_->id || useSegment_ != *selSegment_
+			|| usePoint_ != *selPoint_ ) {
+		return false;
+	}
+
+	auto const& iNames{ ovr_->inputNames( ) };
+	const auto nn{ iNames.size( ) };
+	auto& sync{ Common::Sync( ) };
+	if ( cCopies_.size( ) != nn || cCopies_[ 0 ].name != iNames[ 0 ] ) {
+		cOriginals_.clear( );
+		cCopies_.clear( );
+		for ( auto i = 0u ; i < nn ; i ++ ) {
+			auto const* const c{ sync.getCurve( iNames[ i ] ) };
+			cOriginals_.add( *c );
+			cCopies_.add( *c );
+		}
+	}
+
+	cCopies_[ index ].segments[ useSegment_ ].values[ usePoint_ ] = value;
+	sync.setCurve( cCopies_[ index ] );
+	return true;
+}
+
+T_OwnPtr< sov::A_SyncData > T_PointData_::clone( ) const noexcept
+{
+	auto ptr{ NewOwned< T_PointData_ >( selId_ , selSegment_ ,
+			selPoint_ , cOriginals_ , cCopies_ ) };
+	ptr->useId_ = useId_;
+	ptr->useSegment_ = useSegment_;
+	ptr->usePoint_ = usePoint_;
+	return ptr;
+}
+
+
 /*= T_SyncViewImpl_ ==========================================================*/
 
 struct T_SyncViewImpl_
@@ -322,8 +432,12 @@ struct T_SyncViewImpl_
 
 	// Original and copy of curve being modified
 	E_ChangeType selUpdate{ E_ChangeType::NONE };
-	T_AutoArray< T_SyncCurve , 16 > selUpdatingOriginals;
-	T_AutoArray< T_SyncCurve , 16 > selUpdatingCopies;
+	T_TempCurveStorage_ selUpdatingOriginals;
+	T_TempCurveStorage_ selUpdatingCopies;
+
+	// Override edition
+	T_PointData_ selEditor{ selId , selSegment , selPoint ,
+		selUpdatingOriginals , selUpdatingCopies };
 
 	// Sub-windows
 	E_SubWindow sub{ SW_NONE };
@@ -1867,7 +1981,7 @@ void T_SyncViewImpl_::displayPointWindow( ) noexcept
 	const uint32_t sid{ *selSegment };
 	const uint32_t pid{ *selPoint };
 	auto& sync{ Common::Sync( ) };
-	auto const* const ovr{ selId->isOverride
+	auto* const ovr{ selId->isOverride
 		? sync.getOverride( selId->id )
 		: nullptr };
 	auto const* const curve{ selUpdatingCopies.size( )
@@ -1927,26 +2041,33 @@ void T_SyncViewImpl_::displayPointWindow( ) noexcept
 
 	Separator( );
 
+	// This is here because the curve pointer might get fucked over by
+	// the override control
+	const auto canInsertBefore{ pid != 0
+		&& segment.durations[ pid - 1 ] > 1 };
+	const auto canInsertAfter{ pid != segment.durations.size( )
+		&& segment.durations[ pid ] > 1 };
+	const auto canDelete{ pid != 0 && pid != segment.durations.size( ) };
+
 	bool changed;
-	float value{ segment.values[ pid ] };
+	float value{ 0 };
 	if ( ovr ) {
-		// XXX override control
-		changed = false;
+		selEditor.use( );
+		uint32_t i{ 0 };
+		changed = (UI::Sync( ).uiFor( *ovr ))(
+				*ovr , selEditor , i , stringBuffer );
 	} else {
 		Text( "Value:" );
 		SameLine( 110 );
 		PushItemWidth( -1 );
+		value = segment.values[ pid ];
 		DragFloat( "##value" , &value , .01f , 0 , 0 , "%.6f" );
 		changed = IsItemActive( );
 		PopItemWidth( );
 	}
 
 	const bool canUseButtons{ !changed && selUpdate == E_ChangeType::NONE };
-	const auto canInsertBefore{ pid != 0
-		&& segment.durations[ pid - 1 ] > 1 };
-	const auto canInsertAfter{ pid != segment.durations.size( )
-		&& segment.durations[ pid ] > 1 };
-	if ( pid != 0 && pid != segment.durations.size( ) ) {
+	if ( canDelete ) {
 		Separator( );
 		Text( " " );
 		SameLine( 110 );
@@ -1976,8 +2097,17 @@ void T_SyncViewImpl_::displayPointWindow( ) noexcept
 		}
 	}
 
-	if ( changed ) {
+	if ( ovr && changed ) {
 		if ( selUpdate == E_ChangeType::NONE ) {
+			selUpdate = E_ChangeType::POINT_VALUE;
+		} else {
+			assert( selUpdate == E_ChangeType::POINT_VALUE );
+		}
+
+	} else if ( changed ) {
+		if ( selUpdate == E_ChangeType::NONE ) {
+			assert( selUpdatingOriginals.empty( ) );
+			assert( selUpdatingCopies.empty( ) );
 			selUpdatingOriginals.add( *curve );
 			selUpdatingCopies.add( *curve );
 			selUpdate = E_ChangeType::POINT_VALUE;
@@ -1986,10 +2116,15 @@ void T_SyncViewImpl_::displayPointWindow( ) noexcept
 		}
 		selUpdatingCopies[ 0 ].segments[ sid ].values[ pid ] = value;
 		sync.setCurve( selUpdatingCopies[ 0 ] );
+
 	} else if ( selUpdate == E_ChangeType::POINT_VALUE ) {
 		selUpdate = E_ChangeType::NONE;
-		sync.setCurve( selUpdatingOriginals[ 0 ] );
-		SyncEditor::ReplaceCurve( std::move( selUpdatingCopies[ 0 ] ) );
+		auto& undo{ dynamic_cast< T_UndoSyncChanges& >(
+				Common::Undo( ).add< T_UndoSyncChanges >( ) ) };
+		for ( auto i = 0u ; i < selUpdatingCopies.size( ) ; i ++ ) {
+			undo.curveReplacement( std::move( selUpdatingOriginals[ i ] ) ,
+					std::move( selUpdatingCopies[ i ] ) );
+		}
 		selUpdatingCopies.clear( );
 		selUpdatingOriginals.clear( );
 	}
diff --git a/ui-sync.cc b/ui-sync.cc
index 113035a..a58547a 100644
--- a/ui-sync.cc
+++ b/ui-sync.cc
@@ -20,7 +20,7 @@ class T_SyncInputData_ : public sov::A_SyncData
 	void setFromOverride( A_SyncOverride const& sov ) noexcept;
 
 	float operator[]( uint32_t index ) const noexcept override;
-	float& operator[]( uint32_t index ) noexcept override;
+	bool set( uint32_t index , float value ) noexcept override;
 
 	T_OwnPtr< sov::A_SyncData > clone( ) const noexcept override;
 };
@@ -46,10 +46,12 @@ float T_SyncInputData_::operator[](
 	return *ptr_[ index ];
 }
 
-float& T_SyncInputData_::operator[](
-		const uint32_t index ) noexcept
+bool T_SyncInputData_::set(
+		const uint32_t index ,
+		const float value ) noexcept
 {
-	return *ptr_[ index ];
+	*ptr_[ index ] = value;
+	return true;
 }
 
 T_OwnPtr< sov::A_SyncData > T_SyncInputData_::clone( ) const noexcept
@@ -182,6 +184,7 @@ T_UISync::F_Override T_UISync::uiFor(
 	return rv ? *rv : []( A_SyncOverride& , sov::A_SyncData& ,
 			uint32_t& , T_StringBuilder& ) {
 		ImGui::Text( "(missing UI)" );
+		return false;
 	};
 }
 
diff --git a/ui-sync.hh b/ui-sync.hh
index da1dff2..19c6dcb 100644
--- a/ui-sync.hh
+++ b/ui-sync.hh
@@ -18,7 +18,7 @@ class T_UISync : public A_MouseCtrl
 	void makeOverridesWindow( );
 
 	using F_Override = std::function<
-		void( A_SyncOverride& , sov::A_SyncData& , uint32_t& ,
+		bool( A_SyncOverride& , sov::A_SyncData& , uint32_t& ,
 				T_StringBuilder& ) >;
 
 	F_Override uiFor( A_SyncOverride& target ) const noexcept;