QSkinny 0.8.0
C++/Qt UI toolkit
Loading...
Searching...
No Matches
QskSkinlet.cpp
1/******************************************************************************
2 * QSkinny - Copyright (C) The authors
3 * SPDX-License-Identifier: BSD-3-Clause
4 *****************************************************************************/
5
6#include "QskSkinlet.h"
7
8#include "QskArcNode.h"
9#include "QskAspect.h"
10#include "QskArcMetrics.h"
11#include "QskBoxBorderColors.h"
12#include "QskBoxBorderMetrics.h"
13#include "QskBoxNode.h"
14#include "QskBoxClipNode.h"
15#include "QskBoxRectangleNode.h"
16#include "QskBoxShapeMetrics.h"
17#include "QskBoxHints.h"
18#include "QskColorFilter.h"
19#include "QskControl.h"
20#include "QskFunctions.h"
21#include "QskGradient.h"
22#include "QskGraphicNode.h"
23#include "QskGraphic.h"
24#include "QskLinesNode.h"
25#include "QskSGNode.h"
26#include "QskStippleMetrics.h"
27#include "QskTextColors.h"
28#include "QskTextNode.h"
29#include "QskTextOptions.h"
30#include "QskSkinStateChanger.h"
31#include "QskTextureRenderer.h"
32#include "QskSetup.h"
33
34#include <qquickwindow.h>
35#include <qsgsimplerectnode.h>
36
37static inline QRectF qskSceneAlignedRect( const QQuickItem* item, const QRectF& rect )
38{
39 const auto transform = item->itemTransform( nullptr, nullptr );
40 if ( transform.type() > QTransform::TxTranslate )
41 return rect;
42
43 /*
44 Aligning rect according to scene coordinates, so that
45 we don't run into rounding issues downstream, where values
46 will be floored/ceiled ending up with a slightly different
47 aspect ratio.
48 */
49
50 const auto ratio = item->window()->devicePixelRatio();
51
52 const auto pos = transform.map( rect.topLeft() ) * ratio;
53 const auto size = rect.size() * ratio;
54
55 const qreal x = qRound( pos.x() ) / ratio;
56 const qreal y = qRound( pos.y() ) / ratio;
57 const qreal w = qRound( size.width() ) / ratio;
58 const qreal h = qRound( size.height() ) / ratio;
59
60 return QRectF( item->mapFromScene( QPointF( x, y ) ), QSizeF( w, h ) );
61}
62
63static inline QRectF qskSubControlRect( const QskSkinlet* skinlet,
64 const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
65{
66 if ( auto control = skinnable->controlCast() )
67 {
68 const auto r = control->contentsRect();
69 return skinlet->subControlRect( skinnable, r, subControl );
70 }
71
72 return QRectF();
73}
74
75static inline QSGNode* qskUpdateTextNode( const QskSkinnable* skinnable,
76 QSGNode* node, const QRectF& rect, Qt::Alignment alignment,
77 const QString& text, const QFont& font, const QskTextOptions& textOptions,
78 const QskTextColors& textColors, Qsk::TextStyle textStyle )
79{
80 if ( text.isEmpty() || rect.isEmpty() )
81 return nullptr;
82
83 auto textNode = static_cast< QskTextNode* >( node );
84 if ( textNode == nullptr )
85 textNode = new QskTextNode();
86
87 auto effectiveFont = font;
88 switch ( textOptions.fontSizeMode() )
89 {
90 case QskTextOptions::FixedSize:
91 break;
92
93 case QskTextOptions::HorizontalFit:
94 Q_UNIMPLEMENTED();
95 break;
96
97 case QskTextOptions::VerticalFit:
98 effectiveFont.setPixelSize( static_cast< int >( rect.height() * 0.5 ) );
99 break;
100
101 case QskTextOptions::Fit:
102 Q_UNIMPLEMENTED();
103 break;
104 }
105
106 textNode->setTextData( skinnable->owningItem(),
107 text, rect, effectiveFont, textOptions, textColors, alignment, textStyle );
108
109 return textNode;
110}
111
112static inline QSGNode* qskUpdateGraphicNode(
113 const QskSkinnable* skinnable, QSGNode* node,
114 const QskGraphic& graphic, const QskColorFilter& colorFilter,
115 const QRectF& rect, Qt::Orientations mirrored )
116{
117 if ( rect.isEmpty() )
118 return nullptr;
119
120 const auto item = skinnable->owningItem();
121 if ( item == nullptr )
122 return nullptr;
123
124 auto graphicNode = static_cast< QskGraphicNode* >( node );
125 if ( graphicNode == nullptr )
126 graphicNode = new QskGraphicNode();
127
128 const auto flag = QskItem::PreferRasterForTextures;
129
130 bool useRaster = QskSetup::testUpdateFlag( flag );
131 if ( auto qItem = qobject_cast< const QskItem* >( item ) )
132 useRaster = qItem->testUpdateFlag( flag );
133
134 graphicNode->setRenderHint( useRaster ? QskPaintedNode::Raster : QskPaintedNode::OpenGL );
135
136 graphicNode->setMirrored( mirrored );
137
138 const auto r = qskSceneAlignedRect( item, rect );
139 graphicNode->setGraphic( item->window(), graphic, colorFilter, r );
140
141 return graphicNode;
142}
143
144static inline bool qskIsShadowVisible( const QskShadowMetrics& shadowMetrics,
145 const QColor& shadowColor )
146{
147 return !shadowMetrics.isNull() && shadowColor.isValid() && ( shadowColor.alpha() > 0 );
148}
149
150static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics,
151 const QskBoxBorderColors& borderColors, const QskGradient& gradient )
152{
153 if ( gradient.isVisible() )
154 return true;
155
156 return !borderMetrics.isNull() && borderColors.isVisible();
157}
158
159static inline bool qskIsArcVisible( const QskArcMetrics& arcMetrics,
160 qreal borderWidth, const QColor borderColor, const QskGradient& gradient )
161{
162 if ( arcMetrics.isNull() )
163 return false;
164
165 if ( borderWidth > 0.0 && borderColor.isValid() && borderColor.alpha() > 0 )
166 return true;
167
168 return gradient.isVisible();
169}
170
171static inline bool qskIsLineVisible( const QColor& lineColor, qreal lineWidth )
172{
173 return ( lineWidth > 0.0 ) && lineColor.isValid() && ( lineColor.alpha() > 0 );
174}
175
176static inline QskTextColors qskTextColors(
177 const QskSkinnable* skinnable, QskAspect::Subcontrol subControl )
178{
179 /*
180 Would be more efficient to have QskTextColors hints instead of
181 storing the colors as seperated hints. TODO ...
182 */
183
184 QskSkinHintStatus status;
185
187 c.textColor = skinnable->color( subControl, &status );
188#if 1
189 if ( !status.isValid() )
190 c.textColor = skinnable->color( subControl | QskAspect::TextColor );
191#endif
192
193 c.styleColor = skinnable->color( subControl | QskAspect::StyleColor );
194 c.linkColor = skinnable->color( subControl | QskAspect::LinkColor );
195
196 return c;
197}
198
199static inline QQuickWindow* qskWindowOfSkinnable( const QskSkinnable* skinnable )
200{
201 if ( auto item = skinnable->owningItem() )
202 return item->window();
203
204 return nullptr;
205}
206
207static inline QSGNode* qskUpdateBoxNode(
208 const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect,
209 const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
210 const QskBoxBorderColors& borderColors, const QskGradient& gradient,
211 const QskShadowMetrics& shadowMetrics, const QColor& shadowColor )
212{
213 if ( !rect.isEmpty() )
214 {
215 if ( qskIsBoxVisible( borderMetrics, borderColors, gradient )
216 || qskIsShadowVisible( shadowMetrics, shadowColor ) )
217 {
218 if ( auto window = qskWindowOfSkinnable( skinnable ) )
219 {
220 auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
221 boxNode->updateNode( window, rect, shape, borderMetrics,
222 borderColors, gradient, shadowMetrics, shadowColor );
223
224 return boxNode;
225 }
226 }
227 }
228
229 return nullptr;
230}
231
232static inline QSGNode* qskUpdateArcNode(
233 const QskSkinnable*, QSGNode* node, const QRectF& rect,
234 qreal borderWidth, const QColor borderColor,
235 const QskGradient& gradient, const QskArcMetrics& metrics )
236{
237 if ( rect.isEmpty() )
238 return nullptr;
239
240 if ( !qskIsArcVisible( metrics, borderWidth, borderColor, gradient ) )
241 return nullptr;
242
243 auto arcNode = QskSGNode::ensureNode< QskArcNode >( node );
244 arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient );
245
246 return arcNode;
247}
248
249static inline QSGNode* qskUpdateLineNode(
250 const QskSkinnable*, QSGNode* node, const QColor& lineColor,
251 qreal lineWidth, QskStippleMetrics& lineStipple, const QLineF& line )
252{
253 if ( line.isNull() )
254 return nullptr;
255
256 if ( !qskIsLineVisible( lineColor, lineWidth ) )
257 return nullptr;
258
259 auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node );
260 linesNode->updateLine( lineColor, lineWidth, lineStipple,
261 QTransform(), line.p1(), line.p2() );
262
263 return linesNode;
264}
265
266static inline QSGNode* qskUpdateLinesNode(
267 const QskSkinnable*, QSGNode* node, const QColor& lineColor,
268 qreal lineWidth, QskStippleMetrics& lineStipple, const QVector< QLineF >& lines )
269{
270 if ( lines.isEmpty() )
271 return nullptr;
272
273 if ( !qskIsLineVisible( lineColor, lineWidth ) )
274 return nullptr;
275
276 auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node );
277 linesNode->updateLines( lineColor, lineWidth, lineStipple,
278 QTransform(), lines );
279
280 return linesNode;
281}
282
283class QskSkinlet::PrivateData
284{
285 public:
286 PrivateData( QskSkin* skin )
287 : skin( skin )
288 , ownedBySkinnable( false )
289 {
290 }
291
292 QskSkin* skin;
293 QVector< quint8 > nodeRoles;
294
295 bool ownedBySkinnable : 1;
296};
297
298QskSkinlet::QskSkinlet( QskSkin* skin )
299 : m_data( new PrivateData( skin ) )
300{
301}
302
303QskSkinlet::~QskSkinlet()
304{
305}
306
307QskSkin* QskSkinlet::skin() const
308{
309 return m_data->skin;
310}
311
312void QskSkinlet::setOwnedBySkinnable( bool on )
313{
314 m_data->ownedBySkinnable = on;
315}
316
317bool QskSkinlet::isOwnedBySkinnable() const
318{
319 return m_data->ownedBySkinnable;
320}
321
322void QskSkinlet::setNodeRoles( const QVector< quint8 >& nodeRoles )
323{
324 m_data->nodeRoles = nodeRoles;
325}
326
327void QskSkinlet::appendNodeRoles( const QVector< quint8 >& nodeRoles )
328{
329 m_data->nodeRoles += nodeRoles;
330}
331
332const QVector< quint8 >& QskSkinlet::nodeRoles() const
333{
334 return m_data->nodeRoles;
335}
336
337void QskSkinlet::updateNode( QskSkinnable* skinnable, QSGNode* parentNode ) const
338{
339 using namespace QskSGNode;
340
341 QSGNode* oldNode;
342 QSGNode* newNode;
343
344 if ( const auto control = skinnable->controlCast() )
345 {
346 // background
347
348 oldNode = findChildNode( parentNode, BackgroundRole );
349 newNode = updateBackgroundNode( control, oldNode );
350
351 replaceChildNode( BackgroundRole, parentNode, oldNode, newNode );
352
353 // debug
354
355 oldNode = findChildNode( parentNode, DebugRole );
356
357 newNode = nullptr;
358 if ( control->testUpdateFlag( QskItem::DebugForceBackground ) )
359 newNode = updateDebugNode( control, oldNode );
360
361 replaceChildNode( DebugRole, parentNode, oldNode, newNode );
362 }
363
364 for ( const auto nodeRole : std::as_const( m_data->nodeRoles ) )
365 {
366 Q_ASSERT( nodeRole < FirstReservedRole );
367
368 oldNode = QskSGNode::findChildNode( parentNode, nodeRole );
369 newNode = updateSubNode( skinnable, nodeRole, oldNode );
370
371 replaceChildNode( nodeRole, parentNode, oldNode, newNode );
372 }
373}
374
375QSGNode* QskSkinlet::updateBackgroundNode(
376 const QskControl* control, QSGNode* node ) const
377{
378 const auto rect = control->rect();
379 if ( rect.isEmpty() )
380 return nullptr;
381
382 const auto gradient = control->background();
383 if ( !gradient.isVisible() )
384 return nullptr;
385
386 auto rectNode = QskSGNode::ensureNode< QskBoxRectangleNode >( node );
387 rectNode->updateFilling( control->window(), rect, gradient );
388
389 return rectNode;
390}
391
392QSGNode* QskSkinlet::updateDebugNode(
393 const QskControl* control, QSGNode* node ) const
394{
395 if ( control->size().isEmpty() )
396 return nullptr;
397
398 auto rectNode = static_cast< QSGSimpleRectNode* >( node );
399 if ( rectNode == nullptr )
400 {
401 rectNode = new QSGSimpleRectNode();
402
403 QColor color;
404 if ( control->inherits( "QskFocusIndicator" ) )
405 {
406 color = QColor( Qt::gray );
407 color.setAlpha( 60 );
408 }
409 else
410 {
411 static int idx = 0;
412 idx = ( idx + 3 ) % 14;
413
414 // maybe using something random based on web colors ???
415 color = QColor( Qt::GlobalColor( 4 + idx ) );
416 color.setAlpha( 200 );
417 }
418
419 rectNode->setColor( color );
420 }
421
422 const auto r = control->rect();
423 if ( rectNode->rect() != r )
424 rectNode->setRect( r );
425
426 return rectNode;
427}
428
429void QskSkinlet::replaceChildNode( quint8 role,
430 QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode ) const
431{
432 QskSGNode::replaceChildNode(
433 m_data->nodeRoles, role, parentNode, oldNode, newNode );
434}
435
436QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable,
437 QSGNode* node, QskAspect::Subcontrol subControl ) const
438{
439 const auto rect = qskSubControlRect( this, skinnable, subControl );
440 return updateBoxNode( skinnable, node, rect, subControl );
441}
442
443QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable,
444 QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl )
445{
446 const auto fillGradient = skinnable->gradientHint( subControl );
447 return updateBoxNode( skinnable, node, rect, fillGradient, subControl );
448}
449
450QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable,
451 QSGNode* node, const QRectF& rect, const QskGradient& fillGradient,
452 QskAspect::Subcontrol subControl )
453{
454 const auto margins = skinnable->marginHint( subControl );
455
456 const auto boxRect = rect.marginsRemoved( margins );
457 if ( boxRect.isEmpty() )
458 return nullptr;
459
460 const auto borderMetrics = skinnable->boxBorderMetricsHint( subControl );
461 const auto borderColors = skinnable->boxBorderColorsHint( subControl );
462 const auto shape = skinnable->boxShapeHint( subControl );
463 const auto shadowMetrics = skinnable->shadowMetricsHint( subControl );
464 const auto shadowColor = skinnable->shadowColorHint( subControl );
465
466 return qskUpdateBoxNode( skinnable, node,
467 boxRect, shape, borderMetrics, borderColors, fillGradient,
468 shadowMetrics, shadowColor );
469}
470
471QSGNode* QskSkinlet::updateBoxNode(
472 const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect,
473 const QskBoxShapeMetrics& shape, const QskBoxBorderMetrics& borderMetrics,
474 const QskBoxBorderColors& borderColors, const QskGradient& fillGradient )
475{
476 return qskUpdateBoxNode( skinnable, node,
477 rect, shape, borderMetrics, borderColors, fillGradient,
478 QskShadowMetrics(), QColor() );
479}
480
481QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable,
482 QSGNode* node, const QRectF& rect, const QskBoxHints& hints )
483{
484 return qskUpdateBoxNode( skinnable, node, rect,
485 hints.shape, hints.borderMetrics, hints.borderColors, hints.gradient,
486 hints.shadowMetrics, hints.shadowColor );
487}
488
489QSGNode* QskSkinlet::updateInterpolatedBoxNode(
490 const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect,
491 QskAspect aspect1, QskAspect aspect2, qreal ratio )
492{
493 QskBoxHints boxHints;
494 QRectF r;
495
496 ratio = qBound( 0.0, ratio, 1.0 );
497
498 if ( qFuzzyIsNull( ratio ) )
499 {
500 const auto margins = skinnable->marginHint( aspect1 );
501 r = rect.marginsRemoved( margins );
502
503 boxHints = skinnable->boxHints( aspect1 ).toAbsolute( r.size() );
504 }
505 else if ( qFuzzyCompare( ratio, 1.0 ) )
506 {
507 const auto margins = skinnable->marginHint( aspect2 );
508 r = rect.marginsRemoved( margins );
509
510 boxHints = skinnable->boxHints( aspect2 ).toAbsolute( r.size() );
511 }
512 else
513 {
514 QskMargins margins = skinnable->marginHint( aspect1 );
515 margins = margins.interpolated( skinnable->marginHint( aspect2 ), ratio );
516
517 r = rect.marginsRemoved( margins );
518
519 const auto boxHints1 = skinnable->boxHints( aspect1 ).toAbsolute( r.size() );
520 const auto boxHints2 = skinnable->boxHints( aspect2 ).toAbsolute( r.size() );
521
522 boxHints = boxHints1.interpolated( boxHints2, ratio );
523 }
524
525 return QskSkinlet::updateBoxNode( skinnable, node, r, boxHints );
526}
527
528QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
529 QSGNode* node, QskAspect::Subcontrol subControl ) const
530{
531 const auto rect = qskSubControlRect( this, skinnable, subControl );
532 return updateArcNode( skinnable, node, rect, subControl );
533}
534
535QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
536 QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl )
537{
538 const auto fillGradient = skinnable->gradientHint( subControl );
539 return updateArcNode( skinnable, node, rect, fillGradient, subControl );
540}
541
542QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
543 QSGNode* node, const QRectF& rect, const QskGradient& fillGradient,
544 QskAspect::Subcontrol subControl )
545{
546 const auto metrics = skinnable->arcMetricsHint( subControl );
547 const auto r = rect.marginsRemoved( skinnable->marginHint( subControl ) );
548
549 const qreal borderWidth = skinnable->metric( subControl | QskAspect::Border );
550
551 QColor borderColor;
552 if ( borderWidth > 0.0 )
553 borderColor = skinnable->color( subControl | QskAspect::Border );
554
555 return qskUpdateArcNode( skinnable, node,
556 r, borderWidth, borderColor, fillGradient, metrics );
557}
558
559QSGNode* QskSkinlet::updateArcNode(
560 const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect,
561 qreal borderWidth, const QColor& borderColor,
562 const QskGradient& fillGradient, const QskArcMetrics& metrics )
563{
564 return qskUpdateArcNode( skinnable, node, rect,
565 borderWidth, borderColor, fillGradient, metrics );
566}
567
568QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
569 QSGNode* node, qreal startAngle, qreal spanAngle,
570 QskAspect::Subcontrol subControl ) const
571{
572 const auto rect = qskSubControlRect( this, skinnable, subControl );
573
574 return updateArcNode( skinnable, node,
575 rect, startAngle, spanAngle, subControl );
576}
577
578QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
579 QSGNode* node, const QRectF& rect, qreal startAngle, qreal spanAngle,
580 QskAspect::Subcontrol subControl )
581{
582 const auto fillGradient = skinnable->gradientHint( subControl );
583 return updateArcNode( skinnable, node, rect,
584 fillGradient, startAngle, spanAngle, subControl );
585}
586
587QSGNode* QskSkinlet::updateArcNode( const QskSkinnable* skinnable,
588 QSGNode* node, const QRectF& rect, const QskGradient& fillGradient,
589 qreal startAngle, qreal spanAngle, QskAspect::Subcontrol subControl )
590{
591 auto arcMetrics = skinnable->arcMetricsHint( subControl );
592 arcMetrics.setStartAngle( startAngle );
593 arcMetrics.setSpanAngle( spanAngle );
594
595 const qreal borderWidth = skinnable->metric( subControl | QskAspect::Border );
596
597 QColor borderColor;
598 if ( borderWidth > 0.0 )
599 borderColor = skinnable->color( subControl | QskAspect::Border );
600
601 const auto r = rect.marginsRemoved( skinnable->marginHint( subControl ) );
602 return updateArcNode( skinnable, node, r,
603 borderWidth, borderColor, fillGradient, arcMetrics );
604}
605
606QSGNode* QskSkinlet::updateLineNode( const QskSkinnable* skinnable,
607 QSGNode* node, const QLineF& line, QskAspect::Subcontrol subControl )
608{
609 auto lineStipple = skinnable->stippleMetricsHint( subControl );
610 if ( !lineStipple.isValid() )
611 lineStipple = Qt::SolidLine;
612
613 const auto lineWidth = skinnable->metric( subControl | QskAspect::Size );
614 const auto lineColor = skinnable->color( subControl );
615
616 return qskUpdateLineNode( skinnable, node,
617 lineColor, lineWidth, lineStipple, line );
618}
619
620QSGNode* QskSkinlet::updateLinesNode( const QskSkinnable* skinnable,
621 QSGNode* node, const QVector< QLineF >& lines, QskAspect::Subcontrol subControl )
622{
623 auto lineStipple = skinnable->stippleMetricsHint( subControl );
624 if ( !lineStipple.isValid() )
625 lineStipple = Qt::SolidLine;
626
627 const auto lineWidth = skinnable->metric( subControl | QskAspect::Size );
628 const auto lineColor = skinnable->color( subControl );
629
630 return qskUpdateLinesNode( skinnable, node,
631 lineColor, lineWidth, lineStipple, lines );
632}
633
634QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable,
635 QSGNode* node, QskAspect::Subcontrol subControl ) const
636{
637 const auto rect = qskSubControlRect( this, skinnable, subControl );
638 return updateBoxClipNode( skinnable, node, rect, subControl );
639}
640
641QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable,
642 QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl )
643{
644 auto clipNode = QskSGNode::ensureNode< QskBoxClipNode >( node );
645
646 const auto margins = skinnable->marginHint( subControl );
647
648 const auto clipRect = rect.marginsRemoved( margins );
649 if ( clipRect.isEmpty() )
650 {
651 clipNode->setIsRectangular( true );
652 clipNode->setClipRect( clipRect );
653 }
654 else
655 {
656 auto borderMetrics = skinnable->boxBorderMetricsHint( subControl );
657 borderMetrics = borderMetrics.toAbsolute( clipRect.size() );
658
659 auto shape = skinnable->boxShapeHint( subControl );
660 shape = shape.toAbsolute( clipRect.size() );
661
662 const auto window = qskWindowOfSkinnable( skinnable );
663 clipNode->setBox( window, clipRect, shape, borderMetrics );
664 }
665
666 return clipNode;
667}
668
669QSGNode* QskSkinlet::updateTextNode( const QskSkinnable* skinnable,
670 QSGNode* node, const QRectF& rect, Qt::Alignment alignment,
671 const QString& text, const QFont& font, const QskTextOptions& textOptions,
672 const QskTextColors& textColors, Qsk::TextStyle textStyle )
673{
674 return qskUpdateTextNode( skinnable, node, rect, alignment,
675 text, font, textOptions, textColors, textStyle );
676}
677
678QSGNode* QskSkinlet::updateTextNode(
679 const QskSkinnable* skinnable, QSGNode* node,
680 const QRectF& rect, Qt::Alignment alignment,
681 const QString& text, QskAspect::Subcontrol subControl )
682{
683 if ( text.isEmpty() || rect.isEmpty() )
684 return nullptr;
685
686 const auto textColors = qskTextColors( skinnable, subControl );
687 const auto textOptions = skinnable->textOptionsHint( subControl );
688
689 auto textStyle = Qsk::Normal;
690 if ( textColors.styleColor.alpha() == 0 )
691 {
692 textStyle = skinnable->flagHint< Qsk::TextStyle >(
693 subControl | QskAspect::Style, Qsk::Normal );
694 }
695
696 const auto font = skinnable->effectiveFont( subControl );
697
698 return qskUpdateTextNode( skinnable, node, rect, alignment,
699 text, font, textOptions, textColors, textStyle );
700}
701
702QSGNode* QskSkinlet::updateTextNode(
703 const QskSkinnable* skinnable, QSGNode* node,
704 const QString& text, QskAspect::Subcontrol subControl ) const
705{
706 const auto rect = qskSubControlRect( this, skinnable, subControl );
707 const auto alignment = skinnable->alignmentHint( subControl, Qt::AlignLeft );
708
709 return updateTextNode( skinnable, node,
710 rect, alignment, text, subControl );
711}
712
713QSGNode* QskSkinlet::updateSymbolNode(
714 const QskSkinnable* skinnable, QSGNode* node,
715 QskAspect::Subcontrol subControl ) const
716{
717 return updateGraphicNode( skinnable, node,
718 skinnable->symbolHint( subControl ), subControl );
719}
720
721QSGNode* QskSkinlet::updateGraphicNode(
722 const QskSkinnable* skinnable, QSGNode* node,
723 const QskGraphic& graphic, QskAspect::Subcontrol subControl,
724 Qt::Orientations mirrored ) const
725{
726 const auto rect = qskSubControlRect( this, skinnable, subControl );
727 const auto alignment = skinnable->alignmentHint( subControl, Qt::AlignCenter );
728 const auto colorFilter = skinnable->effectiveGraphicFilter( subControl );
729
730 return updateGraphicNode( skinnable, node,
731 graphic, colorFilter, rect, alignment, mirrored );
732}
733
734QSGNode* QskSkinlet::updateGraphicNode(
735 const QskSkinnable* skinnable, QSGNode* node,
736 const QskGraphic& graphic, const QskColorFilter& colorFilter,
737 const QRectF& rect, Qt::Alignment alignment, Qt::Orientations mirrored )
738{
739 if ( graphic.isNull() )
740 return nullptr;
741
742 const auto size = graphic.defaultSize().scaled(
743 rect.size(), Qt::KeepAspectRatio );
744
745 const auto r = qskAlignedRectF( rect, size, alignment );
746 return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, r, mirrored );
747}
748
749QSGNode* QskSkinlet::updateGraphicNode(
750 const QskSkinnable* skinnable, QSGNode* node,
751 const QskGraphic& graphic, const QskColorFilter& colorFilter,
752 const QRectF& rect, Qt::Orientations mirrored )
753{
754 if ( graphic.isNull() )
755 return nullptr;
756
757 return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, rect, mirrored );
758}
759
760int QskSkinlet::sampleIndexAt( const QskSkinnable* skinnable,
761 const QRectF& rect, QskAspect::Subcontrol subControl, const QPointF& pos ) const
762{
763 // slow default implementation to be overloaded when having many cells
764
765 const auto count = sampleCount( skinnable, subControl );
766
767 for ( int i = 0; i < count; i++ )
768 {
769 const auto r = sampleRect( skinnable, rect, subControl, i );
770 if ( r.contains( pos ) )
771 return i;
772 }
773
774 return -1;
775}
776
777QSGNode* QskSkinlet::updateSeriesNode( const QskSkinnable* skinnable,
778 QskAspect::Subcontrol subControl, QSGNode* rootNode ) const
779{
780 auto node = rootNode ? rootNode->firstChild() : nullptr;
781 QSGNode* lastNode = nullptr;
782
783 const auto count = sampleCount( skinnable, subControl );
784
785 for( int i = 0; i < count; i++ )
786 {
787 QSGNode* newNode = nullptr;
788
789 {
790 const auto newStates = sampleStates( skinnable, subControl, i );
791
792 QskSkinStateChanger stateChanger( skinnable );
793 stateChanger.setStates( newStates, i );
794
795 newNode = updateSampleNode( skinnable, subControl, i, node );
796 }
797
798 if ( newNode )
799 {
800 if ( newNode == node )
801 {
802 node = node->nextSibling();
803 }
804 else
805 {
806 if ( rootNode == nullptr )
807 rootNode = new QSGNode();
808
809 if ( node )
810 rootNode->insertChildNodeBefore( newNode, node );
811 else
812 rootNode->appendChildNode( newNode );
813 }
814
815 lastNode = newNode;
816 }
817 }
818
819 QskSGNode::removeAllChildNodesAfter( rootNode, lastNode );
820
821 return rootNode;
822}
823
824QSGNode* QskSkinlet::updateSampleNode( const QskSkinnable*,
825 QskAspect::Subcontrol, int index, QSGNode* ) const
826{
827 Q_UNUSED( index )
828 return nullptr;
829}
830
831QskAspect::States QskSkinlet::sampleStates(
832 const QskSkinnable* skinnable, QskAspect::Subcontrol, int index ) const
833{
834 Q_UNUSED( index )
835 return skinnable->skinStates();
836}
837
838QVariant QskSkinlet::sampleAt( const QskSkinnable*,
839 QskAspect::Subcontrol, int index ) const
840{
841 Q_UNUSED( index )
842 return QVariant();
843}
844
845QSizeF QskSkinlet::hintWithoutConstraint(
846 const QSizeF& hint, const QSizeF& constraint ) const
847{
848 /*
849 This method is useful in situations, where a hint has been calculated
850 from a constraint and we want to return the calculated part only
851 */
852 QSizeF h;
853
854 if ( constraint.width() < 0.0 )
855 h.setWidth( hint.width() );
856
857 if ( constraint.height() < 0.0 )
858 h.setHeight( hint.height() );
859
860 return h;
861}
862
863#include "moc_QskSkinlet.cpp"
Lookup key for a QskSkinHintTable.
Definition QskAspect.h:15
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Definition QskAspect.h:104
Base class of all controls.
Definition QskControl.h:23
QskGradient background
Definition QskControl.h:41
A paint device for scalable graphics.
Definition QskGraphic.h:28
QRectF rect
Definition QskItem.h:21
@ DebugForceBackground
Definition QskItem.h:56
@ PreferRasterForTextures
Definition QskItem.h:54
bool isValid() const
Describes the rendering interface of a QskControl. Change the skinlet to change the appearance of the...
Definition QskSkinlet.h:34
QMarginsF marginHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a margin hint.
QskControl * controlCast()
QskGradient gradientHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint as gradient.
QFont effectiveFont(QskAspect) const
QskBoxShapeMetrics boxShapeHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a shape hint.
QskBoxBorderColors boxBorderColorsHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves border colors hint.
QskColorFilter effectiveGraphicFilter(QskAspect::Subcontrol) const
QColor color(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a color hint.
QskBoxBorderMetrics boxBorderMetricsHint(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a border hint.
T flagHint(QskAspect, T=T()) const
Retrieves a flag hint.
qreal metric(QskAspect, QskSkinHintStatus *=nullptr) const
Retrieves a metric hint.
Qt::Alignment alignmentHint(QskAspect, Qt::Alignment=Qt::Alignment()) const
Retrieves an alignment hint.