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