#include "util.h"
using namespace empathy;
using namespace empathy::util;
namespace empathy::util::colors
{
const char* base00 = "181818";
const char* base01 = "282828";
const char* base02 = "383838";
const char* base03 = "585858";
const char* base04 = "b8b8b8";
const char* base05 = "d8d8d8";
const char* base06 = "e8e8e8";
const char* base07 = "f8f8f8";
const char* base08 = "ab4642";
const char* base09 = "dc9656";
const char* base0A = "f7ca88";
const char* base0B = "a1b56c";
const char* base0C = "86c1b9";
const char* base0D = "7cafc2";
const char* base0E = "ba8baf";
const char* base0F = "a16946";
}
namespace
{
const char* accent_colors[] =
{
colors::base08,
colors::base09,
colors::base0A,
colors::base0B,
colors::base0C,
colors::base0D,
colors::base0E,
colors::base0F
};
}
namespace empathy::util
{
const char* GraphVizBuilder::BGColor = colors::base00;
const char* GraphVizBuilder::TextColor = colors::base05;
GraphVizBuilder::GraphVizBuilder( ostream& output, bool vertical ) :
m_output( output )
{
m_output <<
"digraph \"empathy\"\n"
"{\n"
"\tbgcolor=\"#" << BGColor << "\";\n"
"\trankdir=" << ( vertical ? "TB" : "LR" ) << ";\n"
"\tnode [ shape=none ];\n"
"\tedge [ color=\"#" << TextColor << "\" ];\n";
}
GraphVizBuilder::~GraphVizBuilder()
{
while( !m_workQueue.empty() )
{
m_workQueue.front()();
m_workQueue.pop();
}
m_output << "\n}\n";
}
ostream& GraphVizBuilder::indent() const
{
for( auto i = 0; i < m_indention; ++i )
m_output << '\t';
return m_output;
}
ostream& GraphVizBuilder::newLine() const
{
m_output << '\n';
return indent();
}
const char* GraphVizBuilder::GetNodeColor( uint32_t id )
{
return accent_colors[ id % ( sizeof( accent_colors ) / sizeof( const char* ) ) ];
}
uint32_t GraphVizBuilder::getNodeId( const void* pNodeAddress )
{
auto it = m_nodesDict.find( pNodeAddress );
if( it != m_nodesDict.end() )
return it->second;
auto id = m_nodeCount++;
m_nodesDict.emplace( pNodeAddress, id );
return id;
}
bool GraphVizBuilder::wasNodeGenerated( const void* pNodeAddress ) const
{
return m_generatedNodes.find( pNodeAddress ) != m_generatedNodes.end();
}
void GraphVizBuilder::addEdge( uint32_t fromId, uint32_t toId )
{
auto portId = m_portCount - 1;
queueWork( [=]
{
newLine()
<< "object" << fromId << ':' << portId
<< " -> object" << toId
<< "[ color=\"#" << GetNodeColor( toId ) << "\" ]";
} );
}
GraphVizBuilder::Indention::Indention( GraphVizBuilder& builder ) :
m_builder( builder )
{
++m_builder.m_indention;
}
GraphVizBuilder::Indention::~Indention()
{
--m_builder.m_indention;
}
GraphVizBuilder::Table::Table( GraphVizBuilder& builder, const char* pColor ) :
m_builder( builder )
{
m_builder.newLine() <<
"<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
" color=\"#" << pColor << "\">";
++m_builder.m_indention;
}
GraphVizBuilder::Table::~Table()
{
--m_builder.m_indention;
m_builder.newLine() << "</table>";
}
GraphVizBuilder::Row::Row( GraphVizBuilder& builder ) :
m_builder( builder )
{
m_builder.newLine() << "<tr>";
++m_builder.m_indention;
}
GraphVizBuilder::Row::~Row()
{
--m_builder.m_indention;
m_builder.newLine() << "</tr>";
}
GraphVizBuilder::Cell::Cell( GraphVizBuilder& builder ) :
m_builder( builder )
{
m_builder.newLine() << "<td port=\"" << m_builder.m_portCount++ << "\">";
++m_builder.m_indention;
}
GraphVizBuilder::Cell::~Cell()
{
--m_builder.m_indention;
m_builder.newLine() << "</td>";
}
GraphVizBuilder::Color::Color( GraphVizBuilder& builder, const char* pColor ) :
m_builder( builder )
{
m_builder.newLine()
<< "<font face=\"Noto Sans\" point-size=\"12\" color=\"#" << pColor << "\">";
++m_builder.m_indention;
}
GraphVizBuilder::Color::~Color()
{
--m_builder.m_indention;
m_builder.newLine() << "</font>";
}
GraphVizBuilder::Node::Node( GraphVizBuilder& builder, const void* pAddress, const char* pTitle ) :
m_builder( builder )
{
m_builder.m_generatedNodes.insert( pAddress );
m_builder.m_currentNode = m_builder.getNodeId( pAddress );
m_builder.newLine() << "object" << m_builder.m_currentNode;
m_builder.newLine() << "[ label=<";
++m_builder.m_indention;
auto color = GetNodeColor( m_builder.m_currentNode ) ;
m_builder.newLine() <<
"<table border=\"0\" cellborder=\"1\" cellspacing=\"0\""
" color=\"#" << color << "\">";
++m_builder.m_indention;
if( pTitle )
{
Row row( m_builder );
Cell cell( m_builder );
Color c( m_builder, color );
m_builder.m_output << m_builder.m_currentNode << ": " << pTitle;
}
}
GraphVizBuilder::Node::~Node()
{
--m_builder.m_indention;
m_builder.newLine() << "</table>";
--m_builder.m_indention;
m_builder.newLine() << "> ]";
}
}