Salome HOME
Copyright update 2022
[modules/gui.git] / src / GraphicsView / GraphicsView_ViewPort.cxx
1 // Copyright (C) 2013-2022  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GraphicsView_ViewPort.h"
21
22 #include "GraphicsView_Object.h"
23 #include "GraphicsView_Scene.h"
24 #include "GraphicsView_ViewTransformer.h"
25
26 #include "SUIT_ResourceMgr.h"
27 #include "SUIT_Session.h"
28
29 #include <QCursor>
30 #include <QGraphicsSceneMouseEvent>
31 #include <QGridLayout>
32 #include <QLabel>
33 #include <QMoveEvent>
34 #include <QRectF>
35 #include <QRubberBand>
36 #include <QScrollBar>
37 #include <QPrinter>
38 #include <QPainter>
39
40 #include <math.h>
41
42 #define FOREGROUND_Z_VALUE -2
43 #define GRID_Z_VALUE       -1
44 #define SKETCH_Z_VALUE     3000
45
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;
53
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
61 {
62 public:
63   ViewLabel( QWidget* theParent )
64   : QLabel( theParent ),
65     myAcceptMoveEvents( false )
66   {
67   }
68   ~ViewLabel() {}
69
70   void setAcceptMoveEvents( bool theFlag )
71   {
72     myAcceptMoveEvents = theFlag;
73   }
74
75 protected:
76   virtual void moveEvent( QMoveEvent* theEvent )
77   {
78     if( myAcceptMoveEvents )
79       QLabel::moveEvent( theEvent );
80     else // return the label to the initial position
81     {
82       myAcceptMoveEvents = true;
83       move( theEvent->oldPos() );
84       myAcceptMoveEvents = false;
85     }
86   }
87
88 private:
89   bool myAcceptMoveEvents;
90 };
91
92 //================================================================
93 // Function : createCursors
94 // Purpose  : 
95 //================================================================
96 void GraphicsView_ViewPort::createCursors ()
97 {
98   defCursor   = new QCursor( Qt::ArrowCursor );
99   handCursor  = new QCursor( Qt::PointingHandCursor );
100   panCursor   = new QCursor( Qt::SizeAllCursor );
101   panglCursor = new QCursor( Qt::CrossCursor );
102
103   SUIT_ResourceMgr* rmgr = SUIT_Session::session()->resourceMgr();
104   zoomCursor   = new QCursor( rmgr->loadPixmap( "GraphicsView", tr( "ICON_GV_CURSOR_ZOOM" ) ) );
105
106   sketchCursor = new QCursor( Qt::CrossCursor );
107 }
108
109 //================================================================
110 // Function : destroyCursors
111 // Purpose  : 
112 //================================================================
113 void GraphicsView_ViewPort::destroyCursors()
114 {
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;
121 }
122
123 //=======================================================================
124 // Name    : GraphicsView_ViewPort
125 // Purpose : Constructor
126 //=======================================================================
127 GraphicsView_ViewPort::GraphicsView_ViewPort( QWidget* theParent )
128 : QGraphicsView( theParent ),
129   myInteractionFlags( 0 ),
130   myViewLabel( 0 ),
131   myViewLabelPosition( VLP_None ),
132   myViewLabelLayout( 0 ),
133   myIsMousePositionEnabled( false ),
134   myForegroundItem( 0 ),
135   myGridItem( 0 ),
136   myIsTransforming( false ),
137   myUnlimitedPanning( false ),
138   myHighlightedObject( 0 ),
139   myHighlightX( 0 ),
140   myHighlightY( 0 ),
141   myIsHighlighting( false ),
142   mySelectionIterator( 0 ),
143   myRectBand( 0 ),
144   myAreSelectionPointsInitialized( false ),
145   mySketchingItem( 0 ),
146   myIsPrepareToSketch( false ),
147   myIsSketching( false ),
148   myIsSketchingByPath( false ),
149   myIsDragging( false ),
150   myIsDragPositionInitialized( false ),
151   myDraggingSelectedByLeftButton( false ),
152   myIsPulling( false ),
153   myPullingObject( 0 ),
154   myStoredCursor( Qt::ArrowCursor ),
155   myZoomCoeff( 100 )
156 {
157   // scene
158   myScene = new GraphicsView_Scene( this );
159   setScene( myScene );
160
161   mySceneGap = 20;
162   myFitAllGap = 40;
163
164   // interaction flags
165   setInteractionFlags( EditFlags );
166   //setInteractionFlag( TraceBoundingRect );
167   //setInteractionFlag( DraggingByMiddleButton );
168   //setInteractionFlag( ImmediateContextMenu );
169   //setInteractionFlag( ImmediateSelection );
170   //setInteractionFlag( Sketching );
171
172   // background
173   setBackgroundBrush( QBrush( Qt::white ) );
174
175   // foreground
176   myIsForegroundEnabled = false;
177   myForegroundSize = QSizeF( 100, 30 );
178   myForegroundMargin = 0.0;
179   myForegroundColor = Qt::white;
180   myForegroundFrameColor = Qt::black;
181   myForegroundFrameLineWidth = 1.0;
182
183   // grid
184   myIsGridEnabled = false;
185   myGridCellSize = 100;
186   myGridLineStyle = Qt::DotLine;
187   myGridLineColor = Qt::darkGray;
188
189   // default index method (BspTreeIndex) leads to
190   // crashes in QGraphicsView::paintEvent() method
191   myScene->setItemIndexMethod( QGraphicsScene::NoIndex );
192
193   // render hints (default - TextAntialiasing only)
194   setRenderHints( QPainter::Antialiasing |
195                   QPainter::TextAntialiasing |
196                   QPainter::SmoothPixmapTransform |
197                   QPainter::HighQualityAntialiasing );
198
199   myHBarPolicy = horizontalScrollBarPolicy();
200   myVBarPolicy = verticalScrollBarPolicy();
201
202   connect( myScene, SIGNAL( gsKeyEvent( QKeyEvent* ) ),
203            this, SLOT( onKeyEvent( QKeyEvent* ) ) );
204   connect( myScene, SIGNAL( gsMouseEvent( QGraphicsSceneMouseEvent* ) ),
205            this, SLOT( onMouseEvent( QGraphicsSceneMouseEvent* ) ) );
206   connect( myScene, SIGNAL( gsWheelEvent( QGraphicsSceneWheelEvent* ) ),
207            this, SLOT( onWheelEvent( QGraphicsSceneWheelEvent* ) ) );
208   connect( myScene, SIGNAL( gsContextMenuEvent( QGraphicsSceneContextMenuEvent* ) ),
209            this, SLOT( onContextMenuEvent( QGraphicsSceneContextMenuEvent* ) ) );
210
211   connect( myScene, SIGNAL( gsBoundingRectChanged() ),
212            this, SLOT( onBoundingRectChanged() ) );
213
214   initialize();
215 }
216
217 //=======================================================================
218 // Name    : GraphicsView_ViewPort
219 // Purpose : Destructor
220 //=======================================================================
221 GraphicsView_ViewPort::~GraphicsView_ViewPort()
222 {
223   cleanup();
224
225   if( myScene )
226   {
227     delete myScene;
228     myScene = 0;
229   }
230 }
231
232 //================================================================
233 // Function : initialize
234 // Purpose  : 
235 //================================================================
236 void GraphicsView_ViewPort::initialize()
237 {
238   if ( nCounter++ == 0 )
239     createCursors();
240
241   setMouseTracking( true );
242   setFocusPolicy( Qt::StrongFocus );
243 }
244
245 //================================================================
246 // Function : cleanup
247 // Purpose  : 
248 //================================================================
249 void GraphicsView_ViewPort::cleanup()
250 {
251   if ( --nCounter == 0 )
252     destroyCursors();
253 }
254
255 //================================================================
256 // Function : addItem
257 // Purpose  : 
258 //================================================================
259 void GraphicsView_ViewPort::addItem( QGraphicsItem* theItem )
260 {
261   if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
262   {
263     int aPriority = anObject->getPriority();
264     GraphicsView_ObjectList::iterator anIter, anIterEnd = myObjects.end();
265     for( anIter = myObjects.begin(); anIter != anIterEnd; anIter++ )
266     {
267       if( GraphicsView_Object* anObjectRef = *anIter )
268       {
269         if( anObjectRef->getPriority() > aPriority )
270           break;
271       }
272     }
273     myObjects.insert( anIter, anObject );
274     anObject->setViewTransform( transform() );
275     anObject->addTo( this );
276   }
277   else
278     myScene->addItem( theItem );
279   onBoundingRectChanged();
280 }
281
282 //================================================================
283 // Function : isItemAdded
284 // Purpose  :
285 //================================================================
286 bool GraphicsView_ViewPort::isItemAdded( QGraphicsItem* theItem )
287 {
288   if( dynamic_cast<GraphicsView_Object*>( theItem ) )
289   {
290     for( GraphicsView_ObjectList::iterator anIter = myObjects.begin(); anIter != myObjects.end(); anIter++ )
291       if( theItem == *anIter )
292         return true;
293   }
294   else {
295     for( int i = 0; i < myScene->items().size(); i++ )
296       if( theItem == myScene->items().at(i) )
297         return true;
298   }
299   return false;
300 }
301
302 //================================================================
303 // Function : removeItem
304 // Purpose  : 
305 //================================================================
306 void GraphicsView_ViewPort::removeItem( QGraphicsItem* theItem )
307 {
308   if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( theItem ) )
309   {
310     if( myHighlightedObject == anObject )
311       myHighlightedObject = 0;
312     mySelectedObjects.removeAll( anObject );
313     myObjects.removeAll( anObject );
314     anObject->removeFrom( this );
315   }
316   else
317     myScene->removeItem( theItem );
318   onBoundingRectChanged();
319 }
320
321 void GraphicsView_ViewPort::clearItems()
322 {
323   myHighlightedObject = 0;
324   mySelectedObjects.clear();
325   myObjects.clear();
326   myScene->clear();
327   onBoundingRectChanged();
328 }
329
330 //================================================================
331 // Function : getObjects
332 // Purpose  : 
333 //================================================================
334 GraphicsView_ObjectList GraphicsView_ViewPort::getObjects( SortType theSortType ) const
335 {
336   if( theSortType == SelectedFirst )
337   {
338     // to append selected objects after their non-selected siblings with similar priority
339     int aCurrentPriority = -1;
340     GraphicsView_ObjectList aSelectedObjects;
341     GraphicsView_ObjectList aTopmostObjects;
342
343     GraphicsView_ObjectList aList;
344     GraphicsView_ObjectListIterator anIter( myObjects );
345     while( anIter.hasNext() )
346     {
347       if( GraphicsView_Object* anObject = anIter.next() )
348       {
349         if( anObject->isOnTop() )
350         {
351           aTopmostObjects.append( anObject );
352           continue;
353         }
354
355         int aPriority = anObject->getPriority();
356         if( aPriority > aCurrentPriority  )
357         {
358           if( !aSelectedObjects.isEmpty() )
359           {
360             aList.append( aSelectedObjects );
361             aSelectedObjects.clear();
362           }
363           aCurrentPriority = aPriority;
364         }
365
366         if( anObject->isSelected() )
367           aSelectedObjects.append( anObject );
368         else
369           aList.append( anObject );
370       }
371     }
372
373     // for selected objects with highest priority,
374     // which were not pushed to the result list yet
375     if( !aSelectedObjects.isEmpty() )
376     {
377       aList.append( aSelectedObjects );
378       aSelectedObjects.clear();
379     }
380
381     aList.append( aTopmostObjects );
382
383     return aList;
384   }
385
386   if( theSortType == SortByZLevel ) // double loop, needs to be optimized
387   {
388     GraphicsView_ObjectList aList;
389
390     GraphicsView_ObjectListIterator anIter( myObjects );
391     while( anIter.hasNext() )
392     {
393       if( GraphicsView_Object* anObject = anIter.next() )
394       {
395         double aZValue = anObject->zValue();
396         GraphicsView_ObjectList::iterator anIter1, anIter1End = aList.end();
397         for( anIter1 = aList.begin(); anIter1 != anIter1End; anIter1++ )
398           if( GraphicsView_Object* anObjectRef = *anIter1 )
399             if( anObjectRef->zValue() > aZValue )
400               break;
401         aList.insert( anIter1, anObject );
402       }
403     }
404     return aList;
405   }
406
407   return myObjects; // theSortType == NoSorting
408 }
409
410 //================================================================
411 // Function : objectsBoundingRect
412 // Purpose  : 
413 //================================================================
414 QRectF GraphicsView_ViewPort::objectsBoundingRect( bool theOnlyVisible ) const
415 {
416   QRectF aRect;
417   QListIterator<QGraphicsItem*> anIter( items() );
418   while( anIter.hasNext() )
419   {
420     if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
421     {
422       if( theOnlyVisible && !anObject->isVisible() )
423         continue;
424
425       QRectF anObjectRect = anObject->getRect();
426       if( !anObjectRect.isNull() )
427       {
428         if( aRect.isNull() )
429           aRect = anObject->getRect();
430         else
431           aRect |= anObject->getRect();
432       }
433     }
434   }
435   return aRect;
436 }
437
438 //================================================================
439 // Function : dumpView
440 // Purpose  : 
441 //================================================================
442 QImage GraphicsView_ViewPort::dumpView( bool theWholeScene,
443                                         QSizeF theSize )
444 {
445   if( !theWholeScene ) // just grab the view contents
446   {
447     QPixmap aPixmap = QPixmap::grabWindow( viewport()->winId() );
448     return aPixmap.toImage();
449   }
450
451   // get a bounding rect of all presented objects
452   // (itemsBoundingRect() method is unsuitable)
453   QRectF aRect = objectsBoundingRect();
454   if( aRect.isNull() )
455     return QImage();
456
457   QRectF aTargetRect( 0, 0, aRect.width(), aRect.height() );
458   if( theSize.isValid() )
459   {
460     double aRatioX = theSize.width() / aTargetRect.width();
461     double aRatioY = theSize.height() / aTargetRect.height();
462     double aRatio = qMin( aRatioX, aRatioY );
463     aTargetRect.setWidth( aTargetRect.width() * aRatio );
464     aTargetRect.setHeight( aTargetRect.height() * aRatio );
465   }
466
467   // render the scene to an image
468   QImage anImage( aTargetRect.toRect().size(), QImage::Format_RGB32 );
469   QPainter aPainter( &anImage );
470   aPainter.setRenderHints( renderHints() );
471
472   myScene->render( &aPainter, aTargetRect, aRect );
473
474   return anImage;
475 }
476
477 bool GraphicsView_ViewPort::dumpViewToFormat(const QString& fileName, const QString& format)
478 {
479   if( format!="PS" && format!="EPS" )
480     return false;
481
482   QPrinter printer(QPrinter::ScreenResolution);
483   printer.setOutputFormat(QPrinter::PdfFormat);
484   printer.setOutputFileName(fileName);
485   QPainter painter;  
486   if (!painter.begin(&printer))
487     return false;
488
489   QRect view( 0, 0, printer.pageRect().width(), printer.paperRect().height() );
490   QRectF bounds = myScene->itemsBoundingRect();
491     
492   if( !view.isEmpty() && !bounds.isEmpty() )
493   {
494     float SCALE = 0.5;//qMin( view.width()/bounds.width(), view.height()/bounds.height() );
495     painter.setViewport( view );
496     painter.scale( SCALE, SCALE );
497   }
498   myScene->render( &painter, QRectF( view ), bounds );
499
500   if (!painter.end())
501     return false;
502   return true;
503 }
504
505 //================================================================
506 // Function : setSceneGap
507 // Purpose  : 
508 //================================================================
509 void GraphicsView_ViewPort::setSceneGap( double theSceneGap )
510 {
511   mySceneGap = theSceneGap;
512   onBoundingRectChanged();
513 }
514
515 //================================================================
516 // Function : setFitAllGap
517 // Purpose  : 
518 //================================================================
519 void GraphicsView_ViewPort::setFitAllGap( double theFitAllGap )
520 {
521   myFitAllGap = theFitAllGap;
522 }
523
524 //================================================================
525 // Function : interactionFlags
526 // Purpose  : 
527 //================================================================
528 int GraphicsView_ViewPort::interactionFlags() const
529 {
530   return myInteractionFlags;
531 }
532
533 //================================================================
534 // Function : hasInteractionFlag
535 // Purpose  : 
536 //================================================================
537 bool GraphicsView_ViewPort::hasInteractionFlag( InteractionFlag theFlag )
538 {
539   return ( interactionFlags() & theFlag ) == theFlag;
540 }
541
542 //================================================================
543 // Function : setInteractionFlag
544 // Purpose  : 
545 //================================================================
546 void GraphicsView_ViewPort::setInteractionFlag( InteractionFlag theFlag,
547                                                 bool theIsEnabled )
548 {
549   if( theIsEnabled )
550     setInteractionFlags( myInteractionFlags | theFlag );
551   else
552     setInteractionFlags( myInteractionFlags & ~theFlag );
553 }
554
555 //================================================================
556 // Function : setInteractionFlags
557 // Purpose  : 
558 //================================================================
559 void GraphicsView_ViewPort::setInteractionFlags( InteractionFlags theFlags )
560 {
561   myInteractionFlags = theFlags;
562 }
563
564 //================================================================
565 // Function : setViewLabelPosition
566 // Purpose  : 
567 //================================================================
568 void GraphicsView_ViewPort::setViewLabelPosition( ViewLabelPosition thePosition,
569                                                   bool theIsForced )
570 {
571   if( theIsForced && !myViewLabel )
572     myViewLabel = new ViewLabel( viewport() );
573
574   if( !myViewLabel )
575     return;
576
577   if( thePosition == VLP_None )
578   {
579     myViewLabel->setVisible( false );
580     return;
581   }
582
583   if( myViewLabelLayout )
584     delete myViewLabelLayout;
585
586   myViewLabelLayout = new QGridLayout( viewport() );
587   myViewLabelLayout->setMargin( 10 );
588   myViewLabelLayout->setSpacing( 0 );
589
590   int aRow = 0, aColumn = 0;
591   switch( thePosition )
592   {
593     case VLP_TopLeft:     aRow = 0; aColumn = 0; break;
594     case VLP_TopRight:    aRow = 0; aColumn = 1; break;
595     case VLP_BottomLeft:  aRow = 1; aColumn = 0; break;
596     case VLP_BottomRight: aRow = 1; aColumn = 1; break;
597     default: break;
598   }
599
600   myViewLabelLayout->addWidget( myViewLabel, aRow, aColumn );
601   myViewLabelLayout->setRowStretch( 1 - aRow, 1 );
602   myViewLabelLayout->setColumnStretch( 1 - aColumn, 1 );
603
604   myViewLabel->setVisible( true );
605 }
606
607 //================================================================
608 // Function : setViewLabelText
609 // Purpose  : 
610 //================================================================
611 void GraphicsView_ViewPort::setViewLabelText( const QString& theText )
612 {
613   if( myViewLabel )
614     myViewLabel->setText( theText );
615 }
616
617 //================================================================
618 // Function : setMousePositionEnabled
619 // Purpose  : 
620 //================================================================
621 void GraphicsView_ViewPort::setMousePositionEnabled( bool theState )
622 {
623   myIsMousePositionEnabled = theState;
624
625   if( theState )
626   {
627     setViewLabelPosition( VLP_BottomLeft, true );
628
629     int aMouseX = 0, aMouseY = 0;
630     setViewLabelText( QString( "(%1, %2)" ).arg( aMouseX ).arg( aMouseY ) );
631   }
632   else
633     setViewLabelPosition( VLP_None );
634 }
635
636 //================================================================
637 // Function : backgroundColor
638 // Purpose  : 
639 //================================================================
640 QColor GraphicsView_ViewPort::backgroundColor() const
641 {
642   return backgroundBrush().color();
643 }
644
645 //================================================================
646 // Function : setBackgroundColor
647 // Purpose  : 
648 //================================================================
649 void GraphicsView_ViewPort::setBackgroundColor( const QColor& theColor )
650 {
651   setBackgroundBrush( QBrush( theColor ) );
652 }
653
654 //================================================================
655 // Function : setForegroundEnabled
656 // Purpose  : 
657 //================================================================
658 void GraphicsView_ViewPort::setForegroundEnabled( bool theState )
659 {
660   myIsForegroundEnabled = theState;
661 }
662
663 //================================================================
664 // Function : setForegroundSize
665 // Purpose  : 
666 //================================================================
667 void GraphicsView_ViewPort::setForegroundSize( const QSizeF& theSize )
668 {
669   myForegroundSize = theSize;
670 }
671
672 //================================================================
673 // Function : setForegroundMargin
674 // Purpose  : 
675 //================================================================
676 void GraphicsView_ViewPort::setForegroundMargin( double theMargin )
677 {
678   myForegroundMargin = theMargin;
679 }
680
681 //================================================================
682 // Function : setForegroundColor
683 // Purpose  : 
684 //================================================================
685 void GraphicsView_ViewPort::setForegroundColor( const QColor& theColor )
686 {
687   myForegroundColor = theColor;
688 }
689
690 //================================================================
691 // Function : setForegroundFrameColor
692 // Purpose  : 
693 //================================================================
694 void GraphicsView_ViewPort::setForegroundFrameColor( const QColor& theColor )
695 {
696   myForegroundFrameColor = theColor;
697 }
698
699 //================================================================
700 // Function : setForegroundFrameLineWidth
701 // Purpose  : 
702 //================================================================
703 void GraphicsView_ViewPort::setForegroundFrameLineWidth( double theLineWidth )
704 {
705   myForegroundFrameLineWidth = theLineWidth;
706 }
707
708 //================================================================
709 // Function : updateForeground
710 // Purpose  : 
711 //================================================================
712 void GraphicsView_ViewPort::updateForeground()
713 {
714   if( myIsForegroundEnabled )
715   {
716     if( !myForegroundItem )
717       myForegroundItem = myScene->addRect( QRectF(), QPen(), QBrush( Qt::white ) );
718     myForegroundItem->setZValue( FOREGROUND_Z_VALUE );
719
720     QPointF aPoint = QPointF();
721     QRectF aRect( aPoint, myForegroundSize );
722     aRect.adjust( -myForegroundMargin, -myForegroundMargin,
723                   myForegroundMargin, myForegroundMargin );
724     myForegroundItem->setRect( aRect );
725
726     QBrush aBrush = myForegroundItem->brush();
727     aBrush.setColor( myForegroundColor );
728     myForegroundItem->setBrush( aBrush );
729
730     QPen aPen = myForegroundItem->pen();
731     aPen.setColor( myForegroundFrameColor );
732     aPen.setWidthF( myForegroundFrameLineWidth );
733     myForegroundItem->setPen( aPen );
734
735     myForegroundItem->setVisible( true );
736
737     myScene->setSceneRect( aRect.adjusted( -mySceneGap, -mySceneGap, mySceneGap, mySceneGap ) );
738   }
739   else
740   {
741     if( myForegroundItem )
742       myForegroundItem->setVisible( false );
743   }
744
745   updateGrid(); // foreground size could be changed
746 }
747
748 //================================================================
749 // Function : setGridEnabled
750 // Purpose  : 
751 //================================================================
752 void GraphicsView_ViewPort::setGridEnabled( bool theState )
753 {
754   myIsGridEnabled = theState;
755 }
756
757 //================================================================
758 // Function : setGridCellSize
759 // Purpose  : 
760 //================================================================
761 void GraphicsView_ViewPort::setGridCellSize( int theCellSize )
762 {
763   myGridCellSize = theCellSize;
764 }
765
766 //================================================================
767 // Function : setGridLineStyle
768 // Purpose  : 
769 //================================================================
770 void GraphicsView_ViewPort::setGridLineStyle( int theLineStyle )
771 {
772   myGridLineStyle = theLineStyle;
773 }
774
775 //================================================================
776 // Function : setGridLineColor
777 // Purpose  : 
778 //================================================================
779 void GraphicsView_ViewPort::setGridLineColor( const QColor& theLineColor )
780 {
781   myGridLineColor = theLineColor;
782 }
783
784 //================================================================
785 // Function : updateGrid
786 // Purpose  : 
787 //================================================================
788 void GraphicsView_ViewPort::updateGrid()
789 {
790   if( myIsGridEnabled )
791   {
792     if( !myGridItem )
793       myGridItem = myScene->addPath( QPainterPath() );
794     myGridItem->setZValue( GRID_Z_VALUE );
795
796     double aWidth = myForegroundSize.width();
797     double aHeight = myForegroundSize.height();
798
799     int aGridNbX = int( aWidth / myGridCellSize ) + 1;
800     int aGridNbY = int( aHeight / myGridCellSize ) + 1;
801
802     int anIndex;
803     QPainterPath aPath;
804     for( anIndex = 0; anIndex < aGridNbX; anIndex++ )
805     {
806       double x = myGridCellSize * (double)anIndex;
807       aPath.moveTo( x, 0 );
808       aPath.lineTo( x, aHeight );
809     }
810     for( anIndex = 0; anIndex < aGridNbY; anIndex++ )
811     {
812       double y = myGridCellSize * (double)anIndex;
813       aPath.moveTo( 0, y );
814       aPath.lineTo( aWidth, y );
815     }
816     myGridItem->setPath( aPath );
817
818     QPen aPen = myGridItem->pen();
819     aPen.setStyle( (Qt::PenStyle)myGridLineStyle );
820     aPen.setColor( myGridLineColor );
821     myGridItem->setPen( aPen );
822
823     myGridItem->setVisible( true );
824   }
825   else
826   {
827     if( myGridItem )
828       myGridItem->setVisible( false );
829   }
830 }
831
832 //================================================================
833 // Function : reset
834 // Purpose  : 
835 //================================================================
836 void GraphicsView_ViewPort::reset()
837 {
838   fitAll();
839 }
840
841 //================================================================
842 // Function : pan
843 // Purpose  : 
844 //================================================================
845 void GraphicsView_ViewPort::pan( double theDX, double theDY )
846 {
847   myIsTransforming = true;
848
849   if( myViewLabel )
850     myViewLabel->setAcceptMoveEvents( false );
851
852   if( QScrollBar* aHBar = horizontalScrollBar() )
853   {
854     if( isUnlimitedPanning() )
855     {
856       int aNewValue = aHBar->value() - theDX;
857       if( aNewValue < aHBar->minimum() )
858         aHBar->setMinimum( aNewValue );
859       if( aNewValue > aHBar->maximum() )
860         aHBar->setMaximum( aNewValue );
861     }
862     aHBar->setValue( aHBar->value() - theDX );
863   }
864   if( QScrollBar* aVBar = verticalScrollBar() )
865   {
866     if( isUnlimitedPanning() )
867     {
868       int aNewValue = aVBar->value() + theDY;
869       if( aNewValue < aVBar->minimum() )
870         aVBar->setMinimum( aNewValue );
871       if( aNewValue > aVBar->maximum() )
872         aVBar->setMaximum( aNewValue );
873     }
874     aVBar->setValue( aVBar->value() + theDY );
875   }
876
877   if( myViewLabel )
878     myViewLabel->setAcceptMoveEvents( true );
879
880   myIsTransforming = false;
881
882   applyTransform();
883 }
884
885 //================================================================
886 // Function : setCenter
887 // Purpose  : 
888 //================================================================
889 void GraphicsView_ViewPort::setCenter( double theX, double theY )
890 {
891   myIsTransforming = true;
892
893   setTransform( myCurrentTransform );
894   centerOn( theX, theY );
895
896   myIsTransforming = false;
897
898   applyTransform();
899 }
900
901 //================================================================
902 // Function : zoom
903 // Purpose  : 
904 //================================================================
905 void GraphicsView_ViewPort::zoom( double theX1, double theY1, double theX2, double theY2 )
906 {
907   myIsTransforming = true;
908
909   double aDX = theX2 - theX1;
910   double aDY = theY2 - theY1;
911   double aZoom = sqrt( aDX * aDX + aDY * aDY ) / 100 + 1;
912   aZoom = ( aDX > 0 ) ?  aZoom : 1 / aZoom;
913
914   QTransform aTransform = transform();
915   aTransform.scale( aZoom, aZoom );
916   double aM11 = aTransform.m11();
917   double aM22 = aTransform.m22();
918
919
920   QGraphicsView::ViewportAnchor old_anchor = transformationAnchor();
921   setTransformationAnchor( QGraphicsView::AnchorUnderMouse );
922
923   // increasing of diagonal coefficients (>300) leads to a crash sometimes
924   // at the values of 100 some primitives are drawn incorrectly
925   if( myZoomCoeff < 0 || qMax( aM11, aM22 ) < myZoomCoeff )
926     setTransform( aTransform );
927
928   myIsTransforming = false;
929
930   applyTransform();
931
932   setTransformationAnchor( old_anchor );
933 }
934
935 //================================================================
936 // Function : fitRect
937 // Purpose  : 
938 //================================================================
939 void GraphicsView_ViewPort::fitRect( const QRectF& theRect )
940 {
941   myIsTransforming = true;
942
943   fitInView( theRect, Qt::KeepAspectRatio );
944
945   myIsTransforming = false;
946
947   applyTransform();
948 }
949
950 //================================================================
951 // Function : fitSelect
952 // Purpose  : 
953 //================================================================
954 void GraphicsView_ViewPort::fitSelect()
955 {
956   myIsTransforming = true;
957
958   QRectF aGlobalRect;
959   for( initSelected(); moreSelected(); nextSelected() )
960   {
961     if( GraphicsView_Object* aMovingObject = selectedObject() )
962     {
963       QRectF aRect = aMovingObject->getRect();
964       if( aGlobalRect.isNull() )
965         aGlobalRect = aRect;
966       else
967         aGlobalRect |= aRect;
968     }
969   }
970
971   if( !aGlobalRect.isNull() )
972   {
973     double aGap = qMax( aGlobalRect.width(), aGlobalRect.height() ) / 5;
974     aGlobalRect.adjust( -aGap, -aGap, aGap, aGap );
975     fitInView( aGlobalRect, Qt::KeepAspectRatio );
976   }
977
978   myIsTransforming = false;
979
980   applyTransform();
981 }
982
983 //================================================================
984 // Function : fitAll
985 // Purpose  : 
986 //================================================================
987 void GraphicsView_ViewPort::fitAll( bool theKeepScale )
988 {
989   myIsTransforming = true;
990
991   if( theKeepScale )
992     myCurrentTransform = transform();
993
994   double aGap = myFitAllGap;
995   QRectF aRect = objectsBoundingRect( true );
996   fitInView( aRect.adjusted( -aGap, -aGap, aGap, aGap ), Qt::KeepAspectRatio );
997
998   myIsTransforming = false;
999
1000   applyTransform();
1001 }
1002
1003 //================================================================
1004 // Function : fitWidth
1005 // Purpose  : 
1006 //================================================================
1007 void GraphicsView_ViewPort::fitWidth()
1008 {
1009   myIsTransforming = true;
1010
1011   double aGap = myFitAllGap;
1012   QRectF aRect = objectsBoundingRect( true );
1013
1014   double aTop = aRect.top();
1015   double aLeft = aRect.left();
1016   double aMargin = 10;
1017
1018   aRect.setY( aRect.center().y() );
1019   aRect.setHeight( aMargin );
1020
1021   fitInView( aRect.adjusted( -aGap, -aGap, aGap, aGap ), Qt::KeepAspectRatio );
1022   ensureVisible( aLeft, aTop, aMargin, aMargin, 0, aGap );
1023
1024   myIsTransforming = false;
1025
1026   applyTransform();
1027 }
1028
1029 //================================================================
1030 // Function : applyTransform
1031 // Purpose  : 
1032 //================================================================
1033 void GraphicsView_ViewPort::applyTransform()
1034 {
1035   GraphicsView_ObjectListIterator anIter( getObjects() );
1036   while( anIter.hasNext() )
1037     if( GraphicsView_Object* anObject = anIter.next() )
1038       anObject->setViewTransform( transform() );
1039 }
1040
1041 //================================================================
1042 // Function : setZoomCoeff
1043 // Purpose  : 
1044 //================================================================
1045 void GraphicsView_ViewPort::setZoomCoeff( const int& theZoomCoeff )
1046 {
1047   myZoomCoeff = theZoomCoeff;
1048 }
1049
1050 //================================================================
1051 // Function : setUnlimitedPanning
1052 // Purpose  : 
1053 //================================================================
1054 void GraphicsView_ViewPort::setUnlimitedPanning( const bool& theValue )
1055 {
1056   if ( myUnlimitedPanning == theValue )
1057     return;
1058
1059   myUnlimitedPanning = theValue;
1060
1061   if( myUnlimitedPanning )
1062   {
1063     myHBarPolicy = horizontalScrollBarPolicy();
1064     myVBarPolicy = verticalScrollBarPolicy();
1065
1066     setHorizontalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
1067     setVerticalScrollBarPolicy( Qt::ScrollBarAlwaysOn );
1068   }
1069   else
1070   {
1071     setHorizontalScrollBarPolicy( myHBarPolicy );
1072     setVerticalScrollBarPolicy( myVBarPolicy );
1073   }
1074 }
1075
1076 //================================================================
1077 // Function : currentBlock
1078 // Purpose  : 
1079 //================================================================
1080 GraphicsView_ViewPort::BlockStatus GraphicsView_ViewPort::currentBlock()
1081 {
1082   if( isDragging() && !myDragPosition.isNull() )
1083     return BlockStatus( BS_Selection );
1084
1085   if( myAreSelectionPointsInitialized && ( myFirstSelectionPoint != myLastSelectionPoint ) )
1086     return BlockStatus( BS_Selection );
1087
1088   if( isPulling() )
1089     return BlockStatus( BS_Selection );
1090
1091   return BS_NoBlock;
1092 }
1093
1094 //================================================================
1095 // Function : highlight
1096 // Purpose  : 
1097 //================================================================
1098 void GraphicsView_ViewPort::highlight( double theX, double theY )
1099 {
1100   myIsHighlighting = true;
1101   myHighlightX = theX;
1102   myHighlightY = theY;
1103
1104   bool anIsHighlighted = false;
1105   bool anIsOnObject = false;
1106
1107   GraphicsView_Object* aHighlightedObject = 0;
1108
1109   QCursor aCursor;
1110
1111   GraphicsView_ObjectList aList = getObjects( SortByZLevel );
1112   GraphicsView_ObjectListIterator anIter( aList );
1113   anIter.toBack(); // objects with higher priority have to be checked earlier
1114   while( anIter.hasPrevious() )
1115   {
1116     if( GraphicsView_Object* anObject = anIter.previous() )
1117     {
1118       if( anObject->isVisible() && anObject->isSelectable() )
1119       {
1120         if( anObject->checkHighlight( theX, theY, aCursor ) )
1121         {
1122           anIsOnObject = true;
1123           anIsHighlighted = anObject->highlight( theX, theY );
1124         }
1125
1126         if( anIsHighlighted )
1127         {
1128           aHighlightedObject = anObject;
1129           break;
1130         }
1131       }
1132     }
1133   }
1134
1135   setCursor( aCursor );
1136
1137   if( !anIsOnObject )
1138   {
1139     anIter = aList;
1140     while( anIter.hasNext() )
1141       if( GraphicsView_Object* anObject = anIter.next() )
1142         anObject->unhighlight();
1143
1144     myHighlightedObject = 0;
1145     return;
1146   }
1147   else if( !myHighlightedObject && anIsHighlighted )
1148   {
1149     myHighlightedObject = aHighlightedObject;
1150   }
1151   else if( myHighlightedObject && !anIsHighlighted )
1152   {
1153     myHighlightedObject->unhighlight();
1154     myHighlightedObject = 0;
1155   }
1156   else if( myHighlightedObject && anIsHighlighted )
1157   {
1158     myHighlightedObject->highlight( theX, theY );
1159     if( myHighlightedObject != aHighlightedObject )
1160     {
1161       myHighlightedObject->unhighlight();
1162       myHighlightedObject = aHighlightedObject;
1163     }
1164   }
1165 }
1166
1167 //================================================================
1168 // Function : clearHighlighted
1169 // Purpose  : 
1170 //================================================================
1171 void GraphicsView_ViewPort::clearHighlighted()
1172 {
1173   if( myHighlightedObject )
1174   {
1175     myHighlightedObject->unhighlight();
1176     myHighlightedObject = 0;
1177   }
1178 }
1179
1180 //================================================================
1181 // Function : select
1182 // Purpose  : 
1183 //================================================================
1184 int GraphicsView_ViewPort::select( const QRectF& theRect, bool theIsAppend )
1185 {
1186   if( !myIsHighlighting )
1187     return GVSS_NoChanged;
1188
1189   GV_SelectionStatus aStatus = GVSS_Invalid;
1190   if( theRect.isNull() ) // point selection
1191   {
1192     if( myHighlightedObject )
1193     {
1194       if( mySelectedObjects.count() == 1 &&
1195           mySelectedObjects.first() == myHighlightedObject )
1196         aStatus = GVSS_LocalChanged;
1197
1198       if( !theIsAppend )
1199       {
1200         GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1201         while( anIter.hasNext() )
1202           if( GraphicsView_Object* anObject = anIter.next() )
1203             if( myHighlightedObject != anObject )
1204               anObject->unselect();
1205
1206         if( !mySelectedObjects.isEmpty() && aStatus == GVSS_Invalid )
1207           aStatus = GVSS_GlobalChanged;
1208         mySelectedObjects.clear();
1209       } 
1210       else if( myHighlightedObject->isSelected() && aStatus != GVSS_LocalChanged )
1211       {
1212         mySelectedObjects.removeAll( myHighlightedObject );
1213         myHighlightedObject->unselect();
1214
1215         if( !mySelectedObjects.isEmpty() && aStatus == GVSS_Invalid )
1216           aStatus = GVSS_GlobalChanged;
1217
1218         return aStatus;
1219       }
1220
1221       if( myHighlightedObject->select( myHighlightX, myHighlightY, QRectF() ) &&
1222           mySelectedObjects.indexOf( myHighlightedObject ) == -1 )
1223       {
1224         mySelectedObjects.append( myHighlightedObject );
1225         if( aStatus == GVSS_Invalid )
1226           aStatus = GVSS_GlobalChanged;
1227       }
1228       else if( aStatus == GVSS_LocalChanged )
1229         aStatus = GVSS_GlobalChanged;
1230
1231       return aStatus;
1232     }
1233
1234     if( !myHighlightedObject )
1235     {
1236       if( !theIsAppend )
1237       {
1238         GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1239         while( anIter.hasNext() )
1240           if( GraphicsView_Object* anObject = anIter.next() )
1241             if( myHighlightedObject != anObject )
1242               anObject->unselect();
1243
1244         if( !mySelectedObjects.isEmpty() )
1245           aStatus = GVSS_GlobalChanged;
1246         mySelectedObjects.clear();
1247       }
1248       return aStatus;
1249     }
1250
1251     return GVSS_NoChanged;
1252   }
1253   else // rectangle selection
1254   {
1255     aStatus = GVSS_NoChanged;
1256
1257     if( !theIsAppend )
1258     {
1259       if( !mySelectedObjects.isEmpty() )
1260         aStatus = GVSS_GlobalChanged;
1261
1262       GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1263       while( anIter.hasNext() )
1264         if( GraphicsView_Object* anObject = anIter.next() )
1265           if( myHighlightedObject != anObject )
1266             anObject->unselect();
1267       mySelectedObjects.clear();
1268     }
1269
1270     QListIterator<QGraphicsItem*> anIter( items() );
1271     while( anIter.hasNext() )
1272     {
1273       if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1274       {
1275         if( anObject->isVisible() && anObject->isSelectable() )
1276         {
1277           bool anIsSelected = false;
1278           QRectF aRect = anObject->getRect();
1279           if( theRect.contains( aRect ) && myIsHighlighting )
1280             anIsSelected = anObject->select( myHighlightX, myHighlightY, theRect );
1281
1282           if( anIsSelected && mySelectedObjects.indexOf( anObject ) == -1 )
1283           {
1284             mySelectedObjects.append( anObject );
1285             aStatus = GVSS_GlobalChanged;
1286           }
1287         }
1288       }
1289     }
1290   }
1291   return aStatus;
1292 }
1293
1294 //================================================================
1295 // Function : clearSelected
1296 // Purpose  : 
1297 //================================================================
1298 void GraphicsView_ViewPort::clearSelected()
1299 {
1300   GraphicsView_ObjectListIterator anIter( mySelectedObjects );
1301   while( anIter.hasNext() )
1302     if( GraphicsView_Object* anObject = anIter.next() )
1303       anObject->unselect();
1304   mySelectedObjects.clear();
1305 }
1306
1307 //================================================================
1308 // Function : setSelected
1309 // Purpose  : 
1310 //================================================================
1311 void GraphicsView_ViewPort::setSelected( GraphicsView_Object* theObject )
1312 {
1313   if( theObject )
1314   {
1315     theObject->setSelected( true );
1316     mySelectedObjects.append( theObject );
1317   }
1318 }
1319
1320 //================================================================
1321 // Function : nbSelected
1322 // Purpose  : 
1323 //================================================================
1324 int GraphicsView_ViewPort::nbSelected() const
1325 {
1326   return mySelectedObjects.count();
1327 }
1328
1329 //================================================================
1330 // Function : initSelected
1331 // Purpose  : 
1332 //================================================================
1333 void GraphicsView_ViewPort::initSelected()
1334 {
1335   mySelectionIterator = 0;
1336 }
1337
1338 //================================================================
1339 // Function : moreSelected
1340 // Purpose  : 
1341 //================================================================
1342 bool GraphicsView_ViewPort::moreSelected()
1343 {
1344   return mySelectionIterator < nbSelected();
1345 }
1346
1347 //================================================================
1348 // Function : nextSelected
1349 // Purpose  : 
1350 //================================================================
1351 bool GraphicsView_ViewPort::nextSelected()
1352 {
1353   if( mySelectionIterator >= 0 && mySelectionIterator < nbSelected() )
1354   {
1355     mySelectionIterator++;
1356     return true;
1357   }
1358   return false;
1359 }
1360
1361 //================================================================
1362 // Function : selectedObject
1363 // Purpose  : 
1364 //================================================================
1365 GraphicsView_Object* GraphicsView_ViewPort::selectedObject()
1366 {
1367   if( mySelectionIterator >= 0 && mySelectionIterator < nbSelected() )
1368     return mySelectedObjects[ mySelectionIterator ];
1369   return 0;
1370 }
1371
1372 //================================================================
1373 // Function : startSelectByRect
1374 // Purpose  : 
1375 //================================================================
1376 void GraphicsView_ViewPort::startSelectByRect( int x, int y )
1377 {
1378   if( !myAreSelectionPointsInitialized )
1379   {
1380     myFirstSelectionPoint = QPoint( x, y );
1381     myLastSelectionPoint = QPoint( x, y );
1382     myAreSelectionPointsInitialized = true;
1383   }
1384
1385   if( !myRectBand )
1386   {
1387     myRectBand = new QRubberBand( QRubberBand::Rectangle, this );
1388     QPalette palette;
1389     palette.setColor( myRectBand->foregroundRole(), Qt::white );
1390     myRectBand->setPalette( palette );
1391   }
1392   myRectBand->hide();
1393 }
1394
1395 //================================================================
1396 // Function : drawSelectByRect
1397 // Purpose  : 
1398 //================================================================
1399 void GraphicsView_ViewPort::drawSelectByRect( int x, int y )
1400 {
1401   if( myAreSelectionPointsInitialized )
1402   {
1403     myRectBand->hide();
1404
1405     myLastSelectionPoint.setX( x );
1406     myLastSelectionPoint.setY( y );
1407
1408     QRect aRect = selectionRect();
1409     myRectBand->setGeometry( aRect );
1410     myRectBand->setVisible( aRect.isValid() );
1411   }
1412 }
1413
1414 //================================================================
1415 // Function : isSelectByRect
1416 // Purpose  : 
1417 //================================================================
1418 bool GraphicsView_ViewPort::isSelectByRect() const
1419 {
1420   return myAreSelectionPointsInitialized;
1421 }
1422
1423 //================================================================
1424 // Function : finishSelectByRect
1425 // Purpose  : 
1426 //================================================================
1427 void GraphicsView_ViewPort::finishSelectByRect()
1428 {
1429   if( myAreSelectionPointsInitialized )
1430   {
1431     if( myRectBand )
1432     {
1433       myRectBand->hide();
1434       delete myRectBand;
1435       myRectBand = 0;
1436     }
1437
1438     myAreSelectionPointsInitialized = false;
1439   }
1440 }
1441
1442 //================================================================
1443 // Function : selectionRect
1444 // Purpose  : 
1445 //================================================================
1446 QRect GraphicsView_ViewPort::selectionRect()
1447 {
1448   QRect aRect;
1449   if( myAreSelectionPointsInitialized )
1450   {
1451     aRect.setLeft( qMin( myFirstSelectionPoint.x(), myLastSelectionPoint.x() ) );
1452     aRect.setTop( qMin( myFirstSelectionPoint.y(), myLastSelectionPoint.y() ) );
1453     aRect.setRight( qMax( myFirstSelectionPoint.x(), myLastSelectionPoint.x() ) );
1454     aRect.setBottom( qMax( myFirstSelectionPoint.y(), myLastSelectionPoint.y() ) );
1455   }
1456   return aRect;
1457 }
1458
1459 //================================================================
1460 // Function : prepareToSketch
1461 // Purpose  : 
1462 //================================================================
1463 void GraphicsView_ViewPort::prepareToSketch( bool theStatus )
1464 {
1465   myIsPrepareToSketch = theStatus;
1466   if( theStatus )
1467     setCursor( *getSketchCursor() );
1468 }
1469
1470 //================================================================
1471 // Function : isPrepareToSketch
1472 // Purpose  : 
1473 //================================================================
1474 bool GraphicsView_ViewPort::isPrepareToSketch()
1475 {
1476   return myIsPrepareToSketch;
1477 }
1478
1479 //================================================================
1480 // Function : startSketching
1481 // Purpose  : 
1482 //================================================================
1483 void GraphicsView_ViewPort::startSketching( const QPointF& thePoint,
1484                                             bool theIsPath )
1485 {
1486   prepareToSketch( false );
1487
1488   if( !mySketchingItem )
1489   {
1490     mySketchingItem = new QGraphicsPathItem();
1491     mySketchingItem->setZValue( SKETCH_Z_VALUE );
1492
1493     QPen aPen = mySketchingItem->pen();
1494     aPen.setStyle( Qt::DotLine );
1495     mySketchingItem->setPen( aPen );
1496
1497     addItem( mySketchingItem );
1498   }
1499
1500   mySketchingPoint = thePoint;
1501
1502   QPainterPath aPath;
1503   aPath.moveTo( mySketchingPoint );
1504   mySketchingItem->setPath( aPath );
1505   mySketchingItem->setVisible( true );
1506
1507   myIsSketching = true;
1508   myIsSketchingByPath = theIsPath;
1509 }
1510
1511 //================================================================
1512 // Function : drawSketching
1513 // Purpose  : 
1514 //================================================================
1515 void GraphicsView_ViewPort::drawSketching( const QPointF& thePoint )
1516 {
1517   bool anIsPath = false;
1518   if( mySketchingItem && isSketching( &anIsPath ) )
1519   {
1520     QPainterPath aPath = mySketchingItem->path();
1521     if( anIsPath ) // arbitrary path
1522       aPath.lineTo( thePoint );
1523     else // rectangle
1524     {
1525       // make a valid rectangle
1526       double x1 = mySketchingPoint.x(), y1 = mySketchingPoint.y();
1527       double x2 = thePoint.x(), y2 = thePoint.y();
1528       QPointF aPoint1( qMin( x1, x2 ), qMin( y1, y2 ) );
1529       QPointF aPoint2( qMax( x1, x2 ), qMax( y1, y2 ) );
1530       QRectF aRect( aPoint1, aPoint2 );
1531
1532       aPath = QPainterPath();
1533       aPath.addRect( aRect );
1534     }
1535     mySketchingItem->setPath( aPath );
1536   }
1537 }
1538
1539 //================================================================
1540 // Function : finishSketching
1541 // Purpose  : 
1542 //================================================================
1543 void GraphicsView_ViewPort::finishSketching( bool theStatus )
1544 {
1545   prepareToSketch( false );
1546
1547   mySketchingItem->setVisible( false );
1548   myIsSketching = false;
1549
1550   setCursor( *getDefaultCursor() );
1551
1552   if( theStatus )
1553   {
1554     QPainterPath aPath = mySketchingItem->path();
1555     emit vpSketchingFinished( aPath );
1556   }
1557 }
1558
1559 //================================================================
1560 // Function : isSketching
1561 // Purpose  : 
1562 //================================================================
1563 bool GraphicsView_ViewPort::isSketching( bool* theIsPath ) const
1564 {
1565   if( theIsPath )
1566     *theIsPath = myIsSketchingByPath;
1567   return myIsSketching;
1568 }
1569
1570 //================================================================
1571 // Function : setDraggingSelectedByLeftButton
1572 // Purpose  : 
1573 //================================================================
1574 void GraphicsView_ViewPort::setDraggingSelectedByLeftButton( const bool& theValue )
1575 {
1576   myDraggingSelectedByLeftButton = theValue;
1577 }
1578
1579 //================================================================
1580 // Function : dragObjects
1581 // Purpose  : 
1582 //================================================================
1583 void GraphicsView_ViewPort::dragObjects( QGraphicsSceneMouseEvent* e )
1584 {
1585   GraphicsView_Object* anObject = getHighlightedObject();
1586
1587   if( myDragPosition.isNull() )
1588   {
1589     myDragPosition = e->scenePos();
1590     return;
1591   }
1592
1593   GraphicsView_ObjectList anObjectsToMove;
1594   if( anObject && anObject->isMovable() && ( e->buttons() & Qt::LeftButton ) )
1595   {
1596     if( anObject->isSelected() )
1597     {
1598       for( initSelected(); moreSelected(); nextSelected() )
1599         if( GraphicsView_Object* aMovingObject = selectedObject() )
1600           if( aMovingObject->isMovable() )
1601             anObjectsToMove.append( aMovingObject );
1602     }
1603     else
1604       anObjectsToMove.append( anObject );
1605   }
1606   else if( ( ( hasInteractionFlag( DraggingByMiddleButton ) && ( e->buttons() & Qt::MidButton ) ) ||
1607              ( isDraggingSelectedByLeftButton() && ( e->buttons() & Qt::LeftButton ) ) ) &&
1608            nbSelected() )
1609   {
1610     for( initSelected(); moreSelected(); nextSelected() )
1611       if( GraphicsView_Object* aMovingObject = selectedObject() )
1612         if( aMovingObject->isMovable() )
1613           anObjectsToMove.append( aMovingObject );
1614   }
1615
1616   if( anObjectsToMove.isEmpty() )
1617     return;
1618
1619   double aDX = e->scenePos().x() - myDragPosition.x();
1620   double aDY = e->scenePos().y() - myDragPosition.y();
1621
1622   bool anIsMovingByXAllowed = true, anIsMovingByYAllowed = true;
1623   GraphicsView_ObjectListIterator anIter( anObjectsToMove );
1624   while( anIter.hasNext() )
1625     if( GraphicsView_Object* aMovingObject = anIter.next() )
1626     {
1627       if( !aMovingObject->isMovingByXAllowed( aDX ) )
1628         anIsMovingByXAllowed = false;
1629       if( !aMovingObject->isMovingByYAllowed( aDY ) )
1630         anIsMovingByYAllowed = false;
1631     }
1632
1633   if( !anIsMovingByXAllowed && !anIsMovingByYAllowed )
1634     return; // myDragPosition shouldn't be changed
1635
1636   if( !anIsMovingByXAllowed )
1637     aDX = 0;
1638
1639   if( !anIsMovingByYAllowed )
1640     aDY = 0;
1641
1642   anIter = anObjectsToMove;
1643   while( anIter.hasNext() )
1644     if( GraphicsView_Object* aMovingObject = anIter.next() )
1645       aMovingObject->move( aDX, aDY );
1646
1647   if( anIsMovingByXAllowed )
1648     myDragPosition.setX( e->scenePos().x() );
1649
1650   if( anIsMovingByYAllowed )
1651     myDragPosition.setY( e->scenePos().y() );
1652 }
1653
1654 //================================================================
1655 // Function : startPulling
1656 // Purpose  : 
1657 //================================================================
1658 bool GraphicsView_ViewPort::startPulling( const QPointF& thePoint )
1659 {
1660   QListIterator<QGraphicsItem*> anIter( items() );
1661   while( anIter.hasNext() )
1662   {
1663     if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1664     {
1665       QRectF aRect = anObject->getPullingRect();
1666       if( aRect.contains( thePoint ) && anObject->startPulling( thePoint ) )
1667       {
1668         myIsPulling = true;
1669         myPullingObject = anObject;
1670         //setCursor( *getHandCursor() ); // testing ImageViewer
1671         return true;
1672       }
1673     }
1674   }
1675   return false;
1676 }
1677
1678 //================================================================
1679 // Function : drawPulling
1680 // Purpose  : 
1681 //================================================================
1682 void GraphicsView_ViewPort::drawPulling( const QPointF& thePoint )
1683 {
1684   GraphicsView_Object* aLockedObject = 0;
1685
1686   QListIterator<QGraphicsItem*> anIter( items() );
1687   while( anIter.hasNext() )
1688   {
1689     if( GraphicsView_Object* anObject = dynamic_cast<GraphicsView_Object*>( anIter.next() ) )
1690     {
1691       if( !anObject->isVisible() )
1692         continue;
1693
1694       QRectF aRect = anObject->getPullingRect();
1695       if( aRect.contains( thePoint ) && anObject->portContains( thePoint ) )
1696       {
1697         aLockedObject = anObject;
1698         break;
1699       }
1700     }
1701   }
1702
1703   myPullingObject->pull( thePoint, aLockedObject, getSelectedObjects() );
1704 }
1705
1706 //================================================================
1707 // Function : finishPulling
1708 // Purpose  : 
1709 //================================================================
1710 void GraphicsView_ViewPort::finishPulling( bool theStatus )
1711 {
1712   myIsPulling = false;
1713   myPullingObject->finishPulling( theStatus, getSelectedObjects() );
1714   setCursor( *getDefaultCursor() );
1715 }
1716
1717 //================================================================
1718 // Function : cancelCurrentOperation
1719 // Purpose  : 
1720 //================================================================
1721 bool GraphicsView_ViewPort::cancelCurrentOperation()
1722 {
1723   myIsHighlighting = false;
1724
1725   if( isDragging() )
1726   {
1727     for( initSelected(); moreSelected(); nextSelected() )
1728       if( GraphicsView_Object* aMovingObject = selectedObject() )
1729         aMovingObject->finishMove( false );
1730
1731     if( GraphicsView_Object* aMovingObject = getHighlightedObject() )
1732       aMovingObject->finishMove( false );
1733
1734     myIsDragging = false;
1735     myDragPosition = QPointF();
1736     //setCursor( myStoredCursor );
1737     setCursor( *getDefaultCursor() );
1738
1739     return true;
1740   }
1741
1742   if( isPulling() )
1743   {
1744     finishPulling( false );
1745     return true;
1746   }
1747
1748   if( isSketching() || isPrepareToSketch() )
1749   {
1750     finishSketching( false );
1751     return true;
1752   }
1753
1754   return false;
1755 }
1756
1757 //================================================================
1758 // Function : onBoundingRectChanged
1759 // Purpose  : 
1760 //================================================================
1761 void GraphicsView_ViewPort::onBoundingRectChanged()
1762 {
1763   if( hasInteractionFlag( TraceBoundingRect ) )
1764   {
1765     QRectF aRect = objectsBoundingRect( true );
1766     myScene->setSceneRect( aRect.adjusted( -mySceneGap, -mySceneGap, mySceneGap, mySceneGap ) );
1767   }
1768 }
1769
1770 //================================================================
1771 // Function : onKeyEvent
1772 // Purpose  : 
1773 //================================================================
1774 void GraphicsView_ViewPort::onKeyEvent( QKeyEvent* e )
1775 {
1776   emit vpKeyEvent( e );
1777 }
1778
1779 //================================================================
1780 // Function : onMouseEvent
1781 // Purpose  : 
1782 //================================================================
1783 void GraphicsView_ViewPort::onMouseEvent( QGraphicsSceneMouseEvent* e )
1784 {
1785   emit vpMouseEvent( e );
1786
1787   bool anIsHandled = false;
1788   switch( e->type() )
1789   {
1790     case QEvent::GraphicsSceneMousePress:
1791     {
1792       if( hasInteractionFlag( EditFlags ) && nbSelected() )
1793         for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1794           if( GraphicsView_Object* anObject = selectedObject() )
1795             anIsHandled = anObject->handleMousePress( e );
1796
1797       if( !anIsHandled && hasInteractionFlag( Dragging ) )
1798       {
1799         bool anAccel = e->modifiers() & GraphicsView_ViewTransformer::accelKey();
1800         if( ( getHighlightedObject() &&
1801               getHighlightedObject()->isMovable() &&
1802               !( anAccel || e->button() != Qt::LeftButton ) ) ||
1803             ( ( ( hasInteractionFlag( DraggingByMiddleButton ) && e->button() == Qt::MidButton ) ||
1804                 ( isDraggingSelectedByLeftButton() && e->button() == Qt::LeftButton ) ) &&
1805               nbSelected() && !anAccel ) )
1806         {
1807           myIsDragging = true;
1808           myStoredCursor = cursor();
1809           setCursor( Qt::ClosedHandCursor );
1810         }
1811       }
1812       break;
1813     }
1814     case QEvent::GraphicsSceneMouseMove:
1815     {
1816       if( hasInteractionFlag( EditFlags ) && nbSelected() )
1817         for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1818           if( GraphicsView_Object* anObject = selectedObject() )
1819             anIsHandled = anObject->handleMouseMove( e );
1820
1821       if( !anIsHandled && !isPulling() && myIsDragging )
1822         dragObjects( e );
1823       break;
1824     }
1825     case QEvent::GraphicsSceneMouseRelease:
1826     {
1827       if( hasInteractionFlag( EditFlags ) && nbSelected() )
1828         for( initSelected(); moreSelected() && !anIsHandled; nextSelected() )
1829           if( GraphicsView_Object* anObject = selectedObject() )
1830             anIsHandled = anObject->handleMouseRelease( e );
1831
1832       if( !anIsHandled && !isPulling() && myIsDragging )
1833       {
1834         emit vpObjectBeforeMoving();
1835
1836         bool anIsMoved = false;
1837         for( initSelected(); moreSelected(); nextSelected() )
1838           if( GraphicsView_Object* aMovingObject = selectedObject() )
1839             anIsMoved = aMovingObject->finishMove( true ) || anIsMoved;
1840
1841         if( GraphicsView_Object* aMovingObject = getHighlightedObject() )
1842           anIsMoved = aMovingObject->finishMove( true ) || anIsMoved;
1843
1844         myIsDragging = false;
1845         myDragPosition = QPointF();
1846         setCursor( myStoredCursor );
1847
1848         emit vpObjectAfterMoving( anIsMoved );
1849       }
1850       break;
1851     }
1852     case QEvent::GraphicsSceneMouseDoubleClick:
1853       break; // do nothing, just emit the signal
1854     default:
1855       break;
1856   }
1857
1858   if( myIsMousePositionEnabled )
1859   {
1860     int aMouseX = (int)e->scenePos().x();
1861     int aMouseY = (int)e->scenePos().y();
1862     setViewLabelText( QString( "(%1, %2)" ).arg( aMouseX ).arg( aMouseY ) );
1863   }
1864 }
1865
1866 //================================================================
1867 // Function : onWheelEvent
1868 // Purpose  : 
1869 //================================================================
1870 void GraphicsView_ViewPort::onWheelEvent( QGraphicsSceneWheelEvent* e )
1871 {
1872   emit vpWheelEvent( e );
1873 }
1874
1875 //================================================================
1876 // Function : onContextMenuEvent
1877 // Purpose  : 
1878 //================================================================
1879 void GraphicsView_ViewPort::onContextMenuEvent( QGraphicsSceneContextMenuEvent* e )
1880 {
1881   emit vpContextMenuEvent( e );
1882 }
1883
1884 //================================================================
1885 // Function : scrollContentsBy
1886 // Purpose  : 
1887 //================================================================
1888 void GraphicsView_ViewPort::scrollContentsBy( int theDX, int theDY )
1889 {
1890   if( myViewLabel )
1891     myViewLabel->setAcceptMoveEvents( false );
1892
1893   QGraphicsView::scrollContentsBy( theDX, theDY );
1894
1895   if( myViewLabel )
1896     myViewLabel->setAcceptMoveEvents( true );
1897 }