Home | History | Annotate | Download | only in turtle
      1 #!/usr/bin/env python
      2 import sys
      3 import os
      4 
      5 from Tkinter import *
      6 from idlelib.Percolator import Percolator
      7 from idlelib.ColorDelegator import ColorDelegator
      8 from idlelib.textView import view_file
      9 
     10 import turtle
     11 import time
     12 
     13 demo_dir = os.getcwd()
     14 if "turtleDemo.py" not in os.listdir(demo_dir):
     15     print "Directory of turtleDemo must be current working directory!"
     16     print "But in your case this is", demo_dir
     17     sys.exit()
     18 
     19 STARTUP = 1
     20 READY = 2
     21 RUNNING = 3
     22 DONE = 4
     23 EVENTDRIVEN = 5
     24 
     25 menufont = ("Arial", 12, NORMAL)
     26 btnfont = ("Arial", 12, 'bold')
     27 txtfont = ('Lucida Console', 8, 'normal')
     28 
     29 def getExampleEntries():
     30     entries1 = [entry for entry in os.listdir(demo_dir) if
     31                      entry.startswith("tdemo_") and
     32                      not entry.endswith(".pyc")]
     33     entries2 = []
     34     for entry in entries1:
     35         if entry.endswith(".py"):
     36             entries2.append(entry)
     37         else:
     38             path = os.path.join(demo_dir, entry)
     39             sys.path.append(path)
     40             subdir = [entry]
     41             scripts = [script for script in os.listdir(path) if
     42                             script.startswith("tdemo_") and
     43                             script.endswith(".py")]
     44             entries2.append(subdir+scripts)
     45     return entries2
     46 
     47 help_entries = (  # (help_label,  help_file)
     48     ('Turtledemo help', "demohelp.txt"),
     49     ('About turtledemo', "about_turtledemo.txt"),
     50     ('About turtle module', "about_turtle.txt"),
     51     )
     52 
     53 class DemoWindow(object):
     54 
     55     def __init__(self, filename=None):
     56         self.root = root = turtle._root = Tk()
     57         root.title('Python turtle-graphics examples')
     58         root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
     59 
     60         root.grid_rowconfigure(1, weight=1)
     61         root.grid_columnconfigure(0, weight=1)
     62         root.grid_columnconfigure(1, minsize=90, weight=1)
     63         root.grid_columnconfigure(2, minsize=90, weight=1)
     64         root.grid_columnconfigure(3, minsize=90, weight=1)
     65 
     66         self.mBar = Frame(root, relief=RAISED, borderwidth=2)
     67         self.ExamplesBtn = self.makeLoadDemoMenu()
     68         self.OptionsBtn = self.makeHelpMenu()
     69         self.mBar.grid(row=0, columnspan=4, sticky='news')
     70 
     71         pane = PanedWindow(orient=HORIZONTAL, sashwidth=5,
     72                            sashrelief=SOLID, bg='#ddd')
     73         pane.add(self.makeTextFrame(pane))
     74         pane.add(self.makeGraphFrame(pane))
     75         pane.grid(row=1, columnspan=4, sticky='news')
     76 
     77         self.output_lbl = Label(root, height= 1, text=" --- ", bg="#ddf",
     78                                 font=("Arial", 16, 'normal'), borderwidth=2,
     79                                 relief=RIDGE)
     80         self.start_btn = Button(root, text=" START ", font=btnfont,
     81                                 fg="white", disabledforeground = "#fed",
     82                                 command=self.startDemo)
     83         self.stop_btn = Button(root, text=" STOP ", font=btnfont,
     84                                fg="white", disabledforeground = "#fed",
     85                                command=self.stopIt)
     86         self.clear_btn = Button(root, text=" CLEAR ", font=btnfont,
     87                                 fg="white", disabledforeground="#fed",
     88                                 command = self.clearCanvas)
     89         self.output_lbl.grid(row=2, column=0, sticky='news', padx=(0,5))
     90         self.start_btn.grid(row=2, column=1, sticky='ew')
     91         self.stop_btn.grid(row=2, column=2, sticky='ew')
     92         self.clear_btn.grid(row=2, column=3, sticky='ew')
     93 
     94         Percolator(self.text).insertfilter(ColorDelegator())
     95         self.dirty = False
     96         self.exitflag = False
     97         if filename:
     98             self.loadfile(filename)
     99         self.configGUI(NORMAL, DISABLED, DISABLED, DISABLED,
    100                        "Choose example from menu", "black")
    101         self.state = STARTUP
    102 
    103 
    104     def onResize(self, event):
    105         cwidth = self._canvas.winfo_width()
    106         cheight = self._canvas.winfo_height()
    107         self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
    108         self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
    109 
    110     def makeTextFrame(self, root):
    111         self.text_frame = text_frame = Frame(root)
    112         self.text = text = Text(text_frame, name='text', padx=5,
    113                                 wrap='none', width=45)
    114 
    115         self.vbar = vbar = Scrollbar(text_frame, name='vbar')
    116         vbar['command'] = text.yview
    117         vbar.pack(side=LEFT, fill=Y)
    118         self.hbar = hbar = Scrollbar(text_frame, name='hbar', orient=HORIZONTAL)
    119         hbar['command'] = text.xview
    120         hbar.pack(side=BOTTOM, fill=X)
    121 
    122         text['font'] = txtfont
    123         text['yscrollcommand'] = vbar.set
    124         text['xscrollcommand'] = hbar.set
    125         text.pack(side=LEFT, fill=BOTH, expand=1)
    126         return text_frame
    127 
    128     def makeGraphFrame(self, root):
    129         turtle._Screen._root = root
    130         self.canvwidth = 1000
    131         self.canvheight = 800
    132         turtle._Screen._canvas = self._canvas = canvas = turtle.ScrolledCanvas(
    133                 root, 800, 600, self.canvwidth, self.canvheight)
    134         canvas.adjustScrolls()
    135         canvas._rootwindow.bind('<Configure>', self.onResize)
    136         canvas._canvas['borderwidth'] = 0
    137 
    138         self.screen = _s_ = turtle.Screen()
    139         turtle.TurtleScreen.__init__(_s_, _s_._canvas)
    140         self.scanvas = _s_._canvas
    141         turtle.RawTurtle.screens = [_s_]
    142         return canvas
    143 
    144     def configGUI(self, menu, start, stop, clear, txt="", color="blue"):
    145         self.ExamplesBtn.config(state=menu)
    146 
    147         self.start_btn.config(state=start,
    148                               bg="#d00" if start == NORMAL else "#fca")
    149         self.stop_btn.config(state=stop,
    150                              bg="#d00" if stop == NORMAL else "#fca")
    151         self.clear_btn.config(state=clear,
    152                               bg="#d00" if clear == NORMAL else"#fca")
    153         self.output_lbl.config(text=txt, fg=color)
    154 
    155     def makeLoadDemoMenu(self):
    156         CmdBtn = Menubutton(self.mBar, text='Examples',
    157                             underline=0, font=menufont)
    158         CmdBtn.pack(side=LEFT, padx="2m")
    159         CmdBtn.menu = Menu(CmdBtn)
    160 
    161         for entry in getExampleEntries():
    162             def loadexample(x):
    163                 def emit():
    164                     self.loadfile(x)
    165                 return emit
    166             if isinstance(entry,str):
    167                 CmdBtn.menu.add_command(label=entry[6:-3], underline=0,
    168                                         font=menufont,
    169                                         command=loadexample(entry))
    170             else:
    171                 _dir, entries = entry[0], entry[1:]
    172                 CmdBtn.menu.choices = Menu(CmdBtn.menu)
    173                 for e in entries:
    174                     CmdBtn.menu.choices.add_command(
    175                             label=e[6:-3], underline=0, font=menufont,
    176                             command = loadexample(os.path.join(_dir,e)))
    177                 CmdBtn.menu.add_cascade(
    178                     label=_dir[6:], menu = CmdBtn.menu.choices, font=menufont)
    179 
    180         CmdBtn['menu'] = CmdBtn.menu
    181         return CmdBtn
    182 
    183     def makeHelpMenu(self):
    184         CmdBtn = Menubutton(self.mBar, text='Help', underline=0, font = menufont)
    185         CmdBtn.pack(side=LEFT, padx='2m')
    186         CmdBtn.menu = Menu(CmdBtn)
    187 
    188         for help_label, help_file in help_entries:
    189             def show(help_label=help_label, help_file=help_file):
    190                 view_file(self.root, help_label, os.path.join(demo_dir, help_file))
    191             CmdBtn.menu.add_command(label=help_label, font=menufont, command=show)
    192 
    193         CmdBtn['menu'] = CmdBtn.menu
    194         return CmdBtn
    195 
    196     def refreshCanvas(self):
    197         if not self.dirty: return
    198         self.screen.clear()
    199         self.dirty=False
    200 
    201     def loadfile(self,filename):
    202         self.refreshCanvas()
    203         if os.path.exists(filename) and not os.path.isdir(filename):
    204             # load and display file text
    205             f = open(filename,'r')
    206             chars = f.read()
    207             f.close()
    208             self.text.delete("1.0", "end")
    209             self.text.insert("1.0",chars)
    210             direc, fname = os.path.split(filename)
    211             self.root.title(fname[6:-3]+" - a Python turtle graphics example")
    212             self.module = __import__(fname[:-3])
    213             self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED,
    214                            "Press start button", "red")
    215             self.state = READY
    216 
    217     def startDemo(self):
    218         self.refreshCanvas()
    219         self.dirty = True
    220         turtle.TurtleScreen._RUNNING = True
    221         self.configGUI(DISABLED, DISABLED, NORMAL, DISABLED,
    222                        "demo running...", "black")
    223         self.screen.clear()
    224         self.screen.mode("standard")
    225         self.state = RUNNING
    226 
    227         try:
    228             result = self.module.main()
    229             if result == "EVENTLOOP":
    230                 self.state = EVENTDRIVEN
    231             else:
    232                 self.state = DONE
    233         except turtle.Terminator:
    234             if self.root is None:
    235                 return
    236             self.state = DONE
    237             result = "stopped!"
    238         if self.state == DONE:
    239             self.configGUI(NORMAL, NORMAL, DISABLED, NORMAL,
    240                            result)
    241         elif self.state == EVENTDRIVEN:
    242             self.exitflag = True
    243             self.configGUI(DISABLED, DISABLED, NORMAL, DISABLED,
    244                            "use mouse/keys or STOP", "red")
    245 
    246     def clearCanvas(self):
    247         self.refreshCanvas()
    248         self.scanvas.config(cursor="")
    249         self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED)
    250 
    251     def stopIt(self):
    252         if self.exitflag:
    253             self.clearCanvas()
    254             self.exitflag = False
    255             self.configGUI(NORMAL, NORMAL, DISABLED, DISABLED,
    256                            "STOPPED!", "red")
    257             turtle.TurtleScreen._RUNNING = False
    258         else:
    259             turtle.TurtleScreen._RUNNING = False
    260 
    261     def _destroy(self):
    262         turtle.TurtleScreen._RUNNING = False
    263         self.root.destroy()
    264         self.root = None
    265         #sys.exit()
    266 
    267 def main():
    268     demo = DemoWindow()
    269     demo.root.mainloop()
    270 
    271 if __name__ == '__main__':
    272     main()
    273