Skip to content

Commit 24d1106

Browse files
nyalldawsonmhugent
authored andcommittedOct 2, 2013
[FEATURE] Allow multi item drag and resize in composer (fix #7918)
[FEATURE] Always draw selection handles on top of composition, add dashed border for selected items (fix #7793) Move responsibility for drawing selection mouse handles and mouse interaction with selection to new class
1 parent 7bc72d4 commit 24d1106

File tree

10 files changed

+1133
-702
lines changed

10 files changed

+1133
-702
lines changed
 

‎python/core/composer/qgscomposeritem.sip

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,6 @@ class QgsComposerItem: QObject, QGraphicsRectItem
332332
@note this method was added in version 1.2*/
333333
bool positionLock() const;
334334

335-
/**Update mouse cursor at (item) position
336-
@note this method was added in version 1.2*/
337-
void updateCursor( const QPointF& itemPos );
338-
339335
double rotation() const;
340336

341337
/**Updates item, with the possibility to do custom update for subclasses*/
@@ -367,22 +363,6 @@ class QgsComposerItem: QObject, QGraphicsRectItem
367363

368364
virtual void hoverMoveEvent( QGraphicsSceneHoverEvent * event );
369365

370-
/**Finds out the appropriate cursor for the current mouse position in the widget (e.g. move in the middle, resize at border)*/
371-
Qt::CursorShape cursorForPosition( const QPointF& itemCoordPos );
372-
373-
/**Finds out which mouse move action to choose depending on the cursor position inside the widget*/
374-
QgsComposerItem::MouseMoveAction mouseMoveActionForPosition( const QPointF& itemCoordPos );
375-
376-
/**Changes the rectangle of an item depending on current mouse action (resize or move)
377-
@param currentPosition current position of mouse cursor
378-
@param mouseMoveStartPos cursor position at the start of the current mouse action
379-
@param originalItem Item position at the start of the mouse action
380-
@param dx x-Change of mouse cursor
381-
@param dy y-Change of mouse cursor
382-
@param changeItem Item to change size (can be the same as originalItem or a differen one)
383-
*/
384-
void changeItemRectangle( const QPointF& currentPosition, const QPointF& mouseMoveStartPos, const QGraphicsRectItem* originalItem, double dx, double dy, QGraphicsRectItem* changeItem );
385-
386366
/**Draw selection boxes around item*/
387367
virtual void drawSelectionBoxes( QPainter* p );
388368

‎python/core/composer/qgscomposition.sip

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -213,23 +213,6 @@ class QgsComposition : QGraphicsScene
213213
/**Snaps a scene coordinate point to grid*/
214214
QPointF snapPointToGrid( const QPointF& scenePoint ) const;
215215

216-
/**Snaps item position to align with other items (left / middle / right or top / middle / bottom
217-
@param item current item
218-
@param alignX x-coordinate of align or -1 if not aligned to x
219-
@param alignY y-coordinate of align or -1 if not aligned to y
220-
@param dx item shift in x direction
221-
@param dy item shift in y direction
222-
@return new upper left point after the align*/
223-
QPointF alignItem( const QgsComposerItem* item, double& alignX, double& alignY, double dx = 0, double dy = 0 );
224-
225-
/**Snaps position to align with the boundaries of other items
226-
@param pos position to snap
227-
@param excludeItem item to exclude
228-
@param alignX snapped x coordinate or -1 if not snapped
229-
@param alignY snapped y coordinate or -1 if not snapped
230-
@return snapped position or original position if no snap*/
231-
QPointF alignPos( const QPointF& pos, const QgsComposerItem* excludeItem, double& alignX, double& alignY );
232-
233216
/**Add a custom snap line (can be horizontal or vertical)*/
234217
QGraphicsLineItem* addSnapLine();
235218
/**Remove custom snap line (and delete the object)*/

‎src/core/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ SET(QGIS_CORE_SRCS
133133
composer/qgscomposermultiframecommand.cpp
134134
composer/qgscomposerarrow.cpp
135135
composer/qgscomposerframe.cpp
136+
composer/qgscomposermousehandles.cpp
136137
composer/qgscomposeritem.cpp
137138
composer/qgscomposeritemcommand.cpp
138139
composer/qgscomposeritemgroup.cpp
@@ -324,6 +325,7 @@ SET(QGIS_CORE_MOC_HDRS
324325
composer/qgscomposerscalebar.h
325326
composer/qgscomposeritem.h
326327
composer/qgscomposeritemgroup.h
328+
composer/qgscomposermousehandles.h
327329
composer/qgscomposerlabel.h
328330
composer/qgscomposershape.h
329331
composer/qgscomposerattributetable.h

‎src/core/composer/qgscomposeritem.cpp

Lines changed: 1 addition & 411 deletions
Large diffs are not rendered by default.

‎src/core/composer/qgscomposeritem.h

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
108108
virtual void setSelected( bool s );
109109

110110
/** \brief Is selected */
111-
virtual bool selected() {return QGraphicsRectItem::isSelected();}
111+
virtual bool selected() const {return QGraphicsRectItem::isSelected();};
112112

113113
/** stores state in project */
114114
virtual bool writeSettings();
@@ -287,10 +287,6 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
287287
@note this method was added in version 1.2*/
288288
bool positionLock() const {return mItemPositionLocked;}
289289

290-
/**Update mouse cursor at (item) position
291-
@note this method was added in version 1.2*/
292-
void updateCursor( const QPointF& itemPos );
293-
294290
double rotation() const {return mRotation;}
295291

296292
/**Updates item, with the possibility to do custom update for subclasses*/
@@ -357,29 +353,6 @@ class CORE_EXPORT QgsComposerItem: public QObject, public QGraphicsRectItem
357353
@note: this member was added in version 2.0*/
358354
ItemPositionMode mLastUsedPositionMode;
359355

360-
//event handlers
361-
virtual void mouseMoveEvent( QGraphicsSceneMouseEvent * event );
362-
virtual void mousePressEvent( QGraphicsSceneMouseEvent * event );
363-
virtual void mouseReleaseEvent( QGraphicsSceneMouseEvent * event );
364-
365-
virtual void hoverMoveEvent( QGraphicsSceneHoverEvent * event );
366-
367-
/**Finds out the appropriate cursor for the current mouse position in the widget (e.g. move in the middle, resize at border)*/
368-
Qt::CursorShape cursorForPosition( const QPointF& itemCoordPos );
369-
370-
/**Finds out which mouse move action to choose depending on the cursor position inside the widget*/
371-
QgsComposerItem::MouseMoveAction mouseMoveActionForPosition( const QPointF& itemCoordPos );
372-
373-
/**Changes the rectangle of an item depending on current mouse action (resize or move)
374-
@param currentPosition current position of mouse cursor
375-
@param mouseMoveStartPos cursor position at the start of the current mouse action
376-
@param originalItem Item position at the start of the mouse action
377-
@param dx x-Change of mouse cursor
378-
@param dy y-Change of mouse cursor
379-
@param changeItem Item to change size (can be the same as originalItem or a differen one)
380-
*/
381-
void changeItemRectangle( const QPointF& currentPosition, const QPointF& mouseMoveStartPos, const QGraphicsRectItem* originalItem, double dx, double dy, QGraphicsRectItem* changeItem );
382-
383356
/**Draw selection boxes around item*/
384357
virtual void drawSelectionBoxes( QPainter* p );
385358

‎src/core/composer/qgscomposermousehandles.cpp

Lines changed: 893 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
/***************************************************************************
2+
qgscomposermousehandles.h
3+
-------------------
4+
begin : September 2013
5+
copyright : (C) 2013 by Nyall Dawson, Radim Blazek
6+
email : nyall.dawson@gmail.com
7+
***************************************************************************/
8+
9+
/***************************************************************************
10+
* *
11+
* This program is free software; you can redistribute it and/or modify *
12+
* it under the terms of the GNU General Public License as published by *
13+
* the Free Software Foundation; either version 2 of the License, or *
14+
* (at your option) any later version. *
15+
* *
16+
***************************************************************************/
17+
#ifndef QGSCOMPOSERMOUSEHANDLES_H
18+
#define QGSCOMPOSERMOUSEHANDLES_H
19+
20+
#include <QGraphicsRectItem>
21+
#include <QObject>
22+
23+
class QgsComposition;
24+
class QgsComposerItem;
25+
26+
/** \ingroup MapComposer
27+
* Handles drawing of selection outlines and mouse handles. Responsible for mouse
28+
* interactions such as resizing and moving selected items.
29+
* */
30+
class CORE_EXPORT QgsComposerMouseHandles: public QObject, public QGraphicsRectItem
31+
{
32+
Q_OBJECT
33+
public:
34+
35+
/**Describes the action (move or resize in different directon) to be done during mouse move*/
36+
enum MouseAction
37+
{
38+
MoveItem,
39+
ResizeUp,
40+
ResizeDown,
41+
ResizeLeft,
42+
ResizeRight,
43+
ResizeLeftUp,
44+
ResizeRightUp,
45+
ResizeLeftDown,
46+
ResizeRightDown,
47+
SelectItem,
48+
NoAction
49+
};
50+
51+
enum ItemPositionMode
52+
{
53+
UpperLeft,
54+
UpperMiddle,
55+
UpperRight,
56+
MiddleLeft,
57+
Middle,
58+
MiddleRight,
59+
LowerLeft,
60+
LowerMiddle,
61+
LowerRight
62+
};
63+
64+
enum SnapGuideMode
65+
{
66+
Item,
67+
Point
68+
};
69+
70+
QgsComposerMouseHandles( QgsComposition *composition );
71+
virtual ~QgsComposerMouseHandles();
72+
73+
void setComposition( QgsComposition* c ) { mComposition = c; }
74+
QgsComposition* composition() { return mComposition; }
75+
76+
void paint( QPainter* painter, const QStyleOptionGraphicsItem* itemStyle, QWidget* pWidget );
77+
78+
/**Finds out which mouse move action to choose depending on the scene cursor position*/
79+
QgsComposerMouseHandles::MouseAction mouseActionForScenePos( const QPointF& sceneCoordPos );
80+
81+
protected:
82+
83+
void mouseMoveEvent( QGraphicsSceneMouseEvent* event );
84+
void mouseReleaseEvent( QGraphicsSceneMouseEvent* event );
85+
void mousePressEvent( QGraphicsSceneMouseEvent* event );
86+
void hoverMoveEvent( QGraphicsSceneHoverEvent * event );
87+
88+
public slots:
89+
90+
/**Sets up listeners to sizeChanged signal for all selected items*/
91+
void selectionChanged();
92+
93+
/**Redraws handles when selected item size changes*/
94+
void selectedItemSizeChanged();
95+
96+
private:
97+
98+
QgsComposition* mComposition; //reference to composition
99+
100+
QgsComposerMouseHandles::MouseAction mCurrentMouseMoveAction;
101+
/**Start point of the last mouse move action (in scene coordinates)*/
102+
QPointF mMouseMoveStartPos;
103+
/**Position of the last mouse move event (in scene coordinates)*/
104+
QPointF mLastMouseEventPos;
105+
/**Position of the mouse at beginning of move/resize (in scene coordinates)*/
106+
QPointF mBeginMouseEventPos;
107+
/**Position of composer handles at beginning of move/resize (in scene coordinates)*/
108+
QPointF mBeginHandlePos;
109+
/**Width and height of composer handles at beginning of resize*/
110+
double mBeginHandleWidth;
111+
double mBeginHandleHeight;
112+
113+
/**True if user is currently dragging items*/
114+
bool mIsDragging;
115+
/**True is user is currently resizing items*/
116+
bool mIsResizing;
117+
118+
/**Align snap lines*/
119+
QGraphicsLineItem* mHAlignSnapItem;
120+
QGraphicsLineItem* mVAlignSnapItem;
121+
122+
/**Returns the scene bounds of current selection*/
123+
QRectF selectionBounds() const;
124+
125+
/**Redraws or hides the handles based on the current selection*/
126+
void updateHandles();
127+
/**Draws the handles*/
128+
void drawHandles( QPainter* painter, double rectHandlerSize );
129+
/**Draw outlines for selected items*/
130+
void drawSelectedItemBounds( QPainter* painter );
131+
132+
/**Returns the current (zoom level dependent) tolerance to decide if mouse position is close enough to the
133+
item border for resizing*/
134+
double rectHandlerBorderTolerance() const;
135+
136+
/**Finds out the appropriate cursor for the current mouse position in the widget (e.g. move in the middle, resize at border)*/
137+
Qt::CursorShape cursorForPosition( const QPointF& itemCoordPos );
138+
139+
/**Finds out which mouse move action to choose depending on the cursor position inside the widget*/
140+
QgsComposerMouseHandles::MouseAction mouseActionForPosition( const QPointF& itemCoordPos );
141+
142+
/**Handles dragging of items during mouse move*/
143+
void dragMouseMove( const QPointF& currentPosition );
144+
/**Handles resizing of items during mouse move*/
145+
void resizeMouseMove( const QPointF& currentPosition );
146+
147+
/**Resizes a QRectF relative to the change from boundsBefore to boundsAfter*/
148+
void relativeResizeRect( QRectF& rectToResize, const QRectF& boundsBefore, const QRectF& boundsAfter );
149+
/**Returns a scaled position given a before and after range*/
150+
double relativePosition( double position, double beforeMin, double beforeMax, double afterMin, double afterMax );
151+
152+
/**Return horizontal align snap item. Creates a new graphics line if 0*/
153+
QGraphicsLineItem* hAlignSnapItem();
154+
void deleteHAlignSnapItem();
155+
/**Return vertical align snap item. Creates a new graphics line if 0*/
156+
QGraphicsLineItem* vAlignSnapItem();
157+
void deleteVAlignSnapItem();
158+
void deleteAlignItems();
159+
160+
/**Snaps an item or point (depending on mode) originating at originalPoint to the grid or align rulers*/
161+
QPointF snapPoint( const QPointF& originalPoint, QgsComposerMouseHandles::SnapGuideMode mode );
162+
/**Snaps an item originating at unalignedX, unalignedY to the grid or align rulers*/
163+
QPointF alignItem( double& alignX, double& alignY, double unalignedX, double unalignedY );
164+
/**Snaps a point to to the grid or align rulers*/
165+
QPointF alignPos( const QPointF& pos, double& alignX, double& alignY );
166+
167+
//helper functions for item align
168+
void collectAlignCoordinates( QMap< double, const QgsComposerItem* >& alignCoordsX, QMap< double, const QgsComposerItem* >& alignCoordsY );
169+
bool nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value, double& nearestValue ) const;
170+
void checkNearestItem( double checkCoord, const QMap< double, const QgsComposerItem* >& alignCoords, double& smallestDiff, double itemCoordOffset, double& itemCoord, double& alignCoord ) const;
171+
172+
};
173+
174+
#endif // QGSCOMPOSERMOUSEHANDLES_H

‎src/core/composer/qgscomposition.cpp

Lines changed: 8 additions & 184 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "qgscomposerlabel.h"
2222
#include "qgscomposerlegend.h"
2323
#include "qgscomposermap.h"
24+
#include "qgscomposermousehandles.h"
2425
#include "qgscomposeritemgroup.h"
2526
#include "qgscomposerpicture.h"
2627
#include "qgscomposerscalebar.h"
@@ -64,13 +65,19 @@ QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer )
6465
, mSnapGridOffsetY( 0.0 )
6566
, mAlignmentSnap( true )
6667
, mAlignmentSnapTolerance( 2 )
68+
, mSelectionHandles( 0 )
6769
, mActiveItemCommand( 0 )
6870
, mActiveMultiFrameCommand( 0 )
6971
, mAtlasComposition( this )
7072
{
7173
setBackgroundBrush( Qt::gray );
7274
addPaperItem();
7375

76+
mSelectionHandles = new QgsComposerMouseHandles( this );
77+
addItem( mSelectionHandles );
78+
mSelectionHandles->setRect( 30, 30, 100, 100 );
79+
mSelectionHandles->setZValue( 200 );
80+
7481
mPrintResolution = 300; //hardcoded default
7582
loadSettings();
7683
}
@@ -93,6 +100,7 @@ QgsComposition::QgsComposition()
93100
mSnapGridOffsetY( 0.0 ),
94101
mAlignmentSnap( true ),
95102
mAlignmentSnapTolerance( 2 ),
103+
mSelectionHandles( 0 ),
96104
mActiveItemCommand( 0 ),
97105
mActiveMultiFrameCommand( 0 ),
98106
mAtlasComposition( this )
@@ -1350,88 +1358,6 @@ QPointF QgsComposition::snapPointToGrid( const QPointF& scenePoint ) const
13501358
return QPointF( xRatio * mSnapGridResolution + mSnapGridOffsetX, yRatio * mSnapGridResolution + mSnapGridOffsetY + yOffset );
13511359
}
13521360

1353-
QPointF QgsComposition::alignItem( const QgsComposerItem* item, double& alignX, double& alignY, double dx, double dy )
1354-
{
1355-
if ( !item )
1356-
{
1357-
return QPointF();
1358-
}
1359-
1360-
double left = item->transform().dx() + dx;
1361-
double right = left + item->rect().width();
1362-
double midH = ( left + right ) / 2.0;
1363-
double top = item->transform().dy() + dy;
1364-
double bottom = top + item->rect().height();
1365-
double midV = ( top + bottom ) / 2.0;
1366-
1367-
QMap<double, const QgsComposerItem* > xAlignCoordinates;
1368-
QMap<double, const QgsComposerItem* > yAlignCoordinates;
1369-
collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates, item );
1370-
1371-
//find nearest matches x
1372-
double xItemLeft = left; //new left coordinate of the item
1373-
double xAlignCoord = 0;
1374-
double smallestDiffX = DBL_MAX;
1375-
1376-
checkNearestItem( left, xAlignCoordinates, smallestDiffX, 0, xItemLeft, xAlignCoord );
1377-
checkNearestItem( midH, xAlignCoordinates, smallestDiffX, ( left - right ) / 2.0, xItemLeft, xAlignCoord );
1378-
checkNearestItem( right, xAlignCoordinates, smallestDiffX, left - right, xItemLeft, xAlignCoord );
1379-
1380-
//find nearest matches y
1381-
double yItemTop = top; //new top coordinate of the item
1382-
double yAlignCoord = 0;
1383-
double smallestDiffY = DBL_MAX;
1384-
1385-
checkNearestItem( top, yAlignCoordinates, smallestDiffY, 0, yItemTop, yAlignCoord );
1386-
checkNearestItem( midV, yAlignCoordinates, smallestDiffY, ( top - bottom ) / 2.0, yItemTop, yAlignCoord );
1387-
checkNearestItem( bottom, yAlignCoordinates, smallestDiffY, top - bottom, yItemTop, yAlignCoord );
1388-
1389-
double xCoord = ( smallestDiffX < 5 ) ? xItemLeft : item->transform().dx() + dx;
1390-
alignX = ( smallestDiffX < 5 ) ? xAlignCoord : -1;
1391-
double yCoord = ( smallestDiffY < 5 ) ? yItemTop : item->transform().dy() + dy;
1392-
alignY = ( smallestDiffY < 5 ) ? yAlignCoord : -1;
1393-
return QPointF( xCoord, yCoord );
1394-
}
1395-
1396-
QPointF QgsComposition::alignPos( const QPointF& pos, const QgsComposerItem* excludeItem, double& alignX, double& alignY )
1397-
{
1398-
QMap<double, const QgsComposerItem* > xAlignCoordinates;
1399-
QMap<double, const QgsComposerItem* > yAlignCoordinates;
1400-
collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates, excludeItem );
1401-
1402-
double nearestX = pos.x();
1403-
double nearestY = pos.y();
1404-
if ( !nearestItem( xAlignCoordinates, pos.x(), nearestX )
1405-
|| !nearestItem( yAlignCoordinates, pos.y(), nearestY ) )
1406-
{
1407-
alignX = -1;
1408-
alignY = -1;
1409-
return pos;
1410-
}
1411-
1412-
QPointF result( pos.x(), pos.y() );
1413-
if ( abs( nearestX - pos.x() ) < mAlignmentSnapTolerance )
1414-
{
1415-
result.setX( nearestX );
1416-
alignX = nearestX;
1417-
}
1418-
else
1419-
{
1420-
alignX = -1;
1421-
}
1422-
1423-
if ( abs( nearestY - pos.y() ) < mAlignmentSnapTolerance )
1424-
{
1425-
result.setY( nearestY );
1426-
alignY = nearestY;
1427-
}
1428-
else
1429-
{
1430-
alignY = -1;
1431-
}
1432-
return result;
1433-
}
1434-
14351361
QGraphicsLineItem* QgsComposition::addSnapLine()
14361362
{
14371363
QGraphicsLineItem* item = new QGraphicsLineItem();
@@ -2218,108 +2144,6 @@ QString QgsComposition::encodeStringForXML( const QString& str )
22182144
return modifiedStr;
22192145
}
22202146

2221-
void QgsComposition::collectAlignCoordinates( QMap< double, const QgsComposerItem* >& alignCoordsX, QMap< double, const QgsComposerItem* >& alignCoordsY,
2222-
const QgsComposerItem* excludeItem )
2223-
{
2224-
alignCoordsX.clear();
2225-
alignCoordsY.clear();
2226-
2227-
QList<QGraphicsItem *> itemList = items();
2228-
QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
2229-
for ( ; itemIt != itemList.end(); ++itemIt )
2230-
{
2231-
const QgsComposerItem* currentItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
2232-
if ( excludeItem )
2233-
{
2234-
if ( !currentItem || currentItem == excludeItem )
2235-
{
2236-
continue;
2237-
}
2238-
alignCoordsX.insert( currentItem->transform().dx(), currentItem );
2239-
alignCoordsX.insert( currentItem->transform().dx() + currentItem->rect().width(), currentItem );
2240-
alignCoordsX.insert( currentItem->transform().dx() + currentItem->rect().center().x(), currentItem );
2241-
alignCoordsY.insert( currentItem->transform().dy() + currentItem->rect().top(), currentItem );
2242-
alignCoordsY.insert( currentItem->transform().dy() + currentItem->rect().center().y(), currentItem );
2243-
alignCoordsY.insert( currentItem->transform().dy() + currentItem->rect().bottom(), currentItem );
2244-
}
2245-
}
2246-
2247-
//arbitrary snap lines
2248-
QList< QGraphicsLineItem* >::const_iterator sIt = mSnapLines.constBegin();
2249-
for ( ; sIt != mSnapLines.constEnd(); ++sIt )
2250-
{
2251-
double x = ( *sIt )->line().x1();
2252-
double y = ( *sIt )->line().y1();
2253-
if ( qgsDoubleNear( y, 0.0 ) )
2254-
{
2255-
alignCoordsX.insert( x, 0 );
2256-
}
2257-
else
2258-
{
2259-
alignCoordsY.insert( y, 0 );
2260-
}
2261-
}
2262-
}
2263-
2264-
void QgsComposition::checkNearestItem( double checkCoord, const QMap< double, const QgsComposerItem* >& alignCoords, double& smallestDiff,
2265-
double itemCoordOffset, double& itemCoord, double& alignCoord ) const
2266-
{
2267-
double currentCoord = 0;
2268-
if ( !nearestItem( alignCoords, checkCoord, currentCoord ) )
2269-
{
2270-
return;
2271-
}
2272-
2273-
double currentDiff = abs( checkCoord - currentCoord );
2274-
if ( currentDiff < mAlignmentSnapTolerance )
2275-
{
2276-
itemCoord = currentCoord + itemCoordOffset;
2277-
alignCoord = currentCoord;
2278-
smallestDiff = currentDiff;
2279-
}
2280-
}
2281-
2282-
bool QgsComposition::nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value, double& nearestValue )
2283-
{
2284-
if ( coords.size() < 1 )
2285-
{
2286-
return false;
2287-
}
2288-
2289-
QMap< double, const QgsComposerItem* >::const_iterator it = coords.lowerBound( value );
2290-
if ( it == coords.constBegin() ) //value smaller than first map value
2291-
{
2292-
nearestValue = it.key();
2293-
return true;
2294-
}
2295-
else if ( it == coords.constEnd() ) //value larger than last map value
2296-
{
2297-
--it;
2298-
nearestValue = it.key();
2299-
return true;
2300-
}
2301-
else
2302-
{
2303-
//get smaller value and larger value and return the closer one
2304-
double upperVal = it.key();
2305-
--it;
2306-
double lowerVal = it.key();
2307-
2308-
double lowerDiff = value - lowerVal;
2309-
double upperDiff = upperVal - value;
2310-
if ( lowerDiff < upperDiff )
2311-
{
2312-
nearestValue = lowerVal;
2313-
return true;
2314-
}
2315-
else
2316-
{
2317-
nearestValue = upperVal;
2318-
return true;
2319-
}
2320-
}
2321-
}
2322-
23232147
void QgsComposition::computeWorldFileParameters( double& a, double& b, double& c, double& d, double& e, double& f ) const
23242148
{
23252149
//

‎src/core/composer/qgscomposition.h

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class QGraphicsRectItem;
4141
class QgsMapRenderer;
4242
class QDomElement;
4343
class QgsComposerArrow;
44+
class QgsComposerMouseHandles;
4445
class QgsComposerHtml;
4546
class QgsComposerItem;
4647
class QgsComposerLabel;
@@ -289,22 +290,11 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
289290
/**Snaps a scene coordinate point to grid*/
290291
QPointF snapPointToGrid( const QPointF& scenePoint ) const;
291292

292-
/**Snaps item position to align with other items (left / middle / right or top / middle / bottom
293-
@param item current item
294-
@param alignX x-coordinate of align or -1 if not aligned to x
295-
@param alignY y-coordinate of align or -1 if not aligned to y
296-
@param dx item shift in x direction
297-
@param dy item shift in y direction
298-
@return new upper left point after the align*/
299-
QPointF alignItem( const QgsComposerItem* item, double& alignX, double& alignY, double dx = 0, double dy = 0 );
300-
301-
/**Snaps position to align with the boundaries of other items
302-
@param pos position to snap
303-
@param excludeItem item to exclude
304-
@param alignX snapped x coordinate or -1 if not snapped
305-
@param alignY snapped y coordinate or -1 if not snapped
306-
@return snapped position or original position if no snap*/
307-
QPointF alignPos( const QPointF& pos, const QgsComposerItem* excludeItem, double& alignX, double& alignY );
293+
/**Returns pointer to snap lines collection*/
294+
QList< QGraphicsLineItem* >* snapLines() {return &mSnapLines;};
295+
296+
/**Returns pointer to selection handles*/
297+
QgsComposerMouseHandles* selectionHandles() {return mSelectionHandles;};
308298

309299
/**Add a custom snap line (can be horizontal or vertical)*/
310300
QGraphicsLineItem* addSnapLine();
@@ -441,6 +431,8 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
441431
/**Arbitraty snap lines (horizontal and vertical)*/
442432
QList< QGraphicsLineItem* > mSnapLines;
443433

434+
QgsComposerMouseHandles* mSelectionHandles;
435+
444436
QUndoStack mUndoStack;
445437

446438
QgsComposerItemCommand* mActiveItemCommand;
@@ -470,17 +462,6 @@ class CORE_EXPORT QgsComposition : public QGraphicsScene
470462

471463
static QString encodeStringForXML( const QString& str );
472464

473-
//helper functions for item align
474-
void collectAlignCoordinates( QMap< double, const QgsComposerItem* >& alignCoordsX,
475-
QMap< double, const QgsComposerItem* >& alignCoordsY, const QgsComposerItem* excludeItem );
476-
477-
void checkNearestItem( double checkCoord, const QMap< double, const QgsComposerItem* >& alignCoords, double& smallestDiff,
478-
double itemCoordOffset, double& itemCoord, double& alignCoord ) const;
479-
480-
/**Find nearest item in coordinate map to a double.
481-
@return true if item found, false if coords is empty*/
482-
static bool nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value, double& nearestValue );
483-
484465
signals:
485466
void paperSizeChanged();
486467
void nPagesChanged();

‎src/gui/qgscomposerview.cpp

Lines changed: 46 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "qgscomposerlabel.h"
3131
#include "qgscomposerlegend.h"
3232
#include "qgscomposermap.h"
33+
#include "qgscomposermousehandles.h"
3334
#include "qgscomposeritemgroup.h"
3435
#include "qgscomposerpicture.h"
3536
#include "qgscomposerruler.h"
@@ -77,9 +78,6 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
7778
bool lock = selectedItem->positionLock() ? false : true;
7879
selectedItem->setPositionLock( lock );
7980
selectedItem->update();
80-
//make sure the new cursor is correct
81-
QPointF itemPoint = selectedItem->mapFromScene( scenePoint );
82-
selectedItem->updateCursor( itemPoint );
8381
}
8482
return;
8583
}
@@ -89,7 +87,21 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
8987
//select/deselect items and pass mouse event further
9088
case Select:
9189
{
92-
QgsComposerItem* selectedItem;
90+
//check if we are clicking on a selection handle
91+
if ( composition()->selectionHandles()->isVisible() )
92+
{
93+
//selection handles are being shown, get mouse action for current cursor position
94+
QgsComposerMouseHandles::MouseAction mouseAction = composition()->selectionHandles()->mouseActionForScenePos( scenePoint );
95+
96+
if ( mouseAction != QgsComposerMouseHandles::MoveItem && mouseAction != QgsComposerMouseHandles::NoAction && mouseAction != QgsComposerMouseHandles::SelectItem )
97+
{
98+
//mouse is over a resize handle, so propagate event onward
99+
QGraphicsView::mousePressEvent( e );
100+
return;
101+
}
102+
}
103+
104+
QgsComposerItem* selectedItem = 0;
93105
QgsComposerItem* previousSelectedItem = 0;
94106

95107
if ( e->modifiers() & Qt::ControlModifier )
@@ -103,11 +115,6 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
103115
}
104116
}
105117

106-
if ( !( e->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed
107-
{
108-
composition()->clearSelection();
109-
}
110-
111118
if ( previousSelectedItem )
112119
{
113120
//select highest item just below previously selected item at position of event
@@ -128,9 +135,16 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
128135

129136
if ( !selectedItem )
130137
{
138+
composition()->clearSelection();
131139
break;
132140
}
133141

142+
if (( !selectedItem->selected() ) && //keep selection if an already selected item pressed
143+
!( e->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed
144+
{
145+
composition()->clearSelection();
146+
}
147+
134148
if (( e->modifiers() & Qt::ShiftModifier ) && ( selectedItem->selected() ) )
135149
{
136150
//SHIFT-clicking a selected item deselects it
@@ -154,14 +168,31 @@ void QgsComposerView::mousePressEvent( QMouseEvent* e )
154168

155169
case MoveItemContent:
156170
{
157-
//store item as member if it is selected and cursor is over item
158-
QgsComposerItem* item = dynamic_cast<QgsComposerItem *>( itemAt( e->pos() ) );
159-
if ( item )
171+
//get a list of items at clicked position
172+
QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos() );
173+
if ( itemsAtCursorPos.size() == 0 )
160174
{
161-
mMoveContentStartPos = scenePoint;
175+
//no items at clicked position
176+
return;
162177
}
163-
mMoveContentItem = item;
164-
break;
178+
179+
//find highest QgsComposerItem at clicked position
180+
//(other graphics items may be higher, eg selection handles)
181+
QList<QGraphicsItem*>::iterator itemIter = itemsAtCursorPos.begin();
182+
for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
183+
{
184+
QgsComposerItem* item = dynamic_cast<QgsComposerItem *>(( *itemIter ) );
185+
if ( item )
186+
{
187+
//we've found the highest QgsComposerItem
188+
mMoveContentStartPos = scenePoint;
189+
mMoveContentItem = item;
190+
break;
191+
}
192+
}
193+
194+
//no QgsComposerItem at clicked position
195+
return;
165196
}
166197

167198
case AddArrow:

0 commit comments

Comments
 (0)
Please sign in to comment.