# HG changeset patch # User William Stein # Date 1204509750 21600 # Node ID c1b3be3bcc9235bb90637864aad61e6cea471e2b # Parent 48f2d5de9355c29c0d5f477db1d137f8def9bca4 sage-1322: manipulate -- part 2 diff -r 48f2d5de9355 -r c1b3be3bcc92 sage/server/notebook/cell.py --- a/sage/server/notebook/cell.py Sun Mar 02 02:48:10 2008 -0600 +++ b/sage/server/notebook/cell.py Sun Mar 02 20:02:30 2008 -0600 @@ -393,7 +393,8 @@ class Cell(Cell_generic): z = self.output_text(ncols,html,raw,allow_manipulate=False) try: # Fill in the input valuees - if hasattr(self, 'manipulate'): + # TODO -- redo + if False and hasattr(self, 'manipulate'): inp = self.manipulate i = inp.lstrip().find('\n'); inp = inp[:i] i = inp.rfind('.'); inp = inp[i+1:] @@ -404,7 +405,6 @@ class Cell(Cell_generic): output,html = self._manipulate_output z = z.replace('', output.lstrip()) z = z.replace('', html) - return z except (ValueError, AttributeError), msg: diff -r 48f2d5de9355 -r c1b3be3bcc92 sage/server/notebook/js.py --- a/sage/server/notebook/js.py Sun Mar 02 02:48:10 2008 -0600 +++ b/sage/server/notebook/js.py Sun Mar 02 20:02:30 2008 -0600 @@ -1990,7 +1990,7 @@ function check_for_cell_update_callback( set_output_text(id, output_text, output_text_wrapped, output_html, stat, introspect_html); - + if (stat == 'd') { active_cell_list = delete_from_array(active_cell_list, id); diff -r 48f2d5de9355 -r c1b3be3bcc92 sage/server/notebook/manipulate.py --- a/sage/server/notebook/manipulate.py Sun Mar 02 02:48:10 2008 -0600 +++ b/sage/server/notebook/manipulate.py Sun Mar 02 20:02:30 2008 -0600 @@ -16,18 +16,92 @@ AUTHOR: -- Jason Grout (2008-03): collaborators substantially on the design and prototypes. -TODO/PLAN: - [ ] sliders - [ ] default value - [ ] more widgets - [ ] better widget layout controls +TODO: + [ ] get sliders to work + [ ] default values; values after move slider + [ ] implement a color object + +PLANS and IDEAS: + [ ] automagically determine the type of control from the default + value of the variable. Here is how this will work: + * u blank input field + * u = (umin,umax) slider; umin must not be a string + * u = (umin,umax,du) discrete slider + * u = [1,2,3,4] setter bar: automatically when there are are most 5 + elements; otherwise a drop down menu + * u = ((xmin,xmax),(ymin,ymax)) 2d slider + * u = Graphic a locator in a 2d plot (Graphic is a 2d graphics objects) + * u = True or u = False a checkbox + * u = color(...) a color slider + * u = "string" text input field + * u = ('label', obj) obj can be any of the above; control is labeled with + the given label + * u = element if parent(element)._manipulate_control_(element) is + defined, then it will be used. Otherwise make a + text input that coerces input to parent(element) + [ ] tag_cell('foo') -- makes it so one can refer to the current cell + from elsewhere using the tag foo instead of the cell id number + This involves doing something with SAGE_CELL_ID and the cell_id() + method. [ ] 100% doctest coverage + +JQUERY: + [ ] tab_view -- represents an object in which clicking the tab + with label lbl[i] displays expr[i] + [ ] slide_view -- represents an object in which the a list of objects + are displayed on successive slides. + [ ] framed -- put a frame around an object + [ ] panel -- put an object in a panel + [ ] flot (?) + +ELEMENTS: + [ ] control: this models the input and other tags in html + align -- left, right, top, texttop, middle, absmiddle, baseline, bottom, absbottom + background -- the color of the background for the cell + frame -- draw a frame around + disabled -- disables the input element when it first loads + so that the user can not write text in it, or + select it. + editable -- bool + font_size -- integer + maxlength -- the maximum number of characters allowed in a text field. + name -- defines a unique name for the input element + size -- the size of the input element + type -- button, checkbox, file, password, radio, slider, text, setter_bar, drop_down + [ ] setter bar (buttons) + [ ] checkbox + [ ] color slider + [ ] blank input field + [ ] 2d slider + [ ] locator in a graphic + +IDEAS for code: + +@manipulate +def foo(x=range(10), y=slider(1,10)): + ... + +@manipulate +def foo(x=random_matrix(ZZ,2)) + ... + + +@framed +def foo(x,y): + ... """ import inspect SAGE_CELL_ID = 0 vars = {} + +_k = 0 +def new_adapt_name(): + global _k + _k += 1 + return 'adapt%s'%_k + def html(s): """ @@ -41,6 +115,24 @@ def html(s): string -- html format """ print "%s"%s + +def html_slider(id, callback, margin=0): + s = """
"""%( + id, int(margin)) + + # We now generat javascript that gets run after the above div gets + # inserted. This happens because of the setTimeout function below + # which gets passed an anonymous function. + s += """ + + """%(id, id, id, callback) + return s + class ManipulateControl: """ @@ -61,6 +153,18 @@ class ManipulateControl: def __repr__(self): return "A ManipulateControl (abstract base class)" + + def adapt(self): + """ + Return string representation of function that is called to + adapt the values of this control to Python. + """ + name = new_adapt_name() + vars[name] = self._adapt + return 'sage.server.notebook.manipulate.vars[\\"%s\\"]'%name + + def _adapt(self, x): + return x def manipulate(self): """ @@ -71,8 +175,9 @@ class ManipulateControl: OUTPUT: string -- that is meant to be evaluated in Javascript """ - return 'manipulate(%s, "sage.server.notebook.manipulate.vars[%s][\\"%s\\"]=sage_eval(r\\"\\"\\""+%s+"\\"\\"\\", globals())\\n%s()");'%( - self.cell_id(), self.cell_id(), self.var(), self.value(), self.function_name()) + s = 'manipulate(%s, "sage.server.notebook.manipulate.vars[%s][\\"%s\\"]=sage_eval(r\\"\\"\\"%s("+%s+")\\"\\"\\", globals())\\n%s()");'%( + self.cell_id(), self.cell_id(), self.var(), self.adapt(), self.value(), self.function_name()) + return s def function_name(self): """ @@ -116,8 +221,8 @@ class TextBox(ManipulateControl): OUTPUT: string -- javascript """ - return "this.value" - + return 'this.value' + def render(self): """ Render this control as a string. @@ -152,8 +257,19 @@ class Slider(ManipulateControl): OUTPUT: string -- javascript """ - return "this.value" + return "position" + def _adapt(self, position): + # Input position is a string that evals to a float between 0 and 100. + # we translate it into an index into self.__values + v = self.__values + i = int(len(v) * (float(position)/100.0)) + if i < 0: + i = 0 + elif i >= len(v): + i = len(v) - 1 + return v[i] + def render(self): """ Render this control as a string. @@ -161,9 +277,7 @@ class Slider(ManipulateControl): OUTPUT: string -- html format """ - return """ - SLIDER %s: - """%(self.var(), self.var(), self.manipulate()) + return html_slider('slider-%s-%s'%(self.var(), self.cell_id()), self.manipulate()) class ManipulateCanvas: @@ -196,7 +310,7 @@ class ManipulateCanvas: return """
- +
@@ -234,20 +348,21 @@ def manipulate(f): if defaults is None: defaults = [] - + n = len(args) - len(defaults) - controls = [TextBox(f, v) for v in args[:n]] + \ - [defaults[i].render(f, args[i+n]) for i in range(len(defaults))] - + controls = [automatic_control(f, args[i], defaults[i-n] if i >= n else None) for i in range(len(args))] + #controls = [automatic_control(f, v) for v in args[:n]] + \ + # [defaults[i].render(f, args[i+n]) for i in range(len(defaults))] + C = ManipulateCanvas(controls) - + vars[SAGE_CELL_ID] = {} d = vars[SAGE_CELL_ID] for v in args: d[v] = '' - + html(C.render()) - + def g(): return f(*[d[args[i]] for i in range(len(args))]) return g @@ -299,3 +414,11 @@ class slider(control): def render(self, f, var): return Slider(f, var, self.__values) +def automatic_control(f, v, default): + if isinstance(default, control): + C = default + elif isinstance(default, list): + C = slider(default) + else: + C = text_box(str(default)) + return C.render(f, v) diff -r 48f2d5de9355 -r c1b3be3bcc92 sage/server/notebook/notebook.py --- a/sage/server/notebook/notebook.py Sun Mar 02 02:48:10 2008 -0600 +++ b/sage/server/notebook/notebook.py Sun Mar 02 20:02:30 2008 -0600 @@ -36,6 +36,8 @@ SYSTEMS = ['sage', 'axiom', 'gap', 'gp', SYSTEMS = ['sage', 'axiom', 'gap', 'gp', 'jsmath', 'kash', 'latex', 'lisp', 'macaulay2', 'magma', 'maple', 'mathematica', 'matlab', 'maxima', 'mupad', 'mwrank', 'octave', 'python', 'sage', 'sh', 'singular'] JSMATH = True + +JQUERY = True if is_package_installed("jsmath-image-fonts"): JSMATH_IMAGE_FONTS = True @@ -1437,12 +1439,33 @@ class Notebook(SageObject): head += '\n' head += "\n" + if JQUERY: + # Load the jquery and ui-jquery javascript library. + # This is used for manipulate functionality in the notebook, and will be used + # to enable drag and drop, image zoom, etc. + head += ''' + + + + + + + + + + ''' + + # This was for syntax hilighting # head +=' \n' # head += '\n' head +=' \n' + + # Jmol -- embedded 3d graphics. head +=' \n' - head +=' \n' # this must stay in the + + head +=' \n' # this must stay in the return head def html_worksheet_topbar(self, worksheet, select=None, username='guest'):