Benjamin Peterson | 9cf41d0 | 2010-03-11 22:33:25 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 2 | import sys |
| 3 | import os |
| 4 | |
| 5 | from Tkinter import * |
| 6 | from idlelib.Percolator import Percolator |
| 7 | from idlelib.ColorDelegator import ColorDelegator |
Terry Jan Reedy | ed6820d | 2014-06-22 02:32:26 -0400 | [diff] [blame] | 8 | from idlelib.textView import view_file |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 9 | |
| 10 | import turtle |
| 11 | import time |
| 12 | |
Terry Jan Reedy | ed6820d | 2014-06-22 02:32:26 -0400 | [diff] [blame] | 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 | |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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(): |
Terry Jan Reedy | ed6820d | 2014-06-22 02:32:26 -0400 | [diff] [blame] | 30 | entries1 = [entry for entry in os.listdir(demo_dir) if |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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: |
Terry Jan Reedy | ed6820d | 2014-06-22 02:32:26 -0400 | [diff] [blame] | 38 | path = os.path.join(demo_dir, entry) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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 | |
Terry Jan Reedy | 8ac01bf | 2014-07-25 01:56:17 -0400 | [diff] [blame] | 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 | ) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 52 | |
| 53 | class DemoWindow(object): |
| 54 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 55 | def __init__(self, filename=None): |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 56 | self.root = root = turtle._root = Tk() |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 57 | root.title('Python turtle-graphics examples') |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 58 | root.wm_protocol("WM_DELETE_WINDOW", self._destroy) |
| 59 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 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) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 65 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 66 | self.mBar = Frame(root, relief=RAISED, borderwidth=2) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 67 | self.ExamplesBtn = self.makeLoadDemoMenu() |
| 68 | self.OptionsBtn = self.makeHelpMenu() |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 69 | self.mBar.grid(row=0, columnspan=4, sticky='news') |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 70 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 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') |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 76 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 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') |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 93 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 94 | Percolator(self.text).insertfilter(ColorDelegator()) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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 | |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 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 |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 143 | |
| 144 | def configGUI(self, menu, start, stop, clear, txt="", color="blue"): |
| 145 | self.ExamplesBtn.config(state=menu) |
| 146 | |
Terry Jan Reedy | 87355a7 | 2014-07-27 03:00:47 -0400 | [diff] [blame] | 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") |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 153 | self.output_lbl.config(text=txt, fg=color) |
| 154 | |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 155 | def makeLoadDemoMenu(self): |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 156 | CmdBtn = Menubutton(self.mBar, text='Examples', |
| 157 | underline=0, font=menufont) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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): |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 167 | CmdBtn.menu.add_command(label=entry[6:-3], underline=0, |
| 168 | font=menufont, |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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: |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 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) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 179 | |
| 180 | CmdBtn['menu'] = CmdBtn.menu |
| 181 | return CmdBtn |
| 182 | |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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 | |
Terry Jan Reedy | 8ac01bf | 2014-07-25 01:56:17 -0400 | [diff] [blame] | 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) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 192 | |
| 193 | CmdBtn['menu'] = CmdBtn.menu |
| 194 | return CmdBtn |
| 195 | |
| 196 | def refreshCanvas(self): |
| 197 | if not self.dirty: return |
| 198 | self.screen.clear() |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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) |
Georg Brandl | 574a857 | 2010-05-24 21:37:54 +0000 | [diff] [blame] | 211 | self.root.title(fname[6:-3]+" - a Python turtle graphics example") |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 212 | self.module = __import__(fname[:-3]) |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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: |
Serhiy Storchaka | cc49aa1 | 2015-02-22 17:22:53 +0200 | [diff] [blame] | 234 | if self.root is None: |
| 235 | return |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 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 |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 258 | else: |
| 259 | turtle.TurtleScreen._RUNNING = False |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 260 | |
| 261 | def _destroy(self): |
Serhiy Storchaka | cc49aa1 | 2015-02-22 17:22:53 +0200 | [diff] [blame] | 262 | turtle.TurtleScreen._RUNNING = False |
Terry Jan Reedy | e2fbf4f | 2014-07-23 15:01:07 -0400 | [diff] [blame] | 263 | self.root.destroy() |
Serhiy Storchaka | cc49aa1 | 2015-02-22 17:22:53 +0200 | [diff] [blame] | 264 | self.root = None |
Terry Jan Reedy | cbe6d24 | 2014-07-23 17:27:51 -0400 | [diff] [blame] | 265 | #sys.exit() |
| 266 | |
| 267 | def main(): |
| 268 | demo = DemoWindow() |
| 269 | demo.root.mainloop() |
Martin v. Löwis | 8718459 | 2008-06-04 06:29:55 +0000 | [diff] [blame] | 270 | |
| 271 | if __name__ == '__main__': |
Terry Jan Reedy | cbe6d24 | 2014-07-23 17:27:51 -0400 | [diff] [blame] | 272 | main() |