Start on layout snapper

This commit is contained in:
Nyall Dawson 2017-07-24 08:12:07 +10:00
parent b42c055e97
commit 361dd312bc
13 changed files with 327 additions and 150 deletions

View File

@ -161,6 +161,7 @@
%Include layout/qgspagesizeregistry.sip
%Include layout/qgslayoutpoint.sip
%Include layout/qgslayoutsize.sip
%Include layout/qgslayoutsnapper.sip
%Include layout/qgslayoututils.sip
%Include metadata/qgslayermetadata.sip
%Include metadata/qgslayermetadatavalidator.sip

View File

@ -141,6 +141,14 @@ class QgsLayout : QGraphicsScene, QgsExpressionContextGenerator
%End
QgsLayoutSnapper &snapper();
%Docstring
Returns a reference to the layout's snapper, which stores handles layout snap grids and lines
and snapping points to the nearest matching point.
:rtype: QgsLayoutSnapper
%End
virtual QgsExpressionContext createExpressionContext() const;
%Docstring

View File

@ -30,13 +30,6 @@ class QgsLayoutContext
typedef QFlags<QgsLayoutContext::Flag> Flags;
enum GridStyle
{
GridLines,
GridDots,
GridCrosses
};
QgsLayoutContext();
void setFlags( const QgsLayoutContext::Flags flags );
@ -138,66 +131,6 @@ class QgsLayoutContext
:rtype: bool
%End
void setGridResolution( const QgsLayoutMeasurement &resolution );
%Docstring
Sets the page/snap grid ``resolution``.
.. seealso:: gridResolution()
.. seealso:: setGridOffset()
%End
QgsLayoutMeasurement gridResolution() const;
%Docstring
Returns the page/snap grid resolution.
.. seealso:: setGridResolution()
.. seealso:: gridOffset()
:rtype: QgsLayoutMeasurement
%End
void setGridOffset( const QgsLayoutPoint offset );
%Docstring
Sets the ``offset`` of the page/snap grid.
.. seealso:: gridOffset()
.. seealso:: setGridResolution()
%End
QgsLayoutPoint gridOffset() const;
%Docstring
Returns the offset of the page/snap grid.
.. seealso:: setGridOffset()
.. seealso:: gridResolution()
:rtype: QgsLayoutPoint
%End
void setGridPen( const QPen &pen );
%Docstring
Sets the ``pen`` used for drawing page/snap grids.
.. seealso:: gridPen()
.. seealso:: setGridStyle()
%End
QPen gridPen() const;
%Docstring
Returns the pen used for drawing page/snap grids.
.. seealso:: setGridPen()
.. seealso:: gridStyle()
:rtype: QPen
%End
void setGridStyle( const GridStyle style );
%Docstring
Sets the ``style`` used for drawing the page/snap grids.
.. seealso:: gridStyle()
.. seealso:: setGridPen()
%End
GridStyle gridStyle() const;
%Docstring
Returns the style used for drawing the page/snap grids.
.. seealso:: setGridStyle()
.. seealso:: gridPen()
:rtype: GridStyle
%End
};

View File

@ -0,0 +1,100 @@
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutsnapper.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/
class QgsLayoutSnapper
{
%Docstring
Manages snapping grids and preset snap lines in a layout, and handles
snapping points to the nearest grid coordinate/snap line when possible.
.. versionadded:: 3.0
%End
%TypeHeaderCode
#include "qgslayoutsnapper.h"
%End
public:
enum GridStyle
{
GridLines,
GridDots,
GridCrosses
};
QgsLayoutSnapper();
void setGridResolution( const QgsLayoutMeasurement &resolution );
%Docstring
Sets the page/snap grid ``resolution``.
.. seealso:: gridResolution()
.. seealso:: setGridOffset()
%End
QgsLayoutMeasurement gridResolution() const;
%Docstring
Returns the page/snap grid resolution.
.. seealso:: setGridResolution()
.. seealso:: gridOffset()
:rtype: QgsLayoutMeasurement
%End
void setGridOffset( const QgsLayoutPoint offset );
%Docstring
Sets the ``offset`` of the page/snap grid.
.. seealso:: gridOffset()
.. seealso:: setGridResolution()
%End
QgsLayoutPoint gridOffset() const;
%Docstring
Returns the offset of the page/snap grid.
.. seealso:: setGridOffset()
.. seealso:: gridResolution()
:rtype: QgsLayoutPoint
%End
void setGridPen( const QPen &pen );
%Docstring
Sets the ``pen`` used for drawing page/snap grids.
.. seealso:: gridPen()
.. seealso:: setGridStyle()
%End
QPen gridPen() const;
%Docstring
Returns the pen used for drawing page/snap grids.
.. seealso:: setGridPen()
.. seealso:: gridStyle()
:rtype: QPen
%End
void setGridStyle( const GridStyle style );
%Docstring
Sets the ``style`` used for drawing the page/snap grids.
.. seealso:: gridStyle()
.. seealso:: setGridPen()
%End
GridStyle gridStyle() const;
%Docstring
Returns the style used for drawing the page/snap grids.
.. seealso:: setGridStyle()
.. seealso:: gridPen()
:rtype: GridStyle
%End
};
/************************************************************************
* This file has been generated automatically from *
* *
* src/core/layout/qgslayoutsnapper.h *
* *
* Do not edit manually ! Edit header and run scripts/sipify.pl again *
************************************************************************/

View File

@ -362,6 +362,7 @@ SET(QGIS_CORE_SRCS
layout/qgslayoutmeasurementconverter.cpp
layout/qgslayoutobject.cpp
layout/qgslayoutpagecollection.cpp
layout/qgslayoutsnapper.cpp
layout/qgslayoututils.cpp
layout/qgspagesizeregistry.cpp
layout/qgslayoutpoint.cpp
@ -940,6 +941,7 @@ SET(QGIS_CORE_HDRS
layout/qgspagesizeregistry.h
layout/qgslayoutpoint.h
layout/qgslayoutsize.h
layout/qgslayoutsnapper.h
layout/qgslayoututils.h
metadata/qgslayermetadata.h

View File

@ -19,6 +19,7 @@
#include "qgis_core.h"
#include <QGraphicsScene>
#include "qgslayoutcontext.h"
#include "qgslayoutsnapper.h"
#include "qgsexpressioncontextgenerator.h"
#include "qgslayoutpagecollection.h"
@ -154,6 +155,18 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
*/
SIP_SKIP const QgsLayoutContext &context() const { return mContext; }
/**
* Returns a reference to the layout's snapper, which stores handles layout snap grids and lines
* and snapping points to the nearest matching point.
*/
QgsLayoutSnapper &snapper() { return mSnapper; }
/**
* Returns a reference to the layout's snapper, which stores handles layout snap grids and lines
* and snapping points to the nearest matching point.
*/
SIP_SKIP const QgsLayoutSnapper &snapper() const { return mSnapper; }
/**
* Creates an expression context relating to the layout's current state. The context includes
* scopes for global, project, layout and layout context properties.
@ -262,6 +275,7 @@ class CORE_EXPORT QgsLayout : public QGraphicsScene, public QgsExpressionContext
QgsUnitTypes::LayoutUnit mUnits = QgsUnitTypes::LayoutMillimeters;
QgsLayoutContext mContext;
QgsLayoutSnapper mSnapper;
std::unique_ptr< QgsLayoutPageCollection > mPageCollection;

View File

@ -20,11 +20,7 @@
QgsLayoutContext::QgsLayoutContext()
: mFlags( FlagAntialiasing | FlagUseAdvancedEffects )
, mGridResolution( QgsLayoutMeasurement( 10 ) )
{
mGridPen = QPen( QColor( 190, 190, 190, 100 ), 0 );
mGridPen.setCosmetic( true );
}
{}
void QgsLayoutContext::setFlags( const QgsLayoutContext::Flags flags )
{

View File

@ -46,14 +46,6 @@ class CORE_EXPORT QgsLayoutContext
};
Q_DECLARE_FLAGS( Flags, Flag )
//! Style for drawing the page/snapping grid
enum GridStyle
{
GridLines, //! Solid lines
GridDots, //! Dots
GridCrosses //! Crosses
};
QgsLayoutContext();
/**
@ -152,62 +144,6 @@ class CORE_EXPORT QgsLayoutContext
*/
bool gridVisible() const;
/**
* Sets the page/snap grid \a resolution.
* \see gridResolution()
* \see setGridOffset()
*/
void setGridResolution( const QgsLayoutMeasurement &resolution ) { mGridResolution = resolution; }
/**
* Returns the page/snap grid resolution.
* \see setGridResolution()
* \see gridOffset()
*/
QgsLayoutMeasurement gridResolution() const { return mGridResolution;}
/**
* Sets the \a offset of the page/snap grid.
* \see gridOffset()
* \see setGridResolution()
*/
void setGridOffset( const QgsLayoutPoint offset ) { mGridOffset = offset; }
/**
* Returns the offset of the page/snap grid.
* \see setGridOffset()
* \see gridResolution()
*/
QgsLayoutPoint gridOffset() const { return mGridOffset; }
/**
* Sets the \a pen used for drawing page/snap grids.
* \see gridPen()
* \see setGridStyle()
*/
void setGridPen( const QPen &pen ) { mGridPen = pen; }
/**
* Returns the pen used for drawing page/snap grids.
* \see setGridPen()
* \see gridStyle()
*/
QPen gridPen() const { return mGridPen; }
/**
* Sets the \a style used for drawing the page/snap grids.
* \see gridStyle()
* \see setGridPen()
*/
void setGridStyle( const GridStyle style ) { mGridStyle = style; }
/**
* Returns the style used for drawing the page/snap grids.
* \see setGridStyle()
* \see gridPen()
*/
GridStyle gridStyle() const { return mGridStyle; }
private:
Flags mFlags = 0;
@ -217,10 +153,6 @@ class CORE_EXPORT QgsLayoutContext
QgsLayoutMeasurementConverter mMeasurementConverter;
QgsLayoutMeasurement mGridResolution;
QgsLayoutPoint mGridOffset;
QPen mGridPen;
GridStyle mGridStyle = GridLines;
};

View File

@ -206,12 +206,13 @@ void QgsLayoutItemPageGrid::paint( QPainter *painter, const QStyleOptionGraphics
return;
const QgsLayoutContext &context = mLayout->context();
const QgsLayoutSnapper &snapper = mLayout->snapper();
if ( !context.gridVisible() || context.gridResolution().length() <= 0 )
if ( !context.gridVisible() || snapper.gridResolution().length() <= 0 )
return;
QPointF gridOffset = mLayout->convertToLayoutUnits( context.gridOffset() );
double gridResolution = mLayout->convertToLayoutUnits( context.gridResolution() );
QPointF gridOffset = mLayout->convertToLayoutUnits( snapper.gridOffset() );
double gridResolution = mLayout->convertToLayoutUnits( snapper.gridResolution() );
int gridMultiplyX = static_cast< int >( gridOffset.x() / gridResolution );
int gridMultiplyY = static_cast< int >( gridOffset.y() / gridResolution );
double currentXCoord = gridOffset.x() - gridMultiplyX * gridResolution;
@ -222,11 +223,11 @@ void QgsLayoutItemPageGrid::paint( QPainter *painter, const QStyleOptionGraphics
//turn of antialiasing so grid is nice and sharp
painter->setRenderHint( QPainter::Antialiasing, false );
switch ( context.gridStyle() )
switch ( snapper.gridStyle() )
{
case QgsLayoutContext::GridLines:
case QgsLayoutSnapper::GridLines:
{
painter->setPen( context.gridPen() );
painter->setPen( snapper.gridPen() );
//draw vertical lines
for ( ; currentXCoord <= rect().width(); currentXCoord += gridResolution )
@ -243,14 +244,14 @@ void QgsLayoutItemPageGrid::paint( QPainter *painter, const QStyleOptionGraphics
break;
}
case QgsLayoutContext::GridDots:
case QgsLayoutContext::GridCrosses:
case QgsLayoutSnapper::GridDots:
case QgsLayoutSnapper::GridCrosses:
{
QPen gridPen = context.gridPen();
QPen gridPen = snapper.gridPen();
painter->setPen( gridPen );
painter->setBrush( QBrush( gridPen.color() ) );
double halfCrossLength = 1;
if ( context.gridStyle() == QgsLayoutContext::GridDots )
if ( snapper.gridStyle() == QgsLayoutSnapper::GridDots )
{
//dots are actually drawn as tiny crosses a few pixels across
//set halfCrossLength to equivalent of 1 pixel

View File

@ -0,0 +1,24 @@
/***************************************************************************
qgslayoutsnapper.cpp
--------------------
begin : July 2017
copyright : (C) 2017 by 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 "qgslayoutsnapper.h"
QgsLayoutSnapper::QgsLayoutSnapper()
: mGridResolution( QgsLayoutMeasurement( 10 ) )
{
mGridPen = QPen( QColor( 190, 190, 190, 100 ), 0 );
mGridPen.setCosmetic( true );
}

View File

@ -0,0 +1,111 @@
/***************************************************************************
qgslayoutsnapper.h
-------------------
begin : July 2017
copyright : (C) 2017 by 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 QGSLAYOUTSNAPPER_H
#define QGSLAYOUTSNAPPER_H
#include "qgis_core.h"
#include "qgslayoutmeasurement.h"
#include "qgslayoutpoint.h"
#include <QPen>
/**
* \ingroup core
* \class QgsLayoutSnapper
* \brief Manages snapping grids and preset snap lines in a layout, and handles
* snapping points to the nearest grid coordinate/snap line when possible.
* \since QGIS 3.0
*/
class CORE_EXPORT QgsLayoutSnapper
{
public:
//! Style for drawing the page/snapping grid
enum GridStyle
{
GridLines, //! Solid lines
GridDots, //! Dots
GridCrosses //! Crosses
};
QgsLayoutSnapper();
/**
* Sets the page/snap grid \a resolution.
* \see gridResolution()
* \see setGridOffset()
*/
void setGridResolution( const QgsLayoutMeasurement &resolution ) { mGridResolution = resolution; }
/**
* Returns the page/snap grid resolution.
* \see setGridResolution()
* \see gridOffset()
*/
QgsLayoutMeasurement gridResolution() const { return mGridResolution;}
/**
* Sets the \a offset of the page/snap grid.
* \see gridOffset()
* \see setGridResolution()
*/
void setGridOffset( const QgsLayoutPoint offset ) { mGridOffset = offset; }
/**
* Returns the offset of the page/snap grid.
* \see setGridOffset()
* \see gridResolution()
*/
QgsLayoutPoint gridOffset() const { return mGridOffset; }
/**
* Sets the \a pen used for drawing page/snap grids.
* \see gridPen()
* \see setGridStyle()
*/
void setGridPen( const QPen &pen ) { mGridPen = pen; }
/**
* Returns the pen used for drawing page/snap grids.
* \see setGridPen()
* \see gridStyle()
*/
QPen gridPen() const { return mGridPen; }
/**
* Sets the \a style used for drawing the page/snap grids.
* \see gridStyle()
* \see setGridPen()
*/
void setGridStyle( const GridStyle style ) { mGridStyle = style; }
/**
* Returns the style used for drawing the page/snap grids.
* \see setGridStyle()
* \see gridPen()
*/
GridStyle gridStyle() const { return mGridStyle; }
private:
QgsLayoutMeasurement mGridResolution;
QgsLayoutPoint mGridOffset;
QPen mGridPen;
GridStyle mGridStyle = GridLines;
};
#endif //QGSLAYOUTSNAPPER_H

View File

@ -79,6 +79,7 @@ ADD_PYTHON_TEST(PyQgsLayoutManager test_qgslayoutmanager.py)
ADD_PYTHON_TEST(PyQgsLayoutPageCollection test_qgslayoutpagecollection.py)
ADD_PYTHON_TEST(PyQgsLayoutView test_qgslayoutview.py)
ADD_PYTHON_TEST(PyQgsLayoutItemPropertiesDialog test_qgslayoutitempropertiesdialog.py)
ADD_PYTHON_TEST(PyQgsLayoutSnapper test_qgslayoutsnapper.py)
ADD_PYTHON_TEST(PyQgsLayoutUnitsComboBox test_qgslayoutunitscombobox.py)
ADD_PYTHON_TEST(PyQgsLineSymbolLayers test_qgslinesymbollayers.py)
ADD_PYTHON_TEST(PyQgsLocator test_qgslocator.py)

View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
"""QGIS Unit tests for QgsLayoutSnapper.
.. note:: 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.
"""
__author__ = 'Nyall Dawson'
__date__ = '05/07/2017'
__copyright__ = 'Copyright 2017, The QGIS Project'
# This will get replaced with a git SHA1 when you do a git archive
__revision__ = '$Format:%H$'
import qgis # NOQA
from qgis.core import (QgsProject,
QgsLayout,
QgsLayoutSnapper,
QgsLayoutMeasurement,
QgsUnitTypes,
QgsLayoutPoint)
from qgis.PyQt.QtCore import QRectF
from qgis.PyQt.QtGui import (QTransform,
QPen,
QColor)
from qgis.testing import start_app, unittest
start_app()
class TestQgsLayoutSnapper(unittest.TestCase):
def testGettersSetters(self):
s = QgsLayoutSnapper()
s.setGridResolution(QgsLayoutMeasurement(5, QgsUnitTypes.LayoutPoints))
self.assertEqual(s.gridResolution().length(), 5.0)
self.assertEqual(s.gridResolution().units(), QgsUnitTypes.LayoutPoints)
s.setGridOffset(QgsLayoutPoint(6, 7, QgsUnitTypes.LayoutPixels))
self.assertEqual(s.gridOffset().x(), 6.0)
self.assertEqual(s.gridOffset().y(), 7.0)
self.assertEqual(s.gridOffset().units(), QgsUnitTypes.LayoutPixels)
s.setGridPen(QPen(QColor(255, 0, 255)))
self.assertEqual(s.gridPen().color().name(), QColor(255, 0, 255).name())
s.setGridStyle(QgsLayoutSnapper.GridDots)
self.assertEqual(s.gridStyle(), QgsLayoutSnapper.GridDots)
if __name__ == '__main__':
unittest.main()