QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskSliderSkinlet.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskSliderSkinlet.h"
7#include "QskSlider.h"
8
9#include "QskAspect.h"
10#include "QskBoxBorderMetrics.h"
11#include "QskFunctions.h"
12
13#include <QFontMetricsF>
14#include <QtMath>
15
16using Q = QskSlider;
17
18namespace
19{
20 inline QRectF qskInnerPanelRect(
21 const QskSlider* slider, const QRectF& contentsRect )
22 {
23 #if 1
24 auto padding = slider->paddingHint( Q::Panel );
25 padding += slider->boxBorderMetricsHint( Q::Panel ).widths();
26
27 auto r = slider->subControlRect( contentsRect, Q::Panel );
28 r = r.marginsRemoved( padding );
29 #else
30 r = slider->subControlContentsRect( contentsRect, Q::Panel );
31 #endif
32
33 return r;
34 }
35
36 QRectF qskInnerValueRect( const QskSlider* slider, const QRectF& contentsRect )
37 {
38 // For M3 the stop indicators have some padding related to the groove (and fill),
39 // so we use the rect between first and last stop indicator as authoritative for
40 // indicators, handle etc.
41 const auto grooveIndicatorMargins = slider->paddingHint( Q::GrooveStopIndicators );
42 const auto r = qskInnerPanelRect( slider, contentsRect ).marginsRemoved( grooveIndicatorMargins );
43 return r;
44 }
45}
46
47QskSliderSkinlet::QskSliderSkinlet( QskSkin* skin )
48 : Inherited( skin )
49{
50 setNodeRoles( {
51 PanelRole,
52 GrooveRole,
53 FillRole,
54 FillStopIndicatorsRole,
55 GrooveStopIndicatorsRole,
56 HandleRole
57 } );
58}
59
60QskSliderSkinlet::~QskSliderSkinlet()
61{
62}
63
64QRectF QskSliderSkinlet::subControlRect( const QskSkinnable* skinnable,
65 const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
66{
67 const auto slider = static_cast< const QskSlider* >( skinnable );
68
69 if ( subControl == Q::Panel )
70 {
71 return panelRect( slider, contentsRect );
72 }
73
74 if ( subControl == Q::Groove )
75 {
76 return grooveRect( slider, contentsRect );
77 }
78
79 if ( subControl == Q::Fill )
80 {
81 return fillRect( slider, contentsRect );
82 }
83
84 if ( subControl == Q::Handle )
85 {
86 return handleRect( slider, contentsRect );
87 }
88
89 if ( subControl == Q::Scale )
90 {
91 return scaleRect( slider, contentsRect );
92 }
93
94 return Inherited::subControlRect( skinnable, contentsRect, subControl );
95}
96
97int QskSliderSkinlet::sampleCount( const QskSkinnable* skinnable,
98 QskAspect::Subcontrol subControl ) const
99{
100 const auto slider = static_cast< const QskSlider* >( skinnable );
101
102 if( slider->snap() )
103 {
104 const auto num = qCeil( slider->boundaryLength() / slider->stepSize() ) + 1;
105 return num;
106 }
107 else
108 {
109 return ( subControl == Q::GrooveStopIndicators ) ? 1 : 0;
110 }
111}
112
113QRectF QskSliderSkinlet::sampleRect(
114 const QskSkinnable* skinnable, const QRectF& contentsRect,
115 QskAspect::Subcontrol subControl, int index ) const
116{
117 const auto slider = static_cast< const QskSlider* >( skinnable );
118
119 auto r = qskInnerValueRect( slider, contentsRect );
120
121 const auto size = slider->strutSizeHint( subControl );
122
123 const auto filledPoints = qFloor( ( slider->value() - slider->minimum() ) / slider->stepSize() );
124
125 if( slider->snap())
126 {
127 if( slider->snap()
128 && ( ( index >= filledPoints && subControl == Q::FillStopIndicators )
129 || ( index < filledPoints && subControl == Q::GrooveStopIndicators ) ) )
130 {
131 return {};
132 }
133 }
134
135 const auto pos = slider->snap() ? slider->minimum() + index * slider->stepSize() : slider->maximum();
136
137 if( slider->orientation() == Qt::Horizontal )
138 {
139 r.setTop( r.center().y() - size.height() / 2 );
140 const auto x = r.left() + slider->valueAsRatio( pos ) * r.width() - size.width() / 2;
141 r.setLeft( x );
142 }
143 else
144 {
145 r.setLeft( r.center().x() - size.width() / 2 );
146 const auto y = r.bottom() - slider->valueAsRatio( pos ) * r.height() - size.height() / 2;
147 r.setTop( y );
148 }
149
150 r.setHeight( size.height() );
151 r.setWidth( size.width() );
152
153 return r;
154}
155
156QskAspect::States QskSliderSkinlet::sampleStates( const QskSkinnable*, QskAspect::Subcontrol, int ) const
157{
158 return {};
159}
160
161QSGNode* QskSliderSkinlet::updateSubNode(
162 const QskSkinnable* skinnable, quint8 nodeRole, QSGNode* node ) const
163{
164 const auto slider = static_cast< const QskSlider* >( skinnable );
165
166 switch ( nodeRole )
167 {
168 case PanelRole:
169 {
170 return updateBoxNode( slider, node, Q::Panel );
171 }
172
173 case GrooveRole:
174 {
175 return updateBoxNode( slider, node, Q::Groove );
176 }
177
178 case FillRole:
179 {
180 return updateBoxNode( slider, node, Q::Fill );
181 }
182
183 case GrooveStopIndicatorsRole:
184 {
185 return updateSeriesNode( slider, Q::GrooveStopIndicators, node );
186 }
187
188 case FillStopIndicatorsRole:
189 {
190 return updateSeriesNode( slider, Q::FillStopIndicators, node );
191 }
192
193 case HandleRole:
194 {
195 return updateBoxNode( slider, node, Q::Handle );
196 }
197 }
198
199 return Inherited::updateSubNode( skinnable, nodeRole, node );
200}
201
202QSGNode* QskSliderSkinlet::updateSampleNode( const QskSkinnable* skinnable,
203 QskAspect::Subcontrol subControl, int index, QSGNode* node ) const
204{
205 const auto slider = static_cast< const QskSlider* >( skinnable );
206 const auto rect = sampleRect( slider, slider->contentsRect(), subControl, index );
207
208 return updateBoxNode( skinnable, node, rect, subControl );
209}
210
211QRectF QskSliderSkinlet::panelRect(
212 const QskSlider* slider, const QRectF& contentsRect ) const
213{
214 auto r = contentsRect;
215
216 const qreal size = slider->metric( Q::Panel | QskAspect::Size ); // 0: no hint
217 if ( size > 0 && size < r.height() )
218 {
219 const auto alignment = slider->alignmentHint( Q::Panel );
220
221 if ( slider->orientation() == Qt::Horizontal )
222 r = qskAlignedRectF( r, r.width(), size, alignment & Qt::AlignVertical_Mask );
223 else
224 r = qskAlignedRectF( r, size, r.height(), alignment & Qt::AlignHorizontal_Mask );
225 }
226
227 return r;
228}
229
230QRectF QskSliderSkinlet::innerRect( const QskSlider* slider,
231 const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const
232{
233 auto r = qskInnerPanelRect( slider, contentsRect );
234
235 QskSkinHintStatus status;
236
237 const qreal extent = slider->metric( subControl | QskAspect::Size, &status );
238
239 if ( slider->orientation() == Qt::Horizontal )
240 {
241 if ( status.isValid() && ( extent < r.height() ) )
242 {
243 r.setTop( r.center().y() - 0.5 * extent );
244 r.setHeight( extent );
245 }
246 }
247 else
248 {
249 if ( status.isValid() && ( extent < r.width() ) )
250 {
251 r.setLeft( r.center().x() - 0.5 * extent );
252 r.setWidth( extent );
253 }
254 }
255
256 return r;
257}
258
259QRectF QskSliderSkinlet::grooveRect(
260 const QskSlider* slider, const QRectF& contentsRect ) const
261{
262 const auto r = qskInnerPanelRect( slider, contentsRect );
263 auto grooveRect = innerRect( slider, contentsRect, Q::Groove );
264 const auto handleRect = slider->subControlRect( Q::Handle );
265
266 if ( slider->orientation() == Qt::Horizontal )
267 {
268 grooveRect.setLeft( handleRect.right() );
269 grooveRect.setRight( r.right() );
270 }
271 else
272 {
273 grooveRect.setBottom( handleRect.top() );
274 grooveRect.setTop( r.top() );
275 }
276
277 return grooveRect;
278}
279
280QRectF QskSliderSkinlet::scaleRect(
281 const QskSlider* slider, const QRectF& rect ) const
282{
283 return innerRect( slider, rect, Q::Groove );
284}
285
286QRectF QskSliderSkinlet::fillRect(
287 const QskSlider* slider, const QRectF& contentsRect ) const
288{
289 const auto r = qskInnerPanelRect( slider, contentsRect );
290 const auto handleRect = slider->subControlRect( Q::Handle );
291
292 auto fillRect = innerRect( slider, contentsRect, Q::Fill );
293 if ( slider->orientation() == Qt::Horizontal )
294 {
295 fillRect.setLeft( r.left() );
296 fillRect.setRight( handleRect.left() );
297 }
298 else
299 {
300 fillRect.setBottom( r.bottom() );
301 fillRect.setTop( handleRect.bottom() );
302 }
303
304 return fillRect;
305}
306
307QRectF QskSliderSkinlet::handleRect(
308 const QskSlider* slider, const QRectF& contentsRect ) const
309{
310 auto handleSize = slider->strutSizeHint( Q::Handle );
311 const auto pos = qBound( 0.0, slider->handlePosition(), 1.0 );
312
313 const auto r = qskInnerValueRect( slider, contentsRect );
314 auto center = r.center();
315
316 if ( slider->orientation() == Qt::Horizontal )
317 {
318 if ( handleSize.height() < 0.0 )
319 handleSize.setHeight( r.height() );
320
321 if ( handleSize.width() < 0.0 )
322 handleSize.setWidth( handleSize.height() );
323
324 center.setX( r.left() + pos * r.width() );
325 }
326 else
327 {
328 if ( handleSize.width() < 0.0 )
329 handleSize.setWidth( r.width() );
330
331 if ( handleSize.height() < 0.0 )
332 handleSize.setHeight( handleSize.width() );
333
334 center.setY( r.bottom() - pos * r.height() );
335 }
336
337 QRectF handleRect( 0, 0, handleSize.width(), handleSize.height() );
338 handleRect.moveCenter( center );
339
340 handleRect = handleRect.marginsRemoved( slider->marginHint( Q::Handle ) );
341
342 return handleRect;
343}
344
345QSizeF QskSliderSkinlet::sizeHint( const QskSkinnable* skinnable,
346 Qt::SizeHint which, const QSizeF& ) const
347{
348 if ( which != Qt::PreferredSize )
349 return QSizeF();
350
351 const auto panelHint = skinnable->strutSizeHint( Q::Panel );
352 const auto grooveHint = skinnable->strutSizeHint( Q::Groove );
353 const auto fillHint = skinnable->strutSizeHint( Q::Fill );
354 const auto handleHint = skinnable->strutSizeHint( Q::Handle );
355
356 auto hint = panelHint;
357 hint = hint.expandedTo( grooveHint );
358 hint = hint.expandedTo( fillHint );
359 hint = hint.expandedTo( handleHint );
360
361 return hint;
362}
363
364#include "moc_QskSliderSkinlet.cpp"
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
QRectF subControlRect(QskAspect::Subcontrol) const
QRectF subControlContentsRect(QskAspect::Subcontrol) const
QRectF contentsRect() const
bool isValid() const
QMarginsF paddingHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a padding hint.
QMarginsF marginHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a margin hint.
QSizeF strutSizeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a strut size hint.
QskBoxBorderMetrics boxBorderMetricsHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a border hint.
qreal metric(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a metric hint.
Qt::Alignment alignmentHint(QskAspect, Qt::Alignment=Qt::Alignment()) const
Retrieves an alignment hint.