Salome HOME
Initial version
[modules/gui.git] / src / GLViewer / GLViewer_ViewFrame.cxx
1 // File:      GLViewer_ViewFrame.cxx
2 // Created:   November, 2004
3 // Author:    OCC team
4 // Copyright (C) CEA 2004
5
6 /***************************************************************************
7 **  Class:   GLViewer_ViewFrame
8 **  Descr:   Frame window for viewport in QAD-based application
9 **  Module:  QAD
10 **  Created: UI team, 05.09.00
11 ****************************************************************************/
12
13 #include "GLViewer_ViewFrame.h"
14
15 #include "GLViewer_Viewer.h"
16 #include "GLViewer_Viewer2d.h"
17 #include "GLViewer_ViewPort2d.h"
18
19 #include <SUIT_Desktop.h>
20 #include <SUIT_Session.h>
21 #include <SUIT_ToolButton.h>
22 #include <SUIT_ResourceMgr.h>
23 #include <QtxAction.h>
24 #include <SUIT_MessageBox.h>
25
26 #include <qcolor.h>
27 #include <qfiledialog.h>
28 #include <qimage.h>
29 #include <qlayout.h>
30 #include <qstring.h>
31
32 /*!
33     Constructor
34 */
35 GLViewer_ViewFrame::GLViewer_ViewFrame( SUIT_Desktop* d, GLViewer_Viewer* vw )
36 : SUIT_ViewWindow( d ),
37 myViewer( vw ),
38 myVP( 0 )
39 {
40     QFrame* client = new QFrame( this );    
41     setCentralWidget( client );
42
43     QBoxLayout* layout = new QHBoxLayout( client, 1, 1 );
44     layout->setAutoAdd( true );
45
46     GLViewer_ViewPort2d* vp = new GLViewer_ViewPort2d( client, this );
47     //vp->turnGrid( true );
48     //vp->turnCompass( true );
49     //vp->enablePopup( false );
50     setViewPort( vp );
51     setBackgroundColor( Qt::white );
52
53     myToolBar = new QToolBar(this);
54     myToolBar->setCloseMode(QDockWindow::Undocked);
55     myToolBar->setLabel(tr("LBL_TOOLBAR_LABEL"));
56     createActions();
57     createToolBar();
58 }
59
60 /*!
61     Destructor
62 */
63 GLViewer_ViewFrame::~GLViewer_ViewFrame()
64 {
65 }
66
67 //================================================================
68 // Function : createActions
69 // Purpose  : 
70 //================================================================
71 void GLViewer_ViewFrame::createActions()
72 {
73   if ( !myActionsMap.isEmpty() )
74     return;
75
76   QtxAction* aAction;
77   SUIT_ResourceMgr* aResMgr = SUIT_Session::session()->resourceMgr();
78
79   // Dump view
80   aAction = new QtxAction(tr("MNU_DUMP_VIEW"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_DUMP" ) ),
81                            tr( "MNU_DUMP_VIEW" ), 0, this);
82   aAction->setStatusTip(tr("DSC_DUMP_VIEW"));
83   connect(aAction, SIGNAL(activated()), this, SLOT(onViewDump()));
84   myActionsMap[ DumpId ] = aAction;
85
86   // FitAll
87   aAction = new QtxAction(tr("MNU_FITALL"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_FITALL" ) ),
88                            tr( "MNU_FITALL" ), 0, this);
89   aAction->setStatusTip(tr("DSC_FITALL"));
90   connect(aAction, SIGNAL(activated()), this, SLOT(onViewFitAll()));
91   myActionsMap[ FitAllId ] = aAction;
92
93   // FitRect
94   aAction = new QtxAction(tr("MNU_FITRECT"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_FITAREA" ) ),
95                            tr( "MNU_FITRECT" ), 0, this);
96   aAction->setStatusTip(tr("DSC_FITRECT"));
97   connect(aAction, SIGNAL(activated()), this, SLOT(onViewFitArea()));
98   myActionsMap[ FitRectId ] = aAction;
99
100   // FitSelect
101   aAction = new QtxAction(tr("MNU_FITSELECT"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_FITSELECT" ) ),
102                           tr( "MNU_FITSELECT" ), 0, this);
103   aAction->setStatusTip(tr("DSC_FITSELECT"));
104   connect(aAction, SIGNAL(activated()), this, SLOT(onViewFitSelect()));
105   myActionsMap[ FitSelectId ] = aAction;
106
107   // Zoom
108   aAction = new QtxAction(tr("MNU_ZOOM_VIEW"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_ZOOM" ) ),
109                            tr( "MNU_ZOOM_VIEW" ), 0, this);
110   aAction->setStatusTip(tr("DSC_ZOOM_VIEW"));
111   connect(aAction, SIGNAL(activated()), this, SLOT(onViewZoom()));
112   myActionsMap[ ZoomId ] = aAction;
113
114   // Panning
115   aAction = new QtxAction(tr("MNU_PAN_VIEW"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_PAN" ) ),
116                            tr( "MNU_PAN_VIEW" ), 0, this);
117   aAction->setStatusTip(tr("DSC_PAN_VIEW"));
118   connect(aAction, SIGNAL(activated()), this, SLOT(onViewPan()));
119   myActionsMap[ PanId ] = aAction;
120
121   // Global Panning
122   aAction = new QtxAction(tr("MNU_GLOBALPAN_VIEW"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_GLOBALPAN" ) ),
123                            tr( "MNU_GLOBALPAN_VIEW" ), 0, this);
124   aAction->setStatusTip(tr("DSC_GLOBALPAN_VIEW"));
125   connect(aAction, SIGNAL(activated()), this, SLOT(onViewGlobalPan()));
126   myActionsMap[ GlobalPanId ] = aAction;
127
128   aAction = new QtxAction(tr("MNU_RESET_VIEW"), aResMgr->loadPixmap( "GLViewer", tr( "ICON_GL_RESET" ) ),
129                            tr( "MNU_RESET_VIEW" ), 0, this);
130   aAction->setStatusTip(tr("DSC_RESET_VIEW"));
131   connect(aAction, SIGNAL(activated()), this, SLOT(onViewReset()));
132   myActionsMap[ ResetId ] = aAction;
133 }
134
135 //================================================================
136 // Function : createToolBar
137 // Purpose  : 
138 //================================================================
139 void GLViewer_ViewFrame::createToolBar()
140 {
141   myActionsMap[DumpId]->addTo(myToolBar);
142
143   SUIT_ToolButton* aScaleBtn = new SUIT_ToolButton(myToolBar);
144   aScaleBtn->AddAction(myActionsMap[FitAllId]);
145   aScaleBtn->AddAction(myActionsMap[FitRectId]);
146   aScaleBtn->AddAction(myActionsMap[FitSelectId]);
147   aScaleBtn->AddAction(myActionsMap[ZoomId]);
148
149   SUIT_ToolButton* aPanBtn = new SUIT_ToolButton(myToolBar);
150   aPanBtn->AddAction(myActionsMap[PanId]);
151   aPanBtn->AddAction(myActionsMap[GlobalPanId]);
152
153   myActionsMap[ResetId]->addTo(myToolBar);
154 }
155
156 /*!
157     Sets the viewport for this frame
158 */
159 void GLViewer_ViewFrame::setViewPort( GLViewer_ViewPort* vp )
160 {
161     if ( myVP == vp )
162         return;
163
164     if ( myVP )
165     {
166         disconnect( myVP, SIGNAL( vpDrawExternal( QPainter* ) ), this, SIGNAL( vfDrawExternal( QPainter* ) ) );
167         disconnect( myVP, SIGNAL( vpMouseEvent( QMouseEvent* ) ), this, SLOT( mouseEvent( QMouseEvent* ) ) );
168         disconnect( myVP, SIGNAL( vpKeyEvent( QKeyEvent* ) ), this, SLOT( keyEvent( QKeyEvent* ) ) );
169         disconnect( myVP, SIGNAL(contextMenuRequested( QContextMenuEvent * )),
170                     this, SIGNAL(contextMenuRequested( QContextMenuEvent * )) );
171         disconnect( myVP, SIGNAL( vpWheelEvent( QWheelEvent* ) ), this, SLOT( wheelEvent( QWheelEvent* ) ) );
172     }
173     myVP = vp;
174     if ( myVP )
175     {
176         connect( myVP, SIGNAL( vpDrawExternal( QPainter* ) ), this, SIGNAL( vfDrawExternal( QPainter* ) ) );
177         connect( myVP, SIGNAL( vpMouseEvent( QMouseEvent* ) ), this, SLOT( mouseEvent( QMouseEvent* ) ) );
178         connect( myVP, SIGNAL( vpKeyEvent( QKeyEvent* ) ), this, SLOT( keyEvent( QKeyEvent* ) ) );
179         connect( myVP, SIGNAL(contextMenuRequested( QContextMenuEvent * )),
180                  this, SIGNAL(contextMenuRequested( QContextMenuEvent * )) );
181         connect( myVP, SIGNAL( vpWheelEvent( QWheelEvent* ) ), this, SLOT( wheelEvent( QWheelEvent* ) ) );
182     }
183 }
184
185 /*!
186     Returns the viewport of this frame. [ public ]
187 */
188 GLViewer_ViewPort* GLViewer_ViewFrame::getViewPort() const
189 {
190     return myVP;
191 }
192
193 /*!
194     Set background of the viewport. [ public ]
195 */
196 void GLViewer_ViewFrame::setBackgroundColor( const QColor& color )
197 {
198     if ( myVP )
199         myVP->setBackgroundColor( color );
200 }
201
202 /*!
203     Returns background of the viewport. [ public ]
204 */
205 QColor GLViewer_ViewFrame::backgroundColor() const
206 {
207     if ( myVP )
208         return myVP->backgroundColor();
209     return QMainWindow::backgroundColor();
210 }
211
212 /*!
213     Sets the viewer for this view. [ public ]
214 */
215 void GLViewer_ViewFrame::setViewer( GLViewer_Viewer* v )
216 {
217     myViewer = v;
218 }
219
220 /*!
221     Returns the viewer of this view. [ public ]
222 */
223 GLViewer_Viewer* GLViewer_ViewFrame::getViewer() const
224 {
225     return myViewer;
226 }
227
228 /*!
229     Returns the preferred view size. [ virtual public ]
230 */
231 QSize GLViewer_ViewFrame::sizeHint() const
232 {
233     QWidget* p = parentWidget();
234     if ( p && p->inherits( "QWorkspaceChild" ) )
235         p = p->parentWidget();      /* QWorkspaceChild: internal impl class in QWorkspace */
236     if ( !p )
237         return QMainWindow::sizeHint();
238     return QSize( 9 * p->width() / 10 , 9 * p->height() / 10  );
239 }
240
241 /*!
242    Called by viewer's 'update()' method. Does nothing by default [ virtual public ]
243 */
244 void GLViewer_ViewFrame::onUpdate( int )
245 {
246 }
247
248 void GLViewer_ViewFrame::onViewDump()
249 {
250     GLViewer_Widget* aWidget = ((GLViewer_ViewPort2d*)myVP)->getGLWidget();
251     int width, height;
252     width = aWidget->width();
253     height = aWidget->height();
254     
255     int imageSize = width*height*3;
256     unsigned char* imageBits = NULL;
257
258     int reserve_bytes = width % 4; //32 bits platform
259     imageSize = (width+reserve_bytes)*height*3;
260     imageBits = new unsigned char[imageSize];
261
262     
263 #ifdef WNT
264
265     int num;
266     HBITMAP hBmp;
267     HDC hdc_old, hdc;
268     HGLRC hglrc_old, hglrc;
269
270     BITMAPINFO bi;
271
272     hglrc_old = wglGetCurrentContext();
273     hdc_old = wglGetCurrentDC();
274
275     hdc = CreateCompatibleDC( hdc_old );
276     if( !hdc )
277     {
278         cout << "Can't create compatible DC. Last Error Code: " << GetLastError() << endl;
279         return;
280     }
281
282     int sizeBmi = Standard_Integer( sizeof(BITMAPINFO) + sizeof(RGBQUAD)*3 );
283     PBITMAPINFO pBmi = (PBITMAPINFO)( new char[sizeBmi] );
284     ZeroMemory( pBmi, sizeBmi );
285
286     pBmi->bmiHeader.biSize        = sizeof( BITMAPINFOHEADER ); //sizeBmi
287     pBmi->bmiHeader.biWidth       = width;
288     pBmi->bmiHeader.biHeight      = height;
289     pBmi->bmiHeader.biPlanes      = 1;
290     pBmi->bmiHeader.biBitCount    = 24;
291     pBmi->bmiHeader.biCompression = BI_RGB;
292
293     LPVOID ppvBits;
294     hBmp = CreateDIBSection ( hdc, pBmi, DIB_RGB_COLORS, &ppvBits, NULL, 0 );
295     SelectObject ( hdc, hBmp );
296     delete[] pBmi;
297
298     PIXELFORMATDESCRIPTOR pfd;
299     ZeroMemory( &pfd, sizeof( PIXELFORMATDESCRIPTOR ) );
300     pfd.nSize      = sizeof( PIXELFORMATDESCRIPTOR );
301     pfd.nVersion   = 1;
302     pfd.dwFlags    = PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP;
303     pfd.iPixelType = PFD_TYPE_RGBA;
304     pfd.cColorBits = 24;
305     pfd.cDepthBits = 32;
306     pfd.iLayerType = PFD_MAIN_PLANE;
307
308     int iPf = ChoosePixelFormat( hdc, &pfd);    
309     if( iPf == 0 )
310     {
311         if ( !DescribePixelFormat ( hdc, iPf, sizeof(PIXELFORMATDESCRIPTOR), &pfd ) )
312         {
313             cout << "Can't describe Pixel Format. Last Error Code: " << GetLastError() << endl;
314         }
315     }
316     if ( !SetPixelFormat(hdc, iPf, &pfd) )
317     {
318         cout << "Can't set Pixel Format. Last Error Code: " << GetLastError() << endl;
319     }
320
321     hglrc = wglCreateContext( hdc );
322     if( !hglrc )
323     {
324         cout << "Can't create new GL Context. Last Error Code: " << GetLastError() << endl;
325         return;
326     }
327     if( !wglMakeCurrent( hdc, hglrc) )
328     {
329         cout << "Can't make current new context!" << endl;
330         return;
331     }
332     
333     glViewport( 0, 0, width, height );
334
335     glMatrixMode( GL_PROJECTION );
336     glLoadIdentity();
337     GLfloat w_c = width / 2., h_c = height / 2.; 
338
339     gluOrtho2D( -w_c, w_c, -h_c, h_c ); 
340
341     glMatrixMode( GL_MODELVIEW );
342     glLoadIdentity();
343
344     //set background
345     QColor aColor = ((GLViewer_ViewPort2d*)myVP)->backgroundColor();
346     glClearColor( ( GLfloat )aColor.red() / 255,
347                   ( GLfloat )aColor.green() / 255,
348                   ( GLfloat )aColor.blue() / 255,
349                   1.0 );
350
351     aWidget->exportRepaint();
352
353       memset(&bi, 0, sizeof(BITMAPINFOHEADER));
354     bi.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
355     bi.bmiHeader.biPlanes      = 1;
356     bi.bmiHeader.biBitCount    = 24;
357     bi.bmiHeader.biHeight      = -height;
358     bi.bmiHeader.biWidth       = width;
359     bi.bmiHeader.biCompression = BI_RGB;
360
361     num = GetDIBits(hdc, hBmp, 0, height, imageBits, &bi, DIB_RGB_COLORS);
362
363     wglMakeCurrent( hdc_old, hglrc_old );
364     wglDeleteContext( hglrc );
365     
366
367 #else //XWindows
368 #endif
369
370     unsigned int* aPix = NULL;
371     QImage  anImage( width, height, 32 );
372     for( int i = 0; i < height; i++ )
373     {
374         memset( anImage.scanLine( i ), 0, sizeof(unsigned int)*width );
375         unsigned char* pos;
376         for( int j = 0; j < width; j++ )
377         {
378             pos = imageBits + i*width*3 + j*3 + reserve_bytes*i;
379             aPix = (unsigned int*)anImage.scanLine(i)+j;
380             *aPix = qRgb( *pos, *(pos+1), *(pos+2) );
381         }
382     }
383
384     delete [] imageBits;
385
386     QString aFilter( "*.bmp\n*.png" );
387
388     QFileDialog aFileDlg( QDir::current().absPath(), aFilter, this );
389     aFileDlg.setCaption( tr( "DUMP_VIEW_SAVE_FILE_DLG_CAPTION" ) );
390     aFileDlg.setMode( QFileDialog::AnyFile );
391
392     if( !aFileDlg.exec() )
393         return;
394
395     QString aFileName = aFileDlg.selectedFile();
396     QString aFileExt = aFileDlg.selectedFilter();
397
398     if( aFileName.isEmpty() )
399     {
400         SUIT_MessageBox::error1( this,
401                                  tr( "DUMP_VIEW_ERROR_DLG_CAPTION" ),
402                                  tr( "DUMP_VIEW_ERROR_DLG_TEXT" ),
403                                  tr( "BUT_OK" ) );
404     }
405
406     QString aSaveOp = "BMP";
407     QString aTypedFileExt = QFileInfo( aFileName ).extension( false ).lower();
408
409     if( aFileExt == "*.bmp" )
410     {
411         if( aTypedFileExt.isEmpty() )
412             aFileName += ".bmp";
413         aSaveOp = "BMP";
414     }
415     else if( aFileExt == "*.png" )
416         if( aTypedFileExt.isEmpty() )
417             aFileName += ".png";
418         aSaveOp = "PNG";
419
420     if( !anImage.save( aFileName, aSaveOp ) )
421     {
422         SUIT_MessageBox::error1( this,
423                                  tr( "DUMP_VIEW_ERROR_DLG_CAPTION" ),
424                                  tr( "DUMP_VIEW_ERROR_DLG_TEXT" ),
425                                  tr( "BUT_OK" ) );
426     }
427 }
428
429 void GLViewer_ViewFrame::onViewPan()
430 {
431     myViewer->activateTransform( GLViewer_Viewer::Pan );
432 }
433
434 void GLViewer_ViewFrame::onViewZoom()
435 {
436     myViewer->activateTransform( GLViewer_Viewer::Zoom );
437 }
438
439 void GLViewer_ViewFrame::onViewFitAll()
440 {
441     myViewer->activateTransform( GLViewer_Viewer::FitAll );
442 }
443
444 void GLViewer_ViewFrame::onViewFitArea()
445
446     myViewer->activateTransform( GLViewer_Viewer::FitRect );
447 }
448
449 void GLViewer_ViewFrame::onViewFitSelect()
450
451     myViewer->activateTransform( GLViewer_Viewer::FitSelect );
452 }
453
454 void GLViewer_ViewFrame::onViewGlobalPan()
455
456     myViewer->activateTransform( GLViewer_Viewer::PanGlobal );
457 }
458
459 void GLViewer_ViewFrame::onViewRotate()
460
461     //myViewer->activateTransform( GLViewer_Viewer::Rotate );
462 }
463
464 void GLViewer_ViewFrame::onViewReset()
465
466     myViewer->activateTransform( GLViewer_Viewer::Reset );
467 }
468   
469 //================================================================
470 // Function : mouseEvent
471 // Purpose  : dispatches mouse events
472 //================================================================
473 void GLViewer_ViewFrame::mouseEvent( QMouseEvent* e )
474 {
475   switch ( e->type() )
476   {
477   case QEvent::MouseButtonPress:
478     emit mousePressed( this, e );
479     break;
480   case QEvent::MouseButtonRelease:
481     emit mouseReleased( this, e );
482     break;
483   case QEvent::MouseButtonDblClick:
484     emit mouseDoubleClicked( this, e );
485     break;
486   case QEvent::MouseMove:
487     emit mouseMoving( this, e );
488     break;
489   default:
490     break;
491   }
492 }
493
494 //================================================================
495 // Function : keyEvent
496 // Purpose  : dispatches key events
497 //================================================================
498 void GLViewer_ViewFrame::keyEvent( QKeyEvent* e )
499 {
500   switch ( e->type() )
501   {
502   case QEvent::KeyPress:
503     emit keyPressed( this, e );
504     break;
505   case QEvent::KeyRelease:
506     emit keyReleased( this, e );
507     break;
508   default:
509     break;
510   }
511 }
512
513 //================================================================
514 // Function : wheelEvent
515 // Purpose  : dispatches wheel events
516 //================================================================
517 void GLViewer_ViewFrame::wheelEvent( QWheelEvent* e )
518 {
519   switch ( e->type() )
520   {
521   case QEvent::Wheel:
522     emit wheeling( this, e );
523     break;
524   default:
525     break;
526   }
527 }