QGIS API Documentation  3.23.0-Master (eb871beae0)
qgslayoutitemwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutitemwidget.cpp
3  ------------------------
4  Date : July 2017
5  Copyright : (C) 2017 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgslayoutitemwidget.h"
18 #include "qgslayout.h"
19 #include "qgsproject.h"
20 #include "qgslayoutundostack.h"
21 #include "qgsprintlayout.h"
22 #include "qgslayoutatlas.h"
24 #include "qgslayoutframe.h"
25 #include "qgssymbolbutton.h"
26 #include "qgsfontbutton.h"
29 #include "qgslayoutmultiframe.h"
30 #include <QButtonGroup>
31 
32 //
33 // QgsLayoutConfigObject
34 //
35 
37  : QObject( parent )
38  , mLayoutObject( layoutObject )
39 {
40  if ( mLayoutObject->layout() )
41  {
42  connect( &mLayoutObject->layout()->reportContext(), &QgsLayoutReportContext::layerChanged,
43  this, [ = ] { updateDataDefinedButtons(); } );
44  }
45  if ( layoutAtlas() )
46  {
47  connect( layoutAtlas(), &QgsLayoutAtlas::toggled, this, &QgsLayoutConfigObject::updateDataDefinedButtons );
48  }
49 }
50 
51 void QgsLayoutConfigObject::updateDataDefinedProperty()
52 {
53  //match data defined button to item's data defined property
54  QgsPropertyOverrideButton *ddButton = qobject_cast<QgsPropertyOverrideButton *>( sender() );
55  if ( !ddButton )
56  {
57  return;
58  }
60 
61  if ( ddButton->propertyKey() >= 0 )
62  key = static_cast< QgsLayoutObject::DataDefinedProperty >( ddButton->propertyKey() );
63 
64  if ( key == QgsLayoutObject::NoProperty )
65  {
66  return;
67  }
68 
69  const bool propertyAssociatesWithMultiFrame = QgsLayoutObject::propertyAssociatesWithParentMultiframe( key );
70 
71  //set the data defined property and refresh the item
72  if ( propertyAssociatesWithMultiFrame )
73  {
74  if ( QgsLayoutFrame *frame = dynamic_cast< QgsLayoutFrame * >( mLayoutObject.data() ) )
75  {
76  if ( QgsLayoutMultiFrame *multiFrame = frame->multiFrame() )
77  {
78  multiFrame->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
79  multiFrame->refresh();
80  }
81  }
82  else if ( QgsLayoutMultiFrame *multiFrame = dynamic_cast< QgsLayoutMultiFrame * >( mLayoutObject.data() ) )
83  {
84  multiFrame->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
85  multiFrame->refresh();
86  }
87  }
88  else if ( mLayoutObject )
89  {
90  mLayoutObject->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
91  mLayoutObject->refresh();
92  }
93 }
94 
95 void QgsLayoutConfigObject::updateDataDefinedButtons()
96 {
97  const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
98  for ( QgsPropertyOverrideButton *button : buttons )
99  {
100  button->setVectorLayer( coverageLayer() );
101  }
102 }
103 
105 {
106  button->blockSignals( true );
107  button->init( key, mLayoutObject->dataDefinedProperties(), QgsLayoutObject::propertyDefinitions(), coverageLayer() );
108  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
109  button->registerExpressionContextGenerator( mLayoutObject );
110  button->blockSignals( false );
111 }
112 
114 {
115  if ( !button )
116  return;
117 
118  if ( button->propertyKey() < 0 || !mLayoutObject )
119  return;
120 
122  whileBlocking( button )->setToProperty( mLayoutObject->dataDefinedProperties().property( key ) );
123 
124  // In case the button was initialized to a different config object, we need to reconnect to it here (see https://github.com/qgis/QGIS/issues/26582 )
125  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
126  button->registerExpressionContextGenerator( mLayoutObject );
127 }
128 
130 {
131  if ( !mLayoutObject )
132  {
133  return nullptr;
134  }
135 
136  QgsPrintLayout *printLayout = qobject_cast< QgsPrintLayout * >( mLayoutObject->layout() );
137 
138  if ( !printLayout )
139  {
140  return nullptr;
141  }
142 
143  return printLayout->atlas();
144 }
145 
147 {
148  mLayoutObject = object;
149 }
150 
152 {
153  if ( !mLayoutObject )
154  return nullptr;
155 
156  QgsLayout *layout = mLayoutObject->layout();
157  if ( !layout )
158  return nullptr;
159 
160  return layout->reportContext().layer();
161 }
162 
163 
164 //
165 // QgsLayoutItemBaseWidget
166 //
167 
169  : QgsPanelWidget( parent )
170  , mConfigObject( new QgsLayoutConfigObject( this, layoutObject ) )
171  , mObject( layoutObject )
172 {
173 
174 }
175 
177 {
178  return mObject;
179 }
180 
182 {
183  QgsLayoutObject *oldObject = mObject;
184  QgsLayoutConfigObject *oldConfigObject = mConfigObject;
185  // have to set new mObject/mConfigObject here, because setNewItem methods require access to them
186  mObject = item;
187  mConfigObject = new QgsLayoutConfigObject( this, mObject );
188  if ( setNewItem( item ) )
189  {
190  oldConfigObject->deleteLater();
191  return true;
192  }
193  else
194  {
195  // revert object change since it was unsuccessful
196  mObject = oldObject;
197  mConfigObject->deleteLater();
198  mConfigObject = oldConfigObject;
199  return false;
200  }
201 }
202 
204 {
205 }
206 
208 {
209  const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
210  for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
211  {
212  symbolWidget->setMessageBar( iface->messageBar() );
213  }
214  const auto fontButtonWidgets = findChildren<QgsFontButton *>();
215  for ( QgsFontButton *fontButton : fontButtonWidgets )
216  {
217  fontButton->setMessageBar( iface->messageBar() );
218  }
219 }
220 
222 {
223 
224 }
225 
227 {
228  mConfigObject->initializeDataDefinedButton( button, property );
229 }
230 
232 {
233  mConfigObject->updateDataDefinedButton( button );
234 }
235 
237 {
238  return mConfigObject->coverageLayer();
239 }
240 
242 {
243  return false;
244 }
245 
247 {
248  return mConfigObject->layoutAtlas();
249 }
250 
251 //
252 
253 
254 //QgsLayoutItemPropertiesWidget
255 
257 {
258  if ( !mItem )
259  return;
260 
261  mBlockVariableUpdates = true;
262  QgsExpressionContext context = mItem->createExpressionContext();
263  mVariableEditor->setContext( &context );
264 
265  // here, we prefer to make the multiframe's scope the editable one. That's because most expressions are evaluated
266  // on the multiframe subclass level, not on a frame-by-frame basis. Ideally both would be editable, but for now let's go
267  // with the most useful one.
268  const int multiFrameScopeIndex = context.indexOfScope( tr( "Multiframe Item" ) );
269  const int itemScopeIndex = context.indexOfScope( tr( "Layout Item" ) );
270  if ( multiFrameScopeIndex >= 0 )
271  mVariableEditor->setEditableScopeIndex( multiFrameScopeIndex );
272  else if ( itemScopeIndex >= 0 )
273  mVariableEditor->setEditableScopeIndex( itemScopeIndex );
274  mBlockVariableUpdates = false;
275 }
276 
278  : QWidget( parent )
279  , mConfigObject( new QgsLayoutConfigObject( this, item ) )
280 {
281  setupUi( this );
282 
283  mVariableEditor->setMinimumHeight( mVariableEditor->fontMetrics().height() * 15 );
284 
285  mItemRotationSpinBox->setClearValue( 0 );
286  mStrokeUnitsComboBox->linkToWidget( mStrokeWidthSpinBox );
287  mStrokeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
288 
289  mPosUnitsComboBox->linkToWidget( mXPosSpin );
290  mPosUnitsComboBox->linkToWidget( mYPosSpin );
291  mSizeUnitsComboBox->linkToWidget( mWidthSpin );
292  mSizeUnitsComboBox->linkToWidget( mHeightSpin );
293 
294  mPosUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
295  mSizeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
296 
297  mPosLockAspectRatio->setWidthSpinBox( mXPosSpin );
298  mPosLockAspectRatio->setHeightSpinBox( mYPosSpin );
299  mSizeLockAspectRatio->setWidthSpinBox( mWidthSpin );
300  mSizeLockAspectRatio->setHeightSpinBox( mHeightSpin );
301 
302  mItemFrameColorDDBtn->registerLinkedWidget( mFrameColorButton );
303  mItemBackgroundColorDDBtn->registerLinkedWidget( mBackgroundColorButton );
304 
305  connect( mFrameColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged );
306  connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged );
307  connect( mStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged );
308  connect( mStrokeUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::strokeUnitChanged );
309  connect( mFrameGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled );
310  connect( mFrameJoinStyleCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged );
311  connect( mBackgroundGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled );
312  connect( mItemIdLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished );
313  connect( mPageSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged );
314  connect( mXPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged );
315  connect( mYPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged );
316  connect( mPosUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::positionUnitsChanged );
317  connect( mWidthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged );
318  connect( mHeightSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged );
319  connect( mSizeUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::sizeUnitsChanged );
320  connect( mUpperLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged );
321  connect( mUpperMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged );
322  connect( mUpperRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged );
323  connect( mMiddleLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged );
324  connect( mMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged );
325  connect( mMiddleRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged );
326  connect( mLowerLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged );
327  connect( mLowerMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged );
328  connect( mLowerRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged );
329  connect( mBlendModeCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged );
330  connect( mItemRotationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged );
331  connect( mExcludeFromPrintsCheckBox, &QCheckBox::toggled, this, &QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled );
332 
333  //make button exclusive
334  QButtonGroup *buttonGroup = new QButtonGroup( this );
335  buttonGroup->addButton( mUpperLeftRadioButton );
336  buttonGroup->addButton( mUpperMiddleRadioButton );
337  buttonGroup->addButton( mUpperRightRadioButton );
338  buttonGroup->addButton( mMiddleLeftRadioButton );
339  buttonGroup->addButton( mMiddleRadioButton );
340  buttonGroup->addButton( mMiddleRightRadioButton );
341  buttonGroup->addButton( mLowerLeftRadioButton );
342  buttonGroup->addButton( mLowerMiddleRadioButton );
343  buttonGroup->addButton( mLowerRightRadioButton );
344  buttonGroup->setExclusive( true );
345 
347 
348  setItem( item );
349 
350  connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsLayoutItemPropertiesWidget::opacityChanged );
351 
352  updateVariables();
353  connect( mVariableEditor, &QgsVariableEditorWidget::scopeChanged, this, [ = ]
354  {
355  if ( !mBlockVariableUpdates )
356  QgsLayoutItemPropertiesWidget::variablesChanged();
357  } );
358  // listen out for variable edits
362 
363  if ( item->layout() )
364  {
368  }
369 }
370 
372 {
373  mBackgroundGroupBox->setVisible( showGroup );
374 }
375 
377 {
378  mFrameGroupBox->setVisible( showGroup );
379 }
380 
382 {
383  if ( mItem )
384  {
385  disconnect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
386  disconnect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
387  }
388  mItem = item;
389  if ( mItem )
390  {
391  connect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
392  connect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
393  }
394 
395  mConfigObject->setObject( mItem );
396 
397  setValuesForGuiElements();
398 }
399 
401 {
402  if ( QgsPrintLayout *printLayout = dynamic_cast< QgsPrintLayout * >( masterLayout ) )
403  {
406  }
407 }
408 
409 //slots
410 
411 void QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged( const QColor &newFrameColor )
412 {
413  if ( !mItem )
414  {
415  return;
416  }
417  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Color" ), QgsLayoutItem::UndoStrokeColor );
418  mItem->setFrameStrokeColor( newFrameColor );
419  mItem->layout()->undoStack()->endCommand();
420  mItem->update();
421 }
422 
423 void QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged( const QColor &newBackgroundColor )
424 {
425  if ( !mItem )
426  {
427  return;
428  }
429  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Background Color" ), QgsLayoutItem::UndoBackgroundColor );
430  mItem->setBackgroundColor( newBackgroundColor );
431  mItem->layout()->undoStack()->endCommand();
432  mItem->invalidateCache();
433 }
434 
435 void QgsLayoutItemPropertiesWidget::changeItemPosition()
436 {
437  if ( !mItem )
438  return;
439 
440  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
441 
442  const QgsLayoutPoint point( mXPosSpin->value(), mYPosSpin->value(), mPosUnitsComboBox->unit() );
443  mItem->attemptMove( point, true, false, mPageSpinBox->value() - 1 );
444 
445  mItem->layout()->undoStack()->endCommand();
446 }
447 
448 void QgsLayoutItemPropertiesWidget::changeItemReference( QgsLayoutItem::ReferencePoint point )
449 {
450  if ( !mItem )
451  return;
452 
453  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item Reference" ) );
454  mItem->setReferencePoint( point );
455  mItem->layout()->undoStack()->endCommand();
456 }
457 
458 void QgsLayoutItemPropertiesWidget::changeItemSize()
459 {
460  if ( !mItem )
461  return;
462 
463  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Resize Item" ), QgsLayoutItem::UndoIncrementalResize );
464 
465  const QgsLayoutSize size( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() );
466  mItem->attemptResize( size );
467 
468  mItem->layout()->undoStack()->endCommand();
469 }
470 
471 void QgsLayoutItemPropertiesWidget::variablesChanged()
472 {
473  if ( !mItem )
474  return;
475 
476  if ( QgsLayoutFrame *frame = qobject_cast< QgsLayoutFrame * >( mItem ) )
477  {
478  if ( QgsLayoutMultiFrame *mf = frame->multiFrame() )
479  {
480  QgsExpressionContextUtils::setLayoutMultiFrameVariables( mf, mVariableEditor->variablesInActiveScope() );
481  }
482  }
483  else
484  {
485  QgsExpressionContextUtils::setLayoutItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
486  }
487 }
488 
490 {
491  if ( mUpperLeftRadioButton->isChecked() )
492  {
494  }
495  else if ( mUpperMiddleRadioButton->isChecked() )
496  {
498  }
499  else if ( mUpperRightRadioButton->isChecked() )
500  {
502  }
503  else if ( mMiddleLeftRadioButton->isChecked() )
504  {
506  }
507  else if ( mMiddleRadioButton->isChecked() )
508  {
509  return QgsLayoutItem::Middle;
510  }
511  else if ( mMiddleRightRadioButton->isChecked() )
512  {
514  }
515  else if ( mLowerLeftRadioButton->isChecked() )
516  {
518  }
519  else if ( mLowerMiddleRadioButton->isChecked() )
520  {
522  }
523  else if ( mLowerRightRadioButton->isChecked() )
524  {
526  }
528 }
529 
530 void QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged( double d )
531 {
532  if ( !mItem )
533  {
534  return;
535  }
536 
537  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
538  mItem->setFrameStrokeWidth( QgsLayoutMeasurement( d, mStrokeUnitsComboBox->unit() ) );
539  mItem->layout()->undoStack()->endCommand();
540 }
541 
542 void QgsLayoutItemPropertiesWidget::strokeUnitChanged( QgsUnitTypes::LayoutUnit unit )
543 {
544  if ( !mItem )
545  {
546  return;
547  }
548 
549  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
550  mItem->setFrameStrokeWidth( QgsLayoutMeasurement( mStrokeWidthSpinBox->value(), unit ) );
551  mItem->layout()->undoStack()->endCommand();
552 }
553 
554 void QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged( int index )
555 {
556  Q_UNUSED( index )
557  if ( !mItem )
558  {
559  return;
560  }
561 
562  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Join Style" ) );
563  mItem->setFrameJoinStyle( mFrameJoinStyleCombo->penJoinStyle() );
564  mItem->layout()->undoStack()->endCommand();
565 }
566 
567 void QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled( bool state )
568 {
569  if ( !mItem )
570  {
571  return;
572  }
573 
574  mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Frame" ) : tr( "Disable Frame" ) );
575  mItem->setFrameEnabled( state );
576  mItem->update();
577  mItem->layout()->undoStack()->endCommand();
578 }
579 
580 void QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled( bool state )
581 {
582  if ( !mItem )
583  {
584  return;
585  }
586 
587  mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Background" ) : tr( "Disable Background" ) );
588  mItem->setBackgroundEnabled( state );
589  mItem->layout()->undoStack()->endCommand();
590  mItem->invalidateCache();
591 }
592 
593 
594 void QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements()
595 {
596  if ( !mItem )
597  {
598  return;
599  }
600 
601  auto block = [ = ]( bool blocked )
602  {
603  mXPosSpin->blockSignals( blocked );
604  mYPosSpin->blockSignals( blocked );
605  mPosUnitsComboBox->blockSignals( blocked );
606  mWidthSpin->blockSignals( blocked );
607  mHeightSpin->blockSignals( blocked );
608  mSizeUnitsComboBox->blockSignals( blocked );
609  mUpperLeftRadioButton->blockSignals( blocked );
610  mUpperMiddleRadioButton->blockSignals( blocked );
611  mUpperRightRadioButton->blockSignals( blocked );
612  mMiddleLeftRadioButton->blockSignals( blocked );
613  mMiddleRadioButton->blockSignals( blocked );
614  mMiddleRightRadioButton->blockSignals( blocked );
615  mLowerLeftRadioButton->blockSignals( blocked );
616  mLowerMiddleRadioButton->blockSignals( blocked );
617  mLowerRightRadioButton->blockSignals( blocked );
618  mPageSpinBox->blockSignals( blocked );
619  };
620  block( true );
621 
622  const QgsLayoutPoint point = mItem->pagePositionWithUnits();
623 
624  if ( !mFreezeXPosSpin )
625  mXPosSpin->setValue( point.x() );
626  if ( !mFreezeYPosSpin )
627  mYPosSpin->setValue( point.y() );
628  mPosUnitsComboBox->setUnit( point.units() );
629 
630  switch ( mItem->referencePoint() )
631  {
633  {
634  mUpperLeftRadioButton->setChecked( true );
635  break;
636  }
637 
639  {
640  mUpperMiddleRadioButton->setChecked( true );
641  break;
642  }
643 
645  {
646  mUpperRightRadioButton->setChecked( true );
647  break;
648  }
649 
651  {
652  mMiddleLeftRadioButton->setChecked( true );
653  break;
654  }
655 
657  {
658  mMiddleRadioButton->setChecked( true );
659  break;
660  }
661 
663  {
664  mMiddleRightRadioButton->setChecked( true );
665  break;
666  }
667 
669  {
670  mLowerLeftRadioButton->setChecked( true );
671  break;
672  }
673 
675  {
676  mLowerMiddleRadioButton->setChecked( true );
677  break;
678  }
679 
681  {
682  mLowerRightRadioButton->setChecked( true );
683  break;
684  }
685  }
686 
687  const QgsLayoutSize size = mItem->sizeWithUnits();
688  if ( !mFreezeWidthSpin )
689  mWidthSpin->setValue( size.width() );
690  if ( !mFreezeHeightSpin )
691  mHeightSpin->setValue( size.height() );
692 
693  mSizeUnitsComboBox->setUnit( size.units() );
694 
695  mSizeLockAspectRatio->resetRatio();
696  mPosLockAspectRatio->resetRatio();
697 
698  if ( !mFreezePageSpin )
699  mPageSpinBox->setValue( mItem->page() + 1 );
700 
701  block( false );
702 }
703 
704 void QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements()
705 {
706  if ( !mItem )
707  {
708  return;
709  }
710 
711  auto block = [ = ]( bool blocked )
712  {
713  mStrokeWidthSpinBox->blockSignals( blocked );
714  mStrokeUnitsComboBox->blockSignals( blocked );
715  mFrameGroupBox->blockSignals( blocked );
716  mBackgroundGroupBox->blockSignals( blocked );
717  mItemIdLineEdit->blockSignals( blocked );
718  mBlendModeCombo->blockSignals( blocked );
719  mOpacityWidget->blockSignals( blocked );
720  mFrameColorButton->blockSignals( blocked );
721  mFrameJoinStyleCombo->blockSignals( blocked );
722  mBackgroundColorButton->blockSignals( blocked );
723  mItemRotationSpinBox->blockSignals( blocked );
724  mExcludeFromPrintsCheckBox->blockSignals( blocked );
725  };
726  block( true );
727 
728  mBackgroundColorButton->setColor( mItem->backgroundColor() );
729  mFrameColorButton->setColor( mItem->frameStrokeColor() );
730  mStrokeUnitsComboBox->setUnit( mItem->frameStrokeWidth().units() );
731  mStrokeWidthSpinBox->setValue( mItem->frameStrokeWidth().length() );
732  mFrameJoinStyleCombo->setPenJoinStyle( mItem->frameJoinStyle() );
733  mItemIdLineEdit->setText( mItem->id() );
734  mFrameGroupBox->setChecked( mItem->frameEnabled() );
735  mBackgroundGroupBox->setChecked( mItem->hasBackground() );
736  mBlendModeCombo->setBlendMode( mItem->blendMode() );
737  mOpacityWidget->setOpacity( mItem->itemOpacity() );
738  mItemRotationSpinBox->setValue( mItem->itemRotation() );
739  mExcludeFromPrintsCheckBox->setChecked( mItem->excludeFromExports() );
740 
741  block( false );
742 }
743 
745 {
746  mConfigObject->initializeDataDefinedButton( mXPositionDDBtn, QgsLayoutObject::PositionX );
747  mConfigObject->initializeDataDefinedButton( mYPositionDDBtn, QgsLayoutObject::PositionY );
748  mConfigObject->initializeDataDefinedButton( mWidthDDBtn, QgsLayoutObject::ItemWidth );
749  mConfigObject->initializeDataDefinedButton( mHeightDDBtn, QgsLayoutObject::ItemHeight );
750  mConfigObject->initializeDataDefinedButton( mItemRotationDDBtn, QgsLayoutObject::ItemRotation );
751  mConfigObject->initializeDataDefinedButton( mOpacityDDBtn, QgsLayoutObject::Opacity );
752  mConfigObject->initializeDataDefinedButton( mBlendModeDDBtn, QgsLayoutObject::BlendMode );
753  mConfigObject->initializeDataDefinedButton( mExcludePrintsDDBtn, QgsLayoutObject::ExcludeFromExports );
754  mConfigObject->initializeDataDefinedButton( mItemFrameColorDDBtn, QgsLayoutObject::FrameColor );
755  mConfigObject->initializeDataDefinedButton( mItemBackgroundColorDDBtn, QgsLayoutObject::BackgroundColor );
756 }
757 
759 {
760  const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
761  for ( QgsPropertyOverrideButton *button : buttons )
762  {
763  mConfigObject->updateDataDefinedButton( button );
764  }
765 }
766 
767 void QgsLayoutItemPropertiesWidget::setValuesForGuiElements()
768 {
769  if ( !mItem )
770  {
771  return;
772  }
773 
774  mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
775  mBackgroundColorButton->setAllowOpacity( true );
776  mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
777  mFrameColorButton->setColorDialogTitle( tr( "Select Frame Color" ) );
778  mFrameColorButton->setAllowOpacity( true );
779  mFrameColorButton->setContext( QStringLiteral( "composer" ) );
780 
781  setValuesForGuiPositionElements();
782  setValuesForGuiNonPositionElements();
784 
785  updateVariables();
786 }
787 
788 void QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged( int index )
789 {
790  Q_UNUSED( index )
791  if ( mItem )
792  {
793  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Blend Mode" ) );
794  mItem->setBlendMode( mBlendModeCombo->blendMode() );
795  mItem->layout()->undoStack()->endCommand();
796  }
797 }
798 
799 void QgsLayoutItemPropertiesWidget::opacityChanged( double value )
800 {
801  if ( mItem )
802  {
803  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Opacity" ), QgsLayoutItem::UndoOpacity );
804  mItem->setItemOpacity( value );
805  mItem->layout()->undoStack()->endCommand();
806  }
807 }
808 
809 void QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished()
810 {
811  if ( mItem )
812  {
813  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item ID" ), QgsLayoutItem::UndoSetId );
814  mItem->setId( mItemIdLineEdit->text() );
815  mItemIdLineEdit->setText( mItem->id() );
816  mItem->layout()->undoStack()->endCommand();
817  }
818 }
819 
820 void QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged( int )
821 {
822  mFreezePageSpin = true;
823  changeItemPosition();
824  mFreezePageSpin = false;
825 }
826 
827 void QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged( double )
828 {
829  mFreezeXPosSpin = true;
830  changeItemPosition();
831  mFreezeXPosSpin = false;
832 }
833 
834 void QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged( double )
835 {
836  mFreezeYPosSpin = true;
837  changeItemPosition();
838  mFreezeYPosSpin = false;
839 }
840 
841 void QgsLayoutItemPropertiesWidget::positionUnitsChanged( QgsUnitTypes::LayoutUnit )
842 {
843  changeItemPosition();
844 }
845 
846 void QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged( double )
847 {
848  mFreezeWidthSpin = true;
849  changeItemSize();
850  mFreezeWidthSpin = false;
851 }
852 
853 void QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged( double )
854 {
855  mFreezeHeightSpin = true;
856  changeItemSize();
857  mFreezeHeightSpin = false;
858 }
859 
860 void QgsLayoutItemPropertiesWidget::sizeUnitsChanged( QgsUnitTypes::LayoutUnit )
861 {
862  changeItemSize();
863 }
864 
865 void QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged( bool state )
866 {
867  if ( !state )
868  return;
869 
870  if ( mItem )
871  {
872  changeItemReference( QgsLayoutItem::UpperLeft );
873  }
874  setValuesForGuiPositionElements();
875 }
876 
877 void QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged( bool state )
878 {
879  if ( !state )
880  return;
881  if ( mItem )
882  {
883  changeItemReference( QgsLayoutItem::UpperMiddle );
884  }
885  setValuesForGuiPositionElements();
886 }
887 
888 void QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged( bool state )
889 {
890  if ( !state )
891  return;
892  if ( mItem )
893  {
894  changeItemReference( QgsLayoutItem::UpperRight );
895  }
896  setValuesForGuiPositionElements();
897 }
898 
899 void QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged( bool state )
900 {
901  if ( !state )
902  return;
903  if ( mItem )
904  {
905  changeItemReference( QgsLayoutItem::MiddleLeft );
906  }
907  setValuesForGuiPositionElements();
908 }
909 
910 void QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged( bool state )
911 {
912  if ( !state )
913  return;
914  if ( mItem )
915  {
916  changeItemReference( QgsLayoutItem::Middle );
917  }
918  setValuesForGuiPositionElements();
919 }
920 
921 void QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged( bool state )
922 {
923  if ( !state )
924  return;
925  if ( mItem )
926  {
927  changeItemReference( QgsLayoutItem::MiddleRight );
928  }
929  setValuesForGuiPositionElements();
930 }
931 
932 void QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged( bool state )
933 {
934  if ( !state )
935  return;
936  if ( mItem )
937  {
938  changeItemReference( QgsLayoutItem::LowerLeft );
939  }
940  setValuesForGuiPositionElements();
941 }
942 
943 void QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged( bool state )
944 {
945  if ( !state )
946  return;
947  if ( mItem )
948  {
949  changeItemReference( QgsLayoutItem::LowerMiddle );
950  }
951  setValuesForGuiPositionElements();
952 }
953 
954 void QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged( bool state )
955 {
956  if ( !state )
957  return;
958  if ( mItem )
959  {
960  changeItemReference( QgsLayoutItem::LowerRight );
961  }
962  setValuesForGuiPositionElements();
963 }
964 
965 void QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged( double val )
966 {
967  if ( mItem )
968  {
969  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Rotate" ), QgsLayoutItem::UndoRotation );
970  mItem->setItemRotation( val, true );
971  mItem->update();
972  mItem->layout()->undoStack()->endCommand();
973  }
974 }
975 
976 void QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled( bool checked )
977 {
978  if ( mItem )
979  {
980  mItem->layout()->undoStack()->beginCommand( mItem, checked ? tr( "Exclude from Exports" ) : tr( "Include in Exports" ) );
981  mItem->setExcludeFromExports( checked );
982  mItem->layout()->undoStack()->endCommand();
983  }
984 }
void customVariablesChanged()
Emitted whenever a custom global variable changes.
static QgsApplication * instance()
Returns the singleton instance of the QgsApplication.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
static void setLayoutItemVariables(QgsLayoutItem *item, const QVariantMap &variables)
Sets all layout item context variables for an item.
static void setLayoutMultiFrameVariables(QgsLayoutMultiFrame *frame, const QVariantMap &variables)
Sets all layout multiframe context variables for an frame.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
int indexOfScope(QgsExpressionContextScope *scope) const
Returns the index of the specified scope if it exists within the context.
A button for customizing QgsTextFormat settings.
Definition: qgsfontbutton.h:48
Class used to render QgsLayout as an atlas, by iterating over the features from an associated vector ...
void toggled(bool)
Emitted when atlas is enabled or disabled.
void coverageLayerChanged(QgsVectorLayer *layer)
Emitted when the coverage layer for the atlas changes.
An object for property widgets for layout items.
QgsLayoutAtlas * layoutAtlas() const
Returns the atlas for the layout, if available.
void setObject(QgsLayoutObject *object) SIP_SKIP
Links a new layout object to this QgsLayoutConfigObject.
void initializeDataDefinedButton(QgsPropertyOverrideButton *button, QgsLayoutObject::DataDefinedProperty key)
Registers a data defined button, setting up its initial value, connections and description.
QgsVectorLayer * coverageLayer() const
Returns the current layout context coverage layer (if set).
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a data defined button to reflect the item's current properties.
QgsLayoutConfigObject(QWidget *parent SIP_TRANSFERTHIS, QgsLayoutObject *layoutObject)
Constructor for QgsLayoutConfigObject, linked with the specified layoutObject.
A common interface for layout designer dialogs and widgets.
virtual QgsMessageBar * messageBar()=0
Returns the designer's message bar.
Base class for frame items, which form a layout multiframe item.
QgsLayoutObject * layoutObject()
Returns the layout object associated with this widget.
void updateDataDefinedButton(QgsPropertyOverrideButton *button)
Updates a previously registered data defined button to reflect the item's current properties.
bool setItem(QgsLayoutItem *item)
Sets the current item to show in the widget.
QgsVectorLayer * coverageLayer() const
Returns the current layout context coverage layer (if set).
virtual bool setNewItem(QgsLayoutItem *item)
Attempts to update the widget to show the properties for the specified item.
void registerDataDefinedButton(QgsPropertyOverrideButton *button, QgsLayoutObject::DataDefinedProperty property)
Registers a data defined button, setting up its initial value, connections and description.
virtual void setDesignerInterface(QgsLayoutDesignerInterface *iface)
Sets the the layout designer interface in which the widget is being shown.
QgsLayoutAtlas * layoutAtlas() const
Returns the atlas for the layout (if available)
virtual void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
QgsLayoutItemBaseWidget(QWidget *parent SIP_TRANSFERTHIS, QgsLayoutObject *layoutObject)
Constructor for QgsLayoutItemBaseWidget, linked with the specified layoutObject.
virtual void setReportTypeString(const QString &string)
Sets the string to use to describe the current report type (e.g.
void setMasterLayout(QgsMasterLayoutInterface *masterLayout)
Sets the master layout associated with the item.
void populateDataDefinedButtons()
Sets data defined button state to match item.
QgsLayoutItemPropertiesWidget(QWidget *parent, QgsLayoutItem *item)
Constructs a QgsLayoutItemPropertiesWidget with a parent and for the given layout item.
void initializeDataDefinedButtons()
Initializes data defined buttons to current atlas coverage layer.
void showFrameGroup(bool showGroup)
Determines if the frame of the group box shall be shown.
void setItem(QgsLayoutItem *item)
Sets the layout item.
QgsLayoutItem::ReferencePoint positionMode() const
Returns the position mode.
void updateVariables()
Updates the variables widget, refreshing the values of variables shown.
void showBackgroundGroup(bool showGroup)
Determines if the background of the group box shall be shown.
Base class for graphical items within a QgsLayout.
@ UndoIncrementalMove
Layout item incremental movement, e.g. as a result of a keypress.
@ UndoBackgroundColor
Background color adjustment.
@ UndoOpacity
Opacity adjustment.
@ UndoIncrementalResize
Incremental resize.
@ UndoRotation
Rotation adjustment.
@ UndoStrokeWidth
Stroke width adjustment.
@ UndoSetId
Change item ID.
@ UndoStrokeColor
Stroke color adjustment.
ReferencePoint
Fixed position reference point.
@ LowerMiddle
Lower center of item.
@ MiddleLeft
Middle left of item.
@ Middle
Center of item.
@ UpperRight
Upper right corner of item.
@ LowerLeft
Lower left corner of item.
@ UpperLeft
Upper left corner of item.
@ UpperMiddle
Upper center of item.
@ MiddleRight
Middle right of item.
@ LowerRight
Lower right corner of item.
void sizePositionChanged()
Emitted when the item's size or position changes.
This class provides a method of storing measurements for use in QGIS layouts using a variety of diffe...
Abstract base class for layout items with the ability to distribute the content to several frames (Qg...
A base class for objects which belong to a layout.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the layout object property definitions.
const QgsLayout * layout() const
Returns the layout the object is attached to.
void changed()
Emitted when the object's properties change.
DataDefinedProperty
Data defined properties for different item types.
@ Opacity
Item opacity.
@ ItemWidth
Width of item.
@ ItemHeight
Height of item.
@ BlendMode
Item blend mode.
@ PositionY
Y position on page.
@ ExcludeFromExports
Exclude item from exports.
@ BackgroundColor
Item background color.
@ ItemRotation
Rotation of item.
@ NoProperty
No property.
@ PositionX
X position on page.
@ FrameColor
Item frame color.
static bool propertyAssociatesWithParentMultiframe(DataDefinedProperty property)
Returns true if the specified property key is normally associated with the parent QgsLayoutMultiFrame...
void changed()
Emitted when pages are added or removed from the collection.
This class provides a method of storing points, consisting of an x and y coordinate,...
double x() const
Returns x coordinate of point.
QgsUnitTypes::LayoutUnit units() const
Returns the units for the point.
double y() const
Returns y coordinate of point.
void dpiChanged()
Emitted when the context's DPI is changed.
const QgsLayoutMeasurementConverter & measurementConverter() const
Returns the layout measurement converter to be used in the layout.
void layerChanged(QgsVectorLayer *layer)
Emitted when the context's layer is changed.
QgsVectorLayer * layer() const
Returns the vector layer associated with the layout's context.
This class provides a method of storing sizes, consisting of a width and height, for use in QGIS layo...
Definition: qgslayoutsize.h:41
QgsUnitTypes::LayoutUnit units() const
Returns the units for the size.
double height() const
Returns the height of the size.
Definition: qgslayoutsize.h:90
double width() const
Returns the width of the size.
Definition: qgslayoutsize.h:76
void changed(QgsUnitTypes::LayoutUnit unit)
Emitted when the unit is changed.
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:51
QgsLayoutRenderContext & renderContext()
Returns a reference to the layout's render context, which stores information relating to the current ...
Definition: qgslayout.cpp:359
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
Definition: qgslayout.cpp:459
void variablesChanged()
Emitted whenever the expression variables stored in the layout have been changed.
QgsLayoutReportContext & reportContext()
Returns a reference to the layout's report context, which stores information relating to the current ...
Definition: qgslayout.cpp:369
QgsProject * project() const
The project associated with the layout.
Definition: qgslayout.cpp:132
Interface for master layout type objects, such as print layouts and reports.
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
Base class for any widget that can be shown as a inline panel.
Print layout, a QgsLayout subclass for static or atlas-based layouts.
QgsLayoutAtlas * atlas()
Returns the print layout's atlas.
void nameChanged(const QString &name)
Emitted when the layout's name is changed.
void metadataChanged()
Emitted when the project's metadata is changed.
void customVariablesChanged()
Emitted whenever the expression variables stored in the project have been changed.
A button for controlling property overrides which may apply to a widget.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
void changed()
Emitted when property definition changes.
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout).
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
int propertyKey() const
Returns the property key linked to the button.
A button for creating and modifying QgsSymbol settings.
LayoutUnit
Layout measurement units.
Definition: qgsunittypes.h:182
void scopeChanged()
Emitted when the user has modified a scope using the widget.
Represents a vector layer which manages a vector based data sets.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:1443