Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/gui.git] / src / GLViewer / GLViewer_ViewPort.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  Author : OPEN CASCADE
24 // File:      GLViewer_ViewPort.cxx
25 // Created:   November, 2004
26 //#include <GLViewerAfx.h>
27 //
28 #include "GLViewer_ViewPort.h"
29
30 #include "SUIT_ResourceMgr.h"
31 #include "SUIT_Session.h"
32
33 #include <QRect>
34 #include <QCursor>
35 #include <QPainter>
36 #include <QMultiHash>
37 //#include <QMenu>
38 #include <QColorDialog>
39 #include <QColormap>
40 #include <QMouseEvent>
41 #include <QCoreApplication>
42
43 #include <stdlib.h>
44
45 #if !defined WIN32
46 #include <QX11Info>
47 #include <GL/glx.h>
48 #include <X11/Xlib.h>
49 #include <X11/Xutil.h>
50 #include <X11/Xatom.h>
51 #include <X11/Xmu/StdCmap.h>
52 #undef QT_CLEAN_NAMESPACE
53 #include <Xw_Window.hxx>
54 #include <Graphic3d_GraphicDevice.hxx>
55
56 /*!
57   \struct CMapEntry
58   Map of indexed colors
59   For internal purposes
60 */
61 struct CMapEntry
62 {
63     CMapEntry();
64     ~CMapEntry();
65     Colormap          cmap;
66     bool              alloc;
67     XStandardColormap scmap;
68 };
69
70 /*!
71   Constructor
72 */
73 CMapEntry::CMapEntry()
74 {
75     cmap = 0;
76     alloc = false;
77     scmap.colormap = 0;
78 }
79
80 /*!
81   Destructor
82 */
83 CMapEntry::~CMapEntry()
84 {
85     if ( alloc )
86         XFreeColormap( QX11Info::display(), cmap );
87 }
88
89 static QMultiHash<int,CMapEntry> *cmap_dict = 0;
90 static bool mesa_gl = false;
91
92 static void cleanup_cmaps()
93 {
94     if ( !cmap_dict )
95         return;
96     //while (!cmap_dict->isEmpty())
97     //  cmap_dict->erase(cmap_dict->begin());
98     cmap_dict->clear();
99     delete cmap_dict;
100     cmap_dict = 0;
101 }
102
103 static Colormap choose_cmap( Display *dpy, XVisualInfo *vi )
104 {
105     if ( !cmap_dict )
106     {
107         cmap_dict = new QMultiHash<int,CMapEntry>;
108         const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION );
109         mesa_gl = strstr( v,"Mesa" ) != 0;
110         qAddPostRoutine( cleanup_cmaps );
111     }
112
113     QHash<int,CMapEntry>::iterator itH = cmap_dict->find( (long)vi->visualid );
114     if ( itH != cmap_dict->end() )  // found colormap for visual
115         return itH.value().cmap;
116
117     CMapEntry x;
118
119     XStandardColormap *c;
120     int n, i;
121
122 #ifdef DEBUG
123     cout << "Choosing cmap for vID = " << vi->visualid << endl;
124 #endif
125
126     if ( vi->visualid == XVisualIDFromVisual( (Visual*)QX11Info::appVisual() ) )
127     {
128 #ifdef DEBUG
129         cout << "Using x11AppColormap" << endl;
130 #endif
131         return QX11Info::appColormap();
132     }
133
134     if ( mesa_gl )
135     {
136         Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
137         if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 )
138         {
139             if ( XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen ), &c, &n, hp_cmaps ) )
140             {
141                 i = 0;
142                 while ( i < n && x.cmap == 0 )
143                 {
144                     if ( c[i].visualid == vi->visual->visualid )
145                     {
146                         x.cmap = c[i].colormap;
147                         x.scmap = c[i];
148                     }
149                     i++;
150                 }
151                 XFree( (char*)c );
152             }
153         }
154     }
155 #if !defined( _OS_SOLARIS_ )
156     if ( !x.cmap )
157     {
158         if ( XmuLookupStandardColormap( dpy, vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP, false, true ) )
159         {
160             if ( XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen ), &c, &n, XA_RGB_DEFAULT_MAP ) )
161             {
162                 i = 0;
163                 while ( i < n && x.cmap == 0 )
164                 {
165                     if ( c[i].visualid == vi->visualid )
166                     {
167                         x.cmap = c[i].colormap;
168                         x.scmap = c[i];
169                     }
170                     i++;
171                 }
172                 XFree( (char *)c );
173             }
174         }
175     }
176 #endif
177     if ( !x.cmap )
178     {
179         // no shared cmap found
180         x.cmap = XCreateColormap( dpy, RootWindow( dpy, vi->screen ), vi->visual, AllocNone );
181         x.alloc = true;
182     }
183
184     cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
185     return x.cmap;
186 }
187 #endif
188
189 int GLViewer_ViewPort::nCounter = 0;
190 QCursor* GLViewer_ViewPort::defCursor = 0;
191 QCursor* GLViewer_ViewPort::panglCursor = 0;
192 QCursor* GLViewer_ViewPort::handCursor = 0;
193 QCursor* GLViewer_ViewPort::panCursor = 0;
194 QCursor* GLViewer_ViewPort::zoomCursor = 0;
195 QCursor* GLViewer_ViewPort::rotCursor = 0;
196 QCursor* GLViewer_ViewPort::sketchCursor = 0;
197
198 /*!
199     Creates the necessary viewport cursors. [ static ]
200 */
201 void GLViewer_ViewPort::createCursors ()
202 {
203     defCursor   = new QCursor( Qt::ArrowCursor );
204     panglCursor = new QCursor( Qt::CrossCursor );
205     handCursor  = new QCursor( Qt::PointingHandCursor );
206     panCursor   = new QCursor( Qt::SizeAllCursor );
207
208     SUIT_ResourceMgr* rmgr = SUIT_Session::session()->resourceMgr();
209     zoomCursor   = new QCursor( rmgr->loadPixmap( "GLViewer", tr( "ICON_GL_CURSOR_ZOOM" ) ) );
210     rotCursor    = new QCursor( rmgr->loadPixmap( "GLViewer", tr( "ICON_GL_CURSOR_ROTATE" ) ) );
211     sketchCursor = new QCursor( rmgr->loadPixmap( "GLViewer", tr( "ICON_GL_CURSOR_SKETCH" ) ) );
212 }
213
214 /*!
215     Destroys the viewport cursors. [ static ]
216 */
217 void GLViewer_ViewPort::destroyCursors()
218 {
219     delete defCursor;   defCursor   = 0;
220     delete panglCursor; panglCursor = 0;
221     delete handCursor;  handCursor  = 0;
222     delete panCursor;   panCursor   = 0;
223     delete zoomCursor;  zoomCursor  = 0;
224     delete rotCursor;   rotCursor   = 0;
225     delete sketchCursor; sketchCursor = 0;
226 }
227
228 /*!
229     Sets new default cursor. [ static ]
230 */
231 void GLViewer_ViewPort::setDefaultCursor( const QCursor& newCursor )
232 {
233     if ( !defCursor )
234         defCursor = new QCursor();
235     *defCursor = newCursor;
236 }
237
238 /*!
239     Sets new cursor for drawing rectangle in the viewport. [ static ]
240 */
241 void GLViewer_ViewPort::setHandCursor( const QCursor& newCursor )
242 {
243     if ( !handCursor )
244         handCursor = new QCursor();
245     *handCursor = newCursor;
246 }
247
248 /*!
249     Sets new cursor for panning. [ static ]
250 */
251 void GLViewer_ViewPort::setPanCursor( const QCursor& newCursor )
252 {
253     if ( !panCursor )
254         panCursor = new QCursor();
255     *panCursor = newCursor;
256 }
257
258 /*!
259     Sets new cursor for global panning. [ static ]
260 */
261 void GLViewer_ViewPort::setPanglCursor( const QCursor& newCursor )
262 {
263     if ( !panglCursor )
264         panglCursor = new QCursor();
265     *panglCursor = newCursor;
266 }
267
268 /*!
269     Sets new cursor for zooming. [ static ]
270 */
271 void GLViewer_ViewPort::setZoomCursor( const QCursor& newCursor )
272 {
273     if ( !zoomCursor )
274         zoomCursor = new QCursor();
275     *zoomCursor = newCursor;
276 }
277
278 /*!
279     Sets new cursor for rotating. [ static ]
280 */
281 void GLViewer_ViewPort::setRotCursor( const QCursor& newCursor )
282 {
283     if ( !rotCursor )
284         rotCursor = new QCursor();
285     *rotCursor = newCursor;
286 }
287
288 /*!
289     Sets new cursor for rotating. [ static ]
290 */
291 void GLViewer_ViewPort::setSketchCursor( const QCursor& newCursor )
292 {
293     if ( !rotCursor )
294         sketchCursor = new QCursor();
295     *sketchCursor = newCursor;
296 }
297
298 /*!
299     Constructor
300 */
301 GLViewer_ViewPort::GLViewer_ViewPort( QWidget* parent )
302 : QWidget( parent, 0 )
303 {
304     initialize();
305 }
306
307 /*!
308     Destructor
309 */
310 GLViewer_ViewPort::~GLViewer_ViewPort()
311 {
312     cleanup();
313 }
314
315 /*!
316     Initializes viewport. [ private ]
317 */
318 void GLViewer_ViewPort::initialize()
319 {
320     if ( nCounter++ == 0 )
321         createCursors();
322
323     //myPopupActions.setAutoDelete( true );
324     myPaintersRedrawing = false;
325     myEnableSketching = false;
326     myEnableTransform = true;
327
328     setMouseTracking( true );
329     setBackgroundRole( QPalette::NoRole );//NoBackground );
330
331     setFocusPolicy( Qt::StrongFocus );
332 }
333
334 /*!
335     Cleans up the viewport. [ private ]
336 */
337 void GLViewer_ViewPort::cleanup()
338 {
339     if ( --nCounter == 0 )
340         destroyCursors();
341 }
342
343 /*!
344     Selects visual ID for OpenGL window ( X11 specific ). [ protected ]
345 */
346 void GLViewer_ViewPort::selectVisualId( ViewType type )
347 {
348 #if !defined WIN32
349     XVisualInfo* pVisualInfo;
350     if ( QX11Info::display() )
351     {
352         /* Initialization with the default VisualID */
353         //Visual *v = DefaultVisual( x11Display(), DefaultScreen( x11Display() ) );
354         // int visualID = XVisualIDFromVisual( v ); unused
355
356         /*  Here we use the settings from Optimizer_ViewInfo::TxglCreateWindow() */
357         int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
358                              GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, None };
359
360         pVisualInfo = ::glXChooseVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ), visualAttr );
361
362         if ( isVisible() )
363             hide();
364
365         XSetWindowAttributes a;
366
367         a.colormap = choose_cmap( QX11Info::display(), pVisualInfo );      /* find best colormap */
368         a.background_pixel = QColormap::instance().pixel( backgroundColor() );
369         a.border_pixel = QColormap::instance().pixel( Qt::black );
370         Window p = RootWindow( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
371         if ( parentWidget() )
372             p = parentWidget()->winId();
373
374         Window w;
375         if ( type == Type2D )  // creating simple X window for 2d
376         {
377             unsigned long xbackground =
378                 BlackPixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
379             unsigned long xforeground =
380                 WhitePixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
381
382             w = XCreateSimpleWindow ( QX11Info::display(), p, x(), y(), width(),
383                                       height(), 0, xforeground, xbackground );
384         }
385         else if ( type == Type3D )
386         {
387             w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
388                                0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
389                                CWBackPixel | CWBorderPixel | CWColormap, &a );
390         }
391         else
392             return;
393
394         Window *cmw;
395         Window *cmwret;
396         int count;
397         if ( XGetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), &cmwret, &count ) )
398         {
399             cmw = new Window[count+1];
400             memcpy( (char*)cmw, (char*)cmwret, sizeof(Window) * count );
401             XFree( (char*)cmwret );
402             int i;
403
404             for ( i = 0; i < count; i++ )
405             {
406                 if ( cmw[i] == winId() ) /* replace old window */
407                 {
408                     cmw[i] = w;
409                     break;
410                 }
411             }
412
413             if ( i >= count )            /* append new window */
414                 cmw[count++] = w;
415         }
416         else
417         {
418             count = 1;
419             cmw = new Window[count];
420             cmw[0] = w;
421         }
422
423         /* Creating new window (with good VisualID) for this widget */
424         create(w);
425         XSetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), cmw, count );
426         delete[] cmw;
427
428         if ( isVisible() )
429             show();
430
431         if ( pVisualInfo )
432         {
433             XFree( (char *)pVisualInfo );
434         }
435         XFlush( QX11Info::display() );
436     }
437 #endif
438 }
439
440 /*!
441     Sets the background 'color'. [ virtual ]
442 */
443 void GLViewer_ViewPort::setBackgroundColor( const QColor& color )
444 {
445     QPalette pal = palette();
446     pal.setColor( QPalette::Background, color );
447     setPalette( pal );
448     repaint();
449 }
450
451 /*!
452     Returns the background color. [ virtual ]
453 */
454 QColor GLViewer_ViewPort::backgroundColor() const
455 {
456     return palette().color( QPalette::Active, QPalette::Background );
457 }
458
459 /*!
460     Returns 'true' if sketching is enabled in  this viewport. [ public ]
461 */
462 bool GLViewer_ViewPort::isSketchingEnabled() const
463 {
464     return myEnableSketching;
465 }
466
467 /*!
468     Enables / disables sketching  [ public ]
469 */
470 void GLViewer_ViewPort::setSketchingEnabled( bool enable )
471 {
472     myEnableSketching = enable;
473 }
474
475 /*!
476     Returns 'true' if transformations ( rotation, zoom etc. )
477     are enabled in this viewport. [ public ]
478 */
479 bool GLViewer_ViewPort::isTransformEnabled() const
480 {
481     return myEnableTransform;
482 }
483
484 /*!
485     Enables / disables transformations. [ public ]
486 */
487 void GLViewer_ViewPort::setTransformEnabled( bool enable )
488 {
489     myEnableTransform = enable;
490 }
491
492 /*!
493     Emits 'mouseEvent' signal. [ virtual protected ]
494 */
495 void GLViewer_ViewPort::mousePressEvent( QMouseEvent *e )
496 {
497     emit vpMouseEvent( e );
498 }
499
500 /*!
501     Emits 'mouseEvent' signal. [ virtual protected ]
502 */
503 void GLViewer_ViewPort::mouseMoveEvent( QMouseEvent* e )
504 {
505     emit vpMouseEvent( e );
506 }
507
508 /*!
509     Emits 'mouseEvent' signal. [ virtual protected ]
510 */
511 void GLViewer_ViewPort::mouseReleaseEvent( QMouseEvent *e )
512 {
513     emit vpMouseEvent( e );
514
515     /* show popup menu */
516     if ( e->button() == Qt::RightButton )
517     {
518         //QPopupMenu* popup = createPopup();
519         //if ( popup && popup->count() )
520         //    popup->exec( QCursor::pos() );
521         //destroyPopup( /*popup*/ );
522     }
523 }
524
525 /*!
526     Emits 'mouseEvent' signal. [ virtual protected ]
527 */
528 void GLViewer_ViewPort::mouseDoubleClickEvent( QMouseEvent *e )
529 {
530     emit vpMouseEvent( e );
531 }
532
533 /*!
534     Emits 'keyEvent' signal. [ virtual protected ]
535 */
536 void GLViewer_ViewPort::keyPressEvent( QKeyEvent *e )
537 {
538     emit vpKeyEvent( e );
539 }
540
541 /*!
542     Emits 'keyEvent' signal. [ virtual protected ]
543 */
544 void GLViewer_ViewPort::keyReleaseEvent( QKeyEvent *e )
545 {
546     emit vpKeyEvent( e );
547 }
548
549 /*!
550     Emits 'mouseEvent' signal. [ virtual protected ]
551 */
552 void GLViewer_ViewPort::wheelEvent( QWheelEvent *e )
553 {
554     emit vpWheelEvent( e );
555 }
556
557 /*!
558     Repaints the viewport. [ virtual protected ]
559 */
560 void GLViewer_ViewPort::paintEvent( QPaintEvent* )
561 {
562     if ( myPaintersRedrawing )
563     {
564         QPainter p( this );
565         emit vpDrawExternal( &p );
566         myPaintersRedrawing = false;
567     }
568 }
569
570 /*!
571     Forces to redraw the viewport by an external painter. [ public ]
572 */
573 void GLViewer_ViewPort::redrawPainters()
574 {
575     myPaintersRedrawing = true;
576     repaint();
577 }
578
579 /*!
580     Updates this view. Does nothing by default. [ virtual public ]
581 */
582 void GLViewer_ViewPort::onUpdate()
583 {
584 }
585
586 /*!
587     Sets the background color with color selection dialog. [ virtual protected slot ]
588 */
589 void GLViewer_ViewPort::onChangeBgColor()
590 {
591     QColor selColor = QColorDialog::getColor ( backgroundColor(), this );
592     if ( selColor.isValid() )
593         setBackgroundColor( selColor );
594 }
595
596 /*!
597   Custom context menu event handler
598 */
599 void GLViewer_ViewPort::contextMenuEvent( QContextMenuEvent* e )
600 {
601   //if ( e->reason() != QContextMenuEvent::Mouse )
602     emit contextMenuRequested( e );
603 }