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