LCOV - code coverage report
Current view: top level - core/layout - qgslayoutitem.cpp (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 0 871 0.0 %
Date: 2021-04-10 08:29:14 Functions: 0 0 -
Branches: 0 0 -

           Branch data     Line data    Source code
       1                 :            : /***************************************************************************
       2                 :            :                               qgslayoutitem.cpp
       3                 :            :                              -------------------
       4                 :            :     begin                : June 2017
       5                 :            :     copyright            : (C) 2017 by Nyall Dawson
       6                 :            :     email                : nyall dot dawson at gmail dot com
       7                 :            :  ***************************************************************************/
       8                 :            : /***************************************************************************
       9                 :            :  *                                                                         *
      10                 :            :  *   This program is free software; you can redistribute it and/or modify  *
      11                 :            :  *   it under the terms of the GNU General Public License as published by  *
      12                 :            :  *   the Free Software Foundation; either version 2 of the License, or     *
      13                 :            :  *   (at your option) any later version.                                   *
      14                 :            :  *                                                                         *
      15                 :            :  ***************************************************************************/
      16                 :            : 
      17                 :            : #include "qgslayoutitem.h"
      18                 :            : #include "qgslayout.h"
      19                 :            : #include "qgslayoututils.h"
      20                 :            : #include "qgspagesizeregistry.h"
      21                 :            : #include "qgslayoutitemundocommand.h"
      22                 :            : #include "qgslayoutmodel.h"
      23                 :            : #include "qgssymbollayerutils.h"
      24                 :            : #include "qgslayoutitemgroup.h"
      25                 :            : #include "qgspainting.h"
      26                 :            : #include "qgslayouteffect.h"
      27                 :            : #include "qgslayoutundostack.h"
      28                 :            : #include "qgslayoutpagecollection.h"
      29                 :            : #include "qgslayoutitempage.h"
      30                 :            : #include "qgsimageoperation.h"
      31                 :            : #include "qgsexpressioncontextutils.h"
      32                 :            : 
      33                 :            : #include <QPainter>
      34                 :            : #include <QStyleOptionGraphicsItem>
      35                 :            : #include <QUuid>
      36                 :            : 
      37                 :            : #define CACHE_SIZE_LIMIT 5000
      38                 :            : 
      39                 :          0 : QgsLayoutItemRenderContext::QgsLayoutItemRenderContext( QgsRenderContext &context, double viewScaleFactor )
      40                 :          0 :   : mRenderContext( context )
      41                 :          0 :   , mViewScaleFactor( viewScaleFactor )
      42                 :            : {
      43                 :          0 : }
      44                 :            : 
      45                 :            : 
      46                 :            : 
      47                 :          0 : QgsLayoutItem::QgsLayoutItem( QgsLayout *layout, bool manageZValue )
      48                 :          0 :   : QgsLayoutObject( layout )
      49                 :          0 :   , QGraphicsRectItem( nullptr )
      50                 :          0 :   , mUuid( QUuid::createUuid().toString() )
      51                 :          0 : {
      52                 :          0 :   setZValue( QgsLayout::ZItem );
      53                 :            : 
      54                 :            :   // needed to access current view transform during paint operations
      55                 :          0 :   setFlags( flags() | QGraphicsItem::ItemUsesExtendedStyleOption | QGraphicsItem::ItemIsSelectable );
      56                 :            : 
      57                 :          0 :   setCacheMode( QGraphicsItem::DeviceCoordinateCache );
      58                 :            : 
      59                 :            :   //record initial position
      60                 :          0 :   QgsUnitTypes::LayoutUnit initialUnits = layout ? layout->units() : QgsUnitTypes::LayoutMillimeters;
      61                 :          0 :   mItemPosition = QgsLayoutPoint( scenePos().x(), scenePos().y(), initialUnits );
      62                 :          0 :   mItemSize = QgsLayoutSize( rect().width(), rect().height(), initialUnits );
      63                 :            : 
      64                 :            :   // required to initially setup background/frame style
      65                 :          0 :   refreshBackgroundColor( false );
      66                 :          0 :   refreshFrame( false );
      67                 :            : 
      68                 :          0 :   initConnectionsToLayout();
      69                 :            : 
      70                 :            :   //let z-Value be managed by layout
      71                 :          0 :   if ( mLayout && manageZValue )
      72                 :            :   {
      73                 :          0 :     mLayoutManagesZValue = true;
      74                 :          0 :     mLayout->itemsModel()->addItemAtTop( this );
      75                 :          0 :   }
      76                 :            :   else
      77                 :            :   {
      78                 :          0 :     mLayoutManagesZValue = false;
      79                 :            :   }
      80                 :            : 
      81                 :            :   // Setup layout effect
      82                 :          0 :   mEffect.reset( new QgsLayoutEffect() );
      83                 :          0 :   if ( mLayout )
      84                 :            :   {
      85                 :          0 :     mEffect->setEnabled( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagUseAdvancedEffects );
      86                 :          0 :     connect( &mLayout->renderContext(), &QgsLayoutRenderContext::flagsChanged, this, [ = ]( QgsLayoutRenderContext::Flags flags )
      87                 :            :     {
      88                 :          0 :       mEffect->setEnabled( flags & QgsLayoutRenderContext::FlagUseAdvancedEffects );
      89                 :          0 :     } );
      90                 :          0 :   }
      91                 :          0 :   setGraphicsEffect( mEffect.get() );
      92                 :          0 : }
      93                 :            : 
      94                 :          0 : QgsLayoutItem::~QgsLayoutItem()
      95                 :          0 : {
      96                 :          0 :   cleanup();
      97                 :          0 : }
      98                 :            : 
      99                 :          0 : void QgsLayoutItem::cleanup()
     100                 :            : {
     101                 :          0 :   if ( mLayout && mLayoutManagesZValue )
     102                 :            :   {
     103                 :          0 :     mLayout->itemsModel()->removeItem( this );
     104                 :          0 :   }
     105                 :          0 : }
     106                 :            : 
     107                 :          0 : QString QgsLayoutItem::displayName() const
     108                 :            : {
     109                 :            :   //return id, if it's not empty
     110                 :          0 :   if ( !id().isEmpty() )
     111                 :            :   {
     112                 :          0 :     return id();
     113                 :            :   }
     114                 :            : 
     115                 :            :   //for unnamed items, default to item type
     116                 :          0 :   if ( QgsLayoutItemAbstractMetadata *metadata = QgsApplication::layoutItemRegistry()->itemMetadata( type() ) )
     117                 :            :   {
     118                 :          0 :     return tr( "<%1>" ).arg( metadata->visibleName() );
     119                 :            :   }
     120                 :            : 
     121                 :          0 :   return tr( "<item>" );
     122                 :          0 : }
     123                 :            : 
     124                 :          0 : int QgsLayoutItem::type() const
     125                 :            : {
     126                 :          0 :   return QgsLayoutItemRegistry::LayoutItem;
     127                 :            : }
     128                 :            : 
     129                 :          0 : QgsLayoutItem::Flags QgsLayoutItem::itemFlags() const
     130                 :            : {
     131                 :          0 :   return QgsLayoutItem::Flags();
     132                 :            : }
     133                 :            : 
     134                 :          0 : void QgsLayoutItem::setId( const QString &id )
     135                 :            : {
     136                 :          0 :   if ( id == mId )
     137                 :            :   {
     138                 :          0 :     return;
     139                 :            :   }
     140                 :            : 
     141                 :          0 :   if ( !shouldBlockUndoCommands() )
     142                 :          0 :     mLayout->undoStack()->beginCommand( this, tr( "Change Item ID" ) );
     143                 :            : 
     144                 :          0 :   mId = id;
     145                 :            : 
     146                 :          0 :   if ( !shouldBlockUndoCommands() )
     147                 :          0 :     mLayout->undoStack()->endCommand();
     148                 :            : 
     149                 :          0 :   setToolTip( id );
     150                 :            : 
     151                 :            :   //inform model that id data has changed
     152                 :          0 :   if ( mLayout )
     153                 :            :   {
     154                 :          0 :     mLayout->itemsModel()->updateItemDisplayName( this );
     155                 :          0 :   }
     156                 :            : 
     157                 :          0 :   emit changed();
     158                 :          0 : }
     159                 :            : 
     160                 :          0 : void QgsLayoutItem::setSelected( bool selected )
     161                 :            : {
     162                 :          0 :   QGraphicsRectItem::setSelected( selected );
     163                 :            :   //inform model that id data has changed
     164                 :          0 :   if ( mLayout )
     165                 :            :   {
     166                 :          0 :     mLayout->itemsModel()->updateItemSelectStatus( this );
     167                 :          0 :   }
     168                 :          0 : }
     169                 :            : 
     170                 :          0 : void QgsLayoutItem::setVisibility( const bool visible )
     171                 :            : {
     172                 :          0 :   if ( visible == isVisible() )
     173                 :            :   {
     174                 :            :     //nothing to do
     175                 :          0 :     return;
     176                 :            :   }
     177                 :            : 
     178                 :          0 :   std::unique_ptr< QgsAbstractLayoutUndoCommand > command;
     179                 :          0 :   if ( !shouldBlockUndoCommands() )
     180                 :            :   {
     181                 :          0 :     command.reset( createCommand( visible ? tr( "Show Item" ) : tr( "Hide Item" ), 0 ) );
     182                 :          0 :     command->saveBeforeState();
     183                 :          0 :   }
     184                 :            : 
     185                 :          0 :   QGraphicsItem::setVisible( visible );
     186                 :            : 
     187                 :          0 :   if ( command )
     188                 :            :   {
     189                 :          0 :     command->saveAfterState();
     190                 :          0 :     mLayout->undoStack()->push( command.release() );
     191                 :          0 :   }
     192                 :            : 
     193                 :            :   //inform model that visibility has changed
     194                 :          0 :   if ( mLayout )
     195                 :            :   {
     196                 :          0 :     mLayout->itemsModel()->updateItemVisibility( this );
     197                 :          0 :   }
     198                 :          0 : }
     199                 :            : 
     200                 :          0 : void QgsLayoutItem::setLocked( const bool locked )
     201                 :            : {
     202                 :          0 :   if ( locked == mIsLocked )
     203                 :            :   {
     204                 :          0 :     return;
     205                 :            :   }
     206                 :            : 
     207                 :          0 :   if ( !shouldBlockUndoCommands() )
     208                 :          0 :     mLayout->undoStack()->beginCommand( this, locked ? tr( "Lock Item" ) : tr( "Unlock Item" ) );
     209                 :            : 
     210                 :          0 :   mIsLocked = locked;
     211                 :            : 
     212                 :          0 :   if ( !shouldBlockUndoCommands() )
     213                 :          0 :     mLayout->undoStack()->endCommand();
     214                 :            : 
     215                 :            :   //inform model that id data has changed
     216                 :          0 :   if ( mLayout )
     217                 :            :   {
     218                 :          0 :     mLayout->itemsModel()->updateItemLockStatus( this );
     219                 :          0 :   }
     220                 :            : 
     221                 :          0 :   update();
     222                 :          0 :   emit lockChanged();
     223                 :          0 : }
     224                 :            : 
     225                 :          0 : bool QgsLayoutItem::isGroupMember() const
     226                 :            : {
     227                 :          0 :   return !mParentGroupUuid.isEmpty() && mLayout && static_cast< bool >( mLayout->itemByUuid( mParentGroupUuid ) );
     228                 :            : }
     229                 :            : 
     230                 :          0 : QgsLayoutItemGroup *QgsLayoutItem::parentGroup() const
     231                 :            : {
     232                 :          0 :   if ( !mLayout || mParentGroupUuid.isEmpty() )
     233                 :          0 :     return nullptr;
     234                 :            : 
     235                 :          0 :   return qobject_cast< QgsLayoutItemGroup * >( mLayout->itemByUuid( mParentGroupUuid ) );
     236                 :          0 : }
     237                 :            : 
     238                 :          0 : void QgsLayoutItem::setParentGroup( QgsLayoutItemGroup *group )
     239                 :            : {
     240                 :          0 :   if ( !group )
     241                 :          0 :     mParentGroupUuid.clear();
     242                 :            :   else
     243                 :          0 :     mParentGroupUuid = group->uuid();
     244                 :          0 :   setFlag( QGraphicsItem::ItemIsSelectable, !static_cast< bool>( group ) ); //item in groups cannot be selected
     245                 :          0 : }
     246                 :            : 
     247                 :          0 : QgsLayoutItem::ExportLayerBehavior QgsLayoutItem::exportLayerBehavior() const
     248                 :            : {
     249                 :          0 :   return CanGroupWithAnyOtherItem;
     250                 :            : }
     251                 :            : 
     252                 :          0 : int QgsLayoutItem::numberExportLayers() const
     253                 :            : {
     254                 :          0 :   return 0;
     255                 :            : }
     256                 :            : 
     257                 :          0 : void QgsLayoutItem::startLayeredExport()
     258                 :            : {
     259                 :            : 
     260                 :          0 : }
     261                 :            : 
     262                 :          0 : void QgsLayoutItem::stopLayeredExport()
     263                 :            : {
     264                 :            : 
     265                 :          0 : }
     266                 :            : 
     267                 :          0 : bool QgsLayoutItem::nextExportPart()
     268                 :            : {
     269                 :            :   Q_NOWARN_DEPRECATED_PUSH
     270                 :          0 :   if ( !mLayout || mLayout->renderContext().currentExportLayer() == -1 )
     271                 :          0 :     return false;
     272                 :            : 
     273                 :            :   // QGIS 4- return false from base class implementation
     274                 :            : 
     275                 :          0 :   const int layers = numberExportLayers();
     276                 :          0 :   return mLayout->renderContext().currentExportLayer() < layers;
     277                 :            :   Q_NOWARN_DEPRECATED_POP
     278                 :          0 : }
     279                 :            : 
     280                 :          0 : QgsLayoutItem::ExportLayerDetail QgsLayoutItem::exportLayerDetails() const
     281                 :            : {
     282                 :          0 :   return QgsLayoutItem::ExportLayerDetail();
     283                 :            : }
     284                 :            : 
     285                 :          0 : void QgsLayoutItem::paint( QPainter *painter, const QStyleOptionGraphicsItem *itemStyle, QWidget * )
     286                 :            : {
     287                 :          0 :   if ( !painter || !painter->device() || !shouldDrawItem() )
     288                 :            :   {
     289                 :          0 :     return;
     290                 :            :   }
     291                 :            : 
     292                 :            :   //TODO - remember to disable saving/restoring on graphics view!!
     293                 :            : 
     294                 :          0 :   if ( shouldDrawDebugRect() )
     295                 :            :   {
     296                 :          0 :     drawDebugRect( painter );
     297                 :          0 :     return;
     298                 :            :   }
     299                 :            : 
     300                 :          0 :   bool previewRender = !mLayout || mLayout->renderContext().isPreviewRender();
     301                 :          0 :   double destinationDpi = previewRender ? QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter ) * 25.4 : mLayout->renderContext().dpi();
     302                 :          0 :   bool useImageCache = false;
     303                 :          0 :   bool forceRasterOutput = containsAdvancedEffects() && ( !mLayout || !( mLayout->renderContext().flags() & QgsLayoutRenderContext::FlagForceVectorOutput ) );
     304                 :            : 
     305                 :          0 :   if ( useImageCache || forceRasterOutput )
     306                 :            :   {
     307                 :          0 :     double widthInPixels = 0;
     308                 :          0 :     double heightInPixels = 0;
     309                 :            : 
     310                 :          0 :     if ( previewRender )
     311                 :            :     {
     312                 :          0 :       widthInPixels = boundingRect().width() * QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
     313                 :          0 :       heightInPixels = boundingRect().height() * QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
     314                 :          0 :     }
     315                 :            :     else
     316                 :            :     {
     317                 :          0 :       double layoutUnitsToPixels = mLayout ? mLayout->convertFromLayoutUnits( 1, QgsUnitTypes::LayoutPixels ).length() : destinationDpi / 25.4;
     318                 :          0 :       widthInPixels = boundingRect().width() * layoutUnitsToPixels;
     319                 :          0 :       heightInPixels = boundingRect().height() * layoutUnitsToPixels;
     320                 :            :     }
     321                 :            : 
     322                 :            :     // limit size of image for better performance
     323                 :          0 :     if ( previewRender && ( widthInPixels > CACHE_SIZE_LIMIT || heightInPixels > CACHE_SIZE_LIMIT ) )
     324                 :            :     {
     325                 :          0 :       double scale = 1.0;
     326                 :          0 :       if ( widthInPixels > heightInPixels )
     327                 :            :       {
     328                 :          0 :         scale = widthInPixels / CACHE_SIZE_LIMIT;
     329                 :          0 :         widthInPixels = CACHE_SIZE_LIMIT;
     330                 :          0 :         heightInPixels /= scale;
     331                 :          0 :       }
     332                 :            :       else
     333                 :            :       {
     334                 :          0 :         scale = heightInPixels / CACHE_SIZE_LIMIT;
     335                 :          0 :         heightInPixels = CACHE_SIZE_LIMIT;
     336                 :          0 :         widthInPixels /= scale;
     337                 :            :       }
     338                 :          0 :       destinationDpi = destinationDpi / scale;
     339                 :          0 :     }
     340                 :            : 
     341                 :          0 :     if ( previewRender && !mItemCachedImage.isNull() && qgsDoubleNear( mItemCacheDpi, destinationDpi ) )
     342                 :            :     {
     343                 :            :       // can reuse last cached image
     344                 :          0 :       QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, painter, destinationDpi );
     345                 :          0 :       QgsScopedQPainterState painterState( painter );
     346                 :          0 :       preparePainter( painter );
     347                 :          0 :       double cacheScale = destinationDpi / mItemCacheDpi;
     348                 :          0 :       painter->scale( cacheScale / context.scaleFactor(), cacheScale / context.scaleFactor() );
     349                 :          0 :       painter->drawImage( boundingRect().x() * context.scaleFactor() / cacheScale,
     350                 :          0 :                           boundingRect().y() * context.scaleFactor() / cacheScale, mItemCachedImage );
     351                 :            :       return;
     352                 :          0 :     }
     353                 :            :     else
     354                 :            :     {
     355                 :          0 :       QImage image = QImage( widthInPixels, heightInPixels, QImage::Format_ARGB32 );
     356                 :          0 :       image.fill( Qt::transparent );
     357                 :          0 :       image.setDotsPerMeterX( 1000 * destinationDpi * 25.4 );
     358                 :          0 :       image.setDotsPerMeterY( 1000 * destinationDpi * 25.4 );
     359                 :          0 :       QPainter p( &image );
     360                 :            : 
     361                 :          0 :       preparePainter( &p );
     362                 :          0 :       QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, &p, destinationDpi );
     363                 :          0 :       context.setExpressionContext( createExpressionContext() );
     364                 :            :       // painter is already scaled to dots
     365                 :            :       // need to translate so that item origin is at 0,0 in painter coordinates (not bounding rect origin)
     366                 :          0 :       p.translate( -boundingRect().x() * context.scaleFactor(), -boundingRect().y() * context.scaleFactor() );
     367                 :            :       // scale to layout units for background and frame rendering
     368                 :          0 :       p.scale( context.scaleFactor(), context.scaleFactor() );
     369                 :          0 :       drawBackground( context );
     370                 :          0 :       p.scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
     371                 :          0 :       double viewScale = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
     372                 :          0 :       QgsLayoutItemRenderContext itemRenderContext( context, viewScale );
     373                 :          0 :       draw( itemRenderContext );
     374                 :          0 :       p.scale( context.scaleFactor(), context.scaleFactor() );
     375                 :          0 :       drawFrame( context );
     376                 :          0 :       p.scale( 1 / context.scaleFactor(), 1 / context.scaleFactor() );
     377                 :          0 :       p.end();
     378                 :            : 
     379                 :          0 :       QgsImageOperation::multiplyOpacity( image, mEvaluatedOpacity );
     380                 :            : 
     381                 :          0 :       QgsScopedQPainterState painterState( painter );
     382                 :            :       // scale painter from mm to dots
     383                 :          0 :       painter->scale( 1.0 / context.scaleFactor(), 1.0 / context.scaleFactor() );
     384                 :          0 :       painter->drawImage( boundingRect().x() * context.scaleFactor(),
     385                 :          0 :                           boundingRect().y() * context.scaleFactor(), image );
     386                 :            : 
     387                 :          0 :       if ( previewRender )
     388                 :            :       {
     389                 :          0 :         mItemCacheDpi = destinationDpi;
     390                 :          0 :         mItemCachedImage = image;
     391                 :          0 :       }
     392                 :          0 :     }
     393                 :          0 :   }
     394                 :            :   else
     395                 :            :   {
     396                 :            :     // no caching or flattening
     397                 :          0 :     QgsScopedQPainterState painterState( painter );
     398                 :          0 :     preparePainter( painter );
     399                 :          0 :     QgsRenderContext context = QgsLayoutUtils::createRenderContextForLayout( mLayout, painter, destinationDpi );
     400                 :          0 :     context.setExpressionContext( createExpressionContext() );
     401                 :          0 :     drawBackground( context );
     402                 :            : 
     403                 :            :     // scale painter from mm to dots
     404                 :          0 :     painter->scale( 1.0 / context.scaleFactor(), 1.0 / context.scaleFactor() );
     405                 :          0 :     double viewScale = QgsLayoutUtils::scaleFactorFromItemStyle( itemStyle, painter );
     406                 :          0 :     QgsLayoutItemRenderContext itemRenderContext( context, viewScale );
     407                 :          0 :     draw( itemRenderContext );
     408                 :            : 
     409                 :          0 :     painter->scale( context.scaleFactor(), context.scaleFactor() );
     410                 :          0 :     drawFrame( context );
     411                 :          0 :   }
     412                 :          0 : }
     413                 :            : 
     414                 :          0 : void QgsLayoutItem::setReferencePoint( const QgsLayoutItem::ReferencePoint point )
     415                 :            : {
     416                 :          0 :   if ( point == mReferencePoint )
     417                 :            :   {
     418                 :          0 :     return;
     419                 :            :   }
     420                 :            : 
     421                 :          0 :   mReferencePoint = point;
     422                 :            : 
     423                 :            :   //also need to adjust stored position
     424                 :          0 :   updateStoredItemPosition();
     425                 :          0 :   refreshItemPosition();
     426                 :          0 : }
     427                 :            : 
     428                 :          0 : void QgsLayoutItem::attemptResize( const QgsLayoutSize &s, bool includesFrame )
     429                 :            : {
     430                 :          0 :   if ( !mLayout )
     431                 :            :   {
     432                 :          0 :     mItemSize = s;
     433                 :          0 :     setRect( 0, 0, s.width(), s.height() );
     434                 :          0 :     return;
     435                 :            :   }
     436                 :            : 
     437                 :          0 :   QgsLayoutSize size = s;
     438                 :            : 
     439                 :          0 :   if ( includesFrame )
     440                 :            :   {
     441                 :            :     //adjust position to account for frame size
     442                 :          0 :     double bleed = mLayout->convertFromLayoutUnits( estimatedFrameBleed(), size.units() ).length();
     443                 :          0 :     size.setWidth( size.width() - 2 * bleed );
     444                 :          0 :     size.setHeight( size.height() - 2 * bleed );
     445                 :          0 :   }
     446                 :            : 
     447                 :          0 :   QgsLayoutSize evaluatedSize = applyDataDefinedSize( size );
     448                 :          0 :   QSizeF targetSizeLayoutUnits = mLayout->convertToLayoutUnits( evaluatedSize );
     449                 :          0 :   QSizeF actualSizeLayoutUnits = applyMinimumSize( targetSizeLayoutUnits );
     450                 :          0 :   actualSizeLayoutUnits = applyFixedSize( actualSizeLayoutUnits );
     451                 :          0 :   actualSizeLayoutUnits = applyItemSizeConstraint( actualSizeLayoutUnits );
     452                 :            : 
     453                 :          0 :   if ( actualSizeLayoutUnits == rect().size() )
     454                 :            :   {
     455                 :          0 :     return;
     456                 :            :   }
     457                 :            : 
     458                 :          0 :   QgsLayoutSize actualSizeTargetUnits = mLayout->convertFromLayoutUnits( actualSizeLayoutUnits, size.units() );
     459                 :          0 :   mItemSize = actualSizeTargetUnits;
     460                 :            : 
     461                 :          0 :   setRect( 0, 0, actualSizeLayoutUnits.width(), actualSizeLayoutUnits.height() );
     462                 :          0 :   refreshItemPosition();
     463                 :          0 :   emit sizePositionChanged();
     464                 :          0 : }
     465                 :            : 
     466                 :          0 : void QgsLayoutItem::attemptMove( const QgsLayoutPoint &p, bool useReferencePoint, bool includesFrame, int page )
     467                 :            : {
     468                 :          0 :   if ( !mLayout )
     469                 :            :   {
     470                 :          0 :     mItemPosition = p;
     471                 :          0 :     setPos( p.toQPointF() );
     472                 :          0 :     return;
     473                 :            :   }
     474                 :            : 
     475                 :          0 :   QgsLayoutPoint point = p;
     476                 :          0 :   if ( page >= 0 )
     477                 :            :   {
     478                 :          0 :     point = mLayout->pageCollection()->pagePositionToAbsolute( page, p );
     479                 :          0 :   }
     480                 :            : 
     481                 :          0 :   if ( includesFrame )
     482                 :            :   {
     483                 :            :     //adjust position to account for frame size
     484                 :          0 :     double bleed = mLayout->convertFromLayoutUnits( estimatedFrameBleed(), point.units() ).length();
     485                 :          0 :     point.setX( point.x() + bleed );
     486                 :          0 :     point.setY( point.y() + bleed );
     487                 :          0 :   }
     488                 :            : 
     489                 :          0 :   QgsLayoutPoint evaluatedPoint = point;
     490                 :          0 :   if ( !useReferencePoint )
     491                 :            :   {
     492                 :          0 :     evaluatedPoint = topLeftToReferencePoint( point );
     493                 :          0 :   }
     494                 :            : 
     495                 :          0 :   evaluatedPoint = applyDataDefinedPosition( evaluatedPoint );
     496                 :          0 :   QPointF evaluatedPointLayoutUnits = mLayout->convertToLayoutUnits( evaluatedPoint );
     497                 :          0 :   QPointF topLeftPointLayoutUnits = adjustPointForReferencePosition( evaluatedPointLayoutUnits, rect().size(), mReferencePoint );
     498                 :          0 :   if ( topLeftPointLayoutUnits == scenePos() && point.units() == mItemPosition.units() )
     499                 :            :   {
     500                 :            :     //TODO - add test for second condition
     501                 :          0 :     return;
     502                 :            :   }
     503                 :            : 
     504                 :          0 :   QgsLayoutPoint referencePointTargetUnits = mLayout->convertFromLayoutUnits( evaluatedPointLayoutUnits, point.units() );
     505                 :          0 :   mItemPosition = referencePointTargetUnits;
     506                 :          0 :   setScenePos( topLeftPointLayoutUnits );
     507                 :          0 :   emit sizePositionChanged();
     508                 :          0 : }
     509                 :            : 
     510                 :          0 : void QgsLayoutItem::attemptSetSceneRect( const QRectF &rect, bool includesFrame )
     511                 :            : {
     512                 :          0 :   QPointF newPos = rect.topLeft();
     513                 :            : 
     514                 :          0 :   blockSignals( true );
     515                 :            :   // translate new size to current item units
     516                 :          0 :   QgsLayoutSize newSize = mLayout->convertFromLayoutUnits( rect.size(), mItemSize.units() );
     517                 :          0 :   attemptResize( newSize, includesFrame );
     518                 :            : 
     519                 :            :   // translate new position to current item units
     520                 :          0 :   QgsLayoutPoint itemPos = mLayout->convertFromLayoutUnits( newPos, mItemPosition.units() );
     521                 :          0 :   attemptMove( itemPos, false, includesFrame );
     522                 :          0 :   blockSignals( false );
     523                 :          0 :   emit sizePositionChanged();
     524                 :          0 : }
     525                 :            : 
     526                 :          0 : void QgsLayoutItem::attemptMoveBy( double deltaX, double deltaY )
     527                 :            : {
     528                 :          0 :   if ( !mLayout )
     529                 :            :   {
     530                 :          0 :     moveBy( deltaX, deltaY );
     531                 :          0 :     return;
     532                 :            :   }
     533                 :            : 
     534                 :          0 :   QgsLayoutPoint itemPos = positionWithUnits();
     535                 :          0 :   QgsLayoutPoint deltaPos = mLayout->convertFromLayoutUnits( QPointF( deltaX, deltaY ), itemPos.units() );
     536                 :          0 :   itemPos.setX( itemPos.x() + deltaPos.x() );
     537                 :          0 :   itemPos.setY( itemPos.y() + deltaPos.y() );
     538                 :          0 :   attemptMove( itemPos );
     539                 :          0 : }
     540                 :            : 
     541                 :          0 : int QgsLayoutItem::page() const
     542                 :            : {
     543                 :          0 :   if ( !mLayout )
     544                 :          0 :     return -1;
     545                 :            : 
     546                 :          0 :   return mLayout->pageCollection()->pageNumberForPoint( pos() );
     547                 :          0 : }
     548                 :            : 
     549                 :          0 : QPointF QgsLayoutItem::pagePos() const
     550                 :            : {
     551                 :          0 :   QPointF p = positionAtReferencePoint( mReferencePoint );
     552                 :            : 
     553                 :          0 :   if ( !mLayout )
     554                 :          0 :     return p;
     555                 :            : 
     556                 :            :   // try to get page
     557                 :          0 :   QgsLayoutItemPage *pageItem = mLayout->pageCollection()->page( page() );
     558                 :          0 :   if ( !pageItem )
     559                 :          0 :     return p;
     560                 :            : 
     561                 :          0 :   p.ry() -= pageItem->pos().y();
     562                 :          0 :   return p;
     563                 :          0 : }
     564                 :            : 
     565                 :          0 : QgsLayoutPoint QgsLayoutItem::pagePositionWithUnits() const
     566                 :            : {
     567                 :          0 :   QPointF p = pagePos();
     568                 :          0 :   if ( !mLayout )
     569                 :          0 :     return QgsLayoutPoint( p );
     570                 :            : 
     571                 :          0 :   return mLayout->convertFromLayoutUnits( p, mItemPosition.units() );
     572                 :          0 : }
     573                 :            : 
     574                 :          0 : void QgsLayoutItem::setScenePos( const QPointF destinationPos )
     575                 :            : {
     576                 :            :   //since setPos does not account for item rotation, use difference between
     577                 :            :   //current scenePos (which DOES account for rotation) and destination pos
     578                 :            :   //to calculate how much the item needs to move
     579                 :          0 :   if ( auto *lParentItem = parentItem() )
     580                 :          0 :     setPos( pos() + ( destinationPos - scenePos() ) + lParentItem->scenePos() );
     581                 :            :   else
     582                 :          0 :     setPos( pos() + ( destinationPos - scenePos() ) );
     583                 :          0 : }
     584                 :            : 
     585                 :          0 : bool QgsLayoutItem::shouldBlockUndoCommands() const
     586                 :            : {
     587                 :          0 :   return !mLayout || mLayout != scene() || mBlockUndoCommands;
     588                 :            : }
     589                 :            : 
     590                 :          0 : bool QgsLayoutItem::shouldDrawItem() const
     591                 :            : {
     592                 :          0 :   if ( mLayout && QgsLayoutUtils::itemIsAClippingSource( this ) )
     593                 :          0 :     return false;
     594                 :            : 
     595                 :          0 :   if ( !mLayout || mLayout->renderContext().isPreviewRender() )
     596                 :            :   {
     597                 :            :     //preview mode so OK to draw item
     598                 :          0 :     return true;
     599                 :            :   }
     600                 :            : 
     601                 :            :   //exporting layout, so check if item is excluded from exports
     602                 :          0 :   return !mEvaluatedExcludeFromExports;
     603                 :          0 : }
     604                 :            : 
     605                 :          0 : double QgsLayoutItem::itemRotation() const
     606                 :            : {
     607                 :          0 :   return mItemRotation;
     608                 :            : }
     609                 :            : 
     610                 :          0 : bool QgsLayoutItem::writeXml( QDomElement &parentElement, QDomDocument &doc, const QgsReadWriteContext &context ) const
     611                 :            : {
     612                 :          0 :   QDomElement element = doc.createElement( QStringLiteral( "LayoutItem" ) );
     613                 :          0 :   element.setAttribute( QStringLiteral( "type" ), QString::number( type() ) );
     614                 :            : 
     615                 :          0 :   element.setAttribute( QStringLiteral( "uuid" ), mUuid );
     616                 :          0 :   element.setAttribute( QStringLiteral( "templateUuid" ), mUuid );
     617                 :          0 :   element.setAttribute( QStringLiteral( "id" ), mId );
     618                 :          0 :   element.setAttribute( QStringLiteral( "referencePoint" ), QString::number( static_cast< int >( mReferencePoint ) ) );
     619                 :          0 :   element.setAttribute( QStringLiteral( "position" ), mItemPosition.encodePoint() );
     620                 :          0 :   element.setAttribute( QStringLiteral( "positionOnPage" ), pagePositionWithUnits().encodePoint() );
     621                 :          0 :   element.setAttribute( QStringLiteral( "size" ), mItemSize.encodeSize() );
     622                 :          0 :   element.setAttribute( QStringLiteral( "itemRotation" ), QString::number( mItemRotation ) );
     623                 :          0 :   element.setAttribute( QStringLiteral( "groupUuid" ), mParentGroupUuid );
     624                 :            : 
     625                 :          0 :   element.setAttribute( QStringLiteral( "zValue" ), QString::number( zValue() ) );
     626                 :          0 :   element.setAttribute( QStringLiteral( "visibility" ), isVisible() );
     627                 :            :   //position lock for mouse moves/resizes
     628                 :          0 :   if ( mIsLocked )
     629                 :            :   {
     630                 :          0 :     element.setAttribute( QStringLiteral( "positionLock" ), QStringLiteral( "true" ) );
     631                 :          0 :   }
     632                 :            :   else
     633                 :            :   {
     634                 :          0 :     element.setAttribute( QStringLiteral( "positionLock" ), QStringLiteral( "false" ) );
     635                 :            :   }
     636                 :            : 
     637                 :            :   //frame
     638                 :          0 :   if ( mFrame )
     639                 :            :   {
     640                 :          0 :     element.setAttribute( QStringLiteral( "frame" ), QStringLiteral( "true" ) );
     641                 :          0 :   }
     642                 :            :   else
     643                 :            :   {
     644                 :          0 :     element.setAttribute( QStringLiteral( "frame" ), QStringLiteral( "false" ) );
     645                 :            :   }
     646                 :            : 
     647                 :            :   //background
     648                 :          0 :   if ( mBackground )
     649                 :            :   {
     650                 :          0 :     element.setAttribute( QStringLiteral( "background" ), QStringLiteral( "true" ) );
     651                 :          0 :   }
     652                 :            :   else
     653                 :            :   {
     654                 :          0 :     element.setAttribute( QStringLiteral( "background" ), QStringLiteral( "false" ) );
     655                 :            :   }
     656                 :            : 
     657                 :            :   //frame color
     658                 :          0 :   QDomElement frameColorElem = doc.createElement( QStringLiteral( "FrameColor" ) );
     659                 :          0 :   frameColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mFrameColor.red() ) );
     660                 :          0 :   frameColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mFrameColor.green() ) );
     661                 :          0 :   frameColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mFrameColor.blue() ) );
     662                 :          0 :   frameColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mFrameColor.alpha() ) );
     663                 :          0 :   element.appendChild( frameColorElem );
     664                 :          0 :   element.setAttribute( QStringLiteral( "outlineWidthM" ), mFrameWidth.encodeMeasurement() );
     665                 :          0 :   element.setAttribute( QStringLiteral( "frameJoinStyle" ), QgsSymbolLayerUtils::encodePenJoinStyle( mFrameJoinStyle ) );
     666                 :            : 
     667                 :            :   //background color
     668                 :          0 :   QDomElement bgColorElem = doc.createElement( QStringLiteral( "BackgroundColor" ) );
     669                 :          0 :   bgColorElem.setAttribute( QStringLiteral( "red" ), QString::number( mBackgroundColor.red() ) );
     670                 :          0 :   bgColorElem.setAttribute( QStringLiteral( "green" ), QString::number( mBackgroundColor.green() ) );
     671                 :          0 :   bgColorElem.setAttribute( QStringLiteral( "blue" ), QString::number( mBackgroundColor.blue() ) );
     672                 :          0 :   bgColorElem.setAttribute( QStringLiteral( "alpha" ), QString::number( mBackgroundColor.alpha() ) );
     673                 :          0 :   element.appendChild( bgColorElem );
     674                 :            : 
     675                 :            :   //blend mode
     676                 :          0 :   element.setAttribute( QStringLiteral( "blendMode" ), QgsPainting::getBlendModeEnum( mBlendMode ) );
     677                 :            : 
     678                 :            :   //opacity
     679                 :          0 :   element.setAttribute( QStringLiteral( "opacity" ), QString::number( mOpacity ) );
     680                 :            : 
     681                 :          0 :   element.setAttribute( QStringLiteral( "excludeFromExports" ), mExcludeFromExports );
     682                 :            : 
     683                 :          0 :   writeObjectPropertiesToElement( element, doc, context );
     684                 :            : 
     685                 :          0 :   writePropertiesToElement( element, doc, context );
     686                 :          0 :   parentElement.appendChild( element );
     687                 :            : 
     688                 :            :   return true;
     689                 :          0 : }
     690                 :            : 
     691                 :          0 : bool QgsLayoutItem::readXml( const QDomElement &element, const QDomDocument &doc, const QgsReadWriteContext &context )
     692                 :            : {
     693                 :          0 :   if ( element.nodeName() != QLatin1String( "LayoutItem" ) )
     694                 :            :   {
     695                 :          0 :     return false;
     696                 :            :   }
     697                 :            : 
     698                 :          0 :   readObjectPropertiesFromElement( element, doc, context );
     699                 :            : 
     700                 :          0 :   mBlockUndoCommands = true;
     701                 :          0 :   mUuid = element.attribute( QStringLiteral( "uuid" ), QUuid::createUuid().toString() );
     702                 :          0 :   setId( element.attribute( QStringLiteral( "id" ) ) );
     703                 :          0 :   mReferencePoint = static_cast< ReferencePoint >( element.attribute( QStringLiteral( "referencePoint" ) ).toInt() );
     704                 :          0 :   setItemRotation( element.attribute( QStringLiteral( "itemRotation" ), QStringLiteral( "0" ) ).toDouble() );
     705                 :          0 :   attemptMove( QgsLayoutPoint::decodePoint( element.attribute( QStringLiteral( "position" ) ) ) );
     706                 :          0 :   attemptResize( QgsLayoutSize::decodeSize( element.attribute( QStringLiteral( "size" ) ) ) );
     707                 :            : 
     708                 :          0 :   mParentGroupUuid = element.attribute( QStringLiteral( "groupUuid" ) );
     709                 :          0 :   if ( !mParentGroupUuid.isEmpty() )
     710                 :            :   {
     711                 :          0 :     if ( QgsLayoutItemGroup *group = parentGroup() )
     712                 :            :     {
     713                 :          0 :       group->addItem( this );
     714                 :          0 :     }
     715                 :          0 :   }
     716                 :          0 :   mTemplateUuid = element.attribute( QStringLiteral( "templateUuid" ) );
     717                 :            : 
     718                 :            :   //position lock for mouse moves/resizes
     719                 :          0 :   QString positionLock = element.attribute( QStringLiteral( "positionLock" ) );
     720                 :          0 :   if ( positionLock.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
     721                 :            :   {
     722                 :          0 :     setLocked( true );
     723                 :          0 :   }
     724                 :            :   else
     725                 :            :   {
     726                 :          0 :     setLocked( false );
     727                 :            :   }
     728                 :            :   //visibility
     729                 :          0 :   setVisibility( element.attribute( QStringLiteral( "visibility" ), QStringLiteral( "1" ) ) != QLatin1String( "0" ) );
     730                 :          0 :   setZValue( element.attribute( QStringLiteral( "zValue" ) ).toDouble() );
     731                 :            : 
     732                 :            :   //frame
     733                 :          0 :   QString frame = element.attribute( QStringLiteral( "frame" ) );
     734                 :          0 :   if ( frame.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
     735                 :            :   {
     736                 :          0 :     mFrame = true;
     737                 :          0 :   }
     738                 :            :   else
     739                 :            :   {
     740                 :          0 :     mFrame = false;
     741                 :            :   }
     742                 :            : 
     743                 :            :   //frame
     744                 :          0 :   QString background = element.attribute( QStringLiteral( "background" ) );
     745                 :          0 :   if ( background.compare( QLatin1String( "true" ), Qt::CaseInsensitive ) == 0 )
     746                 :            :   {
     747                 :          0 :     mBackground = true;
     748                 :          0 :   }
     749                 :            :   else
     750                 :            :   {
     751                 :          0 :     mBackground = false;
     752                 :            :   }
     753                 :            : 
     754                 :            :   //pen
     755                 :          0 :   mFrameWidth = QgsLayoutMeasurement::decodeMeasurement( element.attribute( QStringLiteral( "outlineWidthM" ) ) );
     756                 :          0 :   mFrameJoinStyle = QgsSymbolLayerUtils::decodePenJoinStyle( element.attribute( QStringLiteral( "frameJoinStyle" ), QStringLiteral( "miter" ) ) );
     757                 :          0 :   QDomNodeList frameColorList = element.elementsByTagName( QStringLiteral( "FrameColor" ) );
     758                 :          0 :   if ( !frameColorList.isEmpty() )
     759                 :            :   {
     760                 :          0 :     QDomElement frameColorElem = frameColorList.at( 0 ).toElement();
     761                 :          0 :     bool redOk = false;
     762                 :          0 :     bool greenOk = false;
     763                 :          0 :     bool blueOk = false;
     764                 :          0 :     bool alphaOk = false;
     765                 :            :     int penRed, penGreen, penBlue, penAlpha;
     766                 :            : 
     767                 :          0 :     penRed = frameColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
     768                 :          0 :     penGreen = frameColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
     769                 :          0 :     penBlue = frameColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
     770                 :          0 :     penAlpha = frameColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
     771                 :            : 
     772                 :          0 :     if ( redOk && greenOk && blueOk && alphaOk )
     773                 :            :     {
     774                 :          0 :       mFrameColor = QColor( penRed, penGreen, penBlue, penAlpha );
     775                 :          0 :     }
     776                 :          0 :   }
     777                 :          0 :   refreshFrame( false );
     778                 :            : 
     779                 :            :   //brush
     780                 :          0 :   QDomNodeList bgColorList = element.elementsByTagName( QStringLiteral( "BackgroundColor" ) );
     781                 :          0 :   if ( !bgColorList.isEmpty() )
     782                 :            :   {
     783                 :          0 :     QDomElement bgColorElem = bgColorList.at( 0 ).toElement();
     784                 :            :     bool redOk, greenOk, blueOk, alphaOk;
     785                 :            :     int bgRed, bgGreen, bgBlue, bgAlpha;
     786                 :          0 :     bgRed = bgColorElem.attribute( QStringLiteral( "red" ) ).toDouble( &redOk );
     787                 :          0 :     bgGreen = bgColorElem.attribute( QStringLiteral( "green" ) ).toDouble( &greenOk );
     788                 :          0 :     bgBlue = bgColorElem.attribute( QStringLiteral( "blue" ) ).toDouble( &blueOk );
     789                 :          0 :     bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
     790                 :          0 :     if ( redOk && greenOk && blueOk && alphaOk )
     791                 :            :     {
     792                 :          0 :       mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
     793                 :          0 :       setBrush( QBrush( mBackgroundColor, Qt::SolidPattern ) );
     794                 :          0 :     }
     795                 :            :     //apply any data defined settings
     796                 :          0 :     refreshBackgroundColor( false );
     797                 :          0 :   }
     798                 :            : 
     799                 :            :   //blend mode
     800                 :          0 :   setBlendMode( QgsPainting::getCompositionMode( static_cast< QgsPainting::BlendMode >( element.attribute( QStringLiteral( "blendMode" ), QStringLiteral( "0" ) ).toUInt() ) ) );
     801                 :            : 
     802                 :            :   //opacity
     803                 :          0 :   if ( element.hasAttribute( QStringLiteral( "opacity" ) ) )
     804                 :            :   {
     805                 :          0 :     setItemOpacity( element.attribute( QStringLiteral( "opacity" ), QStringLiteral( "1" ) ).toDouble() );
     806                 :          0 :   }
     807                 :            :   else
     808                 :            :   {
     809                 :          0 :     setItemOpacity( 1.0 - element.attribute( QStringLiteral( "transparency" ), QStringLiteral( "0" ) ).toInt() / 100.0 );
     810                 :            :   }
     811                 :            : 
     812                 :          0 :   mExcludeFromExports = element.attribute( QStringLiteral( "excludeFromExports" ), QStringLiteral( "0" ) ).toInt();
     813                 :          0 :   mEvaluatedExcludeFromExports = mExcludeFromExports;
     814                 :            : 
     815                 :          0 :   bool result = readPropertiesFromElement( element, doc, context );
     816                 :            : 
     817                 :          0 :   mBlockUndoCommands = false;
     818                 :            : 
     819                 :          0 :   emit changed();
     820                 :          0 :   update();
     821                 :          0 :   return result;
     822                 :          0 : }
     823                 :            : 
     824                 :          0 : void QgsLayoutItem::finalizeRestoreFromXml()
     825                 :            : {
     826                 :          0 : }
     827                 :            : 
     828                 :          0 : QgsAbstractLayoutUndoCommand *QgsLayoutItem::createCommand( const QString &text, int id, QUndoCommand *parent )
     829                 :            : {
     830                 :          0 :   return new QgsLayoutItemUndoCommand( this, text, id, parent );
     831                 :          0 : }
     832                 :            : 
     833                 :          0 : void QgsLayoutItem::setFrameEnabled( bool drawFrame )
     834                 :            : {
     835                 :          0 :   if ( drawFrame == mFrame )
     836                 :            :   {
     837                 :            :     //no change
     838                 :          0 :     return;
     839                 :            :   }
     840                 :            : 
     841                 :          0 :   mFrame = drawFrame;
     842                 :          0 :   refreshFrame( true );
     843                 :          0 :   emit frameChanged();
     844                 :          0 : }
     845                 :            : 
     846                 :          0 : void QgsLayoutItem::setFrameStrokeColor( const QColor &color )
     847                 :            : {
     848                 :          0 :   if ( mFrameColor == color )
     849                 :            :   {
     850                 :            :     //no change
     851                 :          0 :     return;
     852                 :            :   }
     853                 :          0 :   mFrameColor = color;
     854                 :            :   // apply any datadefined overrides
     855                 :          0 :   refreshFrame( true );
     856                 :          0 :   emit frameChanged();
     857                 :          0 : }
     858                 :            : 
     859                 :          0 : void QgsLayoutItem::setFrameStrokeWidth( const QgsLayoutMeasurement width )
     860                 :            : {
     861                 :          0 :   if ( mFrameWidth == width )
     862                 :            :   {
     863                 :            :     //no change
     864                 :          0 :     return;
     865                 :            :   }
     866                 :          0 :   mFrameWidth = width;
     867                 :          0 :   refreshFrame();
     868                 :          0 :   emit frameChanged();
     869                 :          0 : }
     870                 :            : 
     871                 :          0 : void QgsLayoutItem::setFrameJoinStyle( const Qt::PenJoinStyle style )
     872                 :            : {
     873                 :          0 :   if ( mFrameJoinStyle == style )
     874                 :            :   {
     875                 :            :     //no change
     876                 :          0 :     return;
     877                 :            :   }
     878                 :          0 :   mFrameJoinStyle = style;
     879                 :            : 
     880                 :          0 :   QPen itemPen = pen();
     881                 :          0 :   itemPen.setJoinStyle( mFrameJoinStyle );
     882                 :          0 :   setPen( itemPen );
     883                 :          0 :   emit frameChanged();
     884                 :          0 : }
     885                 :            : 
     886                 :          0 : void QgsLayoutItem::setBackgroundEnabled( bool drawBackground )
     887                 :            : {
     888                 :          0 :   mBackground = drawBackground;
     889                 :          0 :   update();
     890                 :          0 : }
     891                 :            : 
     892                 :          0 : void QgsLayoutItem::setBackgroundColor( const QColor &color )
     893                 :            : {
     894                 :          0 :   mBackgroundColor = color;
     895                 :            :   // apply any datadefined overrides
     896                 :          0 :   refreshBackgroundColor( true );
     897                 :          0 : }
     898                 :            : 
     899                 :          0 : void QgsLayoutItem::setBlendMode( const QPainter::CompositionMode mode )
     900                 :            : {
     901                 :          0 :   mBlendMode = mode;
     902                 :            :   // Update the item effect to use the new blend mode
     903                 :          0 :   refreshBlendMode();
     904                 :          0 : }
     905                 :            : 
     906                 :          0 : void QgsLayoutItem::setItemOpacity( double opacity )
     907                 :            : {
     908                 :          0 :   mOpacity = opacity;
     909                 :          0 :   refreshOpacity( mItemCachedImage.isNull() );
     910                 :          0 :   if ( !mItemCachedImage.isNull() )
     911                 :          0 :     invalidateCache();
     912                 :          0 : }
     913                 :            : 
     914                 :          0 : bool QgsLayoutItem::excludeFromExports() const
     915                 :            : {
     916                 :          0 :   return mExcludeFromExports;
     917                 :            : }
     918                 :            : 
     919                 :          0 : void QgsLayoutItem::setExcludeFromExports( bool exclude )
     920                 :            : {
     921                 :          0 :   mExcludeFromExports = exclude;
     922                 :          0 :   refreshDataDefinedProperty( QgsLayoutObject::ExcludeFromExports );
     923                 :          0 : }
     924                 :            : 
     925                 :          0 : bool QgsLayoutItem::containsAdvancedEffects() const
     926                 :            : {
     927                 :          0 :   return itemFlags() & Flag::FlagOverridesPaint ? false : mEvaluatedOpacity < 1.0;
     928                 :            : }
     929                 :            : 
     930                 :          0 : bool QgsLayoutItem::requiresRasterization() const
     931                 :            : {
     932                 :          0 :   return ( itemFlags() & Flag::FlagOverridesPaint && itemOpacity() < 1.0 ) ||
     933                 :          0 :          blendMode() != QPainter::CompositionMode_SourceOver;
     934                 :            : }
     935                 :            : 
     936                 :          0 : double QgsLayoutItem::estimatedFrameBleed() const
     937                 :            : {
     938                 :          0 :   if ( !frameEnabled() )
     939                 :            :   {
     940                 :          0 :     return 0;
     941                 :            :   }
     942                 :            : 
     943                 :          0 :   return pen().widthF() / 2.0;
     944                 :          0 : }
     945                 :            : 
     946                 :          0 : QRectF QgsLayoutItem::rectWithFrame() const
     947                 :            : {
     948                 :          0 :   double frameBleed = estimatedFrameBleed();
     949                 :          0 :   return rect().adjusted( -frameBleed, -frameBleed, frameBleed, frameBleed );
     950                 :            : }
     951                 :            : 
     952                 :          0 : void QgsLayoutItem::moveContent( double, double )
     953                 :            : {
     954                 :            : 
     955                 :          0 : }
     956                 :            : 
     957                 :          0 : void QgsLayoutItem::setMoveContentPreviewOffset( double, double )
     958                 :            : {
     959                 :            : 
     960                 :          0 : }
     961                 :            : 
     962                 :          0 : void QgsLayoutItem::zoomContent( double, QPointF )
     963                 :            : {
     964                 :            : 
     965                 :          0 : }
     966                 :            : 
     967                 :          0 : void QgsLayoutItem::beginCommand( const QString &commandText, UndoCommand command )
     968                 :            : {
     969                 :          0 :   if ( !mLayout )
     970                 :          0 :     return;
     971                 :            : 
     972                 :          0 :   mLayout->undoStack()->beginCommand( this, commandText, command );
     973                 :          0 : }
     974                 :            : 
     975                 :          0 : void QgsLayoutItem::endCommand()
     976                 :            : {
     977                 :          0 :   if ( mLayout )
     978                 :          0 :     mLayout->undoStack()->endCommand();
     979                 :          0 : }
     980                 :            : 
     981                 :          0 : void QgsLayoutItem::cancelCommand()
     982                 :            : {
     983                 :          0 :   if ( mLayout )
     984                 :          0 :     mLayout->undoStack()->cancelCommand();
     985                 :          0 : }
     986                 :            : 
     987                 :          0 : QgsLayoutPoint QgsLayoutItem::applyDataDefinedPosition( const QgsLayoutPoint &position )
     988                 :            : {
     989                 :          0 :   if ( !mLayout )
     990                 :            :   {
     991                 :          0 :     return position;
     992                 :            :   }
     993                 :            : 
     994                 :          0 :   QgsExpressionContext context = createExpressionContext();
     995                 :          0 :   double evaluatedX = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::PositionX, context, position.x() );
     996                 :          0 :   double evaluatedY = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::PositionY, context, position.y() );
     997                 :          0 :   return QgsLayoutPoint( evaluatedX, evaluatedY, position.units() );
     998                 :          0 : }
     999                 :            : 
    1000                 :          0 : void QgsLayoutItem::applyDataDefinedOrientation( double &width, double &height, const QgsExpressionContext &context )
    1001                 :            : {
    1002                 :          0 :   bool ok = false;
    1003                 :          0 :   QString orientationString = mDataDefinedProperties.valueAsString( QgsLayoutObject::PaperOrientation, context, QString(), &ok );
    1004                 :          0 :   if ( ok && !orientationString.isEmpty() )
    1005                 :            :   {
    1006                 :          0 :     QgsLayoutItemPage::Orientation orientation = QgsLayoutUtils::decodePaperOrientation( orientationString, ok );
    1007                 :          0 :     if ( ok )
    1008                 :            :     {
    1009                 :          0 :       double heightD = 0.0, widthD = 0.0;
    1010                 :          0 :       switch ( orientation )
    1011                 :            :       {
    1012                 :            :         case QgsLayoutItemPage::Portrait:
    1013                 :            :         {
    1014                 :          0 :           heightD = std::max( height, width );
    1015                 :          0 :           widthD = std::min( height, width );
    1016                 :          0 :           break;
    1017                 :            :         }
    1018                 :            :         case QgsLayoutItemPage::Landscape:
    1019                 :            :         {
    1020                 :          0 :           heightD = std::min( height, width );
    1021                 :          0 :           widthD = std::max( height, width );
    1022                 :          0 :           break;
    1023                 :            :         }
    1024                 :            :       }
    1025                 :          0 :       width = widthD;
    1026                 :          0 :       height = heightD;
    1027                 :          0 :     }
    1028                 :          0 :   }
    1029                 :          0 : }
    1030                 :            : 
    1031                 :          0 : QgsLayoutSize QgsLayoutItem::applyDataDefinedSize( const QgsLayoutSize &size )
    1032                 :            : {
    1033                 :          0 :   if ( !mLayout )
    1034                 :            :   {
    1035                 :          0 :     return size;
    1036                 :            :   }
    1037                 :            : 
    1038                 :          0 :   if ( !mDataDefinedProperties.isActive( QgsLayoutObject::PresetPaperSize ) &&
    1039                 :          0 :        !mDataDefinedProperties.isActive( QgsLayoutObject::ItemWidth ) &&
    1040                 :          0 :        !mDataDefinedProperties.isActive( QgsLayoutObject::ItemHeight ) &&
    1041                 :          0 :        !mDataDefinedProperties.isActive( QgsLayoutObject::PaperOrientation ) )
    1042                 :          0 :     return size;
    1043                 :            : 
    1044                 :            : 
    1045                 :          0 :   QgsExpressionContext context = createExpressionContext();
    1046                 :            : 
    1047                 :            :   // lowest priority is page size
    1048                 :          0 :   QString pageSize = mDataDefinedProperties.valueAsString( QgsLayoutObject::PresetPaperSize, context );
    1049                 :          0 :   QgsPageSize matchedSize;
    1050                 :          0 :   double evaluatedWidth = size.width();
    1051                 :          0 :   double evaluatedHeight = size.height();
    1052                 :          0 :   if ( QgsApplication::pageSizeRegistry()->decodePageSize( pageSize, matchedSize ) )
    1053                 :            :   {
    1054                 :          0 :     QgsLayoutSize convertedSize = mLayout->renderContext().measurementConverter().convert( matchedSize.size, size.units() );
    1055                 :          0 :     evaluatedWidth = convertedSize.width();
    1056                 :          0 :     evaluatedHeight = convertedSize.height();
    1057                 :          0 :   }
    1058                 :            : 
    1059                 :            :   // highest priority is dd width/height
    1060                 :          0 :   evaluatedWidth = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::ItemWidth, context, evaluatedWidth );
    1061                 :          0 :   evaluatedHeight = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::ItemHeight, context, evaluatedHeight );
    1062                 :            : 
    1063                 :            :   //which is finally overwritten by data defined orientation
    1064                 :          0 :   applyDataDefinedOrientation( evaluatedWidth, evaluatedHeight, context );
    1065                 :            : 
    1066                 :          0 :   return QgsLayoutSize( evaluatedWidth, evaluatedHeight, size.units() );
    1067                 :          0 : }
    1068                 :            : 
    1069                 :          0 : double QgsLayoutItem::applyDataDefinedRotation( const double rotation )
    1070                 :            : {
    1071                 :          0 :   if ( !mLayout )
    1072                 :            :   {
    1073                 :          0 :     return rotation;
    1074                 :            :   }
    1075                 :            : 
    1076                 :          0 :   QgsExpressionContext context = createExpressionContext();
    1077                 :          0 :   double evaluatedRotation = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::ItemRotation, context, rotation );
    1078                 :          0 :   return evaluatedRotation;
    1079                 :          0 : }
    1080                 :            : 
    1081                 :          0 : void QgsLayoutItem::refreshDataDefinedProperty( const QgsLayoutObject::DataDefinedProperty property )
    1082                 :            : {
    1083                 :            :   //update data defined properties and update item to match
    1084                 :            : 
    1085                 :            :   //evaluate width and height first, since they may affect position if non-top-left reference point set
    1086                 :          0 :   if ( property == QgsLayoutObject::ItemWidth || property == QgsLayoutObject::ItemHeight ||
    1087                 :          0 :        property == QgsLayoutObject::AllProperties )
    1088                 :            :   {
    1089                 :          0 :     refreshItemSize();
    1090                 :          0 :   }
    1091                 :          0 :   if ( property == QgsLayoutObject::PositionX || property == QgsLayoutObject::PositionY ||
    1092                 :          0 :        property == QgsLayoutObject::AllProperties )
    1093                 :            :   {
    1094                 :          0 :     refreshItemPosition();
    1095                 :          0 :   }
    1096                 :          0 :   if ( property == QgsLayoutObject::ItemRotation || property == QgsLayoutObject::AllProperties )
    1097                 :            :   {
    1098                 :          0 :     refreshItemRotation();
    1099                 :          0 :   }
    1100                 :          0 :   if ( property == QgsLayoutObject::Opacity || property == QgsLayoutObject::AllProperties )
    1101                 :            :   {
    1102                 :          0 :     refreshOpacity( false );
    1103                 :          0 :   }
    1104                 :          0 :   if ( property == QgsLayoutObject::FrameColor || property == QgsLayoutObject::AllProperties )
    1105                 :            :   {
    1106                 :          0 :     refreshFrame( false );
    1107                 :          0 :   }
    1108                 :          0 :   if ( property == QgsLayoutObject::BackgroundColor || property == QgsLayoutObject::AllProperties )
    1109                 :            :   {
    1110                 :          0 :     refreshBackgroundColor( false );
    1111                 :          0 :   }
    1112                 :          0 :   if ( property == QgsLayoutObject::BlendMode || property == QgsLayoutObject::AllProperties )
    1113                 :            :   {
    1114                 :          0 :     refreshBlendMode();
    1115                 :          0 :   }
    1116                 :          0 :   if ( property == QgsLayoutObject::ExcludeFromExports || property == QgsLayoutObject::AllProperties )
    1117                 :            :   {
    1118                 :          0 :     bool exclude = mExcludeFromExports;
    1119                 :            :     //data defined exclude from exports set?
    1120                 :          0 :     mEvaluatedExcludeFromExports = mDataDefinedProperties.valueAsBool( QgsLayoutObject::ExcludeFromExports, createExpressionContext(), exclude );
    1121                 :          0 :   }
    1122                 :            : 
    1123                 :          0 :   update();
    1124                 :          0 : }
    1125                 :            : 
    1126                 :          0 : void QgsLayoutItem::setItemRotation( double angle, const bool adjustPosition )
    1127                 :            : {
    1128                 :          0 :   if ( angle >= 360.0 || angle <= -360.0 )
    1129                 :            :   {
    1130                 :          0 :     angle = std::fmod( angle, 360.0 );
    1131                 :          0 :   }
    1132                 :            : 
    1133                 :          0 :   QPointF point = adjustPosition ? positionAtReferencePoint( QgsLayoutItem::Middle )
    1134                 :          0 :                   : pos();
    1135                 :          0 :   double rotationRequired = angle - rotation();
    1136                 :          0 :   rotateItem( rotationRequired, point );
    1137                 :            : 
    1138                 :          0 :   mItemRotation = angle;
    1139                 :          0 : }
    1140                 :            : 
    1141                 :          0 : void QgsLayoutItem::updateStoredItemPosition()
    1142                 :            : {
    1143                 :          0 :   QPointF layoutPosReferencePoint = positionAtReferencePoint( mReferencePoint );
    1144                 :          0 :   mItemPosition = mLayout->convertFromLayoutUnits( layoutPosReferencePoint, mItemPosition.units() );
    1145                 :          0 : }
    1146                 :            : 
    1147                 :          0 : void QgsLayoutItem::rotateItem( const double angle, const QPointF transformOrigin )
    1148                 :            : {
    1149                 :          0 :   double evaluatedAngle = angle + rotation();
    1150                 :          0 :   evaluatedAngle = QgsLayoutUtils::normalizedAngle( evaluatedAngle, true );
    1151                 :          0 :   mItemRotation = evaluatedAngle;
    1152                 :            : 
    1153                 :          0 :   QPointF itemTransformOrigin = mapFromScene( transformOrigin );
    1154                 :            : 
    1155                 :          0 :   refreshItemRotation( &itemTransformOrigin );
    1156                 :          0 : }
    1157                 :            : 
    1158                 :          0 : QgsExpressionContext QgsLayoutItem::createExpressionContext() const
    1159                 :            : {
    1160                 :          0 :   QgsExpressionContext context = QgsLayoutObject::createExpressionContext();
    1161                 :          0 :   context.appendScope( QgsExpressionContextUtils::layoutItemScope( this ) );
    1162                 :          0 :   return context;
    1163                 :          0 : }
    1164                 :            : 
    1165                 :          0 : bool QgsLayoutItem::accept( QgsStyleEntityVisitorInterface *visitor ) const
    1166                 :            : {
    1167                 :            :   Q_UNUSED( visitor );
    1168                 :          0 :   return true;
    1169                 :            : }
    1170                 :            : 
    1171                 :          0 : QgsGeometry QgsLayoutItem::clipPath() const
    1172                 :            : {
    1173                 :          0 :   return QgsGeometry();
    1174                 :            : }
    1175                 :            : 
    1176                 :          0 : void QgsLayoutItem::refresh()
    1177                 :            : {
    1178                 :          0 :   QgsLayoutObject::refresh();
    1179                 :          0 :   refreshItemSize();
    1180                 :            : 
    1181                 :          0 :   refreshDataDefinedProperty();
    1182                 :          0 : }
    1183                 :            : 
    1184                 :          0 : void QgsLayoutItem::invalidateCache()
    1185                 :            : {
    1186                 :          0 :   if ( !mItemCachedImage.isNull() )
    1187                 :            :   {
    1188                 :          0 :     mItemCachedImage = QImage();
    1189                 :          0 :     mItemCacheDpi = -1;
    1190                 :          0 :     update();
    1191                 :          0 :   }
    1192                 :          0 : }
    1193                 :            : 
    1194                 :          0 : void QgsLayoutItem::redraw()
    1195                 :            : {
    1196                 :          0 :   update();
    1197                 :          0 : }
    1198                 :            : 
    1199                 :          0 : void QgsLayoutItem::drawDebugRect( QPainter *painter )
    1200                 :            : {
    1201                 :          0 :   if ( !painter )
    1202                 :            :   {
    1203                 :          0 :     return;
    1204                 :            :   }
    1205                 :            : 
    1206                 :          0 :   QgsScopedQPainterState painterState( painter );
    1207                 :          0 :   painter->setRenderHint( QPainter::Antialiasing, false );
    1208                 :          0 :   painter->setPen( Qt::NoPen );
    1209                 :          0 :   painter->setBrush( QColor( 100, 255, 100, 200 ) );
    1210                 :          0 :   painter->drawRect( rect() );
    1211                 :          0 : }
    1212                 :            : 
    1213                 :          0 : QPainterPath QgsLayoutItem::framePath() const
    1214                 :            : {
    1215                 :          0 :   QPainterPath path;
    1216                 :          0 :   path.addRect( QRectF( 0, 0, rect().width(), rect().height() ) );
    1217                 :          0 :   return path;
    1218                 :          0 : }
    1219                 :            : 
    1220                 :          0 : void QgsLayoutItem::drawFrame( QgsRenderContext &context )
    1221                 :            : {
    1222                 :          0 :   if ( !mFrame || !context.painter() )
    1223                 :          0 :     return;
    1224                 :            : 
    1225                 :          0 :   QPainter *p = context.painter();
    1226                 :            : 
    1227                 :          0 :   QgsScopedQPainterState painterState( p );
    1228                 :            : 
    1229                 :          0 :   p->setPen( pen() );
    1230                 :          0 :   p->setBrush( Qt::NoBrush );
    1231                 :          0 :   context.setPainterFlagsUsingContext( p );
    1232                 :            : 
    1233                 :          0 :   p->drawPath( framePath() );
    1234                 :          0 : }
    1235                 :            : 
    1236                 :          0 : void QgsLayoutItem::drawBackground( QgsRenderContext &context )
    1237                 :            : {
    1238                 :          0 :   if ( !mBackground || !context.painter() )
    1239                 :          0 :     return;
    1240                 :            : 
    1241                 :          0 :   QgsScopedQPainterState painterState( context.painter() );
    1242                 :            : 
    1243                 :          0 :   QPainter *p = context.painter();
    1244                 :          0 :   p->setBrush( brush() );
    1245                 :          0 :   p->setPen( Qt::NoPen );
    1246                 :          0 :   context.setPainterFlagsUsingContext( p );
    1247                 :            : 
    1248                 :          0 :   p->drawPath( framePath() );
    1249                 :          0 : }
    1250                 :            : 
    1251                 :          0 : void QgsLayoutItem::setFixedSize( const QgsLayoutSize &size )
    1252                 :            : {
    1253                 :          0 :   mFixedSize = size;
    1254                 :          0 :   refreshItemSize();
    1255                 :          0 : }
    1256                 :            : 
    1257                 :          0 : void QgsLayoutItem::setMinimumSize( const QgsLayoutSize &size )
    1258                 :            : {
    1259                 :          0 :   mMinimumSize = size;
    1260                 :          0 :   refreshItemSize();
    1261                 :          0 : }
    1262                 :          0 : 
    1263                 :          0 : QSizeF QgsLayoutItem::applyItemSizeConstraint( const QSizeF targetSize )
    1264                 :            : {
    1265                 :          0 :   return targetSize;
    1266                 :            : }
    1267                 :            : 
    1268                 :          0 : void QgsLayoutItem::refreshItemSize()
    1269                 :            : {
    1270                 :          0 :   attemptResize( mItemSize );
    1271                 :          0 : }
    1272                 :            : 
    1273                 :          0 : void QgsLayoutItem::refreshItemPosition()
    1274                 :            : {
    1275                 :          0 :   attemptMove( mItemPosition );
    1276                 :          0 : }
    1277                 :            : 
    1278                 :          0 : QPointF QgsLayoutItem::itemPositionAtReferencePoint( const ReferencePoint reference, const QSizeF size ) const
    1279                 :          0 : {
    1280                 :          0 :   switch ( reference )
    1281                 :          0 :   {
    1282                 :            :     case UpperMiddle:
    1283                 :          0 :       return QPointF( size.width() / 2.0, 0 );
    1284                 :          0 :     case UpperRight:
    1285                 :          0 :       return QPointF( size.width(), 0 );
    1286                 :          0 :     case MiddleLeft:
    1287                 :          0 :       return QPointF( 0, size.height() / 2.0 );
    1288                 :          0 :     case Middle:
    1289                 :          0 :       return QPointF( size.width() / 2.0, size.height() / 2.0 );
    1290                 :          0 :     case MiddleRight:
    1291                 :          0 :       return QPointF( size.width(), size.height() / 2.0 );
    1292                 :            :     case LowerLeft:
    1293                 :          0 :       return QPointF( 0, size.height() );
    1294                 :            :     case LowerMiddle:
    1295                 :          0 :       return QPointF( size.width() / 2.0, size.height() );
    1296                 :            :     case LowerRight:
    1297                 :          0 :       return QPointF( size.width(), size.height() );
    1298                 :            :     case UpperLeft:
    1299                 :          0 :       return QPointF( 0, 0 );
    1300                 :            :   }
    1301                 :            :   // no warnings
    1302                 :          0 :   return QPointF( 0, 0 );
    1303                 :          0 : }
    1304                 :            : 
    1305                 :          0 : QPointF QgsLayoutItem::adjustPointForReferencePosition( const QPointF position, const QSizeF size, const ReferencePoint reference ) const
    1306                 :            : {
    1307                 :          0 :   QPointF itemPosition = mapFromScene( position ); //need to map from scene to handle item rotation
    1308                 :          0 :   QPointF adjustedPointInsideItem = itemPosition - itemPositionAtReferencePoint( reference, size );
    1309                 :          0 :   return mapToScene( adjustedPointInsideItem );
    1310                 :            : }
    1311                 :            : 
    1312                 :          0 : QPointF QgsLayoutItem::positionAtReferencePoint( const QgsLayoutItem::ReferencePoint reference ) const
    1313                 :            : {
    1314                 :          0 :   QPointF pointWithinItem = itemPositionAtReferencePoint( reference, rect().size() );
    1315                 :          0 :   return mapToScene( pointWithinItem );
    1316                 :            : }
    1317                 :            : 
    1318                 :          0 : QgsLayoutPoint QgsLayoutItem::topLeftToReferencePoint( const QgsLayoutPoint &point ) const
    1319                 :            : {
    1320                 :          0 :   QPointF topLeft = mLayout->convertToLayoutUnits( point );
    1321                 :          0 :   QPointF refPoint = topLeft + itemPositionAtReferencePoint( mReferencePoint, rect().size() );
    1322                 :          0 :   return mLayout->convertFromLayoutUnits( refPoint, point.units() );
    1323                 :            : }
    1324                 :            : 
    1325                 :          0 : bool QgsLayoutItem::writePropertiesToElement( QDomElement &, QDomDocument &, const QgsReadWriteContext & ) const
    1326                 :            : {
    1327                 :          0 :   return true;
    1328                 :            : }
    1329                 :            : 
    1330                 :          0 : bool QgsLayoutItem::readPropertiesFromElement( const QDomElement &, const QDomDocument &, const QgsReadWriteContext & )
    1331                 :            : {
    1332                 :            : 
    1333                 :          0 :   return true;
    1334                 :            : }
    1335                 :            : 
    1336                 :          0 : void QgsLayoutItem::initConnectionsToLayout()
    1337                 :            : {
    1338                 :          0 :   if ( !mLayout )
    1339                 :          0 :     return;
    1340                 :            : 
    1341                 :          0 : }
    1342                 :            : 
    1343                 :          0 : void QgsLayoutItem::preparePainter( QPainter *painter )
    1344                 :            : {
    1345                 :          0 :   if ( !painter || !painter->device() )
    1346                 :            :   {
    1347                 :          0 :     return;
    1348                 :            :   }
    1349                 :            : 
    1350                 :          0 :   painter->setRenderHint( QPainter::Antialiasing, shouldDrawAntialiased() );
    1351                 :            : 
    1352                 :            : #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
    1353                 :          0 :   painter->setRenderHint( QPainter::LosslessImageRendering, mLayout && mLayout->renderContext().testFlag( QgsLayoutRenderContext::FlagLosslessImageRendering ) );
    1354                 :            : #endif
    1355                 :          0 : }
    1356                 :            : 
    1357                 :          0 : bool QgsLayoutItem::shouldDrawAntialiased() const
    1358                 :            : {
    1359                 :          0 :   if ( !mLayout )
    1360                 :            :   {
    1361                 :          0 :     return true;
    1362                 :            :   }
    1363                 :          0 :   return mLayout->renderContext().testFlag( QgsLayoutRenderContext::FlagAntialiasing ) && !mLayout->renderContext().testFlag( QgsLayoutRenderContext::FlagDebug );
    1364                 :          0 : }
    1365                 :            : 
    1366                 :          0 : bool QgsLayoutItem::shouldDrawDebugRect() const
    1367                 :            : {
    1368                 :          0 :   return mLayout && mLayout->renderContext().testFlag( QgsLayoutRenderContext::FlagDebug );
    1369                 :            : }
    1370                 :            : 
    1371                 :          0 : QSizeF QgsLayoutItem::applyMinimumSize( const QSizeF targetSize )
    1372                 :            : {
    1373                 :          0 :   if ( !mLayout || minimumSize().isEmpty() )
    1374                 :            :   {
    1375                 :          0 :     return targetSize;
    1376                 :            :   }
    1377                 :          0 :   QSizeF minimumSizeLayoutUnits = mLayout->convertToLayoutUnits( minimumSize() );
    1378                 :          0 :   return targetSize.expandedTo( minimumSizeLayoutUnits );
    1379                 :          0 : }
    1380                 :            : 
    1381                 :          0 : QSizeF QgsLayoutItem::applyFixedSize( const QSizeF targetSize )
    1382                 :            : {
    1383                 :          0 :   if ( !mLayout || fixedSize().isEmpty() )
    1384                 :            :   {
    1385                 :          0 :     return targetSize;
    1386                 :            :   }
    1387                 :            : 
    1388                 :          0 :   QSizeF size = targetSize;
    1389                 :          0 :   QSizeF fixedSizeLayoutUnits = mLayout->convertToLayoutUnits( fixedSize() );
    1390                 :          0 :   if ( fixedSizeLayoutUnits.width() > 0 )
    1391                 :          0 :     size.setWidth( fixedSizeLayoutUnits.width() );
    1392                 :          0 :   if ( fixedSizeLayoutUnits.height() > 0 )
    1393                 :          0 :     size.setHeight( fixedSizeLayoutUnits.height() );
    1394                 :            : 
    1395                 :          0 :   return size;
    1396                 :          0 : }
    1397                 :            : 
    1398                 :          0 : void QgsLayoutItem::refreshItemRotation( QPointF *origin )
    1399                 :            : {
    1400                 :          0 :   double r = mItemRotation;
    1401                 :            : 
    1402                 :            :   //data defined rotation set?
    1403                 :          0 :   r = mDataDefinedProperties.valueAsDouble( QgsLayoutItem::ItemRotation, createExpressionContext(), r );
    1404                 :            : 
    1405                 :          0 :   if ( qgsDoubleNear( r, rotation() ) && !origin )
    1406                 :            :   {
    1407                 :          0 :     return;
    1408                 :            :   }
    1409                 :            : 
    1410                 :          0 :   QPointF transformPoint = origin ? *origin : mapFromScene( positionAtReferencePoint( QgsLayoutItem::Middle ) );
    1411                 :            : 
    1412                 :          0 :   if ( !transformPoint.isNull() )
    1413                 :            :   {
    1414                 :            :     //adjustPosition set, so shift the position of the item so that rotation occurs around item center
    1415                 :            :     //create a line from the transform point to the item's origin, in scene coordinates
    1416                 :          0 :     QLineF refLine = QLineF( mapToScene( transformPoint ), mapToScene( QPointF( 0, 0 ) ) );
    1417                 :            :     //rotate this line by the current rotation angle
    1418                 :          0 :     refLine.setAngle( refLine.angle() - r + rotation() );
    1419                 :            :     //get new end point of line - this is the new item position
    1420                 :          0 :     QPointF rotatedReferencePoint = refLine.p2();
    1421                 :          0 :     setPos( rotatedReferencePoint );
    1422                 :          0 :   }
    1423                 :            : 
    1424                 :          0 :   setTransformOriginPoint( 0, 0 );
    1425                 :          0 :   QGraphicsItem::setRotation( r );
    1426                 :            : 
    1427                 :            :   //adjust stored position of item to match scene pos of reference point
    1428                 :          0 :   updateStoredItemPosition();
    1429                 :          0 :   emit sizePositionChanged();
    1430                 :            : 
    1431                 :          0 :   emit rotationChanged( r );
    1432                 :            : 
    1433                 :            :   //update bounds of scene, since rotation may affect this
    1434                 :          0 :   mLayout->updateBounds();
    1435                 :          0 : }
    1436                 :            : 
    1437                 :          0 : void QgsLayoutItem::refreshOpacity( bool updateItem )
    1438                 :            : {
    1439                 :            :   //data defined opacity set?
    1440                 :          0 :   double opacity = mDataDefinedProperties.valueAsDouble( QgsLayoutObject::Opacity, createExpressionContext(), mOpacity * 100.0 );
    1441                 :            : 
    1442                 :            :   // Set the QGraphicItem's opacity
    1443                 :          0 :   mEvaluatedOpacity = opacity / 100.0;
    1444                 :            : 
    1445                 :          0 :   if ( itemFlags() & QgsLayoutItem::FlagOverridesPaint )
    1446                 :            :   {
    1447                 :            :     // item handles it's own painting, so it won't use the built-in opacity handling in QgsLayoutItem::paint, and
    1448                 :            :     // we have to rely on QGraphicsItem opacity to handle this
    1449                 :          0 :     setOpacity( mEvaluatedOpacity );
    1450                 :          0 :   }
    1451                 :            : 
    1452                 :          0 :   if ( updateItem )
    1453                 :            :   {
    1454                 :          0 :     update();
    1455                 :          0 :   }
    1456                 :          0 : }
    1457                 :            : 
    1458                 :          0 : void QgsLayoutItem::refreshFrame( bool updateItem )
    1459                 :            : {
    1460                 :          0 :   if ( !mFrame )
    1461                 :            :   {
    1462                 :          0 :     setPen( Qt::NoPen );
    1463                 :          0 :     return;
    1464                 :            :   }
    1465                 :            : 
    1466                 :            :   //data defined stroke color set?
    1467                 :          0 :   bool ok = false;
    1468                 :          0 :   QColor frameColor = mDataDefinedProperties.valueAsColor( QgsLayoutObject::FrameColor, createExpressionContext(), mFrameColor, &ok );
    1469                 :          0 :   QPen itemPen;
    1470                 :          0 :   if ( ok )
    1471                 :            :   {
    1472                 :          0 :     itemPen = QPen( frameColor );
    1473                 :          0 :   }
    1474                 :            :   else
    1475                 :            :   {
    1476                 :          0 :     itemPen = QPen( mFrameColor );
    1477                 :            :   }
    1478                 :          0 :   itemPen.setJoinStyle( mFrameJoinStyle );
    1479                 :            : 
    1480                 :          0 :   if ( mLayout )
    1481                 :          0 :     itemPen.setWidthF( mLayout->convertToLayoutUnits( mFrameWidth ) );
    1482                 :            :   else
    1483                 :          0 :     itemPen.setWidthF( mFrameWidth.length() );
    1484                 :            : 
    1485                 :          0 :   setPen( itemPen );
    1486                 :            : 
    1487                 :          0 :   if ( updateItem )
    1488                 :            :   {
    1489                 :          0 :     update();
    1490                 :          0 :   }
    1491                 :          0 : }
    1492                 :            : 
    1493                 :          0 : void QgsLayoutItem::refreshBackgroundColor( bool updateItem )
    1494                 :            : {
    1495                 :            :   //data defined fill color set?
    1496                 :          0 :   bool ok = false;
    1497                 :          0 :   QColor backgroundColor = mDataDefinedProperties.valueAsColor( QgsLayoutObject::BackgroundColor, createExpressionContext(), mBackgroundColor, &ok );
    1498                 :          0 :   if ( ok )
    1499                 :            :   {
    1500                 :          0 :     setBrush( QBrush( backgroundColor, Qt::SolidPattern ) );
    1501                 :          0 :   }
    1502                 :            :   else
    1503                 :            :   {
    1504                 :          0 :     setBrush( QBrush( mBackgroundColor, Qt::SolidPattern ) );
    1505                 :            :   }
    1506                 :          0 :   if ( updateItem )
    1507                 :            :   {
    1508                 :          0 :     update();
    1509                 :          0 :   }
    1510                 :          0 : }
    1511                 :            : 
    1512                 :          0 : void QgsLayoutItem::refreshBlendMode()
    1513                 :            : {
    1514                 :          0 :   QPainter::CompositionMode blendMode = mBlendMode;
    1515                 :            : 
    1516                 :            :   //data defined blend mode set?
    1517                 :          0 :   bool ok = false;
    1518                 :          0 :   QString blendStr = mDataDefinedProperties.valueAsString( QgsLayoutObject::BlendMode, createExpressionContext(), QString(), &ok );
    1519                 :          0 :   if ( ok && !blendStr.isEmpty() )
    1520                 :            :   {
    1521                 :          0 :     QString blendstr = blendStr.trimmed();
    1522                 :          0 :     QPainter::CompositionMode blendModeD = QgsSymbolLayerUtils::decodeBlendMode( blendstr );
    1523                 :          0 :     blendMode = blendModeD;
    1524                 :          0 :   }
    1525                 :            : 
    1526                 :            :   // Update the item effect to use the new blend mode
    1527                 :          0 :   mEffect->setCompositionMode( blendMode );
    1528                 :          0 : }
    1529                 :            : 

Generated by: LCOV version 1.14