mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-08-07 09:01:38 -04:00
Move spinner implementation into native code
Should make it more performant and allow drawing without holding the GIL. Note that have not currently replaced the actual python implementation as that would break running from source. Will do that after the next release.
This commit is contained in:
parent
10d5d8b6bc
commit
7369171e33
@ -9,18 +9,21 @@
|
||||
#include <QStyleOptionToolButton>
|
||||
#include <QFormLayout>
|
||||
#include <QDialogButtonBox>
|
||||
#include <algorithm>
|
||||
|
||||
QProgressIndicator::QProgressIndicator(QWidget* parent, int size)
|
||||
QProgressIndicator::QProgressIndicator(QWidget* parent, int size, int interval)
|
||||
: QWidget(parent),
|
||||
m_angle(0),
|
||||
m_timerId(-1),
|
||||
m_delay(80),
|
||||
m_displaySize(size),
|
||||
m_displayedWhenStopped(true),
|
||||
m_color(Qt::black)
|
||||
m_delay(interval),
|
||||
m_displaySize(size, size),
|
||||
m_dark(Qt::black),
|
||||
m_light(Qt::white)
|
||||
{
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
|
||||
setFocusPolicy(Qt::NoFocus);
|
||||
m_dark = this->palette().color(QPalette::WindowText);
|
||||
m_light = this->palette().color(QPalette::Window);
|
||||
}
|
||||
|
||||
bool QProgressIndicator::isAnimated () const
|
||||
@ -28,24 +31,22 @@ bool QProgressIndicator::isAnimated () const
|
||||
return (m_timerId != -1);
|
||||
}
|
||||
|
||||
void QProgressIndicator::setDisplayedWhenStopped(bool state)
|
||||
void QProgressIndicator::setDisplaySize(QSize size)
|
||||
{
|
||||
m_displayedWhenStopped = state;
|
||||
|
||||
update();
|
||||
setSizeHint(size);
|
||||
}
|
||||
|
||||
void QProgressIndicator::setDisplaySize(int size)
|
||||
void QProgressIndicator::setSizeHint(int size)
|
||||
{
|
||||
setSizeHint(QSize(size, size));
|
||||
}
|
||||
void QProgressIndicator::setSizeHint(QSize size)
|
||||
{
|
||||
m_displaySize = size;
|
||||
update();
|
||||
}
|
||||
|
||||
|
||||
bool QProgressIndicator::isDisplayedWhenStopped() const
|
||||
{
|
||||
return m_displayedWhenStopped;
|
||||
}
|
||||
|
||||
|
||||
void QProgressIndicator::startAnimation()
|
||||
{
|
||||
@ -54,6 +55,7 @@ void QProgressIndicator::startAnimation()
|
||||
if (m_timerId == -1)
|
||||
m_timerId = startTimer(m_delay);
|
||||
}
|
||||
void QProgressIndicator::start() { startAnimation(); }
|
||||
|
||||
void QProgressIndicator::stopAnimation()
|
||||
{
|
||||
@ -64,6 +66,7 @@ void QProgressIndicator::stopAnimation()
|
||||
|
||||
update();
|
||||
}
|
||||
void QProgressIndicator::stop() { stopAnimation(); }
|
||||
|
||||
void QProgressIndicator::setAnimationDelay(int delay)
|
||||
{
|
||||
@ -76,16 +79,16 @@ void QProgressIndicator::setAnimationDelay(int delay)
|
||||
m_timerId = startTimer(m_delay);
|
||||
}
|
||||
|
||||
void QProgressIndicator::setColor(const QColor & color)
|
||||
void QProgressIndicator::set_colors(const QColor & dark, const QColor & light)
|
||||
{
|
||||
m_color = color;
|
||||
m_dark = dark; m_light = light;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
QSize QProgressIndicator::sizeHint() const
|
||||
{
|
||||
return QSize(m_displaySize, m_displaySize);
|
||||
return m_displaySize;
|
||||
}
|
||||
|
||||
int QProgressIndicator::heightForWidth(int w) const
|
||||
@ -95,40 +98,15 @@ int QProgressIndicator::heightForWidth(int w) const
|
||||
|
||||
void QProgressIndicator::timerEvent(QTimerEvent * /*event*/)
|
||||
{
|
||||
m_angle = (m_angle+30)%360;
|
||||
m_angle = (m_angle-2)%360;
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
void QProgressIndicator::paintEvent(QPaintEvent * /*event*/)
|
||||
{
|
||||
if (!m_displayedWhenStopped && !isAnimated())
|
||||
return;
|
||||
|
||||
int width = qMin(this->width(), this->height());
|
||||
|
||||
QPainter p(this);
|
||||
p.setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int outerRadius = (width-1)*0.5;
|
||||
int innerRadius = (width-1)*0.5*0.38;
|
||||
|
||||
int capsuleHeight = outerRadius - innerRadius;
|
||||
int capsuleWidth = (width > 32 ) ? capsuleHeight *.23 : capsuleHeight *.35;
|
||||
int capsuleRadius = capsuleWidth/2;
|
||||
|
||||
for (int i=0; i<12; i++)
|
||||
{
|
||||
QColor color = m_color;
|
||||
color.setAlphaF(1.0f - (i/12.0f));
|
||||
p.setPen(Qt::NoPen);
|
||||
p.setBrush(color);
|
||||
p.save();
|
||||
p.translate(rect().center());
|
||||
p.rotate(m_angle - i*30.0f);
|
||||
p.drawRoundedRect(-capsuleWidth*0.5, -(innerRadius+capsuleHeight), capsuleWidth, capsuleHeight, capsuleRadius, capsuleRadius);
|
||||
p.restore();
|
||||
}
|
||||
QPainter painter(this);
|
||||
draw_snake_spinner(painter, this->rect(), m_angle, m_light, m_dark);
|
||||
}
|
||||
|
||||
static inline QByteArray detectDesktopEnvironment()
|
||||
@ -282,3 +260,27 @@ class TouchMenuStyle: public QProxyStyle {
|
||||
void set_touch_menu_style(QWidget *widget, int margin) {
|
||||
widget->setStyle(new TouchMenuStyle(margin));
|
||||
}
|
||||
|
||||
void draw_snake_spinner(QPainter &painter, QRect rect, int angle, const QColor & light, const QColor & dark) {
|
||||
painter.save();
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
if (rect.width() > rect.height()) {
|
||||
int delta = (rect.width() - rect.height()) / 2;
|
||||
rect = rect.adjusted(delta, 0, -delta, 0);
|
||||
} else if (rect.height() > rect.width()) {
|
||||
int delta = (rect.height() - rect.width()) / 2;
|
||||
rect = rect.adjusted(0, delta, 0, -delta);
|
||||
}
|
||||
int disc_width = std::max(3, std::min(rect.width() / 10, 8));
|
||||
QRect drawing_rect(rect.x() + disc_width, rect.y() + disc_width, rect.width() - 2 * disc_width, rect.height() - 2 *disc_width);
|
||||
int gap = 60; // degrees
|
||||
QConicalGradient gradient(drawing_rect.center(), angle - gap / 2);
|
||||
gradient.setColorAt((360 - gap/2)/360.0, light);
|
||||
gradient.setColorAt(0, dark);
|
||||
|
||||
QPen pen(QBrush(gradient), disc_width);
|
||||
pen.setCapStyle(Qt::RoundCap);
|
||||
painter.setPen(pen);
|
||||
painter.drawArc(drawing_rect, angle * 16, (360 - gap) * 16);
|
||||
painter.restore();
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QColor>
|
||||
#include <QHash>
|
||||
#include <QPainter>
|
||||
|
||||
/*!
|
||||
\class QProgressIndicator
|
||||
@ -15,11 +16,9 @@ class QProgressIndicator : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(int delay READ animationDelay WRITE setAnimationDelay)
|
||||
Q_PROPERTY(bool displayedWhenStopped READ isDisplayedWhenStopped WRITE setDisplayedWhenStopped)
|
||||
Q_PROPERTY(QColor color READ color WRITE setColor)
|
||||
Q_PROPERTY(int displaySize READ displaySize WRITE setDisplaySize)
|
||||
Q_PROPERTY(QSize displaySize READ displaySize WRITE setDisplaySize)
|
||||
public:
|
||||
QProgressIndicator(QWidget* parent = 0, int size = 64);
|
||||
QProgressIndicator(QWidget* parent = 0, int size = 64, int interval = 10);
|
||||
|
||||
/*! Returns the delay between animation steps.
|
||||
\return The number of milliseconds between animation steps. By default, the animation delay is set to 80 milliseconds.
|
||||
@ -33,30 +32,21 @@ public:
|
||||
*/
|
||||
bool isAnimated () const;
|
||||
|
||||
/*! Returns a Boolean value indicating whether the receiver shows itself even when it is not animating.
|
||||
\return Return true if the progress indicator shows itself even when it is not animating. By default, it returns false.
|
||||
\sa setDisplayedWhenStopped
|
||||
*/
|
||||
bool isDisplayedWhenStopped() const;
|
||||
|
||||
/*! Returns the color of the component.
|
||||
\sa setColor
|
||||
*/
|
||||
const QColor & color() const { return m_color; }
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
int heightForWidth(int w) const;
|
||||
int displaySize() const { return m_displaySize; }
|
||||
QSize displaySize() const { return m_displaySize; }
|
||||
public slots:
|
||||
/*! Starts the spin animation.
|
||||
\sa stopAnimation isAnimated
|
||||
*/
|
||||
void startAnimation();
|
||||
void start();
|
||||
|
||||
/*! Stops the spin animation.
|
||||
\sa startAnimation isAnimated
|
||||
*/
|
||||
void stopAnimation();
|
||||
void stop();
|
||||
|
||||
/*! Sets the delay between animation steps.
|
||||
Setting the \a delay to a value larger than 40 slows the animation, while setting the \a delay to a smaller value speeds it up.
|
||||
@ -65,21 +55,17 @@ public slots:
|
||||
*/
|
||||
void setAnimationDelay(int delay);
|
||||
|
||||
/*! Sets whether the component hides itself when it is not animating.
|
||||
\param state The animation state. Set false to hide the progress indicator when it is not animating; otherwise true.
|
||||
\sa isDisplayedWhenStopped
|
||||
*/
|
||||
void setDisplayedWhenStopped(bool state);
|
||||
|
||||
/*! Sets the color of the components to the given color.
|
||||
\sa color
|
||||
*/
|
||||
void setColor(const QColor & color);
|
||||
void set_colors(const QColor & dark, const QColor & light);
|
||||
|
||||
/*! Set the size of this widget (used by sizeHint)
|
||||
* \sa displaySize
|
||||
*/
|
||||
void setDisplaySize(int size);
|
||||
void setDisplaySize(QSize size);
|
||||
void setSizeHint(int size);
|
||||
void setSizeHint(QSize size);
|
||||
protected:
|
||||
virtual void timerEvent(QTimerEvent * event);
|
||||
virtual void paintEvent(QPaintEvent * event);
|
||||
@ -87,11 +73,11 @@ private:
|
||||
int m_angle;
|
||||
int m_timerId;
|
||||
int m_delay;
|
||||
int m_displaySize;
|
||||
bool m_displayedWhenStopped;
|
||||
QColor m_color;
|
||||
QSize m_displaySize;
|
||||
QColor m_dark, m_light;
|
||||
};
|
||||
|
||||
int load_style(QHash<int,QString> icon_map);
|
||||
void set_no_activate_on_click(QWidget *widget);
|
||||
void set_touch_menu_style(QWidget *widget, int margin=14);
|
||||
void draw_snake_spinner(QPainter &painter, QRect rect, int angle, const QColor & light, const QColor & dark);
|
||||
|
@ -6,9 +6,11 @@
|
||||
%Import QtWidgets/QtWidgetsmod.sip
|
||||
|
||||
%ModuleHeaderCode
|
||||
#include <QPainter>
|
||||
int load_style(QHash<int,QString> icon_map);
|
||||
void set_no_activate_on_click(QWidget *widget);
|
||||
void set_touch_menu_style(QWidget *widget, int margin);
|
||||
void draw_snake_spinner(QPainter &painter, QRect rect, int angle, const QColor & light, const QColor & dark);
|
||||
%End
|
||||
|
||||
class QProgressIndicator : QWidget {
|
||||
@ -19,34 +21,32 @@ class QProgressIndicator : QWidget {
|
||||
|
||||
public:
|
||||
|
||||
QProgressIndicator(QWidget *parent /TransferThis/ = 0, int size = 64);
|
||||
QProgressIndicator(QWidget *parent /TransferThis/ = 0, int size = 64, int interval = 10);
|
||||
|
||||
int animationDelay() const;
|
||||
|
||||
bool isAnimated () const;
|
||||
|
||||
bool isDisplayedWhenStopped() const;
|
||||
|
||||
const QColor & color() const;
|
||||
|
||||
virtual QSize sizeHint() const;
|
||||
|
||||
int heightForWidth(int w) const;
|
||||
|
||||
int displaySize() const;
|
||||
QSize displaySize() const;
|
||||
|
||||
public slots:
|
||||
void startAnimation();
|
||||
void start();
|
||||
|
||||
void stopAnimation();
|
||||
void stop();
|
||||
|
||||
void setAnimationDelay(int delay);
|
||||
|
||||
void setDisplayedWhenStopped(bool state);
|
||||
void set_colors(const QColor & dark, const QColor & light);
|
||||
|
||||
void setColor(const QColor & color);
|
||||
|
||||
void setDisplaySize(int size);
|
||||
void setDisplaySize(QSize size);
|
||||
void setSizeHint(int size);
|
||||
void setSizeHint(QSize size);
|
||||
|
||||
protected:
|
||||
|
||||
@ -59,3 +59,4 @@ protected:
|
||||
int load_style(QHash<int,QString> icon_map);
|
||||
void set_no_activate_on_click(QWidget *widget);
|
||||
void set_touch_menu_style(QWidget *widget, int margin=20);
|
||||
void draw_snake_spinner(QPainter &painter, QRect rect, int angle, const QColor & light, const QColor & dark);
|
||||
|
Loading…
x
Reference in New Issue
Block a user