Ticket #1322: manipulate_take3_part4.patch

File manipulate_take3_part4.patch, 24.3 KB (added by William Stein, 15 years ago)
  • sage/server/notebook/all.py

    # HG changeset patch
    # User William Stein <wstein@gmail.com>
    # Date 1204615417 21600
    # Node ID 6f73ec3c47727f583703041009c39a6b12f1a27a
    # Parent  c1b3be3bcc9235bb90637864aad61e6cea471e2b
    trac #1322 -- manipulate for the sage notebook.
    
    diff -r c1b3be3bcc92 -r 6f73ec3c4772 sage/server/notebook/all.py
    a b from notebook_object import notebook, in 
    1414
    1515from sagetex import sagetex
    1616
    17 from manipulate import manipulate, text_box, slider
     17from manipulate import manipulate, input_box, slider
  • sage/server/notebook/cell.py

    diff -r c1b3be3bcc92 -r 6f73ec3c4772 sage/server/notebook/cell.py
    a b r"""nodoctest 
    1 r"""nodoctest
     1"""nodoctest
    22A Cell.
    33
    44A cell is a single input/output block.  Worksheets are built out of a
    class Cell(Cell_generic): 
    298298            del self.manipulate
    299299
    300300    def set_input_text(self, input):
     301
     302        # Stuff to deal with manipulate
    301303        if input.startswith('%manipulate'):
    302304            self.manipulate = input[len('%manipulate')+1:]
    303305            self.__version = 1+self.version()
    class Cell(Cell_generic): 
    328330        self.__changed_input = new_text
    329331        self.__in = new_text
    330332
    331     def set_output_text(self, output, html, sage=None):
     333    def set_output_text(self, output, html, sage=None):           
     334        if output.count('<?TEXT>') > 1:
     335            html = '<h3><font color="red">WARNING: multiple @manipulates in one cell disabled (not yet implemented).</font></h3>'
     336            output = ''
     337
     338        # In manipulating mode, we just save the computed output
     339        # (do not overwrite).
    332340        if self.is_manipulating():
    333             self._manipulate_output = (output,html)
     341            self._manipulate_output = (output, html)
    334342            return
    335            
     343       
    336344        if hasattr(self, '_html_cache'):
    337345            del self._html_cache
     346
    338347        output = output.replace('\r','')
    339348        if len(output) > MAX_OUTPUT:
    340349            url = ""
    class Cell(Cell_generic): 
    390399
    391400    def output_text(self, ncols=0, html=True, raw=False, allow_manipulate=True):
    392401        if allow_manipulate and hasattr(self, '_manipulate_output'):
    393             z = self.output_text(ncols,html,raw,allow_manipulate=False)
    394             try:
    395                 # Fill in the input valuees
    396                 # TODO -- redo
    397                 if False and hasattr(self, 'manipulate'):
    398                     inp = self.manipulate
    399                     i = inp.lstrip().find('\n'); inp = inp[:i]
    400                     i = inp.rfind('.'); inp = inp[i+1:]
    401                     var, value = inp[:i].split('=')
    402                     z = z.replace('<?%s>'%var, value)
    403                
    404                 # Fill in the output template
    405                 output,html = self._manipulate_output
    406                 z = z.replace('<?TEXT>', output.lstrip())
    407                 z = z.replace('<?HTML>', html)
    408                
     402            # Get the input template
     403            z = self.output_text(ncols, html, raw, allow_manipulate=False)
     404            if not '<?TEXT>' in z or not '<?HTML>' in z:
    409405                return z
    410             except (ValueError, AttributeError), msg:
    411                 print msg
    412                 pass
    413            
     406            if ncols:
     407                # Get the output template
     408                try:
     409                    # Fill in the output template
     410                    output,html = self._manipulate_output
     411                    z = z.replace('<?TEXT>', output.replace('<','&lt;'))
     412                    z = z.replace('<?HTML>', html)
     413                    return z
     414                except (ValueError, AttributeError), msg:
     415                    print msg
     416                    pass
     417            else:
     418                # Get rid of the manipulate div to avoid updating the wrong output location
     419                # during manipulate.
     420                return ''
     421
     422        is_manipulate = '@manipulate' in ''.join(self.input_text().split())
     423        if ncols == 0 and is_manipulate:
     424            return '<h2>Click to the left again to hide and once more to show the manipulation window</h2>'
     425
    414426        s = self.__out
    415427       
    416428        if raw:
    class Cell(Cell_generic): 
    444456                t += format(s[:i]) + format_html(s[i+6:j])
    445457                s = s[j+7:]
    446458            s = t
    447             if not self.is_html() and len(s.strip()) > 0:
     459            if not is_manipulate and not self.is_html() and len(s.strip()) > 0:
    448460                s = '<pre class="shrunk">' + s.strip('\n') + '</pre>'
    449 
    450461
    451462        return s.strip('\n')
    452463
    class Cell(Cell_generic): 
    700711
    701712    def html_out(self, ncols=0, do_print=False):
    702713        out_nowrap = self.output_text(0, html=True)
     714
    703715        out_html = self.output_html()
    704        
    705716        if self.introspect():
    706717            out_wrap = out_nowrap
    707718        else:
    class Cell(Cell_generic): 
    722733        else:
    723734            prnt = ""
    724735
    725         out = """<div class="cell_output_%s%s" id="cell_output_%s">%s</div>
    726                  <div class="cell_output_%snowrap_%s" id="cell_output_nowrap_%s">%s</div>
    727                  <div class="cell_output_html_%s" id="cell_output_html_%s">%s </div>
    728                  """%(prnt, typ, self.__id, out_wrap,
    729                       prnt, typ, self.__id, out_nowrap,
    730                       typ, self.__id, out_html)
     736        out_wrap   = '<div class="cell_output_%s%s" id="cell_output_%s">%s</div>'%(
     737            prnt, typ,self.__id, out_wrap)
     738        out_nowrap = '<div class="cell_output_%snowrap_%s" id="cell_output_nowrap_%s">%s</div>'%(
     739            prnt, typ, self.__id, out_nowrap)
     740        out_html   = '<div class="cell_output_html_%s" id="cell_output_html_%s">%s </div>'%(
     741            typ, self.__id, out_html)
    731742
     743        out = "%s%s%s"%(out_wrap, out_nowrap, out_html)
    732744        s = top + out + '</div>'
    733745
    734746        r = ''
  • sage/server/notebook/css.py

    diff -r c1b3be3bcc92 -r 6f73ec3c4772 sage/server/notebook/css.py
    a b div.cell_div_output_hidden { 
    11681168}
    11691169
    11701170pre.shrunk {
    1171 /*   height:0px; */
    11721171  font-size:12pt;
    11731172  margin:0px;
    11741173}
  • sage/server/notebook/js.py

    diff -r c1b3be3bcc92 -r 6f73ec3c4772 sage/server/notebook/js.py
    a b import keyboards 
    2020#       Copyright (C) 2006 William Stein <wstein@gmail.com>
    2121#                     2006 Tom Boothby <boothby@u.washington.edu>
    2222#
    23 #  Distributed under the terms of the GNU General Public License (GPL)
    24 #                  http://www.gnu.org/licenses/
     23#   Released under the *modified* BSD license.
     24#     Tom wrote in email to me at wstein@gmail.com on March 2, 2008: "You have my permission
     25#     to change the license on anything I've contributed to the notebook, to whatever suits you."
     26#
    2527###########################################################################
    2628
    2729
    function cell_set_not_evaluated(id) { 
    17921794}
    17931795
    17941796function cell_set_running(id) {
    1795     set_output_text(id, '', '', '', '', '');
     1797    set_output_text(id, '', '', '', '', '', 1);   // the 1 means no manipulation dynamics
    17961798    cell_output_set_type(id, 'wrap');
    17971799    var cell_div = get_element('cell_div_output_' + id);
    17981800    cell_div.className = 'cell_output_running';
    function cancel_update_check() { 
    18371839    document.title = original_title;
    18381840}
    18391841
    1840 function set_output_text(id, text, wrapped_text, output_html, status, introspect_html) {
    1841     /* fill in output text got so far */
    1842     var cell_output = get_element('cell_output_' + id);
    1843     var cell_output_nowrap = get_element('cell_output_nowrap_' + id);
    1844     var cell_output_html = get_element('cell_output_html_' + id);
     1842function set_output_text(id, text, wrapped_text, output_html, status, introspect_html, no_manip) {
     1843    var cell_manip = get_element("cell-manipulate-" + id);
     1844    if (!no_manip && cell_manip) {
     1845        var i = wrapped_text.indexOf('<?START>');
     1846        var j = wrapped_text.indexOf('<?END>');
     1847        if (i == -1 || j == -1) {
     1848            alert("bug -- manipulate wrapped text is invalid" + wrapped_text);
     1849            return;
     1850        }
     1851        var new_manip_output = wrapped_text.slice(i+8,j);
     1852        cell_manip.innerHTML = new_manip_output;
     1853    } else {
     1854        /* fill in output text got so far */
     1855        var cell_output = get_element('cell_output_' + id);
     1856        var cell_output_nowrap = get_element('cell_output_nowrap_' + id);
     1857        var cell_output_html = get_element('cell_output_html_' + id);
    18451858
    1846     cell_output.innerHTML = wrapped_text;
    1847     cell_output_nowrap.innerHTML = text;
    1848     cell_output_html.innerHTML = output_html;
     1859        cell_output.innerHTML = wrapped_text;
     1860        cell_output_nowrap.innerHTML = text;
     1861        cell_output_html.innerHTML = output_html;
     1862    }
    18491863
    18501864    if (status == 'd') {
    18511865         cell_set_done(id);
    function check_for_cell_update_callback( 
    19872001    output_text = output_text.replace(/<script.*?>(.|\n|\r)*?<\/script>/gim, '&lt;script&gt;');
    19882002    output_text_wrapped = eval_script_tags(output_text_wrapped);
    19892003    output_html = eval_script_tags(output_html);
    1990    
     2004
    19912005    set_output_text(id, output_text, output_text_wrapped,
    19922006                    output_html, stat, introspect_html);
    19932007
    function manipulate(id, input) { 
    25062520            'newcell=0' + '&id=' + id + '&input='+escape0('%manipulate\n' + input));
    25072521}
    25082522
    2509 
    2510 
    25112523/********************* js math ***************************/
    25122524
    25132525
  • sage/server/notebook/manipulate.py

    diff -r c1b3be3bcc92 -r 6f73ec3c4772 sage/server/notebook/manipulate.py
    a b notebook. 
    66
    77The controls are:
    88\begin{itemize}
    9     \item TextBox -- a text box
     9    \item InputBox -- a input box
    1010    \item Slider -- a slider
    1111\end{itemize}
    1212
    AUTHOR: 
    1717       design and prototypes.
    1818
    1919TODO:
    20    [ ] get sliders to work
    21    [ ] default values; values after move slider
     20   [X] get sliders to work; values after move slider
     21
     22   [x] default values
     23   [ ] get everything in the current version to work 100% bug free (including some style). post bundle.
     24       BUGS:
     25          [x] have default values set from the get go
     26          [x] spacing around sliders; also need to have labels 
     27          [x] when re-evaluate input, make sure to clear output so cell-manipulate-id div is gone.
     28          [ ] if you  use a manipulate control after restarting, doesn't work.   Need to reset it.  How?
     29          [x] two manipulates in one cell -- what to do?
     30          [ ] display html parts of output as html
     31
     32   [ ] implement in non-word wrap mode too.
    2233   [ ] implement a color object
     34   [ ] cool looking sliders:
     35        http://jqueryfordesigners.com/demo/slider-gallery.html
    2336
    2437PLANS and IDEAS:
    2538   [ ] automagically determine the type of control from the default
    PLANS and IDEAS: 
    3346        * u = Graphic            a locator in a 2d plot  (Graphic is a 2d graphics objects)
    3447        * u = True or u = False  a checkbox
    3548        * u = color(...)         a color slider
    36         * u = "string"           text input field
     49        * u = "string"           input field
    3750        * u = ('label', obj)     obj can be any of the above; control is labeled with
    3851                                 the given label
    3952        * u = element            if parent(element)._manipulate_control_(element) is
    40                                  defined, then it will be used.  Otherwise make a
    41                                  text input that coerces input to parent(element)
     53                                 defined, then it will be used.  Otherwise make an
     54                                 input that coerces input to parent(element)
    4255   [ ] tag_cell('foo') -- makes it so one can refer to the current cell
    4356       from elsewhere using the tag foo instead of the cell id number
    4457       This involves doing something with SAGE_CELL_ID and the cell_id()
    ELEMENTS: 
    7083          type -- button, checkbox, file, password, radio, slider, text, setter_bar, drop_down
    7184   [ ] setter bar (buttons)
    7285   [ ] checkbox
    73    [ ] color slider
     86   [ ] color slider:
     87          http://interface.eyecon.ro/demos/slider_colorpicker.html
    7488   [ ] blank input field
    7589   [ ] 2d slider
    7690   [ ] locator in a graphic
    import inspect 
    94108import inspect
    95109
    96110SAGE_CELL_ID = 0
    97 vars = {}
     111state = {}
    98112
    99113_k = 0
    100 def new_adapt_name():
     114def new_adapt_number():
    101115    global _k
    102116    _k += 1
    103     return 'adapt%s'%_k
     117    return _k
    104118   
    105119
    106120def html(s):
    def html(s): 
    116130    """
    117131    print "<html>%s</html>"%s
    118132
    119 def html_slider(id, callback, margin=0):
    120     s = """<div id='%s' class='ui-slider-1' style="margin:%spx;"><span class='ui-slider-handle'></span></div>"""%(
    121         id, int(margin))
     133def html_slider(label, id, callback, steps, default=0, margin=0):
     134    s = """<table style='margin:0px;padding:0px;'><tr><td>%s</td><td><div id='%s' class='ui-slider-1' style='padding:0px;margin:%spx;'><span class='ui-slider-handle'></span></div></div></td></tr></table>"""%(
     135        label, id, int(margin))
    122136
    123137    # We now generat javascript that gets run after the above div gets
    124138    # inserted. This happens because of the setTimeout function below
    def html_slider(id, callback, margin=0): 
    126140    s += """
    127141    <script>
    128142    setTimeout(function() {
    129         $('#%s').slider();
    130         $('#%s').bind('click', function () { var position = $('#%s').slider('value',0); %s; });
    131     }, 1)
     143        $('#%s').slider({
     144               stepping: 1, minValue: 0, maxValue: %s, startValue: %s,
     145               change: function () { var position = Math.ceil($('#%s').slider('value')); %s; }
     146        });
     147    }, 1);      /* setTimeout might be a hack? This could lead to a bug?  */
    132148    </script>
    133     """%(id, id, id, callback)
     149    """%(id, steps-1, default, id, callback)
    134150    return s
    135151   
    136152
    class ManipulateControl: 
    138154    """
    139155    Base class for manipulate controls.
    140156    """
    141     def __init__(self, f, var):
     157    def __init__(self, f, var, default_value):
    142158        """
    143159        Create a new manipulate control.
    144160
    class ManipulateControl: 
    150166        self.__var = var
    151167        self.__cell_id = SAGE_CELL_ID
    152168        self.__f = f
     169        self.__default_value = default_value
     170        self.__adapt_number = new_adapt_number()
    153171
    154172    def __repr__(self):
    155173        return "A ManipulateControl (abstract base class)"
    156174
    157     def adapt(self):
     175    def default_value(self):
     176        return self.__default_value
     177
     178    def adapt_user_input(self):
    158179        """
    159180        Return string representation of function that is called to
    160181        adapt the values of this control to Python.
    161182        """
    162         name = new_adapt_name()
    163         vars[name] = self._adapt
    164         return 'sage.server.notebook.manipulate.vars[\\"%s\\"]'%name
     183        state[self.cell_id()]['adapt'][self.__adapt_number] = self._adapt_user_input
     184        return 'sage.server.notebook.manipulate.state[%s][\\"adapt\\"][%s]'%(self.cell_id(), self.__adapt_number)
    165185
    166     def _adapt(self, x):
     186    def _adapt_user_input(self, x):
    167187        return x
    168188       
    169189    def manipulate(self):
    class ManipulateControl: 
    175195        OUTPUT:
    176196            string -- that is meant to be evaluated in Javascript
    177197        """
    178         s = 'manipulate(%s, "sage.server.notebook.manipulate.vars[%s][\\"%s\\"]=sage_eval(r\\"\\"\\"%s("+%s+")\\"\\"\\", globals())\\n%s()");'%(
    179             self.cell_id(), self.cell_id(), self.var(), self.adapt(), self.value(), self.function_name())
     198        s = 'manipulate(%s, "sage.server.notebook.manipulate.state[%s][\\"variables\\"][\\"%s\\"]=sage_eval(r\\"\\"\\"%s("+%s+")\\"\\"\\", globals())\\n%s()");'%(
     199            self.cell_id(), self.cell_id(), self.var(), self.adapt_user_input(), self.value(), self.function_name())
    180200        return s
    181201
    182202    def function_name(self):
    class ManipulateControl: 
    186206        OUTPUT:
    187207            string -- name of a function as a string
    188208        """
    189         return self.__f.__name__
     209        return 'sage.server.notebook.manipulate.state[%s][\\"function\\"]'%(self.cell_id())
    190210
    191211    def var(self):
    192212        """
    class ManipulateControl: 
    206226        """
    207227        return self.__cell_id
    208228
    209 class TextBox(ManipulateControl):
     229class InputBox(ManipulateControl):
    210230    """
    211     A text box manipulate control.
     231    An input box manipulate control.
    212232    """
    213233    def __repr__(self):
    214         return "A TextBox manipulate control"
     234        return "A InputBox manipulate control"
    215235
    216236    def value(self):
    217237        """
    class TextBox(ManipulateControl): 
    231251             string -- html format
    232252        """
    233253        return """
    234         %s: <input type='text' value='<?%s>' onchange='%s'></input>
    235         """%(self.var(), self.var(), self.manipulate())
     254        %s: <input type='text' value='%r' width=100%% onchange='%s'></input>
     255        """%(self.var(), self.default_value(), self.manipulate())
    236256
    237257class Slider(ManipulateControl):
    238258    """
    239259    A slider manipulate control.
    240260    """
    241     def __init__(self, f, var, values):
     261    def __init__(self, f, var, values, default_position):
    242262        """
    243263        Create a slider manipulate control that takes on the given
    244264        list of values.
    245265        """
    246         ManipulateControl.__init__(self, f, var)
     266        ManipulateControl.__init__(self, f, var, values[default_position])
    247267        self.__values = values
    248        
     268        self.__default_position = default_position
     269
    249270    def __repr__(self):
    250271        return "A Slider manipulate control"
     272
     273    def default_position(self):
     274        """
     275        Return the default position (as an integer) of the slider.
     276        """
     277        return self.__default_position
    251278
    252279    def value(self):
    253280        """
    class Slider(ManipulateControl): 
    259286        """
    260287        return "position"
    261288   
    262     def _adapt(self, position):
     289    def _adapt_user_input(self, position):
    263290        # Input position is a string that evals to a float between 0 and 100.
    264291        # we translate it into an index into self.__values
    265292        v = self.__values
    266         i = int(len(v) * (float(position)/100.0))
    267         if i < 0:
    268             i = 0
    269         elif i >= len(v):
    270             i = len(v) - 1
    271         return v[i]
     293        return v[int(position)]
    272294
    273295    def render(self):
    274296        """
    class Slider(ManipulateControl): 
    277299        OUTPUT:
    278300             string -- html format
    279301        """
    280         return html_slider('slider-%s-%s'%(self.var(), self.cell_id()), self.manipulate())
     302        return html_slider('<font color=black>%s</font> '%self.var(), 'slider-%s-%s'%(self.var(), self.cell_id()),
     303                           self.manipulate(), steps=len(self.__values),
     304                           default=self.default_position())
    281305   
    282306
    283307class ManipulateCanvas:
    class ManipulateCanvas: 
    286310    along with the output of the manipulated function are layed out
    287311    and rendered.
    288312    """
    289     def __init__(self, controls):
     313    def __init__(self, controls, id):
    290314        """
    291315        Create a manipulate canvas.
    292316       
    class ManipulateCanvas: 
    294318            controls -- a list of ManipulateControl instances.
    295319        """
    296320        self.__controls = controls
     321        self.__cell_id = id
     322
     323    def cell_id(self):
     324        return self.__cell_id
    297325
    298326    def render_output(self):
    299327        """
    class ManipulateCanvas: 
    306334        OUTPUT:
    307335            string -- html
    308336        """
    309        
    310337        return """
    311         <table bgcolor=black cellpadding=3><tr><td bgcolor=white>
    312         <?TEXT>
    313            <table border=0 width=800px height=500px>
    314            <tr><td align=center>  <?HTML>  </td></tr>
    315            </table>
    316         </td></tr></table>
    317         """
     338        <div id='cell-manipulate-%s'><?START>
     339        <table border=1 bgcolor='#dcdcdc' cellpadding=3 width=100%% height=100%%>
     340        <tr><td bgcolor=white>
     341          <?TEXT>
     342        </td></tr>
     343        <tr><td><?HTML></td></tr>
     344        </table>
     345        </td></tr></table><?END></div>
     346        """%self.cell_id()
    318347
    319348    def render_controls(self):
    320349        """
    class ManipulateCanvas: 
    325354        """
    326355        # This will need some sophisticated layout querying of the c's, maybe.
    327356        return ''.join([c.render() for c in self.__controls])
    328        
     357
     358    def wrap_in_outside_frame(self, inside):
     359        #return "<table bgcolor='#c5c5c5' width=100%% height=100%% cellpadding=5><tr><td bgcolor='#f9f9f9'>%s</td></tr></table>"%inside
     360        return "<table bgcolor='#c5c5c5' width=800px height=400px cellpadding=5><tr><td bgcolor='#f9f9f9'>%s</td></tr></table>"%inside
     361
    329362    def render(self):
    330363        """
    331364        Render in text (html) the entire manipulate canvas.
    class ManipulateCanvas: 
    333366        OUTPUT:
    334367            string -- html
    335368        """
    336         return "%s%s"%(self.render_controls(), self.render_output())
     369        s = "%s%s"%(self.render_controls(), self.render_output())
     370        s = self.wrap_in_outside_frame(s)
     371        return s
    337372   
    338373       
    339374def manipulate(f):
    def manipulate(f): 
    341376    Decorate a function f to make a manipulate version of f.
    342377        @manipulate
    343378        def foo(n,m):
    344             ...
     379            ...
     380
     381    Note -- it is safe to make several distinct manipulate cells with functions that
     382    have the same name.
    345383    """
    346384   
    347385    (args, varargs, varkw, defaults) = inspect.getargspec(f)
    def manipulate(f): 
    354392    #controls = [automatic_control(f, v) for v in args[:n]] + \
    355393    #           [defaults[i].render(f, args[i+n]) for i in range(len(defaults))]
    356394
    357     C = ManipulateCanvas(controls)
     395    C = ManipulateCanvas(controls, SAGE_CELL_ID)
    358396
    359     vars[SAGE_CELL_ID] = {}
    360     d = vars[SAGE_CELL_ID]
    361     for v in args:
    362          d[v] = ''
     397    d = {}
     398    state[SAGE_CELL_ID] = {'variables':d, 'adapt':{}}
     399
     400    for con in controls:
     401        d[con.var()] = con.default_value()
    363402
    364403    html(C.render())
    365404
    366405    def g():
    367406        return f(*[d[args[i]] for i in range(len(args))])
     407
     408    state[SAGE_CELL_ID]['function'] = g
     409   
    368410    return g   
    369411
    370412
    class control: 
    374416class control:
    375417    pass
    376418
    377 class text_box(control):
     419class input_box(control):
    378420    def __init__(self, default):
    379421        """
    380422        INPUT:
    class text_box(control): 
    383425        self.__default = default
    384426
    385427    def __repr__(self):
    386         return "A manipulate text box control with default value '%s'"%self.__default
     428        return "A manipulate input box control with default value '%r'"%self.__default
    387429
    388430    def render(self, f, var):
    389431        """
    class text_box(control): 
    391433            f -- a Python function
    392434            var -- a string (variable; one of the variable names input to f)
    393435        """
    394         return TextBox(f, var)
     436        return InputBox(f, var, self.__default)
    395437   
    396438class slider(control):
    397     def __init__(self, vmin, vmax=None, steps=30):
     439    def __init__(self, vmin, vmax=None, steps=30, default=None):
    398440        if isinstance(vmin, list):
    399441            self.__values = vmin
    400442        else:
    class slider(control): 
    407449            else:
    408450                step = (vmax-vmin)/steps  # hard coded
    409451                self.__values = [vmin + i*step for i in range(steps)] + [vmax]
     452        if len(self.__values) == 0:
     453            self.__values = [0]
     454        if default is None:
     455            self.__default = 0
     456        else:
     457            try:
     458                i = self.__values.index(default)
     459            except ValueError:
     460                i = 0
     461            self.__default = i
    410462
    411463    def __repr__(self):
    412464        return "A manipulate slider control [%s - %s]."%(min(self.__values), max(self.__values))
    413465
     466    def default(self):
     467        """
     468        Return default index into the list of values.
     469
     470        OUTPUT:
     471            int
     472        """
     473        return self.__default
     474
    414475    def render(self, f, var):
    415         return Slider(f, var, self.__values)
     476        return Slider(f, var, self.__values, self.__default)
    416477       
    417478def automatic_control(f, v, default):
    418479    if isinstance(default, control):
    def automatic_control(f, v, default): 
    420481    elif isinstance(default, list):
    421482        C = slider(default)
    422483    else:
    423         C = text_box(str(default))
     484        C = input_box(default)
    424485    return C.render(f, v)