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