1
0
mirror of https://github.com/wolfpld/tracy synced 2025-04-29 12:23:53 +00:00
tracy/server/TracyTimelineController.cpp
simplyWiri a8b42488ad Clamp scrolling to the difference between the deepest zone near the mouse, and the height of the window.
This prevents from unncessary scrolling when the trace does not exceed the size of the screen
2023-04-02 19:01:58 +10:00

178 lines
4.7 KiB
C++

#include <algorithm>
#include <thread>
#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 ), "Render" )
#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<int> 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, ImFont* smallFont )
{
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();
ImGui::PushFont( smallFont );
ctx.sty = ImGui::GetTextLineHeight();
ImGui::PopFont();
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<int>( *scrollY, std::max<int>( yOffset - ImGui::GetWindowHeight(), 0 ) );
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;
}
}