qskinny/src/nodes/QskRichTextRenderer.cpp

225 lines
6.4 KiB
C++
Raw Normal View History

2017-10-23 07:46:46 +02:00
/******************************************************************************
* 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 <QQuickWindow>
2017-12-01 09:33:13 +01:00
#include <QGlobalStatic>
2017-10-23 07:46:46 +02:00
QSK_QT_PRIVATE_BEGIN
#include <private/qquicktext_p.h>
#include <private/qquicktext_p_p.h>
QSK_QT_PRIVATE_END
#include <limits>
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
}
2018-01-05 09:36:55 +01:00
inline void setGeometry( const QRectF& rect )
{
auto d = QQuickTextPrivate::get( this );
d->heightValid = true;
d->widthValid = true;
if ( ( d->x != rect.x() ) || ( d->y != rect.y() ) )
{
d->x = rect.x();
d->y = rect.y();
d->dirty( QQuickItemPrivate::Position );
}
if ( ( d->width != rect.width() ) || ( d->height != rect.height() ) )
{
d->height = rect.height();
d->width = rect.width();
d->dirty( QQuickItemPrivate::Size );
}
}
2017-10-23 07:46:46 +02:00
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() ) );
}
2018-01-05 09:36:55 +01:00
void begin()
{
classBegin();
QQuickTextPrivate::get( this )->updateOnComponentComplete = true;
}
void end()
{
componentComplete();
}
2017-10-23 07:46:46 +02:00
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() )
2018-01-05 09:36:55 +01:00
delete parentNode->firstChild();
2017-10-23 07:46:46 +02:00
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
*/
2017-12-01 09:33:13 +01:00
Q_GLOBAL_STATIC( TextItem, qskRenderHelper )
Q_GLOBAL_STATIC( TextItem, qskLayoutHelper )
2017-10-23 07:46:46 +02:00
QSizeF QskRichTextRenderer::textSize( const QString& text,
const QFont& font, const QskTextOptions& options )
{
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 )
{
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
2018-01-05 09:36:55 +01:00
// the same item for the creation the text nodes. TODO ...
2017-10-23 07:46:46 +02:00
auto& textItem = *qskRenderHelper;
textItem.begin();
2018-01-05 09:36:55 +01:00
textItem.setGeometry( rect );
textItem.setBottomPadding( 0 );
textItem.setTopPadding( 0 );
2017-10-23 07:46:46 +02:00
textItem.setFont( font );
textItem.setOptions( options );
textItem.setAlignment( alignment );
textItem.setColor( colors.textColor );
textItem.setStyle( static_cast< QQuickText::TextStyle >( style ) );
textItem.setStyleColor( colors.styleColor );
textItem.setLinkColor( colors.linkColor );
textItem.setText( text );
textItem.end();
if ( alignment & Qt::AlignVCenter )
{
/*
We need to have a stable algo for rounding the text base line,
so that texts don't start wobbling, when processing transitions
between margins/paddings. We manipulate the layout code
2018-01-05 09:36:55 +01:00
by adding some padding, so that the position of base line
gets always floored.
*/
auto d = QQuickTextPrivate::get( &textItem );
const qreal h = d->layedOutTextRect.height() + d->lineHeightOffset();
if ( static_cast< int >( rect.height() - h ) % 2 )
{
2018-01-05 09:36:55 +01:00
if ( static_cast< int >( h ) % 2 )
d->extra.value().bottomPadding = 1;
else
d->extra.value().topPadding = 1;
}
}
2017-10-23 07:46:46 +02:00
textItem.updateTextNode( item->window(), node );
textItem.setText( QString::null );
}