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

# [UI] Styles and refactoring

This commit is contained in:
Victor Zarubkin 2018-05-19 23:41:01 +03:00
parent 91b2a4e609
commit 983085157e
13 changed files with 639 additions and 156 deletions

View File

@ -42,6 +42,8 @@ if (Qt5Widgets_FOUND)
graphics_slider_area.cpp graphics_slider_area.cpp
main_window.h main_window.h
main_window.cpp main_window.cpp
round_progress_widget.h
round_progress_widget.cpp
timer.h timer.h
timer.cpp timer.cpp
thread_pool.h thread_pool.h

View File

@ -93,8 +93,8 @@ const qreal MAX_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT, 45); // ~23000
const qreal BASE_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 25); // ~0.003 const qreal BASE_SCALE = pow(::profiler_gui::SCALING_COEFFICIENT_INV, 25); // ~0.003
EASY_CONSTEXPR QRgb BACKGROUND_1 = 0xffe4e4ec; EASY_CONSTEXPR QRgb BACKGROUND_1 = 0xffe4e4ec;
EASY_CONSTEXPR QRgb BACKGROUND_2 = ::profiler::colors::White; EASY_CONSTEXPR QRgb BACKGROUND_2 = profiler::colors::White;
EASY_CONSTEXPR QRgb TIMELINE_BACKGROUND = 0x20000000 | (::profiler::colors::Grey800 & 0x00ffffff);// 0x20303030; EASY_CONSTEXPR QRgb TIMELINE_BACKGROUND = 0x20000000 | (profiler::colors::Grey800 & 0x00ffffff);// 0x20303030;
EASY_CONSTEXPR QRgb TIMELINE_BORDER = 0xffa8a0a0; EASY_CONSTEXPR QRgb TIMELINE_BORDER = 0xffa8a0a0;
EASY_CONSTEXPR int IDLE_TIMER_INTERVAL = 200; // 5Hz EASY_CONSTEXPR int IDLE_TIMER_INTERVAL = 200; // 5Hz
@ -284,7 +284,7 @@ void TimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGraphics
BlocksGraphicsView::BlocksGraphicsView(QWidget* _parent) BlocksGraphicsView::BlocksGraphicsView(QWidget* _parent)
: Parent(_parent) : Parent(_parent)
, m_beginTime(::std::numeric_limits<decltype(m_beginTime)>::max()) , m_beginTime(std::numeric_limits<decltype(m_beginTime)>::max())
, m_sceneWidth(0) , m_sceneWidth(0)
, m_scale(1) , m_scale(1)
, m_offset(0) , m_offset(0)
@ -380,7 +380,7 @@ void BlocksGraphicsView::clear()
m_items.clear(); m_items.clear();
m_selectedBlocks.clear(); m_selectedBlocks.clear();
m_beginTime = ::std::numeric_limits<decltype(m_beginTime)>::max(); // reset begin time m_beginTime = std::numeric_limits<decltype(m_beginTime)>::max(); // reset begin time
m_scale = 1; // scale back to initial 100% scale m_scale = 1; // scale back to initial 100% scale
m_timelineStep = 1; m_timelineStep = 1;
m_offset = 0; // scroll back to the beginning of the scene m_offset = 0; // scroll back to the beginning of the scene
@ -448,7 +448,7 @@ void BlocksGraphicsView::notifyVisibleRegionPosChange(qreal _pos)
notifyVisibleRegionPosChange(); notifyVisibleRegionPosChange();
} }
void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree) void BlocksGraphicsView::setTree(const profiler::thread_blocks_tree_t& _blocksTree)
{ {
// clear scene // clear scene
clear(); clear();
@ -464,8 +464,8 @@ void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocks
// calculate scene size and fill it with items // calculate scene size and fill it with items
// Calculating start and end time // Calculating start and end time
::profiler::timestamp_t finish = 0, busyTime = 0; profiler::timestamp_t finish = 0, busyTime = 0;
::profiler::thread_id_t longestTree = 0, mainTree = 0; profiler::thread_id_t longestTree = 0, mainTree = 0;
for (const auto& threadTree : _blocksTree) for (const auto& threadTree : _blocksTree)
{ {
const auto& t = threadTree.second; const auto& t = threadTree.second;
@ -476,12 +476,12 @@ void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocks
if (!t.children.empty()) if (!t.children.empty())
timestart = easyBlocksTree(t.children.front()).node->begin(); timestart = easyBlocksTree(t.children.front()).node->begin();
if (!t.sync.empty()) if (!t.sync.empty())
timestart = ::std::min(timestart, easyBlocksTree(t.sync.front()).node->begin()); timestart = std::min(timestart, easyBlocksTree(t.sync.front()).node->begin());
if (!t.children.empty()) if (!t.children.empty())
timefinish = easyBlocksTree(t.children.back()).node->end(); timefinish = easyBlocksTree(t.children.back()).node->end();
if (!t.sync.empty()) if (!t.sync.empty())
timefinish = ::std::max(timefinish, easyBlocksTree(t.sync.back()).node->end()); timefinish = std::max(timefinish, easyBlocksTree(t.sync.back()).node->end());
if (m_beginTime > timestart) if (m_beginTime > timestart)
m_beginTime = timestart; m_beginTime = timestart;
@ -500,15 +500,15 @@ void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocks
const decltype(m_beginTime) additional_offset = (finish - m_beginTime) / 20; // Additional 5% before first block and after last block const decltype(m_beginTime) additional_offset = (finish - m_beginTime) / 20; // Additional 5% before first block and after last block
finish += additional_offset; finish += additional_offset;
m_beginTime -= ::std::min(m_beginTime, additional_offset); m_beginTime -= std::min(m_beginTime, additional_offset);
EASY_GLOBALS.begin_time = m_beginTime; EASY_GLOBALS.begin_time = m_beginTime;
// Sort threads by name // Sort threads by name
::std::vector<::std::reference_wrapper<const ::profiler::BlocksTreeRoot> > sorted_roots; std::vector<std::reference_wrapper<const profiler::BlocksTreeRoot> > sorted_roots;
sorted_roots.reserve(_blocksTree.size()); sorted_roots.reserve(_blocksTree.size());
for (const auto& threadTree : _blocksTree) for (const auto& threadTree : _blocksTree)
sorted_roots.push_back(threadTree.second); sorted_roots.emplace_back(threadTree.second);
::std::sort(sorted_roots.begin(), sorted_roots.end(), [](const ::profiler::BlocksTreeRoot& _a, const ::profiler::BlocksTreeRoot& _b) { std::sort(sorted_roots.begin(), sorted_roots.end(), [](const profiler::BlocksTreeRoot& _a, const profiler::BlocksTreeRoot& _b) {
return _a.thread_name < _b.thread_name; return _a.thread_name < _b.thread_name;
}); });
@ -519,7 +519,7 @@ void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocks
m_items.reserve(_blocksTree.size()); m_items.reserve(_blocksTree.size());
qreal y = EASY_GLOBALS.size.timeline_height; qreal y = EASY_GLOBALS.size.timeline_height;
const GraphicsBlockItem *longestItem = nullptr, *mainThreadItem = nullptr; const GraphicsBlockItem *longestItem = nullptr, *mainThreadItem = nullptr;
for (const ::profiler::BlocksTreeRoot& t : sorted_roots) for (const profiler::BlocksTreeRoot& t : sorted_roots)
{ {
if (m_items.size() == 0xff) if (m_items.size() == 0xff)
{ {
@ -635,7 +635,7 @@ bool BlocksGraphicsView::getSelectionRegionForSaving(profiler::timestamp_t& _beg
return true; return true;
} }
qreal BlocksGraphicsView::setTree(GraphicsBlockItem* _item, const ::profiler::BlocksTree::children_t& _children, qreal& _height, uint32_t& _maxDepthChild, qreal _y, short _level) qreal BlocksGraphicsView::setTree(GraphicsBlockItem* _item, const profiler::BlocksTree::children_t& _children, qreal& _height, uint32_t& _maxDepthChild, qreal _y, short _level)
{ {
if (_children.empty()) if (_children.empty())
{ {
@ -1063,7 +1063,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
} }
const ::profiler_gui::EasyBlock* selectedBlock = nullptr; const ::profiler_gui::EasyBlock* selectedBlock = nullptr;
::profiler::thread_id_t selectedBlockThread = 0; profiler::thread_id_t selectedBlockThread = 0;
const auto previouslySelectedBlock = EASY_GLOBALS.selected_block; const auto previouslySelectedBlock = EASY_GLOBALS.selected_block;
if (m_mouseButtons & Qt::LeftButton) if (m_mouseButtons & Qt::LeftButton)
{ {
@ -1096,7 +1096,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event)
// Try to select one of item blocks // Try to select one of item blocks
for (auto item : m_items) for (auto item : m_items)
{ {
::profiler::block_index_t i = ~0U; profiler::block_index_t i = ~0U;
auto block = item->intersect(mouseClickPos, i); auto block = item->intersect(mouseClickPos, i);
if (block != nullptr) if (block != nullptr)
{ {
@ -1558,7 +1558,7 @@ void BlocksGraphicsView::initMode()
setTree(EASY_GLOBALS.profiler_blocks); setTree(EASY_GLOBALS.profiler_blocks);
}); });
connect(globalSignals, &GlobalSignals::selectedBlockIdChanged, [this](::profiler::block_id_t) connect(globalSignals, &GlobalSignals::selectedBlockIdChanged, [this](profiler::block_id_t)
{ {
if (profiler_gui::is_max(EASY_GLOBALS.selected_block_id)) if (profiler_gui::is_max(EASY_GLOBALS.selected_block_id))
{ {
@ -1747,7 +1747,7 @@ void BlocksGraphicsView::onIdleTimeout()
lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight); lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight);
const char* process_name = ""; const char* process_name = "";
::profiler::thread_id_t tid = 0; profiler::thread_id_t tid = 0;
if (EASY_GLOBALS.version < ::profiler_gui::V130) if (EASY_GLOBALS.version < ::profiler_gui::V130)
{ {
tid = cse->tree.node->id(); tid = cse->tree.node->id();
@ -1797,10 +1797,10 @@ void BlocksGraphicsView::onIdleTimeout()
lay->addWidget(new QLabel("Thread", widget), row + 1, 1, Qt::AlignHCenter); lay->addWidget(new QLabel("Thread", widget), row + 1, 1, Qt::AlignHCenter);
auto percent = ::profiler_gui::percentReal(duration, item->root()->profiled_time); auto percent = ::profiler_gui::percentReal(duration, item->root().profiled_time);
lay->addWidget(new QLabel(0.005 < percent && percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent)), widget), row + 2, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(0.005 < percent && percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent)), widget), row + 2, 1, Qt::AlignHCenter);
lay->addWidget(new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration, item->root()->profiled_time)), widget), row + 3, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration, item->root().profiled_time)), widget), row + 3, 1, Qt::AlignHCenter);
lay->addWidget(new QLabel(QString::number(itemBlock.per_thread_stats->calls_number), widget), row + 4, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(QString::number(itemBlock.per_thread_stats->calls_number), widget), row + 4, 1, Qt::AlignHCenter);
@ -1826,7 +1826,7 @@ void BlocksGraphicsView::onIdleTimeout()
break; break;
} }
::profiler::block_index_t i = ~0U; profiler::block_index_t i = ~0U;
auto block = item->intersect(pos, i); auto block = item->intersect(pos, i);
if (block != nullptr) if (block != nullptr)
{ {
@ -1855,7 +1855,7 @@ void BlocksGraphicsView::onIdleTimeout()
int row = 0; int row = 0;
switch (itemDesc.type()) switch (itemDesc.type())
{ {
case ::profiler::BlockType::Block: case profiler::BlockType::Block:
{ {
const auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : itemDesc.name(); const auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : itemDesc.name();
@ -1870,7 +1870,7 @@ void BlocksGraphicsView::onIdleTimeout()
widget), row, 1, 1, 3, Qt::AlignLeft); widget), row, 1, 1, 3, Qt::AlignLeft);
++row; ++row;
::profiler::timestamp_t children_duration = 0; profiler::timestamp_t children_duration = 0;
for (auto child : itemBlock.children) for (auto child : itemBlock.children)
children_duration += easyBlock(child).tree.node->duration(); children_duration += easyBlock(child).tree.node->duration();
@ -1888,7 +1888,7 @@ void BlocksGraphicsView::onIdleTimeout()
break; break;
} }
case ::profiler::BlockType::Event: case profiler::BlockType::Event:
{ {
const auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : itemDesc.name(); const auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : itemDesc.name();
@ -1902,7 +1902,7 @@ void BlocksGraphicsView::onIdleTimeout()
break; break;
} }
case ::profiler::BlockType::Value: case profiler::BlockType::Value:
{ {
lay->addWidget(new BoldLabel("Arbitrary Value", widget), row, 0, 1, 2, Qt::AlignHCenter); lay->addWidget(new BoldLabel("Arbitrary Value", widget), row, 0, 1, 2, Qt::AlignHCenter);
++row; ++row;
@ -1931,7 +1931,7 @@ void BlocksGraphicsView::onIdleTimeout()
if (itemBlock.per_thread_stats != nullptr) if (itemBlock.per_thread_stats != nullptr)
{ {
if (itemDesc.type() == ::profiler::BlockType::Block) if (itemDesc.type() == profiler::BlockType::Block)
{ {
const auto duration = itemBlock.node->duration(); const auto duration = itemBlock.node->duration();
@ -1941,29 +1941,30 @@ void BlocksGraphicsView::onIdleTimeout()
// Calculate idle/active time // Calculate idle/active time
{ {
auto threadRoot = item->root(); const auto& threadRoot = item->root();
::profiler::block_index_t ind = 0; profiler::block_index_t ind = 0;
auto it = ::std::lower_bound(threadRoot->sync.begin(), threadRoot->sync.end(), itemBlock.node->begin(), [](::profiler::block_index_t _cs_index, ::profiler::timestamp_t _val) auto it = std::lower_bound(threadRoot.sync.begin(), threadRoot.sync.end(), itemBlock.node->begin(),
[](profiler::block_index_t _cs_index, profiler::timestamp_t _val)
{ {
return EASY_GLOBALS.gui_blocks[_cs_index].tree.node->begin() < _val; return EASY_GLOBALS.gui_blocks[_cs_index].tree.node->begin() < _val;
}); });
if (it != threadRoot->sync.end()) if (it != threadRoot.sync.end())
{ {
ind = static_cast<::profiler::block_index_t>(it - threadRoot->sync.begin()); ind = static_cast<profiler::block_index_t>(it - threadRoot.sync.begin());
if (ind > 0) if (ind > 0)
--ind; --ind;
} }
else else
{ {
ind = static_cast<::profiler::block_index_t>(threadRoot->sync.size()); ind = static_cast<profiler::block_index_t>(threadRoot.sync.size());
} }
::profiler::timestamp_t idleTime = 0; profiler::timestamp_t idleTime = 0;
for (auto ncs = static_cast<::profiler::block_index_t>(threadRoot->sync.size()); ind < ncs; ++ind) for (auto ncs = static_cast<profiler::block_index_t>(threadRoot.sync.size()); ind < ncs; ++ind)
{ {
auto cs_index = threadRoot->sync[ind]; auto cs_index = threadRoot.sync[ind];
const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node; const auto cs = EASY_GLOBALS.gui_blocks[cs_index].tree.node;
if (cs->begin() > itemBlock.node->end()) if (cs->begin() > itemBlock.node->end())
@ -1989,12 +1990,12 @@ void BlocksGraphicsView::onIdleTimeout()
lay->addWidget(new QLabel("Thread", widget), row + 1, 1, Qt::AlignHCenter); lay->addWidget(new QLabel("Thread", widget), row + 1, 1, Qt::AlignHCenter);
auto percent = ::profiler_gui::percentReal(duration, item->root()->profiled_time); auto percent = ::profiler_gui::percentReal(duration, item->root().profiled_time);
lay->addWidget(new QLabel(0.005 < percent && percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent)), widget), row + 2, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(0.005 < percent && percent < 0.5001 ? QString::number(percent, 'f', 2) : QString::number(static_cast<int>(0.5 + percent)), widget), row + 2, 1, Qt::AlignHCenter);
lay->addWidget(new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration, item->root()->profiled_time)), widget), row + 3, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration, item->root().profiled_time)), widget), row + 3, 1, Qt::AlignHCenter);
lay->addWidget(new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration - itemBlock.per_thread_stats->total_children_duration, item->root()->profiled_time)), widget), row + 4, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(QString::number(::profiler_gui::percent(itemBlock.per_thread_stats->total_duration - itemBlock.per_thread_stats->total_children_duration, item->root().profiled_time)), widget), row + 4, 1, Qt::AlignHCenter);
lay->addWidget(new QLabel(QString::number(itemBlock.per_thread_stats->calls_number), widget), row + 5, 1, Qt::AlignHCenter); lay->addWidget(new QLabel(QString::number(itemBlock.per_thread_stats->calls_number), widget), row + 5, 1, Qt::AlignHCenter);
@ -2067,10 +2068,10 @@ void BlocksGraphicsView::onIdleTimeout()
auto br = m_popupWidget->rect(); auto br = m_popupWidget->rect();
if (scenePos.y() + br.height() > m_visibleSceneRect.bottom()) if (scenePos.y() + br.height() > m_visibleSceneRect.bottom())
scenePos.setY(::std::max(scenePos.y() - br.height(), m_visibleSceneRect.top())); scenePos.setY(std::max(scenePos.y() - br.height(), m_visibleSceneRect.top()));
if (scenePos.x() + br.width() > m_visibleSceneRect.right()) if (scenePos.x() + br.width() > m_visibleSceneRect.right())
scenePos.setX(::std::max(scenePos.x() - br.width(), m_visibleSceneRect.left())); scenePos.setX(std::max(scenePos.x() - br.width(), m_visibleSceneRect.left()));
if ((scenePos - prevPos).manhattanLength() != 0) if ((scenePos - prevPos).manhattanLength() != 0)
m_popupWidget->move(mapToGlobal(mapFromScene(scenePos))); m_popupWidget->move(mapToGlobal(mapFromScene(scenePos)));
@ -2109,7 +2110,7 @@ void BlocksGraphicsView::onHierarchyFlagChange(bool)
} }
} }
void BlocksGraphicsView::onSelectedThreadChange(::profiler::thread_id_t _id) void BlocksGraphicsView::onSelectedThreadChange(profiler::thread_id_t _id)
{ {
if (m_pScrollbar == nullptr || m_pScrollbar->hystThread() == _id) if (m_pScrollbar == nullptr || m_pScrollbar->hystThread() == _id)
{ {
@ -2414,7 +2415,7 @@ ThreadNamesWidget::ThreadNamesWidget(BlocksGraphicsView* _view, int _additionalH
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setFixedWidth(m_maxLength); setFixedWidth(m_maxLength);
connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::selectedThreadChanged, [this](::profiler::thread_id_t){ repaintScene(); }); connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::selectedThreadChanged, [this](profiler::thread_id_t){ repaintScene(); });
connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::allDataGoingToBeDeleted, this, &This::clear); connect(&EASY_GLOBALS.events, &::profiler_gui::GlobalSignals::allDataGoingToBeDeleted, this, &This::clear);
connect(m_view, &BlocksGraphicsView::treeChanged, this, &This::onTreeChange); connect(m_view, &BlocksGraphicsView::treeChanged, this, &This::onTreeChange);
@ -2477,7 +2478,7 @@ void ThreadNamesWidget::onTreeChange()
qreal maxLength = 100; qreal maxLength = 100;
const auto& graphicsItems = m_view->getItems(); const auto& graphicsItems = m_view->getItems();
for (auto graphicsItem : graphicsItems) for (auto graphicsItem : graphicsItems)
maxLength = ::std::max(maxLength, (10 + fm.width(graphicsItem->threadName())) * ::profiler_gui::FONT_METRICS_FACTOR); maxLength = std::max(maxLength, (10 + fm.width(graphicsItem->threadName())) * ::profiler_gui::FONT_METRICS_FACTOR);
auto vbar = verticalScrollBar(); auto vbar = verticalScrollBar();
auto viewBar = m_view->verticalScrollBar(); auto viewBar = m_view->verticalScrollBar();
@ -2582,8 +2583,8 @@ void ThreadNamesWidget::onIdleTimeout()
lay->addWidget(new BoldLabel(intersectingItem->threadName(), widget), row, 0, 1, 2, Qt::AlignHCenter); lay->addWidget(new BoldLabel(intersectingItem->threadName(), widget), row, 0, 1, 2, Qt::AlignHCenter);
++row; ++row;
::profiler::timestamp_t duration = 0; profiler::timestamp_t duration = 0;
const auto& root = *intersectingItem->root(); const auto& root = intersectingItem->root();
if (!root.children.empty()) if (!root.children.empty())
duration = easyBlock(root.children.back()).tree.node->end() - easyBlock(root.children.front()).tree.node->begin(); duration = easyBlock(root.children.back()).tree.node->end() - easyBlock(root.children.front()).tree.node->begin();
@ -2649,10 +2650,10 @@ void ThreadNamesWidget::onIdleTimeout()
} }
if (scenePos.y() + br.height() > visibleSceneRect.bottom()) if (scenePos.y() + br.height() > visibleSceneRect.bottom())
scenePos.setY(::std::max(scenePos.y() - br.height(), visibleSceneRect.top())); scenePos.setY(std::max(scenePos.y() - br.height(), visibleSceneRect.top()));
if (scenePos.x() + br.width() > visibleSceneRect.right()) if (scenePos.x() + br.width() > visibleSceneRect.right())
scenePos.setX(::std::max(scenePos.x() - br.width(), visibleSceneRect.left())); scenePos.setX(std::max(scenePos.x() - br.width(), visibleSceneRect.left()));
m_popupWidget->setPos(scenePos.x(), scenePos.y() - visibleSceneRect.top()); m_popupWidget->setPos(scenePos.x(), scenePos.y() - visibleSceneRect.top());
} }

View File

@ -64,23 +64,25 @@
#include <QMenu> #include <QMenu>
#include <QAction> #include <QAction>
#include <QActionGroup> #include <QActionGroup>
#include <QHeaderView> #include <QApplication>
#include <QByteArray>
#include <QContextMenuEvent> #include <QContextMenuEvent>
#include <QSignalBlocker> #include <QDebug>
#include <QSettings> #include <QHBoxLayout>
#include <QHeaderView>
#include <QLabel>
#include <QLineEdit>
#include <QMoveEvent>
#include <QProgressDialog> #include <QProgressDialog>
#include <QResizeEvent> #include <QResizeEvent>
#include <QMoveEvent> #include <QScrollBar>
#include <QLineEdit> #include <QSettings>
#include <QLabel> #include <QSignalBlocker>
#include <QToolBar> #include <QToolBar>
#include <QHBoxLayout>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QByteArray>
#include <QDebug>
#include <QApplication>
#include "blocks_tree_widget.h" #include "blocks_tree_widget.h"
#include "arbitrary_value_tooltip.h" #include "arbitrary_value_tooltip.h"
#include "round_progress_widget.h"
#include "globals.h" #include "globals.h"
#include "thread_pool.h" #include "thread_pool.h"
@ -139,6 +141,7 @@ BlocksTreeWidget::BlocksTreeWidget(QWidget* _parent)
, m_mode(TreeMode::Plain) , m_mode(TreeMode::Plain)
, m_bLocked(false) , m_bLocked(false)
, m_bSilentExpandCollapse(false) , m_bSilentExpandCollapse(false)
, m_bInitialized(false)
{ {
installEventFilter(this); installEventFilter(this);
memset(m_columnsHiddenStatus, 0, sizeof(m_columnsHiddenStatus)); memset(m_columnsHiddenStatus, 0, sizeof(m_columnsHiddenStatus));
@ -254,9 +257,10 @@ BlocksTreeWidget::BlocksTreeWidget(QWidget* _parent)
} }
} }
m_hintLabel = new QLabel("Use Right Mouse Button on the Diagram to build a hierarchy...\nPress and hold, move, release", this); m_hintLabel = new QLabel("Use Right Mouse Button on the Diagram to build a hierarchy...\n"
"Press and hold the button >> Move mouse >> Release the button", this);
m_hintLabel->setObjectName(QStringLiteral("BlocksTreeWidget_HintLabel"));
m_hintLabel->setAlignment(Qt::AlignCenter); m_hintLabel->setAlignment(Qt::AlignCenter);
m_hintLabel->setStyleSheet("QLabel { color: gray; font: 12pt; }");
QTimer::singleShot(1500, this, &This::alignProgressBar); QTimer::singleShot(1500, this, &This::alignProgressBar);
@ -273,9 +277,14 @@ BlocksTreeWidget::~BlocksTreeWidget()
bool BlocksTreeWidget::eventFilter(QObject* _object, QEvent* _event) bool BlocksTreeWidget::eventFilter(QObject* _object, QEvent* _event)
{ {
if (_object == this) if (_object != this)
return false;
const auto eventType = _event->type();
switch (eventType)
{ {
if (_event->type() == QEvent::MouseMove || _event->type() == QEvent::HoverMove) case QEvent::MouseMove:
case QEvent::HoverMove:
{ {
if (m_idleTimer.isActive()) if (m_idleTimer.isActive())
m_idleTimer.stop(); m_idleTimer.stop();
@ -298,7 +307,23 @@ bool BlocksTreeWidget::eventFilter(QObject* _object, QEvent* _event)
} }
m_idleTimer.start(); m_idleTimer.start();
break;
} }
case QEvent::Show:
{
if (!m_bInitialized)
{
EASY_CONSTEXPR int Margins = 20;
setMinimumSize(m_hintLabel->width() + Margins, m_hintLabel->height() + header()->height() + Margins);
m_bInitialized = true;
}
break;
}
default: break;
} }
return false; return false;
@ -801,13 +826,18 @@ void BlocksTreeWidget::moveEvent(QMoveEvent* _event)
void BlocksTreeWidget::alignProgressBar() void BlocksTreeWidget::alignProgressBar()
{ {
auto center = rect().center(); const auto scrollbarHeight = verticalScrollBar()->isVisible() ? verticalScrollBar()->height() : 0;
auto pos = mapToGlobal(center); const auto center = rect().adjusted(0, header()->height(), 0, -scrollbarHeight - 6).center();
if (m_progress != nullptr) if (m_progress != nullptr)
m_progress->move(pos.x() - (m_progress->width() >> 1), pos.y() - (m_progress->height() >> 1)); {
const auto pos = center;//mapToGlobal(center);
m_progress->move(pos.x() - (m_progress->width() >> 1),
std::max(pos.y() - (m_progress->height() >> 1), header()->height()));
}
m_hintLabel->move(center.x() - (m_hintLabel->width() >> 1), std::max(center.y() - (m_hintLabel->height() >> 1), header()->height())); m_hintLabel->move(center.x() - (m_hintLabel->width() >> 1),
std::max(center.y() - (m_hintLabel->height() >> 1), header()->height()));
} }
void BlocksTreeWidget::destroyProgressDialog() void BlocksTreeWidget::destroyProgressDialog()
@ -824,9 +854,9 @@ void BlocksTreeWidget::createProgressDialog()
{ {
destroyProgressDialog(); destroyProgressDialog();
m_progress = new QProgressDialog("Building blocks hierarchy...", "", 0, 100, this, Qt::FramelessWindowHint); m_progress = new RoundProgressDialog("Building blocks hierarchy...", this);
m_progress->setWindowFlags(Qt::FramelessWindowHint);
m_progress->setAttribute(Qt::WA_TranslucentBackground); m_progress->setAttribute(Qt::WA_TranslucentBackground);
m_progress->setCancelButton(nullptr);
m_progress->setValue(0); m_progress->setValue(0);
m_progress->show(); m_progress->show();
@ -981,8 +1011,7 @@ void BlocksTreeWidget::onItemCollapse(QTreeWidgetItem* _item)
void BlocksTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _previous) void BlocksTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _previous)
{ {
if (_previous != nullptr) (void)_previous;
static_cast<TreeWidgetItem*>(_previous)->setBold(false);
if (_item == nullptr) if (_item == nullptr)
{ {
@ -992,7 +1021,6 @@ void BlocksTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetIt
else else
{ {
auto item = static_cast<TreeWidgetItem*>(_item); auto item = static_cast<TreeWidgetItem*>(_item);
item->setBold(true);
EASY_GLOBALS.selected_block = item->block_index(); EASY_GLOBALS.selected_block = item->block_index();
if (EASY_GLOBALS.selected_block < EASY_GLOBALS.gui_blocks.size()) if (EASY_GLOBALS.selected_block < EASY_GLOBALS.gui_blocks.size())
@ -1044,10 +1072,6 @@ void BlocksTreeWidget::onSelectedBlockChange(uint32_t _block_index)
#endif #endif
} }
auto previous = static_cast<TreeWidgetItem*>(currentItem());
if (previous != nullptr)
previous->setBold(false);
if (item != nullptr) if (item != nullptr)
{ {
//const QSignalBlocker b(this); //const QSignalBlocker b(this);
@ -1074,8 +1098,6 @@ void BlocksTreeWidget::onSelectedBlockChange(uint32_t _block_index)
resizeColumnsToContents(); resizeColumnsToContents();
connect(this, &Parent::itemExpanded, this, &This::onItemExpand); connect(this, &Parent::itemExpanded, this, &This::onItemExpand);
} }
item->setBold(true);
} }
else else
{ {

View File

@ -91,12 +91,13 @@ protected:
QString m_lastSearch; QString m_lastSearch;
QTreeWidgetItem* m_lastFound; QTreeWidgetItem* m_lastFound;
::profiler::timestamp_t m_beginTime; ::profiler::timestamp_t m_beginTime;
class QProgressDialog* m_progress; class RoundProgressDialog* m_progress;
class QLabel* m_hintLabel; class QLabel* m_hintLabel;
class ArbitraryValueToolTip* m_valueTooltip; class ArbitraryValueToolTip* m_valueTooltip;
TreeMode m_mode; TreeMode m_mode;
bool m_bLocked; bool m_bLocked;
bool m_bSilentExpandCollapse; bool m_bSilentExpandCollapse;
bool m_bInitialized;
char m_columnsHiddenStatus[COL_COLUMNS_NUMBER]; char m_columnsHiddenStatus[COL_COLUMNS_NUMBER];
public: public:

View File

@ -110,7 +110,7 @@ struct EasyBlock Q_DECL_FINAL
EasyBlock() = default; EasyBlock() = default;
EasyBlock(EasyBlock&& that) EasyBlock(EasyBlock&& that) EASY_NOEXCEPT
: tree(::std::move(that.tree)) : tree(::std::move(that.tree))
#ifdef EASY_TREE_WIDGET__USE_VECTOR #ifdef EASY_TREE_WIDGET__USE_VECTOR
, tree_item(that.tree_item) , tree_item(that.tree_item)
@ -126,21 +126,19 @@ struct EasyBlock Q_DECL_FINAL
}; };
#pragma pack(pop) #pragma pack(pop)
typedef ::std::vector<EasyBlockItem> EasyItems; using EasyItems = ::std::vector<EasyBlockItem>;
typedef ::std::vector<EasyBlock> EasyBlocks; using EasyBlocks = ::std::vector<EasyBlock>;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
struct EasySelectedBlock Q_DECL_FINAL struct EasySelectedBlock Q_DECL_FINAL
{ {
const ::profiler::BlocksTreeRoot* root; const ::profiler::BlocksTreeRoot* root = nullptr;
::profiler::block_index_t tree; ::profiler::block_index_t tree = 0xffffffff;
EasySelectedBlock() : root(nullptr), tree(0xffffffff) EasySelectedBlock() = default;
{
}
EasySelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::block_index_t _tree) EasySelectedBlock(const ::profiler::BlocksTreeRoot* _root, const ::profiler::block_index_t _tree) EASY_NOEXCEPT
: root(_root) : root(_root)
, tree(_tree) , tree(_tree)
{ {

View File

@ -105,8 +105,8 @@ const QPen HIGHLIGHTER_PEN = ([]() -> QPen { QPen p(profiler::colors::Black); p.
GraphicsBlockItem::GraphicsBlockItem(uint8_t _index, const profiler::BlocksTreeRoot& _root) GraphicsBlockItem::GraphicsBlockItem(uint8_t _index, const profiler::BlocksTreeRoot& _root)
: QGraphicsItem(nullptr) : QGraphicsItem(nullptr)
, m_thread(_root)
, m_threadName(::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, _root, EASY_GLOBALS.hex_thread_id)) , m_threadName(::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, _root, EASY_GLOBALS.hex_thread_id))
, m_pRoot(&_root)
, m_index(_index) , m_index(_index)
{ {
} }
@ -117,7 +117,7 @@ GraphicsBlockItem::~GraphicsBlockItem()
void GraphicsBlockItem::validateName() void GraphicsBlockItem::validateName()
{ {
m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, *m_pRoot, EASY_GLOBALS.hex_thread_id); m_threadName = ::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, m_thread, EASY_GLOBALS.hex_thread_id);
} }
const BlocksGraphicsView* GraphicsBlockItem::view() const const BlocksGraphicsView* GraphicsBlockItem::view() const
@ -453,7 +453,7 @@ void GraphicsBlockItem::paintChildren(const float _minWidth, const int _narrowSi
void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*) void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*)
{ {
const bool gotItems = !m_levels.empty() && !m_levels.front().empty(); const bool gotItems = !m_levels.empty() && !m_levels.front().empty();
const bool gotSync = !m_pRoot->sync.empty(); const bool gotSync = !m_thread.sync.empty();
if (!gotItems && !gotSync) if (!gotItems && !gotSync)
{ {
@ -963,21 +963,21 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem
if (gotSync) if (gotSync)
{ {
const auto sceneView = view(); const auto sceneView = view();
auto firstSync = ::std::lower_bound(m_pRoot->sync.begin(), m_pRoot->sync.end(), p.sceneLeft, [&sceneView](::profiler::block_index_t _index, qreal _value) auto firstSync = ::std::lower_bound(m_thread.sync.begin(), m_thread.sync.end(), p.sceneLeft, [&sceneView](::profiler::block_index_t _index, qreal _value)
{ {
return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value; return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value;
}); });
if (firstSync != m_pRoot->sync.end()) if (firstSync != m_thread.sync.end())
{ {
if (firstSync != m_pRoot->sync.begin()) if (firstSync != m_thread.sync.begin())
--firstSync; --firstSync;
} }
else if (!m_pRoot->sync.empty()) else if (!m_thread.sync.empty())
{ {
firstSync = m_pRoot->sync.begin() + m_pRoot->sync.size() - 1; firstSync = m_thread.sync.begin() + m_thread.sync.size() - 1;
} }
//firstSync = m_pRoot->sync.begin(); //firstSync = m_thread.sync.begin();
p.previousColor = 0; p.previousColor = 0;
qreal prevRight = -1e100; qreal prevRight = -1e100;
@ -986,7 +986,7 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem
{ {
_painter->setPen(BORDERS_COLOR); _painter->setPen(BORDERS_COLOR);
for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it) for (auto it = firstSync, end = m_thread.sync.end(); it != end; ++it)
{ {
const auto& item = easyBlocksTree(*it); const auto& item = easyBlocksTree(*it);
auto left = sceneView->time2position(item.node->begin()); auto left = sceneView->time2position(item.node->begin());
@ -1039,22 +1039,22 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem
if (EASY_GLOBALS.enable_event_markers && !m_pRoot->events.empty()) if (EASY_GLOBALS.enable_event_markers && !m_thread.events.empty())
{ {
const auto sceneView = view(); const auto sceneView = view();
auto first = ::std::lower_bound(m_pRoot->events.begin(), m_pRoot->events.end(), p.offset, [&sceneView](::profiler::block_index_t _index, qreal _value) auto first = ::std::lower_bound(m_thread.events.begin(), m_thread.events.end(), p.offset, [&sceneView](::profiler::block_index_t _index, qreal _value)
{ {
return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value; return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value;
}); });
if (first != m_pRoot->events.end()) if (first != m_thread.events.end())
{ {
if (first != m_pRoot->events.begin()) if (first != m_thread.events.begin())
--first; --first;
} }
else if (!m_pRoot->events.empty()) else if (!m_thread.events.empty())
{ {
first = m_pRoot->events.begin() + m_pRoot->events.size() - 1; first = m_thread.events.begin() + m_thread.events.size() - 1;
} }
p.previousColor = 0; p.previousColor = 0;
@ -1064,7 +1064,7 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem
{ {
_painter->setPen(BORDERS_COLOR); _painter->setPen(BORDERS_COLOR);
for (auto it = first, end = m_pRoot->events.end(); it != end; ++it) for (auto it = first, end = m_thread.events.end(); it != end; ++it)
{ {
const auto& item = easyBlocksTree(*it); const auto& item = easyBlocksTree(*it);
auto left = sceneView->time2position(item.node->begin()); auto left = sceneView->time2position(item.node->begin());
@ -1115,9 +1115,9 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
const ::profiler::BlocksTreeRoot* GraphicsBlockItem::root() const const profiler::BlocksTreeRoot& GraphicsBlockItem::root() const
{ {
return m_pRoot; return m_thread;
} }
const QString& GraphicsBlockItem::threadName() const const QString& GraphicsBlockItem::threadName() const
@ -1173,7 +1173,7 @@ void GraphicsBlockItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tre
continue; continue;
} }
_blocks.emplace_back(m_pRoot, item.block); _blocks.emplace_back(&m_thread, item.block);
} }
} }
@ -1206,31 +1206,31 @@ const ::profiler_gui::EasyBlock* GraphicsBlockItem::intersect(const QPointF& _po
{ {
// The Y position is out of blocks range // The Y position is out of blocks range
if (EASY_GLOBALS.enable_event_markers && !m_pRoot->events.empty()) if (EASY_GLOBALS.enable_event_markers && !m_thread.events.empty())
{ {
// If event indicators are enabled then try to intersect with one of event indicators // If event indicators are enabled then try to intersect with one of event indicators
const auto& sceneView = view(); const auto& sceneView = view();
auto first = ::std::lower_bound(m_pRoot->events.begin(), m_pRoot->events.end(), _pos.x(), [&sceneView](::profiler::block_index_t _index, qreal _value) auto first = ::std::lower_bound(m_thread.events.begin(), m_thread.events.end(), _pos.x(), [&sceneView](::profiler::block_index_t _index, qreal _value)
{ {
return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value; return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value;
}); });
if (first != m_pRoot->events.end()) if (first != m_thread.events.end())
{ {
if (first != m_pRoot->events.begin()) if (first != m_thread.events.begin())
--first; --first;
} }
else if (!m_pRoot->events.empty()) else if (!m_thread.events.empty())
{ {
first = m_pRoot->events.begin() + m_pRoot->events.size() - 1; first = m_thread.events.begin() + m_thread.events.size() - 1;
} }
const auto MIN_WIDTH = EASY_GLOBALS.enable_zero_length ? 0.f : 0.25f; const auto MIN_WIDTH = EASY_GLOBALS.enable_zero_length ? 0.f : 0.25f;
const auto currentScale = sceneView->scale(); const auto currentScale = sceneView->scale();
const auto dw = 5. / currentScale; const auto dw = 5. / currentScale;
for (auto it = first, end = m_pRoot->events.end(); it != end; ++it) for (auto it = first, end = m_thread.events.end(); it != end; ++it)
{ {
_blockIndex = *it; _blockIndex = *it;
const auto& item = easyBlock(_blockIndex); const auto& item = easyBlock(_blockIndex);
@ -1354,7 +1354,7 @@ const ::profiler_gui::EasyBlock* GraphicsBlockItem::intersect(const QPointF& _po
const ::profiler_gui::EasyBlock* GraphicsBlockItem::intersectEvent(const QPointF& _pos) const const ::profiler_gui::EasyBlock* GraphicsBlockItem::intersectEvent(const QPointF& _pos) const
{ {
if (m_pRoot->sync.empty()) if (m_thread.sync.empty())
{ {
return nullptr; return nullptr;
} }
@ -1372,18 +1372,18 @@ const ::profiler_gui::EasyBlock* GraphicsBlockItem::intersectEvent(const QPointF
} }
const auto sceneView = view(); const auto sceneView = view();
auto firstSync = ::std::lower_bound(m_pRoot->sync.begin(), m_pRoot->sync.end(), _pos.x(), [&sceneView](::profiler::block_index_t _index, qreal _value) auto firstSync = ::std::lower_bound(m_thread.sync.begin(), m_thread.sync.end(), _pos.x(), [&sceneView](::profiler::block_index_t _index, qreal _value)
{ {
return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value; return sceneView->time2position(easyBlocksTree(_index).node->begin()) < _value;
}); });
if (firstSync == m_pRoot->sync.end()) if (firstSync == m_thread.sync.end())
firstSync = m_pRoot->sync.begin() + m_pRoot->sync.size() - 1; firstSync = m_thread.sync.begin() + m_thread.sync.size() - 1;
else if (firstSync != m_pRoot->sync.begin()) else if (firstSync != m_thread.sync.begin())
--firstSync; --firstSync;
const auto dw = 4. / view()->scale(); const auto dw = 4. / view()->scale();
for (auto it = firstSync, end = m_pRoot->sync.end(); it != end; ++it) for (auto it = firstSync, end = m_thread.sync.end(); it != end; ++it)
{ {
const auto& item = easyBlock(*it); const auto& item = easyBlock(*it);
@ -1417,7 +1417,7 @@ void GraphicsBlockItem::setBoundingRect(const QRectF& _rect)
::profiler::thread_id_t GraphicsBlockItem::threadId() const ::profiler::thread_id_t GraphicsBlockItem::threadId() const
{ {
return m_pRoot->thread_id; return m_thread.thread_id;
} }
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////

View File

@ -74,19 +74,20 @@ class GraphicsBlockItem : public QGraphicsItem
using RightBounds = std::vector<qreal>; using RightBounds = std::vector<qreal>;
using Sublevels = std::vector<Children>; using Sublevels = std::vector<Children>;
const profiler::BlocksTreeRoot& m_thread; ///< Reference to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
DrawIndexes m_levelsIndexes; ///< Indexes of first item on each level from which we must start painting DrawIndexes m_levelsIndexes; ///< Indexes of first item on each level from which we must start painting
RightBounds m_rightBounds; ///< RightBounds m_rightBounds; ///<
Sublevels m_levels; ///< Arrays of items for each level Sublevels m_levels; ///< Arrays of items for each level
QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem) QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem)
QString m_threadName; ///< QString m_threadName; ///<
const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy.
uint8_t m_index; ///< This item's index in the list of items of BlocksGraphicsView uint8_t m_index; ///< This item's index in the list of items of BlocksGraphicsView
public: public:
explicit GraphicsBlockItem(uint8_t _index, const::profiler::BlocksTreeRoot& _root); explicit GraphicsBlockItem(uint8_t _index, const profiler::BlocksTreeRoot& _root);
virtual ~GraphicsBlockItem(); ~GraphicsBlockItem() override;
// Public virtual methods // Public virtual methods
@ -100,7 +101,7 @@ public:
void validateName(); void validateName();
const ::profiler::BlocksTreeRoot* root() const; const profiler::BlocksTreeRoot& root() const;
const QString& threadName() const; const QString& threadName() const;
QRect getRect() const; QRect getRect() const;

View File

@ -0,0 +1,301 @@
/************************************************************************
* file name : round_progress_widget.cpp
* ----------------- :
* creation time : 2018/05/17
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains implementation of RoundProgressWidget.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#include "round_progress_widget.h"
#include <math.h>
#include <easy/utility.h>
#include <QFontMetrics>
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QVBoxLayout>
#ifdef max
# undef max
#endif
RoundProgressIndicator::RoundProgressIndicator(QWidget* parent)
: Parent(parent)
, m_text("0%")
, m_background(Qt::transparent)
, m_color(Qt::green)
, m_value(0)
{
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
}
RoundProgressIndicator::~RoundProgressIndicator()
{
}
int RoundProgressIndicator::value() const
{
return m_value;
}
void RoundProgressIndicator::setValue(int value)
{
m_value = static_cast<int8_t>(estd::clamp(0, value, 100));
m_text = QString("%1%").arg(m_value);
update();
}
void RoundProgressIndicator::reset()
{
m_value = 0;
m_text = "0%";
update();
}
QColor RoundProgressIndicator::background() const
{
return m_background;
}
void RoundProgressIndicator::setBackground(QColor color)
{
m_background = std::move(color);
update();
}
void RoundProgressIndicator::setBackground(QString color)
{
m_background.setNamedColor(color);
update();
}
QColor RoundProgressIndicator::color() const
{
return m_color;
}
void RoundProgressIndicator::setColor(QColor color)
{
m_color = std::move(color);
update();
}
void RoundProgressIndicator::setColor(QString color)
{
m_color.setNamedColor(color);
update();
}
void RoundProgressIndicator::showEvent(QShowEvent* event)
{
Parent::showEvent(event);
const QFontMetrics fm(font());
const QString text = QStringLiteral("100%");
const int size = std::max(fm.width(text), fm.height()) + 4 * 4;
setFixedSize(size, size);
}
void RoundProgressIndicator::paintEvent(QPaintEvent* /*event*/)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setBrush(Qt::NoBrush);
const auto r = rect().adjusted(4, 4, -4, -4);
auto p = painter.pen();
// Draw circle
p.setWidth(4);
p.setColor(m_background);
painter.setPen(p);
painter.drawArc(r, 0, 360 * 16);
p.setColor(m_color);
painter.setPen(p);
painter.drawArc(r, 90 * 16, -1 * static_cast<int>(m_value) * 16 * 360 / 100);
// Draw text
p.setWidth(1);
p.setColor(palette().foreground().color());
painter.setPen(p);
painter.drawText(r, Qt::AlignCenter, m_text);
}
RoundProgressWidget::RoundProgressWidget(QWidget* parent)
: RoundProgressWidget(QString(), parent)
{
}
RoundProgressWidget::RoundProgressWidget(const QString& title, QWidget* parent)
: Parent(parent)
, m_title(new QLabel(title, this))
, m_indicatorWrapper(new QWidget(this))
, m_indicator(new RoundProgressIndicator(this))
, m_titlePosition(RoundProgressWidget::Top)
{
setWindowFlags(Qt::FramelessWindowHint);
setAttribute(Qt::WA_TranslucentBackground);
m_indicatorWrapper->setWindowFlags(Qt::FramelessWindowHint);
m_indicatorWrapper->setAttribute(Qt::WA_TranslucentBackground);
auto wlay = new QHBoxLayout(m_indicatorWrapper);
wlay->setContentsMargins(0, 0, 0, 0);
wlay->addWidget(m_indicator, 0, Qt::AlignCenter);
auto lay = new QVBoxLayout(this);
lay->addWidget(m_title);
lay->addWidget(m_indicatorWrapper);
}
RoundProgressWidget::~RoundProgressWidget()
{
}
void RoundProgressWidget::setTitle(const QString& title)
{
m_title->setText(title);
}
int RoundProgressWidget::value() const
{
return m_indicator->value();
}
void RoundProgressWidget::setValue(int value)
{
const auto prev = m_indicator->value();
const auto newValue = static_cast<int8_t>(estd::clamp(0, value, 100));
if (prev == newValue)
return;
m_indicator->setValue(newValue);
const auto v = m_indicator->value();
emit valueChanged(v);
if (v == 100)
emit finished();
}
void RoundProgressWidget::reset()
{
m_indicator->reset();
}
RoundProgressWidget::TitlePosition RoundProgressWidget::titlePosition() const
{
return m_titlePosition;
}
void RoundProgressWidget::setTitlePosition(TitlePosition pos)
{
const auto prev = m_titlePosition;
if (prev == pos)
return;
m_titlePosition = pos;
auto lay = static_cast<QVBoxLayout*>(layout());
if (pos == RoundProgressWidget::Top)
{
lay->removeWidget(m_indicatorWrapper);
lay->removeWidget(m_title);
lay->addWidget(m_title);
lay->addWidget(m_indicatorWrapper);
}
else
{
lay->removeWidget(m_title);
lay->removeWidget(m_indicator);
lay->addWidget(m_indicator);
lay->addWidget(m_title);
}
emit titlePositionChanged();
}
bool RoundProgressWidget::isTopTitlePosition() const
{
return m_titlePosition == RoundProgressWidget::Top;
}
void RoundProgressWidget::setTopTitlePosition(bool isTop)
{
setTitlePosition(isTop ? RoundProgressWidget::Top : RoundProgressWidget::Bottom);
}
RoundProgressDialog::RoundProgressDialog(const QString& title, QWidget* parent)
: Parent(parent)
, m_progress(new RoundProgressWidget(title, this))
{
auto lay = new QVBoxLayout(this);
lay->addWidget(m_progress);
}
RoundProgressDialog::~RoundProgressDialog()
{
}
void RoundProgressDialog::showEvent(QShowEvent* event)
{
Parent::showEvent(event);
adjustSize();
}
void RoundProgressDialog::setValue(int value)
{
m_progress->setValue(value);
if (value == 100)
hide();
}

View File

@ -0,0 +1,174 @@
/************************************************************************
* file name : round_progress_widget.h
* ----------------- :
* creation time : 2018/05/17
* author : Victor Zarubkin
* email : v.s.zarubkin@gmail.com
* ----------------- :
* description : The file contains declaration of RoundProgressWidget.
* ----------------- :
* license : Lightweight profiler library for c++
* : Copyright(C) 2016-2018 Sergey Yagovtsev, Victor Zarubkin
* :
* : Licensed under either of
* : * MIT license (LICENSE.MIT or http://opensource.org/licenses/MIT)
* : * Apache License, Version 2.0, (LICENSE.APACHE or http://www.apache.org/licenses/LICENSE-2.0)
* : at your option.
* :
* : The MIT License
* :
* : Permission is hereby granted, free of charge, to any person obtaining a copy
* : of this software and associated documentation files (the "Software"), to deal
* : in the Software without restriction, including without limitation the rights
* : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
* : of the Software, and to permit persons to whom the Software is furnished
* : to do so, subject to the following conditions:
* :
* : The above copyright notice and this permission notice shall be included in all
* : copies or substantial portions of the Software.
* :
* : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* : INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* : PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* : LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* : TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* : USE OR OTHER DEALINGS IN THE SOFTWARE.
* :
* : The Apache License, Version 2.0 (the "License")
* :
* : You may not use this file except in compliance with the License.
* : You may obtain a copy of the License at
* :
* : http://www.apache.org/licenses/LICENSE-2.0
* :
* : Unless required by applicable law or agreed to in writing, software
* : distributed under the License is distributed on an "AS IS" BASIS,
* : WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* : See the License for the specific language governing permissions and
* : limitations under the License.
************************************************************************/
#ifndef ROUND_PROGRESS_WIDGET_H
#define ROUND_PROGRESS_WIDGET_H
#include <stdint.h>
#include <QColor>
#include <QWidget>
#include <QDialog>
class RoundProgressIndicator : public QWidget
{
Q_OBJECT
using Parent = QWidget;
using This = RoundProgressIndicator;
QString m_text;
QColor m_background;
QColor m_color;
int8_t m_value;
public:
Q_PROPERTY(QColor color READ color WRITE setColor);
Q_PROPERTY(QColor background READ background WRITE setBackground);
explicit RoundProgressIndicator(QWidget* parent = nullptr);
~RoundProgressIndicator() override;
int value() const;
void setValue(int value);
void reset();
QColor background() const;
QColor color() const;
public slots:
void setBackground(QColor color);
void setBackground(QString color);
void setColor(QColor color);
void setColor(QString color);
protected:
void showEvent(QShowEvent* event) override;
void paintEvent(QPaintEvent* event) override;
}; // end of class RoundProgressIndicator.
class RoundProgressWidget : public QWidget
{
Q_OBJECT
using Parent = QWidget;
using This = RoundProgressWidget;
public:
Q_PROPERTY(bool topTitlePosition READ isTopTitlePosition WRITE setTopTitlePosition NOTIFY titlePositionChanged);
enum TitlePosition : int8_t
{
Top = 0,
Bottom,
};
private:
class QLabel* m_title;
QWidget* m_indicatorWrapper;
RoundProgressIndicator* m_indicator;
TitlePosition m_titlePosition;
public:
explicit RoundProgressWidget(QWidget* parent = nullptr);
explicit RoundProgressWidget(const QString& title, QWidget* parent = nullptr);
~RoundProgressWidget() override;
void setTitle(const QString& title);
int value() const;
TitlePosition titlePosition() const;
bool isTopTitlePosition() const;
public slots:
void setValue(int value);
void reset();
void setTitlePosition(TitlePosition pos);
void setTopTitlePosition(bool isTop);
signals:
void valueChanged(int value);
void finished();
void titlePositionChanged();
}; // end of class RoundProgressWidget.
class RoundProgressDialog : public QDialog
{
Q_OBJECT
using Parent = QDialog;
using This = RoundProgressDialog;
RoundProgressWidget* m_progress;
public:
explicit RoundProgressDialog(const QString& title, QWidget* parent = nullptr);
~RoundProgressDialog() override;
protected:
void showEvent(QShowEvent* event) override;
public slots:
void setValue(int value);
}; // end of RoundProgressDialog.
#endif // ROUND_PROGRESS_WIDGET_H

View File

@ -183,16 +183,6 @@ QVariant TreeWidgetItem::data(int _column, int _role) const
{ {
if (_column == COL_NAME) if (_column == COL_NAME)
{ {
if (_role == Qt::SizeHintRole)
{
#ifdef _WIN32
const float k = m_font.bold() ? 1.2f : 1.f;
#else
const float k = m_font.bold() ? 1.15f : 1.f;
#endif
return QSize(static_cast<int>(QFontMetrics(m_font).width(text(COL_NAME)) * k) + 20, 26);
}
if (_role == BlockColorRole) if (_role == BlockColorRole)
{ {
if (parent() != nullptr || m_bMain) if (parent() != nullptr || m_bMain)
@ -203,9 +193,6 @@ QVariant TreeWidgetItem::data(int _column, int _role) const
switch (_role) switch (_role)
{ {
case Qt::FontRole:
return m_font;
case Qt::ForegroundRole: case Qt::ForegroundRole:
return m_bMain ? QVariant::fromValue(QColor::fromRgb(profiler_gui::SELECTED_THREAD_FOREGROUND)) : QVariant(); return m_bMain ? QVariant::fromValue(QColor::fromRgb(profiler_gui::SELECTED_THREAD_FOREGROUND)) : QVariant();
@ -331,11 +318,6 @@ void TreeWidgetItem::expandAll()
guiBlock().expanded = true; guiBlock().expanded = true;
} }
void TreeWidgetItem::setBold(bool _bold)
{
m_font.setBold(_bold);
}
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
TreeWidgetItemDelegate::TreeWidgetItemDelegate(QTreeWidget* parent) : QStyledItemDelegate(parent), m_treeWidget(parent) TreeWidgetItemDelegate::TreeWidgetItemDelegate(QTreeWidget* parent) : QStyledItemDelegate(parent), m_treeWidget(parent)
@ -350,7 +332,7 @@ TreeWidgetItemDelegate::~TreeWidgetItemDelegate()
void TreeWidgetItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const void TreeWidgetItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const
{ {
auto brushData = m_treeWidget->model()->data(index, BlockColorRole); const auto brushData = m_treeWidget->model()->data(index, BlockColorRole);
if (brushData.isNull()) if (brushData.isNull())
{ {
// Draw item as usual // Draw item as usual
@ -364,7 +346,7 @@ void TreeWidgetItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem
{ {
// Draw selection background for selected row // Draw selection background for selected row
painter->save(); painter->save();
painter->setBrush(QColor::fromRgba(0xCC98DE98)); painter->setBrush(m_treeWidget->palette().highlight());
painter->setPen(Qt::NoPen); painter->setPen(Qt::NoPen);
painter->drawRect(QRect(option.rect.left(), option.rect.top(), colorBlockSize, option.rect.height())); painter->drawRect(QRect(option.rect.left(), option.rect.top(), colorBlockSize, option.rect.height()));
painter->restore(); painter->restore();
@ -382,15 +364,16 @@ void TreeWidgetItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem
painter->save(); painter->save();
// Draw color marker with block color // Draw color marker with block color
const auto brush = m_treeWidget->model()->data(index, Qt::UserRole + 1).value<QBrush>(); const auto brush = brushData.value<QBrush>();
painter->setBrush(brush); painter->setBrush(brush);
painter->setPen(profiler_gui::SYSTEM_BORDER_COLOR); painter->setPen(QColor::fromRgb(profiler::colors::Grey600));
painter->drawRect(QRect(option.rect.left(), option.rect.top() + (colorBlockRest >> 1), painter->drawRect(QRect(option.rect.left(), option.rect.top() + (colorBlockRest >> 1),
colorBlockSize, option.rect.height() - colorBlockRest)); colorBlockSize, option.rect.height() - colorBlockRest));
// Draw line under tree indicator // Draw line under tree indicator
const auto bottomLeft = opt.rect.bottomLeft(); const auto bottomLeft = opt.rect.bottomLeft();
painter->setBrush(Qt::NoBrush); painter->setBrush(Qt::NoBrush);
painter->setPen(profiler_gui::SYSTEM_BORDER_COLOR);
painter->drawLine(QPoint(bottomLeft.x() - colorBlockSize, bottomLeft.y()), bottomLeft); painter->drawLine(QPoint(bottomLeft.x() - colorBlockSize, bottomLeft.y()), bottomLeft);
painter->restore(); painter->restore();

View File

@ -118,7 +118,6 @@ class TreeWidgetItem : public QTreeWidgetItem
using Parent = QTreeWidgetItem; using Parent = QTreeWidgetItem;
using This = TreeWidgetItem; using This = TreeWidgetItem;
QFont m_font;
const profiler::block_index_t m_block; const profiler::block_index_t m_block;
QRgb m_customBGColor; QRgb m_customBGColor;
std::bitset<17> m_bHasToolTip; std::bitset<17> m_bHasToolTip;
@ -126,7 +125,9 @@ class TreeWidgetItem : public QTreeWidgetItem
public: public:
explicit TreeWidgetItem(const profiler::block_index_t _treeBlock = profiler_gui::numeric_max<decltype(m_block)>(), Parent* _parent = nullptr); explicit TreeWidgetItem(const profiler::block_index_t _treeBlock = profiler_gui::numeric_max<decltype(m_block)>()
, Parent* _parent = nullptr);
~TreeWidgetItem() override; ~TreeWidgetItem() override;
bool operator < (const Parent& _other) const override; bool operator < (const Parent& _other) const override;
@ -156,8 +157,6 @@ public:
void expandAll(); void expandAll();
void setBold(bool _bold);
private: private:
void setHasToolTip(int _column); void setHasToolTip(int _column);

View File

@ -301,7 +301,7 @@ void TreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTim
const auto endTime = gui_block.tree.node->end(); const auto endTime = gui_block.tree.node->end();
if (startTime > _right || endTime < _left) if (startTime > _right || endTime < _left)
{ {
setProgress((90 * ++i) / total); setProgress((95 * ++i) / total);
continue; continue;
} }
@ -502,7 +502,7 @@ void TreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTim
delete item; delete item;
} }
setProgress((90 * ++i) / total); setProgress((95 * ++i) / total);
} }
i = 0; i = 0;
@ -526,7 +526,7 @@ void TreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTim
delete item; delete item;
} }
setProgress(90 + (10 * ++i) / total); setProgress(95 + (5 * ++i) / total);
} }
setDone(); setDone();

View File

@ -122,6 +122,7 @@ private:
void setTreeInternal1(profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const profiler::thread_blocks_tree_t& _blocksTree, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units); void setTreeInternal1(profiler::timestamp_t& _beginTime, const unsigned int _blocksNumber, const profiler::thread_blocks_tree_t& _blocksTree, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units);
void setTreeInternal2(const profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, profiler::timestamp_t _left, profiler::timestamp_t _right, bool _strict, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units); void setTreeInternal2(const profiler::timestamp_t& _beginTime, const ::profiler_gui::TreeBlocks& _blocks, profiler::timestamp_t _left, profiler::timestamp_t _right, bool _strict, bool _addZeroBlocks, bool _decoratedThreadNames, bool _hexThreadId, ::profiler_gui::TimeUnits _units);
size_t setTreeInternal(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _firstCswitch, const profiler::timestamp_t& _beginTime, const profiler::BlocksTree::children_t& _children, TreeWidgetItem* _parent, TreeWidgetItem* _frame, profiler::timestamp_t _left, profiler::timestamp_t _right, bool _strict, profiler::timestamp_t& _duration, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units); size_t setTreeInternal(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _firstCswitch, const profiler::timestamp_t& _beginTime, const profiler::BlocksTree::children_t& _children, TreeWidgetItem* _parent, TreeWidgetItem* _frame, profiler::timestamp_t _left, profiler::timestamp_t _right, bool _strict, profiler::timestamp_t& _duration, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);
size_t setTreeInternalPlain(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _firstCswitch, const profiler::timestamp_t& _beginTime, const profiler::BlocksTree::children_t& _children, TreeWidgetItem* _parent, TreeWidgetItem* _frame, profiler::timestamp_t _left, profiler::timestamp_t _right, bool _strict, profiler::timestamp_t& _duration, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units); size_t setTreeInternalPlain(const profiler::BlocksTreeRoot& _threadRoot, profiler::block_index_t _firstCswitch, const profiler::timestamp_t& _beginTime, const profiler::BlocksTree::children_t& _children, TreeWidgetItem* _parent, TreeWidgetItem* _frame, profiler::timestamp_t _left, profiler::timestamp_t _right, bool _strict, profiler::timestamp_t& _duration, bool _addZeroBlocks, ::profiler_gui::TimeUnits _units);