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"
26#include "QskStippleMetrics.h"
27#include "QskTextColors.h"
28#include "QskTextNode.h"
29#include "QskTextOptions.h"
30#include "QskSkinStateChanger.h"
31#include "QskTextureRenderer.h"
34#include <qquickwindow.h>
35#include <qsgsimplerectnode.h>
37static inline QRectF qskSceneAlignedRect(
const QQuickItem* item,
const QRectF& rect )
39 const auto transform = item->itemTransform(
nullptr,
nullptr );
40 if ( transform.type() > QTransform::TxTranslate )
50 const auto ratio = item->window()->devicePixelRatio();
52 const auto pos = transform.map( rect.topLeft() ) * ratio;
53 const auto size = rect.size() * ratio;
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;
60 return QRectF( item->mapFromScene( QPointF( x, y ) ), QSizeF( w, h ) );
63static inline QRectF qskSubControlRect(
const QskSkinlet* skinlet,
68 const auto r = control->contentsRect();
69 return skinlet->subControlRect( skinnable, r, subControl );
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,
80 if ( text.isEmpty() || rect.isEmpty() )
83 auto textNode =
static_cast< QskTextNode*
>( node );
84 if ( textNode ==
nullptr )
87 auto effectiveFont = font;
88 switch ( textOptions.fontSizeMode() )
90 case QskTextOptions::FixedSize:
93 case QskTextOptions::HorizontalFit:
97 case QskTextOptions::VerticalFit:
98 effectiveFont.setPixelSize(
static_cast< int >( rect.height() * 0.5 ) );
101 case QskTextOptions::Fit:
106 textNode->setTextData( skinnable->owningItem(),
107 text, rect, effectiveFont, textOptions, textColors, alignment, textStyle );
112static inline QSGNode* qskUpdateGraphicNode(
115 const QRectF& rect, Qt::Orientations mirrored )
117 if ( rect.isEmpty() )
120 const auto item = skinnable->owningItem();
121 if ( item ==
nullptr )
125 if ( graphicNode ==
nullptr )
130 bool useRaster = QskSetup::testUpdateFlag( flag );
131 if (
auto qItem = qobject_cast< const QskItem* >( item ) )
132 useRaster = qItem->testUpdateFlag( flag );
134 graphicNode->setRenderHint( useRaster ? QskPaintedNode::Raster :
QskPaintedNode::OpenGL );
136 graphicNode->setMirrored( mirrored );
138 const auto r = qskSceneAlignedRect( item, rect );
139 graphicNode->setGraphic( item->window(), graphic, colorFilter, r );
144static inline bool qskIsShadowVisible(
const QskShadowMetrics& shadowMetrics,
145 const QColor& shadowColor )
147 return !shadowMetrics.isNull() && shadowColor.isValid() && ( shadowColor.alpha() > 0 );
153 if ( gradient.isVisible() )
156 return !borderMetrics.isNull() && borderColors.isVisible();
159static inline bool qskIsArcVisible(
const QskArcMetrics& arcMetrics,
160 qreal borderWidth,
const QColor borderColor,
const QskGradient& gradient )
162 if ( arcMetrics.isNull() )
165 if ( borderWidth > 0.0 && borderColor.isValid() && borderColor.alpha() > 0 )
168 return gradient.isVisible();
171static inline bool qskIsLineVisible(
const QColor& lineColor, qreal lineWidth )
173 return ( lineWidth > 0.0 ) && lineColor.isValid() && ( lineColor.alpha() > 0 );
187 c.textColor = skinnable->
color( subControl, &status );
199static inline QQuickWindow* qskWindowOfSkinnable(
const QskSkinnable* skinnable )
201 if (
auto item = skinnable->owningItem() )
202 return item->window();
207static inline QSGNode* qskUpdateBoxNode(
208 const QskSkinnable* skinnable, QSGNode* node,
const QRectF& rect,
213 if ( !rect.isEmpty() )
215 if ( qskIsBoxVisible( borderMetrics, borderColors, gradient )
216 || qskIsShadowVisible( shadowMetrics, shadowColor ) )
218 if (
auto window = qskWindowOfSkinnable( skinnable ) )
220 auto boxNode = QskSGNode::ensureNode< QskBoxNode >( node );
221 boxNode->updateNode( window, rect, shape, borderMetrics,
222 borderColors, gradient, shadowMetrics, shadowColor );
232static inline QSGNode* qskUpdateArcNode(
234 qreal borderWidth,
const QColor borderColor,
237 if ( rect.isEmpty() )
240 if ( !qskIsArcVisible( metrics, borderWidth, borderColor, gradient ) )
243 auto arcNode = QskSGNode::ensureNode< QskArcNode >( node );
244 arcNode->setArcData( rect, metrics, borderWidth, borderColor, gradient );
249static inline QSGNode* qskUpdateLineNode(
250 const QskSkinnable*, QSGNode* node,
const QColor& lineColor,
256 if ( !qskIsLineVisible( lineColor, lineWidth ) )
259 auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node );
260 linesNode->updateLine( lineColor, lineWidth, lineStipple,
261 QTransform(), line.p1(), line.p2() );
266static inline QSGNode* qskUpdateLinesNode(
267 const QskSkinnable*, QSGNode* node,
const QColor& lineColor,
268 qreal lineWidth,
QskStippleMetrics& lineStipple,
const QVector< QLineF >& lines )
270 if ( lines.isEmpty() )
273 if ( !qskIsLineVisible( lineColor, lineWidth ) )
276 auto linesNode = QskSGNode::ensureNode< QskLinesNode >( node );
277 linesNode->updateLines( lineColor, lineWidth, lineStipple,
278 QTransform(), lines );
283class QskSkinlet::PrivateData
288 , ownedBySkinnable( false )
293 QVector< quint8 > nodeRoles;
295 bool ownedBySkinnable : 1;
298QskSkinlet::QskSkinlet(
QskSkin* skin )
299 : m_data( new PrivateData( skin ) )
303QskSkinlet::~QskSkinlet()
307QskSkin* QskSkinlet::skin()
const
312void QskSkinlet::setOwnedBySkinnable(
bool on )
314 m_data->ownedBySkinnable = on;
317bool QskSkinlet::isOwnedBySkinnable()
const
319 return m_data->ownedBySkinnable;
322void QskSkinlet::setNodeRoles(
const QVector< quint8 >& nodeRoles )
324 m_data->nodeRoles = nodeRoles;
327void QskSkinlet::appendNodeRoles(
const QVector< quint8 >& nodeRoles )
329 m_data->nodeRoles += nodeRoles;
332const QVector< quint8 >& QskSkinlet::nodeRoles()
const
334 return m_data->nodeRoles;
337void QskSkinlet::updateNode(
QskSkinnable* skinnable, QSGNode* parentNode )
const
339 using namespace QskSGNode;
344 if (
const auto control = skinnable->
controlCast() )
348 oldNode = findChildNode( parentNode, BackgroundRole );
349 newNode = updateBackgroundNode( control, oldNode );
351 replaceChildNode( BackgroundRole, parentNode, oldNode, newNode );
355 oldNode = findChildNode( parentNode, DebugRole );
359 newNode = updateDebugNode( control, oldNode );
361 replaceChildNode( DebugRole, parentNode, oldNode, newNode );
364 for (
const auto nodeRole : std::as_const( m_data->nodeRoles ) )
366 Q_ASSERT( nodeRole < FirstReservedRole );
368 oldNode = QskSGNode::findChildNode( parentNode, nodeRole );
369 newNode = updateSubNode( skinnable, nodeRole, oldNode );
371 replaceChildNode( nodeRole, parentNode, oldNode, newNode );
375QSGNode* QskSkinlet::updateBackgroundNode(
376 const QskControl* control, QSGNode* node )
const
378 const auto rect = control->
rect();
379 if ( rect.isEmpty() )
383 if ( !gradient.isVisible() )
386 auto rectNode = QskSGNode::ensureNode< QskBoxRectangleNode >( node );
387 rectNode->updateFilling( control->window(), rect, gradient );
392QSGNode* QskSkinlet::updateDebugNode(
393 const QskControl* control, QSGNode* node )
const
395 if ( control->size().isEmpty() )
398 auto rectNode =
static_cast< QSGSimpleRectNode*
>( node );
399 if ( rectNode ==
nullptr )
401 rectNode =
new QSGSimpleRectNode();
404 if ( control->inherits(
"QskFocusIndicator" ) )
406 color = QColor( Qt::gray );
407 color.setAlpha( 60 );
412 idx = ( idx + 3 ) % 14;
415 color = QColor( Qt::GlobalColor( 4 + idx ) );
416 color.setAlpha( 200 );
419 rectNode->setColor( color );
422 const auto r = control->
rect();
423 if ( rectNode->rect() != r )
424 rectNode->setRect( r );
429void QskSkinlet::replaceChildNode( quint8 role,
430 QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode )
const
432 QskSGNode::replaceChildNode(
433 m_data->nodeRoles, role, parentNode, oldNode, newNode );
436QSGNode* QskSkinlet::updateBoxNode(
const QskSkinnable* skinnable,
439 const auto rect = qskSubControlRect(
this, skinnable, subControl );
440 return updateBoxNode( skinnable, node, rect, subControl );
443QSGNode* QskSkinlet::updateBoxNode(
const QskSkinnable* skinnable,
446 const auto fillGradient = skinnable->
gradientHint( subControl );
447 return updateBoxNode( skinnable, node, rect, fillGradient, subControl );
450QSGNode* QskSkinlet::updateBoxNode(
const QskSkinnable* skinnable,
451 QSGNode* node,
const QRectF& rect,
const QskGradient& fillGradient,
454 const auto margins = skinnable->
marginHint( subControl );
456 const auto boxRect = rect.marginsRemoved( margins );
457 if ( boxRect.isEmpty() )
462 const auto shape = skinnable->
boxShapeHint( subControl );
463 const auto shadowMetrics = skinnable->shadowMetricsHint( subControl );
464 const auto shadowColor = skinnable->shadowColorHint( subControl );
466 return qskUpdateBoxNode( skinnable, node,
467 boxRect, shape, borderMetrics, borderColors, fillGradient,
468 shadowMetrics, shadowColor );
471QSGNode* QskSkinlet::updateBoxNode(
472 const QskSkinnable* skinnable, QSGNode* node,
const QRectF& rect,
476 return qskUpdateBoxNode( skinnable, node,
477 rect, shape, borderMetrics, borderColors, fillGradient,
481QSGNode* QskSkinlet::updateBoxNode(
const QskSkinnable* skinnable,
482 QSGNode* node,
const QRectF& rect,
const QskBoxHints& hints )
484 return qskUpdateBoxNode( skinnable, node, rect,
485 hints.shape, hints.borderMetrics, hints.borderColors, hints.gradient,
486 hints.shadowMetrics, hints.shadowColor );
489QSGNode* QskSkinlet::updateInterpolatedBoxNode(
490 const QskSkinnable* skinnable, QSGNode* node,
const QRectF& rect,
496 ratio = qBound( 0.0, ratio, 1.0 );
498 if ( qFuzzyIsNull( ratio ) )
500 const auto margins = skinnable->
marginHint( aspect1 );
501 r = rect.marginsRemoved( margins );
503 boxHints = skinnable->boxHints( aspect1 ).toAbsolute( r.size() );
505 else if ( qFuzzyCompare( ratio, 1.0 ) )
507 const auto margins = skinnable->
marginHint( aspect2 );
508 r = rect.marginsRemoved( margins );
510 boxHints = skinnable->boxHints( aspect2 ).toAbsolute( r.size() );
515 margins = margins.interpolated( skinnable->
marginHint( aspect2 ), ratio );
517 r = rect.marginsRemoved( margins );
519 const auto boxHints1 = skinnable->boxHints( aspect1 ).toAbsolute( r.size() );
520 const auto boxHints2 = skinnable->boxHints( aspect2 ).toAbsolute( r.size() );
522 boxHints = boxHints1.interpolated( boxHints2, ratio );
525 return QskSkinlet::updateBoxNode( skinnable, node, r, boxHints );
528QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable,
531 const auto rect = qskSubControlRect(
this, skinnable, subControl );
532 return updateArcNode( skinnable, node, rect, subControl );
535QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable,
538 const auto fillGradient = skinnable->
gradientHint( subControl );
539 return updateArcNode( skinnable, node, rect, fillGradient, subControl );
542QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable,
543 QSGNode* node,
const QRectF& rect,
const QskGradient& fillGradient,
546 const auto metrics = skinnable->arcMetricsHint( subControl );
547 const auto r = rect.marginsRemoved( skinnable->
marginHint( subControl ) );
552 if ( borderWidth > 0.0 )
555 return qskUpdateArcNode( skinnable, node,
556 r, borderWidth, borderColor, fillGradient, metrics );
559QSGNode* QskSkinlet::updateArcNode(
560 const QskSkinnable* skinnable, QSGNode* node,
const QRectF& rect,
561 qreal borderWidth,
const QColor& borderColor,
564 return qskUpdateArcNode( skinnable, node, rect,
565 borderWidth, borderColor, fillGradient, metrics );
568QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable,
569 QSGNode* node, qreal startAngle, qreal spanAngle,
572 const auto rect = qskSubControlRect(
this, skinnable, subControl );
574 return updateArcNode( skinnable, node,
575 rect, startAngle, spanAngle, subControl );
578QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable,
579 QSGNode* node,
const QRectF& rect, qreal startAngle, qreal spanAngle,
582 const auto fillGradient = skinnable->
gradientHint( subControl );
583 return updateArcNode( skinnable, node, rect,
584 fillGradient, startAngle, spanAngle, subControl );
587QSGNode* QskSkinlet::updateArcNode(
const QskSkinnable* skinnable,
588 QSGNode* node,
const QRectF& rect,
const QskGradient& fillGradient,
591 auto arcMetrics = skinnable->arcMetricsHint( subControl );
592 arcMetrics.setStartAngle( startAngle );
593 arcMetrics.setSpanAngle( spanAngle );
598 if ( borderWidth > 0.0 )
601 const auto r = rect.marginsRemoved( skinnable->
marginHint( subControl ) );
602 return updateArcNode( skinnable, node, r,
603 borderWidth, borderColor, fillGradient, arcMetrics );
606QSGNode* QskSkinlet::updateLineNode(
const QskSkinnable* skinnable,
609 auto lineStipple = skinnable->stippleMetricsHint( subControl );
610 if ( !lineStipple.isValid() )
611 lineStipple = Qt::SolidLine;
614 const auto lineColor = skinnable->
color( subControl );
616 return qskUpdateLineNode( skinnable, node,
617 lineColor, lineWidth, lineStipple, line );
620QSGNode* QskSkinlet::updateLinesNode(
const QskSkinnable* skinnable,
623 auto lineStipple = skinnable->stippleMetricsHint( subControl );
624 if ( !lineStipple.isValid() )
625 lineStipple = Qt::SolidLine;
628 const auto lineColor = skinnable->
color( subControl );
630 return qskUpdateLinesNode( skinnable, node,
631 lineColor, lineWidth, lineStipple, lines );
634QSGNode* QskSkinlet::updateBoxClipNode(
const QskSkinnable* skinnable,
637 const auto rect = qskSubControlRect(
this, skinnable, subControl );
638 return updateBoxClipNode( skinnable, node, rect, subControl );
641QSGNode* QskSkinlet::updateBoxClipNode(
const QskSkinnable* skinnable,
644 auto clipNode = QskSGNode::ensureNode< QskBoxClipNode >( node );
646 const auto margins = skinnable->
marginHint( subControl );
648 const auto clipRect = rect.marginsRemoved( margins );
649 if ( clipRect.isEmpty() )
651 clipNode->setIsRectangular(
true );
652 clipNode->setClipRect( clipRect );
657 borderMetrics = borderMetrics.toAbsolute( clipRect.size() );
660 shape = shape.toAbsolute( clipRect.size() );
662 const auto window = qskWindowOfSkinnable( skinnable );
663 clipNode->setBox( window, clipRect, shape, borderMetrics );
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,
674 return qskUpdateTextNode( skinnable, node, rect, alignment,
675 text, font, textOptions, textColors, textStyle );
678QSGNode* QskSkinlet::updateTextNode(
680 const QRectF& rect, Qt::Alignment alignment,
683 if ( text.isEmpty() || rect.isEmpty() )
686 const auto textColors = qskTextColors( skinnable, subControl );
687 const auto textOptions = skinnable->textOptionsHint( subControl );
689 auto textStyle = Qsk::Normal;
690 if ( textColors.styleColor.alpha() == 0 )
692 textStyle = skinnable->
flagHint< Qsk::TextStyle >(
698 return qskUpdateTextNode( skinnable, node, rect, alignment,
699 text, font, textOptions, textColors, textStyle );
702QSGNode* QskSkinlet::updateTextNode(
706 const auto rect = qskSubControlRect(
this, skinnable, subControl );
707 const auto alignment = skinnable->
alignmentHint( subControl, Qt::AlignLeft );
709 return updateTextNode( skinnable, node,
710 rect, alignment, text, subControl );
713QSGNode* QskSkinlet::updateSymbolNode(
717 return updateGraphicNode( skinnable, node,
718 skinnable->symbolHint( subControl ), subControl );
721QSGNode* QskSkinlet::updateGraphicNode(
724 Qt::Orientations mirrored )
const
726 const auto rect = qskSubControlRect(
this, skinnable, subControl );
727 const auto alignment = skinnable->
alignmentHint( subControl, Qt::AlignCenter );
730 return updateGraphicNode( skinnable, node,
731 graphic, colorFilter, rect, alignment, mirrored );
734QSGNode* QskSkinlet::updateGraphicNode(
737 const QRectF& rect, Qt::Alignment alignment, Qt::Orientations mirrored )
739 if ( graphic.isNull() )
742 const auto size = graphic.defaultSize().scaled(
743 rect.size(), Qt::KeepAspectRatio );
745 const auto r = qskAlignedRectF( rect, size, alignment );
746 return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, r, mirrored );
749QSGNode* QskSkinlet::updateGraphicNode(
752 const QRectF& rect, Qt::Orientations mirrored )
754 if ( graphic.isNull() )
757 return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, rect, mirrored );
760int QskSkinlet::sampleIndexAt(
const QskSkinnable* skinnable,
765 const auto count = sampleCount( skinnable, subControl );
767 for (
int i = 0; i < count; i++ )
769 const auto r = sampleRect( skinnable, rect, subControl, i );
770 if ( r.contains( pos ) )
777QSGNode* QskSkinlet::updateSeriesNode(
const QskSkinnable* skinnable,
780 auto node = rootNode ? rootNode->firstChild() :
nullptr;
781 QSGNode* lastNode =
nullptr;
783 const auto count = sampleCount( skinnable, subControl );
785 for(
int i = 0; i < count; i++ )
787 QSGNode* newNode =
nullptr;
790 const auto newStates = sampleStates( skinnable, subControl, i );
793 stateChanger.setStates( newStates, i );
795 newNode = updateSampleNode( skinnable, subControl, i, node );
800 if ( newNode == node )
802 node = node->nextSibling();
806 if ( rootNode ==
nullptr )
807 rootNode =
new QSGNode();
810 rootNode->insertChildNodeBefore( newNode, node );
812 rootNode->appendChildNode( newNode );
819 QskSGNode::removeAllChildNodesAfter( rootNode, lastNode );
824QSGNode* QskSkinlet::updateSampleNode(
const QskSkinnable*,
831QskAspect::States QskSkinlet::sampleStates(
835 return skinnable->skinStates();
845QSizeF QskSkinlet::hintWithoutConstraint(
846 const QSizeF& hint,
const QSizeF& constraint )
const
854 if ( constraint.width() < 0.0 )
855 h.setWidth( hint.width() );
857 if ( constraint.height() < 0.0 )
858 h.setHeight( hint.height() );
863#include "moc_QskSkinlet.cpp"
Lookup key for a QskSkinHintTable.
Subcontrol
For use within the rendering or lay-outing of a specific QskSkinnable.
Base class of all controls.
A paint device for scalable graphics.
@ PreferRasterForTextures
Describes the rendering interface of a QskControl. Change the skinlet to change the appearance of the...
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.