diff --git a/examples/sliders/Slider.cpp b/examples/sliders/Slider.cpp index e1044094..1ff46f97 100644 --- a/examples/sliders/Slider.cpp +++ b/examples/sliders/Slider.cpp @@ -3,6 +3,8 @@ #include #include +#include +#include #include QSK_SUBCONTROL( Slider, Scale ) @@ -15,7 +17,15 @@ Slider::Slider( QQuickItem* parentItem ): setMetric( QskSlider::Handle | Size, 80 ); - setColor( Fill, QskRgbValue::Grey700 ); +#if 0 + const QskGradient fillGradient( QskGradient::Horizontal, + QskRgbValue::Grey700, QskRgbValue::Grey500 ); +#else + const QskGradient fillGradient( QskRgbValue::Grey700 ); +#endif + + setBoxShapeHint( Fill, 0 ); + setGradientHint( Fill, fillGradient ); setColor( Scale, qRgb( 178, 178, 178 ) ); // for the ticks setColor( QskSlider::Handle, QskRgbValue::Grey800 ); diff --git a/examples/sliders/SliderSkinlet.cpp b/examples/sliders/SliderSkinlet.cpp index 20696e9a..38d2fb06 100644 --- a/examples/sliders/SliderSkinlet.cpp +++ b/examples/sliders/SliderSkinlet.cpp @@ -8,12 +8,12 @@ #include #include -#include #include +#include +#include +#include -#include #include -#include #include #include @@ -58,7 +58,7 @@ public: setMaterial( &m_material ); } - void update( const QRectF& rect, qreal peak, const QColor& color ) + void update( const QRectF& rect, qreal peakPos, const QColor& color ) { if ( color != m_color ) { @@ -68,15 +68,15 @@ public: markDirty( QSGNode::DirtyMaterial ); } - if ( rect != m_rect || peak != m_peak ) + if ( rect != m_rect || peakPos != m_peakPos ) { QSGGeometry::Point2D* p = reinterpret_cast< QSGGeometry::Point2D* >( m_geometry.vertexData() ); const qreal y0 = rect.y() + qskPeak; - setLine( p, peak, peak, rect.y() ); - setLine( p + 2, peak - 5, peak + 5, y0 ); + setLine( p, peakPos, peakPos, rect.y() ); + setLine( p + 2, peakPos - 5, peakPos + 5, y0 ); // corners manually "rounded" by 3 pixels @@ -88,7 +88,7 @@ public: setLine( p + 14, rect.left() + 2, rect.right() - 2, rect.bottom() ); m_rect = rect; - m_peak = peak; + m_peakPos = peakPos; markDirty( QSGNode::DirtyGeometry ); } } @@ -104,7 +104,7 @@ private: } QRectF m_rect; - qreal m_peak; + qreal m_peakPos; QColor m_color; QSGFlatColorMaterial m_material; @@ -164,7 +164,7 @@ QSGNode* SliderSkinlet::updateSubNode( return updateDecorationNode( slider, node ); case FillRole: - return updateFillNode( slider, node ); + return Inherited::updateSubNode( skinnable, nodeRole, node ); case HandleRole: return updateHandleNode( slider, node ); @@ -224,12 +224,6 @@ QRectF SliderSkinlet::handleRect( const QskSlider* slider ) const return handleRect; } -QSGNode* SliderSkinlet::updateGrooveNode( const QskSlider*, QSGNode* ) const -{ - // we don't have a groove - return nullptr; -} - QSGNode* SliderSkinlet::updateScaleNode( const QskSlider* slider, QSGNode* node ) const { @@ -284,7 +278,7 @@ QSGNode* SliderSkinlet::updateDecorationNode( const int tickCount = std::floor( slider->range() / slider->stepSize() ) + 1; - auto labelNode = static_cast< QSGTransformNode* >( decorationNode->firstChild() ); + auto labelNode = static_cast< QskTextNode* >( decorationNode->firstChild() ); auto stepStride = slider->stepSize() / slider->range() * decorationRect.width(); @@ -295,24 +289,17 @@ QSGNode* SliderSkinlet::updateDecorationNode( { if ( labelNode == nullptr ) { - labelNode = new QSGTransformNode; + labelNode = new QskTextNode; decorationNode->appendChildNode( labelNode ); } auto labelText = QString::number( slider->minimum() + slider->stepSize() * i, 'f', 0 ); - QskPlainTextRenderer renderer; - renderer.setFont( qskLabelFont ); - renderer.setAlignment( Qt::AlignHCenter ); - renderer.updateNode( slider, QRectF(), labelText, labelNode, - QskRgbValue::Grey700, Qsk::Normal, Qt::transparent ); - - QMatrix4x4 matrix; - matrix.translate( x, y ); - labelNode->setMatrix( matrix ); + labelNode->setTextData( slider, labelText, QRectF( x, y, 0, 0 ), + qskLabelFont, QskTextOptions(), QskTextColors( QskRgbValue::Grey700 ), + Qt::AlignHCenter, Qsk::Normal ); labelNode = static_cast< decltype( labelNode ) >( labelNode->nextSibling() ); - x += 100 * stepStride; } @@ -328,28 +315,6 @@ QSGNode* SliderSkinlet::updateDecorationNode( return decorationNode; } -QSGNode* SliderSkinlet::updateFillNode( - const QskSlider* slider, QSGNode* node ) const -{ - const QRectF fillRect = subControlRect( slider, QskSlider::Fill ); - if ( fillRect.isEmpty() ) - return nullptr; - - QSGSimpleRectNode* fillNode = static_cast< QSGSimpleRectNode* >( node ); - - if ( fillNode == nullptr ) - { - fillNode = new QSGSimpleRectNode; - fillNode->setFlags( QSGNode::OwnedByParent ); - fillNode->setColor( slider->color( QskSlider::Fill ) ); - } - - fillNode->setRect( fillRect ); - fillNode->markDirty( QSGNode::DirtyForceUpdate ); - - return fillNode; -} - QSGNode* SliderSkinlet::updateHandleNode( const QskSlider* slider, QSGNode* node ) const { @@ -367,31 +332,26 @@ QSGNode* SliderSkinlet::updateHandleNode( slider->color( QskSlider::Handle ) ); // finally the value label - auto labelNode = static_cast< QSGTransformNode* >( handleNode->firstChild() ); + auto labelNode = static_cast< QskTextNode* >( handleNode->firstChild() ); if ( labelNode == nullptr ) { - labelNode = new QSGTransformNode; + labelNode = new QskTextNode; handleNode->appendChildNode( labelNode ); } QFont font( QStringLiteral( "Roboto" ) ); font.setPixelSize( 26 ); - QskPlainTextRenderer renderer; - renderer.setFont( font ); - renderer.setAlignment( Qt::AlignHCenter ); - renderer.updateNode( slider, handleRect.size(), - QString::number( slider->value(), 'f', 0 ), - labelNode, Qt::white, Qsk::Normal, Qt::transparent ); - -#if 1 const qreal h = QFontMetrics( font ).height(); - qreal y = handleRect.bottom() - 0.5 * ( handleRect.height() - qskPeak + h ); - QMatrix4x4 matrix; - matrix.translate( handleRect.x(), y ); - labelNode->setMatrix( matrix ); -#endif + auto textRect = handleRect; + textRect.setTop( textRect.bottom() - 0.5 * ( textRect.height() - qskPeak + h ) ); + + const QString text = QString::number( slider->value(), 'f', 0 ); + + labelNode->setTextData( slider, text, textRect, + font, QskTextOptions(), QskTextColors( Qt::white ), + Qt::AlignHCenter, Qsk::Normal ); return handleNode; } diff --git a/examples/sliders/SliderSkinlet.h b/examples/sliders/SliderSkinlet.h index 5d82d37b..39e1ab52 100644 --- a/examples/sliders/SliderSkinlet.h +++ b/examples/sliders/SliderSkinlet.h @@ -17,7 +17,7 @@ class SliderSkinlet : public QskSliderSkinlet public: enum NodeRole { - // we have a scale instead of the groove + // we have a scale instead of a groove ScaleRole = QskSliderSkinlet::HandleRole + 1, DecorationRole }; @@ -32,20 +32,15 @@ protected: virtual QSGNode* updateSubNode( const QskSkinnable*, quint8 nodeRole, QSGNode* ) const override; - virtual QSGNode* updateScaleNode( const QskSlider*, QSGNode* ) const; - virtual QSGNode* updateDecorationNode( const QskSlider*, QSGNode* ) const; - - QSGNode* updateFillNode( const QskSlider*, QSGNode* ) const; - QSGNode* updateHandleNode( const QskSlider*, QSGNode* ) const; - QSGNode* updateGrooveNode( const QskSlider*, QSGNode* ) const; - private: + QSGNode* updateScaleNode( const QskSlider*, QSGNode* ) const; + QSGNode* updateDecorationNode( const QskSlider*, QSGNode* ) const; + QSGNode* updateHandleNode( const QskSlider*, QSGNode* ) const; + QRectF fillRect( const QskSlider* ) const; QRectF scaleRect( const QskSlider* ) const; QRectF decorationRect( const QskSlider* ) const; QRectF handleRect( const QskSlider* ) const; - - void updateHandleLabel( const QskSlider*, QSGTransformNode* ) const; }; #endif diff --git a/src/controls/QskInputPanelSkinlet.cpp b/src/controls/QskInputPanelSkinlet.cpp index e2c05a7b..d499f194 100644 --- a/src/controls/QskInputPanelSkinlet.cpp +++ b/src/controls/QskInputPanelSkinlet.cpp @@ -10,7 +10,6 @@ #include "QskAspect.h" #include "QskSkin.h" -#include "QskSkinRenderer.h" #include "QskTextOptions.h" #include "QskTextNode.h" #include "QskBoxNode.h" @@ -146,6 +145,7 @@ QSGNode* QskInputPanelSkinlet::updatePanelNode( const auto rowIndex = &keyRow - panelKeyData; auto& frames = panelNode->frames[ rowIndex ]; auto& glyphs = panelNode->glyphs[ rowIndex ]; + for ( const auto& keyData : keyRow ) { const auto colIndex = &keyData - keyRow; @@ -217,10 +217,8 @@ QSGNode* QskInputPanelSkinlet::updateKeyGlyphNode( const auto alignment = textNode->flagHint< Qt::Alignment >( QskInputPanel::KeyGlyph | QskAspect::Alignment, Qt::AlignCenter ); - QskSkinRenderer::updateText( textNode, rect, alignment, - panel->textForKey( key ), options, textNode, QskInputPanel::KeyGlyph ); - - return textNode; + return updateTextNode( panel, textNode, rect, alignment, + panel->textForKey( key ), options, QskInputPanel::KeyGlyph ); } #include "moc_QskInputPanelSkinlet.cpp" diff --git a/src/controls/QskListViewSkinlet.cpp b/src/controls/QskListViewSkinlet.cpp index 0246f58c..87b0c940 100644 --- a/src/controls/QskListViewSkinlet.cpp +++ b/src/controls/QskListViewSkinlet.cpp @@ -6,7 +6,6 @@ #include "QskListViewSkinlet.h" #include "QskListView.h" #include "QskAspect.h" -#include "QskSkinRenderer.h" #include "QskTextOptions.h" #include "QskTextNode.h" #include "QskGraphic.h" diff --git a/src/controls/QskSkinRenderer.cpp b/src/controls/QskSkinRenderer.cpp deleted file mode 100644 index af337e98..00000000 --- a/src/controls/QskSkinRenderer.cpp +++ /dev/null @@ -1,152 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#include "QskSkinRenderer.h" -#include "QskSkinnable.h" -#include "QskControl.h" - -#include "QskTextRenderer.h" -#include "QskPlainTextRenderer.h" -#include "QskTextNode.h" - -#include - -QSizeF QskSkinRenderer::textSize( const QskSkinnable* skinnable, - const QString& text, const QskTextOptions& options, - QskAspect::Subcontrol subControl ) -{ - using namespace QskAspect; - - auto font = skinnable->effectiveFont( subControl ); - - if ( options.effectiveFormat( text ) == QskTextOptions::PlainText ) - { - QskPlainTextRenderer renderer; - renderer.setFont( font ); - renderer.setOptions( options ); - - return renderer.textSize( text ); - } - else - { - QskTextRenderer renderer; - renderer.setFont( font ); - renderer.setOptions( options ); - - return renderer.textSize( text ); - } -} - -QSizeF QskSkinRenderer::textSize( const QskSkinnable* skinnable, - const QSizeF& boundingSize, const QString& text, - const QskTextOptions& options, QskAspect::Subcontrol subControl ) -{ - const auto font = skinnable->effectiveFont( subControl ); - - if ( options.effectiveFormat( text ) == QskTextOptions::PlainText ) - { - QskPlainTextRenderer renderer; - renderer.setFont( font ); - renderer.setOptions( options ); - - return renderer.textRect( boundingSize, text ).size(); - } - else - { - QskTextRenderer renderer; - renderer.setFont( font ); - renderer.setOptions( options ); - - return renderer.textRect( boundingSize, text ).size(); - } -} - -void QskSkinRenderer::updateText( const QskSkinnable* skinnable, - const QRectF& bounds, Qt::Alignment alignment, - const QString& text, const QskTextOptions& options, - QskTextNode* textNode, QskAspect::Subcontrol subControl ) -{ - using namespace QskAspect; - - QMatrix4x4 matrix; - matrix.translate( bounds.left(), bounds.top() ); - textNode->setMatrix( matrix ); - - QskSkinHintStatus status; - auto textColor = skinnable->color( subControl, &status ); - if ( !status.isValid() ) - textColor = skinnable->color( subControl | QskAspect::TextColor ); - - auto font = skinnable->effectiveFont( subControl ); - - auto styleColor = skinnable->color( subControl | StyleColor ); - - auto textStyle = Qsk::Normal; - if ( styleColor.alpha() == 0 ) - { - textStyle = skinnable->flagHint< Qsk::TextStyle >( - subControl | Style, Qsk::Normal ); - } - - const auto isPlainText = options.effectiveFormat( text ) == QskTextOptions::PlainText; - - // doesn't work - we end up with a black rectangle TODO ... -#if 0 - // Optimization: only update the color if that is all that has changed - if ( isPlainText && color_is_dirty ) - { - QskPlainTextRenderer::updateNodeColor( parentNode, textRgb, - fontOptions.textStyle, styleRgb ); - return; - } -#endif - - switch ( options.fontSizeMode() ) - { - case QskTextOptions::FixedSize: - break; - - case QskTextOptions::HorizontalFit: - Q_UNIMPLEMENTED(); - break; - - case QskTextOptions::VerticalFit: - font.setPixelSize( bounds.height() * 0.5 ); - break; - - case QskTextOptions::Fit: - Q_UNIMPLEMENTED(); - break; - } - - QColor linkColor; - if ( !isPlainText ) - linkColor = skinnable->color( subControl | LinkColor ); - - if ( textNode->setTextData( text, bounds.size(), font, - options, alignment, textStyle, textColor, styleColor, linkColor ) ) - { - if ( isPlainText ) - { - QskPlainTextRenderer renderer; - renderer.setFont( font ); - renderer.setOptions( options ); - renderer.setAlignment( alignment ); - - renderer.updateNode( skinnable->owningControl(), bounds.size(), - text, textNode, textColor, textStyle, styleColor ); - } - else - { - QskTextRenderer renderer; - renderer.setFont( font ); - renderer.setOptions( options ); - renderer.setAlignment( alignment ); - - renderer.updateNode( skinnable->owningControl(), bounds.size(), - text, textNode, textColor, textStyle, styleColor, linkColor ); - } - } -} diff --git a/src/controls/QskSkinRenderer.h b/src/controls/QskSkinRenderer.h deleted file mode 100644 index d2f09f35..00000000 --- a/src/controls/QskSkinRenderer.h +++ /dev/null @@ -1,41 +0,0 @@ -/****************************************************************************** - * QSkinny - Copyright (C) 2016 Uwe Rathmann - * This file may be used under the terms of the QSkinny License, Version 1.0 - *****************************************************************************/ - -#ifndef QSK_SKIN_RENDERER_H -#define QSK_SKIN_RENDERER_H - -#include "QskGlobal.h" -#include "QskAspect.h" - -#include - -class QskSkinnable; -class QskTextOptions; -class QskTextNode; - -class QPointF; -class QRectF; -class QSizeF; -class QString; - -namespace QskSkinRenderer -{ - // a loose collection of functions, waiting to be - // organized somehow. TODO ... - - QSK_EXPORT void updateText( const QskSkinnable*, - const QRectF&, Qt::Alignment, - const QString&, const QskTextOptions&, - QskTextNode*, QskAspect::Subcontrol ); - - QSK_EXPORT QSizeF textSize( const QskSkinnable*, - const QString&, const QskTextOptions&, QskAspect::Subcontrol ); - - QSK_EXPORT QSizeF textSize( const QskSkinnable*, - const QSizeF& boundingSize, const QString&, - const QskTextOptions&, QskAspect::Subcontrol ); -} - -#endif diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index 30c40d46..f109bb1b 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -13,10 +13,11 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxBorderColors.h" #include "QskGradient.h" -#include "QskSkinRenderer.h" #include "QskBoxNode.h" #include "QskBoxClipNode.h" #include "QskTextNode.h" +#include "QskTextColors.h" +#include "QskTextOptions.h" #include "QskGraphicNode.h" #include "QskGraphicTextureFactory.h" #include "QskFunctions.h" @@ -89,6 +90,31 @@ static inline bool qskIsBoxVisible( const QskBoxBorderMetrics& borderMetrics, return !borderMetrics.isNull() && borderColors.isVisible(); } +static inline QskTextColors qskTextColors( + const QskSkinnable* skinnable, QskAspect::Subcontrol subControl ) +{ + using namespace QskAspect; + + /* + Would be more efficient to have QskTextColors hints instead of + storing the colors as seperated hints. TODO ... + */ + + QskSkinHintStatus status; + + QskTextColors c; + c.textColor = skinnable->color( subControl, &status ); +#if 1 + if ( !status.isValid() ) + c.textColor = skinnable->color( subControl | QskAspect::TextColor ); +#endif + + c.styleColor = skinnable->color( subControl | StyleColor ); + c.linkColor = skinnable->color( subControl | LinkColor ); + + return c; +} + class QskSkinlet::PrivateData { public: @@ -428,8 +454,37 @@ QSGNode* QskSkinlet::updateTextNode( if ( textNode == nullptr ) textNode = new QskTextNode(); - QskSkinRenderer::updateText( skinnable, rect, alignment, - text, textOptions, textNode, subControl ); + auto colors = qskTextColors( skinnable, subControl ); + + auto textStyle = Qsk::Normal; + if ( colors.styleColor.alpha() == 0 ) + { + textStyle = skinnable->flagHint< Qsk::TextStyle >( + subControl | QskAspect::Style, Qsk::Normal ); + } + + auto font = skinnable->effectiveFont( subControl ); + + switch ( textOptions.fontSizeMode() ) + { + case QskTextOptions::FixedSize: + break; + + case QskTextOptions::HorizontalFit: + Q_UNIMPLEMENTED(); + break; + + case QskTextOptions::VerticalFit: + font.setPixelSize( rect.height() * 0.5 ); + break; + + case QskTextOptions::Fit: + Q_UNIMPLEMENTED(); + break; + } + + textNode->setTextData( skinnable->owningControl(), + text, rect, font, textOptions, colors, alignment, textStyle ); return textNode; } diff --git a/src/controls/QskSkinnable.cpp b/src/controls/QskSkinnable.cpp index 24fc2829..04d09552 100644 --- a/src/controls/QskSkinnable.cpp +++ b/src/controls/QskSkinnable.cpp @@ -16,7 +16,6 @@ #include "QskControl.h" #include "QskColorFilter.h" #include "QskSkinTransition.h" -#include "QskSkinRenderer.h" #include #include diff --git a/src/controls/QskTextLabel.cpp b/src/controls/QskTextLabel.cpp index 706faa1e..6d38a19c 100644 --- a/src/controls/QskTextLabel.cpp +++ b/src/controls/QskTextLabel.cpp @@ -6,7 +6,7 @@ #include "QskTextLabel.h" #include "QskAspect.h" #include "QskTextOptions.h" -#include "QskSkinRenderer.h" +#include "QskTextNode.h" #include #include @@ -172,8 +172,9 @@ QSizeF QskTextLabel::contentsSizeHint() const { if ( !m_data->text.isEmpty() ) { - return QskSkinRenderer::textSize( this, m_data->text, - m_data->effectiveOptions(), QskTextLabel::Text ); + const auto font = effectiveFont( Text ); + return QskTextNode::textSize( + m_data->text, font, m_data->effectiveOptions() ); } return QSizeF( 0, 0 ); @@ -181,7 +182,8 @@ QSizeF QskTextLabel::contentsSizeHint() const qreal QskTextLabel::heightForWidth( qreal width ) const { - const qreal lineHeight = QFontMetricsF( effectiveFont( Text ) ).height(); + const auto font = effectiveFont( Text ); + const qreal lineHeight = QFontMetricsF( font ).height(); if ( m_data->text.isEmpty() || ( m_data->textOptions.wrapMode() == QskTextOptions::NoWrap ) ) @@ -196,9 +198,8 @@ qreal QskTextLabel::heightForWidth( qreal width ) const maxHeight = m_data->textOptions.maximumLineCount() * lineHeight; } - const QSizeF size = QskSkinRenderer::textSize( this, - QSizeF( width, maxHeight ), m_data->text, - m_data->effectiveOptions(), QskTextLabel::Text ); + QSizeF size( width, maxHeight ); + size = QskTextNode::textSize( m_data->text, font, size, m_data->effectiveOptions() ); return qCeil( size.height() ); } @@ -211,11 +212,11 @@ qreal QskTextLabel::widthForHeight( qreal height ) const return Inherited::widthForHeight( height ); } + const auto font = effectiveFont( Text ); const qreal maxWidth = std::numeric_limits< qreal >::max(); - const QSizeF size = QskSkinRenderer::textSize( this, - QSizeF( maxWidth, height ), m_data->text, - m_data->effectiveOptions(), QskTextLabel::Text ); + QSizeF size( maxWidth, height ); + size = QskTextNode::textSize( m_data->text, font, size, m_data->effectiveOptions() ); return qCeil( size.width() ); } diff --git a/src/controls/QskVariantAnimator.cpp b/src/controls/QskVariantAnimator.cpp index 1d9cbff7..3edfd680 100644 --- a/src/controls/QskVariantAnimator.cpp +++ b/src/controls/QskVariantAnimator.cpp @@ -10,6 +10,7 @@ #include "QskBoxBorderMetrics.h" #include "QskBoxBorderColors.h" #include "QskGradient.h" +#include "QskTextColors.h" // Even if we don't use the standard Qt animation system we // use its registry of interpolators: why adding our own ... @@ -26,6 +27,7 @@ static void qskRegisterInterpolator() qRegisterAnimationInterpolator( QskBoxShapeMetrics::interpolate ); qRegisterAnimationInterpolator( QskBoxBorderMetrics::interpolate ); qRegisterAnimationInterpolator( QskBoxBorderColors::interpolate ); + qRegisterAnimationInterpolator( QskTextColors::interpolate ); } Q_CONSTRUCTOR_FUNCTION( qskRegisterInterpolator ) diff --git a/src/nodes/QskPlainTextRenderer.cpp b/src/nodes/QskPlainTextRenderer.cpp index 47e9d2d6..9499d106 100644 --- a/src/nodes/QskPlainTextRenderer.cpp +++ b/src/nodes/QskPlainTextRenderer.cpp @@ -5,6 +5,7 @@ #include "QskPlainTextRenderer.h" #include "QskSkinlet.h" +#include "QskTextColors.h" #include #include @@ -175,9 +176,9 @@ static void qskRenderText( } } -void QskPlainTextRenderer::updateNode( - const QQuickItem* item, const QRectF& rect, const QString& text, QSGNode* parentNode, - const QColor& textColor, Qsk::TextStyle style, const QColor& styleColor ) +void QskPlainTextRenderer::updateNode( const QString& text, + const QRectF& rect, Qsk::TextStyle style, const QskTextColors& colors, + const QQuickItem* item, QSGTransformNode* node ) { QTextOption textOption( m_alignment ); textOption.setWrapMode( static_cast< QTextOption::WrapMode >( m_options.wrapMode() ) ); @@ -197,8 +198,16 @@ void QskPlainTextRenderer::updateNode( + ( m_alignment & Qt::AlignVCenter ? ( rect.height() - position.y() ) * 0.5 : 0 ) ); - qskRenderText( const_cast< QQuickItem* >( item ), parentNode, &layout, position, - textColor, static_cast< QQuickText::TextStyle >( style ), styleColor ); + qskRenderText( const_cast< QQuickItem* >( item ), node, &layout, position, + colors.textColor, static_cast< QQuickText::TextStyle >( style ), colors.styleColor ); +} + +void QskPlainTextRenderer::updateNode( const QString& text, + const QSizeF& size, Qsk::TextStyle style, const QskTextColors& colors, + const QQuickItem* item, QSGTransformNode* node ) +{ + const QRectF textRect( 0, 0, size.width(), size.height() ); + updateNode( text, textRect, style, colors, item, node ); } void QskPlainTextRenderer::updateNodeColor( QSGNode* parentNode, const QColor& textColor, diff --git a/src/nodes/QskPlainTextRenderer.h b/src/nodes/QskPlainTextRenderer.h index 5f7a2c28..6b1e8cc4 100644 --- a/src/nodes/QskPlainTextRenderer.h +++ b/src/nodes/QskPlainTextRenderer.h @@ -13,9 +13,13 @@ #include #include +class QskTextColors; + class QSGNode; class QQuickItem; class QColor; +class QSGTransformNode; +class QQuickItem; class QSK_EXPORT QskPlainTextRenderer { @@ -27,13 +31,13 @@ public: void setOptions( const QskTextOptions& ); void setAlignment( Qt::Alignment ); - void updateNode( - const QQuickItem*, const QRectF&, const QString&, QSGNode* parentNode, - const QColor& textColor, Qsk::TextStyle, const QColor& styleColor ); + void updateNode( const QString&, const QSizeF&, + Qsk::TextStyle, const QskTextColors&, + const QQuickItem*, QSGTransformNode* ); - void updateNode( - const QQuickItem*, const QSizeF& size, const QString&, QSGNode* parentNode, - const QColor& textColor, Qsk::TextStyle, const QColor& styleColor ); + void updateNode( const QString&, const QRectF&, + Qsk::TextStyle, const QskTextColors&, + const QQuickItem*, QSGTransformNode* ); static void updateNodeColor( QSGNode* parentNode, const QColor& textColor, Qsk::TextStyle, const QColor& styleColor ); @@ -50,12 +54,4 @@ private: Qt::Alignment m_alignment; }; -inline void QskPlainTextRenderer::updateNode( - const QQuickItem* item, const QSizeF& size, const QString& text, QSGNode* parentNode, - const QColor& textColor, Qsk::TextStyle style, const QColor& styleColor ) -{ - updateNode( item, QRectF( QPointF(), size ), - text, parentNode, textColor, style, styleColor ); -} - #endif diff --git a/src/nodes/QskTextNode.cpp b/src/nodes/QskTextNode.cpp index c7cb8e84..3939b862 100644 --- a/src/nodes/QskTextNode.cpp +++ b/src/nodes/QskTextNode.cpp @@ -5,11 +5,32 @@ #include "QskTextNode.h" #include "QskTextOptions.h" +#include "QskTextColors.h" +#include "QskTextRenderer.h" +#include "QskPlainTextRenderer.h" #include #include #include +static inline uint qskHash( + const QString& text, const QSizeF& size, const QFont& font, + const QskTextOptions& options, const QskTextColors& colors, + Qt::Alignment alignment, Qsk::TextStyle textStyle ) +{ + uint hash = 11000; + + hash = qHash( text, hash ); + hash = qHash( font, hash ); + hash = qHash( options, hash ); + hash = qHash( alignment, hash ); + hash = qHash( textStyle, hash ); + hash = colors.hash( hash ); + hash = qHashBits( &size, sizeof( QSizeF ), hash ); + + return hash; +} + QskTextNode::QskTextNode(): m_hash( 0 ) { @@ -19,26 +40,99 @@ QskTextNode::~QskTextNode() { } -bool QskTextNode::setTextData( - const QString& text, const QSizeF& size, const QFont& font, - const QskTextOptions& options, Qt::Alignment alignment, Qsk::TextStyle textStyle, - const QColor& textColor, const QColor& styleColor, const QColor& linkColor ) +void QskTextNode::setTextData( const QQuickItem* item, + const QString& text, const QRectF& rect, const QFont& font, + const QskTextOptions& options, const QskTextColors& colors, + Qt::Alignment alignment, Qsk::TextStyle textStyle ) { - uint hash; + if ( m_rect != rect ) + { + QMatrix4x4 matrix; + matrix.translate( rect.left(), rect.top() ); - hash = qHash( text, 0 ); - hash = qHash( font, hash ); - hash = qHash( options, hash ); - hash = qHash( alignment, hash ); - hash = qHash( textStyle, hash ); - hash = qHash( textColor.rgba(), hash ); - hash = qHash( styleColor.rgba(), hash ); - hash = qHash( linkColor.rgba(), hash ); - hash = qHashBits( &size, sizeof( QSizeF ), hash ); + if ( matrix != this->matrix() ) // avoid setting DirtyMatrix accidently + setMatrix( matrix ); + } + + const uint hash = qskHash( text, rect.size(), font, + options, colors, alignment, textStyle ); if ( hash == m_hash ) - return false; + return; m_hash = hash; - return true; + + const QRectF textRect( 0, 0, rect.width(), rect.height() ); + + if ( options.format() == QskTextOptions::PlainText ) + { +#if 0 + if ( colors_only ) + { + // doesn't work - we end up with a black rectangle TODO ... + + QskPlainTextRenderer::updateNodeColor( parentNode, textRgb, + fontOptions.textStyle, styleRgb ); + return; + } +#endif + QskPlainTextRenderer renderer; + renderer.setFont( font ); + renderer.setOptions( options ); + renderer.setAlignment( alignment ); + + renderer.updateNode( text, textRect, textStyle, colors, item, this ); + } + else + { + QskTextRenderer renderer; + renderer.setFont( font ); + renderer.setOptions( options ); + renderer.setAlignment( alignment ); + + renderer.updateNode( text, textRect, textStyle, colors, item, this ); + } } + +QSizeF QskTextNode::textSize( const QString& text, + const QFont& font, const QskTextOptions& options ) +{ + if ( options.effectiveFormat( text ) == QskTextOptions::PlainText ) + { + QskPlainTextRenderer renderer; + renderer.setFont( font ); + renderer.setOptions( options ); + + return renderer.textSize( text ); + } + else + { + QskTextRenderer renderer; + renderer.setFont( font ); + renderer.setOptions( options ); + + return renderer.textSize( text ); + } +} + +QSizeF QskTextNode::textSize( const QString& text, const QFont& font, + const QSizeF& boundingSize, const QskTextOptions& options ) +{ + if ( options.effectiveFormat( text ) == QskTextOptions::PlainText ) + { + QskPlainTextRenderer renderer; + renderer.setFont( font ); + renderer.setOptions( options ); + + return renderer.textRect( boundingSize, text ).size(); + } + else + { + QskTextRenderer renderer; + renderer.setFont( font ); + renderer.setOptions( options ); + + return renderer.textRect( boundingSize, text ).size(); + } +} + diff --git a/src/nodes/QskTextNode.h b/src/nodes/QskTextNode.h index ef30acba..96492b02 100644 --- a/src/nodes/QskTextNode.h +++ b/src/nodes/QskTextNode.h @@ -10,10 +10,13 @@ #include "QskNamespace.h" #include -#include +#include class QskTextOptions; +class QskTextColors; class QString; +class QFont; +class QQuickItem; class QSK_EXPORT QskTextNode : public QSGTransformNode { @@ -21,10 +24,22 @@ public: QskTextNode(); virtual ~QskTextNode(); - bool setTextData( const QString& text, const QSizeF&, const QFont&, - const QskTextOptions&, Qt::Alignment, Qsk::TextStyle, - const QColor& textColor, const QColor& styleColor, const QColor& linkColor ); + void setTextData( const QQuickItem* item, + const QString& text, const QRectF&, const QFont&, + const QskTextOptions&, const QskTextColors&, + Qt::Alignment, Qsk::TextStyle ); + +#if 1 + // for the moment here TODO ... + static QSizeF textSize( const QString&, + const QFont&, const QskTextOptions& ); + + static QSizeF textSize( const QString&, const QFont&, + const QSizeF&, const QskTextOptions& ); +#endif + private: + QRectF m_rect; uint m_hash; }; diff --git a/src/nodes/QskTextRenderer.cpp b/src/nodes/QskTextRenderer.cpp index f09b4da5..a699da77 100644 --- a/src/nodes/QskTextRenderer.cpp +++ b/src/nodes/QskTextRenderer.cpp @@ -4,6 +4,8 @@ *****************************************************************************/ #include "QskTextRenderer.h" +#include "QskTextColors.h" + #include QSK_QT_PRIVATE_BEGIN @@ -16,63 +18,40 @@ QSK_QT_PRIVATE_END class QskTextHelperItem final : public QQuickText { public: - QskTextHelperItem(); - void refWindow( QQuickWindow* window ); void derefWindow(); - void begin(); - void end(); + void begin() { classBegin(); } + void end() { componentComplete(); } - QRectF layedOutTextRect() const; - void updateTextNode( QQuickWindow*, QSGNode* ); + QRectF layedOutTextRect() const + { + auto that = const_cast< QskTextHelperItem* >( this ); + return QQuickTextPrivate::get( that )->layedOutTextRect; + } + void updateTextNode( QQuickWindow* window, QSGNode* parentNode ) + { + QQuickItemPrivate::get( this )->refWindow( window ); + + while ( parentNode->firstChild() ) + delete parentNode->firstChild(); + + auto node = QQuickText::updatePaintNode( nullptr, nullptr ); + node->reparentChildNodesTo( parentNode ); + delete node; + + QQuickItemPrivate::get( this )->derefWindow(); + } protected: virtual QSGNode* updatePaintNode( - QSGNode*, UpdatePaintNodeData* ) override final; + QSGNode*, UpdatePaintNodeData* ) override final + { + // should never be called + return nullptr; + } }; -QskTextHelperItem::QskTextHelperItem(): - QQuickText( nullptr ) -{ -} - -QRectF QskTextHelperItem::layedOutTextRect() const -{ - auto that = const_cast< QskTextHelperItem* >( this ); - return QQuickTextPrivate::get( that )->layedOutTextRect; -} - -void QskTextHelperItem::updateTextNode( QQuickWindow* window, QSGNode* parentNode ) -{ - QQuickItemPrivate::get( this )->refWindow( window ); - - while ( parentNode->firstChild() ) - delete parentNode->firstChild(); // This is done in QQuickText::updatePaintNode anyway - - auto node = QQuickText::updatePaintNode( nullptr, nullptr ); - node->reparentChildNodesTo( parentNode ); - delete node; - - QQuickItemPrivate::get( this )->derefWindow(); -} - -void QskTextHelperItem::begin() -{ - classBegin(); -} - -void QskTextHelperItem::end() -{ - componentComplete(); -} - -QSGNode* QskTextHelperItem::updatePaintNode( QSGNode*, UpdatePaintNodeData* ) -{ - // should never be called - return nullptr; -} - /* size requests and rendering might be from different threads and we better use different items as we might end up in events internally @@ -171,13 +150,12 @@ void QskTextRenderer::setupItem( QskTextHelperItem* textItem ) const #endif } -void QskTextRenderer::updateNode( const QQuickItem* item, - const QRectF& rect, const QString& text, QSGTransformNode* parentNode, - const QColor& textColor, Qsk::TextStyle style, const QColor& styleColor, - const QColor& linkColor ) +void QskTextRenderer::updateNode( const QString& text, + const QRectF& rect, Qsk::TextStyle style, const QskTextColors& colors, + const QQuickItem* item, QSGTransformNode* node ) { // are we killing internal caches of QQuickText, when always using - // the same item for the creation the text nodes ??? + // the same item for the creation the text nodes. TODO ... if ( qskRenderHelper == NULL ) qskRenderHelper = new QskTextHelperItem(); @@ -204,16 +182,23 @@ void QskTextRenderer::updateNode( const QQuickItem* item, textItem.doLayout(); } - textItem.setColor( textColor ); + textItem.setColor( colors.textColor ); textItem.setStyle( static_cast< QQuickText::TextStyle >( style ) ); - textItem.setStyleColor( styleColor ); - textItem.setLinkColor( linkColor ); + textItem.setStyleColor( colors.styleColor ); + textItem.setLinkColor( colors.linkColor ); textItem.setText( text ); textItem.end(); - textItem.updateTextNode( item->window(), parentNode ); - + textItem.updateTextNode( item->window(), node ); textItem.setText( QString::null ); } + +void QskTextRenderer::updateNode( const QString& text, + const QSizeF& size, Qsk::TextStyle style, const QskTextColors& colors, + const QQuickItem* item, QSGTransformNode* node ) +{ + const QRectF textRect( 0, 0, size.width(), size.height() ); + updateNode( text, textRect, style, colors, item, node ); +} diff --git a/src/nodes/QskTextRenderer.h b/src/nodes/QskTextRenderer.h index b41b0518..e64f03ae 100644 --- a/src/nodes/QskTextRenderer.h +++ b/src/nodes/QskTextRenderer.h @@ -14,6 +14,7 @@ #include class QskTextHelperItem; +class QskTextColors; class QQuickItem; class QQuickWindow; @@ -31,13 +32,13 @@ public: void setOptions( const QskTextOptions& ); void setAlignment( Qt::Alignment ); - void updateNode( const QQuickItem*, const QSizeF&, const QString&, - QSGTransformNode*, const QColor& textColor, - Qsk::TextStyle, const QColor& styleColor, const QColor& linkColor ); + void updateNode( const QString&, const QSizeF&, + Qsk::TextStyle, const QskTextColors&, + const QQuickItem*, QSGTransformNode* ); - void updateNode( const QQuickItem*, const QRectF&, const QString&, - QSGTransformNode*, const QColor& textColor, Qsk::TextStyle, - const QColor& styleColor, const QColor& linkColor ); + void updateNode( const QString&, const QRectF&, + Qsk::TextStyle, const QskTextColors&, + const QQuickItem*, QSGTransformNode* ); QSizeF textSize( const QString& ) const; QRectF textRect( const QSizeF&, const QString& ) const; @@ -50,12 +51,4 @@ private: Qt::Alignment m_alignment; }; -inline void QskTextRenderer::updateNode( const QQuickItem* item, const QSizeF& size, - const QString& text, QSGTransformNode* node, const QColor& textColor, - Qsk::TextStyle style, const QColor& styleColor, const QColor& linkColor ) -{ - updateNode( item, QRectF( 0, 0, size.width(), size.height() ), text, node, - textColor, style, styleColor, linkColor ); -} - #endif diff --git a/src/src.pro b/src/src.pro index 5fe4801a..a0808ab3 100644 --- a/src/src.pro +++ b/src/src.pro @@ -44,6 +44,7 @@ HEADERS += \ common/QskNamespace.h \ common/QskObjectCounter.h \ common/QskSizePolicy.h \ + common/QskTextColors.h \ common/QskTextOptions.h SOURCES += \ @@ -58,6 +59,7 @@ SOURCES += \ common/QskModule.cpp \ common/QskObjectCounter.cpp \ common/QskSizePolicy.cpp \ + common/QskTextColors.cpp \ common/QskTextOptions.cpp HEADERS += \ @@ -154,7 +156,6 @@ HEADERS += \ controls/QskSkinHintTable.h \ controls/QskSkinlet.h \ controls/QskSkinnable.h \ - controls/QskSkinRenderer.h \ controls/QskSkinTransition.h \ controls/QskSlider.h \ controls/QskSliderSkinlet.h \ @@ -218,7 +219,6 @@ SOURCES += \ controls/QskSkinFactory.cpp \ controls/QskSkinlet.cpp \ controls/QskSkinnable.cpp \ - controls/QskSkinRenderer.cpp \ controls/QskSkinTransition.cpp \ controls/QskSlider.cpp \ controls/QskSliderSkinlet.cpp \