From 545d8877c57d6e199f8d6e7cdc755c76d60bf4c2 2014-01-16 10:55:58
From: Jonathan Frederic <jdfreder@calpoly.edu>
Date: 2014-01-16 10:55:58
Subject: [PATCH] Add float range widget

---

diff --git a/IPython/html/widgets/float_range/__init__.py b/IPython/html/widgets/float_range/__init__.py
new file mode 100644
index 0000000..a987e6f
--- /dev/null
+++ b/IPython/html/widgets/float_range/__init__.py
@@ -0,0 +1 @@
+from widget import FloatRangeWidget
\ No newline at end of file
diff --git a/IPython/html/widgets/float_range/model.js b/IPython/html/widgets/float_range/model.js
new file mode 100644
index 0000000..fad0d59
--- /dev/null
+++ b/IPython/html/widgets/float_range/model.js
@@ -0,0 +1,2 @@
+var FloatRangeWidgetModel = IPython.WidgetModel.extend({});
+IPython.notebook.widget_manager.register_widget_model('FloatRangeWidgetModel', FloatRangeWidgetModel);
diff --git a/IPython/html/widgets/float_range/view_slider.js b/IPython/html/widgets/float_range/view_slider.js
new file mode 100644
index 0000000..217cc7e
--- /dev/null
+++ b/IPython/html/widgets/float_range/view_slider.js
@@ -0,0 +1,44 @@
+var FloatSliderView = IPython.WidgetView.extend({
+    
+    // Called when view is rendered.
+    render : function(){
+        this.$el
+            .html('')
+            .addClass(this.model.comm.comm_id);
+        this.$slider = $('<div />')
+                        .slider({})
+                        .addClass('slider');
+        
+        // Put the slider in a container 
+        this.$slider_container = $('<div />')
+                                .css('padding-top', '4px')
+                                .css('padding-bottom', '4px')
+                                .append(this.$slider);    
+        this.$el.append(this.$slider_container);
+        
+        // Set defaults.
+        this.update();
+    },
+    
+    // Handles: Backend -> Frontend Sync
+    //          Frontent -> Frontend Sync
+    update : function(){
+        // Slider related keys.
+        var _keys = ['value', 'step', 'max', 'min', 'disabled', 'orientation'];
+        for (var index in _keys) {
+            var key = _keys[index];
+            if (this.model.get(key) != undefined) {
+                this.$slider.slider("option", key, this.model.get(key));
+            }
+        }
+    },
+    
+    // Handles: User input
+    events: { "slide" : "handleSliderChange" }, 
+    handleSliderChange: function(e, ui) { 
+        this.model.set('value', ui.value); 
+        this.model.apply(this);
+    },
+});
+
+IPython.notebook.widget_manager.register_widget_view('FloatSliderView', FloatSliderView);
diff --git a/IPython/html/widgets/float_range/view_text.js b/IPython/html/widgets/float_range/view_text.js
new file mode 100644
index 0000000..d2f5a6a
--- /dev/null
+++ b/IPython/html/widgets/float_range/view_text.js
@@ -0,0 +1,71 @@
+
+var FloatTextView = IPython.WidgetView.extend({
+    
+    // Called when view is rendered.
+    render : function(){
+        this.$el
+            .html('')
+            .addClass(this.model.comm.comm_id);
+        this.$textbox = $('<input type="text" />')
+            .addClass('input')
+            .appendTo(this.$el);
+        this.update(); // Set defaults.
+    },
+    
+    // Handles: Backend -> Frontend Sync
+    //          Frontent -> Frontend Sync
+    update : function(){
+        var value = this.model.get('value');
+        if (!this.changing && parseFloat(this.$textbox.val()) != value) {
+            this.$textbox.val(value);
+        }
+        
+        if (this.model.get('disabled')) {
+            this.$textbox.attr('disabled','disabled');
+        } else {
+            this.$textbox.removeAttr('disabled');
+        }
+    },
+    
+    
+    events: {"keyup input" : "handleChanging",
+            "paste input" : "handleChanging",
+            "cut input" : "handleChanging",
+            "change input" : "handleChanged"}, // Fires only when control is validated or looses focus.
+    
+    // Handles and validates user input.
+    handleChanging: function(e) { 
+        
+        // Try to parse value as a float.
+        var numericalValue = 0.0;
+        if (e.target.value != '') {
+            numericalValue = parseFloat(e.target.value);
+        }
+        
+        // If parse failed, reset value to value stored in model.
+        if (isNaN(numericalValue)) {
+            e.target.value = this.model.get('value');
+        } else if (!isNaN(numericalValue)) {
+            numericalValue = Math.min(this.model.get('max'), numericalValue);
+            numericalValue = Math.max(this.model.get('min'), numericalValue);
+            
+            // Apply the value if it has changed.
+            if (numericalValue != this.model.get('value')) {
+                this.changing = true;
+                this.model.set('value', numericalValue);
+                this.model.apply(this);
+                this.changing = false;
+            }
+        }
+    },
+    
+    // Applies validated input.
+    handleChanged: function(e) { 
+        // Update the textbox
+        if (this.model.get('value') != e.target.value) {
+            e.target.value = this.model.get('value');
+        }
+    }
+});
+
+IPython.notebook.widget_manager.register_widget_view('FloatTextView', FloatTextView);
diff --git a/IPython/html/widgets/float_range/widget.py b/IPython/html/widgets/float_range/widget.py
new file mode 100644
index 0000000..7732ff3
--- /dev/null
+++ b/IPython/html/widgets/float_range/widget.py
@@ -0,0 +1,17 @@
+import os
+
+from ..widget import Widget
+from IPython.utils.traitlets import Unicode, Float, Bool
+from IPython.utils.javascript import display_all_js
+
+class FloatRangeWidget(Widget):
+    target_name = Unicode('FloatRangeWidgetModel')
+    default_view_name = Unicode('FloatSliderView')
+    _keys = ['value', 'step', 'max', 'min', 'disabled', 'orientation']
+    
+    value = Float(0.0) 
+    max = Float(100.0) # Max value
+    min = Float(0.0) # Min value
+    disabled = Bool(False) # Enable or disable user changes
+    step = Float(0.1) # Minimum step that the value can take (ignored by some views)
+    orientation = Unicode(u'horizontal') # Vertical or horizontal (ignored by some views)