Create rubber band classes for layout views

c++ QgsLayoutItem metadata classes can directly register
a function which creates a QgsLayoutViewRubberBand for the item
subclass.

Python code cannot utilise this shortcut (due to inaccessibility
of forward declared gui classes from core Python classes), so
there's a separate gui registry utility class added for registering
prototypes for rubber bands for already registered item types.
This commit is contained in:
Nyall Dawson 2017-07-04 17:15:07 +10:00
parent 4ebea75e6a
commit 3843b5ef37
14 changed files with 751 additions and 96 deletions

View File

@ -61,6 +61,7 @@ class QgsLayoutItemAbstractMetadata
:rtype: QWidget
%End
virtual void resolvePaths( QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving );
%Docstring
Resolve paths in the item's ``properties`` (if there are any paths).
@ -78,6 +79,7 @@ class QgsLayoutItemAbstractMetadata
class QgsLayoutItemRegistry : QObject
{
%Docstring
@ -141,6 +143,7 @@ class QgsLayoutItemRegistry : QObject
:rtype: QWidget
%End
void resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const;
%Docstring
Resolve paths in properties of a particular symbol layer.

View File

@ -42,7 +42,9 @@
%Include editorwidgets/core/qgseditorwidgetautoconf.sip
%Include layertree/qgslayertreeembeddedconfigwidget.sip
%Include layertree/qgslayertreeembeddedwidgetregistry.sip
%Include layout/qgslayoutitemregistryguiutils.sip
%Include layout/qgslayoutviewmouseevent.sip
%Include layout/qgslayoutviewrubberband.sip
%Include locator/qgslocatorcontext.sip
%Include raster/qgsrasterrendererwidget.sip
%Include symbology-ng/qgssymbolwidgetcontext.sip

View File

@ -0,0 +1,46 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutitemregistryguiutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutItemRegistryGuiUtils
{
%Docstring
A group of static utilities for working with the gui based portions of
QgsLayoutItemRegistry.
This class is designed to allow Python item subclasses to override the
default GUI based QgsLayoutItemAbstractMetadata methods, which
cannot be directly overridden from Python subclasses.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutitemregistryguiutils.h"
%End
public:
static void setItemRubberBandPrototype( int type, QgsLayoutViewRubberBand *prototype /Transfer/ );
%Docstring
Sets a ``prototype`` for the rubber bands for the layout item with specified ``type``.
Python subclasses of QgsLayoutItem must call this method to register their prototypes,
as the usual c++ QgsLayoutItemAbstractMetadata are not accessible via the Python bindings.
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutitemregistryguiutils.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -0,0 +1,157 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutviewrubberband.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutViewRubberBand
{
%Docstring
QgsLayoutViewRubberBand is an abstract base class for temporary rubber band items
in various shapes, for use within QgsLayoutView widgets.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutviewrubberband.h"
%End
%ConvertToSubClassCode
if ( dynamic_cast<QgsLayoutViewMouseEvent *>( sipCpp ) )
sipType = sipType_QgsLayoutViewMouseEvent;
else
sipType = 0;
%End
public:
QgsLayoutViewRubberBand( QgsLayoutView *view );
%Docstring
Constructor for QgsLayoutViewRubberBand.
%End
virtual ~QgsLayoutViewRubberBand();
virtual QgsLayoutViewRubberBand *create( QgsLayoutView *view ) const = 0 /Factory/;
%Docstring
Creates a new instance of the QgsLayoutViewRubberBand subclass.
:rtype: QgsLayoutViewRubberBand
%End
virtual void start( QPointF position, Qt::KeyboardModifiers modifiers ) = 0;
%Docstring
Called when a rubber band should be created at the specified
starting ``position`` (in layout coordinate space).
%End
virtual void update( QPointF position, Qt::KeyboardModifiers modifiers ) = 0;
%Docstring
Called when a rubber band should be updated to reflect a temporary
ending ``position`` (in layout coordinate space).
%End
virtual void finish( QPointF position, Qt::KeyboardModifiers modifiers ) = 0;
%Docstring
Called when a rubber band use has finished and the rubber
band is no longer required.
%End
QgsLayoutView *view() const;
%Docstring
Returns the view associated with the rubber band.
.. seealso:: layout()
:rtype: QgsLayoutView
%End
QgsLayout *layout() const;
%Docstring
Returns the layout associated with the rubber band.
.. seealso:: view()
:rtype: QgsLayout
%End
protected:
QRectF updateRect( QPointF start, QPointF position, bool constrainSquare, bool fromCenter );
%Docstring
Calculates an updated bounding box rectangle from a original ``start`` position
and new ``position``. If ``constrainSquare`` is true then the bounding box will be
forced to a square shape. If ``fromCenter`` is true then the original ``start``
position will form the center point of the returned rectangle.
:rtype: QRectF
%End
};
class QgsLayoutViewRectangularRubberBand : QgsLayoutViewRubberBand
{
%Docstring
QgsLayoutViewRectangularRubberBand is rectangular rubber band for use within QgsLayoutView widgets.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutviewrubberband.h"
%End
public:
QgsLayoutViewRectangularRubberBand( QgsLayoutView *view );
%Docstring
Constructor for QgsLayoutViewRectangularRubberBand.
%End
virtual QgsLayoutViewRectangularRubberBand *create( QgsLayoutView *view ) const /Factory/;
~QgsLayoutViewRectangularRubberBand();
virtual void start( QPointF position, Qt::KeyboardModifiers modifiers );
virtual void update( QPointF position, Qt::KeyboardModifiers modifiers );
virtual void finish( QPointF, Qt::KeyboardModifiers );
};
class QgsLayoutViewEllipticalRubberBand : QgsLayoutViewRubberBand
{
%Docstring
QgsLayoutViewEllipseRubberBand is elliptical rubber band for use within QgsLayoutView widgets.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutviewrubberband.h"
%End
public:
QgsLayoutViewEllipticalRubberBand( QgsLayoutView *view );
%Docstring
Constructor for QgsLayoutViewEllipticalRubberBand.
%End
virtual QgsLayoutViewEllipticalRubberBand *create( QgsLayoutView *view ) const /Factory/;
~QgsLayoutViewEllipticalRubberBand();
virtual void start( QPointF position, Qt::KeyboardModifiers modifiers );
virtual void update( QPointF position, Qt::KeyboardModifiers modifiers );
virtual void finish( QPointF, Qt::KeyboardModifiers );
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/gui/layout/qgslayoutviewrubberband.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -8,7 +8,6 @@
class QgsLayoutViewToolAddItem : QgsLayoutViewTool
{
%Docstring

View File

@ -58,6 +58,17 @@ QWidget *QgsLayoutItemRegistry::createItemWidget( int type ) const
return mMetadata[type]->createItemWidget();
}
QgsLayoutViewRubberBand *QgsLayoutItemRegistry::createItemRubberBand( int type, QgsLayoutView *view ) const
{
if ( mRubberBandFunctions.contains( type ) )
return mRubberBandFunctions.value( type )( view );
if ( !mMetadata.contains( type ) )
return nullptr;
return mMetadata[type]->createRubberBand( view );
}
void QgsLayoutItemRegistry::resolvePaths( int type, QVariantMap &properties, const QgsPathResolver &pathResolver, bool saving ) const
{
if ( !mMetadata.contains( type ) )

View File

@ -25,7 +25,9 @@
#include <functional>
class QgsLayout;
class QgsLayoutView;
class QgsLayoutItem;
class QgsLayoutViewRubberBand;
/**
* \ingroup core
@ -73,6 +75,14 @@ class CORE_EXPORT QgsLayoutItemAbstractMetadata
*/
virtual QWidget *createItemWidget() SIP_FACTORY { return nullptr; }
/**
* Creates a rubber band for use when creating layout items of this type. Can return nullptr if no rubber band
* should be created.
* \note not available in Python bindings. Python item subclasses must use QgsLayoutItemRegistryGuiUtils
* to override the default rubber band creation function.
*/
virtual QgsLayoutViewRubberBand *createRubberBand( QgsLayoutView *view ) SIP_SKIP { Q_UNUSED( view ); return nullptr; }
/**
* Resolve paths in the item's \a properties (if there are any paths).
* When \a saving is true, paths are converted from absolute to relative,
@ -99,6 +109,9 @@ typedef std::function<QgsLayoutItem *( QgsLayout *, const QVariantMap & )> QgsLa
//! Layout item configuration widget creation function
typedef std::function<QWidget *()> QgsLayoutItemWidgetFunc SIP_SKIP;
//! Layout rubber band creation function
typedef std::function<QgsLayoutViewRubberBand *( QgsLayoutView * )> QgsLayoutItemRubberBandFunc SIP_SKIP;
//! Layout item path resolver function
typedef std::function<void( QVariantMap &, const QgsPathResolver &, bool )> QgsLayoutItemPathResolverFunc SIP_SKIP;
@ -152,6 +165,18 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
*/
void setWidgetFunction( QgsLayoutItemWidgetFunc function ) { mWidgetFunc = function; }
/**
* Returns the classes' rubber band creation function.
* \see setRubberBandCreationFunction()
*/
QgsLayoutItemRubberBandFunc rubberBandCreationFunction() const { return mRubberBandFunc; }
/**
* Sets the classes' rubber band creation \a function.
* \see rubberBandCreationFunction()
*/
void setRubberBandCreationFunction( QgsLayoutItemRubberBandFunc function ) { mRubberBandFunc = function; }
QIcon icon() const override { return mIcon.isNull() ? QgsLayoutItemAbstractMetadata::icon() : mIcon; }
QgsLayoutItem *createItem( QgsLayout *layout, const QVariantMap &properties ) override { return mCreateFunc ? mCreateFunc( layout, properties ) : nullptr; }
QWidget *createItemWidget() override { return mWidgetFunc ? mWidgetFunc() : nullptr; }
@ -165,6 +190,7 @@ class CORE_EXPORT QgsLayoutItemMetadata : public QgsLayoutItemAbstractMetadata
QIcon mIcon;
QgsLayoutItemCreateFunc mCreateFunc = nullptr;
QgsLayoutItemWidgetFunc mWidgetFunc = nullptr;
QgsLayoutItemRubberBandFunc mRubberBandFunc = nullptr;
QgsLayoutItemPathResolverFunc mPathResolverFunc = nullptr;
};
@ -237,6 +263,12 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
*/
QWidget *createItemWidget( int type ) const SIP_FACTORY;
/**
* Creates a new rubber band item for the specified item \a type and destination \a view.
* \note not available from Python bindings
*/
QgsLayoutViewRubberBand *createItemRubberBand( int type, QgsLayoutView *view ) const SIP_SKIP;
/**
* Resolve paths in properties of a particular symbol layer.
* This normally means converting relative paths to absolute paths when loading
@ -264,6 +296,10 @@ class CORE_EXPORT QgsLayoutItemRegistry : public QObject
QMap<int, QgsLayoutItemAbstractMetadata *> mMetadata;
QMap<int, QgsLayoutItemRubberBandFunc > mRubberBandFunctions;
friend class QgsLayoutItemRegistryGuiUtils;
};
#endif //QGSLAYOUTITEMREGISTRY_H

View File

@ -158,8 +158,10 @@ SET(QGIS_GUI_SRCS
layertree/qgslayertreeview.cpp
layertree/qgslayertreeviewdefaultactions.cpp
layout/qgslayoutitemregistryguiutils.cpp
layout/qgslayoutview.cpp
layout/qgslayoutviewmouseevent.cpp
layout/qgslayoutviewrubberband.cpp
layout/qgslayoutviewtool.cpp
layout/qgslayoutviewtooladditem.cpp
@ -721,7 +723,9 @@ SET(QGIS_GUI_HDRS
layertree/qgslayertreeembeddedconfigwidget.h
layertree/qgslayertreeembeddedwidgetregistry.h
layout/qgslayoutitemregistryguiutils.h
layout/qgslayoutviewmouseevent.h
layout/qgslayoutviewrubberband.h
locator/qgslocatorcontext.h

View File

@ -0,0 +1,27 @@
/***************************************************************************
qgslayoutitemregistryguiutils.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. *
* *
***************************************************************************/
#include "qgslayoutitemregistryguiutils.h"
#include "qgslayoutviewrubberband.h"
void QgsLayoutItemRegistryGuiUtils::setItemRubberBandPrototype( int type, QgsLayoutViewRubberBand *prototype )
{
auto create = [prototype]( QgsLayoutView * view )->QgsLayoutViewRubberBand *
{
return prototype->create( view );
};
QgsApplication::layoutItemRegistry()->mRubberBandFunctions.insert( type, create );
}

View File

@ -0,0 +1,50 @@
/***************************************************************************
qgslayoutitemregistryguiutils.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 QGSLAYOUTITEMREGISTRYGUIUTILS_H
#define QGSLAYOUTITEMREGISTRYGUIUTILS_H
#include "qgis_gui.h"
#include "qgis_sip.h"
#include "qgslayoutitemregistry.h"
class QgsLayoutViewRubberBand;
/**
* \ingroup gui
* A group of static utilities for working with the gui based portions of
* QgsLayoutItemRegistry.
*
* This class is designed to allow Python item subclasses to override the
* default GUI based QgsLayoutItemAbstractMetadata methods, which
* cannot be directly overridden from Python subclasses.
*
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutItemRegistryGuiUtils
{
public:
/**
* Sets a \a prototype for the rubber bands for the layout item with specified \a type.
* Python subclasses of QgsLayoutItem must call this method to register their prototypes,
* as the usual c++ QgsLayoutItemAbstractMetadata are not accessible via the Python bindings.
*/
static void setItemRubberBandPrototype( int type, QgsLayoutViewRubberBand *prototype SIP_TRANSFER );
};
#endif // QGSLAYOUTITEMREGISTRYGUIUTILS_H

View File

@ -0,0 +1,222 @@
/***************************************************************************
qgslayoutviewrubberband.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 "qgslayoutviewrubberband.h"
#include "qgslayout.h"
#include "qgslayoutview.h"
#include <QGraphicsRectItem>
#include <QGraphicsEllipseItem>
QgsLayoutViewRubberBand::QgsLayoutViewRubberBand( QgsLayoutView *view )
: mView( view )
{
}
QgsLayoutView *QgsLayoutViewRubberBand::view() const
{
return mView;
}
QgsLayout *QgsLayoutViewRubberBand::layout() const
{
return mView->currentLayout();
}
QRectF QgsLayoutViewRubberBand::updateRect( QPointF start, QPointF position, bool constrainSquare, bool fromCenter )
{
double x = 0;
double y = 0;
double width = 0;
double height = 0;
double dx = position.x() - start.x();
double dy = position.y() - start.y();
if ( constrainSquare )
{
if ( fabs( dx ) > fabs( dy ) )
{
width = fabs( dx );
height = width;
}
else
{
height = fabs( dy );
width = height;
}
x = start.x() - ( ( dx < 0 ) ? width : 0 );
y = start.y() - ( ( dy < 0 ) ? height : 0 );
}
else
{
//not constraining
if ( dx < 0 )
{
x = position.x();
width = -dx;
}
else
{
x = start.x();
width = dx;
}
if ( dy < 0 )
{
y = position.y();
height = -dy;
}
else
{
y = start.y();
height = dy;
}
}
if ( fromCenter )
{
x = start.x() - width;
y = start.y() - height;
width *= 2.0;
height *= 2.0;
}
return QRectF( x, y, width, height );
}
QgsLayoutViewRectangularRubberBand::QgsLayoutViewRectangularRubberBand( QgsLayoutView *view )
: QgsLayoutViewRubberBand( view )
{
}
QgsLayoutViewRectangularRubberBand *QgsLayoutViewRectangularRubberBand::create( QgsLayoutView *view ) const
{
return new QgsLayoutViewRectangularRubberBand( view );
}
QgsLayoutViewRectangularRubberBand::~QgsLayoutViewRectangularRubberBand()
{
if ( mRubberBandItem )
{
layout()->removeItem( mRubberBandItem );
delete mRubberBandItem;
}
}
void QgsLayoutViewRectangularRubberBand::start( QPointF position, Qt::KeyboardModifiers )
{
QTransform t;
mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
mRubberBandItem->setBrush( Qt::NoBrush );
mRubberBandItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
mRubberBandStartPos = position;
t.translate( position.x(), position.y() );
mRubberBandItem->setTransform( t );
mRubberBandItem->setZValue( QgsLayout::ZMapTool );
layout()->addItem( mRubberBandItem );
layout()->update();
}
void QgsLayoutViewRectangularRubberBand::update( QPointF position, Qt::KeyboardModifiers modifiers )
{
if ( !mRubberBandItem )
{
return;
}
bool constrainSquare = modifiers & Qt::ShiftModifier;
bool fromCenter = modifiers & Qt::AltModifier;
QRectF newRect = updateRect( mRubberBandStartPos, position, constrainSquare, fromCenter );
mRubberBandItem->setRect( 0, 0, newRect.width(), newRect.height() );
QTransform t;
t.translate( newRect.x(), newRect.y() );
mRubberBandItem->setTransform( t );
}
void QgsLayoutViewRectangularRubberBand::finish( QPointF, Qt::KeyboardModifiers )
{
if ( mRubberBandItem )
{
layout()->removeItem( mRubberBandItem );
delete mRubberBandItem;
mRubberBandItem = nullptr;
}
}
QgsLayoutViewEllipticalRubberBand::QgsLayoutViewEllipticalRubberBand( QgsLayoutView *view )
: QgsLayoutViewRubberBand( view )
{
}
QgsLayoutViewEllipticalRubberBand *QgsLayoutViewEllipticalRubberBand::create( QgsLayoutView *view ) const
{
return new QgsLayoutViewEllipticalRubberBand( view );
}
QgsLayoutViewEllipticalRubberBand::~QgsLayoutViewEllipticalRubberBand()
{
if ( mRubberBandItem )
{
layout()->removeItem( mRubberBandItem );
delete mRubberBandItem;
}
}
void QgsLayoutViewEllipticalRubberBand::start( QPointF position, Qt::KeyboardModifiers )
{
QTransform t;
mRubberBandItem = new QGraphicsEllipseItem( 0, 0, 0, 0 );
mRubberBandItem->setBrush( Qt::NoBrush );
mRubberBandItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
mRubberBandStartPos = position;
t.translate( position.x(), position.y() );
mRubberBandItem->setTransform( t );
mRubberBandItem->setZValue( QgsLayout::ZMapTool );
layout()->addItem( mRubberBandItem );
layout()->update();
}
void QgsLayoutViewEllipticalRubberBand::update( QPointF position, Qt::KeyboardModifiers modifiers )
{
if ( !mRubberBandItem )
{
return;
}
bool constrainSquare = modifiers & Qt::ShiftModifier;
bool fromCenter = modifiers & Qt::AltModifier;
QRectF newRect = updateRect( mRubberBandStartPos, position, constrainSquare, fromCenter );
mRubberBandItem->setRect( 0, 0, newRect.width(), newRect.height() );
QTransform t;
t.translate( newRect.x(), newRect.y() );
mRubberBandItem->setTransform( t );
}
void QgsLayoutViewEllipticalRubberBand::finish( QPointF, Qt::KeyboardModifiers )
{
if ( mRubberBandItem )
{
layout()->removeItem( mRubberBandItem );
delete mRubberBandItem;
mRubberBandItem = nullptr;
}
}

View File

@ -0,0 +1,169 @@
/***************************************************************************
qgslayoutviewrubberband.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 QGSLAYOUTVIEWRUBBERBAND_H
#define QGSLAYOUTVIEWRUBBERBAND_H
#include <QMouseEvent>
#include "qgis_gui.h"
#include "qgis_sip.h"
class QgsLayoutView;
class QGraphicsRectItem;
class QGraphicsEllipseItem;
class QgsLayout;
/**
* \ingroup gui
* QgsLayoutViewRubberBand is an abstract base class for temporary rubber band items
* in various shapes, for use within QgsLayoutView widgets.
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutViewRubberBand
{
#ifdef SIP_RUN
SIP_CONVERT_TO_SUBCLASS_CODE
if ( dynamic_cast<QgsLayoutViewMouseEvent *>( sipCpp ) )
sipType = sipType_QgsLayoutViewMouseEvent;
else
sipType = 0;
SIP_END
#endif
public:
/**
* Constructor for QgsLayoutViewRubberBand.
*/
QgsLayoutViewRubberBand( QgsLayoutView *view );
virtual ~QgsLayoutViewRubberBand() = default;
/**
* Creates a new instance of the QgsLayoutViewRubberBand subclass.
*/
virtual QgsLayoutViewRubberBand *create( QgsLayoutView *view ) const = 0 SIP_FACTORY;
/**
* Called when a rubber band should be created at the specified
* starting \a position (in layout coordinate space).
*/
virtual void start( QPointF position, Qt::KeyboardModifiers modifiers ) = 0;
/**
* Called when a rubber band should be updated to reflect a temporary
* ending \a position (in layout coordinate space).
*/
virtual void update( QPointF position, Qt::KeyboardModifiers modifiers ) = 0;
/**
* Called when a rubber band use has finished and the rubber
* band is no longer required.
*/
virtual void finish( QPointF position, Qt::KeyboardModifiers modifiers ) = 0;
/**
* Returns the view associated with the rubber band.
* \see layout()
*/
QgsLayoutView *view() const;
/**
* Returns the layout associated with the rubber band.
* \see view()
*/
QgsLayout *layout() const;
protected:
/**
* Calculates an updated bounding box rectangle from a original \a start position
* and new \a position. If \a constrainSquare is true then the bounding box will be
* forced to a square shape. If \a fromCenter is true then the original \a start
* position will form the center point of the returned rectangle.
*/
QRectF updateRect( QPointF start, QPointF position, bool constrainSquare, bool fromCenter );
private:
QgsLayoutView *mView = nullptr;
};
/**
* \ingroup gui
* QgsLayoutViewRectangularRubberBand is rectangular rubber band for use within QgsLayoutView widgets.
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutViewRectangularRubberBand : public QgsLayoutViewRubberBand
{
public:
/**
* Constructor for QgsLayoutViewRectangularRubberBand.
*/
QgsLayoutViewRectangularRubberBand( QgsLayoutView *view );
QgsLayoutViewRectangularRubberBand *create( QgsLayoutView *view ) const override SIP_FACTORY;
~QgsLayoutViewRectangularRubberBand();
void start( QPointF position, Qt::KeyboardModifiers modifiers ) override;
void update( QPointF position, Qt::KeyboardModifiers modifiers ) override;
void finish( QPointF, Qt::KeyboardModifiers ) override;
private:
//! Rubber band item
QGraphicsRectItem *mRubberBandItem = nullptr;
//! Start of rubber band creation
QPointF mRubberBandStartPos;
};
/**
* \ingroup gui
* QgsLayoutViewEllipseRubberBand is elliptical rubber band for use within QgsLayoutView widgets.
* \since QGIS 3.0
*/
class GUI_EXPORT QgsLayoutViewEllipticalRubberBand : public QgsLayoutViewRubberBand
{
public:
/**
* Constructor for QgsLayoutViewEllipticalRubberBand.
*/
QgsLayoutViewEllipticalRubberBand( QgsLayoutView *view );
QgsLayoutViewEllipticalRubberBand *create( QgsLayoutView *view ) const override SIP_FACTORY;
~QgsLayoutViewEllipticalRubberBand();
void start( QPointF position, Qt::KeyboardModifiers modifiers ) override;
void update( QPointF position, Qt::KeyboardModifiers modifiers ) override;
void finish( QPointF, Qt::KeyboardModifiers ) override;
private:
//! Rubber band item
QGraphicsEllipseItem *mRubberBandItem = nullptr;
//! Start of rubber band creation
QPointF mRubberBandStartPos;
};
#endif // QGSLAYOUTVIEWRUBBERBAND_H

View File

@ -21,6 +21,7 @@
#include "qgslayoutitemregistry.h"
#include "qgslayoutviewmouseevent.h"
#include "qgslogger.h"
#include "qgslayoutviewrubberband.h"
#include <QGraphicsRectItem>
#include <QPen>
#include <QBrush>
@ -40,22 +41,24 @@ void QgsLayoutViewToolAddItem::setItemType( int itemType )
void QgsLayoutViewToolAddItem::layoutPressEvent( QgsLayoutViewMouseEvent *event )
{
QTransform t;
mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
mRubberBandItem->setBrush( Qt::NoBrush );
mRubberBandItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
mMousePressStartPos = event->pos();
mRubberBandStartPos = QPointF( event->layoutPoint().x(), event->layoutPoint().y() );
t.translate( event->x(), event->y() );
mRubberBandItem->setTransform( t );
mRubberBandItem->setZValue( QgsLayout::ZMapTool );
layout()->addItem( mRubberBandItem );
layout()->update();
if ( event->button() != Qt::LeftButton )
{
return;
}
mRubberBand.reset( QgsApplication::layoutItemRegistry()->createItemRubberBand( mItemType, view() ) );
if ( mRubberBand )
{
mRubberBand->start( event->layoutPoint(), event->modifiers() );
}
}
void QgsLayoutViewToolAddItem::layoutMoveEvent( QgsLayoutViewMouseEvent *event )
{
updateRubberBandRect( event->layoutPoint(), event->modifiers() & Qt::ShiftModifier, event->modifiers() & Qt::AltModifier );
if ( mRubberBand )
{
mRubberBand->update( event->layoutPoint(), event->modifiers() );
}
}
void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *event )
@ -65,6 +68,11 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
return;
}
if ( mRubberBand )
{
mRubberBand->finish( event->layoutPoint(), event->modifiers() );
}
// click? or click-and-drag?
QPoint mousePressStopPoint = event->pos();
int diffX = mousePressStopPoint.x() - mMousePressStartPos.x();
@ -74,88 +82,12 @@ void QgsLayoutViewToolAddItem::layoutReleaseEvent( QgsLayoutViewMouseEvent *even
{
clickOnly = true;
}
Q_UNUSED( clickOnly );
if ( mRubberBandItem )
{
layout()->removeItem( mRubberBandItem );
delete mRubberBandItem;
mRubberBandItem = nullptr;
}
QgsLogger::debug( QStringLiteral( "creating new %1 item " ).arg( QgsApplication::layoutItemRegistry()->itemMetadata( mItemType )->visibleName() ) );
}
void QgsLayoutViewToolAddItem::updateRubberBandRect( QPointF pos, const bool constrainSquare, const bool fromCenter )
{
if ( !mRubberBandItem )
{
return;
}
double x = 0;
double y = 0;
double width = 0;
double height = 0;
double dx = pos.x() - mRubberBandStartPos.x();
double dy = pos.y() - mRubberBandStartPos.y();
if ( constrainSquare )
{
if ( fabs( dx ) > fabs( dy ) )
{
width = fabs( dx );
height = width;
}
else
{
height = fabs( dy );
width = height;
}
x = mRubberBandStartPos.x() - ( ( dx < 0 ) ? width : 0 );
y = mRubberBandStartPos.y() - ( ( dy < 0 ) ? height : 0 );
}
else
{
//not constraining
if ( dx < 0 )
{
x = pos.x();
width = -dx;
}
else
{
x = mRubberBandStartPos.x();
width = dx;
}
if ( dy < 0 )
{
y = pos.y();
height = -dy;
}
else
{
y = mRubberBandStartPos.y();
height = dy;
}
}
if ( fromCenter )
{
x = mRubberBandStartPos.x() - width;
y = mRubberBandStartPos.y() - height;
width *= 2.0;
height *= 2.0;
}
mRubberBandItem->setRect( 0, 0, width, height );
QTransform t;
t.translate( x, y );
mRubberBandItem->setTransform( t );
}
int QgsLayoutViewToolAddItem::itemType() const
{
return mItemType;

View File

@ -19,8 +19,8 @@
#include "qgis.h"
#include "qgis_gui.h"
#include "qgslayoutviewtool.h"
class QGraphicsRectItem;
#include "qgslayoutviewrubberband.h"
#include <memory>
/**
* \ingroup gui
@ -57,7 +57,7 @@ class GUI_EXPORT QgsLayoutViewToolAddItem : public QgsLayoutViewTool
int mItemType = 0;
//! Rubber band item
QGraphicsRectItem *mRubberBandItem = nullptr;
std::unique_ptr< QgsLayoutViewRubberBand > mRubberBand;
//! Start position for mouse press
QPoint mMousePressStartPos;
@ -65,9 +65,6 @@ class GUI_EXPORT QgsLayoutViewToolAddItem : public QgsLayoutViewTool
//! Start of rubber band creation
QPointF mRubberBandStartPos;
//! Redraws the rectangular rubber band
void updateRubberBandRect( QPointF pos, const bool constrainSquare = false, const bool fromCenter = false );
};
#endif // QGSLAYOUTVIEWTOOLADDITEM_H