progress indicators: Update to newest M3 spec

This commit is contained in:
Peter Hartmann 2024-10-28 16:11:44 +01:00
parent a2719b4ccd
commit 35eb98292e
9 changed files with 232 additions and 59 deletions

View File

@ -486,22 +486,21 @@ void Editor::setupProgressBar()
using A = QskAspect; using A = QskAspect;
using Q = QskProgressBar; using Q = QskProgressBar;
auto size = 4_dp;
for ( auto subControl : { Q::Groove, Q::Fill } ) for ( auto subControl : { Q::Groove, Q::Fill } )
{ {
setMetric( subControl | A::Size, size ); setBoxShape( subControl, { 100, Qt::RelativeSize } );
setPadding( subControl, 0 ); setMetric( subControl | A::Size, 4_dp );
setBoxShape( subControl, 0 );
setBoxBorderMetrics( subControl, 0 );
} }
setMetric( Q::Groove | A::Size, size );
setGradient( Q::Groove, m_pal.surfaceContainerHighest ); setGradient( Q::Groove, m_pal.surfaceContainerHighest );
setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 ); setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 );
setStrutSize( Q::GrooveStopIndicator, { 4_dp, 4_dp } );
setBoxShape( Q::GrooveStopIndicator, { 100, Qt::RelativeSize } );
setGradient( Q::GrooveStopIndicator, m_pal.primary );
setGradient( Q::GrooveStopIndicator | Q::Disabled, m_pal.onSurface38 );
setSpacing( Q::Fill, 4_dp );
setGradient( Q::Fill, m_pal.primary ); setGradient( Q::Fill, m_pal.primary );
setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 ); setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 );
} }
@ -510,9 +509,15 @@ void Editor::setupProgressRing()
{ {
using Q = QskProgressRing; using Q = QskProgressRing;
setArcMetrics( Q::Groove, 90, -360, 4_dp );
setGradient( Q::Groove, m_pal.surfaceContainerHighest );
setGradient( Q::Groove | Q::Disabled, m_pal.onSurface12 );
setSpacing( Q::Fill, 10 );
setStrutSize( Q::Fill, { 48_dp, 48_dp } ); setStrutSize( Q::Fill, { 48_dp, 48_dp } );
setGradient( Q::Fill, m_pal.primary );
setArcMetrics( Q::Fill, 90, -360, 4_dp ); setArcMetrics( Q::Fill, 90, -360, 4_dp );
setGradient( Q::Fill, m_pal.primary );
setGradient( Q::Fill | Q::Disabled, m_pal.onSurface38 );
} }
void Editor::setupRadioBox() void Editor::setupRadioBox()

View File

@ -9,6 +9,7 @@
QSK_SUBCONTROL( QskProgressBar, Groove ) QSK_SUBCONTROL( QskProgressBar, Groove )
QSK_SUBCONTROL( QskProgressBar, Fill ) QSK_SUBCONTROL( QskProgressBar, Fill )
QSK_SUBCONTROL( QskProgressBar, GrooveStopIndicator )
class QskProgressBar::PrivateData class QskProgressBar::PrivateData
{ {

View File

@ -18,7 +18,7 @@ class QSK_EXPORT QskProgressBar : public QskProgressIndicator
using Inherited = QskProgressIndicator; using Inherited = QskProgressIndicator;
public: public:
QSK_SUBCONTROLS( Groove, Fill ) QSK_SUBCONTROLS( Groove, Fill, GrooveStopIndicator )
QskProgressBar( Qt::Orientation, QQuickItem* parent = nullptr ); QskProgressBar( Qt::Orientation, QQuickItem* parent = nullptr );
QskProgressBar( Qt::Orientation, qreal min, qreal max, QQuickItem* parent = nullptr ); QskProgressBar( Qt::Orientation, qreal min, qreal max, QQuickItem* parent = nullptr );

View File

@ -15,6 +15,26 @@ using Q = QskProgressBar;
namespace namespace
{ {
QRectF qskFullGrooveRect( const QskProgressBar* bar )
{
const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size );
auto rect = bar->contentsRect();
if ( bar->orientation() == Qt::Horizontal )
{
rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) );
rect.setHeight( grooveSize );
}
else
{
rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) );
rect.setWidth( grooveSize );
}
return rect;
}
QskIntervalF qskFillInterval( const QskProgressIndicator* indicator ) QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
{ {
qreal pos1, pos2; qreal pos1, pos2;
@ -37,6 +57,7 @@ namespace
} }
auto bar = static_cast< const QskProgressBar* >( indicator ); auto bar = static_cast< const QskProgressBar* >( indicator );
if( bar->orientation() == Qt::Horizontal ) if( bar->orientation() == Qt::Horizontal )
{ {
if ( bar->layoutMirroring() ) if ( bar->layoutMirroring() )
@ -51,11 +72,17 @@ namespace
return QskIntervalF( pos1, pos2 ); return QskIntervalF( pos1, pos2 );
} }
inline bool qskIsContiguous( const QskProgressBar* bar )
{
return qFuzzyIsNull( bar->spacingHint( Q::Fill ) );
}
} }
QskProgressBarSkinlet::QskProgressBarSkinlet( QskSkin* skin ) QskProgressBarSkinlet::QskProgressBarSkinlet( QskSkin* skin )
: Inherited( skin ) : Inherited( skin )
{ {
setNodeRoles( { GrooveRole, FillRole, GrooveStopIndicatorRole } );
} }
QskProgressBarSkinlet::~QskProgressBarSkinlet() QskProgressBarSkinlet::~QskProgressBarSkinlet()
@ -68,37 +95,46 @@ QRectF QskProgressBarSkinlet::subControlRect(
{ {
const auto bar = static_cast< const Q* >( skinnable ); const auto bar = static_cast< const Q* >( skinnable );
if( subControl == Q::Groove )
{
const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size );
auto rect = contentsRect;
if ( bar->orientation() == Qt::Horizontal )
{
rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) );
rect.setHeight( grooveSize );
}
else
{
rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) );
rect.setWidth( grooveSize );
}
return rect;
}
if( subControl == Q::Fill ) if( subControl == Q::Fill )
{ {
return barRect( bar ); return barRect( bar );
} }
if( subControl == Q::GrooveStopIndicator )
{
return grooveStopIndicatorRect( bar );
}
return Inherited::subControlRect( skinnable, contentsRect, subControl ); return Inherited::subControlRect( skinnable, contentsRect, subControl );
} }
QSGNode* QskProgressBarSkinlet::updateSubNode(
const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
{
const auto bar = static_cast< const Q* >( skinnable );
switch( nodeRole )
{
case GrooveStopIndicatorRole:
{
if( bar->isIndeterminate() || bar->hasOrigin() )
{
return nullptr;
}
else
{
return updateBoxNode( skinnable, node, Q::GrooveStopIndicator );
}
}
}
return Inherited::updateSubNode( skinnable, nodeRole, node );
}
QSGNode* QskProgressBarSkinlet::updateGrooveNode( QSGNode* QskProgressBarSkinlet::updateGrooveNode(
const QskProgressIndicator* indicator, QSGNode* node ) const const QskProgressIndicator* indicator, QSGNode* node ) const
{ {
return updateBoxNode( indicator, node, Q::Groove ); return updateSeriesNode( indicator, Q::Groove, node );
} }
QSGNode* QskProgressBarSkinlet::updateFillNode( QSGNode* QskProgressBarSkinlet::updateFillNode(
@ -146,12 +182,21 @@ QSGNode* QskProgressBarSkinlet::updateFillNode(
return updateBoxNode( indicator, node, rect, gradient, subControl ); return updateBoxNode( indicator, node, rect, gradient, subControl );
} }
QSGNode* QskProgressBarSkinlet::updateSampleNode( const QskSkinnable* skinnable,
QskAspect::Subcontrol subControl, int index, QSGNode* node ) const
{
const auto bar = static_cast< const QskProgressBar* >( skinnable );
const auto rect = sampleRect( bar, bar->contentsRect(), subControl, index );
return updateBoxNode( skinnable, node, rect, subControl );
}
QRectF QskProgressBarSkinlet::barRect( const Q* bar ) const QRectF QskProgressBarSkinlet::barRect( const Q* bar ) const
{ {
const auto subControl = Q::Groove; const auto subControl = Q::Groove;
const auto barSize = bar->metric( Q::Fill | QskAspect::Size ); const auto barSize = bar->metric( Q::Fill | QskAspect::Size );
auto rect = bar->subControlRect( subControl ); auto rect = qskFullGrooveRect( bar );
if ( bar->orientation() == Qt::Horizontal ) if ( bar->orientation() == Qt::Horizontal )
{ {
@ -207,4 +252,70 @@ QSizeF QskProgressBarSkinlet::sizeHint( const QskSkinnable* skinnable,
return QSizeF( extent, -1 ); return QSizeF( extent, -1 );
} }
int QskProgressBarSkinlet::sampleCount( const QskSkinnable* skinnable, QskAspect::Subcontrol ) const
{
const auto bar = static_cast< const Q* >( skinnable );
const auto samples = ( ( bar->isIndeterminate() || bar->hasOrigin() ) && !qskIsContiguous( bar ) ) ? 2 : 1;
return samples;
}
QRectF QskProgressBarSkinlet::sampleRect( const QskSkinnable* skinnable,
const QRectF&, QskAspect::Subcontrol, int index ) const
{
const auto bar = static_cast< const Q* >( skinnable );
const auto br = barRect( bar );
QRectF rect = qskFullGrooveRect( bar );
const auto spacing = bar->spacingHint( Q::Fill );
const auto isContiguous = qskIsContiguous( bar );
if( isContiguous )
{
return rect;
}
else
{
if( bar->orientation() == Qt::Horizontal )
{
if( index == 0 )
{
rect.setLeft( br.right() + spacing );
}
else
{
rect.setRight( br.left() - spacing );
}
}
else
{
if( index == 0 )
{
rect.setBottom( br.top() - spacing );
}
else
{
rect.setTop( br.bottom() + spacing );
}
}
}
return rect;
}
QRectF QskProgressBarSkinlet::grooveStopIndicatorRect( const QskProgressBar* bar ) const
{
auto rect = qskFullGrooveRect( bar );
const auto size = bar->strutSizeHint( Q::GrooveStopIndicator );
if( bar->orientation() == Qt::Horizontal )
{
rect.setLeft( rect.right() - size.width() );
}
else
{
rect.setBottom( rect.top() + size.height() );
}
return rect;
}
#include "moc_QskProgressBarSkinlet.cpp" #include "moc_QskProgressBarSkinlet.cpp"

View File

@ -17,6 +17,11 @@ class QSK_EXPORT QskProgressBarSkinlet : public QskProgressIndicatorSkinlet
using Inherited = QskProgressIndicatorSkinlet; using Inherited = QskProgressIndicatorSkinlet;
public: public:
enum NodeRole
{
GrooveStopIndicatorRole = Inherited::RoleCount,
};
Q_INVOKABLE QskProgressBarSkinlet( QskSkin* = nullptr ); Q_INVOKABLE QskProgressBarSkinlet( QskSkin* = nullptr );
~QskProgressBarSkinlet() override; ~QskProgressBarSkinlet() override;
@ -26,12 +31,23 @@ class QSK_EXPORT QskProgressBarSkinlet : public QskProgressIndicatorSkinlet
QSizeF sizeHint( const QskSkinnable*, QSizeF sizeHint( const QskSkinnable*,
Qt::SizeHint, const QSizeF& ) const override; Qt::SizeHint, const QSizeF& ) const override;
int sampleCount( const QskSkinnable*, QskAspect::Subcontrol ) const override;
QRectF sampleRect( const QskSkinnable*,
const QRectF&, QskAspect::Subcontrol, int index ) const override;
protected: protected:
QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override;
QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override; QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override;
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override; QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
QSGNode* updateSampleNode( const QskSkinnable*,
QskAspect::Subcontrol, int index, QSGNode* ) const override;
private: private:
QRectF barRect( const QskProgressBar* ) const; QRectF barRect( const QskProgressBar* ) const;
QRectF grooveStopIndicatorRect( const QskProgressBar* ) const;
}; };
#endif #endif

View File

@ -189,6 +189,11 @@ qreal QskProgressIndicator::origin() const
return minimum(); return minimum();
} }
bool QskProgressIndicator::hasOrigin() const
{
return m_data->hasOrigin;
}
void QskProgressIndicator::setValue( qreal value ) void QskProgressIndicator::setValue( qreal value )
{ {
if ( isComponentComplete() ) if ( isComponentComplete() )

View File

@ -51,6 +51,7 @@ class QSK_EXPORT QskProgressIndicator : public QskBoundedControl
void resetOrigin(); void resetOrigin();
qreal origin() const; qreal origin() const;
bool hasOrigin() const;
qreal value() const; qreal value() const;
qreal valueAsRatio() const; // [0.0, 1.0] qreal valueAsRatio() const; // [0.0, 1.0]

View File

@ -10,6 +10,49 @@
using Q = QskProgressRing; using Q = QskProgressRing;
namespace
{
inline bool qskIsContiguous( const QskProgressRing* ring )
{
return qFuzzyIsNull( ring->spacingHint( Q::Fill ) );
}
QskIntervalF fillInterval( const QskProgressIndicator* indicator )
{
qreal pos1, pos2;
if ( indicator->isIndeterminate() )
{
pos1 = pos2 = indicator->positionHint( QskProgressIndicator::Fill );
}
else
{
pos1 = indicator->valueAsRatio( indicator->origin() );
pos2 = indicator->valueAsRatio( indicator->value() );
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
}
inline QskArcMetrics fillAngles( const QskProgressRing* ring )
{
const auto intv = fillInterval( ring );
const auto metrics = ring->arcMetricsHint( Q::Fill );
if ( metrics.isNull() )
return {};
const auto startAngle = metrics.startAngle() + intv.lowerBound() * metrics.spanAngle();
const auto spanAngle = intv.upperBound() * metrics.spanAngle();
return QskArcMetrics( startAngle, spanAngle, 0 );
}
}
QskProgressRingSkinlet::QskProgressRingSkinlet( QskSkin* skin ) QskProgressRingSkinlet::QskProgressRingSkinlet( QskSkin* skin )
: Inherited( skin ) : Inherited( skin )
{ {
@ -32,7 +75,22 @@ QRectF QskProgressRingSkinlet::subControlRect(
QSGNode* QskProgressRingSkinlet::updateGrooveNode( QSGNode* QskProgressRingSkinlet::updateGrooveNode(
const QskProgressIndicator* indicator, QSGNode* node ) const const QskProgressIndicator* indicator, QSGNode* node ) const
{ {
return updateArcNode( indicator, node, Q::Groove ); const auto ring = static_cast< const Q* >( indicator );
if( qskIsContiguous( ring ) )
{
return updateArcNode( indicator, node, Q::Groove );
}
else
{
const auto angles = fillAngles( ring );
const auto spacing = ring->spacingHint( Q::Fill );
const auto sign = ( angles.spanAngle() > 0 ) ? 1 : -1;
const auto startAngle = angles.endAngle() + sign * spacing;
const auto spanAngle = sign * 360 - angles.spanAngle() - sign * 2 * spacing;
return updateArcNode( ring, node, startAngle, spanAngle, Q::Groove );
}
} }
QSGNode* QskProgressRingSkinlet::updateFillNode( QSGNode* QskProgressRingSkinlet::updateFillNode(
@ -67,10 +125,9 @@ QSGNode* QskProgressRingSkinlet::updateFillNode(
gradient.reverse(); gradient.reverse();
} }
const auto startAngle = metrics.startAngle() + intv.lowerBound() * metrics.spanAngle(); const auto angles = fillAngles( ring );
const auto spanAngle = intv.upperBound() * metrics.spanAngle();
return updateArcNode( ring, node, rect, gradient, startAngle, spanAngle, subControl ); return updateArcNode( ring, node, rect, gradient, angles.startAngle(), angles.spanAngle(), subControl );
} }
QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable, QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable,
@ -95,25 +152,4 @@ QSizeF QskProgressRingSkinlet::sizeHint( const QskSkinnable* skinnable,
return hint; return hint;
} }
QskIntervalF QskProgressRingSkinlet::fillInterval(
const QskProgressIndicator* indicator ) const
{
qreal pos1, pos2;
if ( indicator->isIndeterminate() )
{
pos1 = pos2 = indicator->positionHint( QskProgressIndicator::Fill );
}
else
{
pos1 = indicator->valueAsRatio( indicator->origin() );
pos2 = indicator->valueAsRatio( indicator->value() );
}
if ( pos1 > pos2 )
std::swap( pos1, pos2 );
return QskIntervalF( pos1, pos2 );
}
#include "moc_QskProgressRingSkinlet.cpp" #include "moc_QskProgressRingSkinlet.cpp"

View File

@ -29,8 +29,6 @@ class QSK_EXPORT QskProgressRingSkinlet : public QskProgressIndicatorSkinlet
protected: protected:
QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override; QSGNode* updateGrooveNode( const QskProgressIndicator*, QSGNode* ) const override;
QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override; QSGNode* updateFillNode( const QskProgressIndicator*, QSGNode* ) const override;
QskIntervalF fillInterval( const QskProgressIndicator* ) const;
}; };
#endif #endif