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