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