From d66094267f367b0f18c4ac7864c6172f22f4fc89 Mon Sep 17 00:00:00 2001 From: Adriaan de Groot Date: Tue, 19 Sep 2017 12:58:35 +0200 Subject: [PATCH] [Merge] adopt watingspinnerwidget.cpp/h --- LICENSES/MIT-QtWaitingSpinner | 21 ++ .../widgets/waitingspinnerwidget.cpp | 277 ++++++++++++++++++ .../widgets/waitingspinnerwidget.h | 114 +++++++ 3 files changed, 412 insertions(+) create mode 100644 LICENSES/MIT-QtWaitingSpinner create mode 100644 src/libcalamaresui/widgets/waitingspinnerwidget.cpp create mode 100644 src/libcalamaresui/widgets/waitingspinnerwidget.h diff --git a/LICENSES/MIT-QtWaitingSpinner b/LICENSES/MIT-QtWaitingSpinner new file mode 100644 index 000000000..c85c97aeb --- /dev/null +++ b/LICENSES/MIT-QtWaitingSpinner @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Original Work Copyright (c) 2012-2015 Alexander Turkin +Modified 2014 by William Hallatt + +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. diff --git a/src/libcalamaresui/widgets/waitingspinnerwidget.cpp b/src/libcalamaresui/widgets/waitingspinnerwidget.cpp new file mode 100644 index 000000000..0ef03a0ba --- /dev/null +++ b/src/libcalamaresui/widgets/waitingspinnerwidget.cpp @@ -0,0 +1,277 @@ +/* Original Work Copyright (c) 2012-2014 Alexander Turkin + Modified 2014 by William Hallatt + Modified 2015 by Jacob Dawid + +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. +*/ + +// Own includes +#include "waitingspinnerwidget.h" + +// Standard includes +#include +#include + +// Qt includes +#include +#include + +WaitingSpinnerWidget::WaitingSpinnerWidget(QWidget *parent, + bool centerOnParent, + bool disableParentWhenSpinning) + : QWidget(parent), + _centerOnParent(centerOnParent), + _disableParentWhenSpinning(disableParentWhenSpinning) { + initialize(); +} + +WaitingSpinnerWidget::WaitingSpinnerWidget(Qt::WindowModality modality, + QWidget *parent, + bool centerOnParent, + bool disableParentWhenSpinning) + : QWidget(parent, Qt::Dialog | Qt::FramelessWindowHint), + _centerOnParent(centerOnParent), + _disableParentWhenSpinning(disableParentWhenSpinning){ + initialize(); + + // We need to set the window modality AFTER we've hidden the + // widget for the first time since changing this property while + // the widget is visible has no effect. + setWindowModality(modality); + setAttribute(Qt::WA_TranslucentBackground); +} + +void WaitingSpinnerWidget::initialize() { + _color = Qt::black; + _roundness = 100.0; + _minimumTrailOpacity = 3.14159265358979323846; + _trailFadePercentage = 80.0; + _revolutionsPerSecond = 1.57079632679489661923; + _numberOfLines = 20; + _lineLength = 10; + _lineWidth = 2; + _innerRadius = 10; + _currentCounter = 0; + _isSpinning = false; + + _timer = new QTimer(this); + connect(_timer, SIGNAL(timeout()), this, SLOT(rotate())); + updateSize(); + updateTimer(); + hide(); +} + +void WaitingSpinnerWidget::paintEvent(QPaintEvent *) { + updatePosition(); + QPainter painter(this); + painter.fillRect(this->rect(), Qt::transparent); + painter.setRenderHint(QPainter::Antialiasing, true); + + if (_currentCounter >= _numberOfLines) { + _currentCounter = 0; + } + + painter.setPen(Qt::NoPen); + for (int i = 0; i < _numberOfLines; ++i) { + painter.save(); + painter.translate(_innerRadius + _lineLength, + _innerRadius + _lineLength); + qreal rotateAngle = + static_cast(360 * i) / static_cast(_numberOfLines); + painter.rotate(rotateAngle); + painter.translate(_innerRadius, 0); + int distance = + lineCountDistanceFromPrimary(i, _currentCounter, _numberOfLines); + QColor color = + currentLineColor(distance, _numberOfLines, _trailFadePercentage, + _minimumTrailOpacity, _color); + painter.setBrush(color); + // TODO improve the way rounded rect is painted + painter.drawRoundedRect( + QRect(0, -_lineWidth / 2, _lineLength, _lineWidth), _roundness, + _roundness, Qt::RelativeSize); + painter.restore(); + } +} + +void WaitingSpinnerWidget::start() { + updatePosition(); + _isSpinning = true; + show(); + + if(parentWidget() && _disableParentWhenSpinning) { + parentWidget()->setEnabled(false); + } + + if (!_timer->isActive()) { + _timer->start(); + _currentCounter = 0; + } +} + +void WaitingSpinnerWidget::stop() { + _isSpinning = false; + hide(); + + if(parentWidget() && _disableParentWhenSpinning) { + parentWidget()->setEnabled(true); + } + + if (_timer->isActive()) { + _timer->stop(); + _currentCounter = 0; + } +} + +void WaitingSpinnerWidget::setNumberOfLines(int lines) { + _numberOfLines = lines; + _currentCounter = 0; + updateTimer(); +} + +void WaitingSpinnerWidget::setLineLength(int length) { + _lineLength = length; + updateSize(); +} + +void WaitingSpinnerWidget::setLineWidth(int width) { + _lineWidth = width; + updateSize(); +} + +void WaitingSpinnerWidget::setInnerRadius(int radius) { + _innerRadius = radius; + updateSize(); +} + +QColor WaitingSpinnerWidget::color() { + return _color; +} + +qreal WaitingSpinnerWidget::roundness() { + return _roundness; +} + +qreal WaitingSpinnerWidget::minimumTrailOpacity() { + return _minimumTrailOpacity; +} + +qreal WaitingSpinnerWidget::trailFadePercentage() { + return _trailFadePercentage; +} + +qreal WaitingSpinnerWidget::revolutionsPersSecond() { + return _revolutionsPerSecond; +} + +int WaitingSpinnerWidget::numberOfLines() { + return _numberOfLines; +} + +int WaitingSpinnerWidget::lineLength() { + return _lineLength; +} + +int WaitingSpinnerWidget::lineWidth() { + return _lineWidth; +} + +int WaitingSpinnerWidget::innerRadius() { + return _innerRadius; +} + +bool WaitingSpinnerWidget::isSpinning() const { + return _isSpinning; +} + +void WaitingSpinnerWidget::setRoundness(qreal roundness) { + _roundness = std::max(0.0, std::min(100.0, roundness)); +} + +void WaitingSpinnerWidget::setColor(QColor color) { + _color = color; +} + +void WaitingSpinnerWidget::setRevolutionsPerSecond(qreal revolutionsPerSecond) { + _revolutionsPerSecond = revolutionsPerSecond; + updateTimer(); +} + +void WaitingSpinnerWidget::setTrailFadePercentage(qreal trail) { + _trailFadePercentage = trail; +} + +void WaitingSpinnerWidget::setMinimumTrailOpacity(qreal minimumTrailOpacity) { + _minimumTrailOpacity = minimumTrailOpacity; +} + +void WaitingSpinnerWidget::rotate() { + ++_currentCounter; + if (_currentCounter >= _numberOfLines) { + _currentCounter = 0; + } + update(); +} + +void WaitingSpinnerWidget::updateSize() { + int size = (_innerRadius + _lineLength) * 2; + setFixedSize(size, size); +} + +void WaitingSpinnerWidget::updateTimer() { + _timer->setInterval(1000 / (_numberOfLines * _revolutionsPerSecond)); +} + +void WaitingSpinnerWidget::updatePosition() { + if (parentWidget() && _centerOnParent) { + move(parentWidget()->width() / 2 - width() / 2, + parentWidget()->height() / 2 - height() / 2); + } +} + +int WaitingSpinnerWidget::lineCountDistanceFromPrimary(int current, int primary, + int totalNrOfLines) { + int distance = primary - current; + if (distance < 0) { + distance += totalNrOfLines; + } + return distance; +} + +QColor WaitingSpinnerWidget::currentLineColor(int countDistance, int totalNrOfLines, + qreal trailFadePerc, qreal minOpacity, + QColor color) { + if (countDistance == 0) { + return color; + } + const qreal minAlphaF = minOpacity / 100.0; + int distanceThreshold = + static_cast(ceil((totalNrOfLines - 1) * trailFadePerc / 100.0)); + if (countDistance > distanceThreshold) { + color.setAlphaF(minAlphaF); + } else { + qreal alphaDiff = color.alphaF() - minAlphaF; + qreal gradient = alphaDiff / static_cast(distanceThreshold + 1); + qreal resultAlpha = color.alphaF() - gradient * countDistance; + + // If alpha is out of bounds, clip it. + resultAlpha = std::min(1.0, std::max(0.0, resultAlpha)); + color.setAlphaF(resultAlpha); + } + return color; +} diff --git a/src/libcalamaresui/widgets/waitingspinnerwidget.h b/src/libcalamaresui/widgets/waitingspinnerwidget.h new file mode 100644 index 000000000..8129718a5 --- /dev/null +++ b/src/libcalamaresui/widgets/waitingspinnerwidget.h @@ -0,0 +1,114 @@ +/* Original Work Copyright (c) 2012-2014 Alexander Turkin + Modified 2014 by William Hallatt + Modified 2015 by Jacob Dawid +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. +*/ + +#pragma once + +// Qt includes +#include +#include +#include + +class WaitingSpinnerWidget : public QWidget { + Q_OBJECT +public: + /*! Constructor for "standard" widget behaviour - use this + * constructor if you wish to, e.g. embed your widget in another. */ + WaitingSpinnerWidget(QWidget *parent = 0, + bool centerOnParent = true, + bool disableParentWhenSpinning = true); + + /*! Constructor - use this constructor to automatically create a modal + * ("blocking") spinner on top of the calling widget/window. If a valid + * parent widget is provided, "centreOnParent" will ensure that + * QtWaitingSpinner automatically centres itself on it, if not, + * "centreOnParent" is ignored. */ + WaitingSpinnerWidget(Qt::WindowModality modality, + QWidget *parent = 0, + bool centerOnParent = true, + bool disableParentWhenSpinning = true); + +public slots: + void start(); + void stop(); + +public: + void setColor(QColor color); + void setRoundness(qreal roundness); + void setMinimumTrailOpacity(qreal minimumTrailOpacity); + void setTrailFadePercentage(qreal trail); + void setRevolutionsPerSecond(qreal revolutionsPerSecond); + void setNumberOfLines(int lines); + void setLineLength(int length); + void setLineWidth(int width); + void setInnerRadius(int radius); + void setText(QString text); + + QColor color(); + qreal roundness(); + qreal minimumTrailOpacity(); + qreal trailFadePercentage(); + qreal revolutionsPersSecond(); + int numberOfLines(); + int lineLength(); + int lineWidth(); + int innerRadius(); + + bool isSpinning() const; + +private slots: + void rotate(); + +protected: + void paintEvent(QPaintEvent *paintEvent); + +private: + static int lineCountDistanceFromPrimary(int current, int primary, + int totalNrOfLines); + static QColor currentLineColor(int distance, int totalNrOfLines, + qreal trailFadePerc, qreal minOpacity, + QColor color); + + void initialize(); + void updateSize(); + void updateTimer(); + void updatePosition(); + +private: + QColor _color; + qreal _roundness; // 0..100 + qreal _minimumTrailOpacity; + qreal _trailFadePercentage; + qreal _revolutionsPerSecond; + int _numberOfLines; + int _lineLength; + int _lineWidth; + int _innerRadius; + +private: + WaitingSpinnerWidget(const WaitingSpinnerWidget&); + WaitingSpinnerWidget& operator=(const WaitingSpinnerWidget&); + + QTimer *_timer; + bool _centerOnParent; + bool _disableParentWhenSpinning; + int _currentCounter; + bool _isSpinning; +};