1 // Copyright (C) 2013-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "GraphicsView_ViewPort.h"
22 #include "GraphicsView_Object.h"
23 #include "GraphicsView_Scene.h"
24 #include "GraphicsView_ViewTransformer.h"
26 #include "SUIT_ResourceMgr.h"
27 #include "SUIT_Session.h"
30 #include <QGraphicsSceneMouseEvent>
31 #include <QGridLayout>
35 #include <QRubberBand>
42 #define FOREGROUND_Z_VALUE -2
43 #define GRID_Z_VALUE -1
44 #define SKETCH_Z_VALUE 3000
46 int GraphicsView_ViewPort::nCounter = 0;
47 QCursor* GraphicsView_ViewPort::defCursor = 0;
48 QCursor* GraphicsView_ViewPort::handCursor = 0;
49 QCursor* GraphicsView_ViewPort::panCursor = 0;
50 QCursor* GraphicsView_ViewPort::panglCursor = 0;
51 QCursor* GraphicsView_ViewPort::zoomCursor = 0;
52 QCursor* GraphicsView_ViewPort::sketchCursor = 0;
54 //=======================================================================
55 // Name : GraphicsView_ViewPort::ViewLabel
56 // Purpose : Wrapper for label, which can ignore move events sent from
57 // QGraphicsView::scrollContentsBy() method, which,
58 // in its turn, called from GraphicsView_ViewPort::pan()
59 //=======================================================================
60 class GraphicsView_ViewPort::ViewLabel : public QLabel
63 ViewLabel( QWidget* theParent )
64 : QLabel( theParent ),
65 myAcceptMoveEvents( false )
70 void setAcceptMoveEvents( bool theFlag )
72 myAcceptMoveEvents = theFlag;
76 virtual void moveEvent( QMoveEvent* theEvent )
78 if( myAcceptMoveEvents )
79 QLabel::moveEvent( theEvent );
80 else // return the label to the initial position
82 myAcceptMoveEvents = true;
83 move( theEvent->oldPos() );
84 myAcceptMoveEvents = false;
89 bool myAcceptMoveEvents;
92 //================================================================
93 // Function : createCursors
95 //================================================================
96 void GraphicsView_ViewPort::createCursors ()
98 defCursor = new QCursor( Qt::ArrowCursor );
99 handCursor = new QCursor( Qt::PointingHandCursor );
100 panCursor = new QCursor( Qt::SizeAllCursor );
101 panglCursor = new QCursor( Qt::CrossCursor );
103 SUIT_ResourceMgr* rmgr = SUIT_Session::session()->resourceMgr();
104 zoomCursor = new QCursor( rmgr->loadPixmap( "GraphicsView", tr( "ICON_GV_CURSOR_ZOOM" ) ) );
106 sketchCursor = new QCursor( Qt::CrossCursor );
109 //================================================================
110 // Function : destroyCursors
112 //================================================================
113 void GraphicsView_ViewPort::destroyCursors()
115 delete defCursor; defCursor = 0;
116 delete handCursor; handCursor = 0;
117 delete panCursor; panCursor = 0;
118 delete panglCursor; panglCursor = 0;
119 delete zoomCursor; zoomCursor = 0;
120 delete sketchCursor; sketchCursor = 0;
123 //=======================================================================
124 // Name : GraphicsView_ViewPort
125 // Purpose : Constructor
126 //=======================================================================
127 GraphicsView_ViewPort::GraphicsView_ViewPort( QWidget* theParent )
128 : QGraphicsView( theParent ),
129 myInteractionFlags( 0 ),
131 myViewLabelPosition( VLP_None ),
132 myViewLabelLayout( 0 ),
133 myIsMousePositionEnabled( false ),
134 myForegroundItem( 0 ),
136 myIsTransforming( false ),
137 myHighlightedObject( 0 ),
140 myIsHighlighting( false ),
141 mySelectionIterator( 0 ),
143 myAreSelectionPointsInitialized( false ),
144 mySketchingItem( 0 ),
145 myIsPrepareToSketch( false ),
146 myIsSketching( false ),
147 myIsSketchingByPath( false ),
148 myIsDragging( false ),
149 myIsDragPositionInitialized( false ),
150 myIsPulling( false ),
151 myPullingObject( 0 ),
152 myStoredCursor( Qt::ArrowCursor )
155 myScene = new GraphicsView_Scene( this );
162 setInteractionFlags( EditFlags );
163 //setInteractionFlag( TraceBoundingRect );
164 //setInteractionFlag( DraggingByMiddleButton );
165 //setInteractionFlag( ImmediateContextMenu );
166 //setInteractionFlag( ImmediateSelection );
167 //setInteractionFlag( Sketching );
170 setBackgroundBrush( QBrush( Qt::white ) );
173 myIsForegroundEnabled = false;
174 myForegroundSize = QSizeF( 100, 30 );
175 myForegroundMargin = 0.0;
176 myForegroundColor = Qt::white;
177 myForegroundFrameColor = Qt::black;
178 myForegroundFrameLineWidth = 1.0;
181 myIsGridEnabled = false;
182 myGridCellSize = 100;
183 myGridLineStyle = Qt::DotLine;
184 myGridLineColor = Qt::darkGray;
186 // default index method (BspTreeIndex) leads to
187 // crashes in QGraphicsView::paintEvent() method
188 myScene->setItemIndexMethod( QGraphicsScene::NoIndex );
190 // render hints (default - TextAntialiasing only)
191 setRenderHints( QPainter::Antialiasing |
192 QPainter::TextAntialiasing |
193 QPainter::SmoothPixmapTransform |
194 QPainter::HighQualityAntialiasing );
196 connect( myScene, SIGNAL( gsKeyEvent( QKeyEvent* ) ),
197 this, SLOT( onKeyEvent( QKeyEvent* ) ) );
198 connect( myScene, SIGNAL( gsMouseEvent( QGraphicsSceneMouseEvent* ) ),
199 this, SLOT( onMouseEvent( QGraphicsSceneMouseEvent* ) ) );
200 connect( myScene, SIGNAL( gsWheelEvent( QGraphicsSceneWheelEvent* ) ),
201 this, SLOT( onWheelEvent( QGraphicsSceneWheelEvent* ) ) );
202 connect( myScene, SIGNAL( gsContextMenuEvent( QGraphicsSceneContextMenuEvent* ) ),
203 this, SLOT( onContextMenuEvent( QGraphicsSceneContextMenuEvent* ) ) );
205 connect( myScene, SIGNAL( gsBoundingRectChanged() ),
206 this, SLOT( onBoundingRectChanged() ) );
211 //=======================================================================
212 // Name : GraphicsView_ViewPort
213 // Purpose : Destructor
214 //=======================================================================
215 GraphicsView_ViewPort::~GraphicsView_ViewPort()
226 //================================================================
227 // Function : initialize
229 //================================================================
230 void GraphicsView_ViewPort::initialize()
232 if ( nCounter++ == 0 )
235 setMouseTracking( true );
236 setFocusPolicy( Qt::StrongFocus );
239 //================================================================
240 // Function : cleanup
242 //================================================================
243 void GraphicsView_ViewPort::cleanup()
245 if ( --nCounter == 0 )
249 //================================================================
250 // Function : addItem
252 //================================================================
253 void GraphicsView_ViewPort::addItem( QGraphicsItem* theItem )
255 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
257 int aPriority = anObject->getPriority();
258 GraphicsView_ObjectList::iterator anIter, anIterEnd = myObjects.end();
259 for( anIter = myObjects.begin(); anIter != anIterEnd; anIter++ )
261 if( GraphicsView_Object* anObjectRef = *anIter )
263 if( anObjectRef->getPriority() > aPriority )
267 myObjects.insert( anIter, anObject );
268 anObject->setViewTransform( transform() );
269 anObject->addTo( this );
272 myScene->addItem( theItem );
273 onBoundingRectChanged();
276 //================================================================
277 // Function : isItemAdded
279 //================================================================
280 bool GraphicsView_ViewPort::isItemAdded( QGraphicsItem* theItem )
282 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
284 for( GraphicsView_ObjectList::iterator anIter = myObjects.begin(); anIter != myObjects.end(); anIter++ )
285 if( theItem == *anIter )
289 for( int i = 0; i < myScene->items().size(); i++ )
290 if( theItem == myScene->items().at(i) )
296 //================================================================
297 // Function : removeItem
299 //================================================================
300 void GraphicsView_ViewPort::removeItem( QGraphicsItem* theItem )
302 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
304 if( myHighlightedObject == anObject )
305 myHighlightedObject = 0;
306 mySelectedObjects.removeAll( anObject );
307 myObjects.removeAll( anObject );
308 anObject->removeFrom( this );
311 myScene->removeItem( theItem );
312 onBoundingRectChanged();
315 //================================================================
316 // Function : getObjects
318 //================================================================
319 GraphicsView_ObjectList GraphicsView_ViewPort::getObjects( SortType theSortType ) const
321 if( theSortType == SelectedFirst )
323 // to append selected objects after their non-selected siblings with similar priority
324 int aCurrentPriority = -1;
325 GraphicsView_ObjectList aSelectedObjects;
326 GraphicsView_ObjectList aTopmostObjects;
328 GraphicsView_ObjectList aList;
329 GraphicsView_ObjectListIterator anIter( myObjects );
330 while( anIter.hasNext() )
332 if( GraphicsView_Object* anObject = anIter.next() )
334 if( anObject->isOnTop() )
336 aTopmostObjects.append( anObject );
340 int aPriority = anObject->getPriority();
341 if( aPriority > aCurrentPriority )
343 if( !aSelectedObjects.isEmpty() )
345 aList.append( aSelectedObjects );
346 aSelectedObjects.clear();
348 aCurrentPriority = aPriority;
351 if( anObject->isSelected() )
352 aSelectedObjects.append( anObject );
354 aList.append( anObject );
358 // for selected objects with highest priority,
359 // which were not pushed to the result list yet
360 if( !aSelectedObjects.isEmpty() )
362 aList.append( aSelectedObjects );
363 aSelectedObjects.clear();
366 aList.append( aTopmostObjects );
371 if( theSortType == SortByZLevel ) // double loop, needs to be optimized
373 GraphicsView_ObjectList aList;
375 GraphicsView_ObjectListIterator anIter( myObjects );
376 while( anIter.hasNext() )
378 if( GraphicsView_Object* anObject = anIter.next() )
380 double aZValue = anObject->zValue();
381 GraphicsView_ObjectList::iterator anIter1, anIter1End = aList.end();
382 for( anIter1 = aList.begin(); anIter1 != anIter1End; anIter1++ )
383 if( GraphicsView_Object* anObjectRef = *anIter1 )
384 if( anObjectRef->zValue() > aZValue )
386 aList.insert( anIter1, anObject );
392 return myObjects; // theSortType == NoSorting
395 //================================================================
396 // Function : objectsBoundingRect
398 //================================================================
399 QRectF GraphicsView_ViewPort::objectsBoundingRect( bool theOnlyVisible ) const
402 QListIterator<QGraphicsItem*> anIter( items() );
403 while( anIter.hasNext() )
405 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
407 if( theOnlyVisible && !anObject->isVisible() )
410 QRectF anObjectRect = anObject->getRect();
411 if( !anObjectRect.isNull() )
414 aRect = anObject->getRect();
416 aRect |= anObject->getRect();
423 //================================================================
424 // Function : dumpView
426 //================================================================
427 QImage GraphicsView_ViewPort::dumpView( bool theWholeScene,
430 if( !theWholeScene ) // just grab the view contents
432 QPixmap aPixmap = QPixmap::grabWindow( viewport()->winId() );
433 return aPixmap.toImage();
436 // get a bounding rect of all presented objects
437 // (itemsBoundingRect() method is unsuitable)
438 QRectF aRect = objectsBoundingRect();
442 QRectF aTargetRect( 0, 0, aRect.width(), aRect.height() );
443 if( theSize.isValid() )
445 double aRatioX = theSize.width() / aTargetRect.width();
446 double aRatioY = theSize.height() / aTargetRect.height();
447 double aRatio = qMin( aRatioX, aRatioY );
448 aTargetRect.setWidth( aTargetRect.width() * aRatio );
449 aTargetRect.setHeight( aTargetRect.height() * aRatio );
452 // render the scene to an image
453 QImage anImage( aTargetRect.toRect().size(), QImage::Format_RGB32 );
454 QPainter aPainter( &anImage );
455 aPainter.setRenderHints( renderHints() );
457 myScene->render( &aPainter, aTargetRect, aRect );
462 bool GraphicsView_ViewPort::dumpViewToPSFormat(const QString& fileName)
464 QPrinter printer(QPrinter::HighResolution);
465 printer.setOutputFormat(QPrinter::PostScriptFormat);
466 printer.setOutputFileName(fileName);
468 if (!painter.begin(&printer))
471 QRect view( 0, 0, printer.pageRect().width(), printer.paperRect().height() );
472 QRectF bounds = myScene->itemsBoundingRect();
474 if( !view.isEmpty() && !bounds.isEmpty() )
476 float SCALE = 0.5;//qMin( view.width()/bounds.width(), view.height()/bounds.height() );
477 painter.setViewport( view );
478 painter.scale( SCALE, SCALE );
480 myScene->render( &painter, QRectF( view ), bounds );
487 //================================================================
488 // Function : setSceneGap
490 //================================================================
491 void GraphicsView_ViewPort::setSceneGap( double theSceneGap )
493 mySceneGap = theSceneGap;
494 onBoundingRectChanged();
497 //================================================================
498 // Function : setFitAllGap
500 //================================================================
501 void GraphicsView_ViewPort::setFitAllGap( double theFitAllGap )
503 myFitAllGap = theFitAllGap;
506 //================================================================
507 // Function : interactionFlags
509 //================================================================
510 int GraphicsView_ViewPort::interactionFlags() const
512 return myInteractionFlags;
515 //================================================================
516 // Function : hasInteractionFlag
518 //================================================================
519 bool GraphicsView_ViewPort::hasInteractionFlag( InteractionFlag theFlag )
521 return ( interactionFlags() & theFlag ) == theFlag;
524 //================================================================
525 // Function : setInteractionFlag
527 //================================================================
528 void GraphicsView_ViewPort::setInteractionFlag( InteractionFlag theFlag,
532 setInteractionFlags( myInteractionFlags | theFlag );
534 setInteractionFlags( myInteractionFlags & ~theFlag );
537 //================================================================
538 // Function : setInteractionFlags
540 //================================================================
541 void GraphicsView_ViewPort::setInteractionFlags( InteractionFlags theFlags )
543 myInteractionFlags = theFlags;
546 //================================================================
547 // Function : setViewLabelPosition
549 //================================================================
550 void GraphicsView_ViewPort::setViewLabelPosition( ViewLabelPosition thePosition,
553 if( theIsForced && !myViewLabel )
554 myViewLabel = new ViewLabel( viewport() );
559 if( thePosition == VLP_None )
561 myViewLabel->setVisible( false );
565 if( myViewLabelLayout )
566 delete myViewLabelLayout;
568 myViewLabelLayout = new QGridLayout( viewport() );
569 myViewLabelLayout->setMargin( 10 );
570 myViewLabelLayout->setSpacing( 0 );
572 int aRow = 0, aColumn = 0;
573 switch( thePosition )
575 case VLP_TopLeft: aRow = 0; aColumn = 0; break;
576 case VLP_TopRight: aRow = 0; aColumn = 1; break;
577 case VLP_BottomLeft: aRow = 1; aColumn = 0; break;
578 case VLP_BottomRight: aRow = 1; aColumn = 1; break;
582 myViewLabelLayout->addWidget( myViewLabel, aRow, aColumn );
583 myViewLabelLayout->setRowStretch( 1 - aRow, 1 );
584 myViewLabelLayout->setColumnStretch( 1 - aColumn, 1 );
586 myViewLabel->setVisible( true );
589 //================================================================
590 // Function : setViewLabelText
592 //================================================================
593 void GraphicsView_ViewPort::setViewLabelText( const QString& theText )
596 myViewLabel->setText( theText );
599 //================================================================
600 // Function : setMousePositionEnabled
602 //================================================================
603 void GraphicsView_ViewPort::setMousePositionEnabled( bool theState )
605 myIsMousePositionEnabled = theState;
609 setViewLabelPosition( VLP_BottomLeft, true );
611 int aMouseX = 0, aMouseY = 0;
612 setViewLabelText( QString( "(%1, %2)" ).arg( aMouseX ).arg( aMouseY ) );
615 setViewLabelPosition( VLP_None );
618 //================================================================
619 // Function : backgroundColor
621 //================================================================
622 QColor GraphicsView_ViewPort::backgroundColor() const
624 return backgroundBrush().color();
627 //================================================================
628 // Function : setBackgroundColor
630 //================================================================
631 void GraphicsView_ViewPort::setBackgroundColor( const QColor& theColor )
633 setBackgroundBrush( QBrush( theColor ) );
636 //================================================================
637 // Function : setForegroundEnabled
639 //================================================================
640 void GraphicsView_ViewPort::setForegroundEnabled( bool theState )
642 myIsForegroundEnabled = theState;
645 //================================================================
646 // Function : setForegroundSize
648 //================================================================
649 void GraphicsView_ViewPort::setForegroundSize( const QSizeF& theSize )
651 myForegroundSize = theSize;
654 //================================================================
655 // Function : setForegroundMargin
657 //================================================================
658 void GraphicsView_ViewPort::setForegroundMargin( double theMargin )
660 myForegroundMargin = theMargin;
663 //================================================================
664 // Function : setForegroundColor
666 //================================================================
667 void GraphicsView_ViewPort::setForegroundColor( const QColor& theColor )
669 myForegroundColor = theColor;
672 //================================================================
673 // Function : setForegroundFrameColor
675 //================================================================
676 void GraphicsView_ViewPort::setForegroundFrameColor( const QColor& theColor )
678 myForegroundFrameColor = theColor;
681 //================================================================
682 // Function : setForegroundFrameLineWidth
684 //================================================================
685 void GraphicsView_ViewPort::setForegroundFrameLineWidth( double theLineWidth )
687 myForegroundFrameLineWidth = theLineWidth;
690 //================================================================
691 // Function : updateForeground
693 //================================================================
694 void GraphicsView_ViewPort::updateForeground()
696 if( myIsForegroundEnabled )
698 if( !myForegroundItem )
699 myForegroundItem = myScene->addRect( QRectF(), QPen(), QBrush( Qt::white ) );
700 myForegroundItem->setZValue( FOREGROUND_Z_VALUE );
702 QPointF aPoint = QPointF();
703 QRectF aRect( aPoint, myForegroundSize );
704 aRect.adjust( -myForegroundMargin, -myForegroundMargin,
705 myForegroundMargin, myForegroundMargin );
706 myForegroundItem->setRect( aRect );
708 QBrush aBrush = myForegroundItem->brush();
709 aBrush.setColor( myForegroundColor );
710 myForegroundItem->setBrush( aBrush );
712 QPen aPen = myForegroundItem->pen();
713 aPen.setColor( myForegroundFrameColor );
714 aPen.setWidthF( myForegroundFrameLineWidth );
715 myForegroundItem->setPen( aPen );
717 myForegroundItem->setVisible( true );
719 myScene->setSceneRect( aRect.adjusted( -mySceneGap, -mySceneGap, mySceneGap, mySceneGap ) );
723 if( myForegroundItem )
724 myForegroundItem->setVisible( false );
727 updateGrid(); // foreground size could be changed
730 //================================================================
731 // Function : setGridEnabled
733 //================================================================
734 void GraphicsView_ViewPort::setGridEnabled( bool theState )
736 myIsGridEnabled = theState;
739 //================================================================
740 // Function : setGridCellSize
742 //================================================================
743 void GraphicsView_ViewPort::setGridCellSize( int theCellSize )
745 myGridCellSize = theCellSize;
748 //================================================================
749 // Function : setGridLineStyle
751 //================================================================
752 void GraphicsView_ViewPort::setGridLineStyle( int theLineStyle )
754 myGridLineStyle = theLineStyle;
757 //================================================================
758 // Function : setGridLineColor
760 //================================================================
761 void GraphicsView_ViewPort::setGridLineColor( const QColor& theLineColor )
763 myGridLineColor = theLineColor;
766 //================================================================
767 // Function : updateGrid
769 //================================================================
770 void GraphicsView_ViewPort::updateGrid()
772 if( myIsGridEnabled )
775 myGridItem = myScene->addPath( QPainterPath() );
776 myGridItem->setZValue( GRID_Z_VALUE );
778 double aWidth = myForegroundSize.width();
779 double aHeight = myForegroundSize.height();
781 int aGridNbX = int( aWidth / myGridCellSize ) + 1;
782 int aGridNbY = int( aHeight / myGridCellSize ) + 1;
786 for( anIndex = 0; anIndex < aGridNbX; anIndex++ )
788 double x = myGridCellSize * (double)anIndex;
789 aPath.moveTo( x, 0 );
790 aPath.lineTo( x, aHeight );
792 for( anIndex = 0; anIndex < aGridNbY; anIndex++ )
794 double y = myGridCellSize * (double)anIndex;
795 aPath.moveTo( 0, y );
796 aPath.lineTo( aWidth, y );
798 myGridItem->setPath( aPath );
800 QPen aPen = myGridItem->pen();
801 aPen.setStyle( (Qt::PenStyle)myGridLineStyle );
802 aPen.setColor( myGridLineColor );
803 myGridItem->setPen( aPen );
805 myGridItem->setVisible( true );
810 myGridItem->setVisible( false );
814 //================================================================
817 //================================================================
818 void GraphicsView_ViewPort::reset()
823 //================================================================
826 //================================================================
827 void GraphicsView_ViewPort::pan( double theDX, double theDY )
829 myIsTransforming = true;
832 myViewLabel->setAcceptMoveEvents( false );
834 if( QScrollBar* aHBar = horizontalScrollBar() )
835 aHBar->setValue( aHBar->value() - theDX );
836 if( QScrollBar* aVBar = verticalScrollBar() )
837 aVBar->setValue( aVBar->value() + theDY );
840 myViewLabel->setAcceptMoveEvents( true );
842 myIsTransforming = false;
847 //================================================================
848 // Function : setCenter
850 //================================================================
851 void GraphicsView_ViewPort::setCenter( double theX, double theY )
853 myIsTransforming = true;
855 setTransform( myCurrentTransform );
856 centerOn( theX, theY );
858 myIsTransforming = false;
863 //================================================================
866 //================================================================
867 void GraphicsView_ViewPort::zoom( double theX1, double theY1, double theX2, double theY2 )
869 myIsTransforming = true;
871 double aDX = theX2 - theX1;
872 double aDY = theY2 - theY1;
873 double aZoom = sqrt( aDX * aDX + aDY * aDY ) / 100 + 1;
874 aZoom = ( aDX > 0 ) ? aZoom : 1 / aZoom;
876 QTransform aTransform = transform();
877 aTransform.scale( aZoom, aZoom );
878 double aM11 = aTransform.m11();
879 double aM22 = aTransform.m22();
880 // increasing of diagonal coefficients (>300) leads to a crash sometimes
881 // at the values of 100 some primitives are drawn incorrectly
882 if( qMax( aM11, aM22 ) < 100 )
883 setTransform( aTransform );
885 myIsTransforming = false;
890 //================================================================
891 // Function : fitRect
893 //================================================================
894 void GraphicsView_ViewPort::fitRect( const QRectF& theRect )
896 myIsTransforming = true;
898 fitInView( theRect, Qt::KeepAspectRatio );
900 myIsTransforming = false;
905 //================================================================
906 // Function : fitSelect
908 //================================================================
909 void GraphicsView_ViewPort::fitSelect()
911 myIsTransforming = true;
914 for( initSelected(); moreSelected(); nextSelected() )
916 if( GraphicsView_Object* aMovingObject = selectedObject() )
918 QRectF aRect = aMovingObject->getRect();
919 if( aGlobalRect.isNull() )
922 aGlobalRect |= aRect;
926 if( !aGlobalRect.isNull() )
928 double aGap = qMax( aGlobalRect.width(), aGlobalRect.height() ) / 5;
929 aGlobalRect.adjust( -aGap, -aGap, aGap, aGap );
930 fitInView( aGlobalRect, Qt::KeepAspectRatio );
933 myIsTransforming = false;
938 //================================================================
941 //================================================================
942 void GraphicsView_ViewPort::fitAll( bool theKeepScale )
944 myIsTransforming = true;
947 myCurrentTransform = transform();
949 double aGap = myFitAllGap;
950 QRectF aRect = objectsBoundingRect( true );
951 fitInView( aRect.adjusted( -aGap, -aGap, aGap, aGap ), Qt::KeepAspectRatio );
953 myIsTransforming = false;
958 //================================================================
959 // Function : fitWidth
961 //================================================================
962 void GraphicsView_ViewPort::fitWidth()
964 myIsTransforming = true;
966 double aGap = myFitAllGap;
967 QRectF aRect = objectsBoundingRect( true );
969 double aTop = aRect.top();
970 double aLeft = aRect.left();
973 aRect.setY( aRect.center().y() );
974 aRect.setHeight( aMargin );
976 fitInView( aRect.adjusted( -aGap, -aGap, aGap, aGap ), Qt::KeepAspectRatio );
977 ensureVisible( aLeft, aTop, aMargin, aMargin, 0, aGap );
979 myIsTransforming = false;
984 //================================================================
985 // Function : applyTransform
987 //================================================================
988 void GraphicsView_ViewPort::applyTransform()
990 GraphicsView_ObjectListIterator anIter( getObjects() );
991 while( anIter.hasNext() )
992 if( GraphicsView_Object* anObject = anIter.next() )
993 anObject->setViewTransform( transform() );
996 //================================================================
997 // Function : currentBlock
999 //================================================================
1000 GraphicsView_ViewPort::BlockStatus GraphicsView_ViewPort::currentBlock()
1002 if( isDragging() && !myDragPosition.isNull() )
1003 return BlockStatus( BS_Selection );
1005 if( myAreSelectionPointsInitialized && ( myFirstSelectionPoint != myLastSelectionPoint ) )
1006 return BlockStatus( BS_Selection );
1009 return BlockStatus( BS_Selection );
1014 //================================================================
1015 // Function : highlight
1017 //================================================================
1018 void GraphicsView_ViewPort::highlight( double theX, double theY )
1020 myIsHighlighting = true;
1021 myHighlightX = theX;
1022 myHighlightY = theY;
1024 bool anIsHighlighted = false;
1025 bool anIsOnObject = false;
1027 GraphicsView_Object* aPreviousHighlightedObject = myHighlightedObject;
1028 GraphicsView_Object* aHighlightedObject = 0;
1032 GraphicsView_ObjectList aList = getObjects( SortByZLevel );
1033 GraphicsView_ObjectListIterator anIter( aList );
1034 anIter.toBack(); // objects with higher priority have to be checked earlier
1035 while( anIter.hasPrevious() )
1037 if( GraphicsView_Object* anObject = anIter.previous() )
1039 if( anObject->isVisible() && anObject->isSelectable() )
1041 if( anObject->checkHighlight( theX, theY, aCursor ) )
1043 anIsOnObject = true;
1044 anIsHighlighted = anObject->highlight( theX, theY );
1047 if( anIsHighlighted )
1049 aHighlightedObject = anObject;
1056 setCursor( aCursor );
1061 while( anIter.hasNext() )
1062 if( GraphicsView_Object* anObject = anIter.next() )
1063 anObject->unhighlight();
1065 myHighlightedObject = 0;
1068 else if( !myHighlightedObject && anIsHighlighted )
1070 myHighlightedObject = aHighlightedObject;
1072 else if( myHighlightedObject && !anIsHighlighted )
1074 myHighlightedObject->unhighlight();
1075 myHighlightedObject = 0;
1077 else if( myHighlightedObject && anIsHighlighted )
1079 myHighlightedObject->highlight( theX, theY );
1080 if( myHighlightedObject != aHighlightedObject )
1082 myHighlightedObject->unhighlight();
1083 myHighlightedObject = aHighlightedObject;
1088 //================================================================
1089 // Function : clearHighlighted
1091 //================================================================
1092 void GraphicsView_ViewPort::clearHighlighted()
1094 if( myHighlightedObject )
1096 myHighlightedObject->unhighlight();
1097 myHighlightedObject = 0;
1101 //================================================================
1102 // Function : select
1104 //================================================================
1105 int GraphicsView_ViewPort::select( const QRectF& theRect, bool theIsAppend )
1107 if( !myIsHighlighting )
1108 return GVSS_NoChanged;
1110 GV_SelectionStatus aStatus = GVSS_Invalid;
1111 if( theRect.isNull() ) // point selection
1113 if( myHighlightedObject )
1115 if( mySelectedObjects.count() == 1 &&
1116 mySelectedObjects.first() == myHighlightedObject )
1117 aStatus = GVSS_LocalChanged;
1121 GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1122 while( anIter.hasNext() )
1123 if( GraphicsView_Object* anObject = anIter.next() )
1124 if( myHighlightedObject != anObject )
1125 anObject->unselect();
1127 if( !mySelectedObjects.isEmpty() && aStatus == GVSS_Invalid )
1128 aStatus = GVSS_GlobalChanged;
1129 mySelectedObjects.clear();
1131 else if( myHighlightedObject->isSelected() && aStatus != GVSS_LocalChanged )
1133 mySelectedObjects.removeAll( myHighlightedObject );
1134 myHighlightedObject->unselect();
1136 if( !mySelectedObjects.isEmpty() && aStatus == GVSS_Invalid )
1137 aStatus = GVSS_GlobalChanged;
1142 if( myHighlightedObject->select( myHighlightX, myHighlightY, QRectF() ) &&
1143 mySelectedObjects.indexOf( myHighlightedObject ) == -1 )
1145 mySelectedObjects.append( myHighlightedObject );
1146 if( aStatus == GVSS_Invalid )
1147 aStatus = GVSS_GlobalChanged;
1149 else if( aStatus == GVSS_LocalChanged )
1150 aStatus = GVSS_GlobalChanged;
1155 if( !myHighlightedObject )
1159 GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1160 while( anIter.hasNext() )
1161 if( GraphicsView_Object* anObject = anIter.next() )
1162 if( myHighlightedObject != anObject )
1163 anObject->unselect();
1165 if( !mySelectedObjects.isEmpty() )
1166 aStatus = GVSS_GlobalChanged;
1167 mySelectedObjects.clear();
1172 return GVSS_NoChanged;
1174 else // rectangle selection
1176 aStatus = GVSS_NoChanged;
1178 bool updateAll = false;
1181 if( !mySelectedObjects.isEmpty() )
1182 aStatus = GVSS_GlobalChanged;
1184 GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1185 while( anIter.hasNext() )
1186 if( GraphicsView_Object* anObject = anIter.next() )
1187 if( myHighlightedObject != anObject )
1188 anObject->unselect();
1189 mySelectedObjects.clear();
1192 QListIterator<QGraphicsItem*> anIter( items() );
1193 while( anIter.hasNext() )
1195 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1197 if( anObject->isVisible() && anObject->isSelectable() )
1199 bool anIsSelected = false;
1200 QRectF aRect = anObject->getRect();
1201 if( theRect.contains( aRect ) && myIsHighlighting )
1202 anIsSelected = anObject->select( myHighlightX, myHighlightY, theRect );
1204 if( anIsSelected && mySelectedObjects.indexOf( anObject ) == -1 )
1206 mySelectedObjects.append( anObject );
1207 aStatus = GVSS_GlobalChanged;
1216 //================================================================
1217 // Function : clearSelected
1219 //================================================================
1220 void GraphicsView_ViewPort::clearSelected()
1222 GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1223 while( anIter.hasNext() )
1224 if( GraphicsView_Object* anObject = anIter.next() )
1225 anObject->unselect();
1226 mySelectedObjects.clear();
1229 //================================================================
1230 // Function : setSelected
1232 //================================================================
1233 void GraphicsView_ViewPort::setSelected( GraphicsView_Object* theObject )
1237 theObject->setSelected( true );
1238 mySelectedObjects.append( theObject );
1242 //================================================================
1243 // Function : nbSelected
1245 //================================================================
1246 int GraphicsView_ViewPort::nbSelected() const
1248 return mySelectedObjects.count();
1251 //================================================================
1252 // Function : initSelected
1254 //================================================================
1255 void GraphicsView_ViewPort::initSelected()
1257 mySelectionIterator = 0;
1260 //================================================================
1261 // Function : moreSelected
1263 //================================================================
1264 bool GraphicsView_ViewPort::moreSelected()
1266 return mySelectionIterator < nbSelected();
1269 //================================================================
1270 // Function : nextSelected
1272 //================================================================
1273 bool GraphicsView_ViewPort::nextSelected()
1275 if( mySelectionIterator >= 0 && mySelectionIterator < nbSelected() )
1277 mySelectionIterator++;
1283 //================================================================
1284 // Function : selectedObject
1286 //================================================================
1287 GraphicsView_Object* GraphicsView_ViewPort::selectedObject()
1289 if( mySelectionIterator >= 0 && mySelectionIterator < nbSelected() )
1290 return mySelectedObjects[ mySelectionIterator ];
1294 //================================================================
1295 // Function : startSelectByRect
1297 //================================================================
1298 void GraphicsView_ViewPort::startSelectByRect( int x, int y )
1300 if( !myAreSelectionPointsInitialized )
1302 myFirstSelectionPoint = QPoint( x, y );
1303 myLastSelectionPoint = QPoint( x, y );
1304 myAreSelectionPointsInitialized = true;
1309 myRectBand = new QRubberBand( QRubberBand::Rectangle, this );
1311 palette.setColor( myRectBand->foregroundRole(), Qt::white );
1312 myRectBand->setPalette( palette );
1317 //================================================================
1318 // Function : drawSelectByRect
1320 //================================================================
1321 void GraphicsView_ViewPort::drawSelectByRect( int x, int y )
1323 if( myAreSelectionPointsInitialized )
1327 myLastSelectionPoint.setX( x );
1328 myLastSelectionPoint.setY( y );
1330 QRect aRect = selectionRect();
1331 myRectBand->setGeometry( aRect );
1332 myRectBand->setVisible( aRect.isValid() );
1336 //================================================================
1337 // Function : isSelectByRect
1339 //================================================================
1340 bool GraphicsView_ViewPort::isSelectByRect() const
1342 return myAreSelectionPointsInitialized;
1345 //================================================================
1346 // Function : finishSelectByRect
1348 //================================================================
1349 void GraphicsView_ViewPort::finishSelectByRect()
1351 if( myAreSelectionPointsInitialized )
1360 myAreSelectionPointsInitialized = false;
1364 //================================================================
1365 // Function : selectionRect
1367 //================================================================
1368 QRect GraphicsView_ViewPort::selectionRect()
1371 if( myAreSelectionPointsInitialized )
1373 aRect.setLeft( qMin( myFirstSelectionPoint.x(), myLastSelectionPoint.x() ) );
1374 aRect.setTop( qMin( myFirstSelectionPoint.y(), myLastSelectionPoint.y() ) );
1375 aRect.setRight( qMax( myFirstSelectionPoint.x(), myLastSelectionPoint.x() ) );
1376 aRect.setBottom( qMax( myFirstSelectionPoint.y(), myLastSelectionPoint.y() ) );
1381 //================================================================
1382 // Function : prepareToSketch
1384 //================================================================
1385 void GraphicsView_ViewPort::prepareToSketch( bool theStatus )
1387 myIsPrepareToSketch = theStatus;
1389 setCursor( *getSketchCursor() );
1392 //================================================================
1393 // Function : isPrepareToSketch
1395 //================================================================
1396 bool GraphicsView_ViewPort::isPrepareToSketch()
1398 return myIsPrepareToSketch;
1401 //================================================================
1402 // Function : startSketching
1404 //================================================================
1405 void GraphicsView_ViewPort::startSketching( const QPointF& thePoint,
1408 prepareToSketch( false );
1410 if( !mySketchingItem )
1412 mySketchingItem = new QGraphicsPathItem();
1413 mySketchingItem->setZValue( SKETCH_Z_VALUE );
1415 QPen aPen = mySketchingItem->pen();
1416 aPen.setStyle( Qt::DotLine );
1417 mySketchingItem->setPen( aPen );
1419 addItem( mySketchingItem );
1422 mySketchingPoint = thePoint;
1425 aPath.moveTo( mySketchingPoint );
1426 mySketchingItem->setPath( aPath );
1427 mySketchingItem->setVisible( true );
1429 myIsSketching = true;
1430 myIsSketchingByPath = theIsPath;
1433 //================================================================
1434 // Function : drawSketching
1436 //================================================================
1437 void GraphicsView_ViewPort::drawSketching( const QPointF& thePoint )
1439 bool anIsPath = false;
1440 if( mySketchingItem && isSketching( &anIsPath ) )
1442 QPainterPath aPath = mySketchingItem->path();
1443 if( anIsPath ) // arbitrary path
1444 aPath.lineTo( thePoint );
1447 // make a valid rectangle
1448 double x1 = mySketchingPoint.x(), y1 = mySketchingPoint.y();
1449 double x2 = thePoint.x(), y2 = thePoint.y();
1450 QPointF aPoint1( qMin( x1, x2 ), qMin( y1, y2 ) );
1451 QPointF aPoint2( qMax( x1, x2 ), qMax( y1, y2 ) );
1452 QRectF aRect( aPoint1, aPoint2 );
1454 aPath = QPainterPath();
1455 aPath.addRect( aRect );
1457 mySketchingItem->setPath( aPath );
1461 //================================================================
1462 // Function : finishSketching
1464 //================================================================
1465 void GraphicsView_ViewPort::finishSketching( bool theStatus )
1467 prepareToSketch( false );
1469 mySketchingItem->setVisible( false );
1470 myIsSketching = false;
1472 setCursor( *getDefaultCursor() );
1476 QPainterPath aPath = mySketchingItem->path();
1477 emit vpSketchingFinished( aPath );
1481 //================================================================
1482 // Function : isSketching
1484 //================================================================
1485 bool GraphicsView_ViewPort::isSketching( bool* theIsPath ) const
1488 *theIsPath = myIsSketchingByPath;
1489 return myIsSketching;
1492 //================================================================
1493 // Function : dragObjects
1495 //================================================================
1496 void GraphicsView_ViewPort::dragObjects( QGraphicsSceneMouseEvent* e )
1498 GraphicsView_Object* anObject = getHighlightedObject();
1500 if( myDragPosition.isNull() )
1502 myDragPosition = e->scenePos();
1506 GraphicsView_ObjectList anObjectsToMove;
1507 if( anObject && anObject->isMovable() && ( e->buttons() & Qt::LeftButton ) )
1509 if( anObject->isSelected() )
1511 for( initSelected(); moreSelected(); nextSelected() )
1512 if( GraphicsView_Object* aMovingObject = selectedObject() )
1513 if( aMovingObject->isMovable() )
1514 anObjectsToMove.append( aMovingObject );
1517 anObjectsToMove.append( anObject );
1519 else if( hasInteractionFlag( DraggingByMiddleButton ) &&
1520 nbSelected() && ( e->buttons() & Qt::MidButton ) )
1522 for( initSelected(); moreSelected(); nextSelected() )
1523 if( GraphicsView_Object* aMovingObject = selectedObject() )
1524 if( aMovingObject->isMovable() )
1525 anObjectsToMove.append( aMovingObject );
1528 if( anObjectsToMove.isEmpty() )
1531 double aDX = e->scenePos().x() - myDragPosition.x();
1532 double aDY = e->scenePos().y() - myDragPosition.y();
1534 bool anIsMovingByXAllowed = true, anIsMovingByYAllowed = true;
1535 GraphicsView_ObjectListIterator anIter( anObjectsToMove );
1536 while( anIter.hasNext() )
1537 if( GraphicsView_Object* aMovingObject = anIter.next() )
1539 if( !aMovingObject->isMovingByXAllowed( aDX ) )
1540 anIsMovingByXAllowed = false;
1541 if( !aMovingObject->isMovingByYAllowed( aDY ) )
1542 anIsMovingByYAllowed = false;
1545 if( !anIsMovingByXAllowed && !anIsMovingByYAllowed )
1546 return; // myDragPosition shouldn't be changed
1548 if( !anIsMovingByXAllowed )
1551 if( !anIsMovingByYAllowed )
1554 anIter = anObjectsToMove;
1555 while( anIter.hasNext() )
1556 if( GraphicsView_Object* aMovingObject = anIter.next() )
1557 aMovingObject->move( aDX, aDY );
1559 if( anIsMovingByXAllowed )
1560 myDragPosition.setX( e->scenePos().x() );
1562 if( anIsMovingByYAllowed )
1563 myDragPosition.setY( e->scenePos().y() );
1566 //================================================================
1567 // Function : startPulling
1569 //================================================================
1570 bool GraphicsView_ViewPort::startPulling( const QPointF& thePoint )
1572 QListIterator<QGraphicsItem*> anIter( items() );
1573 while( anIter.hasNext() )
1575 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1577 QRectF aRect = anObject->getPullingRect();
1578 if( aRect.contains( thePoint ) && anObject->startPulling( thePoint ) )
1581 myPullingObject = anObject;
1582 //setCursor( *getHandCursor() ); // testing ImageViewer
1590 //================================================================
1591 // Function : drawPulling
1593 //================================================================
1594 void GraphicsView_ViewPort::drawPulling( const QPointF& thePoint )
1596 GraphicsView_Object* aLockedObject = 0;
1598 QListIterator<QGraphicsItem*> anIter( items() );
1599 while( anIter.hasNext() )
1601 if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1603 if( !anObject->isVisible() )
1606 QRectF aRect = anObject->getPullingRect();
1607 if( aRect.contains( thePoint ) && anObject->portContains( thePoint ) )
1609 aLockedObject = anObject;
1615 myPullingObject->pull( thePoint, aLockedObject, getSelectedObjects() );
1618 //================================================================
1619 // Function : finishPulling
1621 //================================================================
1622 void GraphicsView_ViewPort::finishPulling( bool theStatus )
1624 myIsPulling = false;
1625 myPullingObject->finishPulling( theStatus, getSelectedObjects() );
1626 setCursor( *getDefaultCursor() );
1629 //================================================================
1630 // Function : cancelCurrentOperation
1632 //================================================================
1633 bool GraphicsView_ViewPort::cancelCurrentOperation()
1635 myIsHighlighting = false;
1639 for( initSelected(); moreSelected(); nextSelected() )
1640 if( GraphicsView_Object* aMovingObject = selectedObject() )
1641 aMovingObject->finishMove( false );
1643 if( GraphicsView_Object* aMovingObject = getHighlightedObject() )
1644 aMovingObject->finishMove( false );
1646 myIsDragging = false;
1647 myDragPosition = QPointF();
1648 //setCursor( myStoredCursor );
1649 setCursor( *getDefaultCursor() );
1656 finishPulling( false );
1660 if( isSketching() || isPrepareToSketch() )
1662 finishSketching( false );
1669 //================================================================
1670 // Function : onBoundingRectChanged
1672 //================================================================
1673 void GraphicsView_ViewPort::onBoundingRectChanged()
1675 if( hasInteractionFlag( TraceBoundingRect ) )
1677 QRectF aRect = objectsBoundingRect( true );
1678 myScene->setSceneRect( aRect.adjusted( -mySceneGap, -mySceneGap, mySceneGap, mySceneGap ) );
1682 //================================================================
1683 // Function : onKeyEvent
1685 //================================================================
1686 void GraphicsView_ViewPort::onKeyEvent( QKeyEvent* e )
1688 emit vpKeyEvent( e );
1691 //================================================================
1692 // Function : onMouseEvent
1694 //================================================================
1695 void GraphicsView_ViewPort::onMouseEvent( QGraphicsSceneMouseEvent* e )
1697 emit vpMouseEvent( e );
1699 bool anIsHandled = false;
1702 case QEvent::GraphicsSceneMousePress:
1704 if( hasInteractionFlag( EditFlags ) && nbSelected() )
1705 for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1706 if( GraphicsView_Object* anObject = selectedObject() )
1707 anIsHandled = anObject->handleMousePress( e );
1709 if( !anIsHandled && hasInteractionFlag( Dragging ) )
1711 bool anAccel = e->modifiers() & GraphicsView_ViewTransformer::accelKey();
1712 if( ( getHighlightedObject() &&
1713 getHighlightedObject()->isMovable() &&
1714 !( anAccel || e->button() != Qt::LeftButton ) ) ||
1715 ( hasInteractionFlag( DraggingByMiddleButton ) &&
1716 nbSelected() && !anAccel && e->button() == Qt::MidButton ) )
1718 myIsDragging = true;
1719 myStoredCursor = cursor();
1720 setCursor( Qt::ClosedHandCursor );
1725 case QEvent::GraphicsSceneMouseMove:
1727 if( hasInteractionFlag( EditFlags ) && nbSelected() )
1728 for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1729 if( GraphicsView_Object* anObject = selectedObject() )
1730 anIsHandled = anObject->handleMouseMove( e );
1732 if( !anIsHandled && !isPulling() && myIsDragging )
1736 case QEvent::GraphicsSceneMouseRelease:
1738 if( hasInteractionFlag( EditFlags ) && nbSelected() )
1739 for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1740 if( GraphicsView_Object* anObject = selectedObject() )
1741 anIsHandled = anObject->handleMouseRelease( e );
1743 if( !anIsHandled && !isPulling() && myIsDragging )
1745 emit vpObjectBeforeMoving();
1747 bool anIsMoved = false;
1748 for( initSelected(); moreSelected(); nextSelected() )
1749 if( GraphicsView_Object* aMovingObject = selectedObject() )
1750 anIsMoved = aMovingObject->finishMove( true ) || anIsMoved;
1752 if( GraphicsView_Object* aMovingObject = getHighlightedObject() )
1753 anIsMoved = aMovingObject->finishMove( true ) || anIsMoved;
1755 myIsDragging = false;
1756 myDragPosition = QPointF();
1757 setCursor( myStoredCursor );
1759 emit vpObjectAfterMoving( anIsMoved );
1763 case QEvent::GraphicsSceneMouseDoubleClick:
1764 break; // do nothing, just emit the signal
1769 if( myIsMousePositionEnabled )
1771 int aMouseX = (int)e->scenePos().x();
1772 int aMouseY = (int)e->scenePos().y();
1773 setViewLabelText( QString( "(%1, %2)" ).arg( aMouseX ).arg( aMouseY ) );
1777 //================================================================
1778 // Function : onWheelEvent
1780 //================================================================
1781 void GraphicsView_ViewPort::onWheelEvent( QGraphicsSceneWheelEvent* e )
1783 emit vpWheelEvent( e );
1786 //================================================================
1787 // Function : onContextMenuEvent
1789 //================================================================
1790 void GraphicsView_ViewPort::onContextMenuEvent( QGraphicsSceneContextMenuEvent* e )
1792 emit vpContextMenuEvent( e );
1795 //================================================================
1796 // Function : scrollContentsBy
1798 //================================================================
1799 void GraphicsView_ViewPort::scrollContentsBy( int theDX, int theDY )
1802 myViewLabel->setAcceptMoveEvents( false );
1804 QGraphicsView::scrollContentsBy( theDX, theDY );
1807 myViewLabel->setAcceptMoveEvents( true );