1""" 2Description: 3 4 Provides a pyGtk vtkRenderWindowInteractor widget. This embeds a 5 vtkRenderWindow inside a GTK widget and uses the 6 vtkGenericRenderWindowInteractor for the event handling. This is 7 based on vtkTkRenderWindow.py. 8 9 The class uses the gtkgl.GtkGLArea widget (gtkglarea). This avoids 10 a lot of problems with flicker. 11 12 There is a working example at the bottom. 13 14Created by Prabhu Ramachandran, April 2002. 15 16Bugs: 17 18 (*) There is a focus related problem. Tkinter has a focus object 19 that handles focus events. I don't know of an equivalent object 20 under GTK. So, when an 'enter_notify_event' is received on the 21 GtkVTKRenderWindow I grab the focus but I don't know what to do when 22 I get a 'leave_notify_event'. 23 24 (*) Will not work under Win32 because it uses the XID of a window in 25 OnRealize. Suggestions to fix this will be appreciated. 26 27""" 28 29import gtk, GDK, gtkgl 30from vtkmodules.vtkRenderingCore import vtkGenericRenderWindowInteractor 31import math 32 33 34class GtkVTKRenderWindowInteractor(gtkgl.GtkGLArea): 35 36 """ Embeds a vtkRenderWindow into a pyGTK widget and uses 37 vtkGenericRenderWindowInteractor for the event handling. This 38 class embeds the RenderWindow correctly. A __getattr__ hook is 39 provided that makes the class behave like a 40 vtkGenericRenderWindowInteractor.""" 41 42 def __init__(self, *args): 43 l = list(args) 44 attr = (gtkgl.RGBA, gtkgl.DOUBLEBUFFER) 45 l.insert(0, self) 46 l.insert(1, attr) 47 apply(gtkgl.GtkGLArea.__init__, l) 48 self._RenderWindow = vtkRenderWindow() 49 50 # private attributes 51 self.__Created = 0 52 self._ActiveButton = 0 53 54 self._Iren = vtkGenericRenderWindowInteractor() 55 self._Iren.SetRenderWindow(self._RenderWindow) 56 57 self._Iren.AddObserver('CreateTimerEvent', self.CreateTimer) 58 self._Iren.AddObserver('DestroyTimerEvent', self.DestroyTimer) 59 self.ConnectSignals() 60 61 # need this to be able to handle key_press events. 62 self.set_flags(gtk.CAN_FOCUS) 63 # default size 64 self.set_usize(300, 300) 65 66 def set_usize(self, w, h): 67 gtkgl.GtkGLArea.set_usize(self, w, h) 68 self._RenderWindow.SetSize(w, h) 69 self._Iren.SetSize(w, h) 70 self._Iren.ConfigureEvent() 71 72 def ConnectSignals(self): 73 self.connect("realize", self.OnRealize) 74 self.connect("expose_event", self.OnExpose) 75 self.connect("configure_event", self.OnConfigure) 76 self.connect("button_press_event", self.OnButtonDown) 77 self.connect("button_release_event", self.OnButtonUp) 78 self.connect("motion_notify_event", self.OnMouseMove) 79 self.connect("enter_notify_event", self.OnEnter) 80 self.connect("leave_notify_event", self.OnLeave) 81 self.connect("key_press_event", self.OnKeyPress) 82 self.connect("delete_event", self.OnDestroy) 83 self.add_events(GDK.EXPOSURE_MASK| GDK.BUTTON_PRESS_MASK | 84 GDK.BUTTON_RELEASE_MASK | 85 GDK.KEY_PRESS_MASK | 86 GDK.POINTER_MOTION_MASK | 87 GDK.POINTER_MOTION_HINT_MASK | 88 GDK.ENTER_NOTIFY_MASK | GDK.LEAVE_NOTIFY_MASK) 89 90 def __getattr__(self, attr): 91 """Makes the object behave like a 92 vtkGenericRenderWindowInteractor""" 93 if attr == '__vtk__': 94 return lambda t=self._Iren: t 95 elif hasattr(self._Iren, attr): 96 return getattr(self._Iren, attr) 97 else: 98 raise AttributeError(self.__class__.__name__ + 99 " has no attribute named " + attr) 100 101 def CreateTimer(self, obj, event): 102 gtk.timeout_add(10, self._Iren.TimerEvent) 103 104 def DestroyTimer(self, obj, event): 105 """The timer is a one shot timer so will expire automatically.""" 106 return 1 107 108 def GetRenderWindow(self): 109 return self._RenderWindow 110 111 def Render(self): 112 if self.__Created: 113 self._RenderWindow.Render() 114 115 def OnRealize(self, *args): 116 if self.__Created == 0: 117 # you can't get the xid without the window being realized. 118 self.realize() 119 win_id = str(self.get_window().xid) 120 self._RenderWindow.SetWindowInfo(win_id) 121 self._Iren.Initialize() 122 self.__Created = 1 123 return gtk.TRUE 124 125 def OnConfigure(self, wid, event=None): 126 sz = self._RenderWindow.GetSize() 127 if (event.width != sz[0]) or (event.height != sz[1]): 128 self._Iren.SetSize(event.width, event.height) 129 self._Iren.ConfigureEvent() 130 return gtk.TRUE 131 132 def OnExpose(self, *args): 133 self.Render() 134 return gtk.TRUE 135 136 def OnDestroy(self, event=None): 137 self.hide() 138 del self._RenderWindow 139 self.destroy() 140 return gtk.TRUE 141 142 def _GetCtrlShift(self, event): 143 ctrl, shift = 0, 0 144 if ((event.state & GDK.CONTROL_MASK) == GDK.CONTROL_MASK): 145 ctrl = 1 146 if ((event.state & GDK.SHIFT_MASK) == GDK.SHIFT_MASK): 147 shift = 1 148 return ctrl, shift 149 150 def OnButtonDown(self, wid, event): 151 """Mouse button pressed.""" 152 m = self.get_pointer() 153 ctrl, shift = self._GetCtrlShift(event) 154 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 155 chr(0), 0, None) 156 button = event.button 157 if button == 3: 158 self._Iren.RightButtonPressEvent() 159 return gtk.TRUE 160 elif button == 1: 161 self._Iren.LeftButtonPressEvent() 162 return gtk.TRUE 163 elif button == 2: 164 self._Iren.MiddleButtonPressEvent() 165 return gtk.TRUE 166 else: 167 return gtk.FALSE 168 169 def OnButtonUp(self, wid, event): 170 """Mouse button released.""" 171 m = self.get_pointer() 172 ctrl, shift = self._GetCtrlShift(event) 173 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 174 chr(0), 0, None) 175 button = event.button 176 if button == 3: 177 self._Iren.RightButtonReleaseEvent() 178 return gtk.TRUE 179 elif button == 1: 180 self._Iren.LeftButtonReleaseEvent() 181 return gtk.TRUE 182 elif button == 2: 183 self._Iren.MiddleButtonReleaseEvent() 184 return gtk.TRUE 185 186 return gtk.FALSE 187 188 def OnMouseMove(self, wid, event): 189 """Mouse has moved.""" 190 m = self.get_pointer() 191 ctrl, shift = self._GetCtrlShift(event) 192 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 193 chr(0), 0, None) 194 self._Iren.MouseMoveEvent() 195 return gtk.TRUE 196 197 def OnEnter(self, wid, event): 198 """Entering the vtkRenderWindow.""" 199 self.grab_focus() 200 m = self.get_pointer() 201 ctrl, shift = self._GetCtrlShift(event) 202 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 203 chr(0), 0, None) 204 self._Iren.EnterEvent() 205 return gtk.TRUE 206 207 def OnLeave(self, wid, event): 208 """Leaving the vtkRenderWindow.""" 209 m = self.get_pointer() 210 ctrl, shift = self._GetCtrlShift(event) 211 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 212 chr(0), 0, None) 213 self._Iren.LeaveEvent() 214 return gtk.TRUE 215 216 def OnKeyPress(self, wid, event): 217 """Key pressed.""" 218 m = self.get_pointer() 219 ctrl, shift = self._GetCtrlShift(event) 220 keycode, keysym = event.keyval, event.string 221 key = chr(0) 222 if keycode < 256: 223 key = chr(keycode) 224 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 225 key, 0, keysym) 226 self._Iren.KeyPressEvent() 227 self._Iren.CharEvent() 228 return gtk.TRUE 229 230 def OnKeyRelease(self, wid, event): 231 "Key released." 232 m = self.get_pointer() 233 ctrl, shift = self._GetCtrlShift(event) 234 keycode, keysym = event.keyval, event.string 235 key = chr(0) 236 if keycode < 256: 237 key = chr(keycode) 238 self._Iren.SetEventInformationFlipY(m[0], m[1], ctrl, shift, 239 key, 0, keysym) 240 self._Iren.KeyReleaseEvent() 241 return gtk.TRUE 242 243 def Initialize(self): 244 if self.__Created: 245 self._Iren.Initialize() 246 247 248def main(): 249 from vtkmodules.vtkFiltersSources import vtkConeSource 250 from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer 251 252 # The main window 253 window = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL) 254 window.set_title("A GtkVTKRenderWindow Demo!") 255 window.connect("destroy", gtk.mainquit) 256 window.connect("delete_event", gtk.mainquit) 257 window.set_border_width(10) 258 259 # A VBox into which widgets are packed. 260 vbox = gtk.GtkVBox(spacing=3) 261 window.add(vbox) 262 vbox.show() 263 264 # The GtkVTKRenderWindow 265 gvtk = GtkVTKRenderWindowInteractor() 266 #gvtk.SetDesiredUpdateRate(1000) 267 gvtk.set_usize(400, 400) 268 vbox.pack_start(gvtk) 269 gvtk.show() 270 gvtk.Initialize() 271 gvtk.Start() 272 # prevents 'q' from exiting the app. 273 gvtk.AddObserver("ExitEvent", lambda o,e,x=None: x) 274 275 # The VTK stuff. 276 cone = vtkConeSource() 277 cone.SetResolution(80) 278 coneMapper = vtkPolyDataMapper() 279 coneMapper.SetInputConnection(cone.GetOutputPort()) 280 #coneActor = vtkLODActor() 281 coneActor = vtkActor() 282 coneActor.SetMapper(coneMapper) 283 coneActor.GetProperty().SetColor(0.5, 0.5, 1.0) 284 ren = vtkRenderer() 285 gvtk.GetRenderWindow().AddRenderer(ren) 286 ren.AddActor(coneActor) 287 288 # A simple quit button 289 quit = gtk.GtkButton("Quit!") 290 quit.connect("clicked", gtk.mainquit) 291 vbox.pack_start(quit) 292 quit.show() 293 294 # show the main window and start event processing. 295 window.show() 296 gtk.mainloop() 297 298 299if __name__ == "__main__": 300 main() 301