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