mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-04 17:10:47 +00:00
Add styled progress bars, including animations for the 'infinite' case
This commit is contained in:
@@ -59,6 +59,65 @@ static const int ComboArrowDim = 12;
|
||||
|
||||
static const int SpinButtonDim = 12;
|
||||
static const int SpinMargin = 1;
|
||||
|
||||
static const int ProgressMargin = 2;
|
||||
static const qreal ProgressRadius = 4.0;
|
||||
};
|
||||
|
||||
namespace Animation
|
||||
{
|
||||
QHash<QObject *, QAbstractAnimation *> animations;
|
||||
|
||||
bool has(QObject *target)
|
||||
{
|
||||
return animations.contains(target);
|
||||
}
|
||||
|
||||
QAbstractAnimation *get(QObject *target)
|
||||
{
|
||||
return animations.value(target);
|
||||
}
|
||||
|
||||
template <typename AnimationType>
|
||||
AnimationType *get(QObject *target)
|
||||
{
|
||||
return (AnimationType *)get(target);
|
||||
}
|
||||
|
||||
void stop(QObject *target)
|
||||
{
|
||||
if(has(target))
|
||||
{
|
||||
QAbstractAnimation *existing = get(target);
|
||||
existing->stop();
|
||||
delete existing;
|
||||
animations.remove(target);
|
||||
}
|
||||
}
|
||||
|
||||
void removeOnDelete(QObject *target)
|
||||
{
|
||||
if(has(target))
|
||||
animations.remove(target);
|
||||
}
|
||||
|
||||
void start(QAbstractAnimation *anim)
|
||||
{
|
||||
QObject *target = anim->parent();
|
||||
|
||||
stop(target);
|
||||
if(has(target))
|
||||
{
|
||||
QAbstractAnimation *existing = get(target);
|
||||
existing->stop();
|
||||
delete existing;
|
||||
animations.remove(target);
|
||||
}
|
||||
|
||||
animations.insert(target, anim);
|
||||
QObject::connect(target, &QObject::destroyed, &removeOnDelete);
|
||||
anim->start();
|
||||
}
|
||||
};
|
||||
|
||||
RDStyle::RDStyle(ColorScheme scheme) : RDTweakedNativeStyle(new QCommonStyle())
|
||||
@@ -175,6 +234,11 @@ void RDStyle::polish(QWidget *widget)
|
||||
widget->setAttribute(Qt::WA_Hover);
|
||||
}
|
||||
|
||||
void RDStyle::unpolish(QWidget *widget)
|
||||
{
|
||||
Animation::stop(widget);
|
||||
}
|
||||
|
||||
QRect RDStyle::subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
|
||||
const QWidget *widget) const
|
||||
{
|
||||
@@ -458,7 +522,7 @@ QSize RDStyle::sizeFromContents(ContentsType type, const QStyleOption *opt, cons
|
||||
|
||||
return ret;
|
||||
}
|
||||
else if(type == CT_GroupBox || type == CT_ScrollBar)
|
||||
else if(type == CT_GroupBox || type == CT_ScrollBar || type == CT_ProgressBar)
|
||||
{
|
||||
return size;
|
||||
}
|
||||
@@ -497,6 +561,9 @@ int RDStyle::pixelMetric(PixelMetric metric, const QStyleOption *opt, const QWid
|
||||
|
||||
if(metric == PM_ScrollBarExtent)
|
||||
return Constants::ScrollButtonDim + 2;
|
||||
// not used for rendering but just as an estimate of how small a progress bar can get
|
||||
if(metric == PM_ProgressBarChunkWidth)
|
||||
return 10;
|
||||
|
||||
return RDTweakedNativeStyle::pixelMetric(metric, opt, widget);
|
||||
}
|
||||
@@ -519,6 +586,12 @@ int RDStyle::styleHint(StyleHint stylehint, const QStyleOption *opt, const QWidg
|
||||
if(stylehint == SH_UnderlineShortcut)
|
||||
return 0;
|
||||
|
||||
if(stylehint == SH_ProgressDialog_CenterCancelButton)
|
||||
return 1;
|
||||
|
||||
if(stylehint == SH_ProgressDialog_TextLabelAlignment)
|
||||
return Qt::AlignCenter;
|
||||
|
||||
return RDTweakedNativeStyle::styleHint(stylehint, opt, widget, returnData);
|
||||
}
|
||||
|
||||
@@ -1141,6 +1214,68 @@ void RDStyle::drawControl(ControlElement control, const QStyleOption *opt, QPain
|
||||
|
||||
return;
|
||||
}
|
||||
else if(control == QStyle::CE_ProgressBar)
|
||||
{
|
||||
QRect rect = opt->rect;
|
||||
|
||||
rect.adjust(Constants::ProgressMargin, Constants::ProgressMargin, -Constants::ProgressMargin,
|
||||
-Constants::ProgressMargin);
|
||||
|
||||
QPainterPath path;
|
||||
path.addRoundedRect(rect, Constants::ProgressRadius, Constants::ProgressRadius);
|
||||
|
||||
const QStyleOptionProgressBar *progress = qstyleoption_cast<const QStyleOptionProgressBar *>(opt);
|
||||
|
||||
p->save();
|
||||
p->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
p->setPen(QPen(outlineBrush(opt->palette), 1.0));
|
||||
p->drawPath(path);
|
||||
|
||||
if(progress->minimum >= progress->maximum && opt->styleObject)
|
||||
{
|
||||
// animate an 'infinite' progress bar by adding animated clip regions
|
||||
if(!Animation::has(opt->styleObject))
|
||||
Animation::start(new RDProgressAnimation(2, 30, opt->styleObject));
|
||||
|
||||
RDProgressAnimation *anim = Animation::get<RDProgressAnimation>(opt->styleObject);
|
||||
|
||||
QRegion region;
|
||||
|
||||
rect.setWidth(anim->chunkSize());
|
||||
|
||||
rect.moveLeft(rect.left() + anim->offset());
|
||||
|
||||
while(rect.intersects(opt->rect))
|
||||
{
|
||||
region += rect;
|
||||
|
||||
// step two chunks, to skip over the chunk we're excluding from the region
|
||||
rect.moveLeft(rect.left() + anim->chunkSize() * 2);
|
||||
}
|
||||
|
||||
p->setClipRegion(region);
|
||||
}
|
||||
|
||||
// if we're rendering a normal progress bar, set the clip rect
|
||||
if(progress->minimum < progress->maximum)
|
||||
{
|
||||
qreal delta = qreal(progress->progress) / qreal(progress->maximum - progress->minimum);
|
||||
rect.setRight(rect.left() + rect.width() * delta);
|
||||
|
||||
p->setClipRect(rect);
|
||||
}
|
||||
|
||||
p->fillPath(path, opt->palette.brush(QPalette::Highlight));
|
||||
|
||||
p->restore();
|
||||
|
||||
return;
|
||||
}
|
||||
else if(control == QStyle::CE_ProgressBarGroove)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RDTweakedNativeStyle::drawControl(control, opt, p, widget);
|
||||
}
|
||||
@@ -1200,3 +1335,48 @@ void RDStyle::drawRoundedRectBorder(const QStyleOption *opt, QPainter *p, const
|
||||
|
||||
p->restore();
|
||||
}
|
||||
|
||||
RDProgressAnimation::RDProgressAnimation(int stepSize, int chunkSize, QObject *parent)
|
||||
: QAbstractAnimation(parent)
|
||||
{
|
||||
m_stepSize = stepSize;
|
||||
m_offset = 0;
|
||||
m_chunkSize = chunkSize;
|
||||
m_prevTime = 0;
|
||||
}
|
||||
|
||||
void RDProgressAnimation::updateCurrentTime(int currentTime)
|
||||
{
|
||||
// update every 33ms, for a 30Hz animation
|
||||
const int rate = 33;
|
||||
|
||||
// how many steps to take
|
||||
int steps = 0;
|
||||
|
||||
int delta = currentTime - m_prevTime;
|
||||
|
||||
// depending on how fast we're updated, we might have to process multiple frames together.
|
||||
while(delta > rate)
|
||||
{
|
||||
m_prevTime += rate;
|
||||
delta = currentTime - m_prevTime;
|
||||
|
||||
steps++;
|
||||
}
|
||||
|
||||
if(steps > 0)
|
||||
{
|
||||
m_offset += steps * m_stepSize;
|
||||
|
||||
// the animation loops after two chunks, but to visualise a smooth animation with a new chunk
|
||||
// coming in from the left, we wrap to negative.
|
||||
// Consider the graph y = (x+1) % 2 - 1
|
||||
|
||||
if(m_offset > m_chunkSize)
|
||||
m_offset -= m_chunkSize * 2;
|
||||
|
||||
QEvent event(QEvent::StyleAnimationUpdate);
|
||||
event.setAccepted(false);
|
||||
QCoreApplication::sendEvent(parent(), &event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,10 +24,32 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QAbstractAnimation>
|
||||
#include <QPalette>
|
||||
#include <QProxyStyle>
|
||||
#include "Styles/RDTweakedNativeStyle/RDTweakedNativeStyle.h"
|
||||
|
||||
class RDProgressAnimation : public QAbstractAnimation
|
||||
{
|
||||
private:
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
RDProgressAnimation(int stepSize, int chunkSize, QObject *parent);
|
||||
|
||||
int duration() const override { return -1; }
|
||||
int offset() const { return m_offset; }
|
||||
int chunkSize() const { return m_chunkSize; }
|
||||
int stepSize() const { return m_stepSize; }
|
||||
protected:
|
||||
void updateCurrentTime(int currentTime) override;
|
||||
|
||||
int m_prevTime;
|
||||
int m_offset;
|
||||
int m_chunkSize;
|
||||
int m_stepSize;
|
||||
};
|
||||
|
||||
class RDStyle : public RDTweakedNativeStyle
|
||||
{
|
||||
private:
|
||||
@@ -43,6 +65,7 @@ public:
|
||||
|
||||
void polish(QPalette &pal) override;
|
||||
void polish(QWidget *widget) override;
|
||||
void unpolish(QWidget *widget) override;
|
||||
|
||||
QRect subControlRect(ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc,
|
||||
const QWidget *widget = Q_NULLPTR) const override;
|
||||
|
||||
Reference in New Issue
Block a user