#include #include #include "TracyTimelineItem.hpp" #include "TracyTimelineContext.hpp" #include "TracyTimelineController.hpp" #include "TracyView.hpp" namespace tracy { TimelineController::TimelineController( View& view, Worker& worker ) : m_height( 0 ) , m_scroll( 0 ) , m_centerItemkey( nullptr ) , m_centerItemOffsetY( 0 ) , m_firstFrame( true ) , m_view( view ) , m_worker( worker ) #ifdef __EMSCRIPTEN__ , m_td( 1 ) #else , m_td( std::max( 1u, std::thread::hardware_concurrency() - 2 ) ) #endif { } TimelineController::~TimelineController() { } void TimelineController::FirstFrameExpired() { m_firstFrame = false; } void TimelineController::Begin() { m_items.clear(); } void TimelineController::UpdateCenterItem() { ImVec2 mousePos = ImGui::GetMousePos(); m_centerItemkey = nullptr; m_centerItemOffsetY = 0; if( m_firstFrame || !ImGui::IsMousePosValid( &mousePos ) ) return; const auto timelineMousePosY = mousePos.y - ImGui::GetWindowPos().y; int centerY = timelineMousePosY + ImGui::GetScrollY(); int yBegin = 0; int yEnd = 0; for( auto& item : m_items ) { m_centerItemkey = item->GetKey(); yBegin = yEnd; yEnd += item->GetHeight(); const auto inLowerBounds = m_centerItemkey == m_items.front()->GetKey() || yBegin <= centerY; const auto inUpperBounds = m_centerItemkey == m_items.back()->GetKey() || centerY < yEnd; if( inLowerBounds && inUpperBounds ) { m_centerItemOffsetY = centerY - yBegin; break; } } } std::optional TimelineController::CalculateScrollPosition() const { if( !m_centerItemkey ) return std::nullopt; ImVec2 mousePos = ImGui::GetMousePos(); if( !ImGui::IsMousePosValid( &mousePos ) ) return std::nullopt; const auto timelineMousePosY = mousePos.y - ImGui::GetWindowPos().y; int yBegin = 0; int yEnd = 0; for( auto& item : m_items ) { yBegin = yEnd; yEnd += item->GetHeight(); if( item->GetKey() != m_centerItemkey ) continue; int scrollY = yBegin + m_centerItemOffsetY - timelineMousePosY; return scrollY; } return std::nullopt; } void TimelineController::End( double pxns, const ImVec2& wpos, bool hover, bool vcenter, float yMin, float yMax ) { auto shouldUpdateCenterItem = [&] () { const auto imguiChangedScroll = m_scroll != ImGui::GetScrollY(); const auto& mouseDelta = ImGui::GetIO().MouseDelta; const auto mouseMoved = mouseDelta.x != 0.0f || mouseDelta.y != 0.0f; const auto& mousePos = ImGui::GetIO().MousePos; const auto mouseVisible = ImGui::IsMousePosValid( &mousePos ); return ( ( imguiChangedScroll || mouseMoved || !mouseVisible ) && !ImGui::IsMouseDown( 1 ) ) || !m_centerItemkey; }; if( !vcenter ) { m_centerItemkey = nullptr; m_centerItemOffsetY = 0; } else if( shouldUpdateCenterItem() ) { UpdateCenterItem(); } const auto& viewData = m_view.GetViewData(); TimelineContext ctx; ctx.w = ImGui::GetContentRegionAvail().x - 1; ctx.ty = ImGui::GetTextLineHeight(); ctx.scale = GetScale(); ctx.yMin = yMin; ctx.yMax = yMax; ctx.pxns = pxns; ctx.nspx = 1.0 / pxns; ctx.vStart = viewData.zvStart; ctx.vEnd = viewData.zvEnd; ctx.wpos = wpos; ctx.hover = hover; int yOffset = 0; for( auto& item : m_items ) { if( item->WantPreprocess() && item->IsVisible() ) { const auto yPos = wpos.y + yOffset; const bool visible = m_firstFrame || ( yPos < yMax && yPos + item->GetHeight() >= yMin ); item->Preprocess( ctx, m_td, visible ); } yOffset += m_firstFrame ? 0 : item->GetHeight(); } m_td.Sync(); yOffset = 0; for( auto& item : m_items ) { auto currentFrameItemHeight = item->GetHeight(); item->Draw( m_firstFrame, ctx, yOffset ); if( m_firstFrame ) currentFrameItemHeight = item->GetHeight(); yOffset += currentFrameItemHeight; } if( const auto scrollY = CalculateScrollPosition() ) { int clampedScrollY = std::min( *scrollY, yOffset ); ImGui::SetScrollY( clampedScrollY ); int minHeight = ImGui::GetWindowHeight() + clampedScrollY; yOffset = std::max( yOffset, minHeight ); } const auto scrollPos = ImGui::GetScrollY(); if( ( scrollPos == 0 && m_scroll != 0 ) || yOffset > m_height ) { m_height = yOffset; } m_scroll = scrollPos; } }