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