diff --git a/src/core/layout/qgslayoutitem.cpp b/src/core/layout/qgslayoutitem.cpp index d449749fa89..da1e78fc25d 100644 --- a/src/core/layout/qgslayoutitem.cpp +++ b/src/core/layout/qgslayoutitem.cpp @@ -20,6 +20,8 @@ #include #include +#define CACHE_SIZE_LIMIT 5000 + QgsLayoutItem::QgsLayoutItem( QgsLayout *layout ) : QgsLayoutObject( layout ) , QGraphicsRectItem( 0 ) @@ -44,23 +46,89 @@ void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *it } //TODO - remember to disable saving/restoring on graphics view!! - painter->save(); - preparePainter( painter ); if ( shouldDrawDebugRect() ) { drawDebugRect( painter ); + return; + } + + double destinationDpi = itemStyle->matrix.m11() * 25.4; + bool useImageCache = true; + + if ( useImageCache ) + { + double widthInPixels = boundingRect().width() * itemStyle->matrix.m11(); + double heightInPixels = boundingRect().height() * itemStyle->matrix.m11(); + + // limit size of image for better performance + double scale = 1.0; + if ( widthInPixels > CACHE_SIZE_LIMIT || heightInPixels > CACHE_SIZE_LIMIT ) + { + if ( widthInPixels > heightInPixels ) + { + scale = widthInPixels / CACHE_SIZE_LIMIT; + widthInPixels = CACHE_SIZE_LIMIT; + heightInPixels /= scale; + } + else + { + scale = heightInPixels / CACHE_SIZE_LIMIT; + heightInPixels = CACHE_SIZE_LIMIT; + widthInPixels /= scale; + } + destinationDpi = destinationDpi / scale; + } + + if ( !mItemCachedImage.isNull() && qgsDoubleNear( mItemCacheDpi, destinationDpi ) ) + { + // can reuse last cached image + QgsRenderContext context = QgsLayoutUtils::createRenderContextForMap( nullptr, painter, destinationDpi ); + painter->save(); + preparePainter( painter ); + double cacheScale = destinationDpi / mItemCacheDpi; + painter->scale( cacheScale / context.scaleFactor(), cacheScale / context.scaleFactor() ); + painter->drawImage( boundingRect().x() * context.scaleFactor() / cacheScale, + boundingRect().y() * context.scaleFactor() / cacheScale, mItemCachedImage ); + painter->restore(); + return; + } + else + { + mItemCacheDpi = destinationDpi; + + mItemCachedImage = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 ); + mItemCachedImage.fill( Qt::transparent ); + mItemCachedImage.setDotsPerMeterX( 1000 * destinationDpi * 25.4 ); + mItemCachedImage.setDotsPerMeterY( 1000 * destinationDpi * 25.4 ); + QPainter p( &mItemCachedImage ); + + preparePainter( &p ); + QgsRenderContext context = QgsLayoutUtils::createRenderContextForMap( nullptr, &p, destinationDpi ); + // painter is already scaled to dots + // need to translate so that item origin is at 0,0 in painter coordinates (not bounding rect origin) + p.translate( -boundingRect().x() * context.scaleFactor(), -boundingRect().y() * context.scaleFactor() ); + draw( context, itemStyle ); + p.end(); + + painter->save(); + // scale painter from mm to dots + painter->scale( 1.0 / context.scaleFactor(), 1.0 / context.scaleFactor() ); + painter->drawImage( boundingRect().x() * context.scaleFactor(), + boundingRect().y() * context.scaleFactor(), mItemCachedImage ); + painter->restore(); + } } else { - double destinationDpi = itemStyle->matrix.m11() * 25.4; + // no caching or flattening + painter->save(); QgsRenderContext context = QgsLayoutUtils::createRenderContextForMap( nullptr, painter, destinationDpi ); // scale painter from mm to dots painter->scale( 1.0 / context.scaleFactor(), 1.0 / context.scaleFactor() ); draw( context, itemStyle ); + painter->restore(); } - - painter->restore(); } void QgsLayoutItem::setReferencePoint( const QgsLayoutItem::ReferencePoint &point ) diff --git a/src/core/layout/qgslayoutitem.h b/src/core/layout/qgslayoutitem.h index 3e70bfabbd4..537b89529f6 100644 --- a/src/core/layout/qgslayoutitem.h +++ b/src/core/layout/qgslayoutitem.h @@ -252,6 +252,9 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt QgsLayoutPoint mItemPosition; double mItemRotation = 0.0; + QImage mItemCachedImage; + double mItemCacheDpi = -1; + void initConnectionsToLayout(); //! Prepares a painter by setting rendering flags diff --git a/src/core/layout/qgslayoutitemregistry.cpp b/src/core/layout/qgslayoutitemregistry.cpp index 5d5e8f81086..08683ef7e38 100644 --- a/src/core/layout/qgslayoutitemregistry.cpp +++ b/src/core/layout/qgslayoutitemregistry.cpp @@ -95,6 +95,16 @@ TestLayoutItem::TestLayoutItem( QgsLayout *layout ) int s = ( qrand() % ( 200 - 100 + 1 ) ) + 100; int v = ( qrand() % ( 130 - 255 + 1 ) ) + 130; mColor = QColor::fromHsv( h, s, v ); + + QgsStringMap properties; + properties.insert( QStringLiteral( "color" ), mColor.name() ); + properties.insert( QStringLiteral( "style" ), QStringLiteral( "solid" ) ); + properties.insert( QStringLiteral( "style_border" ), QStringLiteral( "solid" ) ); + properties.insert( QStringLiteral( "color_border" ), QStringLiteral( "black" ) ); + properties.insert( QStringLiteral( "width_border" ), QStringLiteral( "0.3" ) ); + properties.insert( QStringLiteral( "joinstyle" ), QStringLiteral( "miter" ) ); + mShapeStyleSymbol = QgsFillSymbol::createSimple( properties ); + } void TestLayoutItem::draw( QgsRenderContext &context, const QStyleOptionGraphicsItem *itemStyle ) @@ -114,9 +124,15 @@ void TestLayoutItem::draw( QgsRenderContext &context, const QStyleOptionGraphics painter->setBrush( mColor ); double scale = context.convertToPainterUnits( 1, QgsUnitTypes::RenderMillimeters ); - QRectF r = QRectF( rect().left() * scale, rect().top() * scale, - rect().width() * scale, rect().height() * scale ); - painter->drawRect( r ); + + QPolygonF shapePolygon = QPolygonF( QRectF( 0, 0, rect().width() * scale, rect().height() * scale ) ); + QList rings; //empty list + + mShapeStyleSymbol->startRender( context ); + mShapeStyleSymbol->renderPolygon( shapePolygon, &rings, nullptr, context ); + mShapeStyleSymbol->stopRender( context ); + +// painter->drawRect( r ); painter->restore(); stack.end( context ); } diff --git a/src/core/layout/qgslayoutitemregistry.h b/src/core/layout/qgslayoutitemregistry.h index a2cda2eb7e7..c4abaae1952 100644 --- a/src/core/layout/qgslayoutitemregistry.h +++ b/src/core/layout/qgslayoutitemregistry.h @@ -29,6 +29,7 @@ class QgsLayout; class QgsLayoutView; class QgsLayoutItem; +class QgsFillSymbol; /** * \ingroup core @@ -271,8 +272,10 @@ class TestLayoutItem : public QgsLayoutItem private: QColor mColor; + QgsFillSymbol *mShapeStyleSymbol = nullptr; }; + ///@endcond #endif diff --git a/src/gui/layout/qgslayoutviewtooladditem.cpp b/src/gui/layout/qgslayoutviewtooladditem.cpp index 497924aa1a1..b4634fbb530 100644 --- a/src/gui/layout/qgslayoutviewtooladditem.cpp +++ b/src/gui/layout/qgslayoutviewtooladditem.cpp @@ -86,7 +86,8 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even Q_UNUSED( clickOnly ); QgsLayoutItem *item = QgsApplication::layoutItemRegistry()->createItem( mItemType, layout() ); - item->setRect( rect ); + item->attemptResize( QgsLayoutSize( rect.width(), rect.height(), QgsUnitTypes::LayoutMillimeters ) ); + item->attemptMove( QgsLayoutPoint( rect.left(), rect.top(), QgsUnitTypes::LayoutMillimeters ) ); layout()->addItem( item ); }