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