Salome HOME
d5f31152b108181eba8189ee916f658800eed108
[modules/shaper.git] / src / XGUI / XGUI_ViewPort.cpp
1 #include "XGUI_ViewPort.h"
2 #include "XGUI_ViewWindow.h"
3 #include "XGUI_Viewer.h"
4 #include "XGUI_Constants.h"
5
6 #include <QPaintEvent>
7 #include <QPainter>
8 #include <QFileInfo>
9 #include <QApplication>
10
11 #include <V3d_OrthographicView.hxx>
12 #include <V3d_PerspectiveView.hxx>
13 #include <Visual3d_View.hxx>
14 #include <Graphic3d_GraphicDriver.hxx>
15
16 #ifdef WIN32
17 #include <WNT_Window.hxx>
18 #else
19 #include <Xw_Window.hxx>
20 #endif
21
22 #include <GL/gl.h>
23
24 static double rx = 0.;
25 static double ry = 0.;
26 static int sx = 0;
27 static int sy = 0;
28 static Standard_Boolean zRotation = Standard_False;
29
30 /*!
31  Create native view window for CasCade view [ static ]
32  */
33 Handle(Aspect_Window) CreateCasWindow(const Handle(V3d_View)& view, WId winId)
34 {
35   Aspect_Handle aWindowHandle = (Aspect_Handle) winId;
36 #ifdef WIN32
37   Handle(WNT_Window) viewWindow = new WNT_Window(aWindowHandle);
38 #else
39   Handle(Aspect_DisplayConnection) aDispConnection = view->Viewer()->Driver()->GetDisplayConnection();
40   Handle(Xw_Window) viewWindow = new Xw_Window( aDispConnection, aWindowHandle );
41 #endif
42   return viewWindow;
43 }
44
45 //************************************************************************
46 //************************************************************************
47 //************************************************************************
48 XGUI_ViewPort::XGUI_ViewPort(XGUI_ViewWindow* theParent, const Handle(V3d_Viewer)& theViewer,
49                              V3d_TypeOfView theType)
50     : QWidget(theParent),
51       myPaintersRedrawing(false),
52       myScale(1.0),
53       myIsAdvancedZoomingEnabled(false),
54       myBgImgHeight(0),
55       myBgImgWidth(0)
56 {
57   setMouseTracking(true);
58   setBackgroundRole(QPalette::NoRole);
59
60   // set focus policy to threat QContextMenuEvent from keyboard  
61   setFocusPolicy(Qt::StrongFocus);
62   setAttribute(Qt::WA_PaintOnScreen);
63   setAttribute(Qt::WA_NoSystemBackground);
64   setAutoFillBackground(false);
65
66   if (theType == V3d_ORTHOGRAPHIC) {
67     myOrthoView = new V3d_OrthographicView(theViewer);
68     myActiveView = myOrthoView;
69     myPerspView = 0;
70   } else {
71     myPerspView = new V3d_PerspectiveView(theViewer);
72     myActiveView = myPerspView;
73   }
74   myActiveView->SetSurfaceDetail(V3d_TEX_ALL);
75 }
76
77 //***********************************************
78 XGUI_ViewPort::~XGUI_ViewPort()
79 {
80 }
81
82 //***********************************************
83 bool XGUI_ViewPort::mapView(const Handle(V3d_View)& theView)
84 {
85   if (!setWindow(theView))
86     return false;
87
88   if (!mapped(theView)) {
89     theView->SetWindow(myWindow);
90     //if (theView != activeView())
91     //theView->View()->Deactivate();
92   }
93
94   /* create static trihedron (16551: EDF PAL 501) */
95   //OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
96   //if ( aVW ) {
97   //    OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
98   //    if ( aViewModel && aViewModel->isStaticTrihedronDisplayed() ){
99   //theView->ZBufferTriedronSetup();
100   theView->TriedronDisplay(Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER);
101   //    }
102   //}
103
104   emit(vpMapped());
105
106   return true;
107 }
108
109 //***********************************************
110 bool XGUI_ViewPort::setWindow(const Handle(V3d_View)& theView)
111 {
112   if (!myWindow.IsNull())
113     return true;
114
115   if (theView.IsNull())
116     return false;
117
118   attachWindow(theView, CreateCasWindow(theView, winId()));
119
120   myWindow = theView->Window();
121   return !myWindow.IsNull();
122 }
123
124 //***********************************************
125 bool XGUI_ViewPort::mapped(const Handle(V3d_View)& theView) const
126 {
127   return (!theView.IsNull() && theView->View()->IsDefined());
128 }
129
130 //***********************************************
131 void XGUI_ViewPort::updateBackground()
132 {
133   if (activeView().IsNull())
134     return;
135   if (!myBackground.isValid())
136     return;
137
138   // VSR: Important note on below code.
139   // In OCCT (in version 6.5.2), things about the background drawing
140   // are not straightforward and not clearly understandable:
141   // - Horizontal gradient is drawn vertically (!), well ok, from top side to bottom one.
142   // - Vertical gradient is drawn horizontally (!), from right side to left one (!!!).
143   // - First and second diagonal gradients are confused.
144   // - Image texture, once set, can not be removed (!).
145   // - Texture image fill mode Aspect_FM_NONE is not taken into account (and means the same
146   //   as Aspect_FM_CENTERED).
147   // - The only way to cancel gradient background (and get back to single colored) is to
148   //   set gradient background style to Aspect_GFM_NONE while passing two colors is also needed
149   //   (see V3d_View::SetBgGradientColors() function).
150   // - Also, it is impossible to draw texture image above the gradiented background (only above
151   //   single-colored).
152   // In OCCT 6.5.3 all above mentioned problems are fixed; so, above comment should be removed as soon
153   // as SALOME is migrated to OCCT 6.5.3. The same concerns #ifdef statements in the below code
154   switch (myBackground.mode()) {
155     case Qtx::ColorBackground: {
156       QColor c = myBackground.color();
157       if (c.isValid()) {
158         // Unset texture should be done here
159         // ...
160         Quantity_Color qCol(c.red() / 255., c.green() / 255., c.blue() / 255., Quantity_TOC_RGB);
161         activeView()->SetBgGradientStyle(Aspect_GFM_NONE);  // cancel gradient background
162         activeView()->SetBgImageStyle(Aspect_FM_NONE);  // cancel texture background
163         // then change background color
164         activeView()->SetBackgroundColor(qCol);
165         // update viewer
166         activeView()->Update();
167       }
168       break;
169     }
170     case Qtx::SimpleGradientBackground: {
171       QColor c1, c2;
172       int type = myBackground.gradient(c1, c2);
173       if (c1.isValid() && type >= XGUI::HorizontalGradient && type <= XGUI::LastGradient) {
174         // Unset texture should be done here
175         // ...
176         // Get colors and set-up gradiented background
177         if (!c2.isValid())
178           c2 = c1;
179         Quantity_Color qCol1(c1.red() / 255., c1.green() / 255., c1.blue() / 255.,
180                              Quantity_TOC_RGB);
181         Quantity_Color qCol2(c2.red() / 255., c2.green() / 255., c2.blue() / 255.,
182                              Quantity_TOC_RGB);
183         activeView()->SetBgImageStyle(Aspect_FM_NONE);  // cancel texture background
184         switch (type) {
185           case XGUI::HorizontalGradient:
186             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_HOR,
187             Standard_True);
188             break;
189           case XGUI::VerticalGradient:
190             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_VER,
191             Standard_True);
192             break;
193           case XGUI::Diagonal1Gradient:
194             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_DIAG1,
195             Standard_True);
196             break;
197           case XGUI::Diagonal2Gradient:
198             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_DIAG2,
199             Standard_True);
200             break;
201           case XGUI::Corner1Gradient:
202             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER1,
203             Standard_True);
204             break;
205           case XGUI::Corner2Gradient:
206             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER2,
207             Standard_True);
208             break;
209           case XGUI::Corner3Gradient:
210             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER3,
211             Standard_True);
212             break;
213           case XGUI::Corner4Gradient:
214             activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER4,
215             Standard_True);
216             break;
217           default:
218             break;
219         }
220       }
221       break;
222     }
223     case Qtx::CustomGradientBackground:
224       // NOT IMPLEMENTED YET
225       break;
226     default:
227       break;
228   }
229   // VSR: In OCCT before v6.5.3 below code can't be used because of very ugly bug - it has been impossible to
230   // clear the background texture image as soon as it was once set to the viewer.
231   if (myBackground.isTextureShown()) {
232     QString fileName;
233     int textureMode = myBackground.texture(fileName);
234     QFileInfo fi(fileName);
235     if (!fileName.isEmpty() && fi.exists()) {
236       // set texture image: file name and fill mode
237       switch (textureMode) {
238         case XGUI::CenterTexture:
239           activeView()->SetBackgroundImage(fi.absoluteFilePath().toLatin1().constData(),
240                                            Aspect_FM_CENTERED);
241           break;
242         case XGUI::TileTexture:
243           activeView()->SetBackgroundImage(fi.absoluteFilePath().toLatin1().constData(),
244                                            Aspect_FM_TILED);
245           break;
246         case XGUI::StretchTexture:
247           activeView()->SetBackgroundImage(fi.absoluteFilePath().toLatin1().constData(),
248                                            Aspect_FM_STRETCH);
249           break;
250         default:
251           break;
252       }
253       activeView()->Update();
254     }
255   }
256 }
257
258 //***********************************************
259 void XGUI_ViewPort::attachWindow(const Handle(V3d_View)& theView,
260                                  const Handle(Aspect_Window)& theWnd)
261 {
262   if (!theView.IsNull()) {
263     theView->SetWindow(theWnd);
264     updateBackground();
265   }
266 }
267
268 //***********************************************
269 void XGUI_ViewPort::paintEvent(QPaintEvent* theEvent)
270 {
271 #ifndef WIN32
272   /* X11 : map before show doesn't work */
273   if ( !mapped( activeView() ) )
274   mapView( activeView() );
275 #endif
276   if (!myWindow.IsNull()) {
277     QApplication::syncX();
278     QRect rc = theEvent->rect();
279     //if ( !myPaintersRedrawing ) {
280     //activeView()->Redraw();
281     activeView()->Redraw(rc.x(), rc.y(), rc.width(), rc.height());
282     emit vpUpdated();
283     //}
284   }
285   //if ( myPaintersRedrawing ) {
286   //    QPainter p( this );
287   //    //emit vpDrawExternal( &p );
288   //    myPaintersRedrawing = false;
289   //}
290 }
291
292 //***********************************************
293 void XGUI_ViewPort::resizeEvent(QResizeEvent* theEvent)
294 {
295 #ifdef WIN32
296   /* Win32 : map before first show to avoid flicker */
297   if (!mapped(activeView()))
298     mapView(activeView());
299 #endif
300   QApplication::syncX();
301   if (!activeView().IsNull()) {
302     activeView()->MustBeResized();
303   }
304   emit resized();
305 }
306
307 //***********************************************
308 QImage XGUI_ViewPort::dumpView(QRect theRect, bool toUpdate)
309 {
310   Handle(V3d_View) view = getView();
311   if (view.IsNull())
312     return QImage();
313
314   int aWidth;
315   int aHeight;
316   if (theRect.isNull()) {
317     aWidth = width();
318     aHeight = height();
319   } else {
320     aWidth = theRect.width();
321     aHeight = theRect.height();
322   }
323   QApplication::syncX();
324
325   unsigned char* data = new unsigned char[aWidth * aHeight * 4];
326
327   QPoint p;
328   if (theRect.isNull()) {
329     if (toUpdate)
330       view->Redraw();
331     p = mapFromParent(geometry().topLeft());
332   } else {
333     if (toUpdate)
334       view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
335     p = theRect.topLeft();
336   }
337   glReadPixels(p.x(), p.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
338
339   QImage anImage(data, aWidth, aHeight, QImage::Format_ARGB32);
340   anImage = anImage.mirrored();
341   anImage = anImage.rgbSwapped();
342   return anImage;
343 }
344
345 /*!
346  Inits 'rotation' transformation.
347  */
348 void XGUI_ViewPort::startRotation(int x, int y, int theRotationPointType,
349                                   const gp_Pnt& theSelectedPoint)
350 {
351   if (!activeView().IsNull()) {
352     switch (theRotationPointType) {
353       case XGUI::GRAVITY:
354         activeView()->StartRotation(x, y, 0.45);
355         break;
356       case XGUI::SELECTED:
357         sx = x;
358         sy = y;
359
360         double X, Y;
361         activeView()->Size(X, Y);
362         rx = Standard_Real(activeView()->Convert(X));
363         ry = Standard_Real(activeView()->Convert(Y));
364
365         activeView()->Rotate(0., 0., 0., theSelectedPoint.X(), theSelectedPoint.Y(),
366                              theSelectedPoint.Z(),
367                              Standard_True);
368
369         Quantity_Ratio zRotationThreshold;
370         zRotation = Standard_False;
371         zRotationThreshold = 0.45;
372         if (zRotationThreshold > 0.) {
373           Standard_Real dx = Abs(sx - rx / 2.);
374           Standard_Real dy = Abs(sy - ry / 2.);
375           Standard_Real dd = zRotationThreshold * (rx + ry) / 2.;
376           if (dx > dd || dy > dd)
377             zRotation = Standard_True;
378         }
379         break;
380       default:
381         break;
382     }
383     activeView()->DepthFitAll();
384   }
385 }
386
387 /*!
388  Rotates the viewport. 
389  */
390 void XGUI_ViewPort::rotate(int x, int y, int theRotationPointType, const gp_Pnt& theSelectedPoint)
391 {
392   if (!activeView().IsNull()) {
393     switch (theRotationPointType) {
394       case XGUI::GRAVITY:
395         activeView()->Rotation(x, y);
396         break;
397       case XGUI::SELECTED:
398         double dx, dy, dz;
399         if (zRotation) {
400           dz = atan2(Standard_Real(x) - rx / 2., ry / 2. - Standard_Real(y))
401               - atan2(sx - rx / 2., ry / 2. - sy);
402           dx = dy = 0.;
403         } else {
404           dx = (Standard_Real(x) - sx) * M_PI / rx;
405           dy = (sy - Standard_Real(y)) * M_PI / ry;
406           dz = 0.;
407         }
408
409         activeView()->Rotate(dx, dy, dz, theSelectedPoint.X(), theSelectedPoint.Y(),
410                              theSelectedPoint.Z(),
411                              Standard_False);
412         break;
413       default:
414         break;
415     }
416     emit vpTransformed();
417   }
418   //  setZSize( getZSize() );
419 }
420
421 /*!
422  Resets the viewport after 'rotation'. 
423  */
424 void XGUI_ViewPort::endRotation()
425 {
426   if (!activeView().IsNull()) {
427     activeView()->ZFitAll(1.);
428     activeView()->SetZSize(0.);
429     activeView()->Update();
430     emit vpTransformed();
431   }
432 }
433
434 /*!
435  Inits 'zoom' transformation.
436  */
437 void XGUI_ViewPort::startZoomAtPoint(int x, int y)
438 {
439   if (!activeView().IsNull()/* && isAdvancedZoomingEnabled() */)
440     activeView()->StartZoomAtPoint(x, y);
441 }
442
443 /*!
444  Centers the viewport. 
445  */
446 void XGUI_ViewPort::setCenter(int x, int y)
447 {
448   if (!activeView().IsNull()) {
449     activeView()->Place(x, y, myScale);
450     emit vpTransformed();
451   }
452 }
453
454 /*!
455  Called at 'pan' transformation. 
456  */
457 void XGUI_ViewPort::pan(int dx, int dy)
458 {
459   if (!activeView().IsNull()) {
460     activeView()->Pan(dx, dy, 1.0);
461     emit vpTransformed();
462   }
463 }
464
465 /*!
466  Called at 'window fit' transformation.
467  */
468 void XGUI_ViewPort::fitRect(const QRect& rect)
469 {
470   if (!activeView().IsNull()) {
471     activeView()->WindowFit(rect.left(), rect.top(), rect.right(), rect.bottom());
472     emit vpTransformed();
473   }
474 }
475
476 /*!
477  Called at 'zoom' transformation.
478  */
479 void XGUI_ViewPort::zoom(int x0, int y0, int x, int y)
480 {
481   if (!activeView().IsNull()) {
482     if (isAdvancedZoomingEnabled())
483       activeView()->ZoomAtPoint(x0, y0, x, y);
484     else
485       activeView()->Zoom(x0 + y0, 0, x + y, 0);
486     emit vpTransformed();
487   }
488 }
489
490 /*!
491  Sets the background data
492  */
493 void XGUI_ViewPort::setBackground(const Qtx::BackgroundData& bgData)
494 {
495   if (bgData.isValid()) {
496     myBackground = bgData;
497     updateBackground();
498     emit vpChangeBackground(myBackground);
499   }
500 }
501
502 void XGUI_ViewPort::fitAll(bool theKeepScale, bool theWithZ, bool theUpd)
503 {
504   if (activeView().IsNull())
505     return;
506
507   if (theKeepScale)
508     myScale = activeView()->Scale();
509
510   Standard_Real aMargin = 0.01;
511   activeView()->FitAll(aMargin, theWithZ, theUpd);
512   activeView()->SetZSize(0.);
513   emit vpTransformed();
514 }
515
516 void XGUI_ViewPort::syncronizeWith(const XGUI_ViewPort* ref)
517 {
518   Handle(V3d_View) refView = ref->getView();
519   Handle(V3d_View) tgtView = getView();
520
521   /*  The following params are copied:
522    - view type( ortho/persp )
523    - position of view point
524    - orientation of high point
525    - position of the eye
526    - projection vector
527    - view center ( 2D )
528    - view twist
529    - view scale
530    */
531
532   /* we'll update after setting all params */
533   tgtView->SetImmediateUpdate( Standard_False);
534
535   /* perspective */
536   if (refView->Type() == V3d_PERSPECTIVE)
537     tgtView->SetFocale(refView->Focale());
538
539   /* copy params */
540   Standard_Real x, y, z;
541   refView->At(x, y, z);
542   tgtView->SetAt(x, y, z);
543   refView->Up(x, y, z);
544   tgtView->SetUp(x, y, z);
545   refView->Eye(x, y, z);
546   tgtView->SetEye(x, y, z);
547   refView->Proj(x, y, z);
548   tgtView->SetProj(x, y, z);
549   refView->Center(x, y);
550   tgtView->SetCenter(x, y);
551   tgtView->SetScale(refView->Scale());
552   tgtView->SetTwist(refView->Twist());
553
554   /* update */
555   tgtView->Update();
556   tgtView->SetImmediateUpdate( Standard_True);
557 }