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