QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 
25 #include <QButtonGroup>
26 
27 //
28 // QgsLayoutConfigObject
29 //
30 
32  : QObject( parent )
33  , mLayoutObject( layoutObject )
34 {
35  if ( mLayoutObject->layout() )
36  {
37  connect( &mLayoutObject->layout()->reportContext(), &QgsLayoutReportContext::layerChanged,
38  this, [ = ] { updateDataDefinedButtons(); } );
39  }
40  if ( layoutAtlas() )
41  {
42  connect( layoutAtlas(), &QgsLayoutAtlas::toggled, this, &QgsLayoutConfigObject::updateDataDefinedButtons );
43  }
44 }
45 
46 void QgsLayoutConfigObject::updateDataDefinedProperty()
47 {
48  //match data defined button to item's data defined property
49  QgsPropertyOverrideButton *ddButton = qobject_cast<QgsPropertyOverrideButton *>( sender() );
50  if ( !ddButton )
51  {
52  return;
53  }
55 
56  if ( ddButton->propertyKey() >= 0 )
57  key = static_cast< QgsLayoutObject::DataDefinedProperty >( ddButton->propertyKey() );
58 
59  if ( key == QgsLayoutObject::NoProperty )
60  {
61  return;
62  }
63 
64  //set the data defined property and refresh the item
65  if ( mLayoutObject )
66  {
67  mLayoutObject->dataDefinedProperties().setProperty( key, ddButton->toProperty() );
68  mLayoutObject->refresh();
69  }
70 }
71 
72 void QgsLayoutConfigObject::updateDataDefinedButtons()
73 {
74  const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
75  for ( QgsPropertyOverrideButton *button : buttons )
76  {
77  button->setVectorLayer( coverageLayer() );
78  }
79 }
80 
82 {
83  button->blockSignals( true );
84  button->init( key, mLayoutObject->dataDefinedProperties(), QgsLayoutObject::propertyDefinitions(), coverageLayer() );
85  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
86  button->registerExpressionContextGenerator( mLayoutObject );
87  button->blockSignals( false );
88 }
89 
91 {
92  if ( !button )
93  return;
94 
95  if ( button->propertyKey() < 0 || !mLayoutObject )
96  return;
97 
99  whileBlocking( button )->setToProperty( mLayoutObject->dataDefinedProperties().property( key ) );
100 
101  // 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 )
102  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
103  button->registerExpressionContextGenerator( mLayoutObject );
104 }
105 
107 {
108  if ( !mLayoutObject )
109  {
110  return nullptr;
111  }
112 
113  QgsPrintLayout *printLayout = qobject_cast< QgsPrintLayout * >( mLayoutObject->layout() );
114 
115  if ( !printLayout )
116  {
117  return nullptr;
118  }
119 
120  return printLayout->atlas();
121 }
122 
124 {
125  mLayoutObject = object;
126 }
127 
129 {
130  if ( !mLayoutObject )
131  return nullptr;
132 
133  QgsLayout *layout = mLayoutObject->layout();
134  if ( !layout )
135  return nullptr;
136 
137  return layout->reportContext().layer();
138 }
139 
140 
141 //
142 // QgsLayoutItemBaseWidget
143 //
144 
146  : QgsPanelWidget( parent )
147  , mConfigObject( new QgsLayoutConfigObject( this, layoutObject ) )
148  , mObject( layoutObject )
149 {
150 
151 }
152 
154 {
155  return mObject;
156 }
157 
159 {
160  QgsLayoutObject *oldObject = mObject;
161  QgsLayoutConfigObject *oldConfigObject = mConfigObject;
162  // have to set new mObject/mConfigObject here, because setNewItem methods require access to them
163  mObject = item;
164  mConfigObject = new QgsLayoutConfigObject( this, mObject );
165  if ( setNewItem( item ) )
166  {
167  oldConfigObject->deleteLater();
168  return true;
169  }
170  else
171  {
172  // revert object change since it was unsuccessful
173  mObject = oldObject;
174  mConfigObject->deleteLater();
175  mConfigObject = oldConfigObject;
176  return false;
177  }
178 }
179 
181 {
182 }
183 
185 {
186 
187 }
188 
190 {
191  mConfigObject->initializeDataDefinedButton( button, property );
192 }
193 
195 {
196  mConfigObject->updateDataDefinedButton( button );
197 }
198 
200 {
201  return mConfigObject->coverageLayer();
202 }
203 
205 {
206  return false;
207 }
208 
210 {
211  return mConfigObject->layoutAtlas();
212 }
213 
214 //
215 
216 
217 //QgsLayoutItemPropertiesWidget
218 
219 void QgsLayoutItemPropertiesWidget::updateVariables()
220 {
221  if ( !mItem )
222  return;
223 
224  QgsExpressionContext context = mItem->createExpressionContext();
225  mVariableEditor->setContext( &context );
226  int editableIndex = context.indexOfScope( tr( "Layout Item" ) );
227  if ( editableIndex >= 0 )
228  mVariableEditor->setEditableScopeIndex( editableIndex );
229 }
230 
232  : QWidget( parent )
233  , mConfigObject( new QgsLayoutConfigObject( this, item ) )
234 {
235  setupUi( this );
236 
237  mVariableEditor->setMinimumHeight( mVariableEditor->fontMetrics().height() * 15 );
238 
239  mItemRotationSpinBox->setClearValue( 0 );
240  mStrokeUnitsComboBox->linkToWidget( mStrokeWidthSpinBox );
241  mStrokeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
242 
243  mPosUnitsComboBox->linkToWidget( mXPosSpin );
244  mPosUnitsComboBox->linkToWidget( mYPosSpin );
245  mSizeUnitsComboBox->linkToWidget( mWidthSpin );
246  mSizeUnitsComboBox->linkToWidget( mHeightSpin );
247 
248  mPosUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
249  mSizeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
250 
251  mPosLockAspectRatio->setWidthSpinBox( mXPosSpin );
252  mPosLockAspectRatio->setHeightSpinBox( mYPosSpin );
253  mSizeLockAspectRatio->setWidthSpinBox( mWidthSpin );
254  mSizeLockAspectRatio->setHeightSpinBox( mHeightSpin );
255 
256  mItemFrameColorDDBtn->registerLinkedWidget( mFrameColorButton );
257  mItemBackgroundColorDDBtn->registerLinkedWidget( mBackgroundColorButton );
258 
259  connect( mFrameColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged );
260  connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged );
261  connect( mStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged );
262  connect( mStrokeUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::strokeUnitChanged );
263  connect( mFrameGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled );
264  connect( mFrameJoinStyleCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged );
265  connect( mBackgroundGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled );
266  connect( mItemIdLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished );
267  connect( mPageSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged );
268  connect( mXPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged );
269  connect( mYPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged );
270  connect( mPosUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::positionUnitsChanged );
271  connect( mWidthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged );
272  connect( mHeightSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged );
273  connect( mSizeUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::sizeUnitsChanged );
274  connect( mUpperLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged );
275  connect( mUpperMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged );
276  connect( mUpperRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged );
277  connect( mMiddleLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged );
278  connect( mMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged );
279  connect( mMiddleRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged );
280  connect( mLowerLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged );
281  connect( mLowerMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged );
282  connect( mLowerRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged );
283  connect( mBlendModeCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged );
284  connect( mItemRotationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged );
285  connect( mExcludeFromPrintsCheckBox, &QCheckBox::toggled, this, &QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled );
286 
287  //make button exclusive
288  QButtonGroup *buttonGroup = new QButtonGroup( this );
289  buttonGroup->addButton( mUpperLeftRadioButton );
290  buttonGroup->addButton( mUpperMiddleRadioButton );
291  buttonGroup->addButton( mUpperRightRadioButton );
292  buttonGroup->addButton( mMiddleLeftRadioButton );
293  buttonGroup->addButton( mMiddleRadioButton );
294  buttonGroup->addButton( mMiddleRightRadioButton );
295  buttonGroup->addButton( mLowerLeftRadioButton );
296  buttonGroup->addButton( mLowerMiddleRadioButton );
297  buttonGroup->addButton( mLowerRightRadioButton );
298  buttonGroup->setExclusive( true );
299 
301 
302  setItem( item );
303 
304  connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsLayoutItemPropertiesWidget::opacityChanged );
305 
306  updateVariables();
307  connect( mVariableEditor, &QgsVariableEditorWidget::scopeChanged, this, &QgsLayoutItemPropertiesWidget::variablesChanged );
308  // listen out for variable edits
309  connect( QgsApplication::instance(), &QgsApplication::customVariablesChanged, this, &QgsLayoutItemPropertiesWidget::updateVariables );
310  connect( item->layout()->project(), &QgsProject::customVariablesChanged, this, &QgsLayoutItemPropertiesWidget::updateVariables );
311 
312  if ( item->layout() )
313  connect( item->layout(), &QgsLayout::variablesChanged, this, &QgsLayoutItemPropertiesWidget::updateVariables );
314 }
315 
317 {
318  mBackgroundGroupBox->setVisible( showGroup );
319 }
320 
322 {
323  mFrameGroupBox->setVisible( showGroup );
324 }
325 
327 {
328  if ( mItem )
329  {
330  disconnect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
331  disconnect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
332  }
333  mItem = item;
334  if ( mItem )
335  {
336  connect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
337  connect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
338  }
339 
340  mConfigObject->setObject( mItem );
341 
342  setValuesForGuiElements();
343 }
344 
345 //slots
346 
347 void QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged( const QColor &newFrameColor )
348 {
349  if ( !mItem )
350  {
351  return;
352  }
353  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Color" ), QgsLayoutItem::UndoStrokeColor );
354  mItem->setFrameStrokeColor( newFrameColor );
355  mItem->layout()->undoStack()->endCommand();
356  mItem->update();
357 }
358 
359 void QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged( const QColor &newBackgroundColor )
360 {
361  if ( !mItem )
362  {
363  return;
364  }
365  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Background Color" ), QgsLayoutItem::UndoBackgroundColor );
366  mItem->setBackgroundColor( newBackgroundColor );
367  mItem->layout()->undoStack()->endCommand();
368  mItem->invalidateCache();
369 }
370 
371 void QgsLayoutItemPropertiesWidget::changeItemPosition()
372 {
373  if ( !mItem )
374  return;
375 
376  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
377 
378  QgsLayoutPoint point( mXPosSpin->value(), mYPosSpin->value(), mPosUnitsComboBox->unit() );
379  mItem->attemptMove( point, true, false, mPageSpinBox->value() - 1 );
380 
381  mItem->layout()->undoStack()->endCommand();
382 }
383 
384 void QgsLayoutItemPropertiesWidget::changeItemReference( QgsLayoutItem::ReferencePoint point )
385 {
386  if ( !mItem )
387  return;
388 
389  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item Reference" ) );
390  mItem->setReferencePoint( point );
391  mItem->layout()->undoStack()->endCommand();
392 }
393 
394 void QgsLayoutItemPropertiesWidget::changeItemSize()
395 {
396  if ( !mItem )
397  return;
398 
399  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Resize Item" ), QgsLayoutItem::UndoIncrementalResize );
400 
401  QgsLayoutSize size( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() );
402  mItem->attemptResize( size );
403 
404  mItem->layout()->undoStack()->endCommand();
405 }
406 
407 void QgsLayoutItemPropertiesWidget::variablesChanged()
408 {
409  if ( !mItem )
410  return;
411 
412  QgsExpressionContextUtils::setLayoutItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
413 }
414 
416 {
417  if ( mUpperLeftRadioButton->isChecked() )
418  {
420  }
421  else if ( mUpperMiddleRadioButton->isChecked() )
422  {
424  }
425  else if ( mUpperRightRadioButton->isChecked() )
426  {
428  }
429  else if ( mMiddleLeftRadioButton->isChecked() )
430  {
432  }
433  else if ( mMiddleRadioButton->isChecked() )
434  {
435  return QgsLayoutItem::Middle;
436  }
437  else if ( mMiddleRightRadioButton->isChecked() )
438  {
440  }
441  else if ( mLowerLeftRadioButton->isChecked() )
442  {
444  }
445  else if ( mLowerMiddleRadioButton->isChecked() )
446  {
448  }
449  else if ( mLowerRightRadioButton->isChecked() )
450  {
452  }
454 }
455 
456 void QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged( double d )
457 {
458  if ( !mItem )
459  {
460  return;
461  }
462 
463  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
464  mItem->setFrameStrokeWidth( QgsLayoutMeasurement( d, mStrokeUnitsComboBox->unit() ) );
465  mItem->layout()->undoStack()->endCommand();
466 }
467 
468 void QgsLayoutItemPropertiesWidget::strokeUnitChanged( QgsUnitTypes::LayoutUnit unit )
469 {
470  if ( !mItem )
471  {
472  return;
473  }
474 
475  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
476  mItem->setFrameStrokeWidth( QgsLayoutMeasurement( mStrokeWidthSpinBox->value(), unit ) );
477  mItem->layout()->undoStack()->endCommand();
478 }
479 
480 void QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged( int index )
481 {
482  Q_UNUSED( index )
483  if ( !mItem )
484  {
485  return;
486  }
487 
488  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Join Style" ) );
489  mItem->setFrameJoinStyle( mFrameJoinStyleCombo->penJoinStyle() );
490  mItem->layout()->undoStack()->endCommand();
491 }
492 
493 void QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled( bool state )
494 {
495  if ( !mItem )
496  {
497  return;
498  }
499 
500  mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Frame" ) : tr( "Disable Frame" ) );
501  mItem->setFrameEnabled( state );
502  mItem->update();
503  mItem->layout()->undoStack()->endCommand();
504 }
505 
506 void QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled( bool state )
507 {
508  if ( !mItem )
509  {
510  return;
511  }
512 
513  mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Background" ) : tr( "Disable Background" ) );
514  mItem->setBackgroundEnabled( state );
515  mItem->layout()->undoStack()->endCommand();
516  mItem->invalidateCache();
517 }
518 
519 
520 void QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements()
521 {
522  if ( !mItem )
523  {
524  return;
525  }
526 
527  auto block = [ = ]( bool blocked )
528  {
529  mXPosSpin->blockSignals( blocked );
530  mYPosSpin->blockSignals( blocked );
531  mPosUnitsComboBox->blockSignals( blocked );
532  mWidthSpin->blockSignals( blocked );
533  mHeightSpin->blockSignals( blocked );
534  mSizeUnitsComboBox->blockSignals( blocked );
535  mUpperLeftRadioButton->blockSignals( blocked );
536  mUpperMiddleRadioButton->blockSignals( blocked );
537  mUpperRightRadioButton->blockSignals( blocked );
538  mMiddleLeftRadioButton->blockSignals( blocked );
539  mMiddleRadioButton->blockSignals( blocked );
540  mMiddleRightRadioButton->blockSignals( blocked );
541  mLowerLeftRadioButton->blockSignals( blocked );
542  mLowerMiddleRadioButton->blockSignals( blocked );
543  mLowerRightRadioButton->blockSignals( blocked );
544  mPageSpinBox->blockSignals( blocked );
545  };
546  block( true );
547 
548  QgsLayoutPoint point = mItem->pagePositionWithUnits();
549 
550  if ( !mFreezeXPosSpin )
551  mXPosSpin->setValue( point.x() );
552  if ( !mFreezeYPosSpin )
553  mYPosSpin->setValue( point.y() );
554  mPosUnitsComboBox->setUnit( point.units() );
555 
556  switch ( mItem->referencePoint() )
557  {
559  {
560  mUpperLeftRadioButton->setChecked( true );
561  break;
562  }
563 
565  {
566  mUpperMiddleRadioButton->setChecked( true );
567  break;
568  }
569 
571  {
572  mUpperRightRadioButton->setChecked( true );
573  break;
574  }
575 
577  {
578  mMiddleLeftRadioButton->setChecked( true );
579  break;
580  }
581 
583  {
584  mMiddleRadioButton->setChecked( true );
585  break;
586  }
587 
589  {
590  mMiddleRightRadioButton->setChecked( true );
591  break;
592  }
593 
595  {
596  mLowerLeftRadioButton->setChecked( true );
597  break;
598  }
599 
601  {
602  mLowerMiddleRadioButton->setChecked( true );
603  break;
604  }
605 
607  {
608  mLowerRightRadioButton->setChecked( true );
609  break;
610  }
611  }
612 
613  QgsLayoutSize size = mItem->sizeWithUnits();
614  if ( !mFreezeWidthSpin )
615  mWidthSpin->setValue( size.width() );
616  if ( !mFreezeHeightSpin )
617  mHeightSpin->setValue( size.height() );
618 
619  mSizeUnitsComboBox->setUnit( size.units() );
620 
621  mSizeLockAspectRatio->resetRatio();
622  mPosLockAspectRatio->resetRatio();
623 
624  if ( !mFreezePageSpin )
625  mPageSpinBox->setValue( mItem->page() + 1 );
626 
627  block( false );
628 }
629 
630 void QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements()
631 {
632  if ( !mItem )
633  {
634  return;
635  }
636 
637  auto block = [ = ]( bool blocked )
638  {
639  mStrokeWidthSpinBox->blockSignals( blocked );
640  mStrokeUnitsComboBox->blockSignals( blocked );
641  mFrameGroupBox->blockSignals( blocked );
642  mBackgroundGroupBox->blockSignals( blocked );
643  mItemIdLineEdit->blockSignals( blocked );
644  mBlendModeCombo->blockSignals( blocked );
645  mOpacityWidget->blockSignals( blocked );
646  mFrameColorButton->blockSignals( blocked );
647  mFrameJoinStyleCombo->blockSignals( blocked );
648  mBackgroundColorButton->blockSignals( blocked );
649  mItemRotationSpinBox->blockSignals( blocked );
650  mExcludeFromPrintsCheckBox->blockSignals( blocked );
651  };
652  block( true );
653 
654  mBackgroundColorButton->setColor( mItem->backgroundColor() );
655  mFrameColorButton->setColor( mItem->frameStrokeColor() );
656  mStrokeUnitsComboBox->setUnit( mItem->frameStrokeWidth().units() );
657  mStrokeWidthSpinBox->setValue( mItem->frameStrokeWidth().length() );
658  mFrameJoinStyleCombo->setPenJoinStyle( mItem->frameJoinStyle() );
659  mItemIdLineEdit->setText( mItem->id() );
660  mFrameGroupBox->setChecked( mItem->frameEnabled() );
661  mBackgroundGroupBox->setChecked( mItem->hasBackground() );
662  mBlendModeCombo->setBlendMode( mItem->blendMode() );
663  mOpacityWidget->setOpacity( mItem->itemOpacity() );
664  mItemRotationSpinBox->setValue( mItem->itemRotation() );
665  mExcludeFromPrintsCheckBox->setChecked( mItem->excludeFromExports() );
666 
667  block( false );
668 }
669 
671 {
672  mConfigObject->initializeDataDefinedButton( mXPositionDDBtn, QgsLayoutObject::PositionX );
673  mConfigObject->initializeDataDefinedButton( mYPositionDDBtn, QgsLayoutObject::PositionY );
674  mConfigObject->initializeDataDefinedButton( mWidthDDBtn, QgsLayoutObject::ItemWidth );
675  mConfigObject->initializeDataDefinedButton( mHeightDDBtn, QgsLayoutObject::ItemHeight );
676  mConfigObject->initializeDataDefinedButton( mItemRotationDDBtn, QgsLayoutObject::ItemRotation );
677  mConfigObject->initializeDataDefinedButton( mOpacityDDBtn, QgsLayoutObject::Opacity );
678  mConfigObject->initializeDataDefinedButton( mBlendModeDDBtn, QgsLayoutObject::BlendMode );
679  mConfigObject->initializeDataDefinedButton( mExcludePrintsDDBtn, QgsLayoutObject::ExcludeFromExports );
680  mConfigObject->initializeDataDefinedButton( mItemFrameColorDDBtn, QgsLayoutObject::FrameColor );
681  mConfigObject->initializeDataDefinedButton( mItemBackgroundColorDDBtn, QgsLayoutObject::BackgroundColor );
682 }
683 
685 {
686  const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
687  for ( QgsPropertyOverrideButton *button : buttons )
688  {
689  mConfigObject->updateDataDefinedButton( button );
690  }
691 }
692 
693 void QgsLayoutItemPropertiesWidget::setValuesForGuiElements()
694 {
695  if ( !mItem )
696  {
697  return;
698  }
699 
700  mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
701  mBackgroundColorButton->setAllowOpacity( true );
702  mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
703  mFrameColorButton->setColorDialogTitle( tr( "Select Frame Color" ) );
704  mFrameColorButton->setAllowOpacity( true );
705  mFrameColorButton->setContext( QStringLiteral( "composer" ) );
706 
707  setValuesForGuiPositionElements();
708  setValuesForGuiNonPositionElements();
710 }
711 
712 void QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged( int index )
713 {
714  Q_UNUSED( index )
715  if ( mItem )
716  {
717  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Blend Mode" ) );
718  mItem->setBlendMode( mBlendModeCombo->blendMode() );
719  mItem->layout()->undoStack()->endCommand();
720  }
721 }
722 
723 void QgsLayoutItemPropertiesWidget::opacityChanged( double value )
724 {
725  if ( mItem )
726  {
727  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Opacity" ), QgsLayoutItem::UndoOpacity );
728  mItem->setItemOpacity( value );
729  mItem->layout()->undoStack()->endCommand();
730  }
731 }
732 
733 void QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished()
734 {
735  if ( mItem )
736  {
737  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item ID" ), QgsLayoutItem::UndoSetId );
738  mItem->setId( mItemIdLineEdit->text() );
739  mItemIdLineEdit->setText( mItem->id() );
740  mItem->layout()->undoStack()->endCommand();
741  }
742 }
743 
744 void QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged( int )
745 {
746  mFreezePageSpin = true;
747  changeItemPosition();
748  mFreezePageSpin = false;
749 }
750 
751 void QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged( double )
752 {
753  mFreezeXPosSpin = true;
754  changeItemPosition();
755  mFreezeXPosSpin = false;
756 }
757 
758 void QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged( double )
759 {
760  mFreezeYPosSpin = true;
761  changeItemPosition();
762  mFreezeYPosSpin = false;
763 }
764 
765 void QgsLayoutItemPropertiesWidget::positionUnitsChanged( QgsUnitTypes::LayoutUnit )
766 {
767  changeItemPosition();
768 }
769 
770 void QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged( double )
771 {
772  mFreezeWidthSpin = true;
773  changeItemSize();
774  mFreezeWidthSpin = false;
775 }
776 
777 void QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged( double )
778 {
779  mFreezeHeightSpin = true;
780  changeItemSize();
781  mFreezeHeightSpin = false;
782 }
783 
784 void QgsLayoutItemPropertiesWidget::sizeUnitsChanged( QgsUnitTypes::LayoutUnit )
785 {
786  changeItemSize();
787 }
788 
789 void QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged( bool state )
790 {
791  if ( !state )
792  return;
793 
794  if ( mItem )
795  {
796  changeItemReference( QgsLayoutItem::UpperLeft );
797  }
798  setValuesForGuiPositionElements();
799 }
800 
801 void QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged( bool state )
802 {
803  if ( !state )
804  return;
805  if ( mItem )
806  {
807  changeItemReference( QgsLayoutItem::UpperMiddle );
808  }
809  setValuesForGuiPositionElements();
810 }
811 
812 void QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged( bool state )
813 {
814  if ( !state )
815  return;
816  if ( mItem )
817  {
818  changeItemReference( QgsLayoutItem::UpperRight );
819  }
820  setValuesForGuiPositionElements();
821 }
822 
823 void QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged( bool state )
824 {
825  if ( !state )
826  return;
827  if ( mItem )
828  {
829  changeItemReference( QgsLayoutItem::MiddleLeft );
830  }
831  setValuesForGuiPositionElements();
832 }
833 
834 void QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged( bool state )
835 {
836  if ( !state )
837  return;
838  if ( mItem )
839  {
840  changeItemReference( QgsLayoutItem::Middle );
841  }
842  setValuesForGuiPositionElements();
843 }
844 
845 void QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged( bool state )
846 {
847  if ( !state )
848  return;
849  if ( mItem )
850  {
851  changeItemReference( QgsLayoutItem::MiddleRight );
852  }
853  setValuesForGuiPositionElements();
854 }
855 
856 void QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged( bool state )
857 {
858  if ( !state )
859  return;
860  if ( mItem )
861  {
862  changeItemReference( QgsLayoutItem::LowerLeft );
863  }
864  setValuesForGuiPositionElements();
865 }
866 
867 void QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged( bool state )
868 {
869  if ( !state )
870  return;
871  if ( mItem )
872  {
873  changeItemReference( QgsLayoutItem::LowerMiddle );
874  }
875  setValuesForGuiPositionElements();
876 }
877 
878 void QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged( bool state )
879 {
880  if ( !state )
881  return;
882  if ( mItem )
883  {
884  changeItemReference( QgsLayoutItem::LowerRight );
885  }
886  setValuesForGuiPositionElements();
887 }
888 
889 void QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged( double val )
890 {
891  if ( mItem )
892  {
893  mItem->layout()->undoStack()->beginCommand( mItem, tr( "Rotate" ), QgsLayoutItem::UndoRotation );
894  mItem->setItemRotation( val, true );
895  mItem->update();
896  mItem->layout()->undoStack()->endCommand();
897  }
898 }
899 
900 void QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled( bool checked )
901 {
902  if ( mItem )
903  {
904  mItem->layout()->undoStack()->beginCommand( mItem, checked ? tr( "Exclude from Exports" ) : tr( "Include in Exports" ) );
905  mItem->setExcludeFromExports( checked );
906  mItem->layout()->undoStack()->endCommand();
907  }
908 }
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.
Base class for any widget that can be shown as a inline panel.
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:357
void initializeDataDefinedButtons()
Initializes data defined buttons to current atlas coverage layer.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the layout object property definitions.
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.
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.
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...
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:367
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:212
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.
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:130
A base class for objects which belong to a layout.
LayoutUnit
Layout measurement units.
Definition: qgsunittypes.h:125
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
QgsLayoutItem::ReferencePoint positionMode() const
Returns the position mode.
void changed()
Emitted when the object&#39;s properties change.
Rotation adjustment.
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.
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.
QgsLayoutObject * layoutObject()
Returns the layout object associated with this widget.
double width() const
Returns the width of the size.
Definition: qgslayoutsize.h:76