Sequencer - Time in header + bars
This commit is contained in:
parent
cb4849d89e
commit
dd0403ab1c
1 changed files with 121 additions and 70 deletions
191
syncview.cc
191
syncview.cc
|
@ -22,14 +22,22 @@ struct T_SyncViewImpl_
|
||||||
const uint32_t ColHeaderText{ ImGui::GetColorU32( ImVec4{ 0 , 0 , 0 , 1 } ) };
|
const uint32_t ColHeaderText{ ImGui::GetColorU32( ImVec4{ 0 , 0 , 0 , 1 } ) };
|
||||||
const uint32_t ColMain{ ImGui::GetColorU32( ImVec4{ .4 , .4 , .4 , .8 } ) };
|
const uint32_t ColMain{ ImGui::GetColorU32( ImVec4{ .4 , .4 , .4 , .8 } ) };
|
||||||
|
|
||||||
float zoomLevel{ 1.f };
|
float zoomLevel{ 0.f };
|
||||||
float startPos{ 100.895f };
|
float startPos{ 0.f };
|
||||||
bool followTime{ true };
|
bool followTime{ true };
|
||||||
|
|
||||||
bool display( ) noexcept;
|
bool display( ) noexcept;
|
||||||
|
void computeMetrics( float innerWidth ) noexcept;
|
||||||
void sequencerWidget( ) noexcept;
|
void sequencerWidget( ) noexcept;
|
||||||
void sequencerHeader( ImRect const& bb ) noexcept;
|
void sequencerHeader( ImRect const& bb ) noexcept;
|
||||||
void sequencerBody( ImRect const& bb ) noexcept;
|
void sequencerBody( ImRect const& bb ) noexcept;
|
||||||
|
|
||||||
|
// Computed metrics
|
||||||
|
float barWidth;
|
||||||
|
float cursorPos;
|
||||||
|
uint32_t startBar;
|
||||||
|
float startBarPos;
|
||||||
|
float timePerBar;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,9 +59,21 @@ bool T_SyncViewImpl_::display( ) noexcept
|
||||||
}
|
}
|
||||||
|
|
||||||
PushItemWidth( 100 );
|
PushItemWidth( 100 );
|
||||||
SliderFloat( "Zoom" , &zoomLevel , 0 , 1 , "%.2f" );
|
SliderFloat( "##zoom" , &zoomLevel , 0 , 1 , "%.2f" );
|
||||||
|
if ( IsItemHovered( ) ) {
|
||||||
|
BeginTooltip( );
|
||||||
|
Text( "Zoom level" );
|
||||||
|
EndTooltip( );
|
||||||
|
}
|
||||||
PopItemWidth( );
|
PopItemWidth( );
|
||||||
SameLine( );
|
SameLine( );
|
||||||
|
Checkbox( "##follow" , &followTime );
|
||||||
|
if ( IsItemHovered( ) ) {
|
||||||
|
BeginTooltip( );
|
||||||
|
Text( "Follow cursor" );
|
||||||
|
EndTooltip( );
|
||||||
|
}
|
||||||
|
SameLine( );
|
||||||
|
|
||||||
PushID( "playing" );
|
PushID( "playing" );
|
||||||
if ( Button( sync.playing( ) ? "Stop" : "Play" ) ) {
|
if ( Button( sync.playing( ) ? "Stop" : "Play" ) ) {
|
||||||
|
@ -102,60 +122,7 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
||||||
if ( !ItemAdd( bbAll , seqId ) ) {
|
if ( !ItemAdd( bbAll , seqId ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
computeMetrics( std::max( 0.f , width - 2.f ) );
|
||||||
/*
|
|
||||||
* Scaling:
|
|
||||||
* At minimal zoom level, we want the whole "track" to fit inside the
|
|
||||||
* available width.
|
|
||||||
* At maximal zoom level, we want units from the sync manager to cover
|
|
||||||
* $MIN_UNIT_WIDTH pixels (that should depend on the text size).
|
|
||||||
* The displayed size of the units increases along with the zoom level.
|
|
||||||
* Display units are rescaled when the distance between them
|
|
||||||
* becomes >= 2 * $MIN_UNIT_WIDTH
|
|
||||||
* At worst, the sequence is only one unit long; this means that no
|
|
||||||
* scaling occurs between minimal and maximal levels.
|
|
||||||
*/
|
|
||||||
|
|
||||||
auto& sync( Globals::Sync( ) );
|
|
||||||
const float innerWidth{ width - 2 };
|
|
||||||
const uint32_t units{ sync.durationUnits( ) };
|
|
||||||
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 );
|
PushID( seqId );
|
||||||
BeginGroup( );
|
BeginGroup( );
|
||||||
|
@ -173,32 +140,94 @@ void T_SyncViewImpl_::sequencerWidget( ) noexcept
|
||||||
sequencerBody( bbDisplay );
|
sequencerBody( bbDisplay );
|
||||||
PopID( );
|
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( );
|
EndGroup( );
|
||||||
PopID( );
|
PopID( );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void T_SyncViewImpl_::computeMetrics(
|
||||||
|
const float innerWidth ) noexcept
|
||||||
|
{
|
||||||
|
auto& sync( Globals::Sync( ) );
|
||||||
|
const uint32_t units{ sync.durationUnits( ) };
|
||||||
|
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 };
|
||||||
|
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 };
|
||||||
|
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 ) ) ) );
|
||||||
|
}();
|
||||||
|
startBarPos = startBar * barWidth - startPixel;
|
||||||
|
cursorPos = absCursorPos - startPixel;
|
||||||
|
timePerBar = unitsPerBar * sync.durationUnitSize( );
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
void T_SyncViewImpl_::sequencerHeader(
|
void T_SyncViewImpl_::sequencerHeader(
|
||||||
ImRect const& bb ) noexcept
|
ImRect const& bb ) noexcept
|
||||||
{
|
{
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
auto* const dl( GetWindowDrawList( ) );
|
auto* const dl( GetWindowDrawList( ) );
|
||||||
|
const ImRect inner{ bb.Min + ImVec2{ 1 , 1 } , bb.Max - ImVec2{ 1 , 1 } };
|
||||||
|
|
||||||
|
dl->AddRectFilled( inner.Min , inner.Max , ColHeader );
|
||||||
|
dl->AddRect( bb.Min , bb.Max , ColFrame );
|
||||||
|
|
||||||
|
if ( cursorPos >= 0 && cursorPos <= inner.GetWidth( ) ) {
|
||||||
|
auto* const dl( GetWindowDrawList( ) );
|
||||||
|
dl->AddLine( inner.Min + ImVec2{ cursorPos , 0 } ,
|
||||||
|
ImVec2{ inner.Min.x + cursorPos , inner.Max.y - 1 } ,
|
||||||
|
GetColorU32( ImVec4{ 1 , 1 , 1 , .5 } ) );
|
||||||
|
}
|
||||||
|
|
||||||
PushFont( Globals::Window( ).smallFont( ) );
|
PushFont( Globals::Window( ).smallFont( ) );
|
||||||
PushStyleColor( ImGuiCol_Text , ColHeaderText );
|
PushStyleColor( ImGuiCol_Text , ColHeaderText );
|
||||||
dl->AddRectFilled( bb.Min + ImVec2( 1 , 1 ) , bb.Max - ImVec2( 1 , 1 ) ,
|
auto pos{ startBarPos };
|
||||||
ColHeader );
|
auto bar{ startBar };
|
||||||
dl->AddRect( bb.Min , bb.Max , ColFrame );
|
const auto max{ bb.GetWidth( ) + barWidth - 2.f };
|
||||||
|
char buffer[ 12 ];
|
||||||
|
while ( pos < max ) {
|
||||||
|
const ImVec2 taStart{ inner.Min + ImVec2{ pos - barWidth * .5f , 0 } };
|
||||||
|
const ImVec2 taEnd{ taStart + ImVec2{ barWidth , inner.Max.y - inner.Min.y } };
|
||||||
|
|
||||||
const ImRect textBb{ bb.Min - ImVec2{ 10 , 0 } , bb.Max + ImVec2{ 10 , 0 } };
|
const float time{ bar * timePerBar };
|
||||||
RenderTextClipped( textBb.Min , textBb.Max , "test!" , nullptr , nullptr , ImVec2{ 0 , .25 } , &bb );
|
const float msf{ fmod( time , 1.f ) };
|
||||||
RenderTextClipped( textBb.Min , textBb.Max , "...icle" , nullptr , nullptr , ImVec2{ 0 , .75 } , &bb );
|
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 ,
|
||||||
|
ImVec2{ .5f , .2f + ( ( bar % 2 ) ? .6f : 0.f ) } , &inner );
|
||||||
|
pos += barWidth;
|
||||||
|
bar ++;
|
||||||
|
}
|
||||||
PopStyleColor( );
|
PopStyleColor( );
|
||||||
PopFont( );
|
PopFont( );
|
||||||
}
|
}
|
||||||
|
@ -208,8 +237,30 @@ void T_SyncViewImpl_::sequencerBody(
|
||||||
{
|
{
|
||||||
using namespace ImGui;
|
using namespace ImGui;
|
||||||
auto* const dl( GetWindowDrawList( ) );
|
auto* const dl( GetWindowDrawList( ) );
|
||||||
|
const ImRect inner{ bb.Min + ImVec2{ 1 , 1 } , bb.Max - ImVec2{ 1 , 1 } };
|
||||||
|
|
||||||
dl->AddRectFilled( bb.Min , bb.Max , ColMain );
|
dl->AddRectFilled( inner.Min , inner.Max , ColMain );
|
||||||
|
dl->AddRect( bb.Min , bb.Max , ColFrame );
|
||||||
|
|
||||||
|
auto pos{ startBarPos };
|
||||||
|
auto bar{ startBar };
|
||||||
|
const auto max{ bb.GetWidth( ) + barWidth - 2.f };
|
||||||
|
while ( pos < max ) {
|
||||||
|
if ( pos >= 0 && pos < inner.GetWidth( ) ) {
|
||||||
|
dl->AddLine( bb.Min + ImVec2{ pos , 0 } ,
|
||||||
|
ImVec2{ inner.Min.x + pos , inner.Max.y } ,
|
||||||
|
0xff000000 );
|
||||||
|
}
|
||||||
|
pos += barWidth;
|
||||||
|
bar ++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( cursorPos >= 0 && cursorPos <= inner.GetWidth( ) ) {
|
||||||
|
auto* const dl( GetWindowDrawList( ) );
|
||||||
|
dl->AddLine( inner.Min + ImVec2{ cursorPos , -1 } ,
|
||||||
|
ImVec2{ inner.Min.x + cursorPos , inner.Max.y - 1 } ,
|
||||||
|
0xffffffff );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue