1 // Copyright (C) 2007-2008 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
22 // SALOME QxGraph : build Supervisor viewer into desktop
24 #include "QxGraph_CanvasView.h"
25 #include "QxGraph_Canvas.h"
26 #include "QxGraph_ViewWindow.h"
27 #include "QxGraph_ActiveItem.h"
28 #include "QxGraph_Def.h"
33 const char* imageZoomCursor[] = {
38 "................................",
39 "................................",
40 ".#######........................",
41 "..aaaaaaa.......................",
42 "................................",
43 ".............#####..............",
44 "...........##.aaaa##............",
45 "..........#.aa.....a#...........",
46 ".........#.a.........#..........",
47 ".........#a..........#a.........",
48 "........#.a...........#.........",
49 "........#a............#a........",
50 "........#a............#a........",
51 "........#a............#a........",
52 "........#a............#a........",
53 ".........#...........#.a........",
54 ".........#a..........#a.........",
55 ".........##.........#.a.........",
56 "........#####.....##.a..........",
57 ".......###aaa#####.aa...........",
58 "......###aa...aaaaa.......#.....",
59 ".....###aa................#a....",
60 "....###aa.................#a....",
61 "...###aa...............#######..",
62 "....#aa.................aa#aaaa.",
63 ".....a....................#a....",
64 "..........................#a....",
65 "...........................a....",
66 "................................",
67 "................................",
68 "................................",
69 "................................"};
71 const char* imageCrossCursor[] = {
76 "................................",
77 "................................",
78 "................................",
79 "................................",
80 "................................",
81 "................................",
82 "................................",
83 "...............#................",
84 "...............#a...............",
85 "...............#a...............",
86 "...............#a...............",
87 "...............#a...............",
88 "...............#a...............",
89 "...............#a...............",
90 "...............#a...............",
91 ".......#################........",
92 "........aaaaaaa#aaaaaaaaa.......",
93 "...............#a...............",
94 "...............#a...............",
95 "...............#a...............",
96 "...............#a...............",
97 "...............#a...............",
98 "...............#a...............",
99 "...............#a...............",
100 "................a...............",
101 "................................",
102 "................................",
103 "................................",
104 "................................",
105 "................................",
106 "................................",
107 "................................"};
112 QxGraph_CanvasView::QxGraph_CanvasView(QxGraph_Canvas* theCanvas, QxGraph_ViewWindow* theViewWindow) :
113 QCanvasView(theCanvas, theViewWindow, 0, Qt::WRepaintNoErase),
120 printf("Construct QxGraph_CanvasView\n");
121 setName("QxGraph_CanvasView");
123 myOperation = NOTHING;
127 myTimer = new QTimer(this);
128 connect(myTimer, SIGNAL(timeout()), this, SLOT(onTimeout()));
130 viewport()->setMouseTracking(true);
136 QxGraph_CanvasView::~QxGraph_CanvasView()
140 void QxGraph_CanvasView::contentsMousePressEvent(QMouseEvent* theEvent)
142 myPoint = inverseWorldMatrix().map(theEvent->pos());
143 myGlobalPoint = theEvent->globalPos();
146 if ( theEvent->button() == Qt::MidButton && theEvent->state() == Qt::ControlButton
148 myOperation == PANVIEW )
150 if ( myOperation != PANVIEW ) {
151 myOperation = PANVIEW;
152 myCursor = cursor(); // save old cursor
153 QCursor panCursor (Qt::SizeAllCursor);
154 setCursor(panCursor);
159 if ( myOperation == PANGLOBAL )
164 if ( myOperation == WINDOWFIT )
169 if ( theEvent->button() == Qt::LeftButton && theEvent->state() == Qt::ControlButton
171 myOperation == ZOOMVIEW )
173 if ( myOperation != ZOOMVIEW ) {
174 myOperation = ZOOMVIEW;
175 myCursor = cursor(); // save old cursor
176 QPixmap zoomPixmap (imageZoomCursor);
177 QCursor zoomCursor (zoomPixmap);
178 setCursor(zoomCursor);
180 // the center of the view before zooming
181 int aXVCenter = viewport()->width()/2;
182 int aYVCenter = viewport()->height()/2;
183 myCenter = viewportToContents(QPoint(aXVCenter,aYVCenter));
188 if ( theEvent->button() == Qt::LeftButton )
190 QCanvasItemList aList = canvas()->collisions(myPoint);
191 // to move items on canvas view
192 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
193 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
195 if ( anActItem && anActItem->isResizable(myPoint,aCursorType) )
196 { // resize itself only active items if it is resizable
197 anActItem->beforeResizing(aCursorType);
201 else if ( anActItem && anActItem->isMoveable() )
202 { // move itself only active items if it is moveable
203 anActItem->beforeMoving();
211 void QxGraph_CanvasView::contentsMouseMoveEvent(QMouseEvent* theEvent)
213 QPoint aPoint = inverseWorldMatrix().map(theEvent->pos());
214 QPoint aGlobalPoint = theEvent->globalPos();
216 if (myTimer->isActive()) myTimer->stop();
218 if ( myOperation == PANVIEW )
220 scrollBy(myGlobalPoint.x() - aGlobalPoint.x(),
221 myGlobalPoint.y() - aGlobalPoint.y());
222 myGlobalPoint = aGlobalPoint;
227 if ( myOperation == WINDOWFIT )
228 { // Fit within rectangle
229 int aLX, aTY; //left x and top y
230 if (myPoint.x() < aPoint.x()) aLX = myPoint.x();
231 else aLX = aPoint.x();
232 if (myPoint.y() < aPoint.y()) aTY = myPoint.y();
233 else aTY = aPoint.y();
234 QRect aRect(aLX, aTY, abs(myPoint.x()-aPoint.x()), abs(myPoint.y()-aPoint.y()));
235 QCanvasRectangle* aRect1 = new QCanvasRectangle(aRect, canvas());
237 //hide old selected rectangle
239 mySelectedRect->hide();
240 //draw new selected rectangle
241 QPen pen(Qt::black,1,Qt::SolidLine);
246 mySelectedRect = aRect1;
252 if ( myOperation == ZOOMVIEW )
254 QCanvasItemList aList = canvas()->allItems();
255 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it)
258 int aXContCenter = myCenter.x();
259 int aYContCenter = myCenter.y();
261 QWMatrix m = worldMatrix();
263 double dx = aGlobalPoint.x() - myGlobalPoint.x();
264 double s = 1. + fabs(dx)*( (m.m11() < 1) ? m.m11() : 1. )/70.;
265 if (dx < 0) s = 1./s;
267 int aXContCenterScaled = aXContCenter*s;
268 int aYContCenterScaled = aYContCenter*s;
273 center(aXContCenterScaled,aYContCenterScaled);
275 myCenter.setX(aXContCenterScaled);
276 myCenter.setY(aYContCenterScaled);
278 // remember the canvas view's current transformation matrix in all canvas items
279 aList = canvas()->allItems();
280 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
281 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
282 if ( anActItem ) anActItem->setTMatrix(m);
286 myGlobalPoint = aGlobalPoint;
294 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( myCurrentItem );
295 if ( anActItem && anActItem->isResizing() )
296 { // to resize items on canvas view
297 anActItem->resize(aPoint);
302 // to move items on canvas view
303 if ( myCurrentItem->x() && myCurrentItem->y() ) {
304 double cx = myCurrentItem->x() - myPoint.x();
305 double cy = myCurrentItem->y() - myPoint.y();
307 if (aPoint.x()+cx < 0) aPoint.setX(-(int)cx);
308 if (aPoint.y()+cy < 0) aPoint.setY(-(int)cy);
310 myCurrentItem->moveBy(aPoint.x() - myPoint.x(),
311 aPoint.y() - myPoint.y());
316 // scroll contents if mouse is outside
317 QRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight());
318 if (!r.contains(theEvent->pos())) {
320 if (theEvent->pos().x() < r.left()) dx = theEvent->pos().x() - r.left();
321 if (theEvent->pos().x() > r.right()) dx = theEvent->pos().x() - r.right();
322 if (theEvent->pos().y() < r.top()) dy = theEvent->pos().y() - r.top();
323 if (theEvent->pos().y() > r.bottom()) dy = theEvent->pos().y() - r.bottom();
325 // start timer to scroll in silent mode
326 myDX = dx; myDY = dy;
334 QCanvasItemList aList = canvas()->collisions(aPoint);
335 // perform actions for active items
336 bool isHilightPerformed = false;
338 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
339 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
341 if (!isHilightPerformed && anActItem) {
343 anActItem->hilight(aPoint);
344 if (anActItem != myHilightedItem) {
346 myHilightedItem->hilight(aPoint, false);
347 myHilightedItem = anActItem;
349 isHilightPerformed = true;
352 QxGraph_ToolTip* aToolTip = new QxGraph_ToolTip(this);
353 aToolTip->maybeTip(aPoint);
357 if ( anActItem && anActItem->isResizable(aPoint,aCursorType) ) {
359 QCursor resizeCursor;
364 resizeCursor = QCursor(Qt::SizeHorCursor);
368 resizeCursor = QCursor(Qt::SizeVerCursor);
371 case 7: //right-bottom
372 resizeCursor = QCursor(Qt::SizeFDiagCursor);
375 case 8: //left-bottom
376 resizeCursor = QCursor(Qt::SizeBDiagCursor);
379 resizeCursor = QCursor(Qt::ArrowCursor);
382 setCursor(resizeCursor);
387 setCursor(QCursor(Qt::ArrowCursor));
392 if (!isHilightPerformed && myHilightedItem) {
393 myHilightedItem->hilight(aPoint, false);
395 QToolTip::hide(); //@ temporary solution
398 if ( cursor().shape() == Qt::SizeVerCursor || cursor().shape() == Qt::SizeHorCursor
399 || cursor().shape() == Qt::SizeBDiagCursor || cursor().shape() == Qt::SizeFDiagCursor)
400 setCursor(QCursor(Qt::ArrowCursor));
405 This method is called by QxGraph_Canvas when item is removed.
406 QxGraph_CanvasView updates its own data accordingly
408 void QxGraph_CanvasView::itemRemoved( QCanvasItem* theItem )
410 if ( myCurrentItem == theItem )
413 QxGraph_ActiveItem* anActiveItem = dynamic_cast<QxGraph_ActiveItem*>( theItem );
416 if ( myHilightedItem == anActiveItem )
418 if ( mySelectedItem == anActiveItem )
423 void QxGraph_CanvasView::setSelectedItem( QxGraph_ActiveItem* theItem )
425 mySelectedItem = theItem;
428 QxGraph_ActiveItem* QxGraph_CanvasView::getSelectedItem() const
430 return mySelectedItem;
433 void QxGraph_CanvasView::contentsMouseReleaseEvent(QMouseEvent* theEvent)
435 QPoint aPoint = inverseWorldMatrix().map(theEvent->pos());
437 if (myTimer->isActive()) myTimer->stop();
440 { // to move items on canvas view
441 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( myCurrentItem );
442 if ( anActItem && anActItem->isResizing() )
444 anActItem->afterResizing();
446 setCursor(QCursor(Qt::ArrowCursor));
448 else if ( anActItem && anActItem->isMoveable() )
449 anActItem->afterMoving();
453 if ( myOperation == PANVIEW )
455 myOperation = NOTHING;
456 viewport()->setMouseTracking(true);
459 emit viewOperationDone();
462 if ( myOperation == PANGLOBAL )
464 myOperation = NOTHING;
465 center( theEvent->x(), theEvent->y() );
468 emit viewOperationDone();
471 if ( myOperation == WINDOWFIT )
472 { // Fit within rectangle
473 myOperation = NOTHING;
475 if (mySelectedRect) {
476 mySelectedRect->hide();
478 //canvas()->update();
481 //myPoint is the start point for selecting rectangle now
482 int aLX, aTY; //left x and top y
483 if (myPoint.x() < aPoint.x()) aLX = myPoint.x();
484 else aLX = aPoint.x();
485 if (myPoint.y() < aPoint.y()) aTY = myPoint.y();
486 else aTY = aPoint.y();
488 //calculate width and height for new view and new zoom factor
489 double aXzoom = ((double)visibleWidth())/((double)(abs(myPoint.x()-aPoint.x())));
490 double aYzoom = ((double)visibleHeight())/((double)(abs(myPoint.y()-aPoint.y())));
491 if (aXzoom > aYzoom) aXzoom = aYzoom;
494 m.scale(aXzoom, aXzoom);
497 // remember the canvas view's current transformation matrix in all canvas items
498 QCanvasItemList aList = canvas()->allItems();
499 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
500 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
501 if ( anActItem ) anActItem->setTMatrix(m);
504 setContentsPos((int)(aLX*aXzoom), (int)(aTY*aYzoom));
508 viewport()->setMouseTracking(true);
511 emit viewOperationDone();
514 if ( myOperation == ZOOMVIEW )
516 myOperation = NOTHING;
517 viewport()->setMouseTracking(true);
520 emit viewOperationDone();
523 if ( theEvent->button() == RightButton )
525 // Selection mechanism
526 QCanvasItemList aList = canvas()->collisions(aPoint);
527 bool isSelectionPerformed = false;
529 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
530 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
531 if (!isSelectionPerformed && anActItem)
533 anActItem->select(aPoint);
534 if (anActItem != mySelectedItem)
536 if (mySelectedItem && isSelectedItemInCanvas() &&
537 !mySelectedItem->arePartsOfOtherItem(anActItem)) mySelectedItem->select(aPoint, false);
538 mySelectedItem = anActItem;
540 // unhilight hilighted item if selection was performed
541 if (myHilightedItem) {
542 myHilightedItem->hilight(aPoint, false);
546 isSelectionPerformed = true;
550 if (!isSelectionPerformed)
552 if ( mySelectedItem )
554 if ( isSelectedItemInCanvas() ) mySelectedItem->select(aPoint, false);
559 printf("Background popup\n");
560 QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
561 theEvent->pos(), theEvent->globalPos(),
563 if ( getViewWindow() )
564 getViewWindow()->contextPopupEvent(&aEvent); // => emit contextMenuRequested( &aEvent );
567 { // show context popup for the selected item
568 mySelectedItem->showPopup(viewport(), theEvent, aPoint);
572 if ( theEvent->button() == LeftButton && !myMovingDone )
574 // Selection mechanism
575 QCanvasItemList aList = canvas()->collisions(aPoint);
577 if ( aList.empty() && mySelectedItem )
579 if ( isSelectedItemInCanvas() ) mySelectedItem->select(aPoint, false);
584 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
585 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
588 anActItem->select(aPoint);
589 if (anActItem != mySelectedItem)
591 if (mySelectedItem && isSelectedItemInCanvas() &&
592 !mySelectedItem->arePartsOfOtherItem(anActItem)) mySelectedItem->select(aPoint, false);
593 mySelectedItem = anActItem;
601 myMovingDone = false;
604 void QxGraph_CanvasView::contentsMouseDoubleClickEvent(QMouseEvent* theEvent)
609 bool QxGraph_CanvasView::isSelectedItemInCanvas()
611 // check if mySelectedItem is included into the canvas:
612 // if yes => unselect it
613 // if no => do nothing
614 bool anIsInCanvas = false;
615 QCanvasItemList aListC = canvas()->allItems();
616 for (QCanvasItemList::Iterator itC = aListC.begin(); itC != aListC.end(); ++itC) {
617 QxGraph_ActiveItem* anActItemC = dynamic_cast<QxGraph_ActiveItem*>( *itC );
618 if ( anActItemC && anActItemC == mySelectedItem ) {
626 void QxGraph_CanvasView::activateFitAll()
628 //myOperation = FITALL;
630 QCanvasItemList l = canvas()->allItems();
631 for (QCanvasItemList::Iterator it = l.begin(); it != l.end(); ++it) {
632 QRect r = (*it)->boundingRect();
633 if (w < r.right()) w = r.right();
634 if (h < r.bottom()) h = r.bottom();
636 w += GRAPH_MARGIN; h += GRAPH_MARGIN;
637 double s = ((double)visibleWidth())/((double)w);
638 double s1 = ((double)visibleHeight())/((double)h);
646 // remember the canvas view's current transformation matrix in all canvas items
647 QCanvasItemList aList = canvas()->allItems();
648 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
649 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
650 if ( anActItem ) anActItem->setTMatrix(m);
654 //myOperation = NOTHING;
656 emit viewOperationDone();
659 void QxGraph_CanvasView::activateFitRect()
661 myOperation = WINDOWFIT;
662 viewport()->setMouseTracking(false);
663 myCursor = cursor(); // save old cursor
664 QCursor handCursor (Qt::PointingHandCursor);
665 setCursor(handCursor);
668 void QxGraph_CanvasView::activateZoom()
670 myOperation = ZOOMVIEW;
671 viewport()->setMouseTracking(false);
672 myCursor = cursor(); // save old cursor
673 QPixmap zoomPixmap (imageZoomCursor);
674 QCursor zoomCursor (zoomPixmap);
675 setCursor(zoomCursor);
678 void QxGraph_CanvasView::activatePanning()
680 myOperation = PANVIEW;
681 viewport()->setMouseTracking(false);
682 myCursor = cursor(); // save old cursor
683 QCursor panCursor (Qt::SizeAllCursor);
684 setCursor(panCursor);
687 void QxGraph_CanvasView::activateGlobalPanning()
689 myOperation = PANGLOBAL;
690 myCursor = cursor(); // save old cursor
691 QPixmap globalPanPixmap (imageCrossCursor);
692 QCursor glPanCursor (globalPanPixmap);
693 setCursor(glPanCursor);
696 void QxGraph_CanvasView::activateReset()
698 //myOperation = RESETVIEW;
703 // remember the canvas view's current transformation matrix in all canvas items
704 QCanvasItemList aList = canvas()->allItems();
705 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
706 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
707 if ( anActItem ) anActItem->setTMatrix(m);
710 //myOperation = NOTHING;
712 emit viewOperationDone();
715 void QxGraph_CanvasView::onTimeout()
718 scrollBy(myDX, myDY);
721 inverseWorldMatrix().map((double)myDX, (double)myDY, &cx, &cy);
722 if (myCurrentItem->x()+cx < 0) cx = -myCurrentItem->x();
723 if (myCurrentItem->y()+cy < 0) cy = -myCurrentItem->y();
724 myCurrentItem->moveBy(cx, cy);
725 myPoint.setX(myPoint.x()+(int)cx);
726 myPoint.setY(myPoint.y()+(int)cy);
731 QxGraph_ViewWindow* QxGraph_CanvasView::getViewWindow() const
733 return dynamic_cast<QxGraph_ViewWindow*>( parent() );
737 Shows tooltip if necessary
739 void QxGraph_ToolTip::maybeTip(const QPoint& theMousePos) {
740 QCanvasItemList aList = ((QCanvasView*)parentWidget())->canvas()->collisions(theMousePos);
742 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
743 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
747 QString aText = anActItem->getToolTipText(theMousePos, aRect);
749 QWMatrix aWM = ((QCanvasView*)parentWidget())->worldMatrix();
750 ((QCanvasView*)parentWidget())->contentsToViewport((int)(aRect.left()*aWM.m11()),
751 (int)(aRect.top()*aWM.m22()),
753 QRect aTipRect(avX, avY, (int)(aRect.width()*aWM.m11()), (int)(aRect.height()*aWM.m22()));
754 if (!aText.isEmpty())
755 tip(aTipRect, aText);