2020-07-31 14:57:22 +00:00
|
|
|
/******************************************************************************
|
2024-01-17 13:31:45 +00:00
|
|
|
* QSkinny - Copyright (C) The authors
|
2023-04-06 07:23:37 +00:00
|
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
2020-07-31 14:57:22 +00:00
|
|
|
*****************************************************************************/
|
|
|
|
|
2020-08-01 15:51:45 +00:00
|
|
|
#include "QskProgressBarSkinlet.h"
|
|
|
|
#include "QskProgressBar.h"
|
2020-08-03 06:02:13 +00:00
|
|
|
#include "QskIntervalF.h"
|
2020-08-06 07:28:18 +00:00
|
|
|
#include "QskBoxBorderMetrics.h"
|
2020-07-31 14:57:22 +00:00
|
|
|
|
2020-08-09 08:49:32 +00:00
|
|
|
#include <qeasingcurve.h>
|
2020-07-31 14:57:22 +00:00
|
|
|
#include <cmath>
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
using Q = QskProgressBar;
|
2020-08-09 08:49:32 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
namespace
|
|
|
|
{
|
2024-09-04 15:08:40 +00:00
|
|
|
QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
|
2020-08-09 08:49:32 +00:00
|
|
|
{
|
2023-07-25 06:56:21 +00:00
|
|
|
qreal pos1, pos2;
|
2020-08-09 08:49:32 +00:00
|
|
|
|
2024-09-04 15:08:40 +00:00
|
|
|
if ( indicator->isIndeterminate() )
|
2023-07-25 06:56:21 +00:00
|
|
|
{
|
2024-09-04 15:08:40 +00:00
|
|
|
const auto pos = indicator->positionHint( QskProgressIndicator::Fill );
|
2020-08-09 08:49:32 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
static const QEasingCurve curve( QEasingCurve::InOutCubic );
|
2020-08-09 08:49:32 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
const qreal off = 0.15;
|
2020-08-03 06:02:13 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
pos1 = curve.valueForProgress( qMax( pos - off, 0.0 ) );
|
|
|
|
pos2 = curve.valueForProgress( qMin( pos + off, 1.0 ) );
|
|
|
|
}
|
|
|
|
else
|
2020-08-03 06:02:13 +00:00
|
|
|
{
|
2024-09-04 15:08:40 +00:00
|
|
|
pos1 = indicator->valueAsRatio( indicator->origin() );
|
|
|
|
pos2 = indicator->valueAsRatio( indicator->value() );
|
2023-07-25 06:56:21 +00:00
|
|
|
}
|
|
|
|
|
2024-09-04 15:08:40 +00:00
|
|
|
auto bar = static_cast< const QskProgressBar* >( indicator );
|
2023-07-25 06:56:21 +00:00
|
|
|
if( bar->orientation() == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
if ( bar->layoutMirroring() )
|
|
|
|
{
|
|
|
|
pos1 = 1.0 - pos1;
|
|
|
|
pos2 = 1.0 - pos2;
|
|
|
|
}
|
2020-08-03 06:02:13 +00:00
|
|
|
}
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
if ( pos1 > pos2 )
|
|
|
|
std::swap( pos1, pos2 );
|
2020-08-03 06:02:13 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
return QskIntervalF( pos1, pos2 );
|
|
|
|
}
|
2020-08-03 06:02:13 +00:00
|
|
|
}
|
|
|
|
|
2020-08-01 15:51:45 +00:00
|
|
|
QskProgressBarSkinlet::QskProgressBarSkinlet( QskSkin* skin )
|
2023-07-25 06:56:21 +00:00
|
|
|
: Inherited( skin )
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-08-01 15:51:45 +00:00
|
|
|
QskProgressBarSkinlet::~QskProgressBarSkinlet()
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2020-08-01 15:51:45 +00:00
|
|
|
QRectF QskProgressBarSkinlet::subControlRect(
|
2020-07-31 14:57:22 +00:00
|
|
|
const QskSkinnable* skinnable, const QRectF& contentsRect,
|
|
|
|
QskAspect::Subcontrol subControl ) const
|
|
|
|
{
|
2023-06-02 13:14:13 +00:00
|
|
|
const auto bar = static_cast< const Q* >( skinnable );
|
2020-07-31 14:57:22 +00:00
|
|
|
|
2023-06-02 13:14:13 +00:00
|
|
|
if( subControl == Q::Groove )
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
2023-06-02 13:14:13 +00:00
|
|
|
const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size );
|
2020-08-09 09:50:34 +00:00
|
|
|
|
2020-07-31 14:57:22 +00:00
|
|
|
auto rect = contentsRect;
|
|
|
|
if ( bar->orientation() == Qt::Horizontal )
|
|
|
|
{
|
2023-06-02 13:14:13 +00:00
|
|
|
rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) );
|
|
|
|
rect.setHeight( grooveSize );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-06-02 13:14:13 +00:00
|
|
|
rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) );
|
|
|
|
rect.setWidth( grooveSize );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
if( subControl == Q::Fill )
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
2020-08-03 06:02:13 +00:00
|
|
|
return barRect( bar );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Inherited::subControlRect( skinnable, contentsRect, subControl );
|
|
|
|
}
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
QSGNode* QskProgressBarSkinlet::updateGrooveNode(
|
|
|
|
const QskProgressIndicator* indicator, QSGNode* node ) const
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
2023-07-25 06:56:21 +00:00
|
|
|
return updateBoxNode( indicator, node, Q::Groove );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
QSGNode* QskProgressBarSkinlet::updateFillNode(
|
|
|
|
const QskProgressIndicator* indicator, QSGNode* node ) const
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
2023-07-25 06:56:21 +00:00
|
|
|
const auto bar = static_cast< const Q* >( indicator );
|
|
|
|
|
|
|
|
const auto subControl = Q::Fill;
|
2020-07-31 14:57:22 +00:00
|
|
|
|
2024-09-04 15:08:40 +00:00
|
|
|
const auto rect = indicator->subControlRect( subControl );
|
2020-07-31 14:57:22 +00:00
|
|
|
if ( rect.isEmpty() )
|
|
|
|
return nullptr;
|
2020-08-09 09:50:34 +00:00
|
|
|
|
2024-09-04 15:08:40 +00:00
|
|
|
auto gradient = indicator->gradientHint( subControl );
|
2020-07-31 14:57:22 +00:00
|
|
|
if ( !gradient.isVisible() )
|
|
|
|
return nullptr;
|
|
|
|
|
2022-10-31 13:42:08 +00:00
|
|
|
if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() )
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
2022-10-31 13:42:08 +00:00
|
|
|
/*
|
|
|
|
When having stops only we use a linear gradient,
|
|
|
|
where the colors are increasing in direction of the
|
|
|
|
progress value. We interprete the gradient as a
|
|
|
|
definition for the 100% situation and have to adjust
|
|
|
|
the stops for smaller bars.
|
|
|
|
|
2023-02-28 14:49:42 +00:00
|
|
|
For this situation it would be more convenient to
|
2022-10-31 13:42:08 +00:00
|
|
|
adjust the start/stop positions, but the box renderer is
|
|
|
|
not supporting this yet. TODO ...
|
|
|
|
*/
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
const auto intv = qskFillInterval( bar );
|
2020-07-31 14:57:22 +00:00
|
|
|
|
2022-11-13 16:22:09 +00:00
|
|
|
const auto stops = qskExtractedGradientStops( gradient.stops(),
|
2022-10-31 13:42:08 +00:00
|
|
|
intv.lowerBound(), intv.upperBound() );
|
|
|
|
|
2022-11-13 16:22:09 +00:00
|
|
|
gradient.setStops( stops );
|
2023-07-25 06:56:21 +00:00
|
|
|
|
|
|
|
gradient.setLinearDirection( static_cast< Qt::Orientation >( bar->orientation() ) );
|
|
|
|
|
2020-08-03 06:02:13 +00:00
|
|
|
if ( bar->orientation() == Qt::Vertical || bar->layoutMirroring() )
|
2020-07-31 14:57:22 +00:00
|
|
|
gradient.reverse();
|
|
|
|
}
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
return updateBoxNode( indicator, node, rect, gradient, subControl );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
QRectF QskProgressBarSkinlet::barRect( const Q* bar ) const
|
2020-07-31 14:57:22 +00:00
|
|
|
{
|
2023-06-02 13:14:13 +00:00
|
|
|
const auto subControl = Q::Groove;
|
2020-08-06 07:28:18 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
const auto barSize = bar->metric( Q::Fill | QskAspect::Size );
|
2020-08-06 07:28:18 +00:00
|
|
|
auto rect = bar->subControlRect( subControl );
|
|
|
|
|
2023-06-02 13:14:13 +00:00
|
|
|
if ( bar->orientation() == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
rect.setY( rect.y() + 0.5 * ( rect.height() - barSize ) );
|
|
|
|
rect.setHeight( barSize );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rect.setX( rect.x() + 0.5 * ( rect.width() - barSize ) );
|
|
|
|
rect.setWidth( barSize );
|
|
|
|
}
|
|
|
|
|
2020-08-06 07:28:18 +00:00
|
|
|
const auto borderMetrics = bar->boxBorderMetricsHint( subControl );
|
|
|
|
|
2020-12-15 06:21:12 +00:00
|
|
|
auto m = bar->paddingHint( subControl );
|
2020-08-06 07:28:18 +00:00
|
|
|
m += 0.5 * borderMetrics.toAbsolute( rect.size() ).widths();
|
|
|
|
|
|
|
|
rect = rect.marginsRemoved( m );
|
2020-07-31 14:57:22 +00:00
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
const auto intv = qskFillInterval( bar );
|
2020-07-31 14:57:22 +00:00
|
|
|
|
|
|
|
if( bar->orientation() == Qt::Horizontal )
|
|
|
|
{
|
|
|
|
const auto w = rect.width();
|
|
|
|
|
2020-08-03 06:02:13 +00:00
|
|
|
rect.setRight( rect.left() + intv.upperBound() * w );
|
|
|
|
rect.setLeft( rect.left() + intv.lowerBound() * w );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
const auto h = rect.height();
|
|
|
|
|
2020-08-03 06:02:13 +00:00
|
|
|
rect.setTop( rect.bottom() - h * intv.upperBound() );
|
|
|
|
rect.setBottom( rect.bottom() - h * intv.lowerBound() );
|
2020-07-31 14:57:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2020-12-29 08:45:00 +00:00
|
|
|
QSizeF QskProgressBarSkinlet::sizeHint( const QskSkinnable* skinnable,
|
|
|
|
Qt::SizeHint which, const QSizeF& ) const
|
|
|
|
{
|
|
|
|
if ( which != Qt::PreferredSize )
|
|
|
|
return QSizeF();
|
|
|
|
|
2023-07-25 06:56:21 +00:00
|
|
|
const auto bar = static_cast< const Q* >( skinnable );
|
2020-12-29 08:45:00 +00:00
|
|
|
|
|
|
|
const auto extent = bar->extent();
|
|
|
|
|
|
|
|
if ( bar->orientation() == Qt::Horizontal )
|
|
|
|
return QSizeF( -1, extent );
|
|
|
|
else
|
|
|
|
return QSizeF( extent, -1 );
|
|
|
|
}
|
|
|
|
|
2020-08-01 15:51:45 +00:00
|
|
|
#include "moc_QskProgressBarSkinlet.cpp"
|