0
0
mirror of https://github.com/yse/easy_profiler.git synced 2024-12-26 16:11:02 +08:00

(GraphicsView) Fixed test();

(GraphicsView) Added a lot of comments;
(GraphicsView) Changed base unit from milliseconds to microseconds;
(GraphicsScrollbar) Fixed fluttering on very small scale;
(GraphicsView)+(TreeWidget) Chronometer item behavior: if selection made from left to right - selecting all items by intersection with rectangle; if selection made from right to left - selecting all items which are strictly inside selection rectangle.
This commit is contained in:
Victor Zarubkin 2016-08-01 22:21:59 +03:00
parent 7bf8d871c1
commit b0f6b3f268
7 changed files with 565 additions and 220 deletions

View File

@ -39,14 +39,21 @@
const qreal SCALING_COEFFICIENT = 1.25;
const qreal SCALING_COEFFICIENT_INV = 1.0 / SCALING_COEFFICIENT;
const qreal MIN_SCALE = pow(SCALING_COEFFICIENT_INV, 70);
const qreal MAX_SCALE = pow(SCALING_COEFFICIENT, 30); // ~800
const qreal BASE_SCALE = pow(SCALING_COEFFICIENT_INV, 25); // ~0.003
const unsigned short GRAPHICS_ROW_SIZE = 16;
const unsigned short GRAPHICS_ROW_SIZE_FULL = GRAPHICS_ROW_SIZE + 2;
const unsigned short ROW_SPACING = 4;
const QRgb BORDERS_COLOR = 0x00a07050;
const QRgb BACKGROUND_1 = 0x00f8f8f8;
const QRgb BACKGROUND_2 = 0x00ffffff;// 0x00e0e0e0;
const QRgb BACKGROUND_1 = 0x00d8d8d8;
const QRgb BACKGROUND_2 = 0x00ffffff;
const QColor CHRONOMETER_COLOR = QColor(64, 64, 64, 64);
const QRgb CHRONOMETER_TEXT_COLOR = 0xff302010;
const int TEST_PROGRESSION_BASE = 4;
//////////////////////////////////////////////////////////////////////////
@ -56,6 +63,15 @@ auto const clamp = [](qreal _minValue, qreal _value, qreal _maxValue) { return _
//////////////////////////////////////////////////////////////////////////
template <int N, class T>
inline T logn(T _value)
{
static const double div = 1.0 / log2((double)N);
return log2(_value) * div;
}
//////////////////////////////////////////////////////////////////////////
QRgb BG1();
QRgb BG2();
QRgb (*GetBackgroundColor)() = BG1;
@ -171,7 +187,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
m_levelsIndexes[i] = -1;
// Search for first visible top item
// Search for first visible top-level item
auto& level0 = m_levels[0];
auto first = ::std::lower_bound(level0.begin(), level0.end(), sceneLeft, [](const ProfBlockItem& _item, qreal _value)
{
@ -203,7 +219,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
// (it seems there is a bug in Qt5.6 when drawText called for big coordinates,
// drawRect at the same time called for actually same coordinates
// works fine without using this additional shifting)
const auto dx = level0[m_levelsIndexes[0]].left() * currentScale;
auto dx = level0[m_levelsIndexes[0]].left() * currentScale;
// Shifting coordinates to current screen offset
_painter->setTransform(QTransform::fromTranslate(dx - offset * currentScale, -y()), true);
@ -229,6 +245,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
if (item.right() < sceneLeft || state == -1 || (l == 0 && (item.top() > visibleSceneRect.bottom() || (item.top() + item.totalHeight) < visibleSceneRect.top())))
{
// This item is not visible
++m_levelsIndexes[l];
continue;
}
@ -239,6 +256,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
// Items which width is less than 20 will be painted as big rectangles which are hiding it's children
if (item.left() > sceneRight)
{
// This is first totally invisible item. No need to check other items.
break;
}
@ -256,6 +274,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
if (previousColor != item.color)
{
// Set background color brush for rectangle
previousColor = item.color;
brush.setColor(previousColor);
_painter->setBrush(brush);
@ -263,6 +282,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
if (w < 3)
{
// Do not paint borders for very narrow items
if (previousPenStyle != Qt::NoPen)
{
previousPenStyle = Qt::NoPen;
@ -271,15 +291,18 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
}
else if (previousPenStyle != Qt::SolidLine)
{
// Restore pen for item which is wide enough to paint borders
previousPenStyle = Qt::SolidLine;
_painter->setPen(BORDERS_COLOR);
}
// Draw rectangle
rect.setRect(x, item.top(), w, item.totalHeight);
_painter->drawRect(rect);
if (next_level < levelsNumber && item.children_begin != -1)
{
// Mark that we would not paint children of current item
m_levels[next_level][item.children_begin].state = -1;
}
@ -290,14 +313,17 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
{
if (m_levelsIndexes[next_level] == -1)
{
// Mark first potentially visible child item on next sublevel
m_levelsIndexes[next_level] = item.children_begin;
}
// Mark children items that we want to draw them
m_levels[next_level][item.children_begin].state = 1;
}
if (item.left() > sceneRight)
{
// This is first totally invisible item. No need to check other items.
break;
}
@ -310,11 +336,14 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
//} else
if (previousColor != item.color)
{
// Set background color brush for rectangle
previousColor = item.color;
brush.setColor(previousColor);
_painter->setBrush(brush);
}
// Draw text-----------------------------------
// calculating text coordinates
const auto x = item.left() * currentScale - dx;
rect.setRect(x, item.top(), w, item.height());
_painter->drawRect(rect);
@ -322,16 +351,20 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
auto xtext = x;
if (item.left() < sceneLeft)
{
// if item left border is out of screen then attach text to the left border of the screen
// to ensure text is always visible for items presenting on the screen.
w += (item.left() - sceneLeft) * currentScale;
xtext = sceneLeft * currentScale - dx;
}
rect.setRect(xtext, item.top(), w, item.height());
rect.setRect(xtext + 1, item.top(), w - 1, item.height());
// text will be painted with inverse color
auto textColor = 0x00ffffff - previousColor;
if (textColor == previousColor) textColor = 0;
_painter->setPen(textColor); // Text is painted with inverse color
_painter->setPen(textColor);
// drawing text
if (m_bTest)
{
char text[128] = {0};
@ -343,6 +376,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
_painter->drawText(rect, 0, item.block->node->getBlockName());
}
// restore previous pen color
if (previousPenStyle == Qt::NoPen)
{
_painter->setPen(Qt::NoPen);
@ -351,6 +385,7 @@ void ProfGraphicsItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*
{
_painter->setPen(BORDERS_COLOR); // restore pen for rectangle painting
}
// END Draw text~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
}
}
@ -366,7 +401,7 @@ void ProfGraphicsItem::getBlocks(qreal _left, qreal _right, TreeBlocks& _blocks)
// return;
//}
// Search for first top item
// Search for first visible top-level item
auto& level0 = m_levels[0];
auto first = ::std::lower_bound(level0.begin(), level0.end(), _left, [](const ProfBlockItem& _item, qreal _value)
{
@ -385,17 +420,21 @@ void ProfGraphicsItem::getBlocks(qreal _left, qreal _right, TreeBlocks& _blocks)
itemIndex = level0.size() - 1;
}
// Add all visible top-level items into array of visible blocks
for (size_t i = itemIndex, end = level0.size(); i < end; ++i)
{
const auto& item = level0[i];
if (item.left() > _right)
{
// First invisible item. No need to check other items.
break;
}
if (item.right() < _left)
{
// This item is not visible yet
// This is just to be sure
continue;
}
@ -500,50 +539,50 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
if (m_left > sceneRight || m_right < sceneLeft)
{
// This item is out of screen
return;
}
const auto time = width();
QRectF rect(m_left * currentScale, visibleSceneRect.top(), ::std::max(time * currentScale, 1.0), visibleSceneRect.height());
const auto selectedInterval = width();
QRectF rect((m_left - offset) * currentScale, visibleSceneRect.top(), ::std::max(selectedInterval * currentScale, 1.0), visibleSceneRect.height());
QString text;
if (time < 1e-3)
{
text = ::std::move(QString("%1 ns").arg(time * 1e6, 0, 'f', 1));
}
else if (time < 1)
{
text = ::std::move(QString("%1 us").arg(time * 1e3, 0, 'f', 1));
}
else if (time < 1e3)
{
text = ::std::move(QString("%1 ms").arg(time, 0, 'f', 1));
}
else
{
text = ::std::move(QString("%1 sec").arg(time * 1e-3, 0, 'f', 1));
}
QString text; // Displayed text
if (selectedInterval < 1.0) // interval in nanoseconds
text = ::std::move(QString("%1 ns").arg(selectedInterval * 1e3, 0, 'f', 1));
else if (selectedInterval < 1e3) // interval in microseconds
text = ::std::move(QString("%1 us").arg(selectedInterval, 0, 'f', 1));
else if (selectedInterval < 1e6) // interval in milliseconds
text = ::std::move(QString("%1 ms").arg(selectedInterval * 1e-3, 0, 'f', 1));
else // interval in seconds
text = ::std::move(QString("%1 sec").arg(selectedInterval * 1e-6, 0, 'f', 1));
const auto textRect = QFontMetrics(m_font).boundingRect(text);
const auto textRect = QFontMetrics(m_font).boundingRect(text); // Calculate displayed text boundingRect
// Paint!--------------------------
_painter->save();
_painter->setTransform(QTransform::fromTranslate(-x() - offset * currentScale, -y()), true);
_painter->setBrush(QColor(64, 64, 64, 64));
// instead of scrollbar we're using manual offset
_painter->setTransform(QTransform::fromTranslate(-x(), -y()), true);
// draw transparent rectangle
_painter->setBrush(CHRONOMETER_COLOR);
_painter->setPen(Qt::NoPen);
_painter->drawRect(rect);
_painter->setPen(0xff302010);
// draw text
_painter->setPen(CHRONOMETER_TEXT_COLOR);
_painter->setFont(m_font);
//if (m_left > sceneLeft && m_right < sceneRight)
{
if (textRect.width() < rect.width())
{
// Text will be drawed inside rectangle
_painter->drawText(rect, Qt::AlignCenter, text);
}
else
{
// Text will be drawed aside of rectangle
_painter->drawText(QPointF(rect.right(), rect.top() + rect.height() * 0.5 + textRect.height() * 0.33), text);
}
}
@ -563,6 +602,7 @@ void ProfChronometerItem::paint(QPainter* _painter, const QStyleOptionGraphicsIt
//}
_painter->restore();
// END Paint!~~~~~~~~~~~~~~~~~~~~~~
}
void ProfChronometerItem::setBoundingRect(qreal x, qreal y, qreal w, qreal h)
@ -608,13 +648,14 @@ ProfGraphicsView::ProfGraphicsView(bool _test)
, m_bUpdatingRect(false)
, m_bTest(_test)
, m_bEmpty(true)
, m_bStrictSelection(false)
{
initMode();
setScene(new QGraphicsScene(this));
if (_test)
{
test(18000, 40000000, 5);
test(18000, 40000000, 2);
}
updateVisibleSceneRect();
@ -632,6 +673,7 @@ ProfGraphicsView::ProfGraphicsView(const thread_blocks_tree_t& _blocksTree)
, m_bUpdatingRect(false)
, m_bTest(false)
, m_bEmpty(true)
, m_bStrictSelection(false)
{
initMode();
setScene(new QGraphicsScene(this));
@ -645,10 +687,10 @@ ProfGraphicsView::~ProfGraphicsView()
//////////////////////////////////////////////////////////////////////////
void fillChildren(ProfGraphicsItem* _item, int _level, qreal _x, qreal _y, size_t _childrenNumber, size_t& _total_items)
void ProfGraphicsView::fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, size_t _childrenNumber, size_t& _total_items)
{
size_t nchildren = _childrenNumber;
_childrenNumber >>= 1;
_childrenNumber = TEST_PROGRESSION_BASE;
for (size_t i = 0; i < nchildren; ++i)
{
@ -657,12 +699,12 @@ void fillChildren(ProfGraphicsItem* _item, int _level, qreal _x, qreal _y, size_
b.color = toRgb(30 + rand() % 225, 30 + rand() % 225, 30 + rand() % 225);
b.state = 0;
if (_childrenNumber > 0)
if (_level < _maxlevel)
{
const auto& children = _item->items(_level + 1);
b.children_begin = static_cast<unsigned int>(children.size());
fillChildren(_item, _level + 1, _x, _y + GRAPHICS_ROW_SIZE_FULL, _childrenNumber, _total_items);
fillTestChildren(_item, _maxlevel, _level + 1, _x, _y + GRAPHICS_ROW_SIZE_FULL, _childrenNumber, _total_items);
const auto& last = children.back();
b.setRect(_x, _y, last.right() - _x, GRAPHICS_ROW_SIZE);
@ -670,7 +712,7 @@ void fillChildren(ProfGraphicsItem* _item, int _level, qreal _x, qreal _y, size_
}
else
{
b.setRect(_x, _y, 10 + rand() % 40, GRAPHICS_ROW_SIZE);
b.setRect(_x, _y, to_microseconds(10 + rand() % 190), GRAPHICS_ROW_SIZE);
b.totalHeight = GRAPHICS_ROW_SIZE;
b.children_begin = -1;
}
@ -680,71 +722,112 @@ void fillChildren(ProfGraphicsItem* _item, int _level, qreal _x, qreal _y, size_
}
}
void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_estimate, int _depth)
void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_estimate, int _rows)
{
static const qreal X_BEGIN = 50;
static const qreal Y_BEGIN = 0;
const auto children_per_frame = _total_items_number_estimate / _frames_number;
const size_t first_level_children_count = sqrt(pow(2, _depth - 1)) * pow(children_per_frame, 1.0 / double(_depth)) + 0.5;
clearSilent(); // Clear scene
auto item = new ProfGraphicsItem(true);
item->setPos(0, Y_BEGIN);
// Calculate items number for first level
_rows = ::std::max(1, _rows);
const size_t children_per_frame = static_cast<size_t>(0.5 + static_cast<double>(_total_items_number_estimate) / static_cast<double>(_rows * _frames_number));
const int max_depth = logn<TEST_PROGRESSION_BASE>(children_per_frame * (TEST_PROGRESSION_BASE - 1) * 0.5 + 1);
const size_t first_level_children_count = children_per_frame * (1.0 - TEST_PROGRESSION_BASE) / (1.0 - pow(TEST_PROGRESSION_BASE, max_depth)) + 0.5;
item->setLevels(_depth + 1);
item->reserve(0, _frames_number);
::std::vector<ProfGraphicsItem*> thread_items(_rows);
for (int i = 0; i < _rows; ++i)
{
auto item = new ProfGraphicsItem(true);
thread_items[i] = item;
item->setPos(0, Y_BEGIN + i * (max_depth * GRAPHICS_ROW_SIZE_FULL + ROW_SPACING * 5));
item->setLevels(max_depth + 1);
item->reserve(0, _frames_number);
}
// Calculate items number for each sublevel
size_t chldrn = first_level_children_count;
size_t tot = first_level_children_count;
for (int i = 1; i <= _depth; ++i)
for (int i = 1; i <= max_depth; ++i)
{
item->reserve(i, tot * _frames_number);
chldrn >>= 1;
tot *= chldrn;
for (int i = 0; i < _rows; ++i)
{
auto item = thread_items[i];
item->reserve(i, chldrn * _frames_number);
}
chldrn *= TEST_PROGRESSION_BASE;
}
// Create required number of items
size_t total_items = 0;
qreal x = X_BEGIN;
for (unsigned int i = 0; i < _frames_number; ++i)
qreal maxX = 0;
for (int i = 0; i < _rows; ++i)
{
size_t j = item->addItem(0);
auto& b = item->getItem(0, j);
b.color = toRgb(30 + rand() % 225, 30 + rand() % 225, 30 + rand() % 225);
b.state = 0;
auto item = thread_items[i];
qreal x = X_BEGIN, y = item->y();
for (unsigned int i = 0; i < _frames_number; ++i)
{
size_t j = item->addItem(0);
auto& b = item->getItem(0, j);
b.color = toRgb(30 + rand() % 225, 30 + rand() % 225, 30 + rand() % 225);
b.state = 0;
const auto& children = item->items(1);
b.children_begin = static_cast<unsigned int>(children.size());
const auto& children = item->items(1);
b.children_begin = static_cast<unsigned int>(children.size());
fillChildren(item, 1, x, Y_BEGIN + GRAPHICS_ROW_SIZE_FULL, first_level_children_count, total_items);
fillTestChildren(item, max_depth, 1, x, y + GRAPHICS_ROW_SIZE_FULL, first_level_children_count, total_items);
const auto& last = children.back();
b.setRect(x, Y_BEGIN, last.right() - x, GRAPHICS_ROW_SIZE);
b.totalHeight = GRAPHICS_ROW_SIZE_FULL + last.totalHeight;
const auto& last = children.back();
b.setRect(x, y, last.right() - x, GRAPHICS_ROW_SIZE);
b.totalHeight = GRAPHICS_ROW_SIZE_FULL + last.totalHeight;
x += b.width() + 500;
x += b.width() * 1.2;
++total_items;
++total_items;
}
const auto h = item->getItem(0, 0).totalHeight;
item->setBoundingRect(0, 0, x, h);
if (_rows > 1)
{
item->setBackgroundColor(GetBackgroundColor());
}
m_items.push_back(item);
scene()->addItem(item);
if (maxX < x)
{
maxX = x;
}
}
const auto h = item->getItem(0, 0).totalHeight;
item->setBoundingRect(0, 0, x, h);
printf("TOTAL ITEMS = %llu\n", total_items);
clearSilent();
m_items.push_back(item);
scene()->addItem(item);
scene()->setSceneRect(0, 0, x, Y_BEGIN + h);
// Calculate scene rect
auto item = thread_items.back();
scene()->setSceneRect(0, 0, maxX, item->y() + item->getItem(0, 0).totalHeight);
// Reset necessary values
m_offset = 0;
updateVisibleSceneRect();
setScrollbar(m_pScrollbar);
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
// It will be shown on mouse right button click.
m_chronometerItem = new ProfChronometerItem();
m_chronometerItem->setZValue(10);
m_chronometerItem->setBoundingRect(scene()->sceneRect());
m_chronometerItem->hide();
scene()->addItem(m_chronometerItem);
// Set necessary flags
m_bTest = true;
m_bEmpty = false;
scaleTo(BASE_SCALE);
}
//////////////////////////////////////////////////////////////////////////
@ -752,15 +835,28 @@ void ProfGraphicsView::test(size_t _frames_number, size_t _total_items_number_es
void ProfGraphicsView::clearSilent()
{
const QSignalBlocker blocker(this), sceneBlocker(scene()); // block all scene signals (otherwise clear() would be extremely slow!)
GetBackgroundColor = BG1; // reset background color
// Stop flicking
m_flickerTimer.stop();
m_flickerSpeed = 0;
// Clear all items
scene()->clear();
m_items.clear();
m_selectedBlocks.clear();
m_beginTime = -1; // reset begin time
m_scale = 1; // scale back to initial 100% scale
m_offset = 0; // scroll back to the beginning of the scene
// Reset necessary flags
m_bTest = false;
m_bEmpty = true;
emit treeblocksChanged(m_selectedBlocks, m_beginTime);
// notify ProfTreeWidget that selection was reset
emit intervalChanged(m_selectedBlocks, m_beginTime, 0, 0, false);
}
void ProfGraphicsView::setTree(const thread_blocks_tree_t& _blocksTree)
@ -811,21 +907,21 @@ void ProfGraphicsView::setTree(const thread_blocks_tree_t& _blocksTree)
}
// Calculating scene rect
const qreal endX = time2position(finish + 1000000);
const qreal endX = time2position(finish) + 1.0;
scene()->setSceneRect(0, 0, endX, y);
// Painting stub...
// Stub! :O
for (auto item : m_items)
{
item->setBoundingRect(0, 0, endX, item->boundingRect().height());
}
// Center view on the beginning of the scene
m_offset = 0;
updateVisibleSceneRect();
setScrollbar(m_pScrollbar);
// Adding invisible chronometer item (it will be shown on mouse right button click)
// Create new chronometer item (previous item was destroyed by scene on scene()->clear()).
// It will be shown on mouse right button click.
m_chronometerItem = new ProfChronometerItem();
m_chronometerItem->setZValue(10);
m_chronometerItem->setBoundingRect(scene()->sceneRect());
@ -835,10 +931,14 @@ void ProfGraphicsView::setTree(const thread_blocks_tree_t& _blocksTree)
// Setting flags
m_bTest = false;
m_bEmpty = false;
scaleTo(BASE_SCALE);
}
qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const BlocksTree::children_t& _children, qreal& _height, qreal _y, unsigned short _level)
{
static const qreal MIN_DURATION = 0.25;
if (_children.empty())
{
return 0;
@ -866,9 +966,9 @@ qreal ProfGraphicsView::setTree(ProfGraphicsItem* _item, const BlocksTree::child
xbegin -= dt;
}
if (duration < 0.1)
if (duration < MIN_DURATION)
{
duration = 0.1;
duration = MIN_DURATION;
}
auto i = _item->addItem(_level);
@ -940,6 +1040,25 @@ void ProfGraphicsView::updateScene()
//////////////////////////////////////////////////////////////////////////
void ProfGraphicsView::scaleTo(qreal _scale)
{
if (m_bEmpty)
{
return;
}
// have to limit scale because of Qt's QPainter feature: it doesn't draw text
// with very big coordinates (but it draw rectangles with the same coordinates good).
m_scale = clamp(MIN_SCALE, _scale, MAX_SCALE);
updateVisibleSceneRect();
// Update slider width for scrollbar
const auto windowWidth = m_visibleSceneRect.width() / m_scale;
m_pScrollbar->setSliderWidth(windowWidth);
updateScene();
}
void ProfGraphicsView::wheelEvent(QWheelEvent* _event)
{
if (m_bEmpty)
@ -954,9 +1073,9 @@ void ProfGraphicsView::wheelEvent(QWheelEvent* _event)
const auto mouseX = mapToScene(_event->pos()).x();
const auto mousePosition = m_offset + mouseX / m_scale;
m_bUpdatingRect = true; // To be sure that updateVisibleSceneRect will not be called by scrollbar change
m_scale *= scaleCoeff;
m_bUpdatingRect = false;
// have to limit scale because of Qt's QPainter feature: it doesn't draw text
// with very big coordinates (but it draw rectangles with the same coordinates good).
m_scale = clamp(MIN_SCALE, m_scale * scaleCoeff, MAX_SCALE);
updateVisibleSceneRect(); // Update scene rect
@ -968,7 +1087,7 @@ void ProfGraphicsView::wheelEvent(QWheelEvent* _event)
m_offset = clamp(0., mousePosition - mouseX / m_scale, scene()->width() - windowWidth);
// Update slider position
m_bUpdatingRect = true;
m_bUpdatingRect = true; // To be sure that updateVisibleSceneRect will not be called by scrollbar change
m_pScrollbar->setValue(m_offset);
m_bUpdatingRect = false;
@ -995,6 +1114,7 @@ void ProfGraphicsView::mousePressEvent(QMouseEvent* _event)
if (m_mouseButtons & Qt::RightButton)
{
m_bStrictSelection = false;
const auto mouseX = m_offset + mapToScene(_event->pos()).x() / m_scale;
m_chronometerItem->setLeftRight(mouseX, mouseX);
m_chronometerItem->hide();
@ -1048,8 +1168,10 @@ void ProfGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
if (changedSelection)
{
emit treeblocksChanged(m_selectedBlocks, m_beginTime);
emit intervalChanged(m_selectedBlocks, m_beginTime, position2time(m_chronometerItem->left()), position2time(m_chronometerItem->right()), m_bStrictSelection);
}
m_bStrictSelection = false;
}
//////////////////////////////////////////////////////////////////////////
@ -1067,13 +1189,29 @@ void ProfGraphicsView::mouseMoveEvent(QMouseEvent* _event)
if (m_mouseButtons & Qt::RightButton)
{
const auto mouseX = m_offset + mapToScene(_event->pos()).x() / m_scale;
if (mouseX > m_chronometerItem->left())
if (m_bStrictSelection)
{
m_chronometerItem->setLeftRight(m_chronometerItem->left(), mouseX);
if (mouseX > m_chronometerItem->right())
{
m_bStrictSelection = false;
m_chronometerItem->setLeftRight(m_chronometerItem->right(), mouseX);
}
else
{
m_chronometerItem->setLeftRight(mouseX, m_chronometerItem->right());
}
}
else
{
m_chronometerItem->setLeftRight(mouseX, m_chronometerItem->right());
if (mouseX < m_chronometerItem->left())
{
m_bStrictSelection = true;
m_chronometerItem->setLeftRight(mouseX, m_chronometerItem->left());
}
else
{
m_chronometerItem->setLeftRight(m_chronometerItem->left(), mouseX);
}
}
if (!m_chronometerItem->isVisible() && m_chronometerItem->width() > 1e-6)
@ -1204,19 +1342,23 @@ ProfGraphicsViewWidget::ProfGraphicsViewWidget(bool _test)
, m_view(new ProfGraphicsView(_test))
{
auto lay = new QVBoxLayout(this);
lay->setContentsMargins(1, 0, 1, 0);
lay->addWidget(m_view);
lay->setSpacing(1);
lay->addWidget(m_scrollbar);
setLayout(lay);
m_view->setScrollbar(m_scrollbar);
}
ProfGraphicsViewWidget::ProfGraphicsViewWidget(const thread_blocks_tree_t& _blocksTree)
: QWidget(false)
: QWidget(nullptr)
, m_scrollbar(new GraphicsHorizontalScrollbar(nullptr))
, m_view(new ProfGraphicsView(_blocksTree))
{
auto lay = new QVBoxLayout(this);
lay->setContentsMargins(1, 0, 1, 0);
lay->addWidget(m_view);
lay->setSpacing(1);
lay->addWidget(m_scrollbar);
setLayout(lay);
m_view->setScrollbar(m_scrollbar);

View File

@ -42,15 +42,15 @@
#pragma pack(push, 1)
struct ProfBlockItem
{
const BlocksTree* block;
qreal x;
float w;
float y;
float h;
QRgb color;
unsigned int children_begin;
unsigned short totalHeight;
char state;
const BlocksTree* block; ///< Pointer to profiler block
qreal x; ///< x coordinate of the item (this is made qreal=double to avoid mistakes on very wide scene)
float w; ///< Width of the item
float y; ///< y coordinate of the item
float h; ///< Height of the item
QRgb color; ///< Background color of the item
unsigned int children_begin; ///< Index of first child item on the next sublevel
unsigned short totalHeight; ///< Total height of the item including heights of all it's children
char state; ///< 0 = no change, 1 = paint, -1 = do not paint
void setRect(qreal _x, float _y, float _w, float _h);
qreal left() const;
@ -72,14 +72,14 @@ class ProfGraphicsItem : public QGraphicsItem
typedef ::std::vector<unsigned int> DrawIndexes;
typedef ::std::vector<Children> Sublevels;
DrawIndexes m_levelsIndexes;
Sublevels m_levels;
DrawIndexes m_levelsIndexes; ///< Indexes of first item on each level from which we must start painting
Sublevels m_levels; ///< Arrays of items for each level
QRectF m_boundingRect;
const BlocksTree* m_pRoot;
::profiler::thread_id_t m_thread_id;
QRgb m_backgroundColor;
const bool m_bTest;
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
const BlocksTree* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
::profiler::thread_id_t m_thread_id; ///< Thread id to which this item belongs
QRgb m_backgroundColor; ///< Background color (to enable AlternateColors behavior like in QTreeWidget)
const bool m_bTest; ///< If true then we are running test()
public:
@ -88,30 +88,92 @@ public:
ProfGraphicsItem(::profiler::thread_id_t _thread_id, const BlocksTree* _root);
virtual ~ProfGraphicsItem();
// Public virtual methods
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
public:
// Public non-virtual methods
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setBoundingRect(const QRectF& _rect);
void setBackgroundColor(QRgb _color);
///< Returns number of levels
unsigned short levels() const;
/** \brief Sets number of levels.
\note Must be set before doing anything else.
\param _levels Desired number of levels */
void setLevels(unsigned short _levels);
/** \brief Reserves memory for desired number of items on specified level.
\param _level Index of the level
\param _items Desired number of items on this level */
void reserve(unsigned short _level, size_t _items);
/**\brief Returns reference to the array of items of specified level.
\param _level Index of the level */
const Children& items(unsigned short _level) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
const ProfBlockItem& getItem(unsigned short _level, size_t _index) const;
/**\brief Returns reference to the item with required index on specified level.
\param _level Index of the level
\param _index Index of required item */
ProfBlockItem& getItem(unsigned short _level, size_t _index);
/** \brief Adds new item to required level.
\param _level Index of the level
\retval Index of the new created item */
size_t addItem(unsigned short _level);
/** \brief Adds new item to required level.
Constructs new item using copy constructor.
\param _level Index of the level
\param _item Reference to the source item to copy from
\retval Index of the new created item */
size_t addItem(unsigned short _level, const ProfBlockItem& _item);
/** \brief Adds new item to required level.
Constructs new item using move constructor.
\param _level Index of the level
\param _item Reference to the source item to move from
\retval Index of the new created item */
size_t addItem(unsigned short _level, ProfBlockItem&& _item);
/** \brief Finds top-level blocks which are intersects with required selection zone.
\note Found blocks will be added into the array of selected blocks.
\param _left Left bound of the selection zone
\param _right Right bound of the selection zone
\param _blocks Reference to the array of selected blocks */
void getBlocks(qreal _left, qreal _right, TreeBlocks& _blocks) const;
private:
///< Returns pointer to the ProfGraphicsView widget.
const ProfGraphicsView* view() const;
}; // END of class ProfGraphicsItem.
@ -120,20 +182,24 @@ private:
class ProfChronometerItem : public QGraphicsItem
{
QFont m_font;
QRectF m_boundingRect;
qreal m_left, m_right;
QFont m_font; ///< Font which is used to draw text
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
qreal m_left, m_right; ///< Left and right bounds of the selection zone
public:
ProfChronometerItem();
virtual ~ProfChronometerItem();
// Public virtual methods
QRectF boundingRect() const override;
void paint(QPainter* _painter, const QStyleOptionGraphicsItem* _option, QWidget* _widget = nullptr) override;
public:
// Public non-virtual methods
void setBoundingRect(qreal x, qreal y, qreal w, qreal h);
void setBoundingRect(const QRectF& _rect);
void setLeftRight(qreal _left, qreal _right);
@ -155,6 +221,7 @@ public:
private:
///< Returns pointer to the ProfGraphicsView widget.
const ProfGraphicsView* view() const;
}; // END of class ProfChronometerItem.
@ -170,21 +237,22 @@ private:
typedef ProfGraphicsView This;
typedef ::std::vector<ProfGraphicsItem*> Items;
Items m_items;
TreeBlocks m_selectedBlocks;
QTimer m_flickerTimer;
QRectF m_visibleSceneRect;
::profiler::timestamp_t m_beginTime;
qreal m_scale;
Items m_items; ///< Array of all ProfGraphicsItem items
TreeBlocks m_selectedBlocks; ///< Array of items which were selected by selection zone (ProfChronometerItem)
QTimer m_flickerTimer; ///< Timer for flicking behavior
QRectF m_visibleSceneRect; ///< Visible scene rectangle
::profiler::timestamp_t m_beginTime; ///< Begin time of profiler session. Used to reduce values of all begin and end times of profiler blocks.
qreal m_scale; ///< Current scale
qreal m_offset; ///< Have to use manual offset for all scene content instead of using scrollbars because QScrollBar::value is 32-bit integer :(
QPoint m_mousePressPos;
Qt::MouseButtons m_mouseButtons;
GraphicsHorizontalScrollbar* m_pScrollbar;
ProfChronometerItem* m_chronometerItem;
int m_flickerSpeed;
bool m_bUpdatingRect;
bool m_bTest;
bool m_bEmpty;
QPoint m_mousePressPos; ///< Last mouse global position (used by mousePressEvent and mouseMoveEvent)
Qt::MouseButtons m_mouseButtons; ///< Pressed mouse buttons
GraphicsHorizontalScrollbar* m_pScrollbar; ///< Pointer to the graphics scrollbar widget
ProfChronometerItem* m_chronometerItem; ///< Pointer to the ProfChronometerItem which is displayed when you press right mouse button and move mouse left or right
int m_flickerSpeed; ///< Current flicking speed
bool m_bUpdatingRect; ///< Stub flag which is used to avoid excess calculations on some scene update (flicking, scaling and so on)
bool m_bTest; ///< Testing flag (true when test() is called)
bool m_bEmpty; ///< Indicates whether scene is empty and has no items
bool m_bStrictSelection; ///< Strict selection flag used by ProfTreeWidget to interpret left and right bounds of selection zone in different ways
public:
@ -192,12 +260,53 @@ public:
ProfGraphicsView(const thread_blocks_tree_t& _blocksTree);
virtual ~ProfGraphicsView();
// Public virtual methods
void wheelEvent(QWheelEvent* _event) override;
void mousePressEvent(QMouseEvent* _event) override;
void mouseReleaseEvent(QMouseEvent* _event) override;
void mouseMoveEvent(QMouseEvent* _event) override;
void resizeEvent(QResizeEvent* _event) override;
public:
// Public non-virtual methods
void setScrollbar(GraphicsHorizontalScrollbar* _scrollbar);
void clearSilent();
void test(size_t _frames_number, size_t _total_items_number_estimate, int _rows);
void setTree(const thread_blocks_tree_t& _blocksTree);
signals:
// Signals
void intervalChanged(const TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
private:
// Private non-virtual methods
void initMode();
void updateVisibleSceneRect();
void updateScene();
void scaleTo(qreal _scale);
qreal setTree(ProfGraphicsItem* _item, const BlocksTree::children_t& _children, qreal& _height, qreal _y, unsigned short _level);
void fillTestChildren(ProfGraphicsItem* _item, const int _maxlevel, int _level, qreal _x, qreal _y, size_t _childrenNumber, size_t& _total_items);
private slots:
// Private Slots
void onScrollbarValueChange(int);
void onGraphicsScrollbarValueChange(qreal);
void onFlickerTimeout();
public:
// Public inline methods
inline qreal scale() const
{
return m_scale;
@ -213,33 +322,33 @@ public:
return m_visibleSceneRect;
}
inline qreal time2position(const profiler::timestamp_t& _time) const
{
return qreal(_time - m_beginTime) * 1e-6;
}
void setScrollbar(GraphicsHorizontalScrollbar* _scrollbar);
void clearSilent();
void test(size_t _frames_number, size_t _total_items_number_estimate, int _depth);
void setTree(const thread_blocks_tree_t& _blocksTree);
signals:
void treeblocksChanged(const TreeBlocks& _blocks, ::profiler::timestamp_t _begin_time);
private:
void initMode();
void updateVisibleSceneRect();
void updateScene();
qreal setTree(ProfGraphicsItem* _item, const BlocksTree::children_t& _children, qreal& _height, qreal _y, unsigned short _level);
// Private inline methods
private slots:
inline qreal time2position(const profiler::timestamp_t& _time) const
{
return PROF_MICROSECONDS(qreal(_time - m_beginTime));
//return PROF_MILLISECONDS(qreal(_time - m_beginTime));
}
void onScrollbarValueChange(int);
void onGraphicsScrollbarValueChange(qreal);
void onFlickerTimeout();
inline ::profiler::timestamp_t position2time(qreal _pos) const
{
return PROF_FROM_MICROSECONDS(_pos);
//return PROF_FROM_MILLISECONDS(_pos);
}
inline qreal to_microseconds(qreal _value) const
{
return _value;
//return _value * 1e-3;
}
inline qreal to_milliseconds(qreal _value) const
{
return _value * 1e3;
//return _value;
}
}; // END of class ProfGraphicsView.

View File

@ -24,6 +24,7 @@
* license : TODO: add license text
************************************************************************/
#include <algorithm>
#include <QMenu>
#include <QContextMenuEvent>
#include <QSignalBlocker>
@ -102,33 +103,36 @@ const BlocksTree* ProfTreeWidgetItem::block() const
void ProfTreeWidgetItem::setTimeSmart(int _column, const ::profiler::timestamp_t& _time)
{
setData(_column, Qt::UserRole, (quint64)_time);
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setToolTip(_column, QString("%1 ns").arg(_time));
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
if (_time < 1e3)
{
setText(_column, QString("%1 ns").arg(_time));
setText(_column, QString("%1 ns").arg(nanosecondsTime));
}
else if (_time < 1e6)
{
setText(_column, QString("%1 us").arg(double(_time) * 1e-3, 0, 'f', 3));
setText(_column, QString("%1 us").arg(double(nanosecondsTime) * 1e-3, 0, 'f', 3));
}
else if (_time < 1e9)
{
setText(_column, QString("%1 ms").arg(double(_time) * 1e-6, 0, 'f', 3));
setText(_column, QString("%1 ms").arg(double(nanosecondsTime) * 1e-6, 0, 'f', 3));
}
else
{
setText(_column, QString("%1 s").arg(double(_time) * 1e-9, 0, 'f', 3));
setText(_column, QString("%1 s").arg(double(nanosecondsTime) * 1e-9, 0, 'f', 3));
}
}
void ProfTreeWidgetItem::setTimeMs(int _column, const ::profiler::timestamp_t& _time)
{
setData(_column, Qt::UserRole, (quint64)_time);
setToolTip(_column, QString("%1 ns").arg(_time));
setText(_column, QString::number(double(_time) * 1e-6, 'g', 9));
const ::profiler::timestamp_t nanosecondsTime = PROF_NANOSECONDS(_time);
setData(_column, Qt::UserRole, (quint64)nanosecondsTime);
setToolTip(_column, QString("%1 ns").arg(nanosecondsTime));
setText(_column, QString::number(double(nanosecondsTime) * 1e-6, 'g', 9));
}
void ProfTreeWidgetItem::setBackgroundColor(const QColor& _color)
@ -237,12 +241,14 @@ void ProfTreeWidget::setTree(const unsigned int _blocksNumber, const thread_bloc
connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
}
void ProfTreeWidget::setTreeBlocks(const TreeBlocks& _blocks, ::profiler::timestamp_t _begin_time)
void ProfTreeWidget::setTreeBlocks(const TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict)
{
clearSilent();
m_beginTime = _begin_time;
setTreeInternal(_blocks);
m_beginTime = _session_begin_time;
_left += m_beginTime;// - ::std::min(m_beginTime, 1000ULL);
_right += m_beginTime;// + 1000;
setTreeInternal(_blocks, _left, _right, _strict);
setSortingEnabled(true);
sortByColumn(COL_BEGIN, Qt::AscendingOrder);
@ -268,19 +274,29 @@ void ProfTreeWidget::clearSilent()
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree)
size_t ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree)
{
m_items.reserve(_blocksNumber + _blocksTree.size()); // _blocksNumber does not include Thread root blocks
decltype(m_beginTime) finishtime = 0;
for (const auto& threadTree : _blocksTree)
{
const auto beginTime = threadTree.second.children.front().node->block()->getBegin();
if (m_beginTime > beginTime)
const auto node_block = threadTree.second.children.front().node->block();
const auto startTime = node_block->getBegin();
const auto endTime = node_block->getEnd();
if (m_beginTime > startTime)
{
m_beginTime = beginTime;
m_beginTime = startTime;
}
if (finishtime < endTime)
{
finishtime = endTime;
}
}
size_t total_items = 0;
const QSignalBlocker b(this);
for (const auto& threadTree : _blocksTree)
{
@ -289,22 +305,32 @@ void ProfTreeWidget::setTreeInternal(const unsigned int _blocksNumber, const thr
m_items.push_back(item);
setTreeInternal(threadTree.second.children, item);
const auto children_items_number = setTreeInternal(threadTree.second.children, item, m_beginTime, finishtime + 1000000000, false);
addTopLevelItem(item);
if (m_bColorRows)
if (children_items_number > 0)
{
item->colorize(m_bColorRows);
total_items += children_items_number + 1;
addTopLevelItem(item);
if (m_bColorRows)
{
item->colorize(m_bColorRows);
}
}
else
{
delete item;
}
}
return total_items;
}
void ProfTreeWidget::setTreeInternal(const TreeBlocks& _blocks)
size_t ProfTreeWidget::setTreeInternal(const TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict)
{
if (_blocks.empty())
{
return;
return 0;
}
size_t blocksNumber = 0;
@ -318,9 +344,17 @@ void ProfTreeWidget::setTreeInternal(const TreeBlocks& _blocks)
typedef ::std::unordered_map<::profiler::thread_id_t, ProfTreeWidgetItem*, ::btw::do_no_hash<::profiler::thread_id_t>::hasher_t> ThreadsMap;
ThreadsMap threadsMap;
size_t total_items = 0;
const QSignalBlocker b(this);
for (const auto& block : _blocks)
{
const auto startTime = block.tree->node->block()->getBegin();
const auto endTime = block.tree->node->block()->getEnd();
if (startTime > _right || endTime < _left)
{
continue;
}
ProfTreeWidgetItem* thread_item = nullptr;
auto thread_item_it = threadsMap.find(block.thread_id);
if (thread_item_it != threadsMap.end())
@ -331,15 +365,14 @@ void ProfTreeWidget::setTreeInternal(const TreeBlocks& _blocks)
{
thread_item = new ProfTreeWidgetItem(block.thread_tree);
thread_item->setText(COL_NAME, QString("Thread %1").arg(block.thread_id));
m_items.push_back(thread_item);
threadsMap.insert(::std::make_pair(block.thread_id, thread_item));
}
auto item = new ProfTreeWidgetItem(block.tree, thread_item);
item->setText(COL_NAME, block.tree->node->getBlockName());
item->setTimeSmart(COL_DURATION, block.tree->node->block()->duration());
item->setTimeMs(COL_BEGIN, block.tree->node->block()->getBegin() - m_beginTime);
item->setTimeMs(COL_END, block.tree->node->block()->getEnd() - m_beginTime);
item->setTimeMs(COL_BEGIN, startTime - m_beginTime);
item->setTimeMs(COL_END, endTime - m_beginTime);
if (block.tree->total_statistics)
{
@ -368,39 +401,70 @@ void ProfTreeWidget::setTreeInternal(const TreeBlocks& _blocks)
item->setTextColor(fgColor);
m_items.push_back(item);
m_itemblocks[block.tree->node] = item;
size_t children_items_number = 0;
if (!block.tree->children.empty())
{
setTreeInternal(block.tree->children, item);
children_items_number = setTreeInternal(block.tree->children, item, _left, _right, _strict);
}
if (m_bColorRows)
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
item->colorize(m_bColorRows);
total_items += children_items_number + 1;
m_itemblocks[block.tree->node] = item;
if (m_bColorRows)
{
item->colorize(m_bColorRows);
}
}
else
{
m_items.pop_back();
delete item;
}
}
for (auto it : threadsMap)
for (auto& it : threadsMap)
{
addTopLevelItem(it.second);
if (m_bColorRows)
if (it.second->childCount() > 0)
{
it.second->colorize(m_bColorRows);
addTopLevelItem(it.second);
if (m_bColorRows)
{
it.second->colorize(m_bColorRows);
}
m_items.push_back(it.second);
++total_items;
}
else
{
delete it.second;
}
}
return total_items;
}
void ProfTreeWidget::setTreeInternal(const BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent)
size_t ProfTreeWidget::setTreeInternal(const BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict)
{
size_t total_items = 0;
for (const auto& child : _children)
{
const auto startTime = child.node->block()->getBegin();
const auto endTime = child.node->block()->getEnd();
if (startTime > _right || endTime < _left)
{
continue;
}
auto item = new ProfTreeWidgetItem(&child, _parent);
item->setText(COL_NAME, child.node->getBlockName());
item->setTimeSmart(COL_DURATION, child.node->block()->duration());
item->setTimeMs(COL_BEGIN, child.node->block()->getBegin() - m_beginTime);
item->setTimeMs(COL_END, child.node->block()->getEnd() - m_beginTime);
item->setTimeMs(COL_BEGIN, startTime - m_beginTime);
item->setTimeMs(COL_END, endTime - m_beginTime);
if (child.total_statistics)
{
@ -429,18 +493,31 @@ void ProfTreeWidget::setTreeInternal(const BlocksTree::children_t& _children, Pr
item->setTextColor(fgColor);
m_items.push_back(item);
m_itemblocks[child.node] = item;
auto children_items_number = 0;
if (!child.children.empty())
{
setTreeInternal(child.children, item);
children_items_number = setTreeInternal(child.children, item, _left, _right, _strict);
}
if (m_bColorRows)
if (children_items_number > 0 || !_strict || (startTime >= _left && endTime <= _right))
{
item->colorize(m_bColorRows);
total_items += children_items_number + 1;
m_itemblocks[child.node] = item;
if (m_bColorRows)
{
item->colorize(m_bColorRows);
}
}
else
{
m_items.pop_back();
delete item;
}
}
return total_items;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@ -449,12 +526,6 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
{
const auto col = currentColumn();
auto item = static_cast<ProfTreeWidgetItem*>(currentItem());
if (item == nullptr || col < 0)
{
return;
}
QMenu menu;
auto action = new QAction("Expand all", nullptr);
@ -465,15 +536,18 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
connect(action, &QAction::triggered, this, &This::onCollapseAllClicked);
menu.addAction(action);
menu.addSeparator();
if (item != nullptr && col >= 0)
{
menu.addSeparator();
action = new QAction("Expand all children", nullptr);
connect(action, &QAction::triggered, this, &This::onExpandAllChildrenClicked);
menu.addAction(action);
action = new QAction("Expand all children", nullptr);
connect(action, &QAction::triggered, this, &This::onExpandAllChildrenClicked);
menu.addAction(action);
action = new QAction("Collapse all children", nullptr);
connect(action, &QAction::triggered, this, &This::onCollapseAllChildrenClicked);
menu.addAction(action);
action = new QAction("Collapse all children", nullptr);
connect(action, &QAction::triggered, this, &This::onCollapseAllChildrenClicked);
menu.addAction(action);
}
menu.addSeparator();
@ -483,26 +557,29 @@ void ProfTreeWidget::contextMenuEvent(QContextMenuEvent* _event)
connect(action, &QAction::triggered, this, &This::onColorizeRowsTriggered);
menu.addAction(action);
switch (col)
if (item != nullptr && col >= 0)
{
case COL_MIN_TOTAL:
case COL_MIN:
switch (col)
{
menu.addSeparator();
auto itemAction = new ProfItemAction("Jump to such item", item);
connect(itemAction, &ProfItemAction::clicked, this, &This::onJumpToMinItemClicked);
menu.addAction(itemAction);
break;
}
case COL_MIN_TOTAL:
case COL_MIN:
{
menu.addSeparator();
auto itemAction = new ProfItemAction("Jump to such item", item);
connect(itemAction, &ProfItemAction::clicked, this, &This::onJumpToMinItemClicked);
menu.addAction(itemAction);
break;
}
case COL_MAX_TOTAL:
case COL_MAX:
{
menu.addSeparator();
auto itemAction = new ProfItemAction("Jump to such item", item);
connect(itemAction, &ProfItemAction::clicked, this, &This::onJumpToMaxItemClicked);
menu.addAction(itemAction);
break;
case COL_MAX_TOTAL:
case COL_MAX:
{
menu.addSeparator();
auto itemAction = new ProfItemAction("Jump to such item", item);
connect(itemAction, &ProfItemAction::clicked, this, &This::onJumpToMaxItemClicked);
menu.addAction(itemAction);
break;
}
}
}

View File

@ -180,15 +180,15 @@ public slots:
void setTree(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree);
void setTreeBlocks(const TreeBlocks& _blocks, ::profiler::timestamp_t _begin_time);
void setTreeBlocks(const TreeBlocks& _blocks, ::profiler::timestamp_t _session_begin_time, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
protected:
void setTreeInternal(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree);
size_t setTreeInternal(const unsigned int _blocksNumber, const thread_blocks_tree_t& _blocksTree);
void setTreeInternal(const TreeBlocks& _blocks);
size_t setTreeInternal(const TreeBlocks& _blocks, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
void setTreeInternal(const BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent);
size_t setTreeInternal(const BlocksTree::children_t& _children, ProfTreeWidgetItem* _parent, ::profiler::timestamp_t _left, ::profiler::timestamp_t _right, bool _strict);
void contextMenuEvent(QContextMenuEvent* _event) override;

View File

@ -27,6 +27,23 @@
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
#define PROF_MICROSECONDS(timestamp) ((timestamp) * 1e-3)
//#define PROF_MICROSECONDS(timestamp) (timestamp)
#define PROF_FROM_MICROSECONDS(to_timestamp) ((to_timestamp) * 1e3)
//#define PROF_FROM_MICROSECONDS(to_timestamp) (to_timestamp)
#define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-6)
//#define PROF_MILLISECONDS(timestamp) ((timestamp) * 1e-3)
#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e6)
//#define PROF_FROM_MILLISECONDS(to_timestamp) ((to_timestamp) * 1e3)
#define PROF_NANOSECONDS(timestamp) (timestamp)
//#define PROF_NANOSECONDS(timestamp) ((timestamp) * 1000)
//////////////////////////////////////////////////////////////////////////
const QRgb DEFAULT_COLOR = 0x00f0e094;
inline QRgb toRgb(unsigned int _red, unsigned int _green, unsigned int _blue)

View File

@ -172,7 +172,7 @@ qreal GraphicsHorizontalScrollbar::value() const
void GraphicsHorizontalScrollbar::setValue(qreal _value)
{
m_value = clamp(m_minimumValue, _value, m_maximumValue - m_slider->width());
m_value = clamp(m_minimumValue, _value, ::std::max(m_minimumValue, m_maximumValue - m_slider->width()));
m_slider->setX(m_value + m_slider->halfwidth());
emit valueChanged(m_value);
}

View File

@ -82,7 +82,7 @@ ProfMainWindow::ProfMainWindow() : QMainWindow(), m_treeWidget(nullptr), m_graph
menuBar()->addMenu(menu);
connect(graphicsView->view(), &ProfGraphicsView::treeblocksChanged, treeWidget, &ProfTreeWidget::setTreeBlocks);
connect(graphicsView->view(), &ProfGraphicsView::intervalChanged, treeWidget, &ProfTreeWidget::setTreeBlocks);
if(QCoreApplication::arguments().size() > 1)
@ -155,8 +155,8 @@ void ProfMainWindow::onTestViewportClicked(bool)
view->clearSilent();
m_currentProf.clear();
view->test(18000, 40000000, 5);
//view->test(3, 300, 4);
view->test(18000, 40000000, 2);
//view->test(3, 300, 1);
}
//////////////////////////////////////////////////////////////////////////