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