Salome HOME
Merge remote-tracking branch 'origin/vsr/fix_single_study_pb' into pre/fix_single_study
[modules/gui.git] / src / SALOME_PY / SalomePy.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 //  SALOME SALOME_PY : binding of VTK graphics and Python
24 //  File   : SalomePy.cxx
25 //  Author : Paul RASCLE, EDF
26 //
27 #ifdef WIN32
28 // E.A. : On windows with python 2.6, there is a conflict
29 // E.A. : between pymath.h and Standard_math.h which define
30 // E.A. : some same symbols : acosh, asinh, ...
31 #include <Standard_math.hxx>
32 #include <pymath.h>
33 #endif
34
35 #include <Python.h>
36 #include <vtkPythonUtil.h>
37
38 #include <vtkVersion.h>
39 #include <vtkRenderer.h>
40 #include <vtkRenderWindow.h>
41 #include <vtkRenderWindowInteractor.h>
42
43 #include <SALOME_Event.h>
44
45 #include <SUIT_Session.h>
46 #include <LightApp_Application.h>
47 #include <LightApp_Study.h>
48
49 #include <SVTK_ViewManager.h>
50 #include <SVTK_ViewWindow.h>
51
52 #define VTK_XVERSION (VTK_MAJOR_VERSION*10000+VTK_MINOR_VERSION*100+VTK_BUILD_VERSION)
53
54 /*!
55   \brief Python wrappings for VTK viewer of the SALOME desktop.
56
57   All methods are implemented using Event mechanism. The module
58   provides the following functions:
59   - getRenderer()
60   - getRenderWindow()
61   - getRenderWindowInteractor()
62   - showTrihedron()
63   - fitAll()
64   - setView()
65   - resetView()
66
67   Usage in Python:
68   \code
69   import SalomePy
70   renderer = SalomePy.getRenderer()     # get VTK renderer
71   window   = SalomePy.getRenderWindow() # get render window
72   \endcode
73
74   The methods getRenderer(), getRenderWindow() and getRenderWindowInteractor()
75   open new VTK viewer if there is no one opened.
76   In case of any error these methods return None object to the Python.
77 */
78
79 #ifdef WIN32
80  #if defined SALOMEPY_EXPORTS || defined SalomePy_EXPORTS
81   #define SALOMEPY_EXPORT __declspec( dllexport )
82  #else
83   #define SALOMEPY_EXPORT __declspec( dllimport )
84  #endif
85 #else
86  #define SALOMEPY_EXPORT
87 #endif
88
89
90 #define PUBLISH_ENUM(i)                              \
91 {                                                    \
92   PyObject *w;                                       \
93   int rc;                                            \
94   if ( ( w = PyInt_FromLong( i ) ) == NULL ) return; \
95   rc = PyDict_SetItemString( aModuleDict, #i, w );   \
96   Py_DECREF( w );                                    \
97   if ( rc < 0 ) return;                              \
98 }
99
100 //! View operation type
101 enum {
102   ViewFront,     //!< front view
103   ViewBack,      //!< back view
104   ViewTop,       //!< top view
105   ViewBottom,    //!< bottom view
106   ViewRight,     //!< right view
107   ViewLeft       //!< left view
108 };
109
110 /*!
111   \brief Get Python class object by name
112   \internal
113   \param theClassName Python class name
114   \return Python class object or None object if class is not found
115 */
116 static PyObject* GetPyClass( const char* theClassName ) 
117 {
118   static PyObject* aVTKModule = 0;
119   PyObject* aPyClass = 0;
120   if( !aVTKModule ) {
121 #if VTK_XVERSION < 30000
122     aVTKModule = PyImport_ImportModule( "libVTKGraphicsPython" ); 
123 #elif VTK_XVERSION < 50700
124     aVTKModule = PyImport_ImportModule( "vtk.libvtkRenderingPython" ); 
125 #elif VTK_XVERSION < 60000
126     aVTKModule = PyImport_ImportModule( "vtkRenderingPython" ); 
127 #else
128     aVTKModule = PyImport_ImportModule( "vtkRenderingCorePython" ); 
129 #endif
130     if( PyErr_Occurred() ) {
131       PyErr_Print();
132     }
133   }
134   if ( aVTKModule ) {
135     PyObject* aVTKDict = PyModule_GetDict( aVTKModule );
136     aPyClass = PyDict_GetItemString(aVTKDict, const_cast<char*>( theClassName ) );
137   }
138   return aPyClass;
139 }
140
141 /*!
142   \brief VTK window find/create mode
143   \internal
144 */
145 enum { 
146   __Find,          // try to find VTK window; if not found, do nothing
147   __FindOrCreate,  // try to find VTK window; if not found, create new one
148   __Create };      // create new VTK window
149
150 /*!
151   \brief Find or create VTK window.
152   \internal
153   \param toCreate window find/create mode
154   \return VTK window pointer or 0 if it could not be found/created
155 */
156 static SVTK_ViewWindow* GetVTKViewWindow( int toCreate = __FindOrCreate ) {
157   SVTK_ViewWindow* aVW = 0;
158   if ( SUIT_Session::session() ) {
159     // get application
160     LightApp_Application* anApp = dynamic_cast<LightApp_Application*>( SUIT_Session::session()->activeApplication() );
161     if ( anApp ) {
162       // get active study
163       LightApp_Study* aStudy = dynamic_cast<LightApp_Study*>( anApp->activeStudy() );
164       if ( aStudy ) {
165         // find or create VTK view manager
166         if ( toCreate == __Create ) {
167           SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->createViewManager( "VTKViewer" ) );
168           if ( aVM ) {
169             aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
170             if ( !aVW )
171               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->createViewWindow() );
172             // VSR : When new view window is created it can be not active yet at this moment,
173             // so the following is a some workaround
174             if ( !aVW && !aVM->getViews().isEmpty() )
175               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
176           }
177         }
178         else {
179           SVTK_ViewManager* aVM = dynamic_cast<SVTK_ViewManager*>( anApp->getViewManager( "VTKViewer", toCreate == __FindOrCreate ) );
180           if ( aVM ) {
181             aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getActiveView() );
182             // VSR : When new view window is created it can be not active yet at this moment,
183             // so the following is a some workaround
184             if ( !aVW && !aVM->getViews().isEmpty() )
185               aVW = dynamic_cast<SVTK_ViewWindow*>( aVM->getViews()[0] );
186           }
187         }
188       }
189     }
190   }
191   return aVW;
192 }
193
194 /*!
195   \fn PyObject* getRenderer( int toCreate = 0 );
196   \brief Get VTK renderer (vtkRenderer).
197   
198   If \a toCreate parameter is 0 (by default) the function tries to find
199   and reuse existing VTK window; if it is not found, the new VTK window
200   is opened.
201
202   If \a toCreate parameter is non-zero, the function always creates
203   new VTK window.
204
205   If VTK window could not be found and or created, the None Python object
206   is returned.
207
208   \param toCreate window creation mode
209   \return VTK window renderer object
210 */
211
212 class SALOMEPY_EXPORT TGetRendererEvent: public SALOME_Event
213 {
214 public:
215   typedef PyObject* TResult;
216   TResult myResult;
217   int     myCreate;
218   TGetRendererEvent( bool toCreate )
219     : myResult( Py_None ), myCreate( toCreate ) {}
220   virtual void Execute()
221   {
222     PyObject* aPyClass = ::GetPyClass( "vtkRenderer" );
223     SVTK_ViewWindow* aVTKViewWindow = 
224       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
225     if( aVTKViewWindow && aPyClass ) {
226       vtkRenderer* aVTKObject = aVTKViewWindow->getRenderer();
227 #if VTK_XVERSION < 50700
228       myResult = PyVTKObject_New( aPyClass, aVTKObject );
229 #else
230       myResult = PyVTKObject_New( aPyClass, NULL, aVTKObject );
231 #endif
232     }
233   }
234 };
235
236 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderer( PyObject* self, PyObject* args )
237 {
238   PyObject* aResult = Py_None;
239   int toCreate = 0;
240   if ( !PyArg_ParseTuple( args, "|i:getRenderer", &toCreate ) )
241     PyErr_Print();
242   else
243     aResult = ProcessEvent( new TGetRendererEvent( toCreate ) );
244   return aResult;
245 }
246
247 /*!
248   \fn PyObject* getRenderWindow( int toCreate = 0 );
249   \brief Get VTK render window (vtkRenderWindow).
250   
251   If \a toCreate parameter is 0 (by default) the function tries to find 
252   and reuse existing VTK window; if it is not found, the new VTK window
253   is opened.
254
255   If \a toCreate parameter is non-zero, the function always creates
256   new VTK window.
257
258   If VTK window could not be found and or created, the None Python object
259   is returned.
260
261   \param toCreate window creation mode
262   \return VTK window render window object
263 */
264
265 class SALOMEPY_EXPORT TGetRenderWindowEvent: public SALOME_Event
266 {
267 public:
268   typedef PyObject* TResult;
269   TResult myResult;
270   int     myCreate;
271   TGetRenderWindowEvent( bool toCreate )
272     : myResult( Py_None ), myCreate( toCreate ) {}
273   virtual void Execute()
274   {
275     PyObject* aPyClass = ::GetPyClass( "vtkRenderWindow" );
276     SVTK_ViewWindow* aVTKViewWindow = 
277       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
278     if( aVTKViewWindow && aPyClass ) {
279       vtkRenderWindow* aVTKObject = aVTKViewWindow->getRenderWindow();
280 #if VTK_XVERSION < 50700
281       myResult = PyVTKObject_New( aPyClass, aVTKObject );
282 #else
283       myResult = PyVTKObject_New( aPyClass, NULL, aVTKObject );
284 #endif
285     }
286   }
287 };
288
289 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindow( PyObject* self, PyObject* args )
290 {
291   PyObject* aResult = Py_None;
292   int toCreate = 0;
293   if ( !PyArg_ParseTuple( args, "|i:getRenderWindow", &toCreate ) )
294     PyErr_Print();
295   else
296     aResult = ProcessEvent( new TGetRenderWindowEvent( toCreate ) );
297   return aResult;
298 }
299
300 /*!
301   \fn PyObject* getRenderWindowInteractor( int toCreate = 0 );
302   \brief Get VTK render window interactor (getRenderWindowInteractor).
303   
304   If \a toCreate parameter is 0 (by default) the function tries to find 
305   and reuse existing VTK window; if it is not found, the new VTK window
306   is opened.
307
308   If \a toCreate parameter is non-zero, the function always creates
309   new VTK window.
310
311   If VTK window could not be found and or created, the None Python object
312   is returned.
313
314   \param toCreate window creation mode
315   \return VTK window render window interactor object
316 */
317
318 class SALOMEPY_EXPORT TGetRenderWindowInteractorEvent: public SALOME_Event
319 {
320 public:
321   typedef PyObject* TResult;
322   TResult myResult;
323   int     myCreate;
324   TGetRenderWindowInteractorEvent( bool toCreate )
325     : myResult( Py_None ), myCreate( toCreate ) {}
326   virtual void Execute()
327   {
328     PyObject* aPyClass = ::GetPyClass( "vtkRenderWindowInteractor" );
329     SVTK_ViewWindow* aVTKViewWindow = 
330       ::GetVTKViewWindow( myCreate ? __Create : __FindOrCreate );
331     if( aVTKViewWindow && aPyClass ) {
332       vtkRenderWindowInteractor* aVTKObject = aVTKViewWindow->getInteractor();
333 #if VTK_XVERSION < 50700
334       myResult = PyVTKObject_New( aPyClass, aVTKObject );
335 #else
336       myResult = PyVTKObject_New( aPyClass, NULL, aVTKObject );
337 #endif
338     }
339   }
340 };
341
342 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_getRenderWindowInteractor( PyObject* self, PyObject* args )
343 {
344   PyObject* aResult = Py_None;
345   int toCreate = 0;
346   if ( !PyArg_ParseTuple( args, "|i:getRenderWindowInteractor", &toCreate ) )
347     PyErr_Print();
348   else
349     aResult = ProcessEvent( new TGetRenderWindowInteractorEvent( toCreate ) );
350   return aResult;
351 }
352
353 /*!
354   \fn PyObject* showTrihedron( int show );
355   \brief Show/hide trihedron in the current VTK viewer.
356
357   If there is no active VTK viewer, nothing happens.
358   
359   \param show new trihedron visibility state
360   \return nothing (Py_None)
361 */
362
363 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_showTrihedron( PyObject* self, PyObject* args )
364 {
365   class TEvent: public SALOME_Event
366   {
367   public:
368     int myShow;
369     TEvent( int bShow )
370       : myShow( bShow ) {}
371     virtual void Execute()
372     {
373       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
374         if ( aVTKViewWindow->isTrihedronDisplayed() != myShow )
375           aVTKViewWindow->onViewTrihedron();
376       }
377     }
378   };
379   
380   PyObject* aResult = Py_None;
381   int bShow = 0;
382   if ( !PyArg_ParseTuple( args, "i:showTrihedron", &bShow ) )
383     PyErr_Print();
384   else
385     ProcessVoidEvent( new TEvent( bShow ) );
386   return aResult;
387 }
388
389 /*!
390   \fn PyObject* fitAll();
391   \brief Fit all the contents in the current VTK viewer.
392
393   If there is no active VTK viewer, nothing happens.
394
395   \return nothing (Py_None)
396 */
397
398 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_fitAll( PyObject* self, PyObject* args )
399 {
400   class TEvent: public SALOME_Event
401   {
402   public:
403     TEvent() {}
404     virtual void Execute()
405     {
406       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
407         aVTKViewWindow->onFitAll();
408       }
409     }
410   };
411   
412   ProcessVoidEvent( new TEvent() );
413   return Py_None;
414 }
415
416 /*!
417   \fn PyObject* setView( int type );
418   \brief Set view type for the current VTK viewer.
419
420   If there is no active VTK viewer, nothing happens.
421   
422   \param type view type
423   \return nothing (Py_None)
424 */
425
426 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_setView( PyObject* self, PyObject* args )
427 {
428   class TEvent: public SALOME_Event
429   {
430   public:
431     long myType;
432     TEvent( long type ) : myType( type) {}
433     virtual void Execute()
434     {
435       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
436         switch( myType ) {
437         case ViewFront:
438           aVTKViewWindow->onFrontView();  break;
439         case ViewBack:
440           aVTKViewWindow->onBackView();   break;
441         case ViewTop:
442           aVTKViewWindow->onTopView();    break;
443         case ViewBottom:
444           aVTKViewWindow->onBottomView(); break;
445         case ViewRight:
446           aVTKViewWindow->onRightView();  break;
447         case ViewLeft:
448           aVTKViewWindow->onLeftView();   break;
449         default:
450           PyErr_Format(PyExc_ValueError,"setView%: wrong parameter value; must be between %d and %d", ViewFront, ViewLeft );
451           break;
452         }
453       }
454     }
455   };
456   
457   long type = -1;
458   if ( !PyArg_ParseTuple( args, "l:setView", &type ) )
459     PyErr_Print();
460   else {
461     ProcessVoidEvent( new TEvent( type ) );
462     if( PyErr_Occurred() )
463       PyErr_Print();
464   }
465   return Py_None;
466 }
467
468 /*!
469   \fn PyObject* resetView();
470   \brief Reset contents of the current VTK viewer.
471
472   If there is no active VTK viewer, nothing happens.
473   
474   \return nothing (Py_None)
475 */
476
477 extern "C" SALOMEPY_EXPORT PyObject* libSalomePy_resetView( PyObject* self, PyObject* args )
478 {
479   class TEvent: public SALOME_Event
480   {
481   public:
482     TEvent() {}
483     virtual void Execute()
484     {
485       if( SVTK_ViewWindow* aVTKViewWindow = GetVTKViewWindow( __Find ) ) {
486         aVTKViewWindow->onResetView();
487       }
488     }
489   };
490   
491   ProcessVoidEvent( new TEvent() );
492   return Py_None;
493 }
494
495 static PyMethodDef Module_Methods[] = 
496 {
497   { "getRenderer",               libSalomePy_getRenderer,               METH_VARARGS },
498   { "getRenderWindow",           libSalomePy_getRenderWindow,           METH_VARARGS },
499   { "getRenderWindowInteractor", libSalomePy_getRenderWindowInteractor, METH_VARARGS },
500   { "showTrihedron",             libSalomePy_showTrihedron,             METH_VARARGS },
501   { "fitAll",                    libSalomePy_fitAll,                    METH_NOARGS  },
502   { "setView",                   libSalomePy_setView,                   METH_VARARGS },
503   { "resetView",                 libSalomePy_resetView,                 METH_NOARGS  },
504   { NULL, NULL }
505 };
506
507 /*!
508   \brief Python module initialization.
509   \internal
510 */
511 extern "C" SALOMEPY_EXPORT void initlibSalomePy()
512 {
513   static char* modulename = (char*)"libSalomePy";
514
515   // init module
516   PyObject* aModule = Py_InitModule( modulename, Module_Methods );
517   if( PyErr_Occurred() ) {
518     PyErr_Print();
519     return;
520   }
521
522   // get module's dictionary
523   PyObject *aModuleDict = PyModule_GetDict( aModule );
524   if ( aModuleDict == NULL )
525     return;
526
527   // export View type enumeration
528   PUBLISH_ENUM( ViewFront );
529   PUBLISH_ENUM( ViewBack );
530   PUBLISH_ENUM( ViewTop );
531   PUBLISH_ENUM( ViewBottom );
532   PUBLISH_ENUM( ViewRight );
533   PUBLISH_ENUM( ViewLeft );
534 }