1 // SALOME QxGraph : build Supervisor viewer into desktop
3 // Copyright (C) 2003 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 #include "QxGraph_CanvasView.h"
24 #include "QxGraph_Canvas.h"
25 #include "QxGraph_ViewWindow.h"
26 #include "QxGraph_ActiveItem.h"
27 #include "QxGraph_Def.h"
32 const char* imageZoomCursor[] = {
37 "................................",
38 "................................",
39 ".#######........................",
40 "..aaaaaaa.......................",
41 "................................",
42 ".............#####..............",
43 "...........##.aaaa##............",
44 "..........#.aa.....a#...........",
45 ".........#.a.........#..........",
46 ".........#a..........#a.........",
47 "........#.a...........#.........",
48 "........#a............#a........",
49 "........#a............#a........",
50 "........#a............#a........",
51 "........#a............#a........",
52 ".........#...........#.a........",
53 ".........#a..........#a.........",
54 ".........##.........#.a.........",
55 "........#####.....##.a..........",
56 ".......###aaa#####.aa...........",
57 "......###aa...aaaaa.......#.....",
58 ".....###aa................#a....",
59 "....###aa.................#a....",
60 "...###aa...............#######..",
61 "....#aa.................aa#aaaa.",
62 ".....a....................#a....",
63 "..........................#a....",
64 "...........................a....",
65 "................................",
66 "................................",
67 "................................",
68 "................................"};
70 const char* imageCrossCursor[] = {
75 "................................",
76 "................................",
77 "................................",
78 "................................",
79 "................................",
80 "................................",
81 "................................",
82 "...............#................",
83 "...............#a...............",
84 "...............#a...............",
85 "...............#a...............",
86 "...............#a...............",
87 "...............#a...............",
88 "...............#a...............",
89 "...............#a...............",
90 ".......#################........",
91 "........aaaaaaa#aaaaaaaaa.......",
92 "...............#a...............",
93 "...............#a...............",
94 "...............#a...............",
95 "...............#a...............",
96 "...............#a...............",
97 "...............#a...............",
98 "...............#a...............",
99 "................a...............",
100 "................................",
101 "................................",
102 "................................",
103 "................................",
104 "................................",
105 "................................",
106 "................................"};
111 QxGraph_CanvasView::QxGraph_CanvasView(QxGraph_Canvas* theCanvas, QxGraph_ViewWindow* theViewWindow) :
112 QCanvasView(theCanvas, theViewWindow, 0, Qt::WRepaintNoErase),
119 printf("Construct QxGraph_CanvasView\n");
120 setName("QxGraph_CanvasView");
122 myOperation = NOTHING;
126 myTimer = new QTimer(this);
127 connect(myTimer, SIGNAL(timeout()), this, SLOT(onTimeout()));
129 viewport()->setMouseTracking(true);
135 QxGraph_CanvasView::~QxGraph_CanvasView()
139 void QxGraph_CanvasView::contentsMousePressEvent(QMouseEvent* theEvent)
141 myPoint = inverseWorldMatrix().map(theEvent->pos());
142 myGlobalPoint = theEvent->globalPos();
145 if ( theEvent->button() == Qt::MidButton && theEvent->state() == Qt::ControlButton
147 myOperation == PANVIEW )
149 if ( myOperation != PANVIEW ) {
150 myOperation = PANVIEW;
151 myCursor = cursor(); // save old cursor
152 QCursor panCursor (Qt::SizeAllCursor);
153 setCursor(panCursor);
158 if ( myOperation == PANGLOBAL )
163 if ( myOperation == WINDOWFIT )
168 if ( theEvent->button() == Qt::LeftButton && theEvent->state() == Qt::ControlButton
170 myOperation == ZOOMVIEW )
172 if ( myOperation != ZOOMVIEW ) {
173 myOperation = ZOOMVIEW;
174 myCursor = cursor(); // save old cursor
175 QPixmap zoomPixmap (imageZoomCursor);
176 QCursor zoomCursor (zoomPixmap);
177 setCursor(zoomCursor);
179 // the center of the view before zooming
180 int aXVCenter = viewport()->width()/2;
181 int aYVCenter = viewport()->height()/2;
182 myCenter = viewportToContents(QPoint(aXVCenter,aYVCenter));
187 if ( theEvent->button() == Qt::LeftButton )
189 QCanvasItemList aList = canvas()->collisions(myPoint);
190 // to move items on canvas view
191 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
192 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
194 if ( anActItem && anActItem->isResizable(myPoint,aCursorType) )
195 { // resize itself only active items if it is resizable
196 anActItem->beforeResizing(aCursorType);
200 else if ( anActItem && anActItem->isMoveable() )
201 { // move itself only active items if it is moveable
202 anActItem->beforeMoving();
210 void QxGraph_CanvasView::contentsMouseMoveEvent(QMouseEvent* theEvent)
212 QPoint aPoint = inverseWorldMatrix().map(theEvent->pos());
213 QPoint aGlobalPoint = theEvent->globalPos();
215 if (myTimer->isActive()) myTimer->stop();
217 if ( myOperation == PANVIEW )
219 scrollBy(myGlobalPoint.x() - aGlobalPoint.x(),
220 myGlobalPoint.y() - aGlobalPoint.y());
221 myGlobalPoint = aGlobalPoint;
226 if ( myOperation == WINDOWFIT )
227 { // Fit within rectangle
228 int aLX, aTY; //left x and top y
229 if (myPoint.x() < aPoint.x()) aLX = myPoint.x();
230 else aLX = aPoint.x();
231 if (myPoint.y() < aPoint.y()) aTY = myPoint.y();
232 else aTY = aPoint.y();
233 QRect aRect(aLX, aTY, abs(myPoint.x()-aPoint.x()), abs(myPoint.y()-aPoint.y()));
234 QCanvasRectangle* aRect1 = new QCanvasRectangle(aRect, canvas());
236 //hide old selected rectangle
238 mySelectedRect->hide();
239 //draw new selected rectangle
240 QPen pen(Qt::black,1,Qt::SolidLine);
245 mySelectedRect = aRect1;
251 if ( myOperation == ZOOMVIEW )
253 QCanvasItemList aList = canvas()->allItems();
254 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it)
257 int aXContCenter = myCenter.x();
258 int aYContCenter = myCenter.y();
260 QWMatrix m = worldMatrix();
262 double dx = aGlobalPoint.x() - myGlobalPoint.x();
263 double s = 1. + fabs(dx)*( (m.m11() < 1) ? m.m11() : 1. )/70.;
264 if (dx < 0) s = 1./s;
266 int aXContCenterScaled = aXContCenter*s;
267 int aYContCenterScaled = aYContCenter*s;
272 center(aXContCenterScaled,aYContCenterScaled);
274 myCenter.setX(aXContCenterScaled);
275 myCenter.setY(aYContCenterScaled);
277 // remember the canvas view's current transformation matrix in all canvas items
278 aList = canvas()->allItems();
279 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
280 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
281 if ( anActItem ) anActItem->setTMatrix(m);
285 myGlobalPoint = aGlobalPoint;
293 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( myCurrentItem );
294 if ( anActItem && anActItem->isResizing() )
295 { // to resize items on canvas view
296 anActItem->resize(aPoint);
301 // to move items on canvas view
302 if ( myCurrentItem->x() && myCurrentItem->y() ) {
303 double cx = myCurrentItem->x() - myPoint.x();
304 double cy = myCurrentItem->y() - myPoint.y();
306 if (aPoint.x()+cx < 0) aPoint.setX(-(int)cx);
307 if (aPoint.y()+cy < 0) aPoint.setY(-(int)cy);
309 myCurrentItem->moveBy(aPoint.x() - myPoint.x(),
310 aPoint.y() - myPoint.y());
315 // scroll contents if mouse is outside
316 QRect r(contentsX(), contentsY(), visibleWidth(), visibleHeight());
317 if (!r.contains(theEvent->pos())) {
319 if (theEvent->pos().x() < r.left()) dx = theEvent->pos().x() - r.left();
320 if (theEvent->pos().x() > r.right()) dx = theEvent->pos().x() - r.right();
321 if (theEvent->pos().y() < r.top()) dy = theEvent->pos().y() - r.top();
322 if (theEvent->pos().y() > r.bottom()) dy = theEvent->pos().y() - r.bottom();
324 // start timer to scroll in silent mode
325 myDX = dx; myDY = dy;
333 QCanvasItemList aList = canvas()->collisions(aPoint);
334 // perform actions for active items
335 bool isHilightPerformed = false;
337 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
338 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
340 if (!isHilightPerformed && anActItem) {
342 anActItem->hilight(aPoint);
343 if (anActItem != myHilightedItem) {
345 myHilightedItem->hilight(aPoint, false);
346 myHilightedItem = anActItem;
348 isHilightPerformed = true;
351 QxGraph_ToolTip* aToolTip = new QxGraph_ToolTip(this);
352 aToolTip->maybeTip(aPoint);
356 if ( anActItem && anActItem->isResizable(aPoint,aCursorType) ) {
358 QCursor resizeCursor;
363 resizeCursor = QCursor(Qt::SizeHorCursor);
367 resizeCursor = QCursor(Qt::SizeVerCursor);
370 case 7: //right-bottom
371 resizeCursor = QCursor(Qt::SizeFDiagCursor);
374 case 8: //left-bottom
375 resizeCursor = QCursor(Qt::SizeBDiagCursor);
378 resizeCursor = QCursor(Qt::ArrowCursor);
381 setCursor(resizeCursor);
386 setCursor(QCursor(Qt::ArrowCursor));
391 if (!isHilightPerformed && myHilightedItem) {
392 myHilightedItem->hilight(aPoint, false);
394 QToolTip::hide(); //@ temporary solution
397 if ( cursor().shape() == Qt::SizeVerCursor || cursor().shape() == Qt::SizeHorCursor
398 || cursor().shape() == Qt::SizeBDiagCursor || cursor().shape() == Qt::SizeFDiagCursor)
399 setCursor(QCursor(Qt::ArrowCursor));
404 This method is called by QxGraph_Canvas when item is removed.
405 QxGraph_CanvasView updates its own data accordingly
407 void QxGraph_CanvasView::itemRemoved( QCanvasItem* theItem )
409 if ( myCurrentItem == theItem )
412 QxGraph_ActiveItem* anActiveItem = dynamic_cast<QxGraph_ActiveItem*>( theItem );
415 if ( myHilightedItem == anActiveItem )
417 if ( mySelectedItem == anActiveItem )
422 void QxGraph_CanvasView::setSelectedItem( QxGraph_ActiveItem* theItem )
424 mySelectedItem = theItem;
427 QxGraph_ActiveItem* QxGraph_CanvasView::getSelectedItem() const
429 return mySelectedItem;
432 void QxGraph_CanvasView::contentsMouseReleaseEvent(QMouseEvent* theEvent)
434 QPoint aPoint = inverseWorldMatrix().map(theEvent->pos());
436 if (myTimer->isActive()) myTimer->stop();
439 { // to move items on canvas view
440 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( myCurrentItem );
441 if ( anActItem && anActItem->isResizing() )
443 anActItem->afterResizing();
445 setCursor(QCursor(Qt::ArrowCursor));
447 else if ( anActItem && anActItem->isMoveable() )
448 anActItem->afterMoving();
452 if ( myOperation == PANVIEW )
454 myOperation = NOTHING;
455 viewport()->setMouseTracking(true);
458 emit viewOperationDone();
461 if ( myOperation == PANGLOBAL )
463 myOperation = NOTHING;
464 center( theEvent->x(), theEvent->y() );
467 emit viewOperationDone();
470 if ( myOperation == WINDOWFIT )
471 { // Fit within rectangle
472 myOperation = NOTHING;
474 if (mySelectedRect) {
475 mySelectedRect->hide();
477 //canvas()->update();
480 //myPoint is the start point for selecting rectangle now
481 int aLX, aTY; //left x and top y
482 if (myPoint.x() < aPoint.x()) aLX = myPoint.x();
483 else aLX = aPoint.x();
484 if (myPoint.y() < aPoint.y()) aTY = myPoint.y();
485 else aTY = aPoint.y();
487 //calculate width and height for new view and new zoom factor
488 double aXzoom = ((double)visibleWidth())/((double)(abs(myPoint.x()-aPoint.x())));
489 double aYzoom = ((double)visibleHeight())/((double)(abs(myPoint.y()-aPoint.y())));
490 if (aXzoom > aYzoom) aXzoom = aYzoom;
493 m.scale(aXzoom, aXzoom);
496 // remember the canvas view's current transformation matrix in all canvas items
497 QCanvasItemList aList = canvas()->allItems();
498 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
499 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
500 if ( anActItem ) anActItem->setTMatrix(m);
503 setContentsPos((int)(aLX*aXzoom), (int)(aTY*aYzoom));
507 viewport()->setMouseTracking(true);
510 emit viewOperationDone();
513 if ( myOperation == ZOOMVIEW )
515 myOperation = NOTHING;
516 viewport()->setMouseTracking(true);
519 emit viewOperationDone();
522 if ( theEvent->button() == RightButton )
524 // Selection mechanism
525 QCanvasItemList aList = canvas()->collisions(aPoint);
526 bool isSelectionPerformed = false;
528 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
529 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
530 if (!isSelectionPerformed && anActItem)
532 anActItem->select(aPoint);
533 if (anActItem != mySelectedItem)
535 if (mySelectedItem && isSelectedItemInCanvas() &&
536 !mySelectedItem->arePartsOfOtherItem(anActItem)) mySelectedItem->select(aPoint, false);
537 mySelectedItem = anActItem;
539 // unhilight hilighted item if selection was performed
540 if (myHilightedItem) {
541 myHilightedItem->hilight(aPoint, false);
545 isSelectionPerformed = true;
549 if (!isSelectionPerformed)
551 if ( mySelectedItem )
553 if ( isSelectedItemInCanvas() ) mySelectedItem->select(aPoint, false);
558 printf("Background popup\n");
559 QContextMenuEvent aEvent( QContextMenuEvent::Mouse,
560 theEvent->pos(), theEvent->globalPos(),
562 if ( getViewWindow() )
563 getViewWindow()->contextPopupEvent(&aEvent); // => emit contextMenuRequested( &aEvent );
566 { // show context popup for the selected item
567 mySelectedItem->showPopup(viewport(), theEvent, aPoint);
571 if ( theEvent->button() == LeftButton && !myMovingDone )
573 // Selection mechanism
574 QCanvasItemList aList = canvas()->collisions(aPoint);
576 if ( aList.empty() && mySelectedItem )
578 if ( isSelectedItemInCanvas() ) mySelectedItem->select(aPoint, false);
583 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
584 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
587 anActItem->select(aPoint);
588 if (anActItem != mySelectedItem)
590 if (mySelectedItem && isSelectedItemInCanvas() &&
591 !mySelectedItem->arePartsOfOtherItem(anActItem)) mySelectedItem->select(aPoint, false);
592 mySelectedItem = anActItem;
600 myMovingDone = false;
603 void QxGraph_CanvasView::contentsMouseDoubleClickEvent(QMouseEvent* theEvent)
608 bool QxGraph_CanvasView::isSelectedItemInCanvas()
610 // check if mySelectedItem is included into the canvas:
611 // if yes => unselect it
612 // if no => do nothing
613 bool anIsInCanvas = false;
614 QCanvasItemList aListC = canvas()->allItems();
615 for (QCanvasItemList::Iterator itC = aListC.begin(); itC != aListC.end(); ++itC) {
616 QxGraph_ActiveItem* anActItemC = dynamic_cast<QxGraph_ActiveItem*>( *itC );
617 if ( anActItemC && anActItemC == mySelectedItem ) {
625 void QxGraph_CanvasView::activateFitAll()
627 //myOperation = FITALL;
629 QCanvasItemList l = canvas()->allItems();
630 for (QCanvasItemList::Iterator it = l.begin(); it != l.end(); ++it) {
631 QRect r = (*it)->boundingRect();
632 if (w < r.right()) w = r.right();
633 if (h < r.bottom()) h = r.bottom();
635 w += GRAPH_MARGIN; h += GRAPH_MARGIN;
636 double s = ((double)visibleWidth())/((double)w);
637 double s1 = ((double)visibleHeight())/((double)h);
645 // remember the canvas view's current transformation matrix in all canvas items
646 QCanvasItemList aList = canvas()->allItems();
647 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
648 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
649 if ( anActItem ) anActItem->setTMatrix(m);
653 //myOperation = NOTHING;
655 emit viewOperationDone();
658 void QxGraph_CanvasView::activateFitRect()
660 myOperation = WINDOWFIT;
661 viewport()->setMouseTracking(false);
662 myCursor = cursor(); // save old cursor
663 QCursor handCursor (Qt::PointingHandCursor);
664 setCursor(handCursor);
667 void QxGraph_CanvasView::activateZoom()
669 myOperation = ZOOMVIEW;
670 viewport()->setMouseTracking(false);
671 myCursor = cursor(); // save old cursor
672 QPixmap zoomPixmap (imageZoomCursor);
673 QCursor zoomCursor (zoomPixmap);
674 setCursor(zoomCursor);
677 void QxGraph_CanvasView::activatePanning()
679 myOperation = PANVIEW;
680 viewport()->setMouseTracking(false);
681 myCursor = cursor(); // save old cursor
682 QCursor panCursor (Qt::SizeAllCursor);
683 setCursor(panCursor);
686 void QxGraph_CanvasView::activateGlobalPanning()
688 myOperation = PANGLOBAL;
689 myCursor = cursor(); // save old cursor
690 QPixmap globalPanPixmap (imageCrossCursor);
691 QCursor glPanCursor (globalPanPixmap);
692 setCursor(glPanCursor);
695 void QxGraph_CanvasView::activateReset()
697 //myOperation = RESETVIEW;
702 // remember the canvas view's current transformation matrix in all canvas items
703 QCanvasItemList aList = canvas()->allItems();
704 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
705 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
706 if ( anActItem ) anActItem->setTMatrix(m);
709 //myOperation = NOTHING;
711 emit viewOperationDone();
714 void QxGraph_CanvasView::onTimeout()
717 scrollBy(myDX, myDY);
720 inverseWorldMatrix().map((double)myDX, (double)myDY, &cx, &cy);
721 if (myCurrentItem->x()+cx < 0) cx = -myCurrentItem->x();
722 if (myCurrentItem->y()+cy < 0) cy = -myCurrentItem->y();
723 myCurrentItem->moveBy(cx, cy);
724 myPoint.setX(myPoint.x()+(int)cx);
725 myPoint.setY(myPoint.y()+(int)cy);
730 QxGraph_ViewWindow* QxGraph_CanvasView::getViewWindow() const
732 return dynamic_cast<QxGraph_ViewWindow*>( parent() );
736 Shows tooltip if necessary
738 void QxGraph_ToolTip::maybeTip(const QPoint& theMousePos) {
739 QCanvasItemList aList = ((QCanvasView*)parentWidget())->canvas()->collisions(theMousePos);
741 for (QCanvasItemList::Iterator it = aList.begin(); it != aList.end(); ++it) {
742 QxGraph_ActiveItem* anActItem = dynamic_cast<QxGraph_ActiveItem*>( *it );
746 QString aText = anActItem->getToolTipText(theMousePos, aRect);
748 QWMatrix aWM = ((QCanvasView*)parentWidget())->worldMatrix();
749 ((QCanvasView*)parentWidget())->contentsToViewport((int)(aRect.left()*aWM.m11()),
750 (int)(aRect.top()*aWM.m22()),
752 QRect aTipRect(avX, avY, (int)(aRect.width()*aWM.m11()), (int)(aRect.height()*aWM.m22()));
753 if (!aText.isEmpty())
754 tip(aTipRect, aText);