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