From 20029c2956207a0765a225c2ade8ab9a5da41b64 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Sat, 22 Jul 2017 21:58:28 +1000 Subject: [PATCH] Add a lot of framework code for showing item properties in designer And hook up a non-functional page properties widget which is shown when right clicking on a page in the view. --- .../gui/layout/qgslayoutitemguiregistry.sip | 15 +- src/app/CMakeLists.txt | 2 + src/app/layout/qgslayoutappmenuprovider.cpp | 11 +- src/app/layout/qgslayoutappmenuprovider.h | 8 +- src/app/layout/qgslayoutdesignerdialog.cpp | 60 +++++- src/app/layout/qgslayoutdesignerdialog.h | 14 ++ .../layout/qgslayoutpagepropertieswidget.cpp | 25 +++ .../layout/qgslayoutpagepropertieswidget.h | 52 +++++ src/core/layout/qgslayoutitemregistry.cpp | 2 + src/gui/layout/qgslayoutitemguiregistry.h | 20 +- src/ui/layout/qgslayoutdesignerbase.ui | 8 +- .../layout/qgslayoutpagepropertieswidget.ui | 180 ++++++++++++++++++ 12 files changed, 385 insertions(+), 12 deletions(-) create mode 100644 src/app/layout/qgslayoutpagepropertieswidget.cpp create mode 100644 src/app/layout/qgslayoutpagepropertieswidget.h create mode 100644 src/ui/layout/qgslayoutpagepropertieswidget.ui diff --git a/python/gui/layout/qgslayoutitemguiregistry.sip b/python/gui/layout/qgslayoutitemguiregistry.sip index 8f7d552b498..3de56bd3df4 100644 --- a/python/gui/layout/qgslayoutitemguiregistry.sip +++ b/python/gui/layout/qgslayoutitemguiregistry.sip @@ -28,7 +28,14 @@ class QgsLayoutItemAbstractGuiMetadata %End public: - QgsLayoutItemAbstractGuiMetadata( int type, const QString &groupId = QString() ); + enum Flag + { + FlagNoCreationTools, + }; + typedef QFlags Flags; + + + QgsLayoutItemAbstractGuiMetadata( int type, const QString &groupId = QString(), Flags flags = 0 ); %Docstring Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class ``type``. @@ -43,6 +50,12 @@ class QgsLayoutItemAbstractGuiMetadata :rtype: int %End + Flags flags() const; +%Docstring + Returns item flags. + :rtype: Flags +%End + QString groupId() const; %Docstring Returns the item group ID, if set. diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 06a3ac9e092..997c1eae6f6 100755 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -158,6 +158,7 @@ SET(QGIS_APP_SRCS layout/qgslayoutaddpagesdialog.cpp layout/qgslayoutdesignerdialog.cpp layout/qgslayoutappmenuprovider.cpp + layout/qgslayoutpagepropertieswidget.cpp locator/qgsinbuiltlocatorfilters.cpp locator/qgslocatoroptionswidget.cpp @@ -337,6 +338,7 @@ SET (QGIS_APP_MOC_HDRS layout/qgslayoutaddpagesdialog.h layout/qgslayoutappmenuprovider.h layout/qgslayoutdesignerdialog.h + layout/qgslayoutpagepropertieswidget.h locator/qgsinbuiltlocatorfilters.h locator/qgslocatoroptionswidget.h diff --git a/src/app/layout/qgslayoutappmenuprovider.cpp b/src/app/layout/qgslayoutappmenuprovider.cpp index 308c9d3a5ea..1c590746a2f 100644 --- a/src/app/layout/qgslayoutappmenuprovider.cpp +++ b/src/app/layout/qgslayoutappmenuprovider.cpp @@ -15,12 +15,14 @@ #include "qgslayoutappmenuprovider.h" #include "qgslayoutitempage.h" +#include "qgslayoutdesignerdialog.h" #include "qgslayout.h" #include #include -QgsLayoutAppMenuProvider::QgsLayoutAppMenuProvider( QObject *parent ) - : QObject( parent ) +QgsLayoutAppMenuProvider::QgsLayoutAppMenuProvider( QgsLayoutDesignerDialog *designer ) + : QObject( nullptr ) + , mDesigner( designer ) { } @@ -34,10 +36,9 @@ QMenu *QgsLayoutAppMenuProvider::createContextMenu( QWidget *parent, QgsLayout * if ( page ) { QAction *pagePropertiesAction = new QAction( tr( "Page Properties…" ), menu ); - connect( pagePropertiesAction, &QAction::triggered, this, [page]() + connect( pagePropertiesAction, &QAction::triggered, this, [this, page]() { - - + mDesigner->showItemOptions( page ); } ); menu->addAction( pagePropertiesAction ); QAction *removePageAction = new QAction( tr( "Remove Page" ), menu ); diff --git a/src/app/layout/qgslayoutappmenuprovider.h b/src/app/layout/qgslayoutappmenuprovider.h index feed54be451..fda8f1eb90e 100644 --- a/src/app/layout/qgslayoutappmenuprovider.h +++ b/src/app/layout/qgslayoutappmenuprovider.h @@ -20,6 +20,8 @@ #include "qgslayoutview.h" #include +class QgsLayoutDesignerDialog; + /** * A menu provider for QgsLayoutView */ @@ -29,10 +31,14 @@ class QgsLayoutAppMenuProvider : public QObject, public QgsLayoutViewMenuProvide public: - QgsLayoutAppMenuProvider( QObject *parent = nullptr ); + QgsLayoutAppMenuProvider( QgsLayoutDesignerDialog *designer ); QMenu *createContextMenu( QWidget *parent, QgsLayout *layout, QPointF layoutPoint ) const override; + private: + + QgsLayoutDesignerDialog *mDesigner = nullptr; + }; #endif // QGSLAYOUTAPPMENUPROVIDER_H diff --git a/src/app/layout/qgslayoutdesignerdialog.cpp b/src/app/layout/qgslayoutdesignerdialog.cpp index 18572f73cdd..cc5497512fe 100644 --- a/src/app/layout/qgslayoutdesignerdialog.cpp +++ b/src/app/layout/qgslayoutdesignerdialog.cpp @@ -27,10 +27,15 @@ #include "qgslayoutviewtoolpan.h" #include "qgslayoutviewtoolzoom.h" #include "qgslayoutviewtoolselect.h" +#include "qgslayoutitemwidget.h" #include "qgsgui.h" #include "qgslayoutitemguiregistry.h" #include "qgslayoutruler.h" #include "qgslayoutaddpagesdialog.h" +#include "qgspanelwidgetstack.h" +#include "qgspanelwidget.h" +#include "qgsdockwidget.h" +#include "qgslayoutpagepropertieswidget.h" #include #include #include @@ -44,6 +49,8 @@ QList QgsLayoutDesignerDialog::sStatusZoomLevelsList { 0.125, 0.25, 0.5, #define FIT_LAYOUT -101 #define FIT_LAYOUT_WIDTH -102 +bool QgsLayoutDesignerDialog::sInitializedRegistry = false; + QgsAppLayoutDesignerInterface::QgsAppLayoutDesignerInterface( QgsLayoutDesignerDialog *dialog ) : QgsLayoutDesignerInterface( dialog ) , mDesigner( dialog ) @@ -70,6 +77,10 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla , mInterface( new QgsAppLayoutDesignerInterface( this ) ) , mToolsActionGroup( new QActionGroup( this ) ) { + if ( !sInitializedRegistry ) + { + initializeRegistry(); + } QgsSettings settings; int size = settings.value( QStringLiteral( "IconSize" ), QGIS_ICON_SIZE ).toInt(); setIconSize( QSize( size, size ) ); @@ -222,9 +233,22 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla connect( mActionToggleFullScreen, &QAction::toggled, this, &QgsLayoutDesignerDialog::toggleFullScreen ); - mMenuProvider = new QgsLayoutAppMenuProvider(); + mMenuProvider = new QgsLayoutAppMenuProvider( this ); mView->setMenuProvider( mMenuProvider ); + int minDockWidth( fontMetrics().width( QStringLiteral( "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ) ) ); + + mItemDock = new QgsDockWidget( tr( "Item properties" ), this ); + mItemDock->setObjectName( QStringLiteral( "ItemDock" ) ); + mItemDock->setMinimumWidth( minDockWidth ); + mItemPropertiesStack = new QgsPanelWidgetStack(); + mItemDock->setWidget( mItemPropertiesStack ); + mPanelsMenu->addAction( mItemDock->toggleViewAction() ); + + addDockWidget( Qt::RightDockWidgetArea, mItemDock ); + + mItemDock->show(); + restoreWindowState(); } @@ -257,6 +281,25 @@ void QgsLayoutDesignerDialog::setIconSizes( int size ) } } +void QgsLayoutDesignerDialog::showItemOptions( QgsLayoutItem *item ) +{ + if ( !item ) + { + delete mItemPropertiesStack->takeMainPanel(); + return; + } + + std::unique_ptr< QgsLayoutItemBaseWidget > widget( QgsGui::layoutItemGuiRegistry()->createItemWidget( item ) ); + if ( ! widget ) + { + return; + } + + delete mItemPropertiesStack->takeMainPanel(); + widget->setDockMode( true ); + mItemPropertiesStack->setMainPanel( widget.release() ); +} + void QgsLayoutDesignerDialog::open() { show(); @@ -302,6 +345,9 @@ void QgsLayoutDesignerDialog::closeEvent( QCloseEvent * ) void QgsLayoutDesignerDialog::itemTypeAdded( int type ) { + if ( QgsGui::layoutItemGuiRegistry()->itemMetadata( type )->flags() & QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools ) + return; + QString name = QgsApplication::layoutItemRegistry()->itemMetadata( type )->visibleName(); QString groupId = QgsGui::layoutItemGuiRegistry()->itemMetadata( type )->groupId(); QToolButton *groupButton = nullptr; @@ -532,4 +578,16 @@ void QgsLayoutDesignerDialog::activateNewItemCreationTool( int type ) } } +void QgsLayoutDesignerDialog::initializeRegistry() +{ + sInitializedRegistry = true; + auto createPageWidget = ( []( QgsLayoutItem * item )->QgsLayoutItemBaseWidget * + { + return new QgsLayoutPagePropertiesWidget( nullptr, item ); + } ); + + QgsGui::layoutItemGuiRegistry()->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPage, QIcon(), createPageWidget, nullptr, QString(), QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools ) ); + +} + diff --git a/src/app/layout/qgslayoutdesignerdialog.h b/src/app/layout/qgslayoutdesignerdialog.h index 72729768af0..0a93533ae06 100644 --- a/src/app/layout/qgslayoutdesignerdialog.h +++ b/src/app/layout/qgslayoutdesignerdialog.h @@ -32,6 +32,9 @@ class QComboBox; class QSlider; class QLabel; class QgsLayoutAppMenuProvider; +class QgsLayoutItem; +class QgsPanelWidgetStack; +class QgsDockWidget; class QgsAppLayoutDesignerInterface : public QgsLayoutDesignerInterface { @@ -90,6 +93,10 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner */ void setIconSizes( int size ); + /** + * Shows the configuration widget for the specified layout \a item. + */ + void showItemOptions( QgsLayoutItem *item ); public slots: @@ -138,6 +145,8 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner private: + static bool sInitializedRegistry; + QgsAppLayoutDesignerInterface *mInterface = nullptr; QgsLayout *mLayout = nullptr; @@ -170,6 +179,9 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner QgsLayoutAppMenuProvider *mMenuProvider; + QgsDockWidget *mItemDock = nullptr; + QgsPanelWidgetStack *mItemPropertiesStack = nullptr; + //! Save window state void saveWindowState(); @@ -179,6 +191,8 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner //! Switch to new item creation tool, for a new item of the specified \a type. void activateNewItemCreationTool( int type ); + void initializeRegistry(); + }; #endif // QGSLAYOUTDESIGNERDIALOG_H diff --git a/src/app/layout/qgslayoutpagepropertieswidget.cpp b/src/app/layout/qgslayoutpagepropertieswidget.cpp new file mode 100644 index 00000000000..80f7be73f37 --- /dev/null +++ b/src/app/layout/qgslayoutpagepropertieswidget.cpp @@ -0,0 +1,25 @@ +/*************************************************************************** + qgslayoutpagepropertieswidget.cpp + --------------------------------- + Date : July 2017 + Copyright : (C) 2017 Nyall Dawson + Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * 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 "qgslayoutpagepropertieswidget.h" +#include "qgslayoutitempage.h" + +QgsLayoutPagePropertiesWidget::QgsLayoutPagePropertiesWidget( QWidget *parent, QgsLayoutItem *layoutItem ) + : QgsLayoutItemBaseWidget( parent, layoutItem ) + , mPage( static_cast< QgsLayoutItemPage *>( layoutItem ) ) +{ + setupUi( this ); + +} diff --git a/src/app/layout/qgslayoutpagepropertieswidget.h b/src/app/layout/qgslayoutpagepropertieswidget.h new file mode 100644 index 00000000000..2f92d8fce49 --- /dev/null +++ b/src/app/layout/qgslayoutpagepropertieswidget.h @@ -0,0 +1,52 @@ +/*************************************************************************** + qgslayoutpagepropertieswidget.h + ------------------------------- + Date : July 2017 + Copyright : (C) 2017 Nyall Dawson + Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * 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 QGSLAYOUTPAGEPROPERTIESWIDGET_H +#define QGSLAYOUTPAGEPROPERTIESWIDGET_H + +#include "qgis.h" +#include "ui_qgslayoutpagepropertieswidget.h" + +#include "qgslayoutsize.h" +#include "qgslayoutpoint.h" +#include "qgslayoutitemwidget.h" +#include "qgslayoutmeasurementconverter.h" + +class QgsLayoutItem; +class QgsLayoutItemPage; + +/** + * A widget for configuring properties of pages in a layout + */ +class QgsLayoutPagePropertiesWidget : public QgsLayoutItemBaseWidget, private Ui::QgsLayoutPagePropertiesWidget +{ + Q_OBJECT + + public: + + /** + * Constructor for QgsLayoutPagePropertiesWidget. + */ + QgsLayoutPagePropertiesWidget( QWidget *parent, QgsLayoutItem *page ); + + private: + + QgsLayoutItemPage *mPage = nullptr; + + QgsLayoutMeasurementConverter mConverter; + +}; + +#endif // QGSLAYOUTPAGEPROPERTIESWIDGET_H diff --git a/src/core/layout/qgslayoutitemregistry.cpp b/src/core/layout/qgslayoutitemregistry.cpp index 0b9b8dbffea..d8840d93f73 100644 --- a/src/core/layout/qgslayoutitemregistry.cpp +++ b/src/core/layout/qgslayoutitemregistry.cpp @@ -42,6 +42,8 @@ bool QgsLayoutItemRegistry::populate() }; addLayoutItemType( new QgsLayoutItemMetadata( 101, QStringLiteral( "temp type" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddLabel.svg" ) ), createTemporaryItem ) ); + addLayoutItemType( new QgsLayoutItemMetadata( LayoutPage, QStringLiteral( "Page" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileNew.svg" ) ), nullptr ) ); + addLayoutItemType( new QgsLayoutItemMetadata( LayoutRectangle, QStringLiteral( "Rectangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), QgsLayoutItemRectangularShape::create ) ); addLayoutItemType( new QgsLayoutItemMetadata( LayoutEllipse, QStringLiteral( "Ellipse" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), QgsLayoutItemEllipseShape::create ) ); addLayoutItemType( new QgsLayoutItemMetadata( LayoutTriangle, QStringLiteral( "Triangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), QgsLayoutItemTriangleShape::create ) ); diff --git a/src/gui/layout/qgslayoutitemguiregistry.h b/src/gui/layout/qgslayoutitemguiregistry.h index fc80758ed53..871e92ac1de 100644 --- a/src/gui/layout/qgslayoutitemguiregistry.h +++ b/src/gui/layout/qgslayoutitemguiregistry.h @@ -46,14 +46,22 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata { public: + //! Flags for controlling how a items behave in the GUI + enum Flag + { + FlagNoCreationTools = 1 << 1, //!< Do not show item creation tools for the item type + }; + Q_DECLARE_FLAGS( Flags, Flag ) + /** * Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class \a type. * * An optional \a groupId can be set, which allows grouping of related layout item classes. See QgsLayoutItemGuiMetadata for details. */ - QgsLayoutItemAbstractGuiMetadata( int type, const QString &groupId = QString() ) + QgsLayoutItemAbstractGuiMetadata( int type, const QString &groupId = QString(), Flags flags = 0 ) : mType( type ) , mGroupId( groupId ) + , mFlags( flags ) {} virtual ~QgsLayoutItemAbstractGuiMetadata() = default; @@ -63,6 +71,11 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata */ int type() const { return mType; } + /** + * Returns item flags. + */ + Flags flags() const { return mFlags; } + /** * Returns the item group ID, if set. */ @@ -88,6 +101,7 @@ class GUI_EXPORT QgsLayoutItemAbstractGuiMetadata int mType = -1; QString mGroupId; + Flags mFlags; }; @@ -118,8 +132,8 @@ class GUI_EXPORT QgsLayoutItemGuiMetadata : public QgsLayoutItemAbstractGuiMetad */ QgsLayoutItemGuiMetadata( int type, const QIcon &creationIcon, QgsLayoutItemWidgetFunc pfWidget = nullptr, - QgsLayoutItemRubberBandFunc pfRubberBand = nullptr, const QString &groupId = QString() ) - : QgsLayoutItemAbstractGuiMetadata( type, groupId ) + QgsLayoutItemRubberBandFunc pfRubberBand = nullptr, const QString &groupId = QString(), QgsLayoutItemAbstractGuiMetadata::Flags flags = 0 ) + : QgsLayoutItemAbstractGuiMetadata( type, groupId, flags ) , mIcon( creationIcon ) , mWidgetFunc( pfWidget ) , mRubberBandFunc( pfRubberBand ) diff --git a/src/ui/layout/qgslayoutdesignerbase.ui b/src/ui/layout/qgslayoutdesignerbase.ui index 6be4a439438..980818247a0 100644 --- a/src/ui/layout/qgslayoutdesignerbase.ui +++ b/src/ui/layout/qgslayoutdesignerbase.ui @@ -83,7 +83,7 @@ 0 0 1083 - 25 + 42 @@ -107,6 +107,11 @@ &Toolbars + + + &Panels + + @@ -116,6 +121,7 @@ + diff --git a/src/ui/layout/qgslayoutpagepropertieswidget.ui b/src/ui/layout/qgslayoutpagepropertieswidget.ui new file mode 100644 index 00000000000..fb87590d9bf --- /dev/null +++ b/src/ui/layout/qgslayoutpagepropertieswidget.ui @@ -0,0 +1,180 @@ + + + QgsLayoutPagePropertiesWidget + + + + 0 + 0 + 660 + 368 + + + + New Item Properties + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Page size + + + + + + Size + + + + + + + Width + + + + + + + + + + Orientation + + + + + + + + + + Height + + + + + + + + + + + + 2 + + + 2 + + + 0 + + + 2 + + + + + + 0 + 0 + + + + Lock aspect ratio (including while drawing extent onto canvas) + + + 13 + + + + + + + + + + + + 3 + + + 9999999.000000000000000 + + + 100.000000000000000 + + + false + + + + + + + + + + 3 + + + 9999999.000000000000000 + + + 100.000000000000000 + + + false + + + + + + + + + + + + + QgsRatioLockButton + QToolButton +
qgsratiolockbutton.h
+ 1 +
+ + QgsDoubleSpinBox + QDoubleSpinBox +
qgsdoublespinbox.h
+
+ + QgsLayoutUnitsComboBox + QComboBox +
qgslayoutunitscombobox.h
+
+
+ + mPageSizeComboBox + mPageOrientationComboBox + mWidthSpin + mHeightSpin + mLockAspectRatio + mSizeUnitsComboBox + + + +