QGIS API Documentation 3.29.0-Master (ade4f0cf0f)
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
51void 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
95void 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 const bool propertyAssociatesWithMultiFrame = QgsLayoutObject::propertyAssociatesWithParentMultiframe( key );
123
124 //set the data defined property
125 if ( propertyAssociatesWithMultiFrame )
126 {
127 if ( QgsLayoutFrame *frame = dynamic_cast< QgsLayoutFrame * >( mLayoutObject.data() ) )
128 {
129 if ( QgsLayoutMultiFrame *multiFrame = frame->multiFrame() )
130 {
131 whileBlocking( button )->setToProperty( multiFrame->dataDefinedProperties().property( key ) );
132 }
133 }
134 else if ( QgsLayoutMultiFrame *multiFrame = dynamic_cast< QgsLayoutMultiFrame * >( mLayoutObject.data() ) )
135 {
136 whileBlocking( button )->setToProperty( multiFrame->dataDefinedProperties().property( key ) );
137 }
138 }
139 else if ( mLayoutObject )
140 {
141 whileBlocking( button )->setToProperty( mLayoutObject->dataDefinedProperties().property( key ) );
142 }
143
144 // 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 )
145 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayoutConfigObject::updateDataDefinedProperty, Qt::UniqueConnection );
146 button->registerExpressionContextGenerator( mLayoutObject );
147}
148
150{
151 if ( !mLayoutObject )
152 {
153 return nullptr;
154 }
155
156 QgsPrintLayout *printLayout = qobject_cast< QgsPrintLayout * >( mLayoutObject->layout() );
157
158 if ( !printLayout )
159 {
160 return nullptr;
161 }
162
163 return printLayout->atlas();
164}
165
167{
168 mLayoutObject = object;
169}
170
172{
173 if ( !mLayoutObject )
174 return nullptr;
175
176 QgsLayout *layout = mLayoutObject->layout();
177 if ( !layout )
178 return nullptr;
179
180 return layout->reportContext().layer();
181}
182
183
184//
185// QgsLayoutItemBaseWidget
186//
187
189 : QgsPanelWidget( parent )
190 , mConfigObject( new QgsLayoutConfigObject( this, layoutObject ) )
191 , mObject( layoutObject )
192{
193
194}
195
197{
198 return mObject;
199}
200
202{
203 QgsLayoutObject *oldObject = mObject;
204 QgsLayoutConfigObject *oldConfigObject = mConfigObject;
205 // have to set new mObject/mConfigObject here, because setNewItem methods require access to them
206 mObject = item;
207 mConfigObject = new QgsLayoutConfigObject( this, mObject );
208 if ( setNewItem( item ) )
209 {
210 oldConfigObject->deleteLater();
211 return true;
212 }
213 else
214 {
215 // revert object change since it was unsuccessful
216 mObject = oldObject;
217 mConfigObject->deleteLater();
218 mConfigObject = oldConfigObject;
219 return false;
220 }
221}
222
224{
225}
226
228{
229 const auto symbolButtonWidgets = findChildren<QgsSymbolButton *>();
230 for ( QgsSymbolButton *symbolWidget : symbolButtonWidgets )
231 {
232 symbolWidget->setMessageBar( iface->messageBar() );
233 }
234 const auto fontButtonWidgets = findChildren<QgsFontButton *>();
235 for ( QgsFontButton *fontButton : fontButtonWidgets )
236 {
237 fontButton->setMessageBar( iface->messageBar() );
238 }
239}
240
242{
243
244}
245
247{
248 mConfigObject->initializeDataDefinedButton( button, property );
249}
250
252{
253 mConfigObject->updateDataDefinedButton( button );
254}
255
257{
258 return mConfigObject->coverageLayer();
259}
260
262{
263 return false;
264}
265
267{
268 return mConfigObject->layoutAtlas();
269}
270
271//
272
273
274//QgsLayoutItemPropertiesWidget
275
277{
278 if ( !mItem )
279 return;
280
281 mBlockVariableUpdates = true;
282 QgsExpressionContext context = mItem->createExpressionContext();
283 mVariableEditor->setContext( &context );
284
285 // here, we prefer to make the multiframe's scope the editable one. That's because most expressions are evaluated
286 // on the multiframe subclass level, not on a frame-by-frame basis. Ideally both would be editable, but for now let's go
287 // with the most useful one.
288 const int multiFrameScopeIndex = context.indexOfScope( tr( "Multiframe Item" ) );
289 const int itemScopeIndex = context.indexOfScope( tr( "Layout Item" ) );
290 if ( multiFrameScopeIndex >= 0 )
291 mVariableEditor->setEditableScopeIndex( multiFrameScopeIndex );
292 else if ( itemScopeIndex >= 0 )
293 mVariableEditor->setEditableScopeIndex( itemScopeIndex );
294 mBlockVariableUpdates = false;
295}
296
298 : QWidget( parent )
299 , mConfigObject( new QgsLayoutConfigObject( this, item ) )
300{
301 setupUi( this );
302
303 mVariableEditor->setMinimumHeight( mVariableEditor->fontMetrics().height() * 15 );
304
305 mItemRotationSpinBox->setClearValue( 0 );
306 mStrokeUnitsComboBox->linkToWidget( mStrokeWidthSpinBox );
307 mStrokeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
308
309 mPosUnitsComboBox->linkToWidget( mXPosSpin );
310 mPosUnitsComboBox->linkToWidget( mYPosSpin );
311 mSizeUnitsComboBox->linkToWidget( mWidthSpin );
312 mSizeUnitsComboBox->linkToWidget( mHeightSpin );
313
314 mPosUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
315 mSizeUnitsComboBox->setConverter( &item->layout()->renderContext().measurementConverter() );
316
317 mPosLockAspectRatio->setWidthSpinBox( mXPosSpin );
318 mPosLockAspectRatio->setHeightSpinBox( mYPosSpin );
319 mSizeLockAspectRatio->setWidthSpinBox( mWidthSpin );
320 mSizeLockAspectRatio->setHeightSpinBox( mHeightSpin );
321
322 mItemFrameColorDDBtn->registerLinkedWidget( mFrameColorButton );
323 mItemBackgroundColorDDBtn->registerLinkedWidget( mBackgroundColorButton );
324
325 connect( mFrameColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged );
326 connect( mBackgroundColorButton, &QgsColorButton::colorChanged, this, &QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged );
327 connect( mStrokeWidthSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged );
328 connect( mStrokeUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::strokeUnitChanged );
329 connect( mFrameGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled );
330 connect( mFrameJoinStyleCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged );
331 connect( mBackgroundGroupBox, &QgsCollapsibleGroupBoxBasic::toggled, this, &QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled );
332 connect( mItemIdLineEdit, &QLineEdit::editingFinished, this, &QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished );
333 connect( mPageSpinBox, static_cast < void ( QSpinBox::* )( int ) > ( &QSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged );
334 connect( mXPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged );
335 connect( mYPosSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged );
336 connect( mPosUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::positionUnitsChanged );
337 connect( mWidthSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged );
338 connect( mHeightSpin, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged );
339 connect( mSizeUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutItemPropertiesWidget::sizeUnitsChanged );
340 connect( mUpperLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged );
341 connect( mUpperMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged );
342 connect( mUpperRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged );
343 connect( mMiddleLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged );
344 connect( mMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged );
345 connect( mMiddleRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged );
346 connect( mLowerLeftRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged );
347 connect( mLowerMiddleRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged );
348 connect( mLowerRightRadioButton, &QRadioButton::toggled, this, &QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged );
349 connect( mBlendModeCombo, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged );
350 connect( mItemRotationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged );
351 connect( mExcludeFromPrintsCheckBox, &QCheckBox::toggled, this, &QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled );
352
353 //make button exclusive
354 QButtonGroup *buttonGroup = new QButtonGroup( this );
355 buttonGroup->addButton( mUpperLeftRadioButton );
356 buttonGroup->addButton( mUpperMiddleRadioButton );
357 buttonGroup->addButton( mUpperRightRadioButton );
358 buttonGroup->addButton( mMiddleLeftRadioButton );
359 buttonGroup->addButton( mMiddleRadioButton );
360 buttonGroup->addButton( mMiddleRightRadioButton );
361 buttonGroup->addButton( mLowerLeftRadioButton );
362 buttonGroup->addButton( mLowerMiddleRadioButton );
363 buttonGroup->addButton( mLowerRightRadioButton );
364 buttonGroup->setExclusive( true );
365
367
368 setItem( item );
369
370 connect( mOpacityWidget, &QgsOpacityWidget::opacityChanged, this, &QgsLayoutItemPropertiesWidget::opacityChanged );
371
373 connect( mVariableEditor, &QgsVariableEditorWidget::scopeChanged, this, [ = ]
374 {
375 if ( !mBlockVariableUpdates )
376 QgsLayoutItemPropertiesWidget::variablesChanged();
377 } );
378 // listen out for variable edits
382
383 if ( item->layout() )
384 {
388 }
389}
390
392{
393 mBackgroundGroupBox->setVisible( showGroup );
394}
395
397{
398 mFrameGroupBox->setVisible( showGroup );
399}
400
402{
403 if ( mItem )
404 {
405 disconnect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
406 disconnect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
407 }
408 mItem = item;
409 if ( mItem )
410 {
411 connect( mItem, &QgsLayoutItem::sizePositionChanged, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements );
412 connect( mItem, &QgsLayoutObject::changed, this, &QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements );
413 }
414
415 mConfigObject->setObject( mItem );
416
417 setValuesForGuiElements();
418}
419
421{
422 if ( QgsPrintLayout *printLayout = dynamic_cast< QgsPrintLayout * >( masterLayout ) )
423 {
426 }
427}
428
429//slots
430
431void QgsLayoutItemPropertiesWidget::mFrameColorButton_colorChanged( const QColor &newFrameColor )
432{
433 if ( !mItem )
434 {
435 return;
436 }
437 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Color" ), QgsLayoutItem::UndoStrokeColor );
438 mItem->setFrameStrokeColor( newFrameColor );
439 mItem->layout()->undoStack()->endCommand();
440 mItem->update();
441}
442
443void QgsLayoutItemPropertiesWidget::mBackgroundColorButton_colorChanged( const QColor &newBackgroundColor )
444{
445 if ( !mItem )
446 {
447 return;
448 }
449 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Background Color" ), QgsLayoutItem::UndoBackgroundColor );
450 mItem->setBackgroundColor( newBackgroundColor );
451 mItem->layout()->undoStack()->endCommand();
452 mItem->invalidateCache();
453}
454
455void QgsLayoutItemPropertiesWidget::changeItemPosition()
456{
457 if ( !mItem )
458 return;
459
460 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
461
462 const QgsLayoutPoint point( mXPosSpin->value(), mYPosSpin->value(), mPosUnitsComboBox->unit() );
463 mItem->attemptMove( point, true, false, mPageSpinBox->value() - 1 );
464
465 mItem->layout()->undoStack()->endCommand();
466}
467
468void QgsLayoutItemPropertiesWidget::changeItemReference( QgsLayoutItem::ReferencePoint point )
469{
470 if ( !mItem )
471 return;
472
473 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item Reference" ) );
474 mItem->setReferencePoint( point );
475 mItem->layout()->undoStack()->endCommand();
476}
477
478void QgsLayoutItemPropertiesWidget::changeItemSize()
479{
480 if ( !mItem )
481 return;
482
483 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Resize Item" ), QgsLayoutItem::UndoIncrementalResize );
484
485 const QgsLayoutSize size( mWidthSpin->value(), mHeightSpin->value(), mSizeUnitsComboBox->unit() );
486 mItem->attemptResize( size );
487
488 mItem->layout()->undoStack()->endCommand();
489}
490
491void QgsLayoutItemPropertiesWidget::variablesChanged()
492{
493 if ( !mItem )
494 return;
495
496 if ( QgsLayoutFrame *frame = qobject_cast< QgsLayoutFrame * >( mItem ) )
497 {
498 if ( QgsLayoutMultiFrame *mf = frame->multiFrame() )
499 {
500 QgsExpressionContextUtils::setLayoutMultiFrameVariables( mf, mVariableEditor->variablesInActiveScope() );
501 }
502 }
503 else
504 {
505 QgsExpressionContextUtils::setLayoutItemVariables( mItem, mVariableEditor->variablesInActiveScope() );
506 }
507}
508
510{
511 if ( mUpperLeftRadioButton->isChecked() )
512 {
514 }
515 else if ( mUpperMiddleRadioButton->isChecked() )
516 {
518 }
519 else if ( mUpperRightRadioButton->isChecked() )
520 {
522 }
523 else if ( mMiddleLeftRadioButton->isChecked() )
524 {
526 }
527 else if ( mMiddleRadioButton->isChecked() )
528 {
530 }
531 else if ( mMiddleRightRadioButton->isChecked() )
532 {
534 }
535 else if ( mLowerLeftRadioButton->isChecked() )
536 {
538 }
539 else if ( mLowerMiddleRadioButton->isChecked() )
540 {
542 }
543 else if ( mLowerRightRadioButton->isChecked() )
544 {
546 }
548}
549
550void QgsLayoutItemPropertiesWidget::mStrokeWidthSpinBox_valueChanged( double d )
551{
552 if ( !mItem )
553 {
554 return;
555 }
556
557 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
558 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( d, mStrokeUnitsComboBox->unit() ) );
559 mItem->layout()->undoStack()->endCommand();
560}
561
562void QgsLayoutItemPropertiesWidget::strokeUnitChanged( QgsUnitTypes::LayoutUnit unit )
563{
564 if ( !mItem )
565 {
566 return;
567 }
568
569 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Stroke Width" ), QgsLayoutItem::UndoStrokeWidth );
570 mItem->setFrameStrokeWidth( QgsLayoutMeasurement( mStrokeWidthSpinBox->value(), unit ) );
571 mItem->layout()->undoStack()->endCommand();
572}
573
574void QgsLayoutItemPropertiesWidget::mFrameJoinStyleCombo_currentIndexChanged( int index )
575{
576 Q_UNUSED( index )
577 if ( !mItem )
578 {
579 return;
580 }
581
582 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Frame Join Style" ) );
583 mItem->setFrameJoinStyle( mFrameJoinStyleCombo->penJoinStyle() );
584 mItem->layout()->undoStack()->endCommand();
585}
586
587void QgsLayoutItemPropertiesWidget::mFrameGroupBox_toggled( bool state )
588{
589 if ( !mItem )
590 {
591 return;
592 }
593
594 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Frame" ) : tr( "Disable Frame" ) );
595 mItem->setFrameEnabled( state );
596 mItem->update();
597 mItem->layout()->undoStack()->endCommand();
598}
599
600void QgsLayoutItemPropertiesWidget::mBackgroundGroupBox_toggled( bool state )
601{
602 if ( !mItem )
603 {
604 return;
605 }
606
607 mItem->layout()->undoStack()->beginCommand( mItem, state ? tr( "Enable Background" ) : tr( "Disable Background" ) );
608 mItem->setBackgroundEnabled( state );
609 mItem->layout()->undoStack()->endCommand();
610 mItem->invalidateCache();
611}
612
613
614void QgsLayoutItemPropertiesWidget::setValuesForGuiPositionElements()
615{
616 if ( !mItem )
617 {
618 return;
619 }
620
621 auto block = [ = ]( bool blocked )
622 {
623 mXPosSpin->blockSignals( blocked );
624 mYPosSpin->blockSignals( blocked );
625 mPosUnitsComboBox->blockSignals( blocked );
626 mWidthSpin->blockSignals( blocked );
627 mHeightSpin->blockSignals( blocked );
628 mSizeUnitsComboBox->blockSignals( blocked );
629 mUpperLeftRadioButton->blockSignals( blocked );
630 mUpperMiddleRadioButton->blockSignals( blocked );
631 mUpperRightRadioButton->blockSignals( blocked );
632 mMiddleLeftRadioButton->blockSignals( blocked );
633 mMiddleRadioButton->blockSignals( blocked );
634 mMiddleRightRadioButton->blockSignals( blocked );
635 mLowerLeftRadioButton->blockSignals( blocked );
636 mLowerMiddleRadioButton->blockSignals( blocked );
637 mLowerRightRadioButton->blockSignals( blocked );
638 mPageSpinBox->blockSignals( blocked );
639 };
640 block( true );
641
642 const QgsLayoutPoint point = mItem->pagePositionWithUnits();
643
644 if ( !mFreezeXPosSpin )
645 mXPosSpin->setValue( point.x() );
646 if ( !mFreezeYPosSpin )
647 mYPosSpin->setValue( point.y() );
648 mPosUnitsComboBox->setUnit( point.units() );
649
650 switch ( mItem->referencePoint() )
651 {
653 {
654 mUpperLeftRadioButton->setChecked( true );
655 break;
656 }
657
659 {
660 mUpperMiddleRadioButton->setChecked( true );
661 break;
662 }
663
665 {
666 mUpperRightRadioButton->setChecked( true );
667 break;
668 }
669
671 {
672 mMiddleLeftRadioButton->setChecked( true );
673 break;
674 }
675
677 {
678 mMiddleRadioButton->setChecked( true );
679 break;
680 }
681
683 {
684 mMiddleRightRadioButton->setChecked( true );
685 break;
686 }
687
689 {
690 mLowerLeftRadioButton->setChecked( true );
691 break;
692 }
693
695 {
696 mLowerMiddleRadioButton->setChecked( true );
697 break;
698 }
699
701 {
702 mLowerRightRadioButton->setChecked( true );
703 break;
704 }
705 }
706
707 const QgsLayoutSize size = mItem->sizeWithUnits();
708 if ( !mFreezeWidthSpin )
709 mWidthSpin->setValue( size.width() );
710 if ( !mFreezeHeightSpin )
711 mHeightSpin->setValue( size.height() );
712
713 mSizeUnitsComboBox->setUnit( size.units() );
714
715 mSizeLockAspectRatio->resetRatio();
716 mPosLockAspectRatio->resetRatio();
717
718 if ( !mFreezePageSpin )
719 mPageSpinBox->setValue( mItem->page() + 1 );
720
721 block( false );
722}
723
724void QgsLayoutItemPropertiesWidget::setValuesForGuiNonPositionElements()
725{
726 if ( !mItem )
727 {
728 return;
729 }
730
731 auto block = [ = ]( bool blocked )
732 {
733 mStrokeWidthSpinBox->blockSignals( blocked );
734 mStrokeUnitsComboBox->blockSignals( blocked );
735 mFrameGroupBox->blockSignals( blocked );
736 mBackgroundGroupBox->blockSignals( blocked );
737 mItemIdLineEdit->blockSignals( blocked );
738 mBlendModeCombo->blockSignals( blocked );
739 mOpacityWidget->blockSignals( blocked );
740 mFrameColorButton->blockSignals( blocked );
741 mFrameJoinStyleCombo->blockSignals( blocked );
742 mBackgroundColorButton->blockSignals( blocked );
743 mItemRotationSpinBox->blockSignals( blocked );
744 mExcludeFromPrintsCheckBox->blockSignals( blocked );
745 };
746 block( true );
747
748 mBackgroundColorButton->setColor( mItem->backgroundColor() );
749 mFrameColorButton->setColor( mItem->frameStrokeColor() );
750 mStrokeUnitsComboBox->setUnit( mItem->frameStrokeWidth().units() );
751 mStrokeWidthSpinBox->setValue( mItem->frameStrokeWidth().length() );
752 mFrameJoinStyleCombo->setPenJoinStyle( mItem->frameJoinStyle() );
753 mItemIdLineEdit->setText( mItem->id() );
754 mFrameGroupBox->setChecked( mItem->frameEnabled() );
755 mBackgroundGroupBox->setChecked( mItem->hasBackground() );
756 mBlendModeCombo->setBlendMode( mItem->blendMode() );
757 mOpacityWidget->setOpacity( mItem->itemOpacity() );
758 mItemRotationSpinBox->setValue( mItem->itemRotation() );
759 mExcludeFromPrintsCheckBox->setChecked( mItem->excludeFromExports() );
760
761 block( false );
762}
763
765{
766 mConfigObject->initializeDataDefinedButton( mXPositionDDBtn, QgsLayoutObject::PositionX );
767 mConfigObject->initializeDataDefinedButton( mYPositionDDBtn, QgsLayoutObject::PositionY );
768 mConfigObject->initializeDataDefinedButton( mWidthDDBtn, QgsLayoutObject::ItemWidth );
769 mConfigObject->initializeDataDefinedButton( mHeightDDBtn, QgsLayoutObject::ItemHeight );
770 mConfigObject->initializeDataDefinedButton( mItemRotationDDBtn, QgsLayoutObject::ItemRotation );
771 mConfigObject->initializeDataDefinedButton( mOpacityDDBtn, QgsLayoutObject::Opacity );
772 mConfigObject->initializeDataDefinedButton( mBlendModeDDBtn, QgsLayoutObject::BlendMode );
773 mConfigObject->initializeDataDefinedButton( mExcludePrintsDDBtn, QgsLayoutObject::ExcludeFromExports );
774 mConfigObject->initializeDataDefinedButton( mItemFrameColorDDBtn, QgsLayoutObject::FrameColor );
775 mConfigObject->initializeDataDefinedButton( mItemBackgroundColorDDBtn, QgsLayoutObject::BackgroundColor );
776}
777
779{
780 const QList< QgsPropertyOverrideButton * > buttons = findChildren< QgsPropertyOverrideButton * >();
781 for ( QgsPropertyOverrideButton *button : buttons )
782 {
783 mConfigObject->updateDataDefinedButton( button );
784 }
785}
786
787void QgsLayoutItemPropertiesWidget::setValuesForGuiElements()
788{
789 if ( !mItem )
790 {
791 return;
792 }
793
794 mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
795 mBackgroundColorButton->setAllowOpacity( true );
796 mBackgroundColorButton->setContext( QStringLiteral( "composer" ) );
797 mFrameColorButton->setColorDialogTitle( tr( "Select Frame Color" ) );
798 mFrameColorButton->setAllowOpacity( true );
799 mFrameColorButton->setContext( QStringLiteral( "composer" ) );
800
801 setValuesForGuiPositionElements();
802 setValuesForGuiNonPositionElements();
804
806}
807
808void QgsLayoutItemPropertiesWidget::mBlendModeCombo_currentIndexChanged( int index )
809{
810 Q_UNUSED( index )
811 if ( mItem )
812 {
813 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Blend Mode" ) );
814 mItem->setBlendMode( mBlendModeCombo->blendMode() );
815 mItem->layout()->undoStack()->endCommand();
816 }
817}
818
819void QgsLayoutItemPropertiesWidget::opacityChanged( double value )
820{
821 if ( mItem )
822 {
823 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Opacity" ), QgsLayoutItem::UndoOpacity );
824 mItem->setItemOpacity( value );
825 mItem->layout()->undoStack()->endCommand();
826 }
827}
828
829void QgsLayoutItemPropertiesWidget::mItemIdLineEdit_editingFinished()
830{
831 if ( mItem )
832 {
833 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Change Item ID" ), QgsLayoutItem::UndoSetId );
834 mItem->setId( mItemIdLineEdit->text() );
835 mItemIdLineEdit->setText( mItem->id() );
836 mItem->layout()->undoStack()->endCommand();
837 }
838}
839
840void QgsLayoutItemPropertiesWidget::mPageSpinBox_valueChanged( int )
841{
842 mFreezePageSpin = true;
843 changeItemPosition();
844 mFreezePageSpin = false;
845}
846
847void QgsLayoutItemPropertiesWidget::mXPosSpin_valueChanged( double )
848{
849 mFreezeXPosSpin = true;
850 changeItemPosition();
851 mFreezeXPosSpin = false;
852}
853
854void QgsLayoutItemPropertiesWidget::mYPosSpin_valueChanged( double )
855{
856 mFreezeYPosSpin = true;
857 changeItemPosition();
858 mFreezeYPosSpin = false;
859}
860
861void QgsLayoutItemPropertiesWidget::positionUnitsChanged( QgsUnitTypes::LayoutUnit )
862{
863 changeItemPosition();
864}
865
866void QgsLayoutItemPropertiesWidget::mWidthSpin_valueChanged( double )
867{
868 mFreezeWidthSpin = true;
869 changeItemSize();
870 mFreezeWidthSpin = false;
871}
872
873void QgsLayoutItemPropertiesWidget::mHeightSpin_valueChanged( double )
874{
875 mFreezeHeightSpin = true;
876 changeItemSize();
877 mFreezeHeightSpin = false;
878}
879
880void QgsLayoutItemPropertiesWidget::sizeUnitsChanged( QgsUnitTypes::LayoutUnit )
881{
882 changeItemSize();
883}
884
885void QgsLayoutItemPropertiesWidget::mUpperLeftCheckBox_stateChanged( bool state )
886{
887 if ( !state )
888 return;
889
890 if ( mItem )
891 {
892 changeItemReference( QgsLayoutItem::UpperLeft );
893 }
894 setValuesForGuiPositionElements();
895}
896
897void QgsLayoutItemPropertiesWidget::mUpperMiddleCheckBox_stateChanged( bool state )
898{
899 if ( !state )
900 return;
901 if ( mItem )
902 {
903 changeItemReference( QgsLayoutItem::UpperMiddle );
904 }
905 setValuesForGuiPositionElements();
906}
907
908void QgsLayoutItemPropertiesWidget::mUpperRightCheckBox_stateChanged( bool state )
909{
910 if ( !state )
911 return;
912 if ( mItem )
913 {
914 changeItemReference( QgsLayoutItem::UpperRight );
915 }
916 setValuesForGuiPositionElements();
917}
918
919void QgsLayoutItemPropertiesWidget::mMiddleLeftCheckBox_stateChanged( bool state )
920{
921 if ( !state )
922 return;
923 if ( mItem )
924 {
925 changeItemReference( QgsLayoutItem::MiddleLeft );
926 }
927 setValuesForGuiPositionElements();
928}
929
930void QgsLayoutItemPropertiesWidget::mMiddleCheckBox_stateChanged( bool state )
931{
932 if ( !state )
933 return;
934 if ( mItem )
935 {
936 changeItemReference( QgsLayoutItem::Middle );
937 }
938 setValuesForGuiPositionElements();
939}
940
941void QgsLayoutItemPropertiesWidget::mMiddleRightCheckBox_stateChanged( bool state )
942{
943 if ( !state )
944 return;
945 if ( mItem )
946 {
947 changeItemReference( QgsLayoutItem::MiddleRight );
948 }
949 setValuesForGuiPositionElements();
950}
951
952void QgsLayoutItemPropertiesWidget::mLowerLeftCheckBox_stateChanged( bool state )
953{
954 if ( !state )
955 return;
956 if ( mItem )
957 {
958 changeItemReference( QgsLayoutItem::LowerLeft );
959 }
960 setValuesForGuiPositionElements();
961}
962
963void QgsLayoutItemPropertiesWidget::mLowerMiddleCheckBox_stateChanged( bool state )
964{
965 if ( !state )
966 return;
967 if ( mItem )
968 {
969 changeItemReference( QgsLayoutItem::LowerMiddle );
970 }
971 setValuesForGuiPositionElements();
972}
973
974void QgsLayoutItemPropertiesWidget::mLowerRightCheckBox_stateChanged( bool state )
975{
976 if ( !state )
977 return;
978 if ( mItem )
979 {
980 changeItemReference( QgsLayoutItem::LowerRight );
981 }
982 setValuesForGuiPositionElements();
983}
984
985void QgsLayoutItemPropertiesWidget::mItemRotationSpinBox_valueChanged( double val )
986{
987 if ( mItem )
988 {
989 mItem->layout()->undoStack()->beginCommand( mItem, tr( "Rotate" ), QgsLayoutItem::UndoRotation );
990 mItem->setItemRotation( val, true );
991 mItem->update();
992 mItem->layout()->undoStack()->endCommand();
993 }
994}
995
996void QgsLayoutItemPropertiesWidget::mExcludeFromPrintsCheckBox_toggled( bool checked )
997{
998 if ( mItem )
999 {
1000 mItem->layout()->undoStack()->beginCommand( mItem, checked ? tr( "Exclude from Exports" ) : tr( "Include in Exports" ) );
1001 mItem->setExcludeFromExports( checked );
1002 mItem->layout()->undoStack()->endCommand();
1003 }
1004}
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:49
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:2708