Merged r10463:10658 from jblum/gui_guts into trunk. Trunk passes distcheck.
[debian/gnuradio] / gr-wxgui / src / python / plotter / common.py
diff --git a/gr-wxgui/src/python/plotter/common.py b/gr-wxgui/src/python/plotter/common.py
new file mode 100644 (file)
index 0000000..7699986
--- /dev/null
@@ -0,0 +1,131 @@
+#
+# Copyright 2009 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GNU Radio is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+#
+
+import threading
+import time
+import math
+import wx
+
+##################################################
+# Number formatting
+##################################################
+def get_exp(num):
+       """
+       Get the exponent of the number in base 10.
+       @param num the floating point number
+       @return the exponent as an integer
+       """
+       if num == 0: return 0
+       return int(math.floor(math.log10(abs(num))))
+
+def get_si_components(num):
+       """
+       Get the SI units for the number.
+       Extract the coeff and exponent of the number.
+       The exponent will be a multiple of 3.
+       @param num the floating point number
+       @return the tuple coeff, exp, prefix
+       """
+       num = float(num)
+       exp = get_exp(num)
+       exp -= exp%3
+       exp = min(max(exp, -24), 24) #bounds on SI table below
+       prefix = {
+               24: 'Y', 21: 'Z',
+               18: 'E', 15: 'P',
+               12: 'T', 9: 'G',
+               6: 'M', 3: 'k',
+               0: '',
+               -3: 'm', -6: 'u',
+               -9: 'n', -12: 'p',
+               -15: 'f', -18: 'a',
+               -21: 'z', -24: 'y',
+       }[exp]
+       coeff = num/10**exp
+       return coeff, exp, prefix
+
+def sci_format(num):
+       """
+       Format a floating point number into scientific notation.
+       @param num the number to format
+       @return a label string
+       """
+       coeff, exp, prefix = get_si_components(num)
+       if -3 <= exp < 3: return '%g'%num
+       return '%.3ge%d'%(coeff, exp)
+
+def eng_format(num, units=''):
+       """
+       Format a floating point number into engineering notation.
+       @param num the number to format
+       @param units the units to append
+       @return a label string
+       """
+       coeff, exp, prefix = get_si_components(num)
+       if -3 <= exp < 3: return '%g'%num
+       return '%g%s%s%s'%(coeff, units and ' ' or '', prefix, units)
+
+##################################################
+# Interface with thread safe lock/unlock
+##################################################
+class mutex(object):
+       _lock = threading.Lock()
+       def lock(self): self._lock.acquire()
+       def unlock(self): self._lock.release()
+
+##################################################
+# Periodic update thread for point label
+##################################################
+class point_label_thread(threading.Thread, mutex):
+
+       def __init__(self, plotter):
+               self._plotter = plotter
+               self._coor_queue = list()
+               #bind plotter mouse events
+               self._plotter.Bind(wx.EVT_MOTION, lambda evt: self.enqueue(evt.GetPosition()))
+               self._plotter.Bind(wx.EVT_LEAVE_WINDOW, lambda evt: self.enqueue(None))
+               #start the thread
+               threading.Thread.__init__(self)
+               self.start()
+
+       def enqueue(self, coor):
+               self.lock()
+               self._coor_queue.append(coor)
+               self.unlock()
+
+       def run(self):
+               last_ts = time.time()
+               last_coor = coor = None
+               try: 
+                       while True:
+                               time.sleep(1.0/30.0)
+                               self.lock()
+                               #get most recent coor change
+                               if self._coor_queue:
+                                       coor = self._coor_queue[-1]
+                                       self._coor_queue = list()
+                               self.unlock()
+                               #update if coor change, or enough time expired
+                               if last_coor != coor or (time.time() - last_ts) > (1.0/2.0):
+                                       self._plotter.set_point_label_coordinate(coor)
+                                       last_coor = coor
+                                       last_ts = time.time()
+               except wx.PyDeadObjectError: pass