# HG changeset patch
# User Jim Unroe <rock.unroe@gmail.com>
# Date 1358631445 18000
# Node ID 810d80a586fd7a5a2a3875dc75489d71e5b801a5
# Parent  d3fcca2f31731a41d7c79e86a059465b25f264ff
[mq]: float_setting_callback_example.patch

diff -r d3fcca2f3173 -r 810d80a586fd chirp/settings.py
--- a/chirp/settings.py	Sat Jan 19 14:51:54 2013 -0500
+++ b/chirp/settings.py	Sat Jan 19 16:37:25 2013 -0500
@@ -28,16 +28,20 @@
     def __init__(self):
         self._current = None
         self._has_changed = False
+        self._callback = lambda x: x
 
     def changed(self):
         """Returns True if the setting has been changed since init"""
         return self._has_changed
 
+    def set_callback(self, callback):
+        self._callback = callback
+
     def set_value(self, value):
         """Sets the current value, triggers changed"""
         if self._current != None and value != self._current:
             self._has_changed = True
-        self._current = value
+        self._current = self._callback(value)
 
     def get_value(self):
         """Gets the current value"""
@@ -81,6 +85,45 @@
         """Returns the step increment"""
         return self._step
 
+class RadioSettingValueFloat(RadioSettingValue):
+    """A floating-point setting"""
+    def __init__(self, minval, maxval, current, resolution=0.001, precision=5):
+        RadioSettingValue.__init__(self)
+        self._min = minval
+        self._max = maxval
+        self._res = resolution
+        self._pre = precision
+        self.set_value(current)
+
+    def format(self, value=None):
+        """Formats the value into a string"""
+        if value is None:
+            value = self._current
+        fmt_string = "%%.%if" % self._pre
+        print fmt_string
+        return fmt_string % value
+
+    def set_value(self, value):
+        try:
+            value = float(value)
+        except:
+            raise InvalidValueError("A floating point value is required")
+        if value > self._max or value < self._min:
+            raise InvalidValueError("Value %s not in range %s-%s" % (
+                    self.format(value),
+                    self.format(self._min), self.format(self._max)))
+        
+        # FIXME: honor resolution
+
+        RadioSettingValue.set_value(self, value)
+
+    def get_min(self):
+        """Returns the minimum allowed value"""
+        return self._min
+
+    def get_max(self):
+        """Returns the maximum allowed value"""
+
 class RadioSettingValueBoolean(RadioSettingValue):
     """A boolean setting"""
     def __init__(self, current):
diff -r d3fcca2f3173 -r 810d80a586fd chirp/uv5r.py
--- a/chirp/uv5r.py	Sat Jan 19 14:51:54 2013 -0500
+++ b/chirp/uv5r.py	Sat Jan 19 16:37:25 2013 -0500
@@ -21,7 +21,8 @@
 from chirp.settings import RadioSetting, RadioSettingGroup, \
     RadioSettingValueInteger, RadioSettingValueList, \
     RadioSettingValueList, RadioSettingValueBoolean, \
-    RadioSettingValueString
+    RadioSettingValueString, RadioSettingValueFloat, \
+    InvalidValueError
 
 MEM_FORMAT = """
 #seekto 0x0008;
@@ -944,6 +945,18 @@
                                                     STEP_LIST[self._memobj.vfob.step]))
             workmode.append(rs)
 
+        test = RadioSettingGroup("test", "test")
+        group.append(test)
+        def my_validate(value):
+            if value < 300 and value > 200:
+                raise InvalidValueError("Can't be between 200-300")
+            return value
+
+        val = RadioSettingValueFloat(136, 450, 146.52)
+        val.set_callback(my_validate)
+        rs = RadioSetting("footest", "Foo Test", val)
+        test.append(rs)
+
         return group
 
     def set_settings(self, settings):
@@ -963,6 +976,8 @@
                     obj = _settings
                     setting = element.get_name()
                 print "Setting %s = %s" % (setting, element.value)
+                if setting == "footest":
+                    return # This is a fake setting!
                 setattr(obj, setting, element.value)
             except Exception, e:
                 print element.get_name()
diff -r d3fcca2f3173 -r 810d80a586fd chirpui/settingsedit.py
--- a/chirpui/settingsedit.py	Sat Jan 19 14:51:54 2013 -0500
+++ b/chirpui/settingsedit.py	Sat Jan 19 16:37:25 2013 -0500
@@ -63,7 +63,12 @@
         if self._top_setting_group is None:
             return
 
-        job = common.RadioJob(None, "set_settings", self._top_setting_group)
+        def setting_cb(result):
+            if isinstance(result, Exception):
+                common.show_error(_("Error in setting value: %s") % result)
+
+        job = common.RadioJob(setting_cb, "set_settings",
+                              self._top_setting_group)
         job.set_desc("Setting radio settings")
         self._rthread.submit(job)
 
@@ -73,6 +78,8 @@
             adj.configure(value.get_value(),
                           value.get_min(), value.get_max(),
                           value.get_step(), 1, 0)
+        elif isinstance(value, settings.RadioSettingValueFloat):
+            widget.set_text(value.format())
         elif isinstance(value, settings.RadioSettingValueBoolean):
             widget.set_active(value.get_value())
         elif isinstance(value, settings.RadioSettingValueList):
@@ -89,9 +96,11 @@
             print "Unsupported widget type %s for %s" % (value.__class__,
                                                          element.get_name())
             
-    def _save_setting(self, widget, value):
+    def _do_save_setting(self, widget, value):
         if isinstance(value, settings.RadioSettingValueInteger):
             value.set_value(widget.get_adjustment().get_value())
+        elif isinstance(value, settings.RadioSettingValueFloat):
+            value.set_value(widget.get_text())
         elif isinstance(value, settings.RadioSettingValueBoolean):
             value.set_value(widget.get_active())
         elif isinstance(value, settings.RadioSettingValueList):
@@ -105,6 +114,12 @@
 
         self._save_settings()
 
+    def _save_setting(self, widget, value):
+        try:
+            self._do_save_setting(widget, value)
+        except settings.InvalidValueError, e:
+            common.show_error(_("Invalid setting value: %s") % e)
+
     def _build_ui_group(self, group):
         def pack(widget, pos):
             self._table.attach(widget, pos, pos+1, self._index, self._index+1,
@@ -139,6 +154,9 @@
                     widget = gtk.SpinButton()
                     print "Digits: %i" % widget.get_digits()
                     signal = "value-changed"
+                elif isinstance(value, settings.RadioSettingValueFloat):
+                    widget = gtk.Entry()
+                    signal = "focus-out-event"
                 elif isinstance(value, settings.RadioSettingValueBoolean):
                     widget = gtk.CheckButton(_("Enabled"))
                     signal = "toggled"
@@ -160,7 +178,11 @@
                 arraybox.pack_start(lalign, 1, 1, 1)
                 widget.show()
                 self._load_setting(value, widget)
-                widget.connect(signal, self._save_setting, value)
+                if signal == "focus-out-event":
+                    widget.connect(signal, lambda w, e, v:
+                                       self._save_setting(w, v), value)
+                else:
+                    widget.connect(signal, self._save_setting, value)
 
             self._index += 1
 
