0001import Tkinter
0002import Pmw
0003import threading
0004from pylogo import reader
0005from Queue import Queue, Empty
0006
0007root = Pmw.initialise()
0008
0009class IDE:
0010    def __init__(self, parent):
0011        self.incoming_history = Queue()
0012        self.incoming_commands = Queue()
0013        self.parent = parent
0014
0015        self.menuBar = Pmw.MainMenuBar(parent)
0016        parent.configure(menu=self.menuBar)
0017        self.menuBar.addmenu('File', '')
0018        self.menuBar.addmenuitem('File', 'command', label='Exit',
0019                                 command=self.exit)
0020        self.parent.protocol('WM_DELETE_WINDOW', self.exit)
0021        self.menuBar.addmenu('Help', '')
0022        self.menuBar.addmenuitem('Help', 'command', label='About',
0023                                 command=self.about)
0024
0025        #self.menuFrame = Tkinter.Frame(parent)
0026        #self.menuFrame.pack(fill='x', side='top', expand=0)
0027        #self.menuFrame.tk_menuBar(self.fileMenu(), self.helpMenu())
0028
0029        self.pw = Pmw.PanedWidget(
0030            parent,
0031            hull_borderwidth=1,
0032            hull_relief='sunken')
0033        pane = self.pw.add('canvas', size=.5)
0034        self.scroller = TurtleSpace(
0035            pane,
0036            canvas_width=1000,
0037            canvas_height=1000,
0038            canvas_background="white")
0039        self.scroller.pack(side='top', expand=1)
0040
0041        pane3 = self.pw.add('history', size=.4)
0042        self.history = Pmw.ScrolledText(
0043            pane3,
0044            borderframe=1,
0045            vscrollmode='static',
0046            text_width=70)
0047        self.history.pack(side='top', expand=1)
0048
0049        pane2 = self.pw.add('entry', size=.1)
0050        self.input = Pmw.EntryField(
0051            pane2,
0052            command=self.feed_input,
0053            entry_width=72)
0054        self.input.pack(side='top', expand=1)
0055
0056        self.pw.pack(expand=1, fill='both')
0057        self.canvas = canvas = self.scroller.component('canvas')
0058        self.parent.after(100, self.idle_updates)
0059        return
0060
0061    def feed_input(self):
0062        value = self.input.getvalue() + '\n'
0063        self.logo_communicator.add_input(value)
0064        self.input.clear()
0065        self.update_history()
0066        self.update_commands()
0067
0068    def idle_updates(self):
0069        #print "IDLE"
0070        self.update_history()
0071        self.update_commands()
0072        self.parent.after(100, self.idle_updates)
0073
0074    def add_history(self, val):
0075        # This should actually put some event in place, so that the
0076        # main thread knows it should try to update the history when
0077        # it has the chance.
0078        self.incoming_history.put(val)
0079
0080    def update_history(self):
0081        history = []
0082        while 1:
0083            try:
0084                history.append(self.incoming_history.get_nowait())
0085            except Empty:
0086                break
0087        for line in history:
0088            if line.endswith('\n') and 0:
0089                # @@: we shouldn't just ignore it, rather when
0090                # it's not present we should not append the text.
0091                # (or put it back on the history)
0092                line = line[:-1]
0093            self.history.appendtext(line)
0094
0095    def exit(self):
0096        print "Exiting!"
0097        self.parent.destroy()
0098        self.logo_communicator.exit()
0099        return
0100
0101    def about(self):
0102        Pmw.aboutversion('0.2')
0103        Pmw.aboutcopyright('Copyright Ian Bicking 2003')
0104        Pmw.aboutcontact('For more information:\n  http://pylogo.org')
0105        about = Pmw.AboutDialog(self.parent, applicationname='PyLogo')
0106        about.show()
0107
0108    def update_commands(self):
0109        while 1:
0110            try:
0111                command = self.incoming_commands.get_nowait()
0112            except Empty:
0113                return
0114            if command == 'quit':
0115                self.exit()
0116            try:
0117                val = command[1](*command[2], **command[3])
0118            except Exception, e:
0119                if command[0]:
0120                    command[0].put([True, e])
0121            else:
0122                if command[0]:
0123                    command[0].put([False, val])
0124
0125    def run_command(self, func, *args, **kw):
0126        if kw.has_key('_nowait'):
0127            nowait = kw['_nowait']
0128            del kw['_nowait']
0129        else:
0130            nowait = 0
0131        if nowait:
0132            out = None
0133        else:
0134            out = Queue(1)
0135        self.incoming_commands.put((out, func, args, kw))
0136        if out:
0137            error, result = out.get()
0138            if error:
0139                raise result
0140            else:
0141                return result
0142
0143    def add_command(self, func, *args, **kw):
0144        kw['_nowait'] = 1
0145        return self.run_command(func, *args, **kw)
0146
0147class TurtleSpace(Pmw.ScrolledCanvas):
0148
0149    def __init__(self, *args, **kw):
0150        Pmw.ScrolledCanvas.__init__(self, *args, **kw)
0151
0152
0153class LogoCommunicator:
0154
0155    def __init__(self, app, interp):
0156        self.interp = interp
0157        self.app = app
0158        app.logo_communicator = self
0159        interp.canvas = app.canvas
0160        interp.app = app
0161        self.pending_input = Queue()
0162        self.pendingOutput = Queue()
0163        self.input_event = threading.Event()
0164
0165    def start(self):
0166        self.logoThread = threading.Thread(
0167            target=self.interp.input_loop,
0168            args=(reader.TrackingStream(self), self))
0169        self.logoThread.start()
0170
0171    def exit(self):
0172        self.add_input('bye\n')
0173
0174    def add_input(self, value):
0175        if not value.endswith('\n'):
0176            value += '\n'
0177        self.app.add_history(value)
0178        self.pending_input.put(value)
0179        self.input_event.set()
0180
0181    def readline(self):
0182        result = self.pending_input.get()
0183        return result
0184
0185    def write(self, value):
0186        self.app.add_history(value)
0187
0188    def flush(self):
0189        pass
0190
0191    name = '<ide>'
0192
0193#import oointerp
0194#oointerp.install()
0195from pylogo import interpreter
0196
0197def add_command(command, *args, **kw):
0198    TheApp.add_command(command, *args, **kw)
0199    return TheApp
0200
0201def get_canvas():
0202    return TheApp.canvas
0203
0204def main():
0205    import sys
0206    from pylogo import logo_turtle
0207    global TheApp
0208    TheApp = IDE(root)
0209    TheApp.input.component('entry').focus_force()
0210    comm = LogoCommunicator(TheApp, interpreter.Logo)
0211    sys.stdout = comm
0212    interpreter.Logo.import_module(logo_turtle)
0213    logo_turtle.createturtle(interpreter.Logo)
0214    #logo_turtle.logo_turtle_main(interpreter.Logo)
0215    #logo_turtle._newmainturtle(interpreter.Logo)
0216
0217    comm.start()
0218
0219    root.mainloop()
0220
0221if __name__ == '__main__':
0222    main()