Skip to content

Commit 44fe2a8

Browse files
committed
Add tools to create node based items
1 parent 6b629e1 commit 44fe2a8

19 files changed

+537
-43
lines changed

python/core/layout/qgslayout.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator, QgsLayoutUndoOb
2828
ZGuide,
2929
ZSmartGuide,
3030
ZMouseHandles,
31-
ZMapTool,
31+
ZViewTool,
3232
ZSnapIndicator,
3333
};
3434

python/core/layout/qgslayoutitemnodeitem.sip

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@ class QgsLayoutNodesItem: QgsLayoutItem
2222
%End
2323
public:
2424

25+
void setNodes( const QPolygonF &nodes );
26+
%Docstring
27+
Sets the ``nodes`` the shape consists of.
28+
.. seealso:: nodes()
29+
%End
30+
31+
QPolygonF nodes() const;
32+
%Docstring
33+
Returns the nodes the shape consists of.
34+
.. seealso:: setNodes()
35+
:rtype: QPolygonF
36+
%End
37+
2538
bool addNode( QPointF point, bool checkArea = true, double radius = 10 );
2639
%Docstring
2740
Add a node in current shape.
@@ -95,12 +108,6 @@ Returns the number of nodes in the shape.
95108
Deselects any selected nodes.
96109
%End
97110

98-
QPolygonF nodes() const;
99-
%Docstring
100-
Returns the nodes the shape consists of.
101-
:rtype: QPolygonF
102-
%End
103-
104111
protected:
105112

106113
QgsLayoutNodesItem( QgsLayout *layout );

python/gui/gui_auto.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@
295295
%Include layout/qgslayoutview.sip
296296
%Include layout/qgslayoutviewtool.sip
297297
%Include layout/qgslayoutviewtooladditem.sip
298+
%Include layout/qgslayoutviewtooladdnodeitem.sip
298299
%Include layout/qgslayoutviewtoolpan.sip
299300
%Include layout/qgslayoutviewtoolselect.sip
300301
%Include layout/qgslayoutviewtooltemporarykeypan.sip

python/gui/layout/qgslayoutitemguiregistry.sip

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,15 @@ class QgsLayoutItemAbstractGuiMetadata
3535
typedef QFlags<QgsLayoutItemAbstractGuiMetadata::Flag> Flags;
3636

3737

38-
QgsLayoutItemAbstractGuiMetadata( int type, const QString &visibleName, const QString &groupId = QString(), Flags flags = 0 );
38+
QgsLayoutItemAbstractGuiMetadata( int type, const QString &visibleName, const QString &groupId = QString(), bool isNodeBased = false, Flags flags = 0 );
3939
%Docstring
4040
Constructor for QgsLayoutItemAbstractGuiMetadata with the specified class ``type``.
4141

4242
``visibleName`` should be set to a translated, user visible name identifying the corresponding layout item.
4343

4444
An optional ``groupId`` can be set, which allows grouping of related layout item classes. See QgsLayoutItemGuiMetadata for details.
45+
46+
If ``isNodeBased`` is true, then the corresponding item is a node based item.
4547
%End
4648

4749
virtual ~QgsLayoutItemAbstractGuiMetadata();
@@ -64,6 +66,12 @@ class QgsLayoutItemAbstractGuiMetadata
6466
:rtype: str
6567
%End
6668

69+
bool isNodeBased() const;
70+
%Docstring
71+
Returns true if the associated item is a node based item.
72+
:rtype: bool
73+
%End
74+
6775
QString visibleName() const;
6876
%Docstring
6977
Returns a translated, user visible name identifying the corresponding layout item.
@@ -86,9 +94,18 @@ class QgsLayoutItemAbstractGuiMetadata
8694
%Docstring
8795
Creates a rubber band for use when creating layout items of this type. Can return None if no rubber band
8896
should be created. The default behavior is to create a rectangular rubber band.
97+
.. seealso:: createNodeRubberBand()
8998
:rtype: QgsLayoutViewRubberBand
9099
%End
91100

101+
virtual QAbstractGraphicsShapeItem *createNodeRubberBand( QgsLayoutView *view ) /Factory/;
102+
%Docstring
103+
Creates a rubber band for use when creating layout node based items of this type. Can return None if no rubber band
104+
should be created. The default behavior is to return None.
105+
.. seealso:: createRubberBand()
106+
:rtype: QAbstractGraphicsShapeItem
107+
%End
108+
92109
virtual QgsLayoutItem *createItem( QgsLayout *layout ) /Factory/;
93110
%Docstring
94111
Creates an instance of the corresponding item type.
@@ -100,6 +117,7 @@ class QgsLayoutItemAbstractGuiMetadata
100117

101118

102119

120+
103121
class QgsLayoutItemGuiGroup
104122
{
105123
%Docstring
@@ -219,6 +237,7 @@ class QgsLayoutItemGuiRegistry : QObject
219237
%End
220238

221239

240+
222241
QList< int > itemMetadataIds() const;
223242
%Docstring
224243
Returns a list of available item metadata ids handled by the registry.
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/************************************************************************
2+
* This file has been generated automatically from *
3+
* *
4+
* src/gui/layout/qgslayoutviewtooladdnodeitem.h *
5+
* *
6+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
7+
************************************************************************/
8+
9+
10+
11+
class QgsLayoutViewToolAddNodeItem : QgsLayoutViewTool
12+
{
13+
%Docstring
14+
Layout view tool for adding node based items to a layout.
15+
.. versionadded:: 3.0
16+
%End
17+
18+
%TypeHeaderCode
19+
#include "qgslayoutviewtooladdnodeitem.h"
20+
%End
21+
public:
22+
23+
QgsLayoutViewToolAddNodeItem( QgsLayoutView *view /TransferThis/ );
24+
25+
int itemMetadataId() const;
26+
%Docstring
27+
Returns the item metadata id for items created by the tool.
28+
.. seealso:: setItemMetadataId()
29+
:rtype: int
30+
%End
31+
32+
void setItemMetadataId( int metadataId );
33+
%Docstring
34+
Sets the item metadata ``metadataId`` for items created by the tool.
35+
36+
The ``metadataId`` associates the current tool behavior with a metadata entry
37+
from QgsLayoutItemGuiRegistry.
38+
39+
.. seealso:: itemMetadataId()
40+
%End
41+
42+
virtual void layoutPressEvent( QgsLayoutViewMouseEvent *event );
43+
44+
virtual void layoutMoveEvent( QgsLayoutViewMouseEvent *event );
45+
46+
virtual void layoutReleaseEvent( QgsLayoutViewMouseEvent *event );
47+
48+
virtual void deactivate();
49+
50+
51+
signals:
52+
53+
void createdItem();
54+
%Docstring
55+
Emitted when an item has been created using the tool.
56+
%End
57+
58+
};
59+
60+
/************************************************************************
61+
* This file has been generated automatically from *
62+
* *
63+
* src/gui/layout/qgslayoutviewtooladdnodeitem.h *
64+
* *
65+
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
66+
************************************************************************/

src/app/layout/qgslayoutapputils.cpp

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
#include "qgslayoutapputils.h"
1717
#include "qgsgui.h"
18+
#include "qgslayout.h"
1819
#include "qgslayoutitemguiregistry.h"
1920
#include "qgslayoutitemregistry.h"
2021
#include "qgslayoutviewrubberband.h"
@@ -59,35 +60,56 @@ void QgsLayoutAppUtils::registerGuiForKnownItemTypes()
5960
return new QgsLayoutShapeWidget( qobject_cast< QgsLayoutItemShape * >( item ) );
6061
};
6162

62-
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Rectangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), createShapeWidget, createRubberBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem*
63+
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Rectangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicRectangle.svg" ) ), createShapeWidget, createRubberBand, QStringLiteral( "shapes" ), false, 0, []( QgsLayout * layout )->QgsLayoutItem*
6364
{
6465
std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout );
6566
shape->setShapeType( QgsLayoutItemShape::Rectangle );
6667
return shape.release();
6768
} ) );
68-
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Ellipse" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), createShapeWidget, createEllipseBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem*
69+
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Ellipse" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicCircle.svg" ) ), createShapeWidget, createEllipseBand, QStringLiteral( "shapes" ), false, 0, []( QgsLayout * layout )->QgsLayoutItem*
6970
{
7071
std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout );
7172
shape->setShapeType( QgsLayoutItemShape::Ellipse );
7273
return shape.release();
7374
} ) );
74-
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Triangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), createShapeWidget, createTriangleBand, QStringLiteral( "shapes" ), 0, []( QgsLayout * layout )->QgsLayoutItem*
75+
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutShape, QObject::tr( "Triangle" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddBasicTriangle.svg" ) ), createShapeWidget, createTriangleBand, QStringLiteral( "shapes" ), false, 0, []( QgsLayout * layout )->QgsLayoutItem*
7576
{
7677
std::unique_ptr< QgsLayoutItemShape > shape = qgis::make_unique< QgsLayoutItemShape >( layout );
7778
shape->setShapeType( QgsLayoutItemShape::Triangle );
7879
return shape.release();
7980
} ) );
8081

81-
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPolygon, QObject::tr( "Polygon" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolygon.svg" ) ),
82-
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
82+
83+
std::unique_ptr< QgsLayoutItemGuiMetadata > polygonMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata >(
84+
QgsLayoutItemRegistry::LayoutPolygon, QObject::tr( "Polygon" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolygon.svg" ) ),
85+
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
8386
{
8487
return nullptr;
8588
//return new QgsLayoutMapWidget( qobject_cast< QgsLayoutItemMap * >( item ) );
86-
}, createRubberBand, QStringLiteral( "nodes" ) ) );
87-
registry->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPolyline, QObject::tr( "Polyline" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolyline.svg" ) ),
88-
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
89+
}, createRubberBand, QStringLiteral( "nodes" ), true );
90+
polygonMetadata->setNodeRubberBandCreationFunction( []( QgsLayoutView * )->QGraphicsPolygonItem*
91+
{
92+
std::unique_ptr< QGraphicsPolygonItem > band = qgis::make_unique< QGraphicsPolygonItem >();
93+
band->setBrush( Qt::NoBrush );
94+
band->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
95+
band->setZValue( QgsLayout::ZViewTool );
96+
return band.release();
97+
} );
98+
registry->addLayoutItemGuiMetadata( polygonMetadata.release() );
99+
100+
std::unique_ptr< QgsLayoutItemGuiMetadata > polylineMetadata = qgis::make_unique< QgsLayoutItemGuiMetadata>(
101+
QgsLayoutItemRegistry::LayoutPolyline, QObject::tr( "Polyline" ), QgsApplication::getThemeIcon( QStringLiteral( "/mActionAddPolyline.svg" ) ),
102+
[ = ]( QgsLayoutItem * item )->QgsLayoutItemBaseWidget *
89103
{
90104
return nullptr;
91105
//return new QgsLayoutMapWidget( qobject_cast< QgsLayoutItemMap * >( item ) );
92-
}, createRubberBand, QStringLiteral( "nodes" ) ) );
106+
}, createRubberBand, QStringLiteral( "nodes" ), true );
107+
polylineMetadata->setNodeRubberBandCreationFunction( []( QgsLayoutView * )->QGraphicsPathItem*
108+
{
109+
std::unique_ptr< QGraphicsPathItem > band = qgis::make_unique< QGraphicsPathItem >();
110+
band->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
111+
band->setZValue( QgsLayout::ZViewTool );
112+
return band.release();
113+
} );
114+
registry->addLayoutItemGuiMetadata( polylineMetadata.release() );
93115
}

src/app/layout/qgslayoutdesignerdialog.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "qgslayoutappmenuprovider.h"
2525
#include "qgslayoutview.h"
2626
#include "qgslayoutviewtooladditem.h"
27+
#include "qgslayoutviewtooladdnodeitem.h"
2728
#include "qgslayoutviewtoolpan.h"
2829
#include "qgslayoutviewtoolzoom.h"
2930
#include "qgslayoutviewtoolselect.h"
@@ -227,6 +228,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
227228
mActionsToolbar->addWidget( resizeToolButton );
228229

229230
mAddItemTool = new QgsLayoutViewToolAddItem( mView );
231+
mAddNodeItemTool = new QgsLayoutViewToolAddNodeItem( mView );
230232
mPanTool = new QgsLayoutViewToolPan( mView );
231233
mPanTool->setAction( mActionPan );
232234
mToolsActionGroup->addAction( mActionPan );
@@ -241,6 +243,7 @@ QgsLayoutDesignerDialog::QgsLayoutDesignerDialog( QWidget *parent, Qt::WindowFla
241243
connect( mActionSelectMoveItem, &QAction::triggered, mSelectTool, [ = ] { mView->setTool( mSelectTool ); } );
242244
// after creating an item with the add item tool, switch immediately to select tool
243245
connect( mAddItemTool, &QgsLayoutViewToolAddItem::createdItem, this, [ = ] { mView->setTool( mSelectTool ); } );
246+
connect( mAddNodeItemTool, &QgsLayoutViewToolAddNodeItem::createdItem, this, [ = ] { mView->setTool( mSelectTool ); } );
244247

245248
//Ctrl+= should also trigger zoom in
246249
QShortcut *ctrlEquals = new QShortcut( QKeySequence( QStringLiteral( "Ctrl+=" ) ), this );
@@ -847,6 +850,7 @@ void QgsLayoutDesignerDialog::itemTypeAdded( int id )
847850

848851
QString name = QgsGui::layoutItemGuiRegistry()->itemMetadata( id )->visibleName();
849852
QString groupId = QgsGui::layoutItemGuiRegistry()->itemMetadata( id )->groupId();
853+
bool nodeBased = QgsGui::layoutItemGuiRegistry()->itemMetadata( id )->isNodeBased();
850854
QToolButton *groupButton = nullptr;
851855
QMenu *itemSubmenu = nullptr;
852856
if ( !groupId.isEmpty() )
@@ -905,9 +909,9 @@ void QgsLayoutDesignerDialog::itemTypeAdded( int id )
905909
else
906910
mToolsToolbar->addAction( action );
907911

908-
connect( action, &QAction::triggered, this, [this, id]()
912+
connect( action, &QAction::triggered, this, [this, id, nodeBased]()
909913
{
910-
activateNewItemCreationTool( id );
914+
activateNewItemCreationTool( id, nodeBased );
911915
} );
912916
}
913917

@@ -1084,12 +1088,19 @@ void QgsLayoutDesignerDialog::restoreWindowState()
10841088
}
10851089
}
10861090

1087-
void QgsLayoutDesignerDialog::activateNewItemCreationTool( int id )
1091+
void QgsLayoutDesignerDialog::activateNewItemCreationTool( int id, bool nodeBasedItem )
10881092
{
1089-
mAddItemTool->setItemMetadataId( id );
1090-
if ( mView )
1093+
if ( !nodeBasedItem )
1094+
{
1095+
mAddItemTool->setItemMetadataId( id );
1096+
if ( mView )
1097+
mView->setTool( mAddItemTool );
1098+
}
1099+
else
10911100
{
1092-
mView->setTool( mAddItemTool );
1101+
mAddNodeItemTool->setItemMetadataId( id );
1102+
if ( mView )
1103+
mView->setTool( mAddNodeItemTool );
10931104
}
10941105
}
10951106

@@ -1123,7 +1134,7 @@ void QgsLayoutDesignerDialog::initializeRegistry()
11231134
return new QgsLayoutPagePropertiesWidget( nullptr, item );
11241135
} );
11251136

1126-
QgsGui::layoutItemGuiRegistry()->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPage, QObject::tr( "Page" ), QIcon(), createPageWidget, nullptr, QString(), QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools ) );
1137+
QgsGui::layoutItemGuiRegistry()->addLayoutItemGuiMetadata( new QgsLayoutItemGuiMetadata( QgsLayoutItemRegistry::LayoutPage, QObject::tr( "Page" ), QIcon(), createPageWidget, nullptr, QString(), false, QgsLayoutItemAbstractGuiMetadata::FlagNoCreationTools ) );
11271138

11281139
}
11291140

src/app/layout/qgslayoutdesignerdialog.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
class QgsLayoutDesignerDialog;
2525
class QgsLayoutView;
2626
class QgsLayoutViewToolAddItem;
27+
class QgsLayoutViewToolAddNodeItem;
2728
class QgsLayoutViewToolPan;
2829
class QgsLayoutViewToolZoom;
2930
class QgsLayoutViewToolSelect;
@@ -270,6 +271,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
270271
static QList<double> sStatusZoomLevelsList;
271272

272273
QgsLayoutViewToolAddItem *mAddItemTool = nullptr;
274+
QgsLayoutViewToolAddNodeItem *mAddNodeItemTool = nullptr;
273275
QgsLayoutViewToolPan *mPanTool = nullptr;
274276
QgsLayoutViewToolZoom *mZoomTool = nullptr;
275277
QgsLayoutViewToolSelect *mSelectTool = nullptr;
@@ -313,7 +315,7 @@ class QgsLayoutDesignerDialog: public QMainWindow, private Ui::QgsLayoutDesigner
313315
void restoreWindowState();
314316

315317
//! Switch to new item creation tool, for a new item of the specified \a id.
316-
void activateNewItemCreationTool( int id );
318+
void activateNewItemCreationTool( int id, bool nodeBasedItem );
317319

318320
void createLayoutPropertiesWidget();
319321

src/core/layout/qgslayout.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
5151
ZGuide = 9998, //!< Z-value for page guides
5252
ZSmartGuide = 9999, //!< Z-value for smart (item bounds based) guides
5353
ZMouseHandles = 10000, //!< Z-value for mouse handles
54-
ZMapTool = 10001, //!< Z-value for temporary map tool items
54+
ZViewTool = 10001, //!< Z-value for temporary view tool items
5555
ZSnapIndicator = 10002, //!< Z-value for snapping indicator
5656
};
5757

0 commit comments

Comments
 (0)