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