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