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