1 /***************************************************************************
2                          qgslayoutshapewidget.cpp
3                          --------------------------
4     begin                : November 2009
5     copyright            : (C) 2009 by Marco Hugentobler
6     email                : marco@hugis.net
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "qgslayoutshapewidget.h"
19 #include "qgsstyle.h"
20 #include "qgslayoutitemshape.h"
21 #include "qgslayout.h"
22 #include "qgslayoutundostack.h"
23 #include "qgsvectorlayer.h"
24 
QgsLayoutShapeWidget(QgsLayoutItemShape * shape)25 QgsLayoutShapeWidget::QgsLayoutShapeWidget( QgsLayoutItemShape *shape )
26   : QgsLayoutItemBaseWidget( nullptr, shape )
27   , mShape( shape )
28 {
29   Q_ASSERT( mShape );
30 
31   setupUi( this );
32   connect( mShapeComboBox, &QComboBox::currentTextChanged, this, &QgsLayoutShapeWidget::mShapeComboBox_currentIndexChanged );
33   connect( mCornerRadiusSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutShapeWidget::mCornerRadiusSpinBox_valueChanged );
34   setPanelTitle( tr( "Shape Properties" ) );
35 
36   //add widget for general composer item properties
37   mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, shape );
38   //shapes don't use background or frame, since the symbol style is set through a QgsSymbolSelectorWidget
39   mItemPropertiesWidget->showBackgroundGroup( false );
40   mItemPropertiesWidget->showFrameGroup( false );
41   mainLayout->addWidget( mItemPropertiesWidget );
42 
43   blockAllSignals( true );
44 
45   //shape types
46   mShapeComboBox->addItem( tr( "Rectangle" ),  QgsLayoutItemShape::Rectangle );
47   mShapeComboBox->addItem( tr( "Ellipse" ), QgsLayoutItemShape::Ellipse );
48   mShapeComboBox->addItem( tr( "Triangle" ), QgsLayoutItemShape::Triangle );
49 
50   mShapeStyleButton->setSymbolType( QgsSymbol::Fill );
51   mRadiusUnitsComboBox->linkToWidget( mCornerRadiusSpinBox );
52   mRadiusUnitsComboBox->setConverter( &mShape->layout()->renderContext().measurementConverter() );
53 
54   setGuiElementValues();
55 
56   blockAllSignals( false );
57 
58   connect( mShape, &QgsLayoutObject::changed, this, &QgsLayoutShapeWidget::setGuiElementValues );
59   mShapeStyleButton->registerExpressionContextGenerator( mShape );
60 
61   connect( mShapeStyleButton, &QgsSymbolButton::changed, this, &QgsLayoutShapeWidget::symbolChanged );
62   connect( mRadiusUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutShapeWidget::radiusUnitsChanged );
63 
64   mShapeStyleButton->setLayer( coverageLayer() );
65   if ( mShape->layout() )
66   {
67     connect( &mShape->layout()->reportContext(), &QgsLayoutReportContext::layerChanged, mShapeStyleButton, &QgsSymbolButton::setLayer );
68   }
69 }
70 
setMasterLayout(QgsMasterLayoutInterface * masterLayout)71 void QgsLayoutShapeWidget::setMasterLayout( QgsMasterLayoutInterface *masterLayout )
72 {
73   if ( mItemPropertiesWidget )
74     mItemPropertiesWidget->setMasterLayout( masterLayout );
75 }
76 
setNewItem(QgsLayoutItem * item)77 bool QgsLayoutShapeWidget::setNewItem( QgsLayoutItem *item )
78 {
79   if ( item->type() != QgsLayoutItemRegistry::LayoutShape )
80     return false;
81 
82   if ( mShape )
83   {
84     disconnect( mShape, &QgsLayoutObject::changed, this, &QgsLayoutShapeWidget::setGuiElementValues );
85   }
86 
87   mShape = qobject_cast< QgsLayoutItemShape * >( item );
88   mItemPropertiesWidget->setItem( mShape );
89 
90   if ( mShape )
91   {
92     connect( mShape, &QgsLayoutObject::changed, this, &QgsLayoutShapeWidget::setGuiElementValues );
93     mShapeStyleButton->registerExpressionContextGenerator( mShape );
94   }
95 
96   setGuiElementValues();
97 
98   return true;
99 }
100 
blockAllSignals(bool block)101 void QgsLayoutShapeWidget::blockAllSignals( bool block )
102 {
103   mShapeComboBox->blockSignals( block );
104   mCornerRadiusSpinBox->blockSignals( block );
105   mRadiusUnitsComboBox->blockSignals( block );
106   mShapeStyleButton->blockSignals( block );
107 }
108 
setGuiElementValues()109 void QgsLayoutShapeWidget::setGuiElementValues()
110 {
111   if ( !mShape )
112   {
113     return;
114   }
115 
116   blockAllSignals( true );
117 
118   mShapeStyleButton->setSymbol( mShape->symbol()->clone() );
119 
120   mCornerRadiusSpinBox->setValue( mShape->cornerRadius().length() );
121   mRadiusUnitsComboBox->setUnit( mShape->cornerRadius().units() );
122 
123   mShapeComboBox->setCurrentIndex( mShapeComboBox->findData( mShape->shapeType() ) );
124   toggleRadiusSpin( mShape->shapeType() );
125 
126   blockAllSignals( false );
127 }
128 
symbolChanged()129 void QgsLayoutShapeWidget::symbolChanged()
130 {
131   if ( !mShape )
132     return;
133 
134   mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Style" ), QgsLayoutItem::UndoShapeStyle );
135   mShape->setSymbol( mShapeStyleButton->clonedSymbol<QgsFillSymbol>() );
136   mShape->layout()->undoStack()->endCommand();
137 }
138 
mCornerRadiusSpinBox_valueChanged(double val)139 void QgsLayoutShapeWidget::mCornerRadiusSpinBox_valueChanged( double val )
140 {
141   if ( !mShape )
142     return;
143 
144   mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Radius" ), QgsLayoutItem::UndoShapeCornerRadius );
145   mShape->setCornerRadius( QgsLayoutMeasurement( val, mRadiusUnitsComboBox->unit() ) );
146   mShape->layout()->undoStack()->endCommand();
147   mShape->update();
148 }
149 
radiusUnitsChanged()150 void QgsLayoutShapeWidget::radiusUnitsChanged()
151 {
152   if ( !mShape )
153     return;
154 
155   mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Radius" ), QgsLayoutItem::UndoShapeCornerRadius );
156   mShape->setCornerRadius( QgsLayoutMeasurement( mCornerRadiusSpinBox->value(), mRadiusUnitsComboBox->unit() ) );
157   mShape->layout()->undoStack()->endCommand();
158   mShape->update();
159 }
160 
mShapeComboBox_currentIndexChanged(const QString &)161 void QgsLayoutShapeWidget::mShapeComboBox_currentIndexChanged( const QString & )
162 {
163   if ( !mShape )
164   {
165     return;
166   }
167 
168   mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Type" ) );
169   QgsLayoutItemShape::Shape shape = static_cast< QgsLayoutItemShape::Shape >( mShapeComboBox->currentData().toInt() );
170   mShape->setShapeType( shape );
171   toggleRadiusSpin( shape );
172   mShape->update();
173   mShape->layout()->undoStack()->endCommand();
174 }
175 
toggleRadiusSpin(QgsLayoutItemShape::Shape shape)176 void QgsLayoutShapeWidget::toggleRadiusSpin( QgsLayoutItemShape::Shape shape )
177 {
178   switch ( shape )
179   {
180     case QgsLayoutItemShape::Ellipse:
181     case QgsLayoutItemShape::Triangle:
182     {
183       mCornerRadiusSpinBox->setEnabled( false );
184       break;
185     }
186     case QgsLayoutItemShape::Rectangle:
187     {
188       mCornerRadiusSpinBox->setEnabled( true );
189       break;
190     }
191   }
192 }
193