From 2ec31d84d311476ce0f9c3f43f3c1b8d7c333832 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Tue, 17 Oct 2017 07:04:54 +1000 Subject: [PATCH] Add configuration widget for shapes --- python/core/layout/qgslayoutitem.sip | 2 + src/app/CMakeLists.txt | 2 + src/app/layout/qgslayoutapputils.cpp | 13 +- src/app/layout/qgslayoutshapewidget.cpp | 172 +++++++++++++++++++++ src/app/layout/qgslayoutshapewidget.h | 60 ++++++++ src/core/layout/qgslayoutitem.h | 2 + src/ui/layout/qgslayoutshapewidgetbase.ui | 179 ++++++++++++++++++++++ 7 files changed, 427 insertions(+), 3 deletions(-) create mode 100644 src/app/layout/qgslayoutshapewidget.cpp create mode 100644 src/app/layout/qgslayoutshapewidget.h create mode 100644 src/ui/layout/qgslayoutshapewidgetbase.ui diff --git a/python/core/layout/qgslayoutitem.sip b/python/core/layout/qgslayoutitem.sip index ab24b388c56..a48d3b7cb76 100644 --- a/python/core/layout/qgslayoutitem.sip +++ b/python/core/layout/qgslayoutitem.sip @@ -60,6 +60,8 @@ class QgsLayoutItem : QgsLayoutObject, QGraphicsRectItem, QgsLayoutUndoObjectInt UndoOpacity, UndoSetId, UndoRotation, + UndoShapeStyle, + UndoShapeCornerRadius, }; explicit QgsLayoutItem( QgsLayout *layout, bool manageZValue = true ); diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 36d2aef8af8..1070c2b11e9 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -182,6 +182,7 @@ SET(QGIS_APP_SRCS layout/qgslayoutmapwidget.cpp layout/qgslayoutpagepropertieswidget.cpp layout/qgslayoutpropertieswidget.cpp + layout/qgslayoutshapewidget.cpp locator/qgsinbuiltlocatorfilters.cpp locator/qgslocatoroptionswidget.cpp @@ -379,6 +380,7 @@ SET (QGIS_APP_MOC_HDRS layout/qgslayoutmapwidget.h layout/qgslayoutpagepropertieswidget.h layout/qgslayoutpropertieswidget.h + layout/qgslayoutshapewidget.h locator/qgsinbuiltlocatorfilters.h locator/qgslocatoroptionswidget.h diff --git a/src/app/layout/qgslayoutapputils.cpp b/src/app/layout/qgslayoutapputils.cpp index 0e0e1cda064..82a6447d0a2 100644 --- a/src/app/layout/qgslayoutapputils.cpp +++ b/src/app/layout/qgslayoutapputils.cpp @@ -20,6 +20,7 @@ #include "qgslayoutviewrubberband.h" #include "qgslayoutitemshape.h" #include "qgslayoutmapwidget.h" +#include "qgslayoutshapewidget.h" #include "qgslayoutitemmap.h" void QgsLayoutAppUtils::registerGuiForKnownItemTypes() @@ -49,19 +50,25 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes() return new QgsLayoutMapWidget( qobject_cast< QgsLayoutItemMap * >( item ) ); }, createRubberBand ) ); - registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Rectangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), nullptr, createRubberBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem* + auto createShapeWidget = + []( QgsLayoutItem * item )->QgsLayoutItemBaseWidget * + { + return new QgsLayoutShapeWidget( qobject_cast< QgsLayoutItemShape * >( item ) ); + }; + + registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Rectangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), createShapeWidget, createRubberBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem* { std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout ); shape->setShapeType( QgsLayoutItemShape::Rectangle ); return shape.release(); } ) ); - registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Ellipse" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), nullptr, createEllipseBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem* + registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Ellipse" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), createShapeWidget, createEllipseBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem* { std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout ); shape->setShapeType( QgsLayoutItemShape::Ellipse ); return shape.release(); } ) ); - registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Triangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), nullptr, createTriangleBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem* + registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Triangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), createShapeWidget, createTriangleBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem* { std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout ); shape->setShapeType( QgsLayoutItemShape::Triangle ); diff --git a/src/app/layout/qgslayoutshapewidget.cpp b/src/app/layout/qgslayoutshapewidget.cpp new file mode 100644 index 00000000000..56aa8aaa0c2 --- /dev/null +++ b/src/app/layout/qgslayoutshapewidget.cpp @@ -0,0 +1,172 @@ +/*************************************************************************** + qgslayoutshapewidget.cpp + -------------------------- + begin : November 2009 + copyright : (C) 2009 by Marco Hugentobler + email : marco@hugis.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "qgslayoutshapewidget.h" +#include "qgsstyle.h" +#include "qgslayoutitemshape.h" +#include "qgslayout.h" +#include "qgslayoutundostack.h" + +QgsLayoutShapeWidget::QgsLayoutShapeWidget( QgsLayoutItemShape *shape ) + : QgsLayoutItemBaseWidget( nullptr, shape ) + , mShape( shape ) +{ + setupUi( this ); + connect( mShapeComboBox, static_cast( &QComboBox::currentIndexChanged ), this, &QgsLayoutShapeWidget::mShapeComboBox_currentIndexChanged ); + connect( mCornerRadiusSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLayoutShapeWidget::mCornerRadiusSpinBox_valueChanged ); + setPanelTitle( tr( "Shape properties" ) ); + + //add widget for general composer item properties + mItemPropertiesWidget = new QgsLayoutItemPropertiesWidget( this, shape ); + //shapes don't use background or frame, since the symbol style is set through a QgsSymbolSelectorWidget + mItemPropertiesWidget->showBackgroundGroup( false ); + mItemPropertiesWidget->showFrameGroup( false ); + mainLayout->addWidget( mItemPropertiesWidget ); + + blockAllSignals( true ); + + //shape types + mShapeComboBox->addItem( tr( "Rectangle" ), QgsLayoutItemShape::Rectangle ); + mShapeComboBox->addItem( tr( "Ellipse" ), QgsLayoutItemShape::Ellipse ); + mShapeComboBox->addItem( tr( "Triangle" ), QgsLayoutItemShape::Triangle ); + + mShapeStyleButton->setSymbolType( QgsSymbol::Fill ); + mRadiusUnitsComboBox->linkToWidget( mCornerRadiusSpinBox ); + mRadiusUnitsComboBox->setConverter( &mShape->layout()->context().measurementConverter() ); + + setGuiElementValues(); + + blockAllSignals( false ); + + if ( mShape ) + { + connect( mShape, &QgsLayoutObject::changed, this, &QgsLayoutShapeWidget::setGuiElementValues ); + mShapeStyleButton->registerExpressionContextGenerator( mShape ); + } + connect( mShapeStyleButton, &QgsSymbolButton::changed, this, &QgsLayoutShapeWidget::symbolChanged ); + connect( mRadiusUnitsComboBox, &QgsLayoutUnitsComboBox::changed, this, &QgsLayoutShapeWidget::radiusUnitsChanged ); + +#if 0 //TODO + mShapeStyleButton->setLayer( atlasCoverageLayer() ); +#endif +} + +bool QgsLayoutShapeWidget::setNewItem( QgsLayoutItem *item ) +{ + if ( item->type() != QgsLayoutItemRegistry::LayoutShape ) + return false; + + mShape = qobject_cast< QgsLayoutItemShape * >( item ); + mItemPropertiesWidget->setItem( mShape ); + + setGuiElementValues(); + + return true; +} + +void QgsLayoutShapeWidget::blockAllSignals( bool block ) +{ + mShapeComboBox->blockSignals( block ); + mCornerRadiusSpinBox->blockSignals( block ); + mRadiusUnitsComboBox->blockSignals( block ); + mShapeStyleButton->blockSignals( block ); +} + +void QgsLayoutShapeWidget::setGuiElementValues() +{ + if ( !mShape ) + { + return; + } + + blockAllSignals( true ); + + mShapeStyleButton->setSymbol( mShape->symbol()->clone() ); + + mCornerRadiusSpinBox->setValue( mShape->cornerRadius().length() ); + mRadiusUnitsComboBox->setUnit( mShape->cornerRadius().units() ); + + mShapeComboBox->setCurrentIndex( mShapeComboBox->findData( mShape->shapeType() ) ); + toggleRadiusSpin( mShape->shapeType() ); + + blockAllSignals( false ); +} + +void QgsLayoutShapeWidget::symbolChanged() +{ + if ( !mShape ) + return; + + mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Style" ), QgsLayoutItem::UndoShapeStyle ); + mShape->setSymbol( mShapeStyleButton->clonedSymbol() ); + mShape->layout()->undoStack()->endCommand(); +} + +void QgsLayoutShapeWidget::mCornerRadiusSpinBox_valueChanged( double val ) +{ + if ( !mShape ) + return; + + mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Radius" ), QgsLayoutItem::UndoShapeCornerRadius ); + mShape->setCornerRadius( QgsLayoutMeasurement( val, mRadiusUnitsComboBox->unit() ) ); + mShape->layout()->undoStack()->endCommand(); + mShape->update(); +} + +void QgsLayoutShapeWidget::radiusUnitsChanged() +{ + if ( !mShape ) + return; + + mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Radius" ), QgsLayoutItem::UndoShapeCornerRadius ); + mShape->setCornerRadius( QgsLayoutMeasurement( mCornerRadiusSpinBox->value(), mRadiusUnitsComboBox->unit() ) ); + mShape->layout()->undoStack()->endCommand(); + mShape->update(); +} + +void QgsLayoutShapeWidget::mShapeComboBox_currentIndexChanged( const QString & ) +{ + if ( !mShape ) + { + return; + } + + mShape->layout()->undoStack()->beginCommand( mShape, tr( "Change Shape Type" ) ); + QgsLayoutItemShape::Shape shape = static_cast< QgsLayoutItemShape::Shape >( mShapeComboBox->currentData().toInt() ); + mShape->setShapeType( shape ); + toggleRadiusSpin( shape ); + mShape->update(); + mShape->layout()->undoStack()->endCommand(); +} + +void QgsLayoutShapeWidget::toggleRadiusSpin( QgsLayoutItemShape::Shape shape ) +{ + switch ( shape ) + { + case QgsLayoutItemShape::Ellipse: + case QgsLayoutItemShape::Triangle: + { + mCornerRadiusSpinBox->setEnabled( false ); + break; + } + case QgsLayoutItemShape::Rectangle: + { + mCornerRadiusSpinBox->setEnabled( true ); + break; + } + } +} diff --git a/src/app/layout/qgslayoutshapewidget.h b/src/app/layout/qgslayoutshapewidget.h new file mode 100644 index 00000000000..e5d119287ad --- /dev/null +++ b/src/app/layout/qgslayoutshapewidget.h @@ -0,0 +1,60 @@ +/*************************************************************************** + qgslayoutshapewidget.h + ------------------------ + begin : November 2009 + copyright : (C) 2009 by Marco Hugentobler + email : marco@hugis.net + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef QGSLAYOUTSHAPEWIDGET_H +#define QGSLAYOUTSHAPEWIDGET_H + +#include "ui_qgslayoutshapewidgetbase.h" +#include "qgslayoutitemwidget.h" +#include "qgslayoutitemshape.h" + +/** + * \ingroup app + * Input widget for the configuration of QgsLayoutItemShape +*/ +class QgsLayoutShapeWidget: public QgsLayoutItemBaseWidget, private Ui::QgsLayoutShapeWidgetBase +{ + Q_OBJECT + public: + explicit QgsLayoutShapeWidget( QgsLayoutItemShape *shape ); + + protected: + + bool setNewItem( QgsLayoutItem *item ) override; + + + private: + QgsLayoutItemShape *mShape = nullptr; + QgsLayoutItemPropertiesWidget *mItemPropertiesWidget = nullptr; + + //! Blocks / unblocks the signal of all GUI elements + void blockAllSignals( bool block ); + + private slots: + void mShapeComboBox_currentIndexChanged( const QString &text ); + void mCornerRadiusSpinBox_valueChanged( double val ); + void radiusUnitsChanged(); + void symbolChanged(); + + //! Sets the GUI elements to the currentValues of mComposerShape + void setGuiElementValues(); + + //! Enables or disables the rounded radius spin box based on shape type + void toggleRadiusSpin( QgsLayoutItemShape::Shape shape ); +}; + +#endif // QGSLAYOUTSHAPEWIDGET_H diff --git a/src/core/layout/qgslayoutitem.h b/src/core/layout/qgslayoutitem.h index 472fd7de891..dec9e0e033a 100644 --- a/src/core/layout/qgslayoutitem.h +++ b/src/core/layout/qgslayoutitem.h @@ -93,6 +93,8 @@ class CORE_EXPORT QgsLayoutItem : public QgsLayoutObject, public QGraphicsRectIt UndoOpacity, //!< Opacity adjustment UndoSetId, //!< Change item ID UndoRotation, //!< Rotation adjustment + UndoShapeStyle, //!< Shape symbol style + UndoShapeCornerRadius, //!< Shape corner radius }; /** diff --git a/src/ui/layout/qgslayoutshapewidgetbase.ui b/src/ui/layout/qgslayoutshapewidgetbase.ui new file mode 100644 index 00000000000..5d37046a453 --- /dev/null +++ b/src/ui/layout/qgslayoutshapewidgetbase.ui @@ -0,0 +1,179 @@ + + + QgsLayoutShapeWidgetBase + + + + 0 + 0 + 564 + 322 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + padding: 2px; font-weight: bold; background-color: rgb(200, 200, 200); + + + Shape + + + + + + + true + + + + + 0 + 0 + 548 + 285 + + + + + + + Qt::StrongFocus + + + Main properties + + + composeritem + + + false + + + + + + Corner radius + + + + + + + + + + 0 + 0 + + + + + + + 999.000000000000000 + + + + + + + + + + + + Style + + + + + + + + 0 + 0 + + + + Change... + + + + + + + + + + + + + + + + + + QgsDoubleSpinBox + QDoubleSpinBox +
qgsdoublespinbox.h
+
+ + QgsScrollArea + QScrollArea +
qgsscrollarea.h
+ 1 +
+ + QgsCollapsibleGroupBoxBasic + QGroupBox +
qgscollapsiblegroupbox.h
+ 1 +
+ + QgsSymbolButton + QToolButton +
qgssymbolbutton.h
+
+ + QgsLayoutUnitsComboBox + QComboBox +
qgslayoutunitscombobox.h
+
+
+ + groupBox + scrollArea + mShapeComboBox + mCornerRadiusSpinBox + mRadiusUnitsComboBox + mShapeStyleButton + + + +