From e3bf55b4c1ebaba81effeadbd06de0f32dffb042 Mon Sep 17 00:00:00 2001 From: Ernie Pasveer Date: Wed, 22 Dec 2021 19:52:21 -0600 Subject: [PATCH] Add a 'spinning' indicator to the toolbar when the program runs. --- src/CMakeLists.txt | 2 + src/QProgressIndicator.cpp | 208 +++++++++++++++++++++++++++++++++ src/QProgressIndicator.h | 59 ++++++++++ src/SeerMainWindow.cpp | 34 +++++- src/SeerMainWindow.h | 4 + src/SeerRunStatusIndicator.cpp | 2 + src/SeerRunStatusIndicator.h | 15 ++- 7 files changed, 317 insertions(+), 7 deletions(-) create mode 100644 src/QProgressIndicator.cpp create mode 100644 src/QProgressIndicator.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c581693..0f243f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -68,6 +68,7 @@ set(HEADER_FILES SeerSlashProcWidget.h SeerSlashProcDialog.h QProcessInfo.h + QProgressIndicator.h ) set(SOURCE_FILES @@ -122,6 +123,7 @@ set(SOURCE_FILES SeerSlashProcWidget.cpp SeerSlashProcDialog.cpp QProcessInfo.cpp + QProgressIndicator.cpp ) qt5_add_resources(SOURCE_FILES resource.qrc) diff --git a/src/QProgressIndicator.cpp b/src/QProgressIndicator.cpp new file mode 100644 index 0000000..af1f9d7 --- /dev/null +++ b/src/QProgressIndicator.cpp @@ -0,0 +1,208 @@ +#include "QProgressIndicator.h" + +#include +#include +#include + +#define SPIN_INTERVAL 60 + +QProgressIndicator::QProgressIndicator(QWidget* parent) : QWidget(parent) { + + _type = QProgressIndicator::line_rotate; + _interval = SPIN_INTERVAL; + _angle = 0; + _scale = 0.0f; + _color = Qt::black; + + setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + setFocusPolicy(Qt::NoFocus); + + _timer = new QTimer(); + + connect(_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); +} + +QProgressIndicator::~QProgressIndicator() { + + stop(); + + delete _timer; +} + +void QProgressIndicator::paintEvent(QPaintEvent* e) { + + Q_UNUSED(e) + + if (!_timer->isActive()) { + return; + } + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + switch (_type) { + case QProgressIndicator::line_rotate: + drawRotateLine(&painter); + break; + case QProgressIndicator::line_scale: + drawScaleLine((&painter)); + break; + case QProgressIndicator::ball_rotate: + drawRotateBall(&painter); + break; + } +} + +void QProgressIndicator::start() { + + _timer->start(_interval); +} + +void QProgressIndicator::stop() { + + _timer->stop(); + + update(); // Force an update to erate the indicator from the view. +} + +int QProgressIndicator::type () { + + return _type; +} + +void QProgressIndicator::setType (int type) { + + _type = type; +} + +const QColor& QProgressIndicator::color () { + + return _color; +} + +void QProgressIndicator::setColor (QColor &color) { + + _color = color; +} + +int QProgressIndicator::interval () { + + return _interval; +} + +void QProgressIndicator::setInterval (int interval) { + + _interval = interval; +} + +void QProgressIndicator::onTimeout() { + + switch (_type) { + case line_rotate: + case ball_rotate: + _angle = (_angle + 45) % 360; + break; + case line_scale: + _scale += 0.1f; + _scale = _scale > .5f ? 0.0f : _scale; + break; + } + + update(); +} + +void QProgressIndicator::drawRotateLine(QPainter* painter) { + + int width = qMin(this->width(), this->height()); + + int outerRadius = (width - 4) * 0.5f; + int innerRadius = outerRadius * 0.42f; + + int capsuleHeight = outerRadius - innerRadius; + int capsuleWidth = (width > 32 ) ? capsuleHeight * .32f : capsuleHeight * .40f; + int capsuleRadius = capsuleWidth / 2; + + for (int i = 0; i < 8; i++) { + + QColor color = _color; + + color.setAlphaF(1.0f - (i / 8.0f)); + painter->setPen(Qt::NoPen); + painter->setBrush(color); + + painter->save(); + + painter->translate(rect().center()); + painter->rotate(_angle - i * 45.0f); + + painter->drawRoundedRect(-capsuleWidth * 0.5, -(innerRadius + capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius); + + painter->restore(); + } +} + +void QProgressIndicator::drawScaleLine(QPainter* painter) { + + int height = qMin(this->width(), this->height()); + + qreal lineWidth = height * 0.15f; + qreal lineHeight = height * 0.9f; + qreal lineRadius = lineWidth / 2.0f; + qreal lineGap = lineWidth; + qreal margin = (this->width() - lineWidth * 5 - lineGap * 4) / 2.0f; + + for (int i = 0; i < 5; i++) { + + painter->setPen(Qt::NoPen); + painter->setBrush(_color); + + int tmp = _scale * 10 + i + 1; + if (tmp > 5) { + tmp = 5 - tmp % 5; + } + + qreal scale = 0.5f + tmp * 0.1f; + qreal h = lineHeight * scale; + + painter->save(); + + painter->translate(QPointF(margin + (lineWidth + lineGap) * i, this->height() / 2)); + + painter->drawRoundedRect(0, -h / 2.0f, lineWidth, h, lineRadius, lineRadius); + + painter->restore(); + } +} + +void QProgressIndicator::drawRotateBall(QPainter* painter) { + + int width = qMin(this->width(), this->height()); + + int outerRadius = (width - 4) * 0.5f; + int innerRadius = outerRadius * 0.78f; + + int capsuleRadius = (outerRadius - innerRadius) / 2; + + for (int i = 0; i < 8; i++) { + + QColor color = _color; + + color.setAlphaF(1.0f - (i / 8.0f)); + + painter->setPen(Qt::NoPen); + painter->setBrush(color); + + qreal radius = capsuleRadius * (1.0f - (i / 16.0f)); + + painter->save(); + + painter->translate(rect().center()); + painter->rotate(_angle - i * 45.0f); + + QPointF centre = QPointF(-capsuleRadius, -(innerRadius + capsuleRadius)); + painter->drawEllipse(centre, radius * 2, radius * 2); + + painter->restore(); + } +} + diff --git a/src/QProgressIndicator.h b/src/QProgressIndicator.h new file mode 100644 index 0000000..70ae722 --- /dev/null +++ b/src/QProgressIndicator.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include +#include + +class QProgressIndicator : public QWidget { + + Q_OBJECT + + Q_PROPERTY(int _type READ type WRITE setType) + Q_PROPERTY(QColor _color READ color WRITE setColor) + Q_PROPERTY(int _interval READ interval WRITE setInterval) + + public: + QProgressIndicator(QWidget* parent = 0); + ~QProgressIndicator(); + + enum { + line_rotate, + line_scale, + ball_rotate, + }; + + void paintEvent (QPaintEvent* e); + + void start (); + void stop (); + + int type (); + void setType (int type); + + const QColor& color (); + void setColor (QColor &color); + + int interval (); + void setInterval (int interval); + + private slots: + void onTimeout (); + + private: + void drawRotateLine (QPainter* painter); + void drawScaleLine (QPainter* painter); + void drawRotateBall (QPainter* painter); + + private: + int _type; + int _interval; + QColor _color; + + int _angle; + qreal _scale; + + QTimer* _timer; +}; + diff --git a/src/SeerMainWindow.cpp b/src/SeerMainWindow.cpp index 2c7c2eb..692b02b 100644 --- a/src/SeerMainWindow.cpp +++ b/src/SeerMainWindow.cpp @@ -1,5 +1,4 @@ #include "SeerMainWindow.h" -#include "SeerRunStatusIndicator.h" #include "SeerDebugDialog.h" #include "SeerConfigDialog.h" #include "SeerArgumentsDialog.h" @@ -25,10 +24,24 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { // // Set up other parts of the UI. // + + // Add status bar indicator. SeerRunStatusIndicator* runStatus = new SeerRunStatusIndicator(this); statusBar()->addPermanentWidget(runStatus); + // Add progress spin widget. + QWidget* spacerWidget = new QWidget(this); + spacerWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + toolBar->addWidget(spacerWidget); + + _progressIndicator = new QProgressIndicator(this); + _progressIndicator->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + _progressIndicator->setFixedWidth(96); + _progressIndicator->setType(QProgressIndicator::ball_rotate); + + toolBar->addWidget(_progressIndicator); + // // Set up shortcut keys. // @@ -99,6 +112,8 @@ SeerMainWindow::SeerMainWindow(QWidget* parent) : QMainWindow(parent) { QObject::connect(centralwidget->gdbMonitor(), &GdbMonitor::astrixTextOutput, this, &SeerMainWindow::handleText); QObject::connect(centralwidget->gdbMonitor(), &GdbMonitor::caretTextOutput, this, &SeerMainWindow::handleText); + QObject::connect(runStatus, &SeerRunStatusIndicator::statusChanged, this, &SeerMainWindow::handleRunStatusChanged); + // Restore window settings. readSettings(); @@ -512,6 +527,23 @@ void SeerMainWindow::handleText (const QString& text) { qDebug() << __PRETTY_FUNCTION__ << ":" << text; } +void SeerMainWindow::handleRunStatusChanged (SeerRunStatusIndicator::RunStatus status) { + + if (status == SeerRunStatusIndicator::RunStatus::Idle) { + _progressIndicator->stop(); + + }else if (status == SeerRunStatusIndicator::RunStatus::Stopped) { + _progressIndicator->stop(); + + }else if (status == SeerRunStatusIndicator::RunStatus::Running) { + _progressIndicator->start(); + + }else{ + _progressIndicator->stop(); + } + +} + void SeerMainWindow::closeEvent (QCloseEvent* event) { event->accept(); diff --git a/src/SeerMainWindow.h b/src/SeerMainWindow.h index c3fee07..e6a6267 100644 --- a/src/SeerMainWindow.h +++ b/src/SeerMainWindow.h @@ -1,6 +1,8 @@ #pragma once #include "ui_SeerMainWindow.h" +#include "SeerRunStatusIndicator.h" +#include "QProgressIndicator.h" #include #include #include @@ -42,6 +44,7 @@ class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { void handleSettingsSaveConfiguration (); void handleHelpAbout (); void handleText (const QString& text); + void handleRunStatusChanged (SeerRunStatusIndicator::RunStatus status); protected: void writeSettings (); @@ -52,5 +55,6 @@ class SeerMainWindow : public QMainWindow, protected Ui::SeerMainWindowForm { void closeEvent (QCloseEvent* event); private: + QProgressIndicator* _progressIndicator; }; diff --git a/src/SeerRunStatusIndicator.cpp b/src/SeerRunStatusIndicator.cpp index e1757f4..ba18275 100644 --- a/src/SeerRunStatusIndicator.cpp +++ b/src/SeerRunStatusIndicator.cpp @@ -35,6 +35,8 @@ void SeerRunStatusIndicator::setRunStatus (SeerRunStatusIndicator::RunStatus sta QApplication::restoreOverrideCursor(); setText("Unknown"); } + + emit statusChanged(status); } SeerRunStatusIndicator::RunStatus SeerRunStatusIndicator::runStatus () const { diff --git a/src/SeerRunStatusIndicator.h b/src/SeerRunStatusIndicator.h index 163d305..05e1587 100644 --- a/src/SeerRunStatusIndicator.h +++ b/src/SeerRunStatusIndicator.h @@ -5,21 +5,24 @@ class SeerRunStatusIndicator : public QLabel { - enum RunStatus { - Idle = 0, - Stopped = 1, - Running = 2 - }; - Q_OBJECT public: + enum RunStatus { + Idle = 0, + Stopped = 1, + Running = 2 + }; + explicit SeerRunStatusIndicator(QWidget* parent = 0); ~SeerRunStatusIndicator (); void setRunStatus (SeerRunStatusIndicator::RunStatus status); SeerRunStatusIndicator::RunStatus runStatus () const; + signals: + void statusChanged (SeerRunStatusIndicator::RunStatus status); + public slots: void handleText (const QString& text);