Spinner: Add SpinnerWidget

Move it from spinner example and make it a reusable widget.

Change-Id: I3d74ec491f5d1cb7d012551f624cff2c618952ca
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2024-01-27 19:38:09 +01:00
parent 096a5aca0d
commit 0890ad05b2
3 changed files with 110 additions and 82 deletions

View File

@@ -5,19 +5,21 @@
#include <QApplication> #include <QApplication>
#include <QEvent> #include <QEvent>
#include <QHBoxLayout>
#include <QIcon> #include <QIcon>
#include <QLabel>
#include <QPainter> #include <QPainter>
#include <QTimer> #include <QTimer>
#include <QWidget> #include <QWidget>
namespace SpinnerSolution { namespace SpinnerSolution {
class OverlayWidget : public QWidget class WidgetOverlay : public QWidget
{ {
public: public:
using PaintFunction = std::function<void(QWidget *, QPainter &, QPaintEvent *)>; using PaintFunction = std::function<void(QWidget *, QPainter &, QPaintEvent *)>;
explicit OverlayWidget(QWidget *parent = nullptr) explicit WidgetOverlay(QWidget *parent = nullptr)
{ {
setAttribute(Qt::WA_TransparentForMouseEvents); setAttribute(Qt::WA_TransparentForMouseEvents);
if (parent) if (parent)
@@ -151,11 +153,11 @@ void SpinnerPainter::paint(QPainter &painter, const QRect &rect) const
painter.restore(); painter.restore();
} }
class SpinnerWidget : public OverlayWidget class SpinnerOverlay : public WidgetOverlay
{ {
public: public:
explicit SpinnerWidget(SpinnerSize size, QWidget *parent = nullptr) explicit SpinnerOverlay(SpinnerSize size, QWidget *parent = nullptr)
: OverlayWidget(parent) : WidgetOverlay(parent)
, m_paint(size) , m_paint(size)
{ {
setPaintFunction( setPaintFunction(
@@ -219,7 +221,7 @@ private:
*/ */
Spinner::Spinner(SpinnerSize size, QWidget *parent) Spinner::Spinner(SpinnerSize size, QWidget *parent)
: QObject(parent) : QObject(parent)
, m_widget(new SpinnerWidget(size, parent)) {} , m_widget(new SpinnerOverlay(size, parent)) {}
/*! /*!
Sets the size of the spinner to the given \a size. Sets the size of the spinner to the given \a size.
@@ -263,4 +265,83 @@ void Spinner::setVisible(bool visible)
m_widget->setVisible(visible); m_widget->setVisible(visible);
} }
static QString colorButtonStyleSheet(const QColor &bgColor)
{
QString rc("border-width: 1px; border-radius: 1px; border-color: black; ");
rc += bgColor.isValid() ? "border-style: solid; background:" + bgColor.name() + ";"
: QString("border-style: dotted;");
return rc;
}
static QColor stateToColor(SpinnerState state)
{
switch (state) {
case SpinnerState::NotRunning: return Qt::gray;
case SpinnerState::Running: return Qt::yellow;
}
return {};
}
class SpinnerWidgetPrivate : public QLabel
{
public:
SpinnerWidgetPrivate(QWidget *parent = nullptr)
: QLabel(parent)
, m_spinner(new Spinner(SpinnerSize::Small, this))
{
updateState();
}
void setState(SpinnerState state)
{
if (m_state == state)
return;
m_state = state;
updateState();
}
void setDecorated(bool on)
{
if (m_decorated == on)
return;
m_decorated = on;
updateState();
}
private:
void updateState()
{
const int size = m_decorated ? 26 : 24;
setFixedSize(size, size);
setStyleSheet(m_decorated ? colorButtonStyleSheet(stateToColor(m_state)) : QString());
if (m_state == SpinnerState::Running)
m_spinner->show();
else
m_spinner->hide();
}
bool m_decorated = true;
SpinnerState m_state = SpinnerState::NotRunning;
Spinner *m_spinner = nullptr;
};
SpinnerWidget::SpinnerWidget(QWidget *parent)
: QWidget(parent)
, d(new SpinnerWidgetPrivate(this))
{
QBoxLayout *layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(d);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}
void SpinnerWidget::setState(SpinnerState state)
{
d->setState(state);
}
void SpinnerWidget::setDecorated(bool on)
{
d->setDecorated(on);
}
} // namespace SpinnerSolution } // namespace SpinnerSolution

View File

@@ -6,7 +6,7 @@
#include "spinner_global.h" #include "spinner_global.h"
#include <QObject> #include <QWidget>
namespace SpinnerSolution { namespace SpinnerSolution {
@@ -15,11 +15,15 @@ Q_NAMESPACE_EXPORT(SPINNER_EXPORT)
enum class SpinnerSize { Small, Medium, Large }; enum class SpinnerSize { Small, Medium, Large };
Q_ENUM_NS(SpinnerSize) Q_ENUM_NS(SpinnerSize)
enum class SpinnerState { NotRunning, Running };
Q_ENUM_NS(SpinnerState)
// TODO: SpinnerOverlay and SpinnerWidget? // TODO: SpinnerOverlay and SpinnerWidget?
class SPINNER_EXPORT Spinner : public QObject class SPINNER_EXPORT Spinner : public QObject
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit Spinner(SpinnerSize size, QWidget *parent = nullptr); explicit Spinner(SpinnerSize size, QWidget *parent = nullptr);
void setSize(SpinnerSize size); void setSize(SpinnerSize size);
@@ -29,7 +33,20 @@ public:
void setVisible(bool visible); void setVisible(bool visible);
private: private:
class SpinnerWidget *m_widget = nullptr; class SpinnerOverlay *m_widget = nullptr;
};
class SPINNER_EXPORT SpinnerWidget : public QWidget
{
Q_OBJECT
public:
explicit SpinnerWidget(QWidget *parent = nullptr);
void setState(SpinnerState state);
void setDecorated(bool on);
private:
class SpinnerWidgetPrivate *d;
}; };
} // namespace SpinnerSolution } // namespace SpinnerSolution

View File

@@ -14,82 +14,12 @@
using namespace SpinnerSolution; using namespace SpinnerSolution;
enum class State {
NotRunning,
Running
};
static QString colorButtonStyleSheet(const QColor &bgColor)
{
QString rc("border-width: 2px; border-radius: 2px; border-color: black; ");
rc += bgColor.isValid() ? "border-style: solid; background:" + bgColor.name() + ";"
: QString("border-style: dotted;");
return rc;
}
static QColor stateToColor(State state)
{
switch (state) {
case State::NotRunning: return Qt::gray;
case State::Running: return Qt::yellow;
}
return {};
}
class StateIndicator : public QLabel
{
public:
StateIndicator(QWidget *parent = nullptr)
: QLabel(parent)
{
setFixedSize(30, 30);
m_spinner = new Spinner(SpinnerSize::Small, this);
m_spinner->hide();
updateState();
}
void setState(State state)
{
if (m_state == state)
return;
m_state = state;
updateState();
}
private:
void updateState()
{
setStyleSheet(colorButtonStyleSheet(stateToColor(m_state)));
if (m_state == State::Running)
m_spinner->show();
else
m_spinner->hide();
}
State m_state = State::NotRunning;
Spinner *m_spinner = nullptr;
};
class StateWidget : public QWidget
{
public:
StateWidget() : m_stateIndicator(new StateIndicator(this)) {
QBoxLayout *layout = new QHBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_stateIndicator);
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}
void setState(State state) { m_stateIndicator->setState(state); }
protected:
StateIndicator *m_stateIndicator = nullptr;
};
QGroupBox *createGroupBox(SpinnerSize size, QWidget *widget) QGroupBox *createGroupBox(SpinnerSize size, QWidget *widget)
{ {
const QMetaEnum spinnerSize = QMetaEnum::fromType<SpinnerSize>(); const QMetaEnum spinnerSize = QMetaEnum::fromType<SpinnerSize>();
QGroupBox *groupBox = new QGroupBox(spinnerSize.valueToKey(int(size))); QGroupBox *groupBox = new QGroupBox(spinnerSize.valueToKey(int(size)));
StateWidget *stateWidget = new StateWidget; SpinnerWidget *spinnerWidget = new SpinnerWidget;
QToolButton *startButton = new QToolButton; QToolButton *startButton = new QToolButton;
startButton->setText("Start"); startButton->setText("Start");
QToolButton *stopButton = new QToolButton; QToolButton *stopButton = new QToolButton;
@@ -97,7 +27,7 @@ QGroupBox *createGroupBox(SpinnerSize size, QWidget *widget)
QVBoxLayout *mainLayout = new QVBoxLayout(groupBox); QVBoxLayout *mainLayout = new QVBoxLayout(groupBox);
QHBoxLayout *topLayout = new QHBoxLayout(); QHBoxLayout *topLayout = new QHBoxLayout();
topLayout->addWidget(stateWidget); topLayout->addWidget(spinnerWidget);
topLayout->addWidget(startButton); topLayout->addWidget(startButton);
topLayout->addWidget(stopButton); topLayout->addWidget(stopButton);
topLayout->addStretch(); topLayout->addStretch();
@@ -108,12 +38,12 @@ QGroupBox *createGroupBox(SpinnerSize size, QWidget *widget)
spinner->hide(); // TODO: make the default hidden? spinner->hide(); // TODO: make the default hidden?
QObject::connect(startButton, &QAbstractButton::clicked, groupBox, [=] { QObject::connect(startButton, &QAbstractButton::clicked, groupBox, [=] {
stateWidget->setState(State::Running); spinnerWidget->setState(SpinnerState::Running);
spinner->show(); spinner->show();
widget->setEnabled(false); widget->setEnabled(false);
}); });
QObject::connect(stopButton, &QAbstractButton::clicked, groupBox, [=] { QObject::connect(stopButton, &QAbstractButton::clicked, groupBox, [=] {
stateWidget->setState(State::NotRunning); spinnerWidget->setState(SpinnerState::NotRunning);
spinner->hide(); spinner->hide();
widget->setEnabled(true); widget->setEnabled(true);
}); });