Salome HOME
Merge branch 'V7_dev'
[modules/gui.git] / src / OCCViewer / OCCViewer_ViewPort.cxx
1 // Copyright (C) 2007-2016  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 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) && OCC_VERSION_LARGE < 0x07000000
222   setAttribute( Qt::WA_PaintOnScreen );
223 #endif
224   setAttribute( Qt::WA_NoSystemBackground );
225 }
226
227 /*!
228     Cleans up the viewport. [ private ]
229 */
230 void OCCViewer_ViewPort::cleanup()
231 {
232 }
233
234 /*!
235     Selects visual ID for OpenGL window ( X11 specific ). [ protected ]
236 */
237 void OCCViewer_ViewPort::selectVisualId()
238 {
239 #if !defined WIN32
240   XVisualInfo* pVisualInfo;
241   if ( QX11Info::display() )
242   {
243     /* Initialization with the default VisualID */
244     Visual *v = DefaultVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
245     /*int visualID = */XVisualIDFromVisual( v );
246     
247     /*  Here we use the settings from Optimizer_ViewInfo::TxglCreateWindow() */
248     int visualAttr[] = { GLX_RGBA, GLX_DEPTH_SIZE, 1, GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1,
249                           GLX_BLUE_SIZE, 1, GLX_DOUBLEBUFFER, None };
250     
251     pVisualInfo = ::glXChooseVisual( QX11Info::display(), DefaultScreen( QX11Info::display() ), visualAttr );
252     
253     if ( isVisible() )
254       hide();
255     
256     XSetWindowAttributes a;
257     
258     a.colormap = choose_cmap( QX11Info::display(), pVisualInfo );       /* find best colormap */
259     a.background_pixel = QColormap::instance().pixel( backgroundColor() );
260     a.border_pixel = QColormap::instance().pixel( Qt::black );
261     Window p = RootWindow( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
262     if ( parentWidget() )
263       p = parentWidget()->winId();
264     
265     Window w;
266     /*
267     if ( type == Type2D )  // creating simple X window for 2d
268     {
269       unsigned long xbackground =
270           BlackPixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
271       unsigned long xforeground =
272           WhitePixel( QX11Info::display(), DefaultScreen( QX11Info::display() ) );
273
274       w = XCreateSimpleWindow ( QX11Info::display(), p, x(), y(), width(),
275                                 height(), 0, xforeground, xbackground );
276     }
277     else if ( type == Type3D )
278     {
279       w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
280                           0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
281                           CWBackPixel | CWBorderPixel | CWColormap, &a );
282     }
283     else
284       return;
285     */
286     w = XCreateWindow( QX11Info::display(), p,  x(), y(), width(), height(),
287                       0, pVisualInfo->depth, InputOutput, pVisualInfo->visual,
288                       CWBackPixel | CWBorderPixel | CWColormap, &a );
289   
290     Window *cmw;
291     Window *cmwret;
292     int count;
293     if ( XGetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), &cmwret, &count ) )
294     {
295       cmw = new Window[count+1];
296       memcpy( (char*)cmw, (char*)cmwret, sizeof(Window) * count );
297       XFree( (char*)cmwret );
298       int i;
299
300       for ( i = 0; i < count; i++ )
301       {
302         if ( cmw[i] == winId() ) /* replace old window */
303         {
304           cmw[i] = w;
305           break;
306         }
307       }
308
309       if ( i >= count )                        /* append new window */
310         cmw[count++] = w;
311     }
312     else
313     {
314       count = 1;
315       cmw = new Window[count];
316       cmw[0] = w;
317     }
318
319     /* Creating new window (with good VisualID) for this widget */
320     create(w);
321     XSetWMColormapWindows( QX11Info::display(), topLevelWidget()->winId(), cmw, count );
322     delete[] cmw;
323
324     if ( isVisible() )
325       show();
326
327     if ( pVisualInfo )
328       XFree( (char *)pVisualInfo );
329
330     XFlush( QX11Info::display() );
331   }
332 #endif
333 }
334
335 /*!
336     Sets the background 'color'. [ virtual ]
337 */
338 void OCCViewer_ViewPort::setBackgroundColor( const QColor& color )
339 {
340   QPalette pal = palette();
341   pal.setColor( QPalette::Background, color );
342   setPalette( pal );
343   repaint();
344   emit vpChangeBGColor( color );
345 }
346
347 /*!
348     Returns the background color. [ virtual ]
349 */
350 QColor OCCViewer_ViewPort::backgroundColor() const
351 {
352   return palette().color( QPalette::Active, QPalette::Background );
353 }
354
355 /*!
356     Returns 'true' if sketching is enabled in  this viewport. [ public ]
357 */
358 bool OCCViewer_ViewPort::isSketchingEnabled() const
359 {
360   return myEnableSketching;
361 }
362
363 /*!
364     Enables / disables sketching  [ public ]
365 */
366 void OCCViewer_ViewPort::setSketchingEnabled( bool enable )
367 {
368   myEnableSketching = enable;
369 }
370
371 /*!
372     Returns 'true' if transformations ( rotation, zoom etc. )
373     are enabled in this viewport. [ public ]
374 */
375 bool OCCViewer_ViewPort::isTransformEnabled() const
376 {
377   return myEnableTransform;
378 }
379
380 /*!
381     Enables / disables transformations. [ public ]
382 */
383 void OCCViewer_ViewPort::setTransformEnabled( bool enable )
384 {
385   myEnableTransform = enable;
386 }
387
388 /*!
389     Emits 'mouseEvent' signal. [ virtual protected ]
390 */
391 void OCCViewer_ViewPort::mousePressEvent( QMouseEvent *e )
392 {
393     emit vpMouseEvent( e );
394 }
395
396 /*!
397     Emits 'mouseEvent' signal. [ virtual protected ]
398 */
399 void OCCViewer_ViewPort::mouseMoveEvent( QMouseEvent* e )
400 {
401   emit vpMouseEvent( e );
402 }
403
404 /*!
405     Emits 'mouseEvent' signal. [ virtual protected ]
406 */
407 void OCCViewer_ViewPort::mouseReleaseEvent( QMouseEvent *e )
408 {
409   emit vpMouseEvent( e );
410 }
411
412 /*!
413     Emits 'mouseEvent' signal. [ virtual protected ]
414 */
415 void OCCViewer_ViewPort::mouseDoubleClickEvent( QMouseEvent *e )
416 {
417   emit vpMouseEvent( e );
418 }
419
420 /*!
421     Emits 'keyEvent' signal. [ virtual protected ]
422 */
423 void OCCViewer_ViewPort::keyPressEvent( QKeyEvent *e )
424 {
425   emit vpKeyEvent( e );
426 }
427
428 /*!
429     Emits 'keyEvent' signal. [ virtual protected ]
430 */
431 void OCCViewer_ViewPort::keyReleaseEvent( QKeyEvent *e )
432 {
433   emit vpKeyEvent( e );
434 }
435
436 /*!
437     Repaints the viewport. [ virtual protected ]
438 */
439 void OCCViewer_ViewPort::paintEvent( QPaintEvent* )
440 {
441   if ( myPaintersRedrawing )
442   {
443     QPainter p( this );
444     emit vpDrawExternal( &p );
445     myPaintersRedrawing = false;
446   }
447 }
448
449 /*!
450     Forces to redraw the viewport by an external painter. [ public ]
451 */
452 void OCCViewer_ViewPort::redrawPainters()
453 {
454   myPaintersRedrawing = true;
455   repaint();
456 }
457
458 /*!
459     Updates this view. Does nothing by default. [ virtual public ]
460 */
461 void OCCViewer_ViewPort::onUpdate()
462 {
463 }
464
465 /*!
466   Get paint engine for the OpenGL viewer. [ virtual public ]
467 */
468 QPaintEngine* OCCViewer_ViewPort::paintEngine() const
469 {
470   return 0;
471 }
472
473 /*!
474   Performs synchronization of view parameters with the specified view.
475   Returns \c true if synchronization is done successfully or \c false otherwise.
476   Default implementation does nothing (return \c false)
477 */
478 bool OCCViewer_ViewPort::synchronize( OCCViewer_ViewPort* )
479 {
480   return false;
481 }
482
483 /*!
484     Sets the background color with color selection dialog. [ virtual protected slot ]
485 */
486 void OCCViewer_ViewPort::onChangeBackground()
487 {
488   QColor selColor = QColorDialog::getColor ( backgroundColor(), this );
489   if ( selColor.isValid() )
490     setBackgroundColor( selColor );
491 }