1 // Copyright (C) 2007-2012 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
23 // SALOME QxGraph : build Supervisor viewer into desktop
25 #include "QxGraph_CanvasView.h"
26 #include "QxGraph_Canvas.h"
27 #include "QxGraph_ViewWindow.h"
28 #include "QxGraph_ActiveItem.h"
29 #include "QxGraph_Def.h"
34 const char* imageZoomCursor[] = {
39 "................................",
40 "................................",
41 ".#######........................",
42 "..aaaaaaa.......................",
43 "................................",
44 ".............#####..............",
45 "...........##.aaaa##............",
46 "..........#.aa.....a#...........",
47 ".........#.a.........#..........",
48 ".........#a..........#a.........",
49 "........#.a...........#.........",
50 "........#a............#a........",
51 "........#a............#a........",
52 "........#a............#a........",
53 "........#a............#a........",
54 ".........#...........#.a........",
55 ".........#a..........#a.........",
56 ".........##.........#.a.........",
57 "........#####.....##.a..........",
58 ".......###aaa#####.aa...........",
59 "......###aa...aaaaa.......#.....",
60 ".....###aa................#a....",
61 "....###aa.................#a....",
62 "...###aa...............#######..",
63 "....#aa.................aa#aaaa.",
64 ".....a....................#a....",
65 "..........................#a....",
66 "...........................a....",
67 "................................",
68 "................................",
69 "................................",
70 "................................"};
72 const char* imageCrossCursor[] = {
77 "................................",
78 "................................",
79 "................................",
80 "................................",
81 "................................",
82 "................................",
83 "................................",
84 "...............#................",
85 "...............#a...............",
86 "...............#a...............",
87 "...............#a...............",
88 "...............#a...............",
89 "...............#a...............",
90 "...............#a...............",
91 "...............#a...............",
92 ".......#################........",
93 "........aaaaaaa#aaaaaaaaa.......",
94 "...............#a...............",
95 "...............#a...............",
96 "...............#a...............",
97 "...............#a...............",
98 "...............#a...............",
99 "...............#a...............",
100 "...............#a...............",
101 "................a...............",
102 "................................",
103 "................................",
104 "................................",
105 "................................",
106 "................................",
107 "................................",
108 "................................"};
113 QxGraph_CanvasView::QxGraph_CanvasView(QxGraph_Canvas* theCanvas, QxGraph_ViewWindow* theViewWindow) :
114 QCanvasView(theCanvas, theViewWindow, 0, Qt::WRepaintNoErase),
121 printf("Construct QxGraph_CanvasView\n");
122 setName("QxGraph_CanvasView");
124 myOperation = NOTHING;
128 myTimer = new QTimer(this);
129 connect(myTimer, SIGNAL(timeout()), this, SLOT(onTimeout()));
131 viewport()->setMouseTracking(true);
137 QxGraph_CanvasView::~QxGraph_CanvasView()
141 void QxGraph_CanvasView::contentsMousePressEvent(QMouseEvent* theEvent)
143 myPoint = inverseWorldMatrix().map(theEvent->pos());
144 myGlobalPoint = theEvent->globalPos();
147 if ( theEvent->button() == Qt::MidButton && theEvent->state() == Qt::ControlButton
149 myOperation == PANVIEW )
151 if ( myOperation != PANVIEW ) {
152 myOperation = PANVIEW;
153 myCursor = cursor(); // save old cursor
154 QCursor panCursor (Qt::SizeAllCursor);
155 setCursor(panCursor);
160 if ( myOperation == PANGLOBAL )
165 if ( myOperation == WINDOWFIT )
170 if ( theEvent->button() == Qt::LeftButton && theEvent->state() == Qt::ControlButton
172 myOperation == ZOOMVIEW )
174 if ( myOperation != ZOOMVIEW ) {
175 myOperation = ZOOMVIEW;
176 myCursor = cursor(); // save old cursor
177 QPixmap zoomPixmap (imageZoomCursor);
178 QCursor zoomCursor (zoomPixmap);
179 setCursor(zoomCursor);
181 // the center of the view before zooming
182 int aXVCenter = viewport()->width()/2;
183 int aYVCenter = viewport()->height()/2;
184 myCenter = viewportToContents(QPoint(aXVCenter,aYVCenter));
189 if ( theEvent->button() == Qt::LeftButton )
191 QCanvasItemList aList = canvas()->collisions(myPoint);
192 // to move items on canvas view
193 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
194 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
196 if ( anActItem && anActItem->isResizable(myPoint,aCursorType) )
197 { // resize itself only active items if it is resizable
198 anActItem->beforeResizing(aCursorType);
202 else if ( anActItem && anActItem->isMoveable() )
203 { // move itself only active items if it is moveable
204 anActItem->beforeMoving();
212 void QxGraph_CanvasView::contentsMouseMoveEvent(QMouseEvent* theEvent)
214 QPoint aPoint = inverseWorldMatrix().map(theEvent->pos());
215 QPoint aGlobalPoint = theEvent->globalPos();
217 if (myTimer->isActive()) myTimer->stop();
219 if ( myOperation == PANVIEW )
221 scrollBy(myGlobalPoint.x() - aGlobalPoint.x(),
222 myGlobalPoint.y() - aGlobalPoint.y());
223 myGlobalPoint = aGlobalPoint;
228 if ( myOperation == WINDOWFIT )
229 { // Fit within rectangle
230 int aLX, aTY; //left x and top y
231 if (myPoint.x() < aPoint.x()) aLX = myPoint.x();
232 else aLX = aPoint.x();
233 if (myPoint.y() < aPoint.y()) aTY = myPoint.y();
234 else aTY = aPoint.y();
235 QRect aRect(aLX, aTY, abs(myPoint.x()-aPoint.x()), abs(myPoint.y()-aPoint.y()));
236 QCanvasRectangle* aRect1 = new QCanvasRectangle(aRect, canvas());
238 //hide old selected rectangle
240 mySelectedRect->hide();
241 //draw new selected rectangle
242 QPen pen(Qt::black,1,Qt::SolidLine);
247 mySelectedRect = aRect1;
253 if ( myOperation == ZOOMVIEW )
255 QCanvasItemList aList = canvas()->allItems();
256 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it)
259 int aXContCenter = myCenter.x();
260 int aYContCenter = myCenter.y();
262 QWMatrix m = worldMatrix();
264 double dx = aGlobalPoint.x() - myGlobalPoint.x();
265 double s = 1. + fabs(dx)*( (m.m11() < 1) ? m.m11() : 1. )/70.;
266 if (dx < 0) s = 1./s;
268 int aXContCenterScaled = aXContCenter*s;
269 int aYContCenterScaled = aYContCenter*s;
274 center(aXContCenterScaled,aYContCenterScaled);
276 myCenter.setX(aXContCenterScaled);
277 myCenter.setY(aYContCenterScaled);
279 // remember the canvas view's current transformation matrix in all canvas items
280 aList = canvas()->allItems();
281 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
282 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
283 if ( anActItem ) anActItem->setTMatrix(m);
287 myGlobalPoint = aGlobalPoint;
295 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( myCurrentItem );
296 if ( anActItem && anActItem->isResizing() )
297 { // to resize items on canvas view
298 anActItem->resize(aPoint);
303 // to move items on canvas view
304 if ( myCurrentItem->x() && myCurrentItem->y() ) {
305 double cx = myCurrentItem->x() - myPoint.x();
306 double cy = myCurrentItem->y() - myPoint.y();
308 if (aPoint.x()+cx < 0) aPoint.setX(-(int)cx);
309 if (aPoint.y()+cy < 0) aPoint.setY(-(int)cy);
311 myCurrentItem->moveBy(aPoint.x() - myPoint.x(),
312 aPoint.y() - myPoint.y());
317 // scroll contents if mouse is outside
318 QRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight());
319 if (!r.contains(theEvent->pos())) {
321 if (theEvent->pos().x() < r.left()) dx = theEvent->pos().x() - r.left();
322 if (theEvent->pos().x() > r.right()) dx = theEvent->pos().x() - r.right();
323 if (theEvent->pos().y() < r.top()) dy = theEvent->pos().y() - r.top();
324 if (theEvent->pos().y() > r.bottom()) dy = theEvent->pos().y() - r.bottom();
326 // start timer to scroll in silent mode
327 myDX = dx; myDY = dy;
335 QCanvasItemList aList = canvas()->collisions(aPoint);
336 // perform actions for active items
337 bool isHilightPerformed = false;
339 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
340 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
342 if (!isHilightPerformed && anActItem) {
344 anActItem->hilight(aPoint);
345 if (anActItem != myHilightedItem) {
347 myHilightedItem->hilight(aPoint, false);
348 myHilightedItem = anActItem;
350 isHilightPerformed = true;
353 QxGraph_ToolTip* aToolTip = new QxGraph_ToolTip(this);
354 aToolTip->maybeTip(aPoint);
358 if ( anActItem && anActItem->isResizable(aPoint,aCursorType) ) {
360 QCursor resizeCursor;
365 resizeCursor = QCursor(Qt::SizeHorCursor);
369 resizeCursor = QCursor(Qt::SizeVerCursor);
372 case 7: //right-bottom
373 resizeCursor = QCursor(Qt::SizeFDiagCursor);
376 case 8: //left-bottom
377 resizeCursor = QCursor(Qt::SizeBDiagCursor);
380 resizeCursor = QCursor(Qt::ArrowCursor);
383 setCursor(resizeCursor);
388 setCursor(QCursor(Qt::ArrowCursor));
393 if (!isHilightPerformed && myHilightedItem) {
394 myHilightedItem->hilight(aPoint, false);
396 QToolTip::hide(); //@ temporary solution
399 if ( cursor().shape() == Qt::SizeVerCursor || cursor().shape() == Qt::SizeHorCursor
400 || cursor().shape() == Qt::SizeBDiagCursor || cursor().shape() == Qt::SizeFDiagCursor)
401 setCursor(QCursor(Qt::ArrowCursor));
406 This method is called by QxGraph_Canvas when item is removed.
407 QxGraph_CanvasView updates its own data accordingly
409 void QxGraph_CanvasView::itemRemoved( QCanvasItem* theItem )
411 if ( myCurrentItem == theItem )
414 QxGraph_ActiveItem* anActiveItem = dynamic_cast<QxGraph_ActiveItem*>( theItem );
417 if ( myHilightedItem == anActiveItem )
419 if ( mySelectedItem == anActiveItem )
424 void QxGraph_CanvasView::setSelectedItem( QxGraph_ActiveItem* theItem )
426 mySelectedItem = theItem;
429 QxGraph_ActiveItem* QxGraph_CanvasView::getSelectedItem() const
431 return mySelectedItem;
434 void QxGraph_CanvasView::contentsMouseReleaseEvent(QMouseEvent* theEvent)
436 QPoint aPoint = inverseWorldMatrix().map(theEvent->pos());
438 if (myTimer->isActive()) myTimer->stop();
441 { // to move items on canvas view
442 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( myCurrentItem );
443 if ( anActItem && anActItem->isResizing() )
445 anActItem->afterResizing();
447 setCursor(QCursor(Qt::ArrowCursor));
449 else if ( anActItem && anActItem->isMoveable() )
450 anActItem->afterMoving();
454 if ( myOperation == PANVIEW )
456 myOperation = NOTHING;
457 viewport()->setMouseTracking(true);
460 emit viewOperationDone();
463 if ( myOperation == PANGLOBAL )
465 myOperation = NOTHING;
466 center( theEvent->x(), theEvent->y() );
469 emit viewOperationDone();
472 if ( myOperation == WINDOWFIT )
473 { // Fit within rectangle
474 myOperation = NOTHING;
476 if (mySelectedRect) {
477 mySelectedRect->hide();
479 //canvas()->update();
482 //myPoint is the start point for selecting rectangle now
483 int aLX, aTY; //left x and top y
484 if (myPoint.x() < aPoint.x()) aLX = myPoint.x();
485 else aLX = aPoint.x();
486 if (myPoint.y() < aPoint.y()) aTY = myPoint.y();
487 else aTY = aPoint.y();
489 //calculate width and height for new view and new zoom factor
490 double aXzoom = ((double)visibleWidth())/((double)(abs(myPoint.x()-aPoint.x())));
491 double aYzoom = ((double)visibleHeight())/((double)(abs(myPoint.y()-aPoint.y())));
492 if (aXzoom > aYzoom) aXzoom = aYzoom;
495 m.scale(aXzoom, aXzoom);
498 // remember the canvas view's current transformation matrix in all canvas items
499 QCanvasItemList aList = canvas()->allItems();
500 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
501 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
502 if ( anActItem ) anActItem->setTMatrix(m);
505 setContentsPos((int)(aLX*aXzoom), (int)(aTY*aYzoom));
509 viewport()->setMouseTracking(true);
512 emit viewOperationDone();
515 if ( myOperation == ZOOMVIEW )
517 myOperation = NOTHING;
518 viewport()->setMouseTracking(true);
521 emit viewOperationDone();
524 if ( theEvent->button() == RightButton )
526 // Selection mechanism
527 QCanvasItemList aList = canvas()->collisions(aPoint);
528 bool isSelectionPerformed = false;
530 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
531 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
532 if (!isSelectionPerformed && anActItem)
534 anActItem->select(aPoint);
535 if (anActItem != mySelectedItem)
537 if (mySelectedItem && isSelectedItemInCanvas() &&
538 !mySelectedItem->arePartsOfOtherItem(anActItem)) mySelectedItem->select(aPoint, false);
539 mySelectedItem = anActItem;
541 // unhilight hilighted item if selection was performed
542 if (myHilightedItem) {
543 myHilightedItem->hilight(aPoint, false);
547 isSelectionPerformed = true;
551 if (!isSelectionPerformed)
553 if ( mySelectedItem )
555 if ( isSelectedItemInCanvas() ) mySelectedItem->select(aPoint, false);
560 printf("Background popup\n");
561 QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
562 theEvent->pos(), theEvent->globalPos(),
564 if ( getViewWindow() )
565 getViewWindow()->contextPopupEvent(&aEvent); // => emit contextMenuRequested( &aEvent );
568 { // show context popup for the selected item
569 mySelectedItem->showPopup(viewport(), theEvent, aPoint);
573 if ( theEvent->button() == LeftButton && !myMovingDone )
575 // Selection mechanism
576 QCanvasItemList aList = canvas()->collisions(aPoint);
578 if ( aList.empty() && mySelectedItem )
580 if ( isSelectedItemInCanvas() ) mySelectedItem->select(aPoint, false);
585 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
586 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
589 anActItem->select(aPoint);
590 if (anActItem != mySelectedItem)
592 if (mySelectedItem && isSelectedItemInCanvas() &&
593 !mySelectedItem->arePartsOfOtherItem(anActItem)) mySelectedItem->select(aPoint, false);
594 mySelectedItem = anActItem;
602 myMovingDone = false;
605 void QxGraph_CanvasView::contentsMouseDoubleClickEvent(QMouseEvent* theEvent)
610 bool QxGraph_CanvasView::isSelectedItemInCanvas()
612 // check if mySelectedItem is included into the canvas:
613 // if yes => unselect it
614 // if no => do nothing
615 bool anIsInCanvas = false;
616 QCanvasItemList aListC = canvas()->allItems();
617 for (QCanvasItemList::Iterator itC = aListC.begin(); itC != aListC.end(); ++itC) {
618 QxGraph_ActiveItem* anActItemC = dynamic_cast<QxGraph_ActiveItem*>( *itC );
619 if ( anActItemC && anActItemC == mySelectedItem ) {
627 void QxGraph_CanvasView::activateFitAll()
629 //myOperation = FITALL;
631 QCanvasItemList l = canvas()->allItems();
632 for (QCanvasItemList::Iterator it = l.begin(); it != l.end(); ++it) {
633 QRect r = (*it)->boundingRect();
634 if (w < r.right()) w = r.right();
635 if (h < r.bottom()) h = r.bottom();
637 w += GRAPH_MARGIN; h += GRAPH_MARGIN;
638 double s = ((double)visibleWidth())/((double)w);
639 double s1 = ((double)visibleHeight())/((double)h);
647 // remember the canvas view's current transformation matrix in all canvas items
648 QCanvasItemList aList = canvas()->allItems();
649 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
650 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
651 if ( anActItem ) anActItem->setTMatrix(m);
655 //myOperation = NOTHING;
657 emit viewOperationDone();
660 void QxGraph_CanvasView::activateFitRect()
662 myOperation = WINDOWFIT;
663 viewport()->setMouseTracking(false);
664 myCursor = cursor(); // save old cursor
665 QCursor handCursor (Qt::PointingHandCursor);
666 setCursor(handCursor);
669 void QxGraph_CanvasView::activateZoom()
671 myOperation = ZOOMVIEW;
672 viewport()->setMouseTracking(false);
673 myCursor = cursor(); // save old cursor
674 QPixmap zoomPixmap (imageZoomCursor);
675 QCursor zoomCursor (zoomPixmap);
676 setCursor(zoomCursor);
679 void QxGraph_CanvasView::activatePanning()
681 myOperation = PANVIEW;
682 viewport()->setMouseTracking(false);
683 myCursor = cursor(); // save old cursor
684 QCursor panCursor (Qt::SizeAllCursor);
685 setCursor(panCursor);
688 void QxGraph_CanvasView::activateGlobalPanning()
690 myOperation = PANGLOBAL;
691 myCursor = cursor(); // save old cursor
692 QPixmap globalPanPixmap (imageCrossCursor);
693 QCursor glPanCursor (globalPanPixmap);
694 setCursor(glPanCursor);
697 void QxGraph_CanvasView::activateReset()
699 //myOperation = RESETVIEW;
704 // remember the canvas view's current transformation matrix in all canvas items
705 QCanvasItemList aList = canvas()->allItems();
706 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
707 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
708 if ( anActItem ) anActItem->setTMatrix(m);
711 //myOperation = NOTHING;
713 emit viewOperationDone();
716 void QxGraph_CanvasView::onTimeout()
719 scrollBy(myDX, myDY);
722 inverseWorldMatrix().map((double)myDX, (double)myDY, &cx, &cy);
723 if (myCurrentItem->x()+cx < 0) cx = -myCurrentItem->x();
724 if (myCurrentItem->y()+cy < 0) cy = -myCurrentItem->y();
725 myCurrentItem->moveBy(cx, cy);
726 myPoint.setX(myPoint.x()+(int)cx);
727 myPoint.setY(myPoint.y()+(int)cy);
732 QxGraph_ViewWindow* QxGraph_CanvasView::getViewWindow() const
734 return dynamic_cast<QxGraph_ViewWindow*>( parent() );
738 Shows tooltip if necessary
740 void QxGraph_ToolTip::maybeTip(const QPoint& theMousePos) {
741 QCanvasItemList aList = ((QCanvasView*)parentWidget())->canvas()->collisions(theMousePos);
743 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
744 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
748 QString aText = anActItem->getToolTipText(theMousePos, aRect);
750 QWMatrix aWM = ((QCanvasView*)parentWidget())->worldMatrix();
751 ((QCanvasView*)parentWidget())->contentsToViewport((int)(aRect.left()*aWM.m11()),
752 (int)(aRect.top()*aWM.m22()),
754 QRect aTipRect(avX, avY, (int)(aRect.width()*aWM.m11()), (int)(aRect.height()*aWM.m22()));
755 if (!aText.isEmpty())
756 tip(aTipRect, aText);