1+ #include < algorithm>
2+
13#include " imgui.h"
24
35#include " TracyTimelineController.hpp"
@@ -8,6 +10,8 @@ namespace tracy
810TimelineController::TimelineController ( View& view, Worker& worker )
911 : m_height( 0 )
1012 , m_scroll( 0 )
13+ , m_centerItemkey( nullptr )
14+ , m_centerItemOffsetY( 0 )
1115 , m_firstFrame( true )
1216 , m_view( view )
1317 , m_worker( worker )
@@ -24,8 +28,83 @@ void TimelineController::Begin()
2428 m_items.clear ();
2529}
2630
27- void TimelineController::End ( double pxns, const ImVec2& wpos, bool hover, float yMin, float yMax )
31+ void TimelineController::UpdateCenterItem ()
32+ {
33+ ImVec2 mousePos = ImGui::GetMousePos ();
34+
35+ m_centerItemkey = nullptr ;
36+ m_centerItemOffsetY = 0 ;
37+
38+ if ( m_firstFrame || !ImGui::IsMousePosValid ( &mousePos ) ) return ;
39+
40+ const auto timelineMousePosY = mousePos.y - ImGui::GetWindowPos ().y ;
41+ int centerY = timelineMousePosY + ImGui::GetScrollY ();
42+
43+ int yBegin = 0 ;
44+ int yEnd = 0 ;
45+ for ( auto & item : m_items )
46+ {
47+ m_centerItemkey = item->GetKey ();
48+ yBegin = yEnd;
49+ yEnd += item->GetNextFrameHeight ();
50+
51+ const auto inLowerBounds = m_centerItemkey == m_items.front ()->GetKey () || yBegin <= centerY;
52+ const auto inUpperBounds = m_centerItemkey == m_items.back ()->GetKey () || centerY < yEnd;
53+
54+ if ( inLowerBounds && inUpperBounds )
55+ {
56+ m_centerItemOffsetY = centerY - yBegin;
57+ break ;
58+ }
59+ }
60+ }
61+
62+ std::optional<int > TimelineController::CalculateScrollPosition () const
63+ {
64+ if ( !m_centerItemkey ) return std::nullopt ;
65+
66+ ImVec2 mousePos = ImGui::GetMousePos ();
67+
68+ if ( !ImGui::IsMousePosValid ( &mousePos ) ) return std::nullopt ;
69+
70+ const auto timelineMousePosY = mousePos.y - ImGui::GetWindowPos ().y ;
71+
72+ int yBegin = 0 ;
73+ int yEnd = 0 ;
74+ for ( auto & item : m_items )
75+ {
76+ yBegin = yEnd;
77+ yEnd += item->GetNextFrameHeight ();
78+
79+ if ( item->GetKey () != m_centerItemkey ) continue ;
80+
81+ int scrollY = yBegin + m_centerItemOffsetY - timelineMousePosY;
82+
83+ return scrollY;
84+ }
85+
86+ return std::nullopt ;
87+ }
88+
89+ void TimelineController::End ( double pxns, const ImVec2& wpos, bool hover, bool vcenter, float yMin, float yMax )
2890{
91+ auto shouldUpdateCenterItem = [&] () {
92+ const auto & mouseDelta = ImGui::GetIO ().MouseDelta ;
93+ const auto mouseMoved = mouseDelta.x != 0 .0f || mouseDelta.y != 0 .0f ;
94+ const auto imguiChangedScroll = m_scroll != ImGui::GetScrollY ();
95+ return ( ( imguiChangedScroll || mouseMoved ) && !ImGui::IsMouseDown ( 1 ) ) || !m_centerItemkey;
96+ };
97+
98+ if ( !vcenter )
99+ {
100+ m_centerItemkey = nullptr ;
101+ m_centerItemOffsetY = 0 ;
102+ }
103+ else if ( shouldUpdateCenterItem () )
104+ {
105+ UpdateCenterItem ();
106+ }
107+
29108 int yOffset = 0 ;
30109
31110 for ( auto & item : m_items )
@@ -36,6 +115,14 @@ void TimelineController::End( double pxns, const ImVec2& wpos, bool hover, float
36115 yOffset += currentFrameItemHeight;
37116 }
38117
118+ if ( const auto scrollY = CalculateScrollPosition () )
119+ {
120+ int clampedScrollY = std::min<int >( *scrollY, yOffset );
121+ ImGui::SetScrollY ( clampedScrollY );
122+ int minHeight = ImGui::GetWindowHeight () + clampedScrollY;
123+ yOffset = std::max ( yOffset, minHeight );
124+ }
125+
39126 const auto scrollPos = ImGui::GetScrollY ();
40127 if ( ( scrollPos == 0 && m_scroll != 0 ) || yOffset > m_height )
41128 {
0 commit comments