This evaluates expressions and displays their results as you type
them.  It's like some hack I posted a year ago, except that it doesn't
look quite as ugly and it has noticeably better updating behavior.
Still, it doesn't limit the time to evaluate an expression, and
doesn't effectively let you define functions.

This is yet another a prototype for the "functional programming for
amateurs in an outliner" goal.

#!/usr/bin/python
"""Functional outline -- at least, eventually.  No outlining yet.

This is "one to throw away."

To do:
D bring up a window
D add an exit button
D add "add row" button
  D make its focus behavior sensible
D fix shitty colors
- remove "select all on focus" behavior
- make entry fields' "relief" change on focus?  No relief for now.
- fix packing
- remove empty rows?  Rearrange rows?  Gravy...
- build f2c
  D add f
  D add c (in Python), and value
  - add re-evaluation
    D store all definitions in one object
    D start by recalculating everything in dumb order on any change, then...
    - topologically sort
    - use compile(expr, varname, 'eval').co_names to find dependencies.  Maybe display 
them?
    - add "valid" bit.  
      - Before setting new value, set to invalid; propagate this to dependents.
      - after setting new value, set to valid.
      - For display, maybe get new value for everything invalid that wants display
  - add K
  - add f2c
- add hierarchy --- expand/collapse
- add ability to *call* f2c
- build something recursive
  - how about factorial?
- add persistence

"""

import Tkinter, sys

bgcolor='white'

mainwin = Tkinter.Tk()
mainwin.title('quickfunc')
mainwin['background'] = bgcolor
varrows = Tkinter.Frame(mainwin, background=bgcolor)
varrows.pack(side='top')

def leftwidget(parent, ctor=Tkinter.Entry, **args):
        rv = ctor(parent, background=bgcolor, **args)
        rv.pack(side='left', fill='both')
        return rv

class namespace:
        def __init__(self):
                self.variables = []
                self.values = {}
                self.exceptions = {}
        def add_var(self, namevar, exprvar, value_widget):
                self.variables.append((namevar, exprvar, value_widget))
        def recalculate_everything(self, *stupid_tcl_vars):
                self.values.clear()
                for namevar, exprvar, widget in self.variables:
                        name = namevar.get()
                        try: 
                                value = eval(exprvar.get(), self.values)
                                self.values[name] = value
                                widget['text'] = repr(value)
                                widget['background'] = bgcolor
                        except:
                                self.exceptions[name] = sys.exc_info()
                                widget['background'] = 'red'

def row(name, expr, env):
        f = Tkinter.Frame(varrows, background=bgcolor)
        f.pack(fill='both')

        fnamevar = Tkinter.Variable()
        fnamevar.set(name)
        
        fname = leftwidget(f, relief='flat', textvariable=fnamevar, width=8, 
justify='right', highlightthickness=0)
        equal = leftwidget(f, Tkinter.Label, text=':')

        exprvar = Tkinter.Variable()
        fexpr = leftwidget(f, relief='flat', textvariable=exprvar, 
highlightthickness=0)
        fvalue = leftwidget(f, Tkinter.Label)
        env.add_var(namevar=fnamevar, exprvar=exprvar, value_widget=fvalue)
        exprvar.trace('w', env.recalculate_everything)
        fnamevar.trace('w', env.recalculate_everything)

        exprvar.set(expr)
        fexpr.focus()
        return f

env = namespace()
f = row('f', '212', env)
c = row('c', '(f - 32) * 5 / 9', env)

def addrow_cmd():
        row('', '', env)

addrow = Tkinter.Button(mainwin, text="New row", command=addrow_cmd)
addrow.pack(side='left')

exit = Tkinter.Button(mainwin, text="Exit", command=mainwin.quit)
exit.pack(side='left')
Tkinter.mainloop()

Reply via email to