Salome HOME
06ac8a4a7550c5de46dd3e4ef9deade35f1ac8f4
[modules/gui.git] / src / OCCViewer / OCCViewer_ViewPort.cxx
1 // Copyright (C) 2007-2014  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 #if !defined WIN32
24 #define QT_CLEAN_NAMESPACE         /* avoid definition of INT32 and INT8 */
25 #endif
26
27 #include "OCCViewer_ViewPort.h"
28
29 #include "SUIT_Session.h"
30
31 #include <QColor>
32 #include <QRect>
33 #include <QPixmap>
34 #include <QPainter>
35 #include <QMultiHash>
36 #include <QMenu>
37 #include <QColorDialog>
38 #include <QColormap>
39 #include <QCoreApplication>
40
41 #include <stdlib.h>
42
43 #if !defined WIN32
44 #include <QX11Info>
45 #include <GL/glx.h>
46 #include <X11/Xlib.h>
47 #include <X11/Xutil.h>
48 #include <X11/Xatom.h>
49 #include <X11/Xmu/StdCmap.h>
50 #undef QT_CLEAN_NAMESPACE
51 #include <Xw_Window.hxx>
52
53 struct CMapEntry
54 {
55   CMapEntry();
56   ~CMapEntry();
57   Colormap          cmap;
58   bool              alloc;
59   XStandardColormap scmap;
60 };
61
62 /*!
63   Constructor
64 */
65 CMapEntry::CMapEntry()
66 {
67   cmap = 0;
68   alloc = false;
69   scmap.colormap = 0;
70 }
71
72 /*!
73   Destructor
74 */
75 CMapEntry::~CMapEntry()
76 {
77   if ( alloc )
78     XFreeColormap( QX11Info::display(), cmap );
79 }
80
81 static QMultiHash<int,CMapEntry> *cmap_dict = 0;
82 static bool mesa_gl = false;
83
84 static void cleanup_cmaps()
85 {
86   if ( !cmap_dict )
87     return;
88   //while (!cmap_dict->isEmpty())
89   //  cmap_dict->erase(cmap_dict->begin());
90   cmap_dict->clear();
91   delete cmap_dict;
92   cmap_dict = 0;
93 }
94
95 static Colormap choose_cmap( Display *dpy, XVisualInfo *vi )
96 {
97   if ( !cmap_dict )
98   {
99     cmap_dict = new QMultiHash<int,CMapEntry>;
100     const char *v = glXQueryServerString( dpy, vi->screen, GLX_VERSION );
101     mesa_gl = strstr( v,"Mesa" ) != 0;
102     qAddPostRoutine( cleanup_cmaps );
103   }
104
105   QHash<int,CMapEntry>::iterator itH = cmap_dict->find( (long)vi->visualid );
106   if ( itH != cmap_dict->end() )  // found colormap for visual
107     return itH.value().cmap;
108   
109   CMapEntry x;
110   
111   XStandardColormap *c;
112   int n, i;
113
114   //#ifdef DEBUG
115   //cout << "Choosing cmap for vID = " << vi->visualid << endl;
116   //#endif
117
118   if ( vi->visualid == XVisualIDFromVisual( (Visual*)QX11Info::appVisual() ) )
119   {
120 #ifdef DEBUG
121 //    cout << "Using x11AppColormap" << endl;
122 #endif
123     return QX11Info::appColormap();
124   }
125
126   if ( mesa_gl )
127   {
128     Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
129     if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 )
130     {
131       if ( XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen ), &c, &n, hp_cmaps ) )
132       {
133         i = 0;
134         while ( i < n && x.cmap == 0 )
135         {
136           if ( c[i].visualid == vi->visual->visualid )
137           {
138             x.cmap = c[i].colormap;
139             x.scmap = c[i];
140           }
141           i++;
142         }
143         XFree( (char*)c );
144       }
145     }
146   }
147 #if !defined( _OS_SOLARIS_ )
148   if ( !x.cmap )
149   {
150     if ( XmuLookupStandardColormap( dpy, vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP, false, true ) )
151     {
152       if ( XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen ), &c, &n, XA_RGB_DEFAULT_MAP ) )
153       {
154         i = 0;
155         while ( i < n && x.cmap == 0 )
156         {
157           if ( c[i].visualid == vi->visualid )
158           {
159             x.cmap = c[i].colormap;
160             x.scmap = c[i];
161           }
162           i++;
163         }
164         XFree( (char *)c );
165       }
166     }
167   }
168 #endif
169   if ( !x.cmap )
170   {
171     // no shared cmap found
172     x.cmap = XCreateColormap( dpy, RootWindow( dpy, vi->screen ), vi->visual, AllocNone );
173     x.alloc = true;
174   }
175
176   cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
177   return x.cmap;
178 }
179 #endif
180
181
182 /*!
183     Constructor
184 */
185 OCCViewer_ViewPort::OCCViewer_ViewPort( QWidget* parent )
186 : QWidget( parent )
187 {
188   initialize();
189 }
190
191 /*!
192     Destructor
193 */
194 OCCViewer_ViewPort::~OCCViewer_ViewPort()
195 {
196   cleanup();
197 }
198
199 /*!
200     Initializes viewport. [ private ]
201 */
202 void OCCViewer_ViewPort::initialize()
203 {
204   myPaintersRedrawing = false;
205   myEnableSketching = true;
206   myEnableTransform = true;
207   
208   setMouseTracking( true );
209   setBackgroundRole( QPalette::NoRole );//NoBackground );
210   // set focus policy to threat QContextMenuEvent from keyboard  
211   setFocusPolicy( Qt::StrongFocus );
212   setAttribute( Qt::WA_PaintOnScreen );
213   setAttribute( Qt::WA_NoSystemBackground );
214 }
215
216 /*!
217     Cleans up the viewport. [ private ]
218 */
219 void OCCViewer_ViewPort::cleanup()
220 {
221 }
222
223 /*!
224     Selects visual ID for OpenGL window ( X11 specific ). [ protected ]
225 */
226 void OCCViewer_ViewPort::selectVisualId()
227 {
228 #if !defined WIN32
229   XVisualInfo* pVisualInfo;
230   if ( QX11Info::display() )
231   {
232     /* Initialization with the default VisualID */
233     Visual *v = DefaultVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
234     /*int visualID = */XVisualIDFromVisual( v );
235     
236     /*  Here we use the settings from Optimizer_ViewInfo::TxglCreateWindow() */
237     int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
238                           GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, None };
239     
240     pVisualInfo = ::glXChooseVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ), visualAttr );
241     
242     if ( isVisible() )
243       hide();
244     
245     XSetWindowAttributes a;
246     
247     a.colormap = choose_cmap( QX11Info::display(), pVisualInfo );       /* find best colormap */
248     a.background_pixel = QColormap::instance().pixel( backgroundColor() );
249     a.border_pixel = QColormap::instance().pixel( Qt::black );
250     Window p = RootWindow( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
251     if ( parentWidget() )
252       p = parentWidget()->winId();
253     
254     Window w;
255     /*
256     if ( type == Type2D )  // creating simple X window for 2d
257     {
258       unsigned long xbackground =
259           BlackPixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
260       unsigned long xforeground =
261           WhitePixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
262
263       w = XCreateSimpleWindow ( QX11Info::display(), p, x(), y(), width(),
264                                 height(), 0, xforeground, xbackground );
265     }
266     else if ( type == Type3D )
267     {
268       w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
269                           0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
270                           CWBackPixel | CWBorderPixel | CWColormap, &a );
271     }
272     else
273       return;
274     */
275     w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
276                       0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
277                       CWBackPixel | CWBorderPixel | CWColormap, &a );
278   
279     Window *cmw;
280     Window *cmwret;
281     int count;
282     if ( XGetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), &cmwret, &count ) )
283     {
284       cmw = new Window[count+1];
285       memcpy( (char*)cmw, (char*)cmwret, sizeof(Window) * count );
286       XFree( (char*)cmwret );
287       int i;
288
289       for ( i = 0; i < count; i++ )
290       {
291         if ( cmw[i] == winId() ) /* replace old window */
292         {
293           cmw[i] = w;
294           break;
295         }
296       }
297
298       if ( i >= count )                        /* append new window */
299         cmw[count++] = w;
300     }
301     else
302     {
303       count = 1;
304       cmw = new Window[count];
305       cmw[0] = w;
306     }
307
308     /* Creating new window (with good VisualID) for this widget */
309     create(w);
310     XSetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), cmw, count );
311     delete[] cmw;
312
313     if ( isVisible() )
314       show();
315
316     if ( pVisualInfo )
317       XFree( (char *)pVisualInfo );
318
319     XFlush( QX11Info::display() );
320   }
321 #endif
322 }
323
324 /*!
325     Sets the background 'color'. [ virtual ]
326 */
327 void OCCViewer_ViewPort::setBackgroundColor( const QColor& color )
328 {
329   QPalette pal = palette();
330   pal.setColor( QPalette::Background, color );
331   setPalette( pal );
332   repaint();
333   emit vpChangeBGColor( color );
334 }
335
336 /*!
337     Returns the background color. [ virtual ]
338 */
339 QColor OCCViewer_ViewPort::backgroundColor() const
340 {
341   return palette().color( QPalette::Active, QPalette::Background );
342 }
343
344 /*!
345     Returns 'true' if sketching is enabled in  this viewport. [ public ]
346 */
347 bool OCCViewer_ViewPort::isSketchingEnabled() const
348 {
349   return myEnableSketching;
350 }
351
352 /*!
353     Enables / disables sketching  [ public ]
354 */
355 void OCCViewer_ViewPort::setSketchingEnabled( bool enable )
356 {
357   myEnableSketching = enable;
358 }
359
360 /*!
361     Returns 'true' if transformations ( rotation, zoom etc. )
362     are enabled in this viewport. [ public ]
363 */
364 bool OCCViewer_ViewPort::isTransformEnabled() const
365 {
366   return myEnableTransform;
367 }
368
369 /*!
370     Enables / disables transformations. [ public ]
371 */
372 void OCCViewer_ViewPort::setTransformEnabled( bool enable )
373 {
374   myEnableTransform = enable;
375 }
376
377 /*!
378     Emits 'mouseEvent' signal. [ virtual protected ]
379 */
380 void OCCViewer_ViewPort::mousePressEvent( QMouseEvent *e )
381 {
382     emit vpMouseEvent( e );
383 }
384
385 /*!
386     Emits 'mouseEvent' signal. [ virtual protected ]
387 */
388 void OCCViewer_ViewPort::mouseMoveEvent( QMouseEvent* e )
389 {
390   emit vpMouseEvent( e );
391 }
392
393 /*!
394     Emits 'mouseEvent' signal. [ virtual protected ]
395 */
396 void OCCViewer_ViewPort::mouseReleaseEvent( QMouseEvent *e )
397 {
398   emit vpMouseEvent( e );
399 }
400
401 /*!
402     Emits 'mouseEvent' signal. [ virtual protected ]
403 */
404 void OCCViewer_ViewPort::mouseDoubleClickEvent( QMouseEvent *e )
405 {
406   emit vpMouseEvent( e );
407 }
408
409 /*!
410     Emits 'keyEvent' signal. [ virtual protected ]
411 */
412 void OCCViewer_ViewPort::keyPressEvent( QKeyEvent *e )
413 {
414   emit vpKeyEvent( e );
415 }
416
417 /*!
418     Emits 'keyEvent' signal. [ virtual protected ]
419 */
420 void OCCViewer_ViewPort::keyReleaseEvent( QKeyEvent *e )
421 {
422   emit vpKeyEvent( e );
423 }
424
425 /*!
426     Repaints the viewport. [ virtual protected ]
427 */
428 void OCCViewer_ViewPort::paintEvent( QPaintEvent* )
429 {
430   if ( myPaintersRedrawing )
431   {
432     QPainter p( this );
433     emit vpDrawExternal( &p );
434     myPaintersRedrawing = false;
435   }
436 }
437
438 /*!
439     Forces to redraw the viewport by an external painter. [ public ]
440 */
441 void OCCViewer_ViewPort::redrawPainters()
442 {
443   myPaintersRedrawing = true;
444   repaint();
445 }
446
447 /*!
448     Updates this view. Does nothing by default. [ virtual public ]
449 */
450 void OCCViewer_ViewPort::onUpdate()
451 {
452 }
453
454 /*!
455   Get paint engine for the OpenGL viewer. [ virtual public ]
456 */
457 QPaintEngine* OCCViewer_ViewPort::paintEngine() const
458 {
459   return 0;
460 }
461
462 /*!
463     Creates the popup. [ virtual protected ]
464 */
465 /*void OCCViewer_ViewPort::onCreatePopup( QPopupMenu* popup )
466 {
467   if ( popup )
468   {
469     QtxAction* a = new QtxAction( "", tr( "MEN_VP_CHANGEBGR" ), 0, this );
470     a->setStatusTip( tr( "PRP_VP_CHANGEBGR" ) );
471     connect( a, SIGNAL( activated() ), SLOT( onChangeBgColor()));
472     myPopupActions.append( a );
473     a->addTo( popup );
474   }
475 }*/
476
477 /*!
478     Destroys the popup. [ virtual protected ]
479 */
480 /*void OCCViewer_ViewPort::onDestroyPopup( QPopupMenu* popup )
481 {
482   if ( popup )
483   {
484     for ( QtxAction* a = myPopupActions.first(); a; a = myPopupActions.next() )
485       a->removeFrom( popup );
486     //while (!myPopupActions.isEmpty())
487     //  delete myPopupActions.takeFirst();
488     myPopupActions.clear();
489   }
490 }*/
491
492 /*!
493   Performs synchronization of view parameters with the specified view.
494   Returns \c true if synchronization is done successfully or \c false otherwise.
495   Default implementation does nothing (return \c false)
496 */
497 bool OCCViewer_ViewPort::synchronize( OCCViewer_ViewPort* )
498 {
499   return false;
500 }
501
502 /*!
503     Sets the background color with color selection dialog. [ virtual protected slot ]
504 */
505 void OCCViewer_ViewPort::onChangeBackground()
506 {
507   QColor selColor = QColorDialog::getColor ( backgroundColor(), this );
508   if ( selColor.isValid() )
509     setBackgroundColor( selColor );
510 }