diff --git a/src/Insight/CMakeLists.txt b/src/Insight/CMakeLists.txt index 33131fb6..bc38d4ae 100755 --- a/src/Insight/CMakeLists.txt +++ b/src/Insight/CMakeLists.txt @@ -39,6 +39,9 @@ target_sources( ${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/CaptureMemorySnapshot.cpp ${CMAKE_CURRENT_SOURCE_DIR}/InsightWorker/Tasks/RetrieveMemorySnapshots.cpp + # Task indicator + ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.cpp + # Error dialogue window ${CMAKE_CURRENT_SOURCE_DIR}/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp diff --git a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp index 8dac53b6..7d4c4a2a 100644 --- a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp @@ -160,6 +160,10 @@ namespace Bloom this->targetIdLabel = this->footer->findChild("target-id"); this->variantMenu = this->footer->findChild("target-variant-menu"); + this->taskIndicator = new TaskIndicator(this); + auto* footerLayout = this->footer->findChild(); + footerLayout->insertWidget(2, this->taskIndicator); + const auto windowSize = this->size(); this->windowContainer->setFixedSize(windowSize); this->layoutContainer->setFixedSize(windowSize); diff --git a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp index 4cfbe1c5..4eb48961 100644 --- a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp @@ -13,15 +13,15 @@ #include "src/Targets/TargetDescriptor.hpp" #include "src/Targets/TargetVariant.hpp" -#include "Widgets/PanelWidget.hpp" - #include "Widgets/Label.hpp" #include "Widgets/SvgToolButton.hpp" #include "Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp" #include "Widgets/TargetWidgets/TargetPackageWidget.hpp" +#include "Widgets/PanelWidget.hpp" #include "Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp" #include "Widgets/TargetMemoryInspectionPane/TargetMemoryInspectionPane.hpp" #include "Widgets/TargetMemoryInspectionPane/TargetMemoryInspectionPaneSettings.hpp" +#include "Widgets/TaskIndicator/TaskIndicator.hpp" #include "AboutWindow.hpp" namespace Bloom @@ -103,6 +103,7 @@ namespace Bloom QWidget* footer = nullptr; Widgets::Label* targetStatusLabel = nullptr; Widgets::Label* programCounterValueLabel = nullptr; + Widgets::TaskIndicator* taskIndicator = nullptr; std::map supportedVariantsByName; const Targets::TargetVariant* selectedVariant = nullptr; diff --git a/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui b/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui index 0489892d..30010a4c 100644 --- a/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui +++ b/src/Insight/UserInterfaces/InsightWindow/UiFiles/InsightWindow.ui @@ -387,12 +387,18 @@ + + 130 + - Program Counter Value (byte address) + + Qt::AlignCenter + diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.cpp new file mode 100644 index 00000000..cd97a4b6 --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.cpp @@ -0,0 +1,113 @@ +#include "TaskIndicator.hpp" + +#include +#include + +#include "src/Insight/InsightSignals.hpp" + +namespace Bloom::Widgets +{ + TaskIndicator::TaskIndicator(QWidget* parent) + : QWidget(parent) + { + this->setObjectName("task-indicator"); + this->setFixedSize(50, 26); + + auto* insightSignals = InsightSignals::instance(); + + QObject::connect( + insightSignals, + &InsightSignals::taskQueued, + this, + &TaskIndicator::onTaskQueued + ); + + QObject::connect( + insightSignals, + &InsightSignals::taskProcessed, + this, + &TaskIndicator::onTaskFinished + ); + + this->updateToolTip(); + } + + void TaskIndicator::enterEvent(QEnterEvent* event) { + this->hovered = true; + this->update(); + } + + void TaskIndicator::leaveEvent(QEvent* event) { + this->hovered = false; + this->update(); + } + + void TaskIndicator::paintEvent(QPaintEvent* event) { + auto painter = QPainter(this); + painter.setPen(Qt::PenStyle::NoPen); + + const auto size = this->size(); + + static constexpr auto activeItemColor = QColor(0x7C, 0x5D, 0x3B); + static constexpr auto inactiveItemColor = QColor(0x83, 0x83, 0x82); + static constexpr auto itemSize = QSize(3, 3); + + static constexpr auto rowCount = 3; + static constexpr auto itemsPerRow = 6; + + static constexpr auto itemRightMargin = 2; + static constexpr auto itemBottomMargin = 2; + + if (this->hovered) { + static constexpr auto hoveredBackgroundColor = QColor(0x45, 0x45, 0x41); + painter.setBrush(hoveredBackgroundColor); + painter.drawRect(0, 1, size.width(), size.height() - 1); + } + + const auto activeTaskCount = this->activeTasksById.size(); + + // Position the items at the center of the drawing space + auto startX = (size.width() / 2) - (((itemSize.width() + itemRightMargin) * itemsPerRow - itemRightMargin) / 2); + auto startY = (size.height() / 2) - (((itemSize.height() + itemBottomMargin) * rowCount - itemBottomMargin) / 2); + + // The itemIndex goes in reverse + auto itemIndex = rowCount * itemsPerRow; + + for (auto rowIndex = 0; rowIndex < rowCount; ++rowIndex) { + for (auto rowItemIndex = 0; rowItemIndex < itemsPerRow; ++rowItemIndex) { + painter.setBrush(itemIndex <= activeTaskCount ? activeItemColor : inactiveItemColor); + + painter.drawRect( + startX + ((itemSize.width() + itemRightMargin) * rowItemIndex), + startY + ((itemSize.height() + itemBottomMargin) * rowIndex), + itemSize.width(), + itemSize.height() + ); + + --itemIndex; + } + } + } + + void TaskIndicator::onTaskQueued(QSharedPointer task) { + this->activeTasksById[task->id] = task; + this->updateToolTip(); + this->update(); + } + + void TaskIndicator::onTaskFinished(QSharedPointer task) { + this->activeTasksById.erase(task->id); + this->updateToolTip(); + this->update(); + } + + void TaskIndicator::updateToolTip() { + const auto taskCount = this->activeTasksById.size(); + if (taskCount > 0) { + this->setToolTip("Processing " + QString::number(taskCount) + (taskCount == 1 ? " task" : " tasks")); + return; + } + + this->setToolTip("Open Task Window"); + } +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.hpp new file mode 100644 index 00000000..72fd9879 --- /dev/null +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TaskIndicator/TaskIndicator.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include + +#include "src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp" + +namespace Bloom::Widgets +{ + class TaskIndicator: public QWidget + { + Q_OBJECT + + public: + TaskIndicator(QWidget* parent); + + protected: + void enterEvent(QEnterEvent* event) override; + void leaveEvent(QEvent* event) override; + void paintEvent(QPaintEvent* event) override; + + private: + std::unordered_map> activeTasksById; + bool hovered = false; + + void onTaskQueued(QSharedPointer task); + void onTaskFinished(QSharedPointer task); + + void updateToolTip(); + }; +}