From 9a3d9feb308d734b4fcbfa4438211433d42331dd Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Fri, 15 Apr 2022 12:13:16 +0200 Subject: [PATCH] [libcalamaresui] Add a countdown widget for limited waiting. --- src/libcalamaresui/widgets/WaitingWidget.cpp | 91 ++++++++++++++++++++ src/libcalamaresui/widgets/WaitingWidget.h | 49 ++++++++++- 2 files changed, 139 insertions(+), 1 deletion(-) diff --git a/src/libcalamaresui/widgets/WaitingWidget.cpp b/src/libcalamaresui/widgets/WaitingWidget.cpp index aef5aecf5..671f140c5 100644 --- a/src/libcalamaresui/widgets/WaitingWidget.cpp +++ b/src/libcalamaresui/widgets/WaitingWidget.cpp @@ -16,6 +16,7 @@ #include #include +#include WaitingWidget::WaitingWidget( const QString& text, QWidget* parent ) : QWidget( parent ) @@ -55,3 +56,93 @@ WaitingWidget::setText( const QString& text ) { m_waitingLabel->setText( text ); } + +struct CountdownWaitingWidget::Private +{ + std::chrono::seconds duration; + // int because we count down, need to be able to show a 0, + // and then wrap around to duration a second later. + int count = 0; + WaitingSpinnerWidget* spinner = nullptr; + QLabel* label = nullptr; + QTimer* timer = nullptr; + + Private( std::chrono::seconds seconds, QWidget* parent ) + : duration( seconds ) + , spinner( new WaitingSpinnerWidget( parent ) ) + , label( new QLabel( parent ) ) + , timer( new QTimer( parent ) ) + { + } +}; + +CountdownWaitingWidget::CountdownWaitingWidget( std::chrono::seconds duration, QWidget* parent ) + : QWidget( parent ) + , d( std::make_unique< Private >( duration, this ) ) +{ + // Set up the label first for sizing + const int labelHeight = d->label->fontMetrics().height() * 3 / 2; + + // Set up the spinner + d->spinner->setFixedSize( labelHeight, labelHeight ); + + // Overall UI layout + QBoxLayout* box = new QHBoxLayout; + box->addWidget( d->spinner ); + box->addWidget( d->label ); + setLayout( box ); + + // Last because it updates the text + setInterval( duration ); + + d->timer->setInterval( std::chrono::seconds( 1 ) ); + connect( d->timer, &QTimer::timeout, this, &CountdownWaitingWidget::tick ); +} + +CountdownWaitingWidget::~CountdownWaitingWidget() +{ + d->timer->stop(); +} + +void +CountdownWaitingWidget::setInterval( std::chrono::seconds duration ) +{ + d->duration = duration; + d->count = int( duration.count() ); + tick(); +} + +void +CountdownWaitingWidget::start() +{ + // start it from the top + if ( d->count <= 0 ) + { + d->count = int( d->duration.count() ); + tick(); + } + d->timer->start(); +} + +void +CountdownWaitingWidget::stop() +{ + d->timer->stop(); +} + +void +CountdownWaitingWidget::tick() +{ + // We do want to **display** a 0 which is why we wrap around only + // after counting down from 0. + d->count--; + if ( d->count < 0 ) + { + d->count = int( d->duration.count() ); + } + d->label->setText( QString::number( d->count ) ); + if ( d->count == 0 ) + { + timeout(); + } +} diff --git a/src/libcalamaresui/widgets/WaitingWidget.h b/src/libcalamaresui/widgets/WaitingWidget.h index 850b81ca9..867529641 100644 --- a/src/libcalamaresui/widgets/WaitingWidget.h +++ b/src/libcalamaresui/widgets/WaitingWidget.h @@ -12,18 +12,65 @@ #include -class QLabel; +#include +#include +class QLabel; +class QTimer; + +/** @brief A spinner and a label below it + * + * The spinner has a fixed size of 4* the font height, + * and the text is displayed centered below it. Use this + * to display a long-term waiting situation with a status report. + */ class WaitingWidget : public QWidget { Q_OBJECT public: + /// Create a WaitingWidget with initial @p text label. explicit WaitingWidget( const QString& text, QWidget* parent = nullptr ); + /// Update the @p text displayed in the label. void setText( const QString& text ); private: QLabel* m_waitingLabel; }; +/** @brief A spinner and a countdown next to it + * + * The spinner is sized to the text-height and displays a + * numeric countdown next to it. The countdown is updated + * every second. The signal timeout() is sent every time + * the countdown reaches 0. + */ +class CountdownWaitingWidget : public QWidget +{ + Q_OBJECT +public: + /// Create a countdown widget with a given @p duration + explicit CountdownWaitingWidget( std::chrono::seconds duration = std::chrono::seconds( 5 ), + QWidget* parent = nullptr ); + ~CountdownWaitingWidget() override; + + /// Changes the duration used and resets the countdown + void setInterval( std::chrono::seconds duration ); + + /// Start the countdown, resets to the full duration + void start(); + /// Stop the countdown + void stop(); + +Q_SIGNALS: + void timeout(); + +protected Q_SLOTS: + void tick(); + +private: + struct Private; + std::unique_ptr< Private > d; +}; + #endif // WAITINGWIDGET_H