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