Salome HOME
Qt 5 migration: correction of bugs
[modules/gui.git] / src / OCCViewer / OCCViewer_ViewPort.cxx
1 // Copyright (C) 2007-2015  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 QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
119   if ( vi->visualid == XVisualIDFromVisual( (Visual*)QX11Info::appVisual() ) )
120   {
121 #ifdef DEBUG
122 //    cout << "Using x11AppColormap" << endl;
123 #endif
124     return QX11Info::appColormap();
125   }
126 #else
127   if ( vi->visualid == XVisualIDFromVisual( XDefaultVisual( QX11Info::display(), -1 ) ) )
128   {
129 #ifdef DEBUG
130 //    cout << "Using XDefaultColormap" << endl;
131 #endif
132     return XDefaultColormap( QX11Info::display(), -1 );
133   }
134 #endif
135   if ( mesa_gl )
136   {
137     Atom hp_cmaps = XInternAtom( dpy, "_HP_RGB_SMOOTH_MAP_LIST", true );
138     if ( hp_cmaps && vi->visual->c_class == TrueColor && vi->depth == 8 )
139     {
140       if ( XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen ), &c, &n, hp_cmaps ) )
141       {
142         i = 0;
143         while ( i < n && x.cmap == 0 )
144         {
145           if ( c[i].visualid == vi->visual->visualid )
146           {
147             x.cmap = c[i].colormap;
148             x.scmap = c[i];
149           }
150           i++;
151         }
152         XFree( (char*)c );
153       }
154     }
155   }
156 #if !defined( _OS_SOLARIS_ )
157   if ( !x.cmap )
158   {
159     if ( XmuLookupStandardColormap( dpy, vi->screen, vi->visualid, vi->depth, XA_RGB_DEFAULT_MAP, false, true ) )
160     {
161       if ( XGetRGBColormaps( dpy, RootWindow( dpy, vi->screen ), &c, &n, XA_RGB_DEFAULT_MAP ) )
162       {
163         i = 0;
164         while ( i < n && x.cmap == 0 )
165         {
166           if ( c[i].visualid == vi->visualid )
167           {
168             x.cmap = c[i].colormap;
169             x.scmap = c[i];
170           }
171           i++;
172         }
173         XFree( (char *)c );
174       }
175     }
176   }
177 #endif
178   if ( !x.cmap )
179   {
180     // no shared cmap found
181     x.cmap = XCreateColormap( dpy, RootWindow( dpy, vi->screen ), vi->visual, AllocNone );
182     x.alloc = true;
183   }
184
185   cmap_dict->insert( (long)vi->visualid, x ); // associate cmap with visualid
186   return x.cmap;
187 }
188 #endif
189
190
191 /*!
192     Constructor
193 */
194 OCCViewer_ViewPort::OCCViewer_ViewPort( QWidget* parent )
195 : QWidget( parent )
196 {
197   initialize();
198 }
199
200 /*!
201     Destructor
202 */
203 OCCViewer_ViewPort::~OCCViewer_ViewPort()
204 {
205   cleanup();
206 }
207
208 /*!
209     Initializes viewport. [ private ]
210 */
211 void OCCViewer_ViewPort::initialize()
212 {
213   myPaintersRedrawing = false;
214   myEnableSketching = true;
215   myEnableTransform = true;
216   
217   setMouseTracking( true );
218   setBackgroundRole( QPalette::NoRole );//NoBackground );
219   // set focus policy to threat QContextMenuEvent from keyboard  
220   setFocusPolicy( Qt::StrongFocus );
221   setAttribute( Qt::WA_PaintOnScreen );
222   setAttribute( Qt::WA_NoSystemBackground );
223 }
224
225 /*!
226     Cleans up the viewport. [ private ]
227 */
228 void OCCViewer_ViewPort::cleanup()
229 {
230 }
231
232 /*!
233     Selects visual ID for OpenGL window ( X11 specific ). [ protected ]
234 */
235 void OCCViewer_ViewPort::selectVisualId()
236 {
237 #if !defined WIN32
238   XVisualInfo* pVisualInfo;
239   if ( QX11Info::display() )
240   {
241     /* Initialization with the default VisualID */
242     Visual *v = DefaultVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
243     /*int visualID = */XVisualIDFromVisual( v );
244     
245     /*  Here we use the settings from Optimizer_ViewInfo::TxglCreateWindow() */
246     int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
247                           GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, None };
248     
249     pVisualInfo = ::glXChooseVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ), visualAttr );
250     
251     if ( isVisible() )
252       hide();
253     
254     XSetWindowAttributes a;
255     
256     a.colormap = choose_cmap( QX11Info::display(), pVisualInfo );       /* find best colormap */
257     a.background_pixel = QColormap::instance().pixel( backgroundColor() );
258     a.border_pixel = QColormap::instance().pixel( Qt::black );
259     Window p = RootWindow( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
260     if ( parentWidget() )
261       p = parentWidget()->winId();
262     
263     Window w;
264     /*
265     if ( type == Type2D )  // creating simple X window for 2d
266     {
267       unsigned long xbackground =
268           BlackPixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
269       unsigned long xforeground =
270           WhitePixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
271
272       w = XCreateSimpleWindow ( QX11Info::display(), p, x(), y(), width(),
273                                 height(), 0, xforeground, xbackground );
274     }
275     else if ( type == Type3D )
276     {
277       w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
278                           0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
279                           CWBackPixel | CWBorderPixel | CWColormap, &a );
280     }
281     else
282       return;
283     */
284     w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
285                       0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
286                       CWBackPixel | CWBorderPixel | CWColormap, &a );
287   
288     Window *cmw;
289     Window *cmwret;
290     int count;
291     if ( XGetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), &cmwret, &count ) )
292     {
293       cmw = new Window[count+1];
294       memcpy( (char*)cmw, (char*)cmwret, sizeof(Window) * count );
295       XFree( (char*)cmwret );
296       int i;
297
298       for ( i = 0; i < count; i++ )
299       {
300         if ( cmw[i] == winId() ) /* replace old window */
301         {
302           cmw[i] = w;
303           break;
304         }
305       }
306
307       if ( i >= count )                        /* append new window */
308         cmw[count++] = w;
309     }
310     else
311     {
312       count = 1;
313       cmw = new Window[count];
314       cmw[0] = w;
315     }
316
317     /* Creating new window (with good VisualID) for this widget */
318     create(w);
319     XSetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), cmw, count );
320     delete[] cmw;
321
322     if ( isVisible() )
323       show();
324
325     if ( pVisualInfo )
326       XFree( (char *)pVisualInfo );
327
328     XFlush( QX11Info::display() );
329   }
330 #endif
331 }
332
333 /*!
334     Sets the background 'color'. [ virtual ]
335 */
336 void OCCViewer_ViewPort::setBackgroundColor( const QColor& color )
337 {
338   QPalette pal = palette();
339   pal.setColor( QPalette::Background, color );
340   setPalette( pal );
341   repaint();
342   emit vpChangeBGColor( color );
343 }
344
345 /*!
346     Returns the background color. [ virtual ]
347 */
348 QColor OCCViewer_ViewPort::backgroundColor() const
349 {
350   return palette().color( QPalette::Active, QPalette::Background );
351 }
352
353 /*!
354     Returns 'true' if sketching is enabled in  this viewport. [ public ]
355 */
356 bool OCCViewer_ViewPort::isSketchingEnabled() const
357 {
358   return myEnableSketching;
359 }
360
361 /*!
362     Enables / disables sketching  [ public ]
363 */
364 void OCCViewer_ViewPort::setSketchingEnabled( bool enable )
365 {
366   myEnableSketching = enable;
367 }
368
369 /*!
370     Returns 'true' if transformations ( rotation, zoom etc. )
371     are enabled in this viewport. [ public ]
372 */
373 bool OCCViewer_ViewPort::isTransformEnabled() const
374 {
375   return myEnableTransform;
376 }
377
378 /*!
379     Enables / disables transformations. [ public ]
380 */
381 void OCCViewer_ViewPort::setTransformEnabled( bool enable )
382 {
383   myEnableTransform = enable;
384 }
385
386 /*!
387     Emits 'mouseEvent' signal. [ virtual protected ]
388 */
389 void OCCViewer_ViewPort::mousePressEvent( QMouseEvent *e )
390 {
391     emit vpMouseEvent( e );
392 }
393
394 /*!
395     Emits 'mouseEvent' signal. [ virtual protected ]
396 */
397 void OCCViewer_ViewPort::mouseMoveEvent( QMouseEvent* e )
398 {
399   emit vpMouseEvent( e );
400 }
401
402 /*!
403     Emits 'mouseEvent' signal. [ virtual protected ]
404 */
405 void OCCViewer_ViewPort::mouseReleaseEvent( QMouseEvent *e )
406 {
407   emit vpMouseEvent( e );
408 }
409
410 /*!
411     Emits 'mouseEvent' signal. [ virtual protected ]
412 */
413 void OCCViewer_ViewPort::mouseDoubleClickEvent( QMouseEvent *e )
414 {
415   emit vpMouseEvent( e );
416 }
417
418 /*!
419     Emits 'keyEvent' signal. [ virtual protected ]
420 */
421 void OCCViewer_ViewPort::keyPressEvent( QKeyEvent *e )
422 {
423   emit vpKeyEvent( e );
424 }
425
426 /*!
427     Emits 'keyEvent' signal. [ virtual protected ]
428 */
429 void OCCViewer_ViewPort::keyReleaseEvent( QKeyEvent *e )
430 {
431   emit vpKeyEvent( e );
432 }
433
434 /*!
435     Repaints the viewport. [ virtual protected ]
436 */
437 void OCCViewer_ViewPort::paintEvent( QPaintEvent* )
438 {
439   if ( myPaintersRedrawing )
440   {
441     QPainter p( this );
442     emit vpDrawExternal( &p );
443     myPaintersRedrawing = false;
444   }
445 }
446
447 /*!
448     Forces to redraw the viewport by an external painter. [ public ]
449 */
450 void OCCViewer_ViewPort::redrawPainters()
451 {
452   myPaintersRedrawing = true;
453   repaint();
454 }
455
456 /*!
457     Updates this view. Does nothing by default. [ virtual public ]
458 */
459 void OCCViewer_ViewPort::onUpdate()
460 {
461 }
462
463 /*!
464   Get paint engine for the OpenGL viewer. [ virtual public ]
465 */
466 QPaintEngine* OCCViewer_ViewPort::paintEngine() const
467 {
468   return 0;
469 }
470
471 /*!
472   Performs synchronization of view parameters with the specified view.
473   Returns \c true if synchronization is done successfully or \c false otherwise.
474   Default implementation does nothing (return \c false)
475 */
476 bool OCCViewer_ViewPort::synchronize( OCCViewer_ViewPort* )
477 {
478   return false;
479 }
480
481 /*!
482     Sets the background color with color selection dialog. [ virtual protected slot ]
483 */
484 void OCCViewer_ViewPort::onChangeBackground()
485 {
486   QColor selColor = QColorDialog::getColor ( backgroundColor(), this );
487   if ( selColor.isValid() )
488     setBackgroundColor( selColor );
489 }