Sequencer - Progress on track display
This commit is contained in:
parent
2cfc80a6e4
commit
c4d5bd3fd1
1 changed files with 287 additions and 133 deletions
420
ui-sequencer.cc
420
ui-sequencer.cc
|
@ -16,7 +16,7 @@ using namespace ebcl;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
/*= VARIOUS IMGUI HELPERS ====================================================*/
|
/*= VARIOUS HELPERS ==========================================================*/
|
||||||
|
|
||||||
bool FakeTab_(
|
bool FakeTab_(
|
||||||
char const* const name ,
|
char const* const name ,
|
||||||
|
@ -34,6 +34,18 @@ bool FakeTab_(
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TimeToString_(
|
||||||
|
char* const buffer ,
|
||||||
|
const size_t bSize ,
|
||||||
|
const float time ) noexcept
|
||||||
|
{
|
||||||
|
const float msf{ fmod( time , 1.f ) };
|
||||||
|
const float sf{ fmod( time - msf , 60.f ) };
|
||||||
|
snprintf( buffer , bSize , "%02d:%02d.%03d" ,
|
||||||
|
uint32_t( ( time - msf - sf ) / 60.f ) ,
|
||||||
|
uint32_t( sf ) , uint32_t( msf * 1000.f ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*= T_ChangeDurationDialog_ ==================================================*/
|
/*= T_ChangeDurationDialog_ ==================================================*/
|
||||||
|
|
||||||
|
@ -139,10 +151,62 @@ struct T_SyncViewImpl_
|
||||||
static constexpr float BarWidth = 40.f;
|
static constexpr float BarWidth = 40.f;
|
||||||
static constexpr float TrackHeight = 15.f;
|
static constexpr float TrackHeight = 15.f;
|
||||||
static constexpr float TrackPadding = 2.f;
|
static constexpr float TrackPadding = 2.f;
|
||||||
|
static constexpr float PointRadius = ( TrackHeight - 2.f ) * .5f;
|
||||||
|
static constexpr float PointRadiusSqr = PointRadius * PointRadius;
|
||||||
|
|
||||||
bool display( ) noexcept;
|
bool display( ) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Track display data
|
||||||
|
struct T_TrackDisplay
|
||||||
|
{
|
||||||
|
T_String id;
|
||||||
|
bool isOverride;
|
||||||
|
ImRect area;
|
||||||
|
uint32_t dispSegs;
|
||||||
|
uint32_t firstSeg;
|
||||||
|
};
|
||||||
|
struct T_TrackSegDisplay
|
||||||
|
{
|
||||||
|
uint32_t track;
|
||||||
|
uint32_t seg;
|
||||||
|
ImRect area;
|
||||||
|
uint32_t dispPoints;
|
||||||
|
uint32_t firstPoint;
|
||||||
|
};
|
||||||
|
struct T_TrackPointDisplay
|
||||||
|
{
|
||||||
|
uint32_t seg;
|
||||||
|
uint32_t index;
|
||||||
|
ImVec2 center;
|
||||||
|
enum {
|
||||||
|
START ,
|
||||||
|
MIDDLE ,
|
||||||
|
END
|
||||||
|
} mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Description for mouse locations in the sequencer window
|
||||||
|
enum class E_MousePosType
|
||||||
|
{
|
||||||
|
NONE ,
|
||||||
|
TRACK ,
|
||||||
|
SEGMENT ,
|
||||||
|
POINT
|
||||||
|
};
|
||||||
|
struct T_MousePos
|
||||||
|
{
|
||||||
|
E_MousePosType type;
|
||||||
|
uint32_t index;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Type of sub-windows
|
||||||
|
enum E_SubWindow {
|
||||||
|
SW_NONE ,
|
||||||
|
SW_CURVE_SELECTOR ,
|
||||||
|
SW_OVERRIDE_SELECTOR ,
|
||||||
|
};
|
||||||
|
|
||||||
// Make sure all displayed curves/inputs/overrides still exist
|
// Make sure all displayed curves/inputs/overrides still exist
|
||||||
void checkSelectedCurves( ) noexcept;
|
void checkSelectedCurves( ) noexcept;
|
||||||
void displayToolbar( ) noexcept;
|
void displayToolbar( ) noexcept;
|
||||||
|
@ -150,18 +214,23 @@ struct T_SyncViewImpl_
|
||||||
void computeMetrics( float innerWidth ) noexcept;
|
void computeMetrics( float innerWidth ) noexcept;
|
||||||
void sequencerWidget( ) noexcept;
|
void sequencerWidget( ) noexcept;
|
||||||
void sequencerHeader( ImRect const& bb ) noexcept;
|
void sequencerHeader( ImRect const& bb ) noexcept;
|
||||||
bool sequencerBody( ImRect const& bb ) noexcept;
|
void sequencerBody( ImRect const& bb ) noexcept;
|
||||||
bool sequencerTracks(
|
void sequencerTracks(
|
||||||
float& hue ,
|
float& hue ,
|
||||||
ImRect& bb ,
|
ImRect& bb ,
|
||||||
ImRect const& container ) noexcept;
|
ImRect const& container ) noexcept;
|
||||||
bool sequencerTrack(
|
void sequencerTrack(
|
||||||
float& hue ,
|
float& hue ,
|
||||||
ImRect const& bb ,
|
ImRect const& bb ,
|
||||||
ImRect const& container ,
|
ImRect const& container ,
|
||||||
T_String const& name ,
|
T_String const& name ,
|
||||||
T_SyncCurve const* curve ) noexcept;
|
T_SyncCurve const* curve ) noexcept;
|
||||||
|
|
||||||
|
void displayTooltips(
|
||||||
|
const float time ) noexcept;
|
||||||
|
|
||||||
|
T_MousePos getMousePos( ) const noexcept;
|
||||||
|
|
||||||
void displayCurveSelectorWindow( ) noexcept;
|
void displayCurveSelectorWindow( ) noexcept;
|
||||||
void displayCurveSelector( ) noexcept;
|
void displayCurveSelector( ) noexcept;
|
||||||
void displayOverrideSelector( ) noexcept;
|
void displayOverrideSelector( ) noexcept;
|
||||||
|
@ -191,19 +260,21 @@ struct T_SyncViewImpl_
|
||||||
float totalPixels;
|
float totalPixels;
|
||||||
float startPixel;
|
float startPixel;
|
||||||
|
|
||||||
|
// Track display
|
||||||
|
T_Array< T_TrackDisplay > dspTracks;
|
||||||
|
T_Array< T_TrackSegDisplay > dspSegments;
|
||||||
|
T_Array< T_TrackPointDisplay > dspPoints;
|
||||||
|
|
||||||
// Zoom area selection
|
// Zoom area selection
|
||||||
bool zoomInProgress{ false };
|
bool zoomInProgress{ false };
|
||||||
bool justZoomed{ false };
|
bool justZoomed{ false };
|
||||||
float firstZoomPixel;
|
float firstZoomPixel;
|
||||||
float curZoomPixel;
|
float curZoomPixel;
|
||||||
|
|
||||||
// Curve display / edition
|
// Sub-windows
|
||||||
enum E_SubWindow {
|
|
||||||
SW_NONE ,
|
|
||||||
SW_CURVE_SELECTOR ,
|
|
||||||
SW_OVERRIDE_SELECTOR ,
|
|
||||||
};
|
|
||||||
E_SubWindow sub{ SW_NONE };
|
E_SubWindow sub{ SW_NONE };
|
||||||
|
|
||||||
|
// Curve selection
|
||||||
T_KeyValueTable< T_String , bool > sCurves;
|
T_KeyValueTable< T_String , bool > sCurves;
|
||||||
T_Set< T_String > sOverrides;
|
T_Set< T_String > sOverrides;
|
||||||
T_String curveFinder;
|
T_String curveFinder;
|
||||||
|
@ -387,17 +458,13 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
||||||
sequencerHeader( bbHeader );
|
sequencerHeader( bbHeader );
|
||||||
PopID( );
|
PopID( );
|
||||||
}
|
}
|
||||||
bool mouseConsumed{ false };
|
|
||||||
if ( bbDisplay.Min.y < bbDisplay.Max.y && ItemAdd( bbDisplay , dspId ) ) {
|
if ( bbDisplay.Min.y < bbDisplay.Max.y && ItemAdd( bbDisplay , dspId ) ) {
|
||||||
PushID( dspId );
|
PushID( dspId );
|
||||||
mouseConsumed = sequencerBody( bbDisplay );
|
sequencerBody( bbDisplay );
|
||||||
PopID( );
|
PopID( );
|
||||||
}
|
}
|
||||||
PopID( );
|
PopID( );
|
||||||
if ( mouseConsumed ) {
|
EndGroup( );
|
||||||
EndGroup( );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& io( GetIO( ) );
|
auto& io( GetIO( ) );
|
||||||
if ( hovered && ( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) ) {
|
if ( hovered && ( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) ) {
|
||||||
|
@ -406,46 +473,56 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool active( GetCurrentContext( )->ActiveId == seqId );
|
const bool active( GetCurrentContext( )->ActiveId == seqId );
|
||||||
if ( hovered && !active && io.MouseWheel != 0 ) {
|
auto& sync( Common::Sync( ) );
|
||||||
zoomLevel = ImSaturate( zoomLevel + .025 * io.MouseWheel );
|
const float mPixels{ io.MousePos.x - bbAll.Min.x + startPixel };
|
||||||
} else if ( active ) {
|
const float mTime{ mPixels * sync.duration( ) / totalPixels };
|
||||||
if ( io.MouseDown[ 0 ] ) {
|
|
||||||
const float p{ io.MousePos.x - bbAll.Min.x + startPixel };
|
if ( !active ) {
|
||||||
auto& sync( Common::Sync( ) );
|
if ( !hovered ) {
|
||||||
sync.setTime( p * Common::Sync( ).duration( ) / totalPixels );
|
return;
|
||||||
}
|
}
|
||||||
if ( io.MouseDown[ 1 ] ) {
|
if ( io.MouseWheel != 0 ) {
|
||||||
const float p{ io.MousePos.x - bbAll.Min.x + startPixel };
|
zoomLevel = ImSaturate( zoomLevel + .025 * io.MouseWheel );
|
||||||
if ( !zoomInProgress ) {
|
|
||||||
firstZoomPixel = p;
|
|
||||||
zoomInProgress = true;
|
|
||||||
}
|
|
||||||
curZoomPixel = p;
|
|
||||||
} else if ( zoomInProgress ) {
|
|
||||||
zoomInProgress = false;
|
|
||||||
justZoomed = true;
|
|
||||||
const auto zMin{ std::min( firstZoomPixel , curZoomPixel ) } ,
|
|
||||||
zMax{ std::max( firstZoomPixel , curZoomPixel ) } ,
|
|
||||||
diff{ zMax - zMin };
|
|
||||||
if ( diff > 4 ) {
|
|
||||||
auto& sync( Common::Sync( ) );
|
|
||||||
const float u( sync.durationUnits( ) );
|
|
||||||
startPos = zMin * u / totalPixels;
|
|
||||||
if ( ( width - 2.f ) / u >= BarWidth ) {
|
|
||||||
zoomLevel = 0;
|
|
||||||
} else {
|
|
||||||
const auto length{ std::min( u , diff * u / totalPixels ) };
|
|
||||||
const auto ppu{ std::min( ( width - 2 ) / length , BarWidth ) };
|
|
||||||
zoomLevel = ( ppu - BarWidth ) / ( BarWidth - width / u ) + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if ( !( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) ) {
|
if ( bbDisplay.Contains( io.MousePos ) ) {
|
||||||
ClearActiveID( );
|
displayTooltips( mTime );
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( io.MouseDown[ 0 ] ) {
|
||||||
|
sync.setTime( mTime );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( io.MouseDown[ 1 ] ) {
|
||||||
|
if ( !zoomInProgress ) {
|
||||||
|
firstZoomPixel = mPixels;
|
||||||
|
zoomInProgress = true;
|
||||||
|
}
|
||||||
|
curZoomPixel = mPixels;
|
||||||
|
|
||||||
|
} else if ( zoomInProgress ) {
|
||||||
|
zoomInProgress = false;
|
||||||
|
justZoomed = true;
|
||||||
|
const auto zMin{ std::min( firstZoomPixel , curZoomPixel ) } ,
|
||||||
|
zMax{ std::max( firstZoomPixel , curZoomPixel ) } ,
|
||||||
|
diff{ zMax - zMin };
|
||||||
|
if ( diff > 4 ) {
|
||||||
|
const float u( sync.durationUnits( ) );
|
||||||
|
startPos = zMin * u / totalPixels;
|
||||||
|
if ( ( width - 2.f ) / u >= BarWidth ) {
|
||||||
|
zoomLevel = 0;
|
||||||
|
} else {
|
||||||
|
const auto length{ std::min( u , diff * u / totalPixels ) };
|
||||||
|
const auto ppu{ std::min( ( width - 2 ) / length , BarWidth ) };
|
||||||
|
zoomLevel = ( ppu - BarWidth ) / ( BarWidth - width / u ) + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EndGroup( );
|
if ( !( io.MouseDown[ 0 ] || io.MouseDown[ 1 ] ) ) {
|
||||||
|
ClearActiveID( );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void T_SyncViewImpl_::computeMetrics(
|
void T_SyncViewImpl_::computeMetrics(
|
||||||
|
@ -526,11 +603,7 @@ void T_SyncViewImpl_::sequencerHeader(
|
||||||
const ImVec2 taEnd{ taStart + ImVec2{ barWidth , inner.Max.y - inner.Min.y } };
|
const ImVec2 taEnd{ taStart + ImVec2{ barWidth , inner.Max.y - inner.Min.y } };
|
||||||
|
|
||||||
const float time{ bar * timePerBar };
|
const float time{ bar * timePerBar };
|
||||||
const float msf{ fmod( time , 1.f ) };
|
TimeToString_( buffer , sizeof( buffer ) , time );
|
||||||
const float sf{ fmod( time - msf , 60.f ) };
|
|
||||||
snprintf( buffer , sizeof( buffer ) , "%02d:%02d.%03d" ,
|
|
||||||
uint32_t( ( time - msf - sf ) / 60.f ) ,
|
|
||||||
uint32_t( sf ) , uint32_t( msf * 1000.f ) );
|
|
||||||
RenderTextClipped( taStart , taEnd , buffer , nullptr , nullptr ,
|
RenderTextClipped( taStart , taEnd , buffer , nullptr , nullptr ,
|
||||||
ImVec2{ .5f , .05f + ( ( bar % 2 ) ? .9f : 0.f ) } , &inner );
|
ImVec2{ .5f , .05f + ( ( bar % 2 ) ? .9f : 0.f ) } , &inner );
|
||||||
pos += barWidth;
|
pos += barWidth;
|
||||||
|
@ -540,7 +613,7 @@ void T_SyncViewImpl_::sequencerHeader(
|
||||||
PopFont( );
|
PopFont( );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool T_SyncViewImpl_::sequencerBody(
|
void T_SyncViewImpl_::sequencerBody(
|
||||||
ImRect const& bb ) noexcept
|
ImRect const& bb ) noexcept
|
||||||
{
|
{
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
|
@ -574,7 +647,6 @@ bool T_SyncViewImpl_::sequencerBody(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display the curve / override controls
|
// Display the curve / override controls
|
||||||
bool mouseConsumed{ false };
|
|
||||||
if ( sCurves.size( ) != 0 ) {
|
if ( sCurves.size( ) != 0 ) {
|
||||||
|
|
||||||
ImRect subBb{ inner };
|
ImRect subBb{ inner };
|
||||||
|
@ -585,7 +657,7 @@ bool T_SyncViewImpl_::sequencerBody(
|
||||||
float hue{ 0.12f };
|
float hue{ 0.12f };
|
||||||
|
|
||||||
// TODO: display overrides
|
// TODO: display overrides
|
||||||
mouseConsumed = sequencerTracks( hue , subBb , inner ) || mouseConsumed;
|
sequencerTracks( hue , subBb , inner );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( cursorPos >= 0 && cursorPos <= inner.GetWidth( ) ) {
|
if ( cursorPos >= 0 && cursorPos <= inner.GetWidth( ) ) {
|
||||||
|
@ -594,18 +666,14 @@ bool T_SyncViewImpl_::sequencerBody(
|
||||||
ImVec2{ inner.Min.x + cursorPos , inner.Max.y - 1 } ,
|
ImVec2{ inner.Min.x + cursorPos , inner.Max.y - 1 } ,
|
||||||
0xffffffff );
|
0xffffffff );
|
||||||
}
|
}
|
||||||
|
|
||||||
return mouseConsumed;
|
|
||||||
}
|
}
|
||||||
|
void T_SyncViewImpl_::sequencerTracks(
|
||||||
bool T_SyncViewImpl_::sequencerTracks(
|
|
||||||
float& hue ,
|
float& hue ,
|
||||||
ImRect& subBb ,
|
ImRect& subBb ,
|
||||||
ImRect const& container ) noexcept
|
ImRect const& container ) noexcept
|
||||||
{
|
{
|
||||||
auto& sync{ Common::Sync( ) };
|
auto& sync{ Common::Sync( ) };
|
||||||
const auto nc{ sCurves.size( ) };
|
const auto nc{ sCurves.size( ) };
|
||||||
bool mouseConsumed{ false };
|
|
||||||
for ( auto i = 0u ; i < nc ; i ++ ) {
|
for ( auto i = 0u ; i < nc ; i ++ ) {
|
||||||
if ( sCurves.values( )[ i ] ) {
|
if ( sCurves.values( )[ i ] ) {
|
||||||
continue;
|
continue;
|
||||||
|
@ -613,31 +681,38 @@ bool T_SyncViewImpl_::sequencerTracks(
|
||||||
|
|
||||||
auto const& name{ sCurves.keys( )[ i ] };
|
auto const& name{ sCurves.keys( )[ i ] };
|
||||||
auto* const curve{ sync.getCurve( name ) };
|
auto* const curve{ sync.getCurve( name ) };
|
||||||
mouseConsumed = sequencerTrack( hue , subBb , container , name , curve )
|
sequencerTrack( hue , subBb , container , name , curve );
|
||||||
|| mouseConsumed;
|
|
||||||
subBb.Min.y += TrackHeight + 2 * TrackPadding;
|
subBb.Min.y += TrackHeight + 2 * TrackPadding;
|
||||||
subBb.Max.y += TrackHeight + 2 * TrackPadding;
|
subBb.Max.y += TrackHeight + 2 * TrackPadding;
|
||||||
hue = fmodf( hue + .17f , 1.f );
|
hue = fmodf( hue + .17f , 1.f );
|
||||||
}
|
}
|
||||||
return mouseConsumed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool T_SyncViewImpl_::sequencerTrack(
|
void T_SyncViewImpl_::sequencerTrack(
|
||||||
float& hue ,
|
float& hue ,
|
||||||
ImRect const& bb ,
|
ImRect const& bb ,
|
||||||
ImRect const& container ,
|
ImRect const& container ,
|
||||||
T_String const& name ,
|
T_String const& id ,
|
||||||
T_SyncCurve const* curve ) noexcept
|
T_SyncCurve const* curve ) noexcept
|
||||||
{
|
{
|
||||||
using namespace ImGui;
|
// Don't display if the track is fully hidden
|
||||||
if ( !container.Overlaps( bb ) ) {
|
if ( !container.Overlaps( bb ) ) {
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
auto* const dl{ GetWindowDrawList( ) };
|
|
||||||
|
// Add track display record
|
||||||
|
const auto dTrackIdx{ dspTracks.size( ) };
|
||||||
|
auto& dTrack{ dspTracks.addNew( ) };
|
||||||
|
dTrack.id = id;
|
||||||
|
dTrack.isOverride = false;
|
||||||
|
dTrack.dispSegs = 0;
|
||||||
|
dTrack.firstSeg = dspSegments.size( );
|
||||||
|
dTrack.area = bb;
|
||||||
|
|
||||||
// Compute colors
|
// Compute colors
|
||||||
|
using namespace ImGui;
|
||||||
const auto bgColor{ ColorHSVAToU32( hue , .25f , 1.f , .25f ) } ,
|
const auto bgColor{ ColorHSVAToU32( hue , .25f , 1.f , .25f ) } ,
|
||||||
borderColor{ ColorHSVAToU32( hue , .12f , 1.f , 1.f ) };
|
borderColor{ ColorHSVAToU32( hue , .88f , 1.f , 1.f ) };
|
||||||
const uint32_t segColors[ 2 ] = {
|
const uint32_t segColors[ 2 ] = {
|
||||||
ColorHSVAToU32( hue - .03f , .4f , 1.f , 1.f ) ,
|
ColorHSVAToU32( hue - .03f , .4f , 1.f , 1.f ) ,
|
||||||
ColorHSVAToU32( hue + .03f , .4f , 1.f , 1.f ) ,
|
ColorHSVAToU32( hue + .03f , .4f , 1.f , 1.f ) ,
|
||||||
|
@ -650,6 +725,7 @@ bool T_SyncViewImpl_::sequencerTrack(
|
||||||
ImVec2{ ImFloor( bb.Max.x ) - 1 ,
|
ImVec2{ ImFloor( bb.Max.x ) - 1 ,
|
||||||
ImFloor( ImMin( container.Max.y , bb.Max.y ) ) }
|
ImFloor( ImMin( container.Max.y , bb.Max.y ) ) }
|
||||||
};
|
};
|
||||||
|
auto* const dl{ GetWindowDrawList( ) };
|
||||||
dl->AddRectFilled( bar.Min , bar.Max , bgColor );
|
dl->AddRectFilled( bar.Min , bar.Max , bgColor );
|
||||||
if ( container.Contains( bb.GetTL( ) ) ) {
|
if ( container.Contains( bb.GetTL( ) ) ) {
|
||||||
dl->AddLine( bar.GetTL( ) , bar.GetTR( ) , borderColor );
|
dl->AddLine( bar.GetTL( ) , bar.GetTR( ) , borderColor );
|
||||||
|
@ -667,13 +743,6 @@ bool T_SyncViewImpl_::sequencerTrack(
|
||||||
}
|
}
|
||||||
dl->PushClipRect( bar.Min , bar.Max );
|
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
|
// If there's a curve, go through all segments
|
||||||
const auto units{ Common::Sync( ).durationUnits( ) };
|
const auto units{ Common::Sync( ).durationUnits( ) };
|
||||||
const auto nSeg{ curve ? curve->segments.size( ) : 0u };
|
const auto nSeg{ curve ? curve->segments.size( ) : 0u };
|
||||||
|
@ -699,6 +768,17 @@ bool T_SyncViewImpl_::sequencerTrack(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add segment to displayed list
|
||||||
|
auto dSegIdx{ dspSegments.size( ) };
|
||||||
|
auto& dSeg{ dspSegments.addNew( ) };
|
||||||
|
dSeg.area = segFull;
|
||||||
|
dSeg.track = dTrackIdx;
|
||||||
|
dSeg.seg = i;
|
||||||
|
dSeg.dispPoints = 0;
|
||||||
|
dSeg.firstPoint = dspPoints.size( );
|
||||||
|
dTrack.dispSegs ++;
|
||||||
|
|
||||||
|
// Draw segment
|
||||||
const ImRect segBar{
|
const ImRect segBar{
|
||||||
ImVec2{ ImMax( bar.Min.x , segFull.Min.x ) , segFull.Min.y } ,
|
ImVec2{ ImMax( bar.Min.x , segFull.Min.x ) , segFull.Min.y } ,
|
||||||
ImVec2{ ImMin( bar.Max.x , segFull.Max.x ) , segFull.Max.y }
|
ImVec2{ ImMin( bar.Max.x , segFull.Max.x ) , segFull.Max.y }
|
||||||
|
@ -706,73 +786,147 @@ bool T_SyncViewImpl_::sequencerTrack(
|
||||||
dl->AddRectFilled( segBar.Min , segBar.Max , color );
|
dl->AddRectFilled( segBar.Min , segBar.Max , color );
|
||||||
dl->PushClipRect( segBar.Min , segBar.Max );
|
dl->PushClipRect( segBar.Min , segBar.Max );
|
||||||
|
|
||||||
|
// Handle points
|
||||||
const auto nd{ seg.durations.size( ) };
|
const auto nd{ seg.durations.size( ) };
|
||||||
const auto radius{ ( TrackHeight - 2.f ) * .5f };
|
const auto ym{ bb.Min.y + PointRadius + 1 };
|
||||||
const auto ym{ bb.Min.y + radius + 1 };
|
|
||||||
auto cDur{ 0 };
|
auto cDur{ 0 };
|
||||||
for ( auto j = 0u ; j < nd + 1 ; j ++ ) {
|
for ( auto j = 0u ; j < nd + 1 ; j ++ ) {
|
||||||
const ImVec2 ctr{
|
const ImVec2 ctr{
|
||||||
std::roundf( xStart + cDur * totalPixels / units ) ,
|
std::roundf( xStart + cDur * totalPixels / units ) ,
|
||||||
ym
|
ym
|
||||||
};
|
};
|
||||||
dl->AddCircleFilled( ctr , radius , 0x7f000000 ); // XXX color
|
dl->AddCircleFilled( ctr , PointRadius , 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;
|
cDur += j < nd ? seg.durations[ j ] : 0;
|
||||||
|
|
||||||
|
// Add point record
|
||||||
|
auto& dPoint{ dspPoints.addNew( ) };
|
||||||
|
dPoint.center = ctr;
|
||||||
|
dPoint.index = j;
|
||||||
|
dPoint.mode =
|
||||||
|
j == 0 ? T_TrackPointDisplay::START : (
|
||||||
|
j == nd ? T_TrackPointDisplay::END :
|
||||||
|
T_TrackPointDisplay::MIDDLE );
|
||||||
|
dPoint.seg = dSegIdx;
|
||||||
|
dSeg.dispPoints ++;
|
||||||
}
|
}
|
||||||
dl->PopClipRect( );
|
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( );
|
dl->PopClipRect( );
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
void T_SyncViewImpl_::displayTooltips(
|
||||||
|
const float time ) noexcept
|
||||||
|
{
|
||||||
|
auto mp{ getMousePos( ) };
|
||||||
|
if ( mp.type == E_MousePosType::NONE ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Track / segment / point from mouse info
|
||||||
|
auto const& track( [&](){
|
||||||
|
if ( mp.type == E_MousePosType::POINT ) {
|
||||||
|
return dspTracks[ dspSegments[
|
||||||
|
dspPoints[ mp.index ].seg ].track ];
|
||||||
|
}
|
||||||
|
if ( mp.type == E_MousePosType::SEGMENT ) {
|
||||||
|
return dspTracks[ dspSegments[ mp.index ].track ];
|
||||||
|
}
|
||||||
|
return dspTracks[ mp.index ];
|
||||||
|
}() );
|
||||||
|
auto const* const seg( [&]() -> T_TrackSegDisplay const* {
|
||||||
|
if ( mp.type == E_MousePosType::TRACK ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
if ( mp.type == E_MousePosType::SEGMENT ) {
|
||||||
|
return &dspSegments[ mp.index ];
|
||||||
|
}
|
||||||
|
return &dspSegments[ dspPoints[ mp.index ].seg ];
|
||||||
|
}() );
|
||||||
|
auto const* const point( [&]() -> T_TrackPointDisplay const* {
|
||||||
|
if ( mp.type != E_MousePosType::POINT ) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return &dspPoints[ mp.index ];
|
||||||
|
}() );
|
||||||
|
|
||||||
|
// Curve from track
|
||||||
|
T_SyncCurve const* const curve{ Common::Sync( ).getCurve( track.id ) };
|
||||||
|
assert( mp.type == E_MousePosType::TRACK || curve != nullptr );
|
||||||
|
|
||||||
|
// Time offset
|
||||||
|
const float dTime( [&](){
|
||||||
|
if ( point ) {
|
||||||
|
auto tDur{ .0f };
|
||||||
|
printf( "segseg %d\n" , seg->seg );
|
||||||
|
for ( auto i = 0u ; i <= seg->seg ; i ++ ) {
|
||||||
|
auto const& s{ curve->segments[ i ] };
|
||||||
|
auto const nd{ i == seg->seg
|
||||||
|
? point->index
|
||||||
|
: s.durations.size( ) };
|
||||||
|
printf( "s %d -> nd %d\n" , i , nd );
|
||||||
|
for ( auto j = 0u ; j < nd ; j ++ ) {
|
||||||
|
tDur += s.durations[ j ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tDur * Common::Sync( ).durationUnitSize( );
|
||||||
|
}
|
||||||
|
return time;
|
||||||
|
}() );
|
||||||
|
char buffer[ 12 ];
|
||||||
|
TimeToString_( buffer , sizeof( buffer ) , dTime );
|
||||||
|
|
||||||
|
const float value{ point ? curve->segments[ seg->seg ].values[ point->index ] : -.666f }; // FIXME
|
||||||
|
|
||||||
|
stringBuffer.clear( ) << track.id << " (input)\n";
|
||||||
|
if ( mp.type == E_MousePosType::TRACK ) {
|
||||||
|
stringBuffer << "No segment";
|
||||||
|
} else {
|
||||||
|
auto const& s{ curve->segments[ seg->seg ] };
|
||||||
|
if ( mp.type == E_MousePosType::SEGMENT ) {
|
||||||
|
stringBuffer << "Segment type: " << s.type;
|
||||||
|
} else {
|
||||||
|
stringBuffer << "On " << s.type << " segment, index " << point->index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stringBuffer << "\nTime: " << buffer << "\nValue: " << value;
|
||||||
|
|
||||||
|
using namespace ImGui;
|
||||||
|
stringBuffer << '\0';
|
||||||
|
BeginTooltip( );
|
||||||
|
Text( "%s" , stringBuffer.data( ) );
|
||||||
|
EndTooltip( );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
T_SyncViewImpl_::T_MousePos T_SyncViewImpl_::getMousePos( ) const noexcept
|
||||||
|
{
|
||||||
|
auto const& mp{ ImGui::GetIO( ).MousePos };
|
||||||
|
for ( auto i = 0u ; i < dspTracks.size( ) ; i ++ ) {
|
||||||
|
auto const& track{ dspTracks[ i ] };
|
||||||
|
if ( !track.area.Contains( mp ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for ( auto j = 0u ; j < track.dispSegs ; j ++ ) {
|
||||||
|
auto const& seg{ dspSegments[ track.firstSeg + j ] };
|
||||||
|
if ( !seg.area.Contains( mp ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for ( auto k = 0u ; k < seg.dispPoints ; k ++ ) {
|
||||||
|
auto const& p{ dspPoints[ seg.firstPoint + k ] };
|
||||||
|
if ( ImLengthSqr( mp - p.center ) <= PointRadiusSqr ) {
|
||||||
|
return T_MousePos{ E_MousePosType::POINT ,
|
||||||
|
seg.firstPoint + k };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return T_MousePos{ E_MousePosType::SEGMENT , i };
|
||||||
|
}
|
||||||
|
return T_MousePos{ E_MousePosType::TRACK , i };
|
||||||
|
}
|
||||||
|
return T_MousePos{ E_MousePosType::NONE , 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/*----------------------------------------------------------------------------*/
|
/*----------------------------------------------------------------------------*/
|
||||||
|
|
Loading…
Reference in a new issue