Imported Upstream version 3.2.2
[debian/gnuradio] / gr-wxgui / src / python / plotter / plotter_base.py
1 #
2 # Copyright 2008, 2009 Free Software Foundation, Inc.
3 #
4 # This file is part of GNU Radio
5 #
6 # GNU Radio is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3, or (at your option)
9 # any later version.
10 #
11 # GNU Radio 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
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with GNU Radio; see the file COPYING.  If not, write to
18 # the Free Software Foundation, Inc., 51 Franklin Street,
19 # Boston, MA 02110-1301, USA.
20 #
21
22 import wx
23 import wx.glcanvas
24 from OpenGL import GL
25 import common
26
27 BACKGROUND_COLOR_SPEC = (1, 0.976, 1, 1) #creamy white
28
29 ##################################################
30 # GL caching interface
31 ##################################################
32 class gl_cache(object):
33         """
34         Cache a set of gl drawing routines in a compiled list.
35         """
36
37         def __init__(self, draw):
38                 """
39                 Create a new cache.
40                 @param draw a function to draw gl stuff
41                 """
42                 self.changed(True)
43                 self._draw = draw
44
45         def init(self):
46                 """
47                 To be called when gl initializes.
48                 Create a new compiled list.
49                 """
50                 self._grid_compiled_list_id = GL.glGenLists(1)
51
52         def draw(self):
53                 """
54                 Draw the gl stuff using a compiled list.
55                 If changed, reload the compiled list.
56                 """
57                 if self.changed():
58                         GL.glNewList(self._grid_compiled_list_id, GL.GL_COMPILE)
59                         self._draw()
60                         GL.glEndList()
61                         self.changed(False)
62                 #draw the grid
63                 GL.glCallList(self._grid_compiled_list_id)
64
65         def changed(self, state=None):
66                 """
67                 Set the changed flag if state is not None.
68                 Otherwise return the changed flag.
69                 """
70                 if state is None: return self._changed
71                 self._changed = state
72
73 ##################################################
74 # OpenGL WX Plotter Canvas
75 ##################################################
76 class plotter_base(wx.glcanvas.GLCanvas, common.mutex):
77         """
78         Plotter base class for all plot types.
79         """
80
81         def __init__(self, parent):
82                 """
83                 Create a new plotter base.
84                 Initialize the GLCanvas with double buffering.
85                 Initialize various plotter flags.
86                 Bind the paint and size events.
87                 @param parent the parent widgit
88                 """
89                 attribList = (wx.glcanvas.WX_GL_DOUBLEBUFFER, wx.glcanvas.WX_GL_RGBA)
90                 wx.glcanvas.GLCanvas.__init__(self, parent, attribList=attribList)
91                 self._gl_init_flag = False
92                 self._resized_flag = True
93                 self._init_fcns = list()
94                 self._draw_fcns = list()
95                 self._gl_caches = list()
96                 self.Bind(wx.EVT_PAINT, self._on_paint)
97                 self.Bind(wx.EVT_SIZE, self._on_size)
98                 self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None)
99
100         def new_gl_cache(self, draw_fcn, draw_pri=50):
101                 """
102                 Create a new gl cache.
103                 Register its draw and init function.
104                 @return the new cache object
105                 """
106                 cache = gl_cache(draw_fcn)
107                 self.register_init(cache.init)
108                 self.register_draw(cache.draw, draw_pri)
109                 self._gl_caches.append(cache)
110                 return cache
111
112         def register_init(self, init_fcn):
113                 self._init_fcns.append(init_fcn)
114
115         def register_draw(self, draw_fcn, draw_pri=50):
116                 """
117                 Register a draw function with a layer priority.
118                 Large pri values are drawn last.
119                 Small pri values are drawn first.
120                 """
121                 for i in range(len(self._draw_fcns)):
122                         if draw_pri < self._draw_fcns[i][0]:
123                                 self._draw_fcns.insert(i, (draw_pri, draw_fcn))
124                                 return
125                 self._draw_fcns.append((draw_pri, draw_fcn))
126
127         def _on_size(self, event):
128                 """
129                 Flag the resize event.
130                 The paint event will handle the actual resizing.
131                 """
132                 self.lock()
133                 self._resized_flag = True
134                 self.unlock()
135
136         def _on_paint(self, event):
137                 """
138                 Respond to paint events.
139                 Initialize GL if this is the first paint event.
140                 Resize the view port if the width or height changed.
141                 Redraw the screen, calling the draw functions.
142                 """
143                 self.lock()
144                 self.SetCurrent()
145                 #check if gl was initialized
146                 if not self._gl_init_flag:
147                         GL.glClearColor(*BACKGROUND_COLOR_SPEC)
148                         for fcn in self._init_fcns: fcn()
149                         self._gl_init_flag = True
150                 #check for a change in window size
151                 if self._resized_flag:
152                         self.width, self.height = self.GetSize()
153                         GL.glMatrixMode(GL.GL_PROJECTION)
154                         GL.glLoadIdentity()
155                         GL.glOrtho(0, self.width, self.height, 0, 1, 0)
156                         GL.glMatrixMode(GL.GL_MODELVIEW)
157                         GL.glLoadIdentity()
158                         GL.glViewport(0, 0, self.width, self.height)
159                         for cache in self._gl_caches: cache.changed(True)
160                         self._resized_flag = False
161                 #clear, draw functions, swap
162                 GL.glClear(GL.GL_COLOR_BUFFER_BIT)
163                 for fcn in self._draw_fcns: fcn[1]()
164                 self.SwapBuffers()
165                 self.unlock()
166
167         def update(self):
168                 """
169                 Force a paint event.
170                 """
171                 if not self._gl_init_flag: return
172                 wx.PostEvent(self, wx.PaintEvent())