Salome HOME
Merge branch 'master' into BR_PYTHON_PLUGIN
[modules/shaper.git] / src / XGUI / XGUI_ViewWindow.cpp
1 #include "XGUI_ViewWindow.h"
2 #include "XGUI_ViewPort.h"
3 #include "XGUI_Viewer.h"
4 #include "XGUI_Tools.h"
5 #include "XGUI_RubberBand.h"
6
7 #include <QLayout>
8 #include <QLabel>
9 #include <QToolBar>
10 #include <QAction>
11 #include <QResizeEvent>
12 #include <QApplication>
13 #include <QMdiArea>
14 #include <QMdiSubWindow>
15 #include <QPainter>
16 #include <QTimer>
17 #include <QFileDialog>
18 #include <QStyleOptionToolBar>
19
20 #include <TopoDS_Shape.hxx>
21 #include <BRep_Tool.hxx>
22 #include <TopoDS.hxx>
23 #include <Visual3d_View.hxx>
24
25 #include <math.h>
26
27 #define BORDER_SIZE 2
28
29 const char* imageZoomCursor[] = { "32 32 3 1", ". c None", "a c #000000", "# c #ffffff",
30     "................................", "................................",
31     ".#######........................", "..aaaaaaa.......................",
32     "................................", ".............#####..............",
33     "...........##.aaaa##............", "..........#.aa.....a#...........",
34     ".........#.a.........#..........", ".........#a..........#a.........",
35     "........#.a...........#.........", "........#a............#a........",
36     "........#a............#a........", "........#a............#a........",
37     "........#a............#a........", ".........#...........#.a........",
38     ".........#a..........#a.........", ".........##.........#.a.........",
39     "........#####.....##.a..........", ".......###aaa#####.aa...........",
40     "......###aa...aaaaa.......#.....", ".....###aa................#a....",
41     "....###aa.................#a....", "...###aa...............#######..",
42     "....#aa.................aa#aaaa.", ".....a....................#a....",
43     "..........................#a....", "...........................a....",
44     "................................", "................................",
45     "................................", "................................" };
46
47 const char* imageRotateCursor[] = { "32 32 3 1", ". c None", "a c #000000", "# c #ffffff",
48     "................................", "................................",
49     "................................", "................................",
50     "........#.......................", ".......#.a......................",
51     "......#######...................", ".......#aaaaa#####..............",
52     "........#..##.a#aa##........##..", ".........a#.aa..#..a#.....##.aa.",
53     ".........#.a.....#...#..##.aa...", ".........#a.......#..###.aa.....",
54     "........#.a.......#a..#aa.......", "........#a.........#..#a........",
55     "........#a.........#a.#a........", "........#a.........#a.#a........",
56     "........#a.........#a.#a........", ".........#.........#a#.a........",
57     "........##a........#a#a.........", "......##.a#.......#.#.a.........",
58     "....##.aa..##.....##.a..........", "..##.aa.....a#####.aa...........",
59     "...aa.........aaa#a.............", "................#.a.............",
60     "...............#.a..............", "..............#.a...............",
61     "...............a................", "................................",
62     "................................", "................................",
63     "................................", "................................" };
64
65 const char* imageCrossCursor[] = { "32 32 3 1", ". c None", "a c #000000", "# c #ffffff",
66     "................................", "................................",
67     "................................", "................................",
68     "................................", "................................",
69     "................................", "...............#................",
70     "...............#a...............", "...............#a...............",
71     "...............#a...............", "...............#a...............",
72     "...............#a...............", "...............#a...............",
73     "...............#a...............", ".......#################........",
74     "........aaaaaaa#aaaaaaaaa.......", "...............#a...............",
75     "...............#a...............", "...............#a...............",
76     "...............#a...............", "...............#a...............",
77     "...............#a...............", "...............#a...............",
78     "................a...............", "................................",
79     "................................", "................................",
80     "................................", "................................",
81     "................................", "................................" };
82
83 ViewerToolbar::ViewerToolbar(QWidget* theParent, XGUI_ViewPort* thePort)
84     : QToolBar(theParent),
85       myVPort(thePort),
86       myResize(false)
87 {
88   connect(myVPort, SIGNAL(resized()), this, SLOT(onViewPortResized()));
89 }
90
91 void ViewerToolbar::paintEvent(QPaintEvent* theEvent)
92 {
93   //QToolBar::paintEvent(theEvent);
94   // Paint background
95   QPainter aPainter(this);
96   QRect aRect = rect();
97   QRect aVPRect = myVPort->rect();
98   QPoint aGlobPnt = mapToGlobal(aRect.topLeft());
99   QPoint aPnt = myVPort->mapFromGlobal(aGlobPnt);
100
101   QRect aImgRect(
102       QRect(aPnt.x(), aPnt.y() + aVPRect.height() - aRect.height(), aRect.width(), aRect.height()));
103   unsigned char* aData = 0;
104   QImage aImg = myVPort->dumpView(aData, aImgRect, myResize);
105   if (!aImg.isNull())
106     aPainter.drawImage(aRect, aImg);
107   myResize = false;
108
109   // Paint foreground
110   QStyle *style = this->style();
111   QStyleOptionToolBar aOpt;
112   initStyleOption(&aOpt);
113
114   aOpt.rect = style->subElementRect(QStyle::SE_ToolBarHandle, &aOpt, this);
115   if (aOpt.rect.isValid())
116     style->drawPrimitive(QStyle::PE_IndicatorToolBarHandle, &aOpt, &aPainter, this);
117   if (aData)
118     delete aData;
119 }
120
121 //**************************************************************************
122 ViewerLabel::ViewerLabel(QWidget* theParent, XGUI_ViewPort* thePort)
123     : QLabel(theParent),
124       myVPort(thePort),
125       myResize(false)
126 {
127   connect(myVPort, SIGNAL(resized()), this, SLOT(onViewPortResized()));
128 }
129
130 void ViewerLabel::paintEvent(QPaintEvent* theEvent)
131 {
132   QRect aRect = rect();
133   QRect aVPRect = myVPort->rect();
134   QPoint aGlobPnt = mapToGlobal(aRect.topLeft());
135   QPoint aPnt = myVPort->mapFromGlobal(aGlobPnt);
136
137   QRect aImgRect(
138       QRect(aPnt.x(), aPnt.y() + aVPRect.height() - aRect.height(), aRect.width(), aRect.height()));
139   unsigned char* aData = 0;
140   QImage aImg = myVPort->dumpView(aData, aImgRect, myResize);
141   if (!aImg.isNull())
142     QPainter(this).drawImage(aRect, aImg);
143   myResize = false;
144   QLabel::paintEvent(theEvent);
145   if (aData)
146     delete aData;
147 }
148
149 //**************************************************************************
150 //**************************************************************************
151 //**************************************************************************
152 XGUI_ViewWindow::XGUI_ViewWindow(XGUI_Viewer* theViewer, V3d_TypeOfView theType)
153     : QFrame(),
154       myViewer(theViewer),
155       myMoving(false),
156       MinimizeIco(":pictures/wnd_minimize.png"),
157       MaximizeIco(":pictures/wnd_maximize.png"),
158       CloseIco(":pictures/wnd_close.png"),
159       RestoreIco(":pictures/wnd_restore.png"),
160       myInteractionStyle(XGUI::STANDARD),
161       myRectBand(0),
162       myIsKeyFree(false),
163       my2dMode(XGUI::No2dMode),
164       myCurrPointType(XGUI::GRAVITY),
165       myPrevPointType(XGUI::GRAVITY),
166       myRotationPointSelection(false),
167       myClosable(true),
168       myStartX(0),
169       myStartY(0),
170       myCurrX(0),
171       myCurrY(0),
172       myCurScale(0.0),
173       myCurSketch(0),
174       myDrawRect(false),
175       myEnableDrawMode(false),
176       myCursorIsHand(false),
177       myEventStarted(false),
178       myIsActive(false),
179       myLastState(WindowNormalState),
180       myOperation(NOTHING),
181       myGripWgt(0),
182       myPicture(0)
183 {
184   mySelectedPoint = gp_Pnt(0., 0., 0.);
185   setFrameStyle(QFrame::Raised);
186   setFrameShape(QFrame::Panel);
187   setLineWidth(BORDER_SIZE);
188   setMouseTracking(true);
189
190   QVBoxLayout* aLay = new QVBoxLayout(this);
191   aLay->setContentsMargins(BORDER_SIZE, BORDER_SIZE, BORDER_SIZE, BORDER_SIZE);
192   myViewPort = new XGUI_ViewPort(this, myViewer->v3dViewer(), theType);
193   myViewPort->installEventFilter(this);
194   myViewPort->setCursor(Qt::ArrowCursor);
195   aLay->addWidget(myViewPort);
196
197   myPicture = new QLabel(this);
198   myPicture->setFrameStyle(QFrame::Sunken);
199   myPicture->setFrameShape(QFrame::Panel);
200   myPicture->setMouseTracking(true);
201   myPicture->installEventFilter(this);
202   aLay->addWidget(myPicture);
203   myPicture->hide();
204
205   QVBoxLayout* aVPLay = new QVBoxLayout(myViewPort);
206   aVPLay->setMargin(0);
207   aVPLay->setSpacing(0);
208   aVPLay->setContentsMargins(0, 0, 0, 0);
209
210   QHBoxLayout* aToolLay = new QHBoxLayout();
211   aToolLay->setMargin(0);
212   aToolLay->setSpacing(0);
213   aToolLay->setContentsMargins(0, 0, 0, 0);
214   aVPLay->addLayout(aToolLay);
215   aVPLay->addStretch();
216
217   myGripWgt = new ViewerLabel(this, myViewPort);
218   myGripWgt->setPixmap(QPixmap(":pictures/wnd_grip.png"));
219   myGripWgt->setMouseTracking(true);
220   myGripWgt->installEventFilter(this);
221   myGripWgt->setCursor(Qt::OpenHandCursor);
222   aToolLay->addWidget(myGripWgt);
223
224   // Create Viewer management buttons
225   myViewBar = new ViewerToolbar(this, myViewPort);
226   myViewBar->setCursor(Qt::PointingHandCursor);
227   aToolLay->addWidget(myViewBar);
228   aToolLay->addStretch();
229
230   QAction* aBtn;
231
232   // Dump view
233   aBtn = new QAction(QIcon(":pictures/occ_view_camera_dump.png"), tr("Dump view"), myViewBar);
234   connect(aBtn, SIGNAL(triggered()), SLOT(dumpView()));
235   myViewBar->addAction(aBtn);
236   // Fit all
237   aBtn = new QAction(QIcon(":pictures/occ_view_fitall.png"), tr("Fit all"), myViewBar);
238   connect(aBtn, SIGNAL(triggered()), SLOT(fitAll()));
239   myViewBar->addAction(aBtn);
240   // Fit area
241   aBtn = new QAction(QIcon(":pictures/occ_view_fitarea.png"), tr("Fit area"), myViewBar);
242   connect(aBtn, SIGNAL(triggered()), SLOT(activateWindowFit()));
243   myViewBar->addAction(aBtn);
244   // Zoom
245   aBtn = new QAction(QIcon(":pictures/occ_view_zoom.png"), tr("Zoom"), myViewBar);
246   connect(aBtn, SIGNAL(triggered()), SLOT(activateZoom()));
247   myViewBar->addAction(aBtn);
248   // Pan
249   aBtn = new QAction(QIcon(":pictures/occ_view_pan.png"), tr("Panning"), myViewBar);
250   connect(aBtn, SIGNAL(triggered()), SLOT(activatePanning()));
251   myViewBar->addAction(aBtn);
252   // Global Panning
253   aBtn = new QAction(QIcon(":pictures/occ_view_glpan.png"), tr("Global panning"), myViewBar);
254   connect(aBtn, SIGNAL(triggered()), SLOT(activateGlobalPanning()));
255   myViewBar->addAction(aBtn);
256   // Rotation
257   aBtn = new QAction(QIcon(":pictures/occ_view_rotate.png"), tr("Rotate"), myViewBar);
258   connect(aBtn, SIGNAL(triggered()), SLOT(activateRotation()));
259   myViewBar->addAction(aBtn);
260   // Reset
261   aBtn = new QAction(QIcon(":pictures/occ_view_reset.png"), tr("Reset"), myViewBar);
262   connect(aBtn, SIGNAL(triggered()), SLOT(reset()));
263   myViewBar->addAction(aBtn);
264   // Front view
265   aBtn = new QAction(QIcon(":pictures/occ_view_front.png"), tr("Front"), myViewBar);
266   connect(aBtn, SIGNAL(triggered()), SLOT(frontView()));
267   myViewBar->addAction(aBtn);
268   // Back view
269   aBtn = new QAction(QIcon(":pictures/occ_view_back.png"), tr("Back"), myViewBar);
270   connect(aBtn, SIGNAL(triggered()), SLOT(backView()));
271   myViewBar->addAction(aBtn);
272   // Top view
273   aBtn = new QAction(QIcon(":pictures/occ_view_top.png"), tr("Top"), myViewBar);
274   connect(aBtn, SIGNAL(triggered()), SLOT(topView()));
275   myViewBar->addAction(aBtn);
276   // Bottom view
277   aBtn = new QAction(QIcon(":pictures/occ_view_bottom.png"), tr("Bottom"), myViewBar);
278   connect(aBtn, SIGNAL(triggered()), SLOT(bottomView()));
279   myViewBar->addAction(aBtn);
280   // Left view
281   aBtn = new QAction(QIcon(":pictures/occ_view_left.png"), tr("Left"), myViewBar);
282   connect(aBtn, SIGNAL(triggered()), SLOT(leftView()));
283   myViewBar->addAction(aBtn);
284   // Right view
285   aBtn = new QAction(QIcon(":pictures/occ_view_right.png"), tr("Right"), myViewBar);
286   connect(aBtn, SIGNAL(triggered()), SLOT(rightView()));
287   myViewBar->addAction(aBtn);
288   // Clone view
289   aBtn = new QAction(QIcon(":pictures/occ_view_clone.png"), tr("Clone"), myViewBar);
290   connect(aBtn, SIGNAL(triggered()), SLOT(cloneView()));
291   myViewBar->addAction(aBtn);
292
293   // Create Window management buttons
294   myWindowBar = new ViewerToolbar(this, myViewPort);
295   myWindowBar->setCursor(Qt::PointingHandCursor);
296   aToolLay->addWidget(myWindowBar);
297
298   myMinimizeBtn = new QAction(myWindowBar);
299   myMinimizeBtn->setIcon(MinimizeIco);
300   myWindowBar->addAction(myMinimizeBtn);
301   connect(myMinimizeBtn, SIGNAL(triggered()), SLOT(onMinimize()));
302
303   myMaximizeBtn = new QAction(myWindowBar);
304   myMaximizeBtn->setIcon(MaximizeIco);
305   myWindowBar->addAction(myMaximizeBtn);
306   connect(myMaximizeBtn, SIGNAL(triggered()), SLOT(onMaximize()));
307
308   aBtn = new QAction(myWindowBar);
309   aBtn->setIcon(CloseIco);
310   myWindowBar->addAction(aBtn);
311   connect(aBtn, SIGNAL(triggered()), SLOT(onClose()));
312
313   //Support copy of background on updating of viewer
314   connect(myViewPort, SIGNAL(vpTransformed()), this, SLOT(updateToolBar()));
315   connect(myViewPort, SIGNAL(vpUpdated()), this, SLOT(updateToolBar()));
316   connect(this, SIGNAL(vpTransformationFinished(XGUI_ViewWindow::OperationType)), this,
317           SLOT(updateToolBar()));
318 }
319
320 //****************************************************************
321 XGUI_ViewWindow::~XGUI_ViewWindow()
322 {
323 }
324
325 //****************************************************************
326 void XGUI_ViewWindow::showEvent(QShowEvent* theEvent)
327 {
328   QFrame::showEvent(theEvent);
329   myWindowBar->setFixedSize(myWindowBar->sizeHint());
330 }
331
332 //****************************************************************
333 void XGUI_ViewWindow::changeEvent(QEvent* theEvent)
334 {
335
336   if (theEvent->type() == QEvent::WindowStateChange) {
337     if (isMinimized()) {
338       if (myPicture->isHidden()) {
339         myViewBar->hide();
340         myGripWgt->hide();
341         myWindowBar->hide();
342         myViewPort->hide();
343         myPicture->show();
344       }
345     } else {
346       if (myPicture->isVisible()) {
347         myPicture->hide();
348         myViewPort->show();
349       }
350       if (isMaximized()) {
351         myMinimizeBtn->setIcon(MinimizeIco);
352         myMaximizeBtn->setIcon(RestoreIco);
353       }
354       myViewBar->setVisible(myIsActive);
355       myWindowBar->setVisible(myIsActive);
356       myGripWgt->setVisible(myIsActive && (!isMaximized()));
357     }
358   } else
359     QWidget::changeEvent(theEvent);
360 }
361
362 //****************************************************************
363 void XGUI_ViewWindow::windowActivated()
364 {
365   if (!(isMinimized() || parentWidget()->isMinimized())) {
366     myIsActive = true;
367     if (isMaximized() || parentWidget()->isMaximized()) {
368       myMaximizeBtn->setIcon(RestoreIco);
369     } else {
370       myMaximizeBtn->setIcon(MaximizeIco);
371     }
372     myViewBar->show();
373     myWindowBar->show();
374     myGripWgt->setVisible(
375         !(isMaximized() || isMinimized() || parentWidget()->isMaximized()
376             || parentWidget()->isMinimized()));
377   } else
378     myIsActive = false;
379 }
380
381 //****************************************************************
382 void XGUI_ViewWindow::windowDeactivated()
383 {
384   myIsActive = false;
385   if (!(isMinimized() || parentWidget()->isMinimized())) {
386     if (isMaximized() || parentWidget()->isMaximized()) {
387       myMaximizeBtn->setIcon(RestoreIco);
388     } else {
389       myMaximizeBtn->setIcon(MaximizeIco);
390     }
391     myViewBar->hide();
392     myWindowBar->hide();
393     myGripWgt->hide();
394   }
395 }
396
397 //****************************************************************
398 void XGUI_ViewWindow::onClose()
399 {
400   if (parentWidget()) {
401     emit tryClosing(this);
402     if (closable()) {
403       emit closed(static_cast<QMdiSubWindow*>(parentWidget()));
404       parentWidget()->close();
405     }
406   }
407 }
408
409 //****************************************************************
410 void XGUI_ViewWindow::onMinimize()
411 {
412   unsigned char* aData = 0;
413   QPixmap aPMap = QPixmap::fromImage(myViewPort->dumpView(aData));
414   int aW = width();
415   int aH = height();
416   double aR = aW / 100.;
417   int aNewH = int(aH / aR);
418   myPicture->setPixmap(aPMap.scaled(100, aNewH));
419
420   myLastState =
421       (isMaximized() || parentWidget()->isMaximized()) ? MaximizedState : WindowNormalState;
422   showMinimized();
423   parentWidget()->showMinimized();
424   parentWidget()->setGeometry(parentWidget()->x(), parentWidget()->y(), 100, aNewH);
425   parentWidget()->lower();
426   windowDeactivated();
427   myViewer->onWindowMinimized((QMdiSubWindow*) parentWidget());
428   delete aData;
429 }
430
431 //****************************************************************
432 void XGUI_ViewWindow::onMaximize()
433 {
434   if (isMaximized() || parentWidget()->isMaximized()) {
435     myMaximizeBtn->setIcon(MaximizeIco);
436     myGripWgt->show();
437     showNormal();
438     parentWidget()->showNormal();
439   } else {
440     myMaximizeBtn->setIcon(RestoreIco);
441     myGripWgt->hide();
442     showMaximized();
443     parentWidget()->showMaximized();
444   }
445   parentWidget()->activateWindow();
446   myMinimizeBtn->setIcon(MinimizeIco);
447
448   //  In order to avoid frosen background in toolbars when it shown as a second view
449   QTimer::singleShot(50, parentWidget(), SLOT(setFocus()));
450 }
451
452 //****************************************************************
453 bool XGUI_ViewWindow::processWindowControls(QObject *theObj, QEvent *theEvent)
454 {
455   switch (theEvent->type()) {
456     case QEvent::MouseButtonPress: {
457       QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
458       if ((aEvent->button() == Qt::LeftButton) && (!myMoving)) {
459         myMoving = true;
460         myMousePnt = aEvent->globalPos();
461         return true;
462       }
463     }
464       break;
465     case QEvent::MouseButtonRelease: {
466       QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
467       if ((aEvent->button() == Qt::LeftButton) && myMoving) {
468         myMoving = false;
469         return true;
470       }
471     }
472       break;
473     case QEvent::MouseMove: {
474       QMouseEvent* aEvent = static_cast<QMouseEvent*>(theEvent);
475       if (myMoving) {
476         QMdiSubWindow* aParent = static_cast<QMdiSubWindow*>(parentWidget());
477         QMdiArea* aMDIArea = aParent->mdiArea();
478
479         QPoint aPnt = aEvent->globalPos();
480         QPoint aMDIPnt = aMDIArea->mapFromGlobal(aPnt);
481         if (aMDIArea->rect().contains(aMDIPnt)) {
482           int aX = aParent->x() + (aPnt.x() - myMousePnt.x());
483           int aY = aParent->y() + (aPnt.y() - myMousePnt.y());
484           aParent->move(aX, aY);
485           myMousePnt = aPnt;
486         }
487         return true;
488       }
489     }
490       break;
491     case QEvent::MouseButtonDblClick:
492       if (theObj == myPicture) {
493         myMoving = false;
494         if (myLastState == MaximizedState) {
495           showMaximized();
496         } else {
497           showNormal();
498         }
499         myViewer->onWindowActivated((QMdiSubWindow*) parentWidget());
500
501         //  In order to avoid frosen background in toolbars when it shown as a second view
502         QTimer::singleShot(20, parentWidget(), SLOT(setFocus()));
503
504         return true;
505       }
506   }
507   return false;
508 }
509
510 //****************************************************************
511 bool XGUI_ViewWindow::processViewPort(QEvent *theEvent)
512 {
513   switch (theEvent->type()) {
514     case QEvent::MouseButtonPress:
515       vpMousePressEvent((QMouseEvent*) theEvent);
516       return true;
517
518     case QEvent::MouseButtonRelease:
519       vpMouseReleaseEvent((QMouseEvent*) theEvent);
520       return true;
521
522     case QEvent::MouseMove:
523       vpMouseMoveEvent((QMouseEvent*) theEvent);
524       return true;
525
526     case QEvent::MouseButtonDblClick:
527       emit mouseDoubleClicked(this, (QMouseEvent*) theEvent);
528       return true;
529     case QEvent::Wheel: {
530       QWheelEvent* aEvent = (QWheelEvent*) theEvent;
531       myViewPort->startZoomAtPoint(aEvent->x(), aEvent->y());
532       double aDelta = (double) (aEvent->delta()) / (15 * 8);
533       int x = aEvent->x();
534       int y = aEvent->y();
535       int x1 = (int) (aEvent->x() + width() * aDelta / 100);
536       int y1 = (int) (aEvent->y() + height() * aDelta / 100);
537       myViewPort->zoom(x, y, x1, y1);
538     }
539       return true;
540   }
541   return false;
542 }
543
544 //****************************************************************
545 bool XGUI_ViewWindow::eventFilter(QObject *theObj, QEvent *theEvent)
546 {
547   if ((theObj == myGripWgt) || (theObj == myPicture)) {
548     if (processWindowControls(theObj, theEvent))
549       return true;
550   } else if (theObj == myViewPort) {
551     if (processViewPort(theEvent)) {
552       return true;
553     }
554     if (theEvent->type() == QEvent::KeyRelease) {
555       emit keyReleased(this, (QKeyEvent*) theEvent);
556       return true;
557     }
558   }
559   return QFrame::eventFilter(theObj, theEvent);
560 }
561
562 //****************************************************************
563 XGUI_ViewWindow::OperationType XGUI_ViewWindow::getButtonState(
564     QMouseEvent* theEvent, XGUI::InteractionStyle theInteractionStyle)
565 {
566   OperationType aOp = NOTHING;
567   XGUI::InteractionStyle aStyle = (XGUI::InteractionStyle) theInteractionStyle;
568   if ((theEvent->modifiers() == XGUI_Viewer::myStateMap[aStyle][XGUI::ZOOM])
569       && (theEvent->buttons() == XGUI_Viewer::myButtonMap[aStyle][XGUI::ZOOM]))
570     aOp = ZOOMVIEW;
571   else if ((theEvent->modifiers() == XGUI_Viewer::myStateMap[aStyle][XGUI::PAN])
572       && (theEvent->buttons() == XGUI_Viewer::myButtonMap[aStyle][XGUI::PAN]))
573     aOp = PANVIEW;
574   else if ((theEvent->modifiers() == XGUI_Viewer::myStateMap[aStyle][XGUI::ROTATE])
575       && (theEvent->buttons() == XGUI_Viewer::myButtonMap[aStyle][XGUI::ROTATE])
576       && (my2dMode == XGUI::No2dMode))
577     aOp = ROTATE;
578
579   return aOp;
580 }
581
582 //****************************************************************
583 void XGUI_ViewWindow::vpMousePressEvent(QMouseEvent* theEvent)
584 {
585   myStartX = theEvent->x();
586   myStartY = theEvent->y();
587   XGUI::InteractionStyle anInteractionStyle = interactionStyle();
588
589   // in "key free" interaction style zoom operation is activated by two buttons (simultaneously pressed),
590   // which are assigned for pan and rotate - these operations are activated immediately after pressing 
591   // of the first button, so it is necessary to switch to zoom when the second button is pressed
592   bool aSwitchToZoom = false;
593   if ((anInteractionStyle == XGUI::KEY_FREE) && (myOperation == PANVIEW || myOperation == ROTATE)) {
594     aSwitchToZoom = getButtonState(theEvent, anInteractionStyle) == ZOOMVIEW;
595   }
596
597   switch (myOperation) {
598     case WINDOWFIT:
599       if (theEvent->button() == Qt::LeftButton)
600         emit vpTransformationStarted(WINDOWFIT);
601       break;
602
603     case PANGLOBAL:
604       if (theEvent->button() == Qt::LeftButton)
605         emit vpTransformationStarted(PANGLOBAL);
606       break;
607
608     case ZOOMVIEW:
609       if (theEvent->button() == Qt::LeftButton) {
610         myViewPort->startZoomAtPoint(myStartX, myStartY);
611         emit vpTransformationStarted(ZOOMVIEW);
612       }
613       break;
614
615     case PANVIEW:
616       if (aSwitchToZoom) {
617         myViewPort->startZoomAtPoint(myStartX, myStartY);
618         activateZoom();
619       } else if (theEvent->button() == Qt::LeftButton)
620         emit vpTransformationStarted(PANVIEW);
621       break;
622
623     case ROTATE:
624       if (aSwitchToZoom) {
625         myViewPort->startZoomAtPoint(myStartX, myStartY);
626         activateZoom();
627       } else if (theEvent->button() == Qt::LeftButton) {
628         myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint);
629         emit vpTransformationStarted(ROTATE);
630       }
631       break;
632
633     default:
634       /*  Try to activate a transformation */
635       OperationType aState;
636       if (interactionStyle() == XGUI::STANDARD)
637         aState = getButtonState(theEvent, anInteractionStyle);
638       else {
639         aState = XGUI_ViewWindow::NOTHING;
640         myIsKeyFree = true;
641       }
642       switch (aState) {
643         case ZOOMVIEW:
644           myViewPort->startZoomAtPoint(myStartX, myStartY);
645           activateZoom();
646           break;
647         case PANVIEW:
648           activatePanning();
649           break;
650         case ROTATE:
651           activateRotation();
652           myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint);
653           break;
654         default:
655           if (myRotationPointSelection) {
656             if (theEvent->button() == Qt::LeftButton) {
657               Handle(AIS_InteractiveContext) ic = myViewer->AISContext();
658               ic->Select();
659               for (ic->InitSelected(); ic->MoreSelected(); ic->NextSelected()) {
660                 TopoDS_Shape aShape = ic->SelectedShape();
661                 if (!aShape.IsNull() && aShape.ShapeType() == TopAbs_VERTEX) {
662                   gp_Pnt aPnt = BRep_Tool::Pnt(TopoDS::Vertex(ic->SelectedShape()));
663                   /*if ( mySetRotationPointDlg ) {
664                    myRotationPointSelection = false;
665                    mySetRotationPointDlg->setCoords(aPnt.X(), aPnt.Y(), aPnt.Z());
666                    }*/
667                 } else {
668                   myCurrPointType = myPrevPointType;
669                   break;
670                 }
671               }
672               if (ic->NbSelected() == 0)
673                 myCurrPointType = myPrevPointType;
674               //if ( mySetRotationPointDlg ) mySetRotationPointDlg->toggleChange();
675               ic->CloseAllContexts();
676               myOperation = NOTHING;
677               myViewPort->setCursor(myCursor);
678               myCursorIsHand = false;
679               myRotationPointSelection = false;
680             }
681           } else
682             emit mousePressed(this, theEvent);
683           break;
684       }
685       /* notify that we start a transformation */
686       if (transformRequested())
687         emit vpTransformationStarted(myOperation);
688   }
689   if (transformRequested())
690     setTransformInProcess(true);
691
692   /* we may need it for sketching... */
693   /*    if ( l_mbPressEvent )
694    delete l_mbPressEvent;
695    l_mbPressEvent = new QMouseEvent( *theEvent );*/
696 }
697
698 //****************************************************************
699 void XGUI_ViewWindow::contextMenuEvent(QContextMenuEvent* theEvent)
700 {
701   if (theEvent->modifiers() == Qt::NoModifier) {
702     // Temporary: has to be removed when viewer popup will be defined
703     //QFrame::contextMenuEvent(theEvent);
704     emit contextMenuRequested(theEvent);
705   }
706 }
707
708 //****************************************************************
709 void XGUI_ViewWindow::vpMouseReleaseEvent(QMouseEvent* theEvent)
710 {
711   switch (myOperation) {
712     case NOTHING: {
713       int prevState = myCurSketch;
714       /*            if(theEvent->button() == Qt::RightButton) {
715        QList<OCCViewer_ViewSketcher*>::Iterator it;
716        for ( it = mySketchers.begin(); it != mySketchers.end() && myCurSketch != -1; ++it ) {
717        OCCViewer_ViewSketcher* sk = (*it);
718        if( ( sk->sketchButton() & theEvent->button() ) && sk->sketchButton() == myCurSketch )
719        myCurSketch = -1;
720        }
721        }
722        */
723       emit mouseReleased(this, theEvent);
724     }
725       break;
726     case ROTATE:
727       myViewPort->endRotation();
728       resetState();
729       break;
730
731     case PANVIEW:
732     case ZOOMVIEW:
733       resetState();
734       break;
735
736     case PANGLOBAL:
737       if (theEvent->button() == Qt::LeftButton) {
738         myViewPort->setCenter(theEvent->x(), theEvent->y());
739         myViewPort->getView()->SetScale(myCurScale);
740         resetState();
741       }
742       break;
743
744     case WINDOWFIT:
745       if (theEvent->button() == Qt::LeftButton) {
746         myCurrX = theEvent->x();
747         myCurrY = theEvent->y();
748         drawRect();
749         QRect rect = XGUI_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
750         if (!rect.isEmpty())
751           myViewPort->fitRect(rect);
752         endDrawRect();
753         resetState();
754       }
755       break;
756   }
757
758   // NOTE: viewer 3D detects a rectangle of selection using this event
759   // so we must emit it BEFORE resetting the selection rectangle
760   if (theEvent->button() == Qt::LeftButton && myDrawRect) {
761     drawRect();
762     endDrawRect();
763     resetState();
764     myViewPort->update();
765   }
766   /*    if ( l_mbPressEvent ) {
767    delete l_mbPressEvent;
768    l_mbPressEvent = 0;
769    }*/
770 }
771
772 //****************************************************************
773 void XGUI_ViewWindow::vpMouseMoveEvent(QMouseEvent* theEvent)
774 {
775   if (myIsKeyFree && interactionStyle() == XGUI::KEY_FREE) {
776     myIsKeyFree = false;
777     switch (getButtonState(theEvent, interactionStyle())) {
778       case ZOOMVIEW:
779         myViewPort->startZoomAtPoint(myStartX, myStartY);
780         activateZoom();
781         break;
782       case PANVIEW:
783         activatePanning();
784         break;
785       case ROTATE:
786         activateRotation();
787         myViewPort->startRotation(myStartX, myStartY, myCurrPointType, mySelectedPoint);
788         break;
789       default:
790         break;
791     }
792   }
793
794   myCurrX = theEvent->x();
795   myCurrY = theEvent->y();
796   switch (myOperation) {
797     case ROTATE:
798       myViewPort->rotate(myCurrX, myCurrY, myCurrPointType, mySelectedPoint);
799       break;
800
801     case ZOOMVIEW:
802       myViewPort->zoom(myStartX, myStartY, myCurrX, myCurrY);
803       myStartX = myCurrX;
804       myStartY = myCurrY;
805       break;
806
807     case PANVIEW:
808       myViewPort->pan(myCurrX - myStartX, myStartY - myCurrY);
809       myStartX = myCurrX;
810       myStartY = myCurrY;
811       break;
812
813     case PANGLOBAL:
814       break;
815
816     default:
817       if (myRotationPointSelection /*|| isSketcherStyle()*/) {
818         emit mouseMoving(this, theEvent);
819       } else {
820         int aState = theEvent->modifiers();
821         int aButton = theEvent->buttons();
822         int anInteractionStyle = interactionStyle();
823         if (((anInteractionStyle == XGUI::STANDARD) && (aButton == Qt::LeftButton)
824             && (aState == Qt::NoModifier || Qt::ShiftModifier))
825             || ((anInteractionStyle == XGUI::KEY_FREE) && (aButton == Qt::LeftButton)
826                 && (aState == Qt::ControlModifier
827                     || aState == (Qt::ControlModifier | Qt::ShiftModifier)))) {
828           myDrawRect = myEnableDrawMode;
829           if (myDrawRect) {
830             drawRect();
831             if (!myCursorIsHand) {   // we are going to sketch a rectangle
832               QCursor handCursor(Qt::PointingHandCursor);
833               myCursorIsHand = true;
834               myCursor = cursor();
835               myViewPort->setCursor(handCursor);
836             }
837           }
838           emit mouseMoving(this, theEvent);
839         } /* else if ( ( (anInteractionStyle == XGUI::STANDARD) &&
840          (aButton == Qt::RightButton) && 
841          ( aState == Qt::NoModifier || Qt::ShiftModifier ) ) ||
842          ( (anInteractionStyle == XGUI::KEY_FREE) &&
843          (aButton == Qt::RightButton) && 
844          ( aState == Qt::ControlModifier || aState == ( Qt::ControlModifier|Qt::ShiftModifier ) ) ) ) {
845          OCCViewer_ViewSketcher* sketcher = 0;
846          QList<OCCViewer_ViewSketcher*>::Iterator it;
847          for ( it = mySketchers.begin(); it != mySketchers.end() && !sketcher; ++it ) {
848          OCCViewer_ViewSketcher* sk = (*it);
849          if( sk->isDefault() && sk->sketchButton() == aButton )
850          sketcher = sk;
851          }
852          if ( sketcher && myCurSketch == -1 ) {
853          activateSketching( sketcher->type() );
854          if ( mypSketcher ) {
855          myCurSketch = mypSketcher->sketchButton();
856
857          if ( l_mbPressEvent )  {
858          QApplication::sendEvent( getViewPort(), l_mbPressEvent );
859          delete l_mbPressEvent;
860          l_mbPressEvent = 0;
861          }
862          QApplication::sendEvent( getViewPort(), theEvent );
863          }
864          }
865          } */else
866           emit mouseMoving(this, theEvent);
867       }
868   }
869 }
870
871 /*!
872  \brief Draw rubber band rectangle.
873  */
874 void XGUI_ViewWindow::drawRect()
875 {
876   if (!myRectBand) {
877     myRectBand = new XGUI_RectRubberBand(myViewPort);
878   }
879
880   myRectBand->setUpdatesEnabled(false);
881   QRect aRect = XGUI_Tools::makeRect(myStartX, myStartY, myCurrX, myCurrY);
882   myRectBand->initGeometry(aRect);
883
884   if (!myRectBand->isVisible())
885     myRectBand->show();
886
887   myRectBand->setUpdatesEnabled(true);
888 }
889
890 /*!
891  \brief Clear rubber band rectangle on the end on the dragging operation.
892  */
893 void XGUI_ViewWindow::endDrawRect()
894 {
895   if (myRectBand) {
896     myRectBand->clearGeometry();
897     myRectBand->hide();
898   }
899 }
900
901 void XGUI_ViewWindow::activateZoom()
902 {
903   if (!transformRequested() && !myCursorIsHand)
904     myCursor = cursor(); /* save old cursor */
905
906   if (myOperation != ZOOMVIEW) {
907     QPixmap zoomPixmap(imageZoomCursor);
908     QCursor zoomCursor(zoomPixmap);
909     if (setTransformRequested(ZOOMVIEW))
910       myViewPort->setCursor(zoomCursor);
911   }
912 }
913
914 bool XGUI_ViewWindow::transformRequested() const
915 {
916   return (myOperation != NOTHING);
917 }
918
919 /*!
920  \brief Start delayed viewer operation.
921  */
922 bool XGUI_ViewWindow::setTransformRequested(OperationType op)
923 {
924   bool ok = transformEnabled(op);
925   myOperation = ok ? op : NOTHING;
926   myViewPort->setMouseTracking(myOperation == NOTHING);
927   return ok;
928 }
929
930 /*!
931  Set enabled state of transformation (rotate, zoom, etc)
932  */
933 void XGUI_ViewWindow::setTransformEnabled(const OperationType id, const bool on)
934 {
935   if (id != NOTHING)
936     myStatus.insert(id, on);
937 }
938
939 /*!
940  \return enabled state of transformation (rotate, zoom, etc)
941  */
942 bool XGUI_ViewWindow::transformEnabled(const OperationType id) const
943 {
944   return myStatus.contains(id) ? myStatus[id] : true;
945 }
946
947 /*!
948  \brief Start panning operation.
949
950  Sets the corresponding cursor for the widget.
951  */
952 void XGUI_ViewWindow::activatePanning()
953 {
954   if (!transformRequested() && !myCursorIsHand)
955     myCursor = cursor();                // save old cursor
956
957   if (myOperation != PANVIEW) {
958     QCursor panCursor(Qt::SizeAllCursor);
959     if (setTransformRequested(PANVIEW))
960       myViewPort->setCursor(panCursor);
961   }
962 }
963
964 /*!
965  \brief Start global panning operation
966
967  Sets the corresponding cursor for the widget.
968  */
969 void XGUI_ViewWindow::activateGlobalPanning()
970 {
971   Handle(V3d_View) aView3d = myViewPort->getView();
972   if (!aView3d.IsNull()) {
973     QPixmap globalPanPixmap(imageCrossCursor);
974     QCursor glPanCursor(globalPanPixmap);
975     myCurScale = aView3d->Scale();
976     aView3d->FitAll(0.01, false);
977     myCursor = cursor();                // save old cursor
978     myViewPort->fitAll();  // fits view before selecting a new scene center
979     if (setTransformRequested(PANGLOBAL))
980       myViewPort->setCursor(glPanCursor);
981   }
982 }
983
984 /*!
985  \brief Start rotation operation
986
987  Sets the corresponding cursor for the widget.
988  */
989 void XGUI_ViewWindow::activateRotation()
990 {
991   if (!transformRequested() && !myCursorIsHand)
992     myCursor = cursor();                // save old cursor
993
994   if (myOperation != ROTATE) {
995     QPixmap rotatePixmap(imageRotateCursor);
996     QCursor rotCursor(rotatePixmap);
997     if (setTransformRequested(ROTATE))
998       myViewPort->setCursor(rotCursor);
999   }
1000 }
1001
1002 /*!
1003  \brief Reset the viewport to its initial state
1004  ( no transformations in process etc. )
1005  */
1006 void XGUI_ViewWindow::resetState()
1007 {
1008   myDrawRect = false;
1009
1010   if (myRotationPointSelection) {
1011     QCursor handCursor(Qt::PointingHandCursor);
1012     myViewPort->setCursor(handCursor);
1013   } else {
1014     if (transformRequested() || myCursorIsHand)
1015       myViewPort->setCursor(myCursor);
1016     myCursorIsHand = false;
1017   }
1018
1019   if (transformRequested())
1020     emit vpTransformationFinished(myOperation);
1021
1022   setTransformInProcess(false);
1023   setTransformRequested(NOTHING);
1024 }
1025
1026 Qtx::BackgroundData XGUI_ViewWindow::background() const
1027 {
1028   return myViewPort ? myViewPort->background() : Qtx::BackgroundData();
1029 }
1030
1031 void XGUI_ViewWindow::setBackground(const Qtx::BackgroundData& theBackground)
1032 {
1033   if (myViewPort)
1034     myViewPort->setBackground(theBackground);
1035 }
1036
1037 /*!
1038  \brief Create one more window with same content.
1039  */
1040 void XGUI_ViewWindow::cloneView()
1041 {
1042   QMdiSubWindow* vw = myViewer->createView();
1043   XGUI_ViewWindow* aNewWnd = static_cast<XGUI_ViewWindow*>(vw->widget());
1044   aNewWnd->viewPort()->syncronizeWith(myViewPort);
1045
1046   emit viewCloned(vw);
1047
1048   //  In order to avoid frosen background in toolbars when it shown as a second view
1049   QTimer::singleShot(20, vw, SLOT(setFocus()));
1050 }
1051
1052 void XGUI_ViewWindow::dumpView()
1053 {
1054   QString aFilter(tr("Images Files (*.bmp *.png *.jpg *.jpeg *.eps *.ps)"));
1055   QString aSelectedFilter;
1056   QString aFileName = QFileDialog::getSaveFileName(this, "Save picture", QString(), aFilter,
1057                                                    &aSelectedFilter);
1058   if (!aFileName.isNull()) {
1059     QApplication::setOverrideCursor(Qt::WaitCursor);
1060     unsigned char* aData = 0;
1061     QImage aPicture = myViewPort->dumpView(aData);
1062
1063     QString aFmt = XGUI_Tools::extension(aFileName).toUpper();
1064     if (aFmt.isEmpty())
1065       aFmt = QString("BMP");  // default format
1066     else if (aFmt == "JPG")
1067       aFmt = "JPEG";
1068
1069     Handle(Visual3d_View) a3dView = myViewPort->getView()->View();
1070     if (aFmt == "PS")
1071 #ifdef WIN32
1072       a3dView->Export(_strdup(qPrintable(aFileName)), Graphic3d_EF_PostScript);
1073 #else
1074       a3dView->Export(strdup(qPrintable(aFileName)), Graphic3d_EF_PostScript);
1075 #endif
1076     else if (aFmt == "EPS")
1077 #ifdef WIN32
1078       a3dView->Export(_strdup(qPrintable(aFileName)), Graphic3d_EF_EnhPostScript);
1079 #else
1080       a3dView->Export(strdup(qPrintable(aFileName)), Graphic3d_EF_EnhPostScript);
1081 #endif
1082     else
1083       aPicture.save(aFileName, aFmt.toLatin1());
1084     delete aData;
1085     QApplication::restoreOverrideCursor();
1086   }
1087 }
1088
1089 void XGUI_ViewWindow::fitAll()
1090 {
1091   emit vpTransformationStarted(FITALLVIEW);
1092   myViewPort->fitAll();
1093   emit vpTransformationFinished(FITALLVIEW);
1094 }
1095
1096 /*!
1097  \brief Starts fit operation.
1098
1099  Sets the corresponding cursor for the widget.
1100  */
1101 void XGUI_ViewWindow::activateWindowFit()
1102 {
1103   if (!transformRequested() && !myCursorIsHand)
1104     myCursor = cursor(); /* save old cursor */
1105
1106   if (myOperation != WINDOWFIT) {
1107     QCursor handCursor(Qt::PointingHandCursor);
1108     if (setTransformRequested(WINDOWFIT)) {
1109       myViewPort->setCursor(handCursor);
1110       myCursorIsHand = true;
1111     }
1112   }
1113 }
1114
1115 /*!
1116  \brief Perform "front view" transformation.
1117  */
1118 void XGUI_ViewWindow::frontView()
1119 {
1120   emit vpTransformationStarted(FRONTVIEW);
1121   Handle(V3d_View) aView3d = myViewPort->getView();
1122   if (!aView3d.IsNull())
1123     aView3d->SetProj(V3d_Xpos);
1124   myViewPort->fitAll();
1125   emit vpTransformationFinished(FRONTVIEW);
1126 }
1127
1128 /*!
1129  \brief Perform "back view" transformation.
1130  */
1131 void XGUI_ViewWindow::backView()
1132 {
1133   emit vpTransformationStarted(BACKVIEW);
1134   Handle(V3d_View) aView3d = myViewPort->getView();
1135   if (!aView3d.IsNull())
1136     aView3d->SetProj(V3d_Xneg);
1137   myViewPort->fitAll();
1138   emit vpTransformationFinished(BACKVIEW);
1139 }
1140
1141 /*!
1142  \brief Perform "top view" transformation.
1143  */
1144 void XGUI_ViewWindow::topView()
1145 {
1146   emit vpTransformationStarted(TOPVIEW);
1147   Handle(V3d_View) aView3d = myViewPort->getView();
1148   if (!aView3d.IsNull())
1149     aView3d->SetProj(V3d_Zpos);
1150   myViewPort->fitAll();
1151   emit vpTransformationFinished(TOPVIEW);
1152 }
1153
1154 /*!
1155  \brief Perform "bottom view" transformation.
1156  */
1157 void XGUI_ViewWindow::bottomView()
1158 {
1159   emit vpTransformationStarted(BOTTOMVIEW);
1160   Handle(V3d_View) aView3d = myViewPort->getView();
1161   if (!aView3d.IsNull())
1162     aView3d->SetProj(V3d_Zneg);
1163   myViewPort->fitAll();
1164   emit vpTransformationFinished(BOTTOMVIEW);
1165 }
1166
1167 /*!
1168  \brief Perform "left view" transformation.
1169  */
1170 void XGUI_ViewWindow::leftView()
1171 {
1172   emit vpTransformationStarted(LEFTVIEW);
1173   Handle(V3d_View) aView3d = myViewPort->getView();
1174   if (!aView3d.IsNull())
1175     aView3d->SetProj(V3d_Yneg);
1176   myViewPort->fitAll();
1177   emit vpTransformationFinished(LEFTVIEW);
1178 }
1179
1180 /*!
1181  \brief Perform "right view" transformation.
1182  */
1183 void XGUI_ViewWindow::rightView()
1184 {
1185   emit vpTransformationStarted(RIGHTVIEW);
1186   Handle(V3d_View) aView3d = myViewPort->getView();
1187   if (!aView3d.IsNull())
1188     aView3d->SetProj(V3d_Ypos);
1189   myViewPort->fitAll();
1190   emit vpTransformationFinished(RIGHTVIEW);
1191 }
1192
1193 void XGUI_ViewWindow::reset()
1194 {
1195   emit vpTransformationStarted(RESETVIEW);
1196   bool upd = myViewPort->getView()->SetImmediateUpdate(false);
1197   myViewPort->getView()->Reset(false);
1198   myViewPort->fitAll(false, true, false);
1199   myViewPort->getView()->SetImmediateUpdate(upd);
1200   myViewPort->getView()->Update();
1201   emit vpTransformationFinished(RESETVIEW);
1202 }
1203
1204 void XGUI_ViewWindow::updateToolBar()
1205 {
1206   myGripWgt->update();
1207   myViewBar->update();
1208   myWindowBar->update();
1209 }
1210
1211 /*!
1212  \brief Update state of enable draw mode state.
1213  */
1214 void XGUI_ViewWindow::updateEnabledDrawMode()
1215 {
1216   myEnableDrawMode = myViewer->isSelectionEnabled() && myViewer->isMultiSelectionEnabled();
1217 }