Merged r10463:10658 from jblum/gui_guts into trunk. Trunk passes distcheck.
[debian/gnuradio] / gr-wxgui / src / python / plotter / waterfall_plotter.py
index 4dc19f672f50e670efd9cbd9d0bf9779ca8c208f..2e0669961badf81da5e6494186746600bc47145a 100644 (file)
@@ -1,5 +1,5 @@
 #
 #
-# Copyright 2008 Free Software Foundation, Inc.
+# Copyright 2008, 2009 Free Software Foundation, Inc.
 #
 # This file is part of GNU Radio
 #
 #
 # This file is part of GNU Radio
 #
@@ -20,9 +20,9 @@
 #
 
 import wx
 #
 
 import wx
-from plotter_base import grid_plotter_base
-from OpenGL.GL import *
-from gnuradio.wxgui import common
+from grid_plotter_base import grid_plotter_base
+from OpenGL import GL
+import common
 import numpy
 import gltext
 import math
 import numpy
 import gltext
 import math
@@ -33,7 +33,7 @@ LEGEND_NUM_LABELS = 9
 LEGEND_WIDTH = 8
 LEGEND_FONT_SIZE = 8
 LEGEND_BORDER_COLOR_SPEC = (0, 0, 0) #black
 LEGEND_WIDTH = 8
 LEGEND_FONT_SIZE = 8
 LEGEND_BORDER_COLOR_SPEC = (0, 0, 0) #black
-PADDING = 35, 60, 40, 60 #top, right, bottom, left
+MIN_PADDING = 0, 60, 0, 0 #top, right, bottom, left
 
 ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2)))
 
 
 ceil_log2 = lambda x: 2**int(math.ceil(math.log(x)/math.log(2)))
 
@@ -91,7 +91,13 @@ class waterfall_plotter(grid_plotter_base):
                Create a new channel plotter.
                """
                #init
                Create a new channel plotter.
                """
                #init
-               grid_plotter_base.__init__(self, parent, PADDING)
+               grid_plotter_base.__init__(self, parent, MIN_PADDING)
+               #setup legend cache
+               self._legend_cache = self.new_gl_cache(self._draw_legend)
+               #setup waterfall cache
+               self._waterfall_cache = self.new_gl_cache(self._draw_waterfall, 50)
+               #setup waterfall plotter
+               self.register_init(self._init_waterfall)
                self._resize_texture(False)
                self._minimum = 0
                self._maximum = 0
                self._resize_texture(False)
                self._minimum = 0
                self._maximum = 0
@@ -102,35 +108,11 @@ class waterfall_plotter(grid_plotter_base):
                self.set_num_lines(0)
                self.set_color_mode(COLORS.keys()[0])
 
                self.set_num_lines(0)
                self.set_color_mode(COLORS.keys()[0])
 
-       def _gl_init(self):
+       def _init_waterfall(self):
                """
                Run gl initialization tasks.
                """
                """
                Run gl initialization tasks.
                """
-               self._grid_compiled_list_id = glGenLists(1)
-               self._waterfall_texture = glGenTextures(1)
-
-       def draw(self):
-               """
-               Draw the grid and waveforms.
-               """
-               self.lock()
-               #resize texture
-               self._resize_texture()
-               #store the grid drawing operations
-               if self.changed():
-                       glNewList(self._grid_compiled_list_id, GL_COMPILE)
-                       self._draw_grid()
-                       self._draw_legend()
-                       glEndList()
-                       self.changed(False)
-               self.clear()
-               #draw the grid
-               glCallList(self._grid_compiled_list_id)
-               self._draw_waterfall()
-               self._draw_point_label()
-               #swap buffer into display
-               self.SwapBuffers()
-               self.unlock()
+               self._waterfall_texture = GL.glGenTextures(1)
 
        def _draw_waterfall(self):
                """
 
        def _draw_waterfall(self):
                """
@@ -138,42 +120,44 @@ class waterfall_plotter(grid_plotter_base):
                The texture is circularly filled and will wrap around.
                Use matrix modeling to shift and scale the texture onto the coordinate plane.
                """
                The texture is circularly filled and will wrap around.
                Use matrix modeling to shift and scale the texture onto the coordinate plane.
                """
+               #resize texture
+               self._resize_texture()
                #setup texture
                #setup texture
-               glBindTexture(GL_TEXTURE_2D, self._waterfall_texture)
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
-               glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
+               GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture)
+               GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, GL.GL_LINEAR)
+               GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, GL.GL_LINEAR)
+               GL.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL.GL_REPEAT)
+               GL.glTexEnvi(GL.GL_TEXTURE_ENV, GL.GL_TEXTURE_ENV_MODE, GL.GL_REPLACE)
                #write the buffer to the texture
                while self._buffer:
                #write the buffer to the texture
                while self._buffer:
-                       glTexSubImage2D(GL_TEXTURE_2D, 0, 0, self._pointer, self._fft_size, 1, GL_RGBA, GL_UNSIGNED_BYTE, self._buffer.pop(0))
+                       GL.glTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, self._pointer, self._fft_size, 1, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, self._buffer.pop(0))
                        self._pointer = (self._pointer + 1)%self._num_lines
                #begin drawing
                        self._pointer = (self._pointer + 1)%self._num_lines
                #begin drawing
-               glEnable(GL_TEXTURE_2D)
-               glPushMatrix()
+               GL.glEnable(GL.GL_TEXTURE_2D)
+               GL.glPushMatrix()
                #matrix scaling
                #matrix scaling
-               glTranslatef(self.padding_left, self.padding_top, 0)
-               glScalef(
+               GL.glTranslatef(self.padding_left, self.padding_top, 0)
+               GL.glScalef(
                        float(self.width-self.padding_left-self.padding_right),
                        float(self.height-self.padding_top-self.padding_bottom),
                        1.0,
                )
                #draw texture with wrapping
                        float(self.width-self.padding_left-self.padding_right),
                        float(self.height-self.padding_top-self.padding_bottom),
                        1.0,
                )
                #draw texture with wrapping
-               glBegin(GL_QUADS)
+               GL.glBegin(GL.GL_QUADS)
                prop_y = float(self._pointer)/(self._num_lines-1)
                prop_x = float(self._fft_size)/ceil_log2(self._fft_size)
                off = 1.0/(self._num_lines-1)
                prop_y = float(self._pointer)/(self._num_lines-1)
                prop_x = float(self._fft_size)/ceil_log2(self._fft_size)
                off = 1.0/(self._num_lines-1)
-               glTexCoord2f(0, prop_y+1-off)
-               glVertex2f(0, 1)
-               glTexCoord2f(prop_x, prop_y+1-off)
-               glVertex2f(1, 1)
-               glTexCoord2f(prop_x, prop_y)
-               glVertex2f(1, 0)
-               glTexCoord2f(0, prop_y)
-               glVertex2f(0, 0)
-               glEnd()
-               glPopMatrix()
-               glDisable(GL_TEXTURE_2D)
+               GL.glTexCoord2f(0, prop_y+1-off)
+               GL.glVertex2f(0, 1)
+               GL.glTexCoord2f(prop_x, prop_y+1-off)
+               GL.glVertex2f(1, 1)
+               GL.glTexCoord2f(prop_x, prop_y)
+               GL.glVertex2f(1, 0)
+               GL.glTexCoord2f(0, prop_y)
+               GL.glVertex2f(0, 0)
+               GL.glEnd()
+               GL.glPopMatrix()
+               GL.glDisable(GL.GL_TEXTURE_2D)
 
        def _populate_point_label(self, x_val, y_val):
                """
 
        def _populate_point_label(self, x_val, y_val):
                """
@@ -183,7 +167,7 @@ class waterfall_plotter(grid_plotter_base):
                @param y_val the current y value
                @return a value string with units
                """
                @param y_val the current y value
                @return a value string with units
                """
-               return '%s: %s %s'%(self.x_label, common.label_format(x_val), self.x_units)
+               return '%s: %s'%(self.x_label, common.eng_format(x_val, self.x_units))
 
        def _draw_legend(self):
                """
 
        def _draw_legend(self):
                """
@@ -196,11 +180,11 @@ class waterfall_plotter(grid_plotter_base):
                x = self.width - self.padding_right + LEGEND_LEFT_PAD
                for i in range(LEGEND_NUM_BLOCKS):
                        color = COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))]
                x = self.width - self.padding_right + LEGEND_LEFT_PAD
                for i in range(LEGEND_NUM_BLOCKS):
                        color = COLORS[self._color_mode][int(255*i/float(LEGEND_NUM_BLOCKS-1))]
-                       glColor4f(*map(lambda c: ord(c)/255.0, color))
+                       GL.glColor4f(*map(lambda c: ord(c)/255.0, color))
                        y = self.height - (i+1)*block_height - self.padding_bottom
                        self._draw_rect(x, y, LEGEND_WIDTH, block_height)
                #draw rectangle around color scale border
                        y = self.height - (i+1)*block_height - self.padding_bottom
                        self._draw_rect(x, y, LEGEND_WIDTH, block_height)
                #draw rectangle around color scale border
-               glColor3f(*LEGEND_BORDER_COLOR_SPEC)
+               GL.glColor3f(*LEGEND_BORDER_COLOR_SPEC)
                self._draw_rect(x, self.padding_top, LEGEND_WIDTH, legend_height, fill=False)
                #draw each legend label
                label_spacing = float(legend_height)/(LEGEND_NUM_LABELS-1)
                self._draw_rect(x, self.padding_top, LEGEND_WIDTH, legend_height, fill=False)
                #draw each legend label
                label_spacing = float(legend_height)/(LEGEND_NUM_LABELS-1)
@@ -224,9 +208,9 @@ class waterfall_plotter(grid_plotter_base):
                self._buffer = list()
                self._pointer = 0
                if self._num_lines and self._fft_size:
                self._buffer = list()
                self._pointer = 0
                if self._num_lines and self._fft_size:
-                       glBindTexture(GL_TEXTURE_2D, self._waterfall_texture)
+                       GL.glBindTexture(GL.GL_TEXTURE_2D, self._waterfall_texture)
                        data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring()
                        data = numpy.zeros(self._num_lines*self._fft_size*4, numpy.uint8).tostring()
-                       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL_RGBA, GL_UNSIGNED_BYTE, data)
+                       GL.glTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGBA, ceil_log2(self._fft_size), self._num_lines, 0, GL.GL_RGBA, GL.GL_UNSIGNED_BYTE, data)
                self._resize_texture_flag = False
 
        def set_color_mode(self, color_mode):
                self._resize_texture_flag = False
 
        def set_color_mode(self, color_mode):
@@ -239,7 +223,7 @@ class waterfall_plotter(grid_plotter_base):
                self.lock()
                if color_mode in COLORS.keys():
                        self._color_mode = color_mode
                self.lock()
                if color_mode in COLORS.keys():
                        self._color_mode = color_mode
-                       self.changed(True)
+                       self._legend_cache.changed(True)
                self.update()
                self.unlock()
 
                self.update()
                self.unlock()
 
@@ -268,7 +252,7 @@ class waterfall_plotter(grid_plotter_base):
                if self._minimum != minimum or self._maximum != maximum:
                        self._minimum = minimum
                        self._maximum = maximum
                if self._minimum != minimum or self._maximum != maximum:
                        self._minimum = minimum
                        self._maximum = maximum
-                       self.changed(True)
+                       self._legend_cache.changed(True)
                if self._fft_size != len(samples):
                        self._fft_size = len(samples)
                        self._resize_texture(True)
                if self._fft_size != len(samples):
                        self._fft_size = len(samples)
                        self._resize_texture(True)
@@ -279,4 +263,5 @@ class waterfall_plotter(grid_plotter_base):
                #convert the samples to RGBA data
                data = numpy.choose(samples, COLORS[self._color_mode]).tostring()
                self._buffer.append(data)
                #convert the samples to RGBA data
                data = numpy.choose(samples, COLORS[self._color_mode]).tostring()
                self._buffer.append(data)
+               self._waterfall_cache.changed(True)
                self.unlock()
                self.unlock()