diff --git a/profiler_gui/CMakeLists.txt b/profiler_gui/CMakeLists.txt index e23412c..1d9d539 100644 --- a/profiler_gui/CMakeLists.txt +++ b/profiler_gui/CMakeLists.txt @@ -42,6 +42,8 @@ if (Qt5Widgets_FOUND) graphics_slider_area.cpp main_window.h main_window.cpp + round_progress_widget.h + round_progress_widget.cpp timer.h timer.cpp thread_pool.h diff --git a/profiler_gui/blocks_graphics_view.cpp b/profiler_gui/blocks_graphics_view.cpp index d28bc76..4af3e2d 100644 --- a/profiler_gui/blocks_graphics_view.cpp +++ b/profiler_gui/blocks_graphics_view.cpp @@ -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 EASY_CONSTEXPR QRgb BACKGROUND_1 = 0xffe4e4ec; -EASY_CONSTEXPR QRgb BACKGROUND_2 = ::profiler::colors::White; -EASY_CONSTEXPR QRgb TIMELINE_BACKGROUND = 0x20000000 | (::profiler::colors::Grey800 & 0x00ffffff);// 0x20303030; +EASY_CONSTEXPR QRgb BACKGROUND_2 = profiler::colors::White; +EASY_CONSTEXPR QRgb TIMELINE_BACKGROUND = 0x20000000 | (profiler::colors::Grey800 & 0x00ffffff);// 0x20303030; EASY_CONSTEXPR QRgb TIMELINE_BORDER = 0xffa8a0a0; EASY_CONSTEXPR int IDLE_TIMER_INTERVAL = 200; // 5Hz @@ -284,7 +284,7 @@ void TimelineIndicatorItem::paint(QPainter* _painter, const QStyleOptionGraphics BlocksGraphicsView::BlocksGraphicsView(QWidget* _parent) : Parent(_parent) - , m_beginTime(::std::numeric_limits::max()) + , m_beginTime(std::numeric_limits::max()) , m_sceneWidth(0) , m_scale(1) , m_offset(0) @@ -380,7 +380,7 @@ void BlocksGraphicsView::clear() m_items.clear(); m_selectedBlocks.clear(); - m_beginTime = ::std::numeric_limits::max(); // reset begin time + m_beginTime = std::numeric_limits::max(); // reset begin time m_scale = 1; // scale back to initial 100% scale m_timelineStep = 1; m_offset = 0; // scroll back to the beginning of the scene @@ -448,7 +448,7 @@ void BlocksGraphicsView::notifyVisibleRegionPosChange(qreal _pos) notifyVisibleRegionPosChange(); } -void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocksTree) +void BlocksGraphicsView::setTree(const profiler::thread_blocks_tree_t& _blocksTree) { // clear scene clear(); @@ -464,8 +464,8 @@ void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocks // calculate scene size and fill it with items // Calculating start and end time - ::profiler::timestamp_t finish = 0, busyTime = 0; - ::profiler::thread_id_t longestTree = 0, mainTree = 0; + profiler::timestamp_t finish = 0, busyTime = 0; + profiler::thread_id_t longestTree = 0, mainTree = 0; for (const auto& threadTree : _blocksTree) { const auto& t = threadTree.second; @@ -476,12 +476,12 @@ void BlocksGraphicsView::setTree(const ::profiler::thread_blocks_tree_t& _blocks if (!t.children.empty()) timestart = easyBlocksTree(t.children.front()).node->begin(); 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()) timefinish = easyBlocksTree(t.children.back()).node->end(); 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) 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 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; // Sort threads by name - ::std::vector<::std::reference_wrapper > sorted_roots; + std::vector > sorted_roots; sorted_roots.reserve(_blocksTree.size()); for (const auto& threadTree : _blocksTree) - sorted_roots.push_back(threadTree.second); - ::std::sort(sorted_roots.begin(), sorted_roots.end(), [](const ::profiler::BlocksTreeRoot& _a, const ::profiler::BlocksTreeRoot& _b) { + sorted_roots.emplace_back(threadTree.second); + std::sort(sorted_roots.begin(), sorted_roots.end(), [](const profiler::BlocksTreeRoot& _a, const profiler::BlocksTreeRoot& _b) { 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()); qreal y = EASY_GLOBALS.size.timeline_height; 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) { @@ -635,7 +635,7 @@ bool BlocksGraphicsView::getSelectionRegionForSaving(profiler::timestamp_t& _beg 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()) { @@ -1063,7 +1063,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event) } 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; if (m_mouseButtons & Qt::LeftButton) { @@ -1096,7 +1096,7 @@ void BlocksGraphicsView::mouseReleaseEvent(QMouseEvent* _event) // Try to select one of item blocks for (auto item : m_items) { - ::profiler::block_index_t i = ~0U; + profiler::block_index_t i = ~0U; auto block = item->intersect(mouseClickPos, i); if (block != nullptr) { @@ -1558,7 +1558,7 @@ void BlocksGraphicsView::initMode() 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)) { @@ -1747,7 +1747,7 @@ void BlocksGraphicsView::onIdleTimeout() lay->addWidget(new QLabel("Thread:", widget), row, 0, Qt::AlignRight); const char* process_name = ""; - ::profiler::thread_id_t tid = 0; + profiler::thread_id_t tid = 0; if (EASY_GLOBALS.version < ::profiler_gui::V130) { tid = cse->tree.node->id(); @@ -1797,10 +1797,10 @@ void BlocksGraphicsView::onIdleTimeout() 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(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); @@ -1826,7 +1826,7 @@ void BlocksGraphicsView::onIdleTimeout() break; } - ::profiler::block_index_t i = ~0U; + profiler::block_index_t i = ~0U; auto block = item->intersect(pos, i); if (block != nullptr) { @@ -1855,7 +1855,7 @@ void BlocksGraphicsView::onIdleTimeout() int row = 0; switch (itemDesc.type()) { - case ::profiler::BlockType::Block: + case profiler::BlockType::Block: { 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); ++row; - ::profiler::timestamp_t children_duration = 0; + profiler::timestamp_t children_duration = 0; for (auto child : itemBlock.children) children_duration += easyBlock(child).tree.node->duration(); @@ -1888,7 +1888,7 @@ void BlocksGraphicsView::onIdleTimeout() break; } - case ::profiler::BlockType::Event: + case profiler::BlockType::Event: { const auto name = *itemBlock.node->name() != 0 ? itemBlock.node->name() : itemDesc.name(); @@ -1902,7 +1902,7 @@ void BlocksGraphicsView::onIdleTimeout() break; } - case ::profiler::BlockType::Value: + case profiler::BlockType::Value: { lay->addWidget(new BoldLabel("Arbitrary Value", widget), row, 0, 1, 2, Qt::AlignHCenter); ++row; @@ -1931,7 +1931,7 @@ void BlocksGraphicsView::onIdleTimeout() if (itemBlock.per_thread_stats != nullptr) { - if (itemDesc.type() == ::profiler::BlockType::Block) + if (itemDesc.type() == profiler::BlockType::Block) { const auto duration = itemBlock.node->duration(); @@ -1941,29 +1941,30 @@ void BlocksGraphicsView::onIdleTimeout() // Calculate idle/active time { - auto threadRoot = item->root(); + const auto& threadRoot = item->root(); - ::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) + 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) { 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(it - threadRoot.sync.begin()); if (ind > 0) --ind; } else { - ind = static_cast<::profiler::block_index_t>(threadRoot->sync.size()); + ind = static_cast(threadRoot.sync.size()); } - ::profiler::timestamp_t idleTime = 0; - for (auto ncs = static_cast<::profiler::block_index_t>(threadRoot->sync.size()); ind < ncs; ++ind) + profiler::timestamp_t idleTime = 0; + for (auto ncs = static_cast(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; if (cs->begin() > itemBlock.node->end()) @@ -1989,12 +1990,12 @@ void BlocksGraphicsView::onIdleTimeout() 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(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); @@ -2067,10 +2068,10 @@ void BlocksGraphicsView::onIdleTimeout() auto br = m_popupWidget->rect(); 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()) - 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) 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) { @@ -2414,7 +2415,7 @@ ThreadNamesWidget::ThreadNamesWidget(BlocksGraphicsView* _view, int _additionalH setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 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(m_view, &BlocksGraphicsView::treeChanged, this, &This::onTreeChange); @@ -2477,7 +2478,7 @@ void ThreadNamesWidget::onTreeChange() qreal maxLength = 100; const auto& graphicsItems = m_view->getItems(); 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 viewBar = m_view->verticalScrollBar(); @@ -2582,8 +2583,8 @@ void ThreadNamesWidget::onIdleTimeout() lay->addWidget(new BoldLabel(intersectingItem->threadName(), widget), row, 0, 1, 2, Qt::AlignHCenter); ++row; - ::profiler::timestamp_t duration = 0; - const auto& root = *intersectingItem->root(); + profiler::timestamp_t duration = 0; + const auto& root = intersectingItem->root(); if (!root.children.empty()) 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()) - 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()) - 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()); } diff --git a/profiler_gui/blocks_tree_widget.cpp b/profiler_gui/blocks_tree_widget.cpp index 50f67b3..97347b4 100644 --- a/profiler_gui/blocks_tree_widget.cpp +++ b/profiler_gui/blocks_tree_widget.cpp @@ -64,23 +64,25 @@ #include #include #include -#include +#include +#include #include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -#include -#include -#include +#include +#include +#include #include -#include #include -#include -#include -#include #include "blocks_tree_widget.h" #include "arbitrary_value_tooltip.h" +#include "round_progress_widget.h" #include "globals.h" #include "thread_pool.h" @@ -139,6 +141,7 @@ BlocksTreeWidget::BlocksTreeWidget(QWidget* _parent) , m_mode(TreeMode::Plain) , m_bLocked(false) , m_bSilentExpandCollapse(false) + , m_bInitialized(false) { installEventFilter(this); 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->setStyleSheet("QLabel { color: gray; font: 12pt; }"); QTimer::singleShot(1500, this, &This::alignProgressBar); @@ -273,9 +277,14 @@ BlocksTreeWidget::~BlocksTreeWidget() 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()) m_idleTimer.stop(); @@ -298,7 +307,23 @@ bool BlocksTreeWidget::eventFilter(QObject* _object, QEvent* _event) } 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; @@ -801,13 +826,18 @@ void BlocksTreeWidget::moveEvent(QMoveEvent* _event) void BlocksTreeWidget::alignProgressBar() { - auto center = rect().center(); - auto pos = mapToGlobal(center); + const auto scrollbarHeight = verticalScrollBar()->isVisible() ? verticalScrollBar()->height() : 0; + const auto center = rect().adjusted(0, header()->height(), 0, -scrollbarHeight - 6).center(); 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() @@ -824,9 +854,9 @@ void BlocksTreeWidget::createProgressDialog() { 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->setCancelButton(nullptr); m_progress->setValue(0); m_progress->show(); @@ -981,8 +1011,7 @@ void BlocksTreeWidget::onItemCollapse(QTreeWidgetItem* _item) void BlocksTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetItem* _previous) { - if (_previous != nullptr) - static_cast(_previous)->setBold(false); + (void)_previous; if (_item == nullptr) { @@ -992,7 +1021,6 @@ void BlocksTreeWidget::onCurrentItemChange(QTreeWidgetItem* _item, QTreeWidgetIt else { auto item = static_cast(_item); - item->setBold(true); EASY_GLOBALS.selected_block = item->block_index(); if (EASY_GLOBALS.selected_block < EASY_GLOBALS.gui_blocks.size()) @@ -1044,10 +1072,6 @@ void BlocksTreeWidget::onSelectedBlockChange(uint32_t _block_index) #endif } - auto previous = static_cast(currentItem()); - if (previous != nullptr) - previous->setBold(false); - if (item != nullptr) { //const QSignalBlocker b(this); @@ -1074,8 +1098,6 @@ void BlocksTreeWidget::onSelectedBlockChange(uint32_t _block_index) resizeColumnsToContents(); connect(this, &Parent::itemExpanded, this, &This::onItemExpand); } - - item->setBold(true); } else { diff --git a/profiler_gui/blocks_tree_widget.h b/profiler_gui/blocks_tree_widget.h index b6fe645..a0b265e 100644 --- a/profiler_gui/blocks_tree_widget.h +++ b/profiler_gui/blocks_tree_widget.h @@ -91,12 +91,13 @@ protected: QString m_lastSearch; QTreeWidgetItem* m_lastFound; ::profiler::timestamp_t m_beginTime; - class QProgressDialog* m_progress; + class RoundProgressDialog* m_progress; class QLabel* m_hintLabel; class ArbitraryValueToolTip* m_valueTooltip; TreeMode m_mode; bool m_bLocked; bool m_bSilentExpandCollapse; + bool m_bInitialized; char m_columnsHiddenStatus[COL_COLUMNS_NUMBER]; public: diff --git a/profiler_gui/common_types.h b/profiler_gui/common_types.h index b43dcd5..3478d0e 100644 --- a/profiler_gui/common_types.h +++ b/profiler_gui/common_types.h @@ -110,7 +110,7 @@ struct EasyBlock Q_DECL_FINAL EasyBlock() = default; - EasyBlock(EasyBlock&& that) + EasyBlock(EasyBlock&& that) EASY_NOEXCEPT : tree(::std::move(that.tree)) #ifdef EASY_TREE_WIDGET__USE_VECTOR , tree_item(that.tree_item) @@ -126,21 +126,19 @@ struct EasyBlock Q_DECL_FINAL }; #pragma pack(pop) -typedef ::std::vector EasyItems; -typedef ::std::vector EasyBlocks; +using EasyItems = ::std::vector; +using EasyBlocks = ::std::vector; ////////////////////////////////////////////////////////////////////////// struct EasySelectedBlock Q_DECL_FINAL { - const ::profiler::BlocksTreeRoot* root; - ::profiler::block_index_t tree; + const ::profiler::BlocksTreeRoot* root = nullptr; + ::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) , tree(_tree) { diff --git a/profiler_gui/graphics_block_item.cpp b/profiler_gui/graphics_block_item.cpp index 82d3e70..80fc3ad 100644 --- a/profiler_gui/graphics_block_item.cpp +++ b/profiler_gui/graphics_block_item.cpp @@ -105,8 +105,8 @@ const QPen HIGHLIGHTER_PEN = ([]() -> QPen { QPen p(profiler::colors::Black); p. GraphicsBlockItem::GraphicsBlockItem(uint8_t _index, const profiler::BlocksTreeRoot& _root) : QGraphicsItem(nullptr) + , m_thread(_root) , m_threadName(::profiler_gui::decoratedThreadName(EASY_GLOBALS.use_decorated_thread_name, _root, EASY_GLOBALS.hex_thread_id)) - , m_pRoot(&_root) , m_index(_index) { } @@ -117,7 +117,7 @@ GraphicsBlockItem::~GraphicsBlockItem() 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 @@ -453,7 +453,7 @@ void GraphicsBlockItem::paintChildren(const float _minWidth, const int _narrowSi void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem*, QWidget*) { 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) { @@ -963,21 +963,21 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem if (gotSync) { 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; }); - 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; } - 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; qreal prevRight = -1e100; @@ -986,7 +986,7 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem { _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); 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(); - 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; }); - 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; } - 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; @@ -1064,7 +1064,7 @@ void GraphicsBlockItem::paint(QPainter* _painter, const QStyleOptionGraphicsItem { _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); 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 @@ -1173,7 +1173,7 @@ void GraphicsBlockItem::getBlocks(qreal _left, qreal _right, ::profiler_gui::Tre 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 - 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 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; }); - 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; } - 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 currentScale = sceneView->scale(); 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; 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 { - if (m_pRoot->sync.empty()) + if (m_thread.sync.empty()) { return nullptr; } @@ -1372,18 +1372,18 @@ const ::profiler_gui::EasyBlock* GraphicsBlockItem::intersectEvent(const QPointF } 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; }); - if (firstSync == m_pRoot->sync.end()) - firstSync = m_pRoot->sync.begin() + m_pRoot->sync.size() - 1; - else if (firstSync != m_pRoot->sync.begin()) + if (firstSync == m_thread.sync.end()) + firstSync = m_thread.sync.begin() + m_thread.sync.size() - 1; + else if (firstSync != m_thread.sync.begin()) --firstSync; 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); @@ -1417,7 +1417,7 @@ void GraphicsBlockItem::setBoundingRect(const QRectF& _rect) ::profiler::thread_id_t GraphicsBlockItem::threadId() const { - return m_pRoot->thread_id; + return m_thread.thread_id; } ////////////////////////////////////////////////////////////////////////// diff --git a/profiler_gui/graphics_block_item.h b/profiler_gui/graphics_block_item.h index 4f8d116..1dcd9c1 100644 --- a/profiler_gui/graphics_block_item.h +++ b/profiler_gui/graphics_block_item.h @@ -74,19 +74,20 @@ class GraphicsBlockItem : public QGraphicsItem using RightBounds = std::vector; using Sublevels = std::vector; + 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 - RightBounds m_rightBounds; ///< + RightBounds m_rightBounds; ///< Sublevels m_levels; ///< Arrays of items for each level QRectF m_boundingRect; ///< boundingRect (see QGraphicsItem) - QString m_threadName; ///< - const ::profiler::BlocksTreeRoot* m_pRoot; ///< Pointer to the root profiler block (thread block). Used by ProfTreeWidget to restore hierarchy. + QString m_threadName; ///< uint8_t m_index; ///< This item's index in the list of items of BlocksGraphicsView public: - explicit GraphicsBlockItem(uint8_t _index, const::profiler::BlocksTreeRoot& _root); - virtual ~GraphicsBlockItem(); + explicit GraphicsBlockItem(uint8_t _index, const profiler::BlocksTreeRoot& _root); + ~GraphicsBlockItem() override; // Public virtual methods @@ -100,7 +101,7 @@ public: void validateName(); - const ::profiler::BlocksTreeRoot* root() const; + const profiler::BlocksTreeRoot& root() const; const QString& threadName() const; QRect getRect() const; diff --git a/profiler_gui/round_progress_widget.cpp b/profiler_gui/round_progress_widget.cpp new file mode 100644 index 0000000..e157756 --- /dev/null +++ b/profiler_gui/round_progress_widget.cpp @@ -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 +#include +#include +#include +#include +#include +#include + +#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(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(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(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(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(); +} diff --git a/profiler_gui/round_progress_widget.h b/profiler_gui/round_progress_widget.h new file mode 100644 index 0000000..e7fdbd0 --- /dev/null +++ b/profiler_gui/round_progress_widget.h @@ -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 +#include +#include +#include + +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 diff --git a/profiler_gui/tree_widget_item.cpp b/profiler_gui/tree_widget_item.cpp index 3174ba9..1ba1620 100644 --- a/profiler_gui/tree_widget_item.cpp +++ b/profiler_gui/tree_widget_item.cpp @@ -183,16 +183,6 @@ QVariant TreeWidgetItem::data(int _column, int _role) const { 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(QFontMetrics(m_font).width(text(COL_NAME)) * k) + 20, 26); - } - if (_role == BlockColorRole) { if (parent() != nullptr || m_bMain) @@ -203,9 +193,6 @@ QVariant TreeWidgetItem::data(int _column, int _role) const switch (_role) { - case Qt::FontRole: - return m_font; - case Qt::ForegroundRole: return m_bMain ? QVariant::fromValue(QColor::fromRgb(profiler_gui::SELECTED_THREAD_FOREGROUND)) : QVariant(); @@ -331,11 +318,6 @@ void TreeWidgetItem::expandAll() guiBlock().expanded = true; } -void TreeWidgetItem::setBold(bool _bold) -{ - m_font.setBold(_bold); -} - ////////////////////////////////////////////////////////////////////////// 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 { - auto brushData = m_treeWidget->model()->data(index, BlockColorRole); + const auto brushData = m_treeWidget->model()->data(index, BlockColorRole); if (brushData.isNull()) { // Draw item as usual @@ -364,7 +346,7 @@ void TreeWidgetItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem { // Draw selection background for selected row painter->save(); - painter->setBrush(QColor::fromRgba(0xCC98DE98)); + painter->setBrush(m_treeWidget->palette().highlight()); painter->setPen(Qt::NoPen); painter->drawRect(QRect(option.rect.left(), option.rect.top(), colorBlockSize, option.rect.height())); painter->restore(); @@ -382,15 +364,16 @@ void TreeWidgetItemDelegate::paint(QPainter* painter, const QStyleOptionViewItem painter->save(); // Draw color marker with block color - const auto brush = m_treeWidget->model()->data(index, Qt::UserRole + 1).value(); + const auto brush = brushData.value(); 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), colorBlockSize, option.rect.height() - colorBlockRest)); // Draw line under tree indicator const auto bottomLeft = opt.rect.bottomLeft(); painter->setBrush(Qt::NoBrush); + painter->setPen(profiler_gui::SYSTEM_BORDER_COLOR); painter->drawLine(QPoint(bottomLeft.x() - colorBlockSize, bottomLeft.y()), bottomLeft); painter->restore(); diff --git a/profiler_gui/tree_widget_item.h b/profiler_gui/tree_widget_item.h index cd5cc27..9432e08 100644 --- a/profiler_gui/tree_widget_item.h +++ b/profiler_gui/tree_widget_item.h @@ -118,7 +118,6 @@ class TreeWidgetItem : public QTreeWidgetItem using Parent = QTreeWidgetItem; using This = TreeWidgetItem; - QFont m_font; const profiler::block_index_t m_block; QRgb m_customBGColor; std::bitset<17> m_bHasToolTip; @@ -126,7 +125,9 @@ class TreeWidgetItem : public QTreeWidgetItem public: - explicit TreeWidgetItem(const profiler::block_index_t _treeBlock = profiler_gui::numeric_max(), Parent* _parent = nullptr); + explicit TreeWidgetItem(const profiler::block_index_t _treeBlock = profiler_gui::numeric_max() + , Parent* _parent = nullptr); + ~TreeWidgetItem() override; bool operator < (const Parent& _other) const override; @@ -156,8 +157,6 @@ public: void expandAll(); - void setBold(bool _bold); - private: void setHasToolTip(int _column); diff --git a/profiler_gui/tree_widget_loader.cpp b/profiler_gui/tree_widget_loader.cpp index decbff9..c710891 100644 --- a/profiler_gui/tree_widget_loader.cpp +++ b/profiler_gui/tree_widget_loader.cpp @@ -301,7 +301,7 @@ void TreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTim const auto endTime = gui_block.tree.node->end(); if (startTime > _right || endTime < _left) { - setProgress((90 * ++i) / total); + setProgress((95 * ++i) / total); continue; } @@ -502,7 +502,7 @@ void TreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTim delete item; } - setProgress((90 * ++i) / total); + setProgress((95 * ++i) / total); } i = 0; @@ -526,7 +526,7 @@ void TreeWidgetLoader::setTreeInternal2(const ::profiler::timestamp_t& _beginTim delete item; } - setProgress(90 + (10 * ++i) / total); + setProgress(95 + (5 * ++i) / total); } setDone(); diff --git a/profiler_gui/tree_widget_loader.h b/profiler_gui/tree_widget_loader.h index 46dea77..2b3a139 100644 --- a/profiler_gui/tree_widget_loader.h +++ b/profiler_gui/tree_widget_loader.h @@ -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 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 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);