Skip to content
Permalink
Browse files

Tweak snapping logic, and add explicit action to "Snap Selected Compo…

…nents to Grid"

This is useful when a user doesn't want to enable the auto snapping, but wants to line
up stuff nicely by hand
  • Loading branch information
nyalldawson committed Mar 23, 2020
1 parent 4bad254 commit 681d12e549af774f509b102ad6b327ca565b9d74
@@ -106,11 +106,6 @@ Shows a preview of moving the item from its stored position by ``dx``, ``dy``.
void setItemRect( QRectF rect );
%Docstring
Sets a new scene ``rect`` for the item.
%End

QRectF previewItemRectChange( QRectF rect );
%Docstring
Shows a preview of setting a new ``rect`` for the item.
%End

virtual void mouseDoubleClickEvent( QGraphicsSceneMouseEvent *event );
@@ -78,6 +78,13 @@ Starts a macro command, containing a group of interactions in the view.
void endMacroCommand();
%Docstring
Ends a macro command, containing a group of interactions in the view.
%End

public slots:

void snapSelected();
%Docstring
Snaps the selected items to the grid.
%End

signals:
@@ -128,22 +128,29 @@ void QgsModelComponentGraphicItem::previewItemMove( qreal dx, qreal dy )
emit updateArrowPaths();
}

void QgsModelComponentGraphicItem::setItemRect( QRectF )
void QgsModelComponentGraphicItem::setItemRect( QRectF rect )
{
mComponent->setPosition( pos() );
rect = rect.normalized();

if ( rect.width() < MIN_COMPONENT_WIDTH )
rect.setWidth( MIN_COMPONENT_WIDTH );
if ( rect.height() < MIN_COMPONENT_HEIGHT )
rect.setHeight( MIN_COMPONENT_HEIGHT );

setPos( rect.center() );
prepareGeometryChange();
mComponent->setSize( mTempSize );
mTempSize = QSizeF();

emit aboutToChange( tr( "Resize %1" ).arg( mComponent->description() ) );

mComponent->setPosition( pos() );
mComponent->setSize( rect.size() );
updateStoredComponentPosition( pos(), mComponent->size() );

updateButtonPositions();

emit changed();

emit sizePositionChanged();
emit updateArrowPaths();
emit sizePositionChanged();
}

QRectF QgsModelComponentGraphicItem::previewItemRectChange( QRectF rect )
@@ -166,6 +173,24 @@ QRectF QgsModelComponentGraphicItem::previewItemRectChange( QRectF rect )
return rect;
}

void QgsModelComponentGraphicItem::finalizePreviewedItemRectChange( QRectF )
{
mComponent->setPosition( pos() );
prepareGeometryChange();
mComponent->setSize( mTempSize );
mTempSize = QSizeF();

emit aboutToChange( tr( "Resize %1" ).arg( mComponent->description() ) );
updateStoredComponentPosition( pos(), mComponent->size() );

updateButtonPositions();

emit changed();

emit sizePositionChanged();
emit updateArrowPaths();
}

void QgsModelComponentGraphicItem::modelHoverEnterEvent( QgsModelViewMouseEvent *event )
{
if ( view() && view()->tool() && view()->tool()->allowItemInteraction() )
@@ -130,12 +130,17 @@ class GUI_EXPORT QgsModelComponentGraphicItem : public QGraphicsObject
*/
void setItemRect( QRectF rect );

#ifndef SIP_RUN

/**
* Shows a preview of setting a new \a rect for the item.
*/
QRectF previewItemRectChange( QRectF rect );

#ifndef SIP_RUN
/**
* Sets a new scene \a rect for the item.
*/
void finalizePreviewedItemRectChange( QRectF rect );

/**
* Handles a model hover enter \a event.
@@ -359,7 +364,7 @@ class GUI_EXPORT QgsModelComponentGraphicItem : public QGraphicsObject
QgsModelDesignerFlatButtonGraphicItem *mDeleteButton = nullptr;

static constexpr double MIN_COMPONENT_WIDTH = 70;
static constexpr double MIN_COMPONENT_HEIGHT = 50;
static constexpr double MIN_COMPONENT_HEIGHT = 30;

static constexpr double DEFAULT_BUTTON_WIDTH = 16;
static constexpr double DEFAULT_BUTTON_HEIGHT = 16;
@@ -132,12 +132,13 @@ QgsModelDesignerDialog::QgsModelDesignerDialog( QWidget *parent, Qt::WindowFlags
connect( mActionSave, &QAction::triggered, this, [ = ] { saveModel( false ); } );
connect( mActionSaveAs, &QAction::triggered, this, [ = ] { saveModel( true ); } );
connect( mActionDeleteComponents, &QAction::triggered, this, &QgsModelDesignerDialog::deleteSelected );
connect( mActionSnapSelected, &QAction::triggered, mView, &QgsModelGraphicsView::snapSelected );

mActionSnappingEnabled->setChecked( settings.value( QStringLiteral( "/Processing/modelDesignerEnableSnap" ), true ).toBool() );
mActionSnappingEnabled->setChecked( settings.value( QStringLiteral( "/Processing/Modeler/enableSnapToGrid" ), true ).toBool() );
connect( mActionSnappingEnabled, &QAction::toggled, this, [ = ]( bool enabled )
{
mView->snapper()->setSnapToGrid( enabled );
QgsSettings().setValue( QStringLiteral( "/Processing/modelDesignerEnableSnap" ), enabled );
QgsSettings().setValue( QStringLiteral( "/Processing/Modeler/enableSnapToGrid" ), enabled );
} );
mView->snapper()->setSnapToGrid( mActionSnappingEnabled->isChecked() );

@@ -435,6 +435,29 @@ void QgsModelGraphicsView::endMacroCommand()
emit macroCommandEnded();
}

void QgsModelGraphicsView::snapSelected()
{
QgsModelGraphicsScene *s = modelScene();
const QList<QgsModelComponentGraphicItem *> itemList = s->selectedComponentItems();
if ( !itemList.empty() )
{
itemList.at( 0 )->aboutToChange( tr( "Snap Items" ) );
bool prevSetting = mSnapper.snapToGrid();
mSnapper.setSnapToGrid( true );
for ( QgsModelComponentGraphicItem *item : itemList )
{
bool wasSnapped = false;
QRectF snapped = mSnapper.snapRectWithResize( item->mapRectToScene( item->itemRect( ) ), transform().m11(), wasSnapped );
if ( wasSnapped )
{
item->setItemRect( snapped );
}
}
mSnapper.setSnapToGrid( prevSetting );
itemList.at( 0 )->changed();
}
}


QgsModelViewSnapMarker::QgsModelViewSnapMarker()
: QGraphicsRectItem( QRectF( 0, 0, 0, 0 ) )
@@ -110,6 +110,13 @@ class GUI_EXPORT QgsModelGraphicsView : public QGraphicsView
*/
void endMacroCommand();

public slots:

/**
* Snaps the selected items to the grid.
*/
void snapSelected();

signals:

/**
@@ -21,7 +21,7 @@
QgsModelSnapper::QgsModelSnapper()
{
QgsSettings s;
mTolerance = s.value( QStringLiteral( "/Processing/modelDesignerSnapTolerancePixels" ), 20 ).toInt();
mTolerance = s.value( QStringLiteral( "/Processing/Modeler/snapTolerancePixels" ), 40 ).toInt();
}

void QgsModelSnapper::setSnapTolerance( const int snapTolerance )
@@ -60,11 +60,6 @@ QRectF QgsModelSnapper::snapRect( const QRectF &rect, double scaleFactor, bool &
snapped = false;
QRectF snappedRect = rect;

QList< double > xCoords;
xCoords << rect.left() << rect.center().x() << rect.right();
QList< double > yCoords;
yCoords << rect.top() << rect.center().y() << rect.bottom();

bool snappedXToGrid = false;
bool snappedYToGrid = false;
QList< QPointF > points;
@@ -84,6 +79,39 @@ QRectF QgsModelSnapper::snapRect( const QRectF &rect, double scaleFactor, bool &
return snappedRect;
}

QRectF QgsModelSnapper::snapRectWithResize( const QRectF &rect, double scaleFactor, bool &snapped, bool snapHorizontal, bool snapVertical ) const
{
snapped = false;
QRectF snappedRect = rect;

bool snappedXToGrid = false;
bool snappedYToGrid = false;
QPointF res = snapPointsToGrid( QList< QPointF >() << rect.topLeft(), scaleFactor, snappedXToGrid, snappedYToGrid );
if ( snappedXToGrid && snapVertical )
{
snapped = true;
snappedRect.setLeft( snappedRect.left() + res.x() );
}
if ( snappedYToGrid && snapHorizontal )
{
snapped = true;
snappedRect.setTop( snappedRect.top() + res.y() );
}
res = snapPointsToGrid( QList< QPointF >() << rect.bottomRight(), scaleFactor, snappedXToGrid, snappedYToGrid );
if ( snappedXToGrid && snapVertical )
{
snapped = true;
snappedRect.setRight( snappedRect.right() + res.x() );
}
if ( snappedYToGrid && snapHorizontal )
{
snapped = true;
snappedRect.setBottom( snappedRect.bottom() + res.y() );
}

return snappedRect;
}

QPointF QgsModelSnapper::snapPointToGrid( QPointF point, double scaleFactor, bool &snappedX, bool &snappedY ) const
{
QPointF delta = snapPointsToGrid( QList< QPointF >() << point, scaleFactor, snappedX, snappedY );
@@ -103,6 +103,24 @@ class GUI_EXPORT QgsModelSnapper
*/
QRectF snapRect( const QRectF &rect, double scaleFactor, bool &snapped SIP_OUT, bool snapHorizontal = true, bool snapVertical = true ) const;

/**
* Snaps a layout coordinate \a rect. If \a rect was snapped, \a snapped will be set to TRUE.
*
* The \a scaleFactor argument should be set to the transformation from
* scalar transform from layout coordinates to pixels, i.e. the
* graphics view transform().m11() value.
*
* This method considers snapping to the grid, snap lines, etc.
*
* If the \a horizontalSnapLine and \a verticalSnapLine arguments are specified, then the snapper
* will automatically display and position these lines to indicate snapping positions to item bounds.
*
* A list of items to ignore during the snapping can be specified via the \a ignoreItems list.
*
* \see snapPoint()
*/
QRectF snapRectWithResize( const QRectF &rect, double scaleFactor, bool &snapped SIP_OUT, bool snapHorizontal = true, bool snapVertical = true ) const;

/**
* Snaps a layout coordinate \a point to the grid. If \a point
* was snapped horizontally, \a snappedX will be set to TRUE. If \a point
@@ -137,7 +137,7 @@ void QgsModelViewMouseHandles::setItemRect( QGraphicsItem *item, QRectF rect )
{
if ( QgsModelComponentGraphicItem *componentItem = dynamic_cast<QgsModelComponentGraphicItem *>( item ) )
{
componentItem->setItemRect( rect );
componentItem->finalizePreviewedItemRectChange( rect );
}
}

@@ -164,13 +164,10 @@ QPointF QgsModelViewMouseHandles::snapPoint( QPointF originalPoint, QgsGraphicsV
{
bool snapped = false;

//depending on the mode, we either snap just the single point, or all the bounds of the selection
QPointF snappedPoint;
switch ( mode )
{
case Item:
snappedPoint = mView->snapper()->snapRect( rect().translated( originalPoint ), mView->transform().m11(), snapped, snapHorizontal, snapVertical ).topLeft();
break;
case Point:
snappedPoint = mView->snapper()->snapPoint( originalPoint, mView->transform().m11(), snapped, snapHorizontal, snapVertical );
break;
@@ -88,6 +88,8 @@
<string>&amp;Edit</string>
</property>
<addaction name="mActionDeleteComponents"/>
<addaction name="separator"/>
<addaction name="mActionSnapSelected"/>
</widget>
<addaction name="menu_Model"/>
<addaction name="mMenuEdit"/>
@@ -159,7 +161,7 @@
<x>0</x>
<y>0</y>
<width>256</width>
<height>98</height>
<height>97</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
@@ -249,7 +251,7 @@
<x>0</x>
<y>0</y>
<width>256</width>
<height>152</height>
<height>153</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
@@ -620,6 +622,11 @@
<string>Enable Snapping</string>
</property>
</action>
<action name="mActionSnapSelected">
<property name="text">
<string>Snap Selected Components to Grid</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

0 comments on commit 681d12e

Please sign in to comment.
You can’t perform that action at this time.