QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskProgressBarSkinlet.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskProgressBarSkinlet.h"
7#include "QskProgressBar.h"
8#include "QskIntervalF.h"
9#include "QskBoxBorderMetrics.h"
10
11#include <qeasingcurve.h>
12#include <cmath>
13
14using Q = QskProgressBar;
15
16namespace
17{
18 QskIntervalF qskFillInterval( const QskProgressIndicator* indicator )
19 {
20 qreal pos1, pos2;
21
22 if ( indicator->isIndeterminate() )
23 {
24 const auto pos = indicator->positionHint( QskProgressIndicator::Fill );
25
26 static const QEasingCurve curve( QEasingCurve::InOutCubic );
27
28 const qreal off = 0.15;
29
30 pos1 = curve.valueForProgress( qMax( pos - off, 0.0 ) );
31 pos2 = curve.valueForProgress( qMin( pos + off, 1.0 ) );
32 }
33 else
34 {
35 pos1 = indicator->valueAsRatio( indicator->origin() );
36 pos2 = indicator->valueAsRatio( indicator->value() );
37 }
38
39 auto bar = static_cast< const QskProgressBar* >( indicator );
40 if( bar->orientation() == Qt::Horizontal )
41 {
42 if ( bar->layoutMirroring() )
43 {
44 pos1 = 1.0 - pos1;
45 pos2 = 1.0 - pos2;
46 }
47 }
48
49 if ( pos1 > pos2 )
50 std::swap( pos1, pos2 );
51
52 return QskIntervalF( pos1, pos2 );
53 }
54}
55
56QskProgressBarSkinlet::QskProgressBarSkinlet( QskSkin* skin )
57 : Inherited( skin )
58{
59}
60
61QskProgressBarSkinlet::~QskProgressBarSkinlet()
62{
63}
64
65QRectF QskProgressBarSkinlet::subControlRect(
66 const QskSkinnable* skinnable, const QRectF& contentsRect,
67 QskAspect::Subcontrol subControl ) const
68{
69 const auto bar = static_cast< const Q* >( skinnable );
70
71 if( subControl == Q::Groove )
72 {
73 const auto grooveSize = bar->metric( Q::Groove | QskAspect::Size );
74
75 auto rect = contentsRect;
76 if ( bar->orientation() == Qt::Horizontal )
77 {
78 rect.setY( rect.y() + 0.5 * ( rect.height() - grooveSize ) );
79 rect.setHeight( grooveSize );
80 }
81 else
82 {
83 rect.setX( rect.x() + 0.5 * ( rect.width() - grooveSize ) );
84 rect.setWidth( grooveSize );
85 }
86
87 return rect;
88 }
89
90 if( subControl == Q::Fill )
91 {
92 return barRect( bar );
93 }
94
95 return Inherited::subControlRect( skinnable, contentsRect, subControl );
96}
97
98QSGNode* QskProgressBarSkinlet::updateGrooveNode(
99 const QskProgressIndicator* indicator, QSGNode* node ) const
100{
101 return updateBoxNode( indicator, node, Q::Groove );
102}
103
104QSGNode* QskProgressBarSkinlet::updateFillNode(
105 const QskProgressIndicator* indicator, QSGNode* node ) const
106{
107 const auto bar = static_cast< const Q* >( indicator );
108
109 const auto subControl = Q::Fill;
110
111 const auto rect = indicator->subControlRect( subControl );
112 if ( rect.isEmpty() )
113 return nullptr;
114
115 auto gradient = indicator->gradientHint( subControl );
116 if ( !gradient.isVisible() )
117 return nullptr;
118
119 if ( ( gradient.type() == QskGradient::Stops ) && !gradient.isMonochrome() )
120 {
121 /*
122 When having stops only we use a linear gradient,
123 where the colors are increasing in direction of the
124 progress value. We interprete the gradient as a
125 definition for the 100% situation and have to adjust
126 the stops for smaller bars.
127
128 For this situation it would be more convenient to
129 adjust the start/stop positions, but the box renderer is
130 not supporting this yet. TODO ...
131 */
132
133 const auto intv = qskFillInterval( bar );
134
135 const auto stops = qskExtractedGradientStops( gradient.stops(),
136 intv.lowerBound(), intv.upperBound() );
137
138 gradient.setStops( stops );
139
140 gradient.setLinearDirection( static_cast< Qt::Orientation >( bar->orientation() ) );
141
142 if ( bar->orientation() == Qt::Vertical || bar->layoutMirroring() )
143 gradient.reverse();
144 }
145
146 return updateBoxNode( indicator, node, rect, gradient, subControl );
147}
148
149QRectF QskProgressBarSkinlet::barRect( const Q* bar ) const
150{
151 const auto subControl = Q::Groove;
152
153 const auto barSize = bar->metric( Q::Fill | QskAspect::Size );
154 auto rect = bar->subControlRect( subControl );
155
156 if ( bar->orientation() == Qt::Horizontal )
157 {
158 rect.setY( rect.y() + 0.5 * ( rect.height() - barSize ) );
159 rect.setHeight( barSize );
160 }
161 else
162 {
163 rect.setX( rect.x() + 0.5 * ( rect.width() - barSize ) );
164 rect.setWidth( barSize );
165 }
166
167 const auto borderMetrics = bar->boxBorderMetricsHint( subControl );
168
169 auto m = bar->paddingHint( subControl );
170 m += 0.5 * borderMetrics.toAbsolute( rect.size() ).widths();
171
172 rect = rect.marginsRemoved( m );
173
174 const auto intv = qskFillInterval( bar );
175
176 if( bar->orientation() == Qt::Horizontal )
177 {
178 const auto w = rect.width();
179
180 rect.setRight( rect.left() + intv.upperBound() * w );
181 rect.setLeft( rect.left() + intv.lowerBound() * w );
182 }
183 else
184 {
185 const auto h = rect.height();
186
187 rect.setTop( rect.bottom() - h * intv.upperBound() );
188 rect.setBottom( rect.bottom() - h * intv.lowerBound() );
189 }
190
191 return rect;
192}
193
194QSizeF QskProgressBarSkinlet::sizeHint( const QskSkinnable* skinnable,
195 Qt::SizeHint which, const QSizeF& ) const
196{
197 if ( which != Qt::PreferredSize )
198 return QSizeF();
199
200 const auto bar = static_cast< const Q* >( skinnable );
201
202 const auto extent = bar->extent();
203
204 if ( bar->orientation() == Qt::Horizontal )
205 return QSizeF( -1, extent );
206 else
207 return QSizeF( extent, -1 );
208}
209
210#include "moc_QskProgressBarSkinlet.cpp"
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
QRectF subControlRect(QskAspect::Subcontrol) const
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
QskGradient gradientHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint as gradient.
QskBoxBorderMetrics boxBorderMetricsHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a border hint.
qreal metric(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a metric hint.