Extract the manual window from View into a standalone class.

The manual rendering was a View method bound to View members. Move it
into a ManualWindow class that owns the active chunk, scroll-reset and
shown state and holds a reference to the shared manual data.
This commit is contained in:
Bartosz Taudul
2026-10-07 20:13:32 +02:00
parent e33ccfda76
commit e56fbefc05
8 changed files with 86 additions and 44 deletions

View File

@@ -91,6 +91,7 @@ set(SERVER_FILES
TracyFilesystem.cpp
TracyImGui.cpp
TracyManualData.cpp
TracyManualWindow.cpp
TracyMarkdown.cpp
TracyMicroArchitecture.cpp
TracyMouse.cpp
@@ -124,7 +125,6 @@ set(SERVER_FILES
TracyView_FrameTree.cpp
TracyView_GpuTimeline.cpp
TracyView_Locks.cpp
TracyView_Manual.cpp
TracyView_Memory.cpp
TracyView_Messages.cpp
TracyView_Navigation.cpp

View File

@@ -172,7 +172,7 @@ std::string TracyLlmChat::ToolCallDescription( const nlohmann::json& json ) cons
TracyLlmChat::TracyLlmChat( View& view, Worker& worker, const std::vector<LlmSkill>& skills )
: m_width( new float[NumRoles] )
, m_markdown( &view, &worker )
, m_markdown( &view, &worker, &view.GetManualWindow() )
, m_skills( skills )
, m_worker( worker )
, m_view( view )

View File

@@ -1,22 +1,28 @@
#include <assert.h>
#include <algorithm>
#include <stdio.h>
#include <string>
#include "TracyImGui.hpp"
#include "TracyManualData.hpp"
#include "TracyManualWindow.hpp"
#include "TracyMarkdown.hpp"
#include "TracyView.hpp"
#include "TracyWeb.hpp"
#include "../Fonts.hpp"
namespace tracy
{
void View::DrawManual()
ManualWindow::ManualWindow( const TracyManualData& manual )
: m_manual( manual )
{
}
void ManualWindow::Draw( Markdown& md )
{
const auto scale = GetScale();
ImGui::SetNextWindowSize( ImVec2( 1200 * scale, 800 * scale ), ImGuiCond_FirstUseEver );
if( m_manualPositionReset ) ImGui::SetNextWindowFocus();
ImGui::Begin( "User manual", &m_showManual );
if( m_positionReset ) ImGui::SetNextWindowFocus();
ImGui::Begin( "User manual", &m_show );
if( ImGui::GetCurrentWindowRead()->SkipItems ) { ImGui::End(); return; }
ImGui::PushStyleColor( ImGuiCol_Text, ImVec4( 1.f, 1.f, 0.f, 1.0f ) );
@@ -41,7 +47,7 @@ void View::DrawManual()
ImGui::BeginChild( "##toc", ImVec2( 0, 0 ), ImGuiChildFlags_AlwaysUseWindowPadding );
int level = 0;
auto& chunks = m_manualData.GetChunks();
auto& chunks = m_manual.GetChunks();
assert( !chunks.empty() );
for( size_t i=0; i<chunks.size(); i++ )
{
@@ -64,10 +70,10 @@ void View::DrawManual()
level--;
}
if( m_manualPositionReset && i < m_activeManualChunk && chunk.level < chunks[m_activeManualChunk].level )
if( m_positionReset && i < m_activeChunk && chunk.level < chunks[m_activeChunk].level )
{
bool ancestor = true;
for( size_t j = i+1; j < m_activeManualChunk; j++ )
for( size_t j = i+1; j < m_activeChunk; j++ )
{
if( chunks[j].level <= chunk.level )
{
@@ -81,16 +87,16 @@ void View::DrawManual()
ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
const bool isLeaf = i == ( chunks.size() - 1 ) || chunks[i+1].level <= chunk.level;
if( isLeaf ) flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen;
if( i == m_activeManualChunk ) flags |= ImGuiTreeNodeFlags_Selected;
if( i == m_activeChunk ) flags |= ImGuiTreeNodeFlags_Selected;
if( ImGui::TreeNodeEx( tmp, flags ) )
{
if( !isLeaf ) level++;
}
if( m_manualPositionReset && i == m_activeManualChunk ) ImGui::SetScrollHereY();
if( m_positionReset && i == m_activeChunk ) ImGui::SetScrollHereY();
if( ImGui::IsItemClicked() && !ImGui::IsItemToggledOpen() )
{
m_activeManualChunk = i;
m_manualPositionReset = true;
m_activeChunk = i;
m_positionReset = true;
}
}
while( level-- > 0 ) ImGui::TreePop();
@@ -99,15 +105,15 @@ void View::DrawManual()
ImGui::NextColumn();
ImGui::BeginChild( "##content", ImVec2( 0, 0 ), ImGuiChildFlags_AlwaysUseWindowPadding );
if( m_manualPositionReset )
if( m_positionReset )
{
ImGui::SetScrollY( 0 );
m_manualPositionReset = false;
m_positionReset = false;
}
auto& chunk = chunks[m_activeManualChunk];
auto& chunk = chunks[m_activeChunk];
if( m_activeManualChunk == 0 )
if( m_activeChunk == 0 )
{
ImageCentered( GetProfilerIconTexture(), ImVec2( 80 * scale, 80 * scale ) );
ImGui::Dummy( ImVec2( 0, ImGui::GetTextLineHeight() * 0.5f ) );
@@ -148,7 +154,7 @@ void View::DrawManual()
const auto separator = chunk.text.find( "\n-----" );
const auto size = separator == std::string::npos ? chunk.text.size() : ( separator + 1 );
m_markdown.Print( chunk.text.c_str(), size );
md.Print( chunk.text.c_str(), size );
}
ImGui::EndChild();
@@ -157,24 +163,23 @@ void View::DrawManual()
ImGui::End();
}
const TracyManualData::ManualChunk* View::GetManualChunk( const char* anchor ) const
const TracyManualData::ManualChunk* ManualWindow::GetChunk( const char* anchor ) const
{
assert( anchor && *anchor );
auto& chunks = m_manualData.GetChunks();
auto& chunks = m_manual.GetChunks();
auto it = std::ranges::find_if( chunks, [anchor]( const auto& chunk ) { return chunk.link == anchor; } );
if( it != chunks.end() ) return &*it;
return nullptr;
}
bool View::ViewManualChunk( const char* anchor )
bool ManualWindow::Navigate( const char* anchor )
{
assert( anchor && *anchor );
const auto chunk = GetManualChunk( anchor );
const auto chunk = GetChunk( anchor );
if( !chunk ) return false;
m_activeManualChunk = std::distance( m_manualData.GetChunks().data(), chunk );
m_showManual = true;
m_manualPositionReset = true;
m_activeChunk = std::distance( m_manual.GetChunks().data(), chunk );
m_show = true;
m_positionReset = true;
return true;
}

View File

@@ -0,0 +1,33 @@
#ifndef __TRACYMANUALWINDOW_HPP__
#define __TRACYMANUALWINDOW_HPP__
#include <stddef.h>
#include "TracyManualData.hpp"
namespace tracy
{
class Markdown;
class ManualWindow
{
public:
explicit ManualWindow( const TracyManualData& manual );
void Draw( Markdown& md );
bool& Show() { return m_show; }
bool Navigate( const char* anchor );
const TracyManualData::ManualChunk* GetChunk( const char* anchor ) const;
private:
const TracyManualData& m_manual;
size_t m_activeChunk = 0;
bool m_positionReset = true;
bool m_show = false;
};
}
#endif

View File

@@ -3,6 +3,7 @@
#include <string>
#include <string.h>
#include <vector>
#include "TracyManualWindow.hpp"
#include "TracyFilesystem.hpp"
#include "TracyMarkdown.hpp"
@@ -52,7 +53,7 @@ class MarkdownContext
};
public:
MarkdownContext( View* view, Worker* worker ) : m_view( view ), m_worker( worker ) {}
MarkdownContext( View* view, Worker* worker, ManualWindow* manualWindow ) : m_view( view ), m_worker( worker ), m_manualWindow( manualWindow ) {}
int EnterBlock( MD_BLOCKTYPE type, void* detail )
{
@@ -470,7 +471,7 @@ private:
void LinkHover()
{
const auto isSource = link.starts_with( "source:" ) && m_view && m_worker;
const auto isAnchor = link.starts_with( "#" ) && m_view;
const auto isAnchor = link.starts_with( "#" ) && m_manualWindow;
StringIdx idx;
uint32_t lineStart = 0;
uint32_t lineEnd = 0;
@@ -520,7 +521,7 @@ private:
}
else if( isAnchor )
{
auto chunk = m_view->GetManualChunk( link.c_str() );
auto chunk = m_manualWindow->GetChunk( link.c_str() );
if( chunk )
{
if( chunk->section.empty() )
@@ -557,7 +558,7 @@ private:
}
else if( isAnchor )
{
m_view->ViewManualChunk( link.c_str() );
m_manualWindow->Navigate( link.c_str() );
}
else
{
@@ -587,13 +588,15 @@ private:
View* m_view;
Worker* m_worker;
ManualWindow* m_manualWindow;
};
Markdown::Markdown( View* view, Worker* worker )
Markdown::Markdown( View* view, Worker* worker, ManualWindow* manualWindow )
: m_parser( new MD_PARSER() )
, m_view( view )
, m_worker( worker )
, m_manualWindow( manualWindow )
{
memset( m_parser, 0, sizeof( MD_PARSER ) );
m_parser->flags = MD_FLAG_COLLAPSEWHITESPACE | MD_FLAG_PERMISSIVEAUTOLINKS | MD_FLAG_NOHTML | MD_FLAG_TABLES | MD_FLAG_TASKLISTS | MD_FLAG_STRIKETHROUGH | MD_FLAG_FOOTNOTES | MD_FLAG_ADMONITIONS;
@@ -613,7 +616,7 @@ void Markdown::Print( const char* str, size_t size )
{
ImGui::PushStyleVar( ImGuiStyleVar_ItemSpacing, ImVec2( ImGui::GetStyle().ItemSpacing.x, 0.0f ) );
MarkdownContext md( m_view, m_worker );
MarkdownContext md( m_view, m_worker, m_manualWindow );
md_parse( str, size, m_parser, &md );
ImGui::PopStyleVar();

View File

@@ -8,13 +8,14 @@ struct MD_PARSER;
namespace tracy
{
class ManualWindow;
class View;
class Worker;
class Markdown
{
public:
Markdown( View* view, Worker* worker );
Markdown( View* view, Worker* worker, ManualWindow* manualWindow = nullptr );
~Markdown();
void Print( const char* str, size_t size );
@@ -23,6 +24,7 @@ private:
MD_PARSER* m_parser;
View* m_view;
Worker* m_worker;
ManualWindow* m_manualWindow;
};
}

View File

@@ -55,7 +55,8 @@ View::View( void(*cbMainThread)(const std::function<void()>&, bool), const char*
, m_horizontalScrollMultiplier( s_config.horizontalScrollMultiplier )
, m_verticalScrollMultiplier( s_config.verticalScrollMultiplier )
, m_manualData( GetManualData() )
, m_markdown( this, &m_worker )
, m_manualWindow( m_manualData )
, m_markdown( this, &m_worker, &m_manualWindow )
#ifdef __EMSCRIPTEN__
, m_td( 2, "ViewMt" )
#else
@@ -87,7 +88,8 @@ View::View( void(*cbMainThread)(const std::function<void()>&, bool), FileRead& f
, m_horizontalScrollMultiplier( s_config.horizontalScrollMultiplier )
, m_verticalScrollMultiplier( s_config.verticalScrollMultiplier )
, m_manualData( GetManualData() )
, m_markdown( this, &m_worker )
, m_manualWindow( m_manualData )
, m_markdown( this, &m_worker, &m_manualWindow )
#ifdef __EMSCRIPTEN__
, m_td( 2, "ViewMt" )
#else
@@ -1017,7 +1019,7 @@ bool View::DrawImpl()
ImGui::EndPopup();
}
ImGui::SameLine();
ToggleButton( ICON_FA_BOOK, m_showManual );
ToggleButton( ICON_FA_BOOK, m_manualWindow.Show() );
if( m_sscb )
{
ImGui::SameLine();
@@ -1234,7 +1236,7 @@ bool View::DrawImpl()
if( m_sampleParents.symAddr != 0 ) DrawSampleParents();
if( m_showRanges ) DrawRanges();
if( m_showWaitStacks ) DrawWaitStacks();
if( m_showManual ) DrawManual();
if( m_manualWindow.Show() ) m_manualWindow.Draw( m_markdown );
if( m_showFrameStatistics ) DrawFrameStatistics();
#ifndef __EMSCRIPTEN__
if( m_llm.m_show ) m_llm.Draw( m_llmConstraint );

View File

@@ -19,6 +19,7 @@
#include "TracyConfig.hpp"
#include "TracyDecayValue.hpp"
#include "TracyManualData.hpp"
#include "TracyManualWindow.hpp"
#include "TracyMarkdown.hpp"
#include "TracySourceContents.hpp"
#include "TracyTimelineController.hpp"
@@ -167,8 +168,7 @@ public:
void ViewSymbol( const char* fileName, int line, uint64_t baseAddr, uint64_t symAddr );
bool ViewDispatch( const char* fileName, int line, uint64_t symAddr );
const TracyManualData::ManualChunk* GetManualChunk( const char* anchor ) const;
bool ViewManualChunk( const char* anchor );
ManualWindow& GetManualWindow() { return m_manualWindow; }
bool ReconnectRequested() const { return m_reconnectRequested; }
std::string GetAddress() const { return m_worker.GetAddr(); }
@@ -366,7 +366,6 @@ private:
void DrawRangeEntry( Range& range, const char* label, const char* tooltip, uint32_t color, int id );
bool ShouldDrawRange( const RangeId& id ) const;
void DrawWaitStacks();
void DrawManual();
void DrawFrameStatistics();
void DrawFlameGraph();
void DrawFlameGraphHeader( int64_t vStart, int64_t vEnd );
@@ -657,8 +656,6 @@ private:
bool m_showAnnotationList = false;
bool m_showWaitStacks = false;
bool m_showFlameGraph = false;
bool m_showManual = false;
bool m_manualPositionReset = false;
bool m_showFrameStatistics = false;
AccumulationMode m_statAccumulationMode = AccumulationMode::SelfOnly;
@@ -1084,7 +1081,7 @@ private:
double m_verticalScrollMultiplier = 1.0;
const TracyManualData& m_manualData;
size_t m_activeManualChunk = 0;
ManualWindow m_manualWindow;
Markdown m_markdown;
TaskDispatch m_td;