From 5d8b0e63527c1876865a2bddb9c3180ff943be9e Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 25 Jul 2017 13:51:36 +0200 Subject: [PATCH] Utils: Separate rendering out of ProgressIndicator I want to reuse the rendering of the progress indicator outside of a widget. Change-Id: Icaeeb798578ad838693b68556bf2193c4ba45cfa Reviewed-by: Eike Ziller Reviewed-by: Tim Jenssen --- src/libs/utils/basetreeview.cpp | 2 +- src/libs/utils/progressindicator.cpp | 140 ++++++++++++------ src/libs/utils/progressindicator.h | 70 ++++++--- src/plugins/android/androiddevicedialog.cpp | 2 +- src/plugins/autotest/testnavigationwidget.cpp | 2 +- .../cmakebuildsettingswidget.cpp | 2 +- .../coreplugin/locator/locatorwidget.cpp | 2 +- .../diffeditor/diffeditorwidgetcontroller.cpp | 2 +- src/plugins/git/gerrit/gerritdialog.cpp | 2 +- src/plugins/updateinfo/settingspage.cpp | 2 +- src/plugins/vcsbase/vcsbaseeditor.cpp | 2 +- 11 files changed, 153 insertions(+), 75 deletions(-) diff --git a/src/libs/utils/basetreeview.cpp b/src/libs/utils/basetreeview.cpp index abe01ada6e1..29c531e1cc5 100644 --- a/src/libs/utils/basetreeview.cpp +++ b/src/libs/utils/basetreeview.cpp @@ -355,7 +355,7 @@ void BaseTreeView::showEvent(QShowEvent *ev) void BaseTreeView::showProgressIndicator() { if (!d->m_progressIndicator) { - d->m_progressIndicator = new ProgressIndicator(ProgressIndicator::Large); + d->m_progressIndicator = new ProgressIndicator(ProgressIndicatorSize::Large); d->m_progressIndicator->attachToWidget(this); } d->m_progressIndicator->show(); diff --git a/src/libs/utils/progressindicator.cpp b/src/libs/utils/progressindicator.cpp index 009d57c009d..4efd9871372 100644 --- a/src/libs/utils/progressindicator.cpp +++ b/src/libs/utils/progressindicator.cpp @@ -33,51 +33,114 @@ #include #include -using namespace Utils; +namespace { -ProgressIndicator::ProgressIndicator(IndicatorSize size, QWidget *parent) - : QWidget(parent), - m_rotation(0) -{ - setAttribute(Qt::WA_TransparentForMouseEvents); - m_timer.setSingleShot(false); - connect(&m_timer, &QTimer::timeout, this, &ProgressIndicator::step); - setIndicatorSize(size); -} - -static QString imageFileNameForIndicatorSize(ProgressIndicator::IndicatorSize size) +static QString imageFileNameForIndicatorSize(Utils::ProgressIndicatorSize size) { switch (size) { - case ProgressIndicator::Large: - return QLatin1String(":/utils/images/progressindicator_big.png"); - case ProgressIndicator::Medium: - return QLatin1String(":/utils/images/progressindicator_medium.png"); - case ProgressIndicator::Small: - default: + case Utils::ProgressIndicatorSize::Large: + return QLatin1String(":/utils/images/progressindicator_big.png"); + case Utils::ProgressIndicatorSize::Medium: + return QLatin1String(":/utils/images/progressindicator_medium.png"); + case Utils::ProgressIndicatorSize::Small: + default: return QLatin1String(":/utils/images/progressindicator_small.png"); } } -void ProgressIndicator::setIndicatorSize(ProgressIndicator::IndicatorSize size) +} // namespace + +namespace Utils { + +ProgressIndicatorPainter::ProgressIndicatorPainter(ProgressIndicatorSize size) { - m_size = size; - m_rotationStep = size == Small ? 45 : 30; - m_timer.setInterval(size == Small ? 100 : 80); - m_pixmap = Icon({{imageFileNameForIndicatorSize(size), - Theme::PanelTextColorMid}}, Icon::Tint).pixmap(); - updateGeometry(); + m_timer.setSingleShot(false); + QObject::connect(&m_timer, &QTimer::timeout, [this]() { + nextAnimationStep(); + if (m_callback) + m_callback(); + }); + + setIndicatorSize(size); } -ProgressIndicator::IndicatorSize ProgressIndicator::indicatorSize() const +void ProgressIndicatorPainter::setIndicatorSize(ProgressIndicatorSize size) +{ + m_size = size; + m_rotationStep = size == ProgressIndicatorSize::Small ? 45 : 30; + m_timer.setInterval(size == ProgressIndicatorSize::Small ? 100 : 80); + m_pixmap = Icon({{imageFileNameForIndicatorSize(size), + Theme::PanelTextColorMid}}, Icon::Tint).pixmap(); +} + +ProgressIndicatorSize ProgressIndicatorPainter::indicatorSize() const { return m_size; } -QSize ProgressIndicator::sizeHint() const +void ProgressIndicatorPainter::setUpdateCallback(const UpdateCallback &cb) +{ + m_callback = cb; +} + +QSize ProgressIndicatorPainter::size() const { return m_pixmap.size() / m_pixmap.devicePixelRatio(); } +// Paint indicator centered on the rect +void ProgressIndicatorPainter::paint(QPainter &painter, const QRect &rect) const +{ + painter.save(); + painter.setRenderHint(QPainter::SmoothPixmapTransform); + QPoint translate(rect.x() + rect.width() / 2, rect.y() + rect.height() / 2); + QTransform t; + t.translate(translate.x(), translate.y()); + t.rotate(m_rotation); + t.translate(-translate.x(), -translate.y()); + painter.setTransform(t); + QSize pixmapUserSize(m_pixmap.size() / m_pixmap.devicePixelRatio()); + painter.drawPixmap(QPoint(rect.x() + ((rect.width() - pixmapUserSize.width()) / 2), + rect.y() + ((rect.height() - pixmapUserSize.height()) / 2)), + m_pixmap); + painter.restore(); +} + +void ProgressIndicatorPainter::startAnimation() +{ + QTC_ASSERT(m_callback, return); + m_timer.start(); +} + +void ProgressIndicatorPainter::stopAnimation() +{ + m_timer.stop(); +} + +void Utils::ProgressIndicatorPainter::nextAnimationStep() +{ + m_rotation = (m_rotation + m_rotationStep + 360) % 360; +} + +ProgressIndicator::ProgressIndicator(ProgressIndicatorSize size, QWidget *parent) + : QWidget(parent), m_paint(size) +{ + setAttribute(Qt::WA_TransparentForMouseEvents); + m_paint.setUpdateCallback([this]() { update(); }); + updateGeometry(); +} + +void ProgressIndicator::setIndicatorSize(ProgressIndicatorSize size) +{ + m_paint.setIndicatorSize(size); + updateGeometry(); +} + +QSize ProgressIndicator::sizeHint() const +{ + return m_paint.size(); +} + void ProgressIndicator::attachToWidget(QWidget *parent) { if (parentWidget()) @@ -91,27 +154,17 @@ void ProgressIndicator::attachToWidget(QWidget *parent) void ProgressIndicator::paintEvent(QPaintEvent *) { QPainter p(this); - p.setRenderHint(QPainter::SmoothPixmapTransform); - QPoint translate(rect().width() / 2, rect().height() / 2); - QTransform t; - t.translate(translate.x(), translate.y()); - t.rotate(m_rotation); - t.translate(-translate.x(), -translate.y()); - p.setTransform(t); - QSize pixmapUserSize(m_pixmap.size() / m_pixmap.devicePixelRatio()); - p.drawPixmap(QPoint((rect().width() - pixmapUserSize.width()) / 2, - (rect().height() - pixmapUserSize.height()) / 2), - m_pixmap); + m_paint.paint(p, rect()); } void ProgressIndicator::showEvent(QShowEvent *) { - m_timer.start(); + m_paint.startAnimation(); } void ProgressIndicator::hideEvent(QHideEvent *) { - m_timer.stop(); + m_paint.stopAnimation(); } bool ProgressIndicator::eventFilter(QObject *obj, QEvent *ev) @@ -122,15 +175,10 @@ bool ProgressIndicator::eventFilter(QObject *obj, QEvent *ev) return QWidget::eventFilter(obj, ev); } -void ProgressIndicator::step() -{ - m_rotation = (m_rotation + m_rotationStep + 360) % 360; - update(); -} - void ProgressIndicator::resizeToParent() { QTC_ASSERT(parentWidget(), return); setGeometry(QRect(QPoint(0, 0), parentWidget()->size())); } +} // namespace Utils diff --git a/src/libs/utils/progressindicator.h b/src/libs/utils/progressindicator.h index 4fee8b19569..6713709c1b0 100644 --- a/src/libs/utils/progressindicator.h +++ b/src/libs/utils/progressindicator.h @@ -30,44 +30,74 @@ #include #include +#include +#include + namespace Utils { namespace Internal { class ProgressIndicatorPrivate; } +enum class ProgressIndicatorSize +{ + Small, + Medium, + Large +}; + +class QTCREATOR_UTILS_EXPORT ProgressIndicatorPainter +{ +public: + using UpdateCallback = std::function; + + ProgressIndicatorPainter(ProgressIndicatorSize size); + virtual ~ProgressIndicatorPainter() = default; + + virtual void setIndicatorSize(ProgressIndicatorSize size); + ProgressIndicatorSize indicatorSize() const; + + void setUpdateCallback(const UpdateCallback &cb); + + QSize size() const; + + void paint(QPainter &painter, const QRect &rect) const; + + void startAnimation(); + void stopAnimation(); + +protected: + void nextAnimationStep(); + +private: + ProgressIndicatorSize m_size = ProgressIndicatorSize::Small; + int m_rotationStep = 45; + int m_rotation = 0; + QTimer m_timer; + QPixmap m_pixmap; + UpdateCallback m_callback; +}; + class QTCREATOR_UTILS_EXPORT ProgressIndicator : public QWidget { Q_OBJECT public: - enum IndicatorSize { - Small, - Medium, - Large - }; + explicit ProgressIndicator(ProgressIndicatorSize size, QWidget *parent = nullptr); - explicit ProgressIndicator(IndicatorSize size, QWidget *parent = 0); + void setIndicatorSize(ProgressIndicatorSize size); - void setIndicatorSize(IndicatorSize size); - IndicatorSize indicatorSize() const; - - QSize sizeHint() const; + QSize sizeHint() const final; void attachToWidget(QWidget *parent); protected: - void paintEvent(QPaintEvent *); - void showEvent(QShowEvent *); - void hideEvent(QHideEvent *); - bool eventFilter(QObject *obj, QEvent *ev); + void paintEvent(QPaintEvent *) final; + void showEvent(QShowEvent *) final; + void hideEvent(QHideEvent *) final; + bool eventFilter(QObject *obj, QEvent *ev) final; private: - void step(); void resizeToParent(); - ProgressIndicator::IndicatorSize m_size; - int m_rotationStep; - int m_rotation; - QTimer m_timer; - QPixmap m_pixmap; + ProgressIndicatorPainter m_paint; }; } // Utils diff --git a/src/plugins/android/androiddevicedialog.cpp b/src/plugins/android/androiddevicedialog.cpp index 451abf2dc53..a874466e15b 100644 --- a/src/plugins/android/androiddevicedialog.cpp +++ b/src/plugins/android/androiddevicedialog.cpp @@ -462,7 +462,7 @@ AndroidDeviceDialog::AndroidDeviceDialog(int apiLevel, const QString &abi, Andro m_ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large, this); + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large, this); m_progressIndicator->attachToWidget(m_ui->deviceView); if (serialNumber.isEmpty()) { diff --git a/src/plugins/autotest/testnavigationwidget.cpp b/src/plugins/autotest/testnavigationwidget.cpp index 5e34c666e00..7b583730ba1 100644 --- a/src/plugins/autotest/testnavigationwidget.cpp +++ b/src/plugins/autotest/testnavigationwidget.cpp @@ -86,7 +86,7 @@ TestNavigationWidget::TestNavigationWidget(QWidget *parent) : connect(m_view, &TestTreeView::activated, this, &TestNavigationWidget::onItemActivated); - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Medium, this); + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Medium, this); m_progressIndicator->attachToWidget(m_view); m_progressIndicator->hide(); diff --git a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp index 0a84b8f406c..375176f4939 100644 --- a/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp +++ b/src/plugins/cmakeprojectmanager/cmakebuildsettingswidget.cpp @@ -158,7 +158,7 @@ CMakeBuildSettingsWidget::CMakeBuildSettingsWidget(CMakeBuildConfiguration *bc) QFrame *findWrapper = Core::ItemViewFind::createSearchableWrapper(m_configView, Core::ItemViewFind::LightColored); findWrapper->setFrameStyle(QFrame::StyledPanel); - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large, findWrapper); + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large, findWrapper); m_progressIndicator->attachToWidget(findWrapper); m_progressIndicator->raise(); m_progressIndicator->hide(); diff --git a/src/plugins/coreplugin/locator/locatorwidget.cpp b/src/plugins/coreplugin/locator/locatorwidget.cpp index 5073bcd33c3..3c09e0a32f4 100644 --- a/src/plugins/coreplugin/locator/locatorwidget.cpp +++ b/src/plugins/coreplugin/locator/locatorwidget.cpp @@ -570,7 +570,7 @@ LocatorWidget::LocatorWidget(Locator *locator) : m_showPopupTimer.setSingleShot(true); connect(&m_showPopupTimer, &QTimer::timeout, this, &LocatorWidget::showPopupNow); - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Small, + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Small, m_fileLineEdit); m_progressIndicator->raise(); m_progressIndicator->hide(); diff --git a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp index 6197da5296f..6e7b947bb18 100644 --- a/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp +++ b/src/plugins/diffeditor/diffeditorwidgetcontroller.cpp @@ -65,7 +65,7 @@ DiffEditorWidgetController::DiffEditorWidgetController(QWidget *diffEditorWidget void DiffEditorWidgetController::setDocument(DiffEditorDocument *document) { if (!m_progressIndicator) { - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large); + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large); m_progressIndicator->attachToWidget(m_diffEditorWidget); m_progressIndicator->hide(); } diff --git a/src/plugins/git/gerrit/gerritdialog.cpp b/src/plugins/git/gerrit/gerritdialog.cpp index 21ccef371a5..be1d79af902 100644 --- a/src/plugins/git/gerrit/gerritdialog.cpp +++ b/src/plugins/git/gerrit/gerritdialog.cpp @@ -97,7 +97,7 @@ GerritDialog::GerritDialog(const QSharedPointer &p, m_progressIndicatorTimer.setSingleShot(true); m_progressIndicatorTimer.setInterval(50); // don't show progress for < 50ms tasks - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large, + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large, m_ui->treeView); m_progressIndicator->attachToWidget(m_ui->treeView->viewport()); m_progressIndicator->hide(); diff --git a/src/plugins/updateinfo/settingspage.cpp b/src/plugins/updateinfo/settingspage.cpp index e8e07a7d9d7..03a1045a325 100644 --- a/src/plugins/updateinfo/settingspage.cpp +++ b/src/plugins/updateinfo/settingspage.cpp @@ -116,7 +116,7 @@ void SettingsPage::checkRunningChanged(bool running) if (running) { if (!m_progressIndicator) { - m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large); + m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large); m_progressIndicator->attachToWidget(m_widget); } m_progressIndicator->show(); diff --git a/src/plugins/vcsbase/vcsbaseeditor.cpp b/src/plugins/vcsbase/vcsbaseeditor.cpp index 063d2695d7b..2d17bb36928 100644 --- a/src/plugins/vcsbase/vcsbaseeditor.cpp +++ b/src/plugins/vcsbase/vcsbaseeditor.cpp @@ -1398,7 +1398,7 @@ void VcsBaseEditorWidget::setCommand(VcsCommand *command) } d->m_command = command; if (command) { - d->m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicator::Large); + d->m_progressIndicator = new Utils::ProgressIndicator(Utils::ProgressIndicatorSize::Large); d->m_progressIndicator->attachToWidget(this); connect(command, &VcsCommand::finished, this, &VcsBaseEditorWidget::reportCommandFinished); QTimer::singleShot(100, this, &VcsBaseEditorWidget::showProgressIndicator);