Iot dashboard: Make circular progress bar a QskControl (#124)
* IOT example, circular progress bar: Use a pen instead of a brush That way we don't have to draw two circles, and we can in addition use a conical gradient. * IOT example: Make circular progress bar a QskControl ... and internally use a QskPaintedNode for now. By doing this we already have the API ready (similar to QskProgressBar) and can swap the QskPaintedNode with an arc renderer at a later point in time.
This commit is contained in:
parent
279ec9537c
commit
3a1a7c635c
@ -5,107 +5,190 @@
|
|||||||
|
|
||||||
#include "CircularProgressBar.h"
|
#include "CircularProgressBar.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QskAnimator.h>
|
||||||
|
#include <QskFunctions.h>
|
||||||
|
|
||||||
CircularProgressBar::CircularProgressBar( const QskGradient& gradient, int progress, QQuickItem* parent )
|
QSK_SUBCONTROL( CircularProgressBar, Groove )
|
||||||
: QQuickPaintedItem( parent )
|
QSK_SUBCONTROL( CircularProgressBar, Bar )
|
||||||
, m_progress( progress )
|
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
// This is a bit hackish, but let's do this properly
|
class PositionAnimator : public QskAnimator
|
||||||
// once QSkinny has an arc renderer in place
|
|
||||||
QLinearGradient g( 0, 0, 30, 0 );
|
|
||||||
QGradientStop stop1( 0.0, gradient.colorAt( 0 ) );
|
|
||||||
QGradientStop stop2( 1.0, gradient.colorAt( 1 ) );
|
|
||||||
g.setStops( {stop1, stop2} );
|
|
||||||
m_gradient = g;
|
|
||||||
|
|
||||||
connect( this, &QQuickPaintedItem::contentsSizeChanged, [this]()
|
|
||||||
{
|
{
|
||||||
auto size = contentsSize();
|
public:
|
||||||
QRadialGradient ringGradient( size.width() / 2, size.height() / 2, 45 );
|
PositionAnimator( CircularProgressBar* progressBar )
|
||||||
QGradientStop stop1( 0.0, "#c0c0c0" );
|
: m_progressBar( progressBar )
|
||||||
QGradientStop stop2( 0.5, "#f0f0f0" );
|
{
|
||||||
QGradientStop stop3( 1.0, "#c0c0c0" );
|
setAutoRepeat( true );
|
||||||
ringGradient.setStops( {stop1, stop2, stop3} );
|
setDuration( 1300 );
|
||||||
|
|
||||||
m_ringGradient = ringGradient;
|
setWindow( progressBar->window() );
|
||||||
} );
|
}
|
||||||
|
|
||||||
|
void advance( qreal value ) override
|
||||||
|
{
|
||||||
|
const auto aspect = CircularProgressBar::Bar | QskAspect::Position;
|
||||||
|
|
||||||
|
m_progressBar->setMetric( aspect, value );
|
||||||
|
m_progressBar->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CircularProgressBar* m_progressBar;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
double CircularProgressBar::width() const
|
class CircularProgressBar::PrivateData
|
||||||
{
|
{
|
||||||
return m_width;
|
public:
|
||||||
}
|
void updateIndeterminateAnimator( CircularProgressBar* progressBar )
|
||||||
|
{
|
||||||
|
if ( !isIndeterminate )
|
||||||
|
{
|
||||||
|
delete animator;
|
||||||
|
animator = nullptr;
|
||||||
|
|
||||||
void CircularProgressBar::setWidth( double width )
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( progressBar->window() && progressBar->isVisible() )
|
||||||
|
{
|
||||||
|
if ( animator == nullptr )
|
||||||
|
animator = new PositionAnimator( progressBar );
|
||||||
|
|
||||||
|
animator->start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( animator )
|
||||||
|
animator->stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PositionAnimator* animator = nullptr;
|
||||||
|
|
||||||
|
qreal value = 0.0;
|
||||||
|
qreal origin = 0.0;
|
||||||
|
|
||||||
|
bool hasOrigin = false;
|
||||||
|
bool isIndeterminate = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
CircularProgressBar::CircularProgressBar( qreal min, qreal max, QQuickItem* parent )
|
||||||
|
: QskBoundedControl( min, max, parent )
|
||||||
|
, m_data( new PrivateData )
|
||||||
{
|
{
|
||||||
m_width = width;
|
m_data->value = minimum();
|
||||||
|
|
||||||
|
initSizePolicy( QskSizePolicy::MinimumExpanding, QskSizePolicy::MinimumExpanding );
|
||||||
|
|
||||||
|
connect( this, &QskBoundedControl::boundariesChanged,
|
||||||
|
this, &CircularProgressBar::adjustValue );
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor CircularProgressBar::backgroundColor() const
|
CircularProgressBar::CircularProgressBar( QQuickItem* parent )
|
||||||
|
: CircularProgressBar( 0.0, 100.0, parent )
|
||||||
{
|
{
|
||||||
return m_backgroundColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CircularProgressBar::setBackgroundColor( const QColor& color )
|
bool CircularProgressBar::isIndeterminate() const
|
||||||
{
|
{
|
||||||
m_backgroundColor = color;
|
return m_data->isIndeterminate;
|
||||||
}
|
}
|
||||||
|
|
||||||
QRadialGradient CircularProgressBar::ringGradient() const
|
void CircularProgressBar::setIndeterminate( bool on )
|
||||||
{
|
{
|
||||||
return m_ringGradient;
|
if ( on == m_data->isIndeterminate )
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_data->isIndeterminate = on;
|
||||||
|
m_data->updateIndeterminateAnimator( this );
|
||||||
|
|
||||||
|
update();
|
||||||
|
Q_EMIT indeterminateChanged( on );
|
||||||
}
|
}
|
||||||
|
|
||||||
void CircularProgressBar::setRingGradient( const QRadialGradient& gradient )
|
void CircularProgressBar::resetOrigin()
|
||||||
{
|
{
|
||||||
m_ringGradient = gradient;
|
if ( m_data->hasOrigin )
|
||||||
|
{
|
||||||
|
m_data->hasOrigin = false;
|
||||||
|
|
||||||
|
update();
|
||||||
|
Q_EMIT originChanged( origin() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CircularProgressBar::paint( QPainter* painter )
|
qreal CircularProgressBar::origin() const
|
||||||
{
|
{
|
||||||
const auto size = contentsSize();
|
if ( m_data->hasOrigin )
|
||||||
|
{
|
||||||
|
return boundedValue( m_data->origin );
|
||||||
|
}
|
||||||
|
|
||||||
const int startAngle = 1440;
|
return minimum();
|
||||||
const int endAngle = -16 * ( m_progress / 100.0 ) * 360;
|
|
||||||
|
|
||||||
painter->setRenderHint( QPainter::Antialiasing, true );
|
|
||||||
|
|
||||||
#if 1
|
|
||||||
QRectF outerRect( {0, 0}, size );
|
|
||||||
|
|
||||||
painter->setBrush( m_ringGradient );
|
|
||||||
painter->setPen( m_backgroundColor );
|
|
||||||
painter->drawEllipse( outerRect );
|
|
||||||
|
|
||||||
painter->setBrush( m_gradient );
|
|
||||||
painter->drawPie( outerRect, startAngle, endAngle );
|
|
||||||
|
|
||||||
painter->setBrush( m_backgroundColor );
|
|
||||||
painter->setPen( m_backgroundColor );
|
|
||||||
QRectF innerRect( width() / 2, width() / 2, size.width() - width(), size.height() - width() );
|
|
||||||
painter->drawEllipse( innerRect );
|
|
||||||
#else
|
|
||||||
const qreal w = 10;
|
|
||||||
|
|
||||||
const QRectF r( 0.5 * w, 0.5 * w, size.width() - w, size.height() - w );
|
|
||||||
|
|
||||||
const QColor c0 ( Qt::lightGray );
|
|
||||||
|
|
||||||
QRadialGradient g1( r.center(), qMin( r.width(), r.height() ) );
|
|
||||||
g1.setColorAt( 0.0, c0 );
|
|
||||||
g1.setColorAt( 0.5, c0.lighter( 120 ) );
|
|
||||||
g1.setColorAt( 1.0, c0 );
|
|
||||||
|
|
||||||
painter->setPen( QPen( g1, w, Qt::SolidLine, Qt::FlatCap ) );
|
|
||||||
painter->drawArc( r, startAngle, 16 * 360 );
|
|
||||||
|
|
||||||
QConicalGradient g2( r.center(), 0 );
|
|
||||||
g2.setColorAt( 0.0, Qt::red );
|
|
||||||
g2.setColorAt( 0.5, Qt::blue );
|
|
||||||
g2.setColorAt( 1.0, Qt::red );
|
|
||||||
|
|
||||||
painter->setPen( QPen( g2, w, Qt::SolidLine, Qt::FlatCap ) );
|
|
||||||
painter->drawArc( r, startAngle, endAngle );
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qreal CircularProgressBar::value() const
|
||||||
|
{
|
||||||
|
return m_data->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal CircularProgressBar::valueAsRatio() const
|
||||||
|
{
|
||||||
|
return QskBoundedControl::valueAsRatio( m_data->value );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircularProgressBar::setValue( qreal value )
|
||||||
|
{
|
||||||
|
if ( isComponentComplete() )
|
||||||
|
value = boundedValue( value );
|
||||||
|
|
||||||
|
setValueInternal( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircularProgressBar::setValueAsRatio( qreal ratio )
|
||||||
|
{
|
||||||
|
ratio = qBound( 0.0, ratio, 1.0 );
|
||||||
|
setValue( minimum() + ratio * boundaryLength() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircularProgressBar::setOrigin( qreal origin )
|
||||||
|
{
|
||||||
|
if ( isComponentComplete() )
|
||||||
|
origin = boundedValue( origin );
|
||||||
|
|
||||||
|
if( !m_data->hasOrigin || !qskFuzzyCompare( m_data->origin, origin ) )
|
||||||
|
{
|
||||||
|
m_data->hasOrigin = true;
|
||||||
|
m_data->origin = origin;
|
||||||
|
|
||||||
|
update();
|
||||||
|
Q_EMIT originChanged( origin );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircularProgressBar::componentComplete()
|
||||||
|
{
|
||||||
|
Inherited::componentComplete();
|
||||||
|
adjustValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircularProgressBar::setValueInternal( qreal value )
|
||||||
|
{
|
||||||
|
if ( !qskFuzzyCompare( value, m_data->value ) )
|
||||||
|
{
|
||||||
|
m_data->value = value;
|
||||||
|
Q_EMIT valueChanged( value );
|
||||||
|
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CircularProgressBar::adjustValue()
|
||||||
|
{
|
||||||
|
if ( isComponentComplete() )
|
||||||
|
setValueInternal( boundedValue( m_data->value ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_CircularProgressBar.cpp"
|
||||||
|
@ -5,31 +5,59 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskBoundedControl.h>
|
||||||
#include <QskGradient.h>
|
#include <QskGradient.h>
|
||||||
|
|
||||||
#include <QGradient>
|
#include <QGradient>
|
||||||
#include <QQuickPaintedItem>
|
|
||||||
|
|
||||||
class CircularProgressBar : public QQuickPaintedItem
|
class CircularProgressBar : public QskBoundedControl
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY( bool indeterminate READ isIndeterminate
|
||||||
|
WRITE setIndeterminate NOTIFY indeterminateChanged )
|
||||||
|
|
||||||
|
Q_PROPERTY( qreal origin READ origin
|
||||||
|
WRITE setOrigin RESET resetOrigin NOTIFY originChanged )
|
||||||
|
|
||||||
|
Q_PROPERTY( qreal value READ value WRITE setValue NOTIFY valueChanged )
|
||||||
|
Q_PROPERTY( qreal valueAsRatio READ valueAsRatio
|
||||||
|
WRITE setValueAsRatio NOTIFY valueChanged )
|
||||||
|
|
||||||
|
using Inherited = QskBoundedControl;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CircularProgressBar( const QskGradient&, int progress, QQuickItem* parent = nullptr );
|
QSK_SUBCONTROLS( Groove, Bar )
|
||||||
|
|
||||||
virtual void paint( QPainter* painter ) override;
|
CircularProgressBar( qreal min, qreal max, QQuickItem* parent = nullptr );
|
||||||
|
CircularProgressBar( QQuickItem* parent = nullptr );
|
||||||
|
|
||||||
double width() const;
|
bool isIndeterminate() const;
|
||||||
void setWidth( double width );
|
void setIndeterminate( bool on = true );
|
||||||
|
|
||||||
QColor backgroundColor() const;
|
void resetOrigin();
|
||||||
void setBackgroundColor( const QColor& );
|
qreal origin() const;
|
||||||
|
|
||||||
QRadialGradient ringGradient() const;
|
qreal value() const;
|
||||||
void setRingGradient( const QRadialGradient& );
|
qreal valueAsRatio() const; // [0.0, 1.0]
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void setValue( qreal );
|
||||||
|
void setValueAsRatio( qreal );
|
||||||
|
void setOrigin( qreal );
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
void indeterminateChanged( bool );
|
||||||
|
void valueChanged( qreal );
|
||||||
|
void originChanged( qreal );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void componentComplete() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QGradient m_gradient;
|
void setValueInternal( qreal value );
|
||||||
QColor m_backgroundColor;
|
void adjustValue();
|
||||||
QRadialGradient m_ringGradient;
|
|
||||||
double m_width = 20;
|
class PrivateData;
|
||||||
int m_progress;
|
std::unique_ptr< PrivateData > m_data;
|
||||||
};
|
};
|
||||||
|
220
examples/iotdashboard/CircularProgressBarSkinlet.cpp
Normal file
220
examples/iotdashboard/CircularProgressBarSkinlet.cpp
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2021 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "CircularProgressBarSkinlet.h"
|
||||||
|
#include "CircularProgressBar.h"
|
||||||
|
|
||||||
|
#include <QskPaintedNode.h>
|
||||||
|
|
||||||
|
#include <QEasingCurve>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class ArcNode : public QskPaintedNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ArcNode() : QskPaintedNode()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGradient( const QskGradient& gradient )
|
||||||
|
{
|
||||||
|
m_gradient = gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setGradientType( QGradient::Type type )
|
||||||
|
{
|
||||||
|
m_gradientType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setWidth( double width )
|
||||||
|
{
|
||||||
|
m_width = width;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue( double value )
|
||||||
|
{
|
||||||
|
m_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setOrigin( double origin )
|
||||||
|
{
|
||||||
|
m_origin = origin;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setMaximum( double maximum )
|
||||||
|
{
|
||||||
|
m_maximum = maximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setIndeterminate( bool isIndeterminate )
|
||||||
|
{
|
||||||
|
m_isIndeterminate = isIndeterminate;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setPosition( double position )
|
||||||
|
{
|
||||||
|
m_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void paint( QPainter* painter, const QSizeF& size ) override
|
||||||
|
{
|
||||||
|
int startAngle;
|
||||||
|
int spanAngle;
|
||||||
|
|
||||||
|
if( m_isIndeterminate )
|
||||||
|
{
|
||||||
|
static const QEasingCurve curve( QEasingCurve::Linear );
|
||||||
|
|
||||||
|
startAngle = -1 * m_position * 360;
|
||||||
|
// the other option is to just set a fixed value for the
|
||||||
|
// span angle (or do some advanced stuff with easing curves)
|
||||||
|
spanAngle = qAbs( 0.5 - m_position ) * 360;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startAngle = 90 + -1 * ( m_origin / m_maximum ) * 360;
|
||||||
|
spanAngle = -1 * ( m_value / m_maximum ) * 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setRenderHint( QPainter::Antialiasing, true );
|
||||||
|
|
||||||
|
const QRectF r( 0.5 * m_width, 0.5 * m_width, size.width() - m_width, size.height() - m_width );
|
||||||
|
|
||||||
|
QGradientStops stops;
|
||||||
|
|
||||||
|
for( const QskGradientStop& stop : m_gradient.stops() )
|
||||||
|
{
|
||||||
|
QGradientStop s( stop.position(), stop.color() );
|
||||||
|
stops.append( s );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( m_gradientType == QGradient::RadialGradient )
|
||||||
|
{
|
||||||
|
QRadialGradient radialGradient( r.center(), qMin( r.width(), r.height() ) );
|
||||||
|
radialGradient.setStops( stops );
|
||||||
|
|
||||||
|
painter->setPen( QPen( radialGradient, m_width, Qt::SolidLine, Qt::FlatCap ) );
|
||||||
|
painter->drawArc( r, startAngle * 16, spanAngle * 16 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QConicalGradient conicalGradient( r.center(), startAngle );
|
||||||
|
conicalGradient.setStops( stops );
|
||||||
|
|
||||||
|
painter->setPen( QPen( conicalGradient, m_width, Qt::SolidLine, Qt::FlatCap ) );
|
||||||
|
painter->drawArc( r, startAngle * 16, spanAngle * 16 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint hash() const override
|
||||||
|
{
|
||||||
|
uint h = qHash( m_gradientType );
|
||||||
|
h = qHash( m_width, h );
|
||||||
|
h = qHash( m_value, h );
|
||||||
|
h = qHash( m_origin, h );
|
||||||
|
h = qHash( m_maximum, h );
|
||||||
|
h = qHash( m_isIndeterminate, h );
|
||||||
|
h = qHash( m_position, h );
|
||||||
|
|
||||||
|
for( const QskGradientStop& stop : m_gradient.stops() )
|
||||||
|
{
|
||||||
|
h = stop.hash( h );
|
||||||
|
}
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QskGradient m_gradient;
|
||||||
|
QGradient::Type m_gradientType;
|
||||||
|
double m_width;
|
||||||
|
double m_value;
|
||||||
|
double m_origin;
|
||||||
|
double m_maximum;
|
||||||
|
bool m_isIndeterminate;
|
||||||
|
double m_position;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularProgressBarSkinlet::CircularProgressBarSkinlet( QskSkin* skin )
|
||||||
|
: QskSkinlet( skin )
|
||||||
|
{
|
||||||
|
setNodeRoles( { GrooveRole, BarRole } );
|
||||||
|
}
|
||||||
|
|
||||||
|
CircularProgressBarSkinlet::~CircularProgressBarSkinlet()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF CircularProgressBarSkinlet::subControlRect(
|
||||||
|
const QskSkinnable* /*skinnable*/, const QRectF& contentsRect,
|
||||||
|
QskAspect::Subcontrol /*subControl*/ ) const
|
||||||
|
{
|
||||||
|
return contentsRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* CircularProgressBarSkinlet::updateSubNode(
|
||||||
|
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
|
||||||
|
{
|
||||||
|
const auto bar = static_cast< const CircularProgressBar* >( skinnable );
|
||||||
|
|
||||||
|
switch( nodeRole )
|
||||||
|
{
|
||||||
|
case GrooveRole: // fall through
|
||||||
|
case BarRole:
|
||||||
|
{
|
||||||
|
return updateBarNode( bar, nodeRole, node );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Inherited::updateSubNode( skinnable, nodeRole, node );
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGNode* CircularProgressBarSkinlet::updateBarNode( const CircularProgressBar* bar, quint8 nodeRole, QSGNode* node ) const
|
||||||
|
{
|
||||||
|
auto arcNode = static_cast< ArcNode* >( node );
|
||||||
|
|
||||||
|
if( arcNode == nullptr )
|
||||||
|
{
|
||||||
|
arcNode = new ArcNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto subControl = ( nodeRole == GrooveRole ) ? CircularProgressBar::Groove
|
||||||
|
: CircularProgressBar::Bar;
|
||||||
|
|
||||||
|
const QskGradient gradient = bar->gradientHint( subControl );
|
||||||
|
|
||||||
|
const QGradient::Type type = ( nodeRole == GrooveRole ) ?
|
||||||
|
QGradient::RadialGradient : QGradient::ConicalGradient;
|
||||||
|
|
||||||
|
const double width = bar->metric( subControl | QskAspect::Size );
|
||||||
|
const double value = ( nodeRole == GrooveRole ) ? bar->maximum() : bar->value();
|
||||||
|
|
||||||
|
arcNode->setGradient( gradient );
|
||||||
|
arcNode->setGradientType( type );
|
||||||
|
arcNode->setWidth( width );
|
||||||
|
arcNode->setOrigin( bar->origin() );
|
||||||
|
arcNode->setMaximum( bar->maximum() );
|
||||||
|
arcNode->setIndeterminate( bar->isIndeterminate() );
|
||||||
|
|
||||||
|
if( bar->isIndeterminate() )
|
||||||
|
{
|
||||||
|
const double position = bar->metric( CircularProgressBar::Bar | QskAspect::Position );
|
||||||
|
arcNode->setPosition( position );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
arcNode->setValue( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
QQuickWindow* window = bar->window();
|
||||||
|
const QRect rect = bar->contentsRect().toRect();
|
||||||
|
arcNode->update( window, QskTextureRenderer::AutoDetect, rect );
|
||||||
|
|
||||||
|
return arcNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_CircularProgressBarSkinlet.cpp"
|
39
examples/iotdashboard/CircularProgressBarSkinlet.h
Normal file
39
examples/iotdashboard/CircularProgressBarSkinlet.h
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2021 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the QSkinny License, Version 1.0
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QskSkinlet.h>
|
||||||
|
|
||||||
|
class CircularProgressBar;
|
||||||
|
|
||||||
|
class CircularProgressBarSkinlet : public QskSkinlet
|
||||||
|
{
|
||||||
|
Q_GADGET
|
||||||
|
|
||||||
|
using Inherited = QskSkinlet;
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum NodeRole
|
||||||
|
{
|
||||||
|
GrooveRole,
|
||||||
|
BarRole,
|
||||||
|
|
||||||
|
RoleCount,
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_INVOKABLE CircularProgressBarSkinlet( QskSkin* = nullptr );
|
||||||
|
~CircularProgressBarSkinlet() override;
|
||||||
|
|
||||||
|
QRectF subControlRect( const QskSkinnable*,
|
||||||
|
const QRectF&, QskAspect::Subcontrol ) const override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
QSGNode* updateSubNode( const QskSkinnable*,
|
||||||
|
quint8 nodeRole, QSGNode* ) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSGNode* updateBarNode( const CircularProgressBar*, quint8 nodeRole, QSGNode* ) const;
|
||||||
|
};
|
@ -47,7 +47,6 @@ class ProgressBarAnimator : public QskAnimator
|
|||||||
void setup() override
|
void setup() override
|
||||||
{
|
{
|
||||||
m_backgroundColor = m_pieChart->color( PieChartPainted::Panel );
|
m_backgroundColor = m_pieChart->color( PieChartPainted::Panel );
|
||||||
m_ringGradient = m_progressBar->ringGradient();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance( qreal value ) override
|
void advance( qreal value ) override
|
||||||
@ -68,7 +67,6 @@ class ProgressBarAnimator : public QskAnimator
|
|||||||
newGradient.setColorAt( stop.first, newColor );
|
newGradient.setColorAt( stop.first, newColor );
|
||||||
}
|
}
|
||||||
|
|
||||||
m_progressBar->setRingGradient( newGradient );
|
|
||||||
m_progressBar->update();
|
m_progressBar->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,13 +81,16 @@ PieChartPainted::PieChartPainted( const QColor& color, const QskGradient& gradie
|
|||||||
: QskControl( parent )
|
: QskControl( parent )
|
||||||
, m_color( color )
|
, m_color( color )
|
||||||
, m_gradient( gradient )
|
, m_gradient( gradient )
|
||||||
, m_progressBar( new CircularProgressBar( gradient, progress, this ) )
|
, m_progressBar( new CircularProgressBar( this ) )
|
||||||
, m_progressLabel( new QskTextLabel( this ) )
|
, m_progressLabel( new QskTextLabel( this ) )
|
||||||
, m_animator( new ProgressBarAnimator( this, m_progressBar ) )
|
, m_animator( new ProgressBarAnimator( this, m_progressBar ) )
|
||||||
{
|
{
|
||||||
setAutoLayoutChildren( true );
|
setAutoLayoutChildren( true );
|
||||||
setSubcontrolProxy( QskBox::Panel, PieChartPainted::Panel );
|
setSubcontrolProxy( QskBox::Panel, PieChartPainted::Panel );
|
||||||
|
|
||||||
|
m_progressBar->setGradientHint( CircularProgressBar::Bar, gradient );
|
||||||
|
m_progressBar->setValue( progress );
|
||||||
|
|
||||||
auto progressText = QString::number( progress ) + " %";
|
auto progressText = QString::number( progress ) + " %";
|
||||||
m_progressLabel->setText( progressText );
|
m_progressLabel->setText( progressText );
|
||||||
m_progressLabel->setFontRole( QskSkin::SmallFont );
|
m_progressLabel->setFontRole( QskSkin::SmallFont );
|
||||||
@ -109,7 +110,6 @@ QSizeF PieChartPainted::contentsSizeHint( Qt::SizeHint /*sizeHint*/, const QSize
|
|||||||
|
|
||||||
void PieChartPainted::updateLayout()
|
void PieChartPainted::updateLayout()
|
||||||
{
|
{
|
||||||
m_progressBar->setContentsSize( size().toSize() );
|
|
||||||
m_progressBar->update();
|
m_progressBar->update();
|
||||||
|
|
||||||
const auto rect = layoutRect();
|
const auto rect = layoutRect();
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "Box.h"
|
#include "Box.h"
|
||||||
#include "BoxWithButtons.h"
|
#include "BoxWithButtons.h"
|
||||||
|
#include "CircularProgressBar.h"
|
||||||
|
#include "CircularProgressBarSkinlet.h"
|
||||||
#include "Diagram.h"
|
#include "Diagram.h"
|
||||||
#include "DiagramSkinlet.h"
|
#include "DiagramSkinlet.h"
|
||||||
#include "LightIntensity.h"
|
#include "LightIntensity.h"
|
||||||
@ -48,6 +50,7 @@ namespace
|
|||||||
Skin::Skin( const Palette& palette, QObject* parent )
|
Skin::Skin( const Palette& palette, QObject* parent )
|
||||||
: QskSkin( parent )
|
: QskSkin( parent )
|
||||||
{
|
{
|
||||||
|
declareSkinlet< CircularProgressBar, CircularProgressBarSkinlet >();
|
||||||
declareSkinlet< Diagram, DiagramSkinlet >();
|
declareSkinlet< Diagram, DiagramSkinlet >();
|
||||||
|
|
||||||
initHints( palette );
|
initHints( palette );
|
||||||
@ -104,10 +107,15 @@ void Skin::initHints( const Palette& palette )
|
|||||||
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, "#f99055" );
|
ed.setColor( TopBarItem::Item3 | QskAspect::TextColor, "#f99055" );
|
||||||
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, "#6776ff" );
|
ed.setColor( TopBarItem::Item4 | QskAspect::TextColor, "#6776ff" );
|
||||||
|
|
||||||
ed.setGradient( TopBarItem::Item1, { Qt::Horizontal, "#FF5C00", "#FF3122" } );
|
// conical gradients are counterclockwise, so specify the 2nd color first:
|
||||||
ed.setGradient( TopBarItem::Item2, { Qt::Horizontal, "#6776FF", "#6100FF" } );
|
ed.setGradient( TopBarItem::Item1, { Qt::Horizontal, "#FF3122", "#FF5C00" } );
|
||||||
ed.setGradient( TopBarItem::Item3, { Qt::Horizontal, "#FFCE50", "#FF3122" } );
|
ed.setGradient( TopBarItem::Item2, { Qt::Horizontal, "#6100FF", "#6776FF" } );
|
||||||
ed.setGradient( TopBarItem::Item4, { Qt::Horizontal, "#6776FF", "#6100FF" } );
|
ed.setGradient( TopBarItem::Item3, { Qt::Horizontal, "#FF3122", "#FFCE50" } );
|
||||||
|
ed.setGradient( TopBarItem::Item4, { Qt::Horizontal, "#6100FF", "#6776FF" } );
|
||||||
|
|
||||||
|
// the bar gradient is defined through the top bar items above
|
||||||
|
ed.setMetricHint( CircularProgressBar::Groove | QskAspect::Size, 8.53 );
|
||||||
|
ed.setMetricHint( CircularProgressBar::Bar | QskAspect::Size, 8.53 );
|
||||||
|
|
||||||
ed.setFontRole( TimeTitleLabel::Text, Skin::TitleFont );
|
ed.setFontRole( TimeTitleLabel::Text, Skin::TitleFont );
|
||||||
|
|
||||||
@ -180,4 +188,5 @@ void Skin::initHints( const Palette& palette )
|
|||||||
ed.setColor( QskTextLabel::Text, palette.text );
|
ed.setColor( QskTextLabel::Text, palette.text );
|
||||||
ed.setColor( UsageDiagramBox::DayText, palette.text );
|
ed.setColor( UsageDiagramBox::DayText, palette.text );
|
||||||
ed.setColor( ShadowPositioner::Panel, palette.shadow );
|
ed.setColor( ShadowPositioner::Panel, palette.shadow );
|
||||||
|
ed.setGradient( CircularProgressBar::Groove, palette.circularProgressBarGroove );
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,8 @@ class Skin : public QskSkin
|
|||||||
Palette( const QskGradient& menuBar, const QskGradient& mainContent,
|
Palette( const QskGradient& menuBar, const QskGradient& mainContent,
|
||||||
const QskGradient& box, const QColor& lightDisplay, const QColor& pieChart,
|
const QskGradient& box, const QColor& lightDisplay, const QColor& pieChart,
|
||||||
const QskGradient& roundButton, const QColor& weekdayBox,
|
const QskGradient& roundButton, const QColor& weekdayBox,
|
||||||
const QColor& text, const QColor& shadow )
|
const QColor& text, const QColor& shadow,
|
||||||
|
const QskGradient& circularProgressBarGroove )
|
||||||
: menuBar( menuBar )
|
: menuBar( menuBar )
|
||||||
, mainContent( mainContent )
|
, mainContent( mainContent )
|
||||||
, box( box )
|
, box( box )
|
||||||
@ -27,6 +28,7 @@ class Skin : public QskSkin
|
|||||||
, weekdayBox( weekdayBox )
|
, weekdayBox( weekdayBox )
|
||||||
, text( text )
|
, text( text )
|
||||||
, shadow( shadow )
|
, shadow( shadow )
|
||||||
|
, circularProgressBarGroove( circularProgressBarGroove )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
QskGradient menuBar;
|
QskGradient menuBar;
|
||||||
@ -38,6 +40,7 @@ class Skin : public QskSkin
|
|||||||
QColor weekdayBox;
|
QColor weekdayBox;
|
||||||
QColor text;
|
QColor text;
|
||||||
QColor shadow;
|
QColor shadow;
|
||||||
|
QskGradient circularProgressBarGroove;
|
||||||
};
|
};
|
||||||
|
|
||||||
Skin( const Palette& palette, QObject* parent = nullptr );
|
Skin( const Palette& palette, QObject* parent = nullptr );
|
||||||
@ -59,7 +62,8 @@ class DaytimeSkin : public Skin
|
|||||||
: Skin(
|
: Skin(
|
||||||
Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"},
|
Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"},
|
||||||
"#ffffff", "#ffffff", {"#f7f7f7"},
|
"#ffffff", "#ffffff", {"#f7f7f7"},
|
||||||
{"#f4f4f4"}, Qt::black, Qt::black )
|
{"#f4f4f4"}, Qt::black, Qt::black,
|
||||||
|
{ Qt::Horizontal, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } )
|
||||||
, parent )
|
, parent )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -72,7 +76,8 @@ class NighttimeSkin : public Skin
|
|||||||
: Skin(
|
: Skin(
|
||||||
Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"},
|
Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"},
|
||||||
"#000000", "#000000", {"#0a0a0a"},
|
"#000000", "#000000", {"#0a0a0a"},
|
||||||
{"#0c0c0c"}, Qt::white, Qt::white )
|
{"#0c0c0c"}, Qt::white, Qt::white,
|
||||||
|
{ Qt::Horizontal, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } )
|
||||||
, parent )
|
, parent )
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ SOURCES += \
|
|||||||
Box.cpp \
|
Box.cpp \
|
||||||
BoxWithButtons.cpp \
|
BoxWithButtons.cpp \
|
||||||
CircularProgressBar.cpp \
|
CircularProgressBar.cpp \
|
||||||
|
CircularProgressBarSkinlet.cpp \
|
||||||
Diagram.cpp \
|
Diagram.cpp \
|
||||||
DiagramSkinlet.cpp \
|
DiagramSkinlet.cpp \
|
||||||
LightIntensity.cpp \
|
LightIntensity.cpp \
|
||||||
@ -30,6 +31,7 @@ HEADERS += \
|
|||||||
Box.h \
|
Box.h \
|
||||||
BoxWithButtons.h \
|
BoxWithButtons.h \
|
||||||
CircularProgressBar.h \
|
CircularProgressBar.h \
|
||||||
|
CircularProgressBarSkinlet.h \
|
||||||
Diagram.h \
|
Diagram.h \
|
||||||
DiagramSkinlet.h \
|
DiagramSkinlet.h \
|
||||||
LightIntensity.h \
|
LightIntensity.h \
|
||||||
|
Loading…
x
Reference in New Issue
Block a user