diff --git a/main.cc b/main.cc index 43934fb..240f7b8 100644 --- a/main.cc +++ b/main.cc @@ -76,6 +76,10 @@ void T_Main::mainLoop( ) if ( needInit ) { initDemo( ); } +#warning FIXME remove this + if ( !sequencer ) { + sequencer.setNew( ); + } Globals::Watcher( ).check( ); Globals::Shaders( ).update( ); diff --git a/sync.hh b/sync.hh index a274ea9..f692a1c 100644 --- a/sync.hh +++ b/sync.hh @@ -289,6 +289,11 @@ struct T_SyncManager : public virtual A_MouseCtrl float duration( ) const noexcept { return time_.duration( ); } + uint32_t durationUnits( ) const noexcept + { return time_.iDuration; } + float durationUnitSize( ) const noexcept + { return time_.uDuration; } + void setTime( const float time ); void timeDelta( const float delta ) { setTime( time_.time + delta ); } diff --git a/syncview.cc b/syncview.cc index 0b55199..4b0beec 100644 --- a/syncview.cc +++ b/syncview.cc @@ -1,6 +1,10 @@ #include "externals.hh" #include "syncview.hh" #include "globals.hh" +#include "window.hh" + +#define IMGUI_DEFINE_MATH_OPERATORS +#include using namespace ebcl; @@ -10,7 +14,19 @@ namespace { struct T_SyncViewImpl_ { + static constexpr float SeqHeaderHeight = 24; + static constexpr float MinUnitWidth = 80; + + const uint32_t ColFrame{ ImGui::GetColorU32( ImVec4{ 0 , 0 , 0 , .8 } ) }; + const uint32_t ColHeader{ ImGui::GetColorU32( ImVec4{ .5 , .5 , .5 , .8 } ) }; + const uint32_t ColHeaderText{ ImGui::GetColorU32( ImVec4{ 0 , 0 , 0 , 1 } ) }; + const uint32_t ColMain{ ImGui::GetColorU32( ImVec4{ .4 , .4 , .4 , .8 } ) }; + + float zoomLevel{ 1.f }; + bool display( ) noexcept; + void sequencerWidget( ) noexcept; + void sequencerHeader( ImRect const& bb ) noexcept; }; @@ -24,8 +40,10 @@ bool T_SyncViewImpl_::display( ) noexcept SetNextWindowSize( ImVec2( dspSize.x , 150 ) , ImGuiSetCond_Appearing ); SetNextWindowPos( ImVec2( 0 , dspSize.y - 150 ) , ImGuiSetCond_Appearing ); bool displayed{ true }; - Begin( "Sequencer" , &displayed , ImGuiWindowFlags_NoCollapse ); + Begin( "Sequencer" , &displayed , ImGuiWindowFlags_NoCollapse + | ImGuiWindowFlags_NoScrollWithMouse ); if ( !displayed ) { + End( ); return false; } @@ -46,11 +64,98 @@ bool T_SyncViewImpl_::display( ) noexcept } PopItemWidth( ); PopID( ); - End( ); + PushItemWidth( -1 ); + sequencerWidget( ); + PopItemWidth( ); + + End( ); return true; } +void T_SyncViewImpl_::sequencerWidget( ) noexcept +{ + using namespace ImGui; + + const auto width{ CalcItemWidth( ) }; + auto* const win( GetCurrentWindow( ) ); + const auto seqId{ win->GetID( "##sequencer" ) }; + + const ImVec2 cPos( win->DC.CursorPos ); + const ImVec2 ws( GetWindowContentRegionMax( ) ); + + auto& style( ImGui::GetStyle( ) ); + const ImRect bbHeader{ cPos , cPos + ImVec2( width , SeqHeaderHeight ) }; + const ImRect bbDisplay{ ImVec2{ cPos.x , bbHeader.Max.y } , + ImVec2{ cPos.x + width , GetWindowPos( ).y + ws.y - style.FramePadding.y } }; + const ImRect bbAll{ bbHeader.Min , bbDisplay.Max }; + + ItemSize( bbAll , style.FramePadding.y ); + if ( !ItemAdd( bbAll , seqId ) ) { + return; + } + + /* + * 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 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 ); + + 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 ); + sequencerHeader( bbHeader ); + 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 ) ) ); + } + + EndGroup( ); + PopID( ); +} + +void T_SyncViewImpl_::sequencerHeader( + ImRect const& bb ) noexcept +{ + using namespace ImGui; + auto* const dl( GetWindowDrawList( ) ); + + PushFont( Globals::Window( ).smallFont( ) ); + PushStyleColor( ImGuiCol_Text , ColHeaderText ); + dl->AddRectFilled( bb.Min + ImVec2( 1 , 1 ) , bb.Max - ImVec2( 1 , 1 ) , + ColHeader ); + dl->AddRect( bb.Min , bb.Max , ColFrame ); + + const ImRect textBb{ bb.Min - ImVec2{ 10 , 0 } , bb.Max + ImVec2{ 10 , 0 } }; + RenderTextClipped( textBb.Min , textBb.Max , "test!" , nullptr , nullptr , ImVec2{ 0 , .25 } , &bb ); + RenderTextClipped( textBb.Min , textBb.Max , "...icle" , nullptr , nullptr , ImVec2{ 0 , .75 } , &bb ); + PopStyleColor( ); + PopFont( ); +} + } // namespace /*= T_SyncView =================================================================*/ diff --git a/window.cc b/window.cc index 28b7902..b4dd571 100644 --- a/window.cc +++ b/window.cc @@ -1,6 +1,7 @@ #include "externals.hh" #include "window.hh" #include "imgui_impl_sdl.h" +#include T_Window::T_Window( ) @@ -27,6 +28,19 @@ T_Window::T_Window( ) } ImGui_ImplSdl_Init( window ); + + using namespace ImGui; + ImGuiIO& io{ GetIO( ) }; + { + ImFontConfig cfg; + cfg.SizePixels = 13.0f; + defaultFont_ = io.Fonts->AddFontDefault( &cfg ); + } + { + ImFontConfig cfg; + cfg.SizePixels = 9.0f; + smallFont_ = io.Fonts->AddFontDefault( &cfg ); + } } T_Window::~T_Window( ) diff --git a/window.hh b/window.hh index 1b9c1cb..53aa4e6 100644 --- a/window.hh +++ b/window.hh @@ -15,8 +15,15 @@ struct T_Window void swap( ) const; + ImFont* defaultFont( ) const noexcept + { return defaultFont_; } + ImFont* smallFont( ) const noexcept + { return smallFont_; } + private: SDL_Window * window; SDL_GLContext gl; + ImFont* defaultFont_; + ImFont* smallFont_; };