From 610bc48931c82565f8d7f861b1cb7e9b03b7d462 Mon Sep 17 00:00:00 2001 From: Uwe Rathmann Date: Mon, 23 Oct 2017 07:46:46 +0200 Subject: [PATCH] APIs fot creating text nodes changed --- src/controls/QskSkinlet.cpp | 24 ++-- src/controls/QskSkinlet.h | 24 ++-- src/controls/QskTextLabel.cpp | 10 +- src/nodes/QskPlainTextRenderer.cpp | 68 +++------- src/nodes/QskPlainTextRenderer.h | 48 ++----- src/nodes/QskRichTextRenderer.cpp | 195 ++++++++++++++++++++++++++ src/nodes/QskRichTextRenderer.h | 35 +++++ src/nodes/QskTextNode.cpp | 79 +---------- src/nodes/QskTextNode.h | 9 -- src/nodes/QskTextRenderer.cpp | 211 ++++------------------------- src/nodes/QskTextRenderer.h | 45 ++---- src/src.pro | 6 +- 12 files changed, 344 insertions(+), 410 deletions(-) create mode 100644 src/nodes/QskRichTextRenderer.cpp create mode 100644 src/nodes/QskRichTextRenderer.h diff --git a/src/controls/QskSkinlet.cpp b/src/controls/QskSkinlet.cpp index f109bb1b..475ebb8c 100644 --- a/src/controls/QskSkinlet.cpp +++ b/src/controls/QskSkinlet.cpp @@ -59,7 +59,7 @@ static inline QSGNode* qskFindNodeByFlag( QSGNode* parent, int nodeRole ) return nullptr; } -static inline QSGNode* qskUpdateGraphicNode( +static inline QSGNode* qskUpdateGraphicNode( const QskSkinnable* skinnable, QSGNode* node, const QskGraphic& graphic, const QskColorFilter& colorFilter, const QRect& rect ) @@ -101,13 +101,13 @@ static inline QskTextColors qskTextColors( */ QskSkinHintStatus status; - + QskTextColors c; c.textColor = skinnable->color( subControl, &status ); #if 1 if ( !status.isValid() ) c.textColor = skinnable->color( subControl | QskAspect::TextColor ); -#endif +#endif c.styleColor = skinnable->color( subControl | StyleColor ); c.linkColor = skinnable->color( subControl | LinkColor ); @@ -372,7 +372,7 @@ QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, } QSGNode* QskSkinlet::updateBoxNode( const QskSkinnable* skinnable, - QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl ) const + QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl ) { using namespace QskAspect; @@ -411,7 +411,7 @@ QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, } QSGNode* QskSkinlet::updateBoxClipNode( const QskSkinnable* skinnable, - QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl ) const + QSGNode* node, const QRectF& rect, QskAspect::Subcontrol subControl ) { using namespace QskAspect; @@ -445,7 +445,7 @@ QSGNode* QskSkinlet::updateTextNode( const QskSkinnable* skinnable, QSGNode* node, const QRectF& rect, Qt::Alignment alignment, const QString& text, const QskTextOptions& textOptions, - QskAspect::Subcontrol subControl ) const + QskAspect::Subcontrol subControl ) { if ( text.isEmpty() || rect.isEmpty() ) return nullptr; @@ -510,9 +510,9 @@ QSGNode* QskSkinlet::updateGraphicNode( const Qt::Alignment alignment = skinnable->flagHint< Qt::Alignment >( subcontrol | QskAspect::Alignment, Qt::AlignCenter ); - + const auto colorFilter = skinnable->effectiveGraphicFilter( subcontrol ); - + return updateGraphicNode( skinnable, node, graphic, colorFilter, rect, alignment ); } @@ -520,7 +520,7 @@ QSGNode* QskSkinlet::updateGraphicNode( QSGNode* QskSkinlet::updateGraphicNode( const QskSkinnable* skinnable, QSGNode* node, const QskGraphic& graphic, const QskColorFilter& colorFilter, - const QRectF& rect, Qt::Alignment alignment ) const + const QRectF& rect, Qt::Alignment alignment ) { if ( graphic.isNull() ) return nullptr; @@ -537,13 +537,13 @@ QSGNode* QskSkinlet::updateGraphicNode( QSGNode* QskSkinlet::updateGraphicNode( const QskSkinnable* skinnable, QSGNode* node, const QskGraphic& graphic, const QskColorFilter& colorFilter, - const QRectF& rect ) const -{ + const QRectF& rect ) +{ if ( graphic.isNull() ) return nullptr; return qskUpdateGraphicNode( skinnable, node, graphic, colorFilter, rect.toAlignedRect() ); -} +} #include "moc_QskSkinlet.cpp" diff --git a/src/controls/QskSkinlet.h b/src/controls/QskSkinlet.h index f600fcb8..bde81ab7 100644 --- a/src/controls/QskSkinlet.h +++ b/src/controls/QskSkinlet.h @@ -66,33 +66,33 @@ protected: QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, QskAspect::Subcontrol ) const; - QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, - const QRectF&, QskAspect::Subcontrol ) const; + static QSGNode* updateBoxNode( const QskSkinnable*, QSGNode*, + const QRectF&, QskAspect::Subcontrol ); QSGNode* updateBoxClipNode( const QskSkinnable*, QSGNode*, QskAspect::Subcontrol ) const; - QSGNode* updateBoxClipNode( const QskSkinnable*, QSGNode*, - const QRectF&, QskAspect::Subcontrol ) const; - - QSGNode* updateTextNode( const QskSkinnable*, QSGNode*, - const QRectF&, Qt::Alignment, const QString&, const QskTextOptions&, - QskAspect::Subcontrol ) const; + static QSGNode* updateBoxClipNode( const QskSkinnable*, QSGNode*, + const QRectF&, QskAspect::Subcontrol ); QSGNode* updateTextNode( const QskSkinnable*, QSGNode*, const QString&, const QskTextOptions&, QskAspect::Subcontrol ) const; + static QSGNode* updateTextNode( const QskSkinnable*, QSGNode*, + const QRectF&, Qt::Alignment, const QString&, const QskTextOptions&, + QskAspect::Subcontrol ); + QSGNode* updateGraphicNode( const QskSkinnable*, QSGNode*, const QskGraphic&, QskAspect::Subcontrol ) const; // keeping the aspect ratio - QSGNode* updateGraphicNode( const QskSkinnable*, QSGNode*, + static QSGNode* updateGraphicNode( const QskSkinnable*, QSGNode*, const QskGraphic&, const QskColorFilter&, - const QRectF&, Qt::Alignment ) const; + const QRectF&, Qt::Alignment ); // stretching to fit - QSGNode* updateGraphicNode( const QskSkinnable*, QSGNode*, - const QskGraphic&, const QskColorFilter&, const QRectF& ) const; + static QSGNode* updateGraphicNode( const QskSkinnable*, QSGNode*, + const QskGraphic&, const QskColorFilter&, const QRectF& ); void insertRemoveNodes( QSGNode* parentNode, QSGNode* oldNode, QSGNode* newNode, int nodeRole ) const; diff --git a/src/controls/QskTextLabel.cpp b/src/controls/QskTextLabel.cpp index 6d38a19c..18d14706 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 "QskTextNode.h" +#include "QskTextRenderer.h" #include #include @@ -173,7 +173,7 @@ QSizeF QskTextLabel::contentsSizeHint() const if ( !m_data->text.isEmpty() ) { const auto font = effectiveFont( Text ); - return QskTextNode::textSize( + return QskTextRenderer::textSize( m_data->text, font, m_data->effectiveOptions() ); } @@ -199,7 +199,8 @@ qreal QskTextLabel::heightForWidth( qreal width ) const } QSizeF size( width, maxHeight ); - size = QskTextNode::textSize( m_data->text, font, size, m_data->effectiveOptions() ); + size = QskTextRenderer::textSize( m_data->text, font, + m_data->effectiveOptions(), size ); return qCeil( size.height() ); } @@ -216,7 +217,8 @@ qreal QskTextLabel::widthForHeight( qreal height ) const const qreal maxWidth = std::numeric_limits< qreal >::max(); QSizeF size( maxWidth, height ); - size = QskTextNode::textSize( m_data->text, font, size, m_data->effectiveOptions() ); + size = QskTextRenderer::textSize( m_data->text, font, + m_data->effectiveOptions(), size ); return qCeil( size.width() ); } diff --git a/src/nodes/QskPlainTextRenderer.cpp b/src/nodes/QskPlainTextRenderer.cpp index 9499d106..90c6010e 100644 --- a/src/nodes/QskPlainTextRenderer.cpp +++ b/src/nodes/QskPlainTextRenderer.cpp @@ -4,8 +4,8 @@ *****************************************************************************/ #include "QskPlainTextRenderer.h" -#include "QskSkinlet.h" #include "QskTextColors.h" +#include "QskTextOptions.h" #include #include @@ -27,45 +27,20 @@ QSK_QT_PRIVATE_END #define GlyphFlag static_cast< QSGNode::Flag >( 0x800 ) -QskPlainTextRenderer::QskPlainTextRenderer(): - m_fontMetrics( m_font ) -{ -} - -QskPlainTextRenderer::~QskPlainTextRenderer() -{ -} - -void QskPlainTextRenderer::setFont( const QFont& font ) -{ - m_font = font; - m_fontMetrics = QFontMetricsF( m_font ); -} - -void QskPlainTextRenderer::setOptions( const QskTextOptions& options ) -{ - m_options = options; -} - -void QskPlainTextRenderer::setAlignment( Qt::Alignment alignment ) -{ - m_alignment = alignment; -} - -QSizeF QskPlainTextRenderer::textSize( const QString& text ) const +QSizeF QskPlainTextRenderer::textSize( const QString& text, + const QFont& font, const QskTextOptions& options ) { // result differs from QskTextRenderer::implicitSizeHint ??? - return textRect( QSizeF( 10e6, 10e6 ), text ).size(); + return textRect( text, font, options, QSizeF( 10e6, 10e6 ) ).size(); } -QRectF QskPlainTextRenderer::textRect( const QSizeF& size, const QString& text ) const +QRectF QskPlainTextRenderer::textRect( const QString& text, + const QFont& font, const QskTextOptions& options, const QSizeF& size ) { - return m_fontMetrics.boundingRect( { QPointF(), size }, flags(), text ); -} + const QFontMetricsF fm( font ); + const QRect r( 0, 0, size.width(), size.height() ); -int QskPlainTextRenderer::flags() const -{ - return m_options.textFlags() | m_alignment; + return fm.boundingRect( r, options.textFlags(), text ); } static qreal qskLayoutText( QTextLayout* layout, const QPointF& position, qreal lineWidth, @@ -177,39 +152,32 @@ static void qskRenderText( } void QskPlainTextRenderer::updateNode( const QString& text, - const QRectF& rect, Qsk::TextStyle style, const QskTextColors& colors, + const QFont& font, const QskTextOptions& options, + Qsk::TextStyle style, const QskTextColors& colors, + Qt::Alignment alignment, const QRectF& rect, const QQuickItem* item, QSGTransformNode* node ) { - QTextOption textOption( m_alignment ); - textOption.setWrapMode( static_cast< QTextOption::WrapMode >( m_options.wrapMode() ) ); + QTextOption textOption( alignment ); + textOption.setWrapMode( static_cast< QTextOption::WrapMode >( options.wrapMode() ) ); QTextLayout layout; - layout.setFont( m_font ); + layout.setFont( font ); layout.setTextOption( textOption ); layout.setText( text ); layout.beginLayout(); QPointF position; - position.ry() += qskLayoutText( &layout, position, rect.width(), m_options ); + position.ry() += qskLayoutText( &layout, position, rect.width(), options ); layout.endLayout(); position.setX( 0 ); - position.setY( m_fontMetrics.ascent() - + ( m_alignment & Qt::AlignVCenter - ? ( rect.height() - position.y() ) * 0.5 : 0 ) ); + position.setY( QFontMetricsF( font ).ascent() + + ( alignment & Qt::AlignVCenter ? ( rect.height() - position.y() ) * 0.5 : 0 ) ); 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, Qsk::TextStyle style, const QColor& styleColor ) { diff --git a/src/nodes/QskPlainTextRenderer.h b/src/nodes/QskPlainTextRenderer.h index 6b1e8cc4..0a5140c1 100644 --- a/src/nodes/QskPlainTextRenderer.h +++ b/src/nodes/QskPlainTextRenderer.h @@ -8,50 +8,32 @@ #include "QskGlobal.h" #include "QskNamespace.h" -#include "QskTextOptions.h" - -#include -#include +#include class QskTextColors; +class QskTextOptions; -class QSGNode; +class QString; +class QFont; +class QRectF; +class QSizeF; class QQuickItem; class QColor; class QSGTransformNode; -class QQuickItem; +class QSGNode; -class QSK_EXPORT QskPlainTextRenderer +namespace QskPlainTextRenderer { -public: - QskPlainTextRenderer(); - ~QskPlainTextRenderer(); - - void setFont( const QFont& ); - void setOptions( const QskTextOptions& ); - void setAlignment( Qt::Alignment ); - - void updateNode( const QString&, const QSizeF&, - Qsk::TextStyle, const QskTextColors&, + QSK_EXPORT void updateNode( const QString&, const QFont&, const QskTextOptions&, + Qsk::TextStyle, const QskTextColors&, Qt::Alignment, const QRectF&, const QQuickItem*, QSGTransformNode* ); - void updateNode( const QString&, const QRectF&, - Qsk::TextStyle, const QskTextColors&, - const QQuickItem*, QSGTransformNode* ); - - static void updateNodeColor( QSGNode* parentNode, + QSK_EXPORT void updateNodeColor( QSGNode* parentNode, const QColor& textColor, Qsk::TextStyle, const QColor& styleColor ); - QSizeF textSize( const QString& ) const; - QRectF textRect( const QSizeF&, const QString& ) const; - -private: - int flags() const; - - QFont m_font; - QFontMetricsF m_fontMetrics; - QskTextOptions m_options; - Qt::Alignment m_alignment; -}; + QSK_EXPORT QSizeF textSize( const QString&, const QFont&, const QskTextOptions& ); + QSK_EXPORT QRectF textRect( const QString&, const QFont&, + const QskTextOptions&, const QSizeF& ); +} #endif diff --git a/src/nodes/QskRichTextRenderer.cpp b/src/nodes/QskRichTextRenderer.cpp new file mode 100644 index 00000000..96189e64 --- /dev/null +++ b/src/nodes/QskRichTextRenderer.cpp @@ -0,0 +1,195 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#include "QskRichTextRenderer.h" +#include "QskTextColors.h" +#include "QskTextOptions.h" + +#include + +QSK_QT_PRIVATE_BEGIN +#include +#include +QSK_QT_PRIVATE_END + +#include + +namespace +{ + class TextItem final : public QQuickText + { + public: + TextItem() + { + // fonts are supposed to be defined in the application skin and we + // probably don't want to have them scaled + setFontSizeMode( QQuickText::FixedSize ); + +#if 0 + setAntialiasing( true ); + setRenderType( QQuickText::QtRendering ); + setPadding( 0 ); + + setMinimumPixelSize(); + setMinimumPointSize(); + + // also something, that should be defined in an application skin + setLineHeightMode( ... ); + setLineHeight(); +#endif + } + + inline void setAlignment( Qt::Alignment alignment ) + { + setHAlign( ( QQuickText::HAlignment ) ( int( alignment ) & 0x0f ) ); + setVAlign( ( QQuickText::VAlignment ) ( int( alignment ) & 0xf0 ) ); + } + + inline void setOptions( const QskTextOptions& options ) + { + // what about Qt::TextShowMnemonic ??? + setTextFormat( ( QQuickText::TextFormat ) options.format() ); + setElideMode( ( QQuickText::TextElideMode ) options.elideMode() ); + setMaximumLineCount( options.maximumLineCount() ); + setWrapMode( static_cast< QQuickText::WrapMode >( options.wrapMode() ) ); + } + + void refWindow( QQuickWindow* window ); + void derefWindow(); + + void begin() { classBegin(); } + void end() { componentComplete(); } + + QRectF layedOutTextRect() const + { + auto that = const_cast< TextItem* >( 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 + { + Q_ASSERT( false ); + 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 + being sent, that leads to crashes because of it + */ +static TextItem* qskRenderHelper = nullptr; +static TextItem* qskLayoutHelper = nullptr; + +QSizeF QskRichTextRenderer::textSize( const QString& text, + const QFont& font, const QskTextOptions& options ) +{ + if ( qskLayoutHelper == NULL ) + qskLayoutHelper = new TextItem(); + + auto& item = *qskLayoutHelper; + + item.begin(); + + item.setFont( font ); + item.setOptions( options ); + + item.setWidth( -1 ); + item.setText( text ); + + item.end(); + + return QSizeF( item.implicitWidth(), item.implicitHeight() ); +} + +QRectF QskRichTextRenderer::textRect( const QString& text, + const QFont& font, const QskTextOptions& options, const QSizeF& size ) +{ + if ( qskLayoutHelper == NULL ) + qskLayoutHelper = new TextItem(); + + auto& textItem = *qskLayoutHelper; + + textItem.begin(); + + textItem.setFont( font ); + textItem.setOptions( options ); + textItem.setAlignment( Qt::Alignment() ); + + textItem.setWidth( size.width() ); + textItem.setHeight( size.height() ); + + textItem.setText( text ); + + textItem.end(); + + return textItem.layedOutTextRect(); +} + +void QskRichTextRenderer::updateNode( const QString& text, + const QFont& font, const QskTextOptions& options, + Qsk::TextStyle style, const QskTextColors& colors, + Qt::Alignment alignment, const QRectF& rect, + const QQuickItem* item, QSGTransformNode* node ) +{ + // are we killing internal caches of QQuickText, when always using + // the same item for the creation the text nodes. TODO ... + + if ( qskRenderHelper == NULL ) + qskRenderHelper = new TextItem(); + + auto& textItem = *qskRenderHelper; + + textItem.begin(); + + textItem.setFont( font ); + textItem.setOptions( options ); + textItem.setAlignment( alignment ); + +#if 0 + // the position of textItem seems to have no effect + // on the position of the node. We do it by translation later. + + textItem.setX( rect.x() ); + textItem.setY( rect.y() ); +#endif + + if ( rect.width() != item->width() || + rect.height() != item->height() ) + { + textItem.setWidth( rect.width() ); + textItem.setHeight( rect.height() ); + textItem.doLayout(); + } + + textItem.setColor( colors.textColor ); + textItem.setStyle( static_cast< QQuickText::TextStyle >( style ) ); + textItem.setStyleColor( colors.styleColor ); + textItem.setLinkColor( colors.linkColor ); + + textItem.setText( text ); + + textItem.end(); + + textItem.updateTextNode( item->window(), node ); + textItem.setText( QString::null ); +} diff --git a/src/nodes/QskRichTextRenderer.h b/src/nodes/QskRichTextRenderer.h new file mode 100644 index 00000000..63c668b2 --- /dev/null +++ b/src/nodes/QskRichTextRenderer.h @@ -0,0 +1,35 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the QSkinny License, Version 1.0 + *****************************************************************************/ + +#ifndef QSK_RICH_TEXT_RENDERER_H +#define QSK_RICH_TEXT_RENDERER_H + +#include "QskGlobal.h" +#include "QskNamespace.h" +#include + +class QskTextColors; +class QskTextOptions; + +class QString; +class QFont; +class QRectF; +class QSizeF; +class QQuickItem; +class QSGTransformNode; + +namespace QskRichTextRenderer +{ + QSK_EXPORT void updateNode( const QString&, const QFont&, const QskTextOptions&, + Qsk::TextStyle, const QskTextColors&, Qt::Alignment, const QRectF&, + const QQuickItem*, QSGTransformNode* ); + + QSK_EXPORT QSizeF textSize( const QString&, const QFont&, const QskTextOptions& ); + + QSK_EXPORT QRectF textRect( const QString&, const QFont&, + const QskTextOptions&, const QSizeF& ); +} + +#endif diff --git a/src/nodes/QskTextNode.cpp b/src/nodes/QskTextNode.cpp index 3939b862..a7ec825d 100644 --- a/src/nodes/QskTextNode.cpp +++ b/src/nodes/QskTextNode.cpp @@ -7,7 +7,6 @@ #include "QskTextOptions.h" #include "QskTextColors.h" #include "QskTextRenderer.h" -#include "QskPlainTextRenderer.h" #include #include @@ -64,75 +63,11 @@ void QskTextNode::setTextData( const QQuickItem* item, 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 ); - } + /* + In case of having color changes only we would could + go a faster update path: see QskPlainTextRenderer::updateNodeColor. + TODO ... + */ + QskTextRenderer::updateNode( text, font, options, textStyle, + colors, alignment, textRect, 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 96492b02..8dc0ce0a 100644 --- a/src/nodes/QskTextNode.h +++ b/src/nodes/QskTextNode.h @@ -29,15 +29,6 @@ public: 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 a699da77..7f8bf1d3 100644 --- a/src/nodes/QskTextRenderer.cpp +++ b/src/nodes/QskTextRenderer.cpp @@ -4,201 +4,44 @@ *****************************************************************************/ #include "QskTextRenderer.h" -#include "QskTextColors.h" +#include "QskRichTextRenderer.h" +#include "QskPlainTextRenderer.h" +#include "QskTextOptions.h" -#include +#include -QSK_QT_PRIVATE_BEGIN -#include -#include -QSK_QT_PRIVATE_END - -#include - -class QskTextHelperItem final : public QQuickText +QSizeF QskTextRenderer::textSize( const QString& text, + const QFont& font, const QskTextOptions& options ) { -public: - void refWindow( QQuickWindow* window ); - void derefWindow(); - - void begin() { classBegin(); } - void end() { componentComplete(); } - - 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 - { - // 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 - being sent, that leads to crashes because of it - */ -static QskTextHelperItem* qskRenderHelper = nullptr; -static QskTextHelperItem* qskLayoutHelper = nullptr; - -void QskTextRenderer::setFont( const QFont& font ) -{ - m_font = font; + if ( options.effectiveFormat( text ) == QskTextOptions::PlainText ) + return QskPlainTextRenderer::textSize( text, font, options ); + else + return QskRichTextRenderer::textSize( text, font, options ); } -void QskTextRenderer::setOptions( const QskTextOptions& options ) +QSizeF QskTextRenderer::textSize( const QString& text, + const QFont& font, const QskTextOptions& options, const QSizeF& size ) { - m_options = options; -} - -void QskTextRenderer::setAlignment( Qt::Alignment alignment ) -{ - m_alignment = alignment; -} - -QSizeF QskTextRenderer::textSize( const QString& text ) const -{ - if ( qskLayoutHelper == NULL ) - qskLayoutHelper = new QskTextHelperItem(); - - QskTextHelperItem& textItem = *qskLayoutHelper; - - textItem.begin(); - - setupItem( &textItem ); - - textItem.setWidth( -1 ); - textItem.setText( text ); - - textItem.end(); - - return QSizeF( textItem.implicitWidth(), textItem.implicitHeight() ); -} - -QRectF QskTextRenderer::textRect( const QSizeF& size, const QString& text ) const -{ - if ( qskLayoutHelper == NULL ) - qskLayoutHelper = new QskTextHelperItem(); - - QskTextHelperItem& textItem = *qskLayoutHelper; - - textItem.begin(); - - setupItem( &textItem ); - - textItem.setWidth( size.width() ); - textItem.setHeight( size.height() ); - - textItem.setText( text ); - - textItem.end(); - - return textItem.layedOutTextRect(); -} - -void QskTextRenderer::setupItem( QskTextHelperItem* textItem ) const -{ -#if 0 - textItem->setAntialiasing( true ); - textItem->setRenderType( QQuickText::QtRendering ); - textItem->setPadding( 0 ); -#endif - - textItem->setHAlign( ( QQuickText::HAlignment ) ( int( m_alignment ) & 0x0f ) ); - textItem->setVAlign( ( QQuickText::VAlignment ) ( int( m_alignment ) & 0xf0 ) ); - - // fonts are supposed to be defined in the application skin and we - // probably don't want to have them scaled - textItem->setFont( m_font ); - textItem->setFontSizeMode( QQuickText::FixedSize ); - -#if 0 - textItem->setMinimumPixelSize(); - textItem->setMinimumPointSize(); -#endif - - textItem->setTextFormat( ( QQuickText::TextFormat ) m_options.format() ); - textItem->setElideMode( ( QQuickText::TextElideMode ) m_options.elideMode() ); - textItem->setMaximumLineCount( m_options.maximumLineCount() ); - textItem->setWrapMode( static_cast< QQuickText::WrapMode >( m_options.wrapMode() ) ); - - // what about Qt::TextShowMnemonic ??? - -#if 0 - // also something, that should be defined in an application skin - textItem->setLineHeightMode( ... ); - textItem->setLineHeight(); -#endif + if ( options.effectiveFormat( text ) == QskTextOptions::PlainText ) + return QskPlainTextRenderer::textRect( text, font, options, size ).size(); + else + return QskRichTextRenderer::textRect( text, font, options, size ).size(); } void QskTextRenderer::updateNode( const QString& text, - const QRectF& rect, Qsk::TextStyle style, const QskTextColors& colors, + const QFont& font, const QskTextOptions& options, + Qsk::TextStyle style, const QskTextColors& colors, + Qt::Alignment alignment, const QRectF& rect, const QQuickItem* item, QSGTransformNode* node ) { - // are we killing internal caches of QQuickText, when always using - // the same item for the creation the text nodes. TODO ... - - if ( qskRenderHelper == NULL ) - qskRenderHelper = new QskTextHelperItem(); - - QskTextHelperItem& textItem = *qskRenderHelper; - - textItem.begin(); - - setupItem( &textItem ); - -#if 0 - // the position of textItem seems to have no effect - // on the position of the node. We do it by translation later. - - textItem.setX( rect.x() ); - textItem.setY( rect.y() ); -#endif - - if ( rect.width() != textItem.width() || - rect.height() != textItem.height() ) + if ( options.format() == QskTextOptions::PlainText ) { - textItem.setWidth( rect.width() ); - textItem.setHeight( rect.height() ); - textItem.doLayout(); + QskPlainTextRenderer::updateNode( text, font, options, style, + colors, alignment, rect, item, node ); + } + else + { + QskRichTextRenderer::updateNode( text, font, options, style, + colors, alignment, rect, item, node ); } - - textItem.setColor( colors.textColor ); - textItem.setStyle( static_cast< QQuickText::TextStyle >( style ) ); - textItem.setStyleColor( colors.styleColor ); - textItem.setLinkColor( colors.linkColor ); - - textItem.setText( text ); - - textItem.end(); - - 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 e64f03ae..25caaede 100644 --- a/src/nodes/QskTextRenderer.h +++ b/src/nodes/QskTextRenderer.h @@ -8,47 +8,28 @@ #include "QskGlobal.h" #include "QskNamespace.h" -#include "QskTextOptions.h" +#include -#include -#include - -class QskTextHelperItem; class QskTextColors; +class QskTextOptions; +class QString; +class QFont; +class QRectF; +class QSizeF; class QQuickItem; -class QQuickWindow; class QSGTransformNode; -class QColor; -// Hacking a QQuickTextNode using a QQuickText helper item -// How to create the nodes in a better way needs further -// investigations - -class QSK_EXPORT QskTextRenderer +namespace QskTextRenderer { -public: - void setFont( const QFont& font ); - void setOptions( const QskTextOptions& ); - void setAlignment( Qt::Alignment ); - - void updateNode( const QString&, const QSizeF&, - Qsk::TextStyle, const QskTextColors&, + QSK_EXPORT void updateNode( const QString&, const QFont&, const QskTextOptions&, + Qsk::TextStyle, const QskTextColors&, Qt::Alignment, const QRectF&, const QQuickItem*, QSGTransformNode* ); - void updateNode( const QString&, const QRectF&, - Qsk::TextStyle, const QskTextColors&, - const QQuickItem*, QSGTransformNode* ); + QSK_EXPORT QSizeF textSize( const QString&, const QFont&, const QskTextOptions& ); - QSizeF textSize( const QString& ) const; - QRectF textRect( const QSizeF&, const QString& ) const; - -private: - void setupItem( QskTextHelperItem* ) const; - - QFont m_font; - QskTextOptions m_options; - Qt::Alignment m_alignment; -}; + QSK_EXPORT QSizeF textSize( const QString&, const QFont&, + const QskTextOptions&, const QSizeF& ); +} #endif diff --git a/src/src.pro b/src/src.pro index a0808ab3..c5788d1f 100644 --- a/src/src.pro +++ b/src/src.pro @@ -93,8 +93,9 @@ HEADERS += \ nodes/QskBoxRendererColorMap.h \ nodes/QskGraphicNode.h \ nodes/QskPlainTextRenderer.h \ - nodes/QskTextNode.h \ + nodes/QskRichTextRenderer.h \ nodes/QskTextRenderer.h \ + nodes/QskTextNode.h \ nodes/QskTextureNode.h \ nodes/QskVertex.h @@ -106,8 +107,9 @@ SOURCES += \ nodes/QskBoxRendererDEllipse.cpp \ nodes/QskGraphicNode.cpp \ nodes/QskPlainTextRenderer.cpp \ - nodes/QskTextNode.cpp \ + nodes/QskRichTextRenderer.cpp \ nodes/QskTextRenderer.cpp \ + nodes/QskTextNode.cpp \ nodes/QskTextureNode.cpp \ nodes/QskVertex.cpp