blob: a44743386f2de4cd39470caa0d5c2e6b50858768 [file] [log] [blame]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001#
2# turtle.py: a Tkinter based turtle graphics module for Python
Georg Brandleaa84ef2009-05-05 08:14:33 +00003# Version 1.1b - 4. 5. 2009
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004#
Benjamin Peterson46a99002010-01-09 18:45:30 +00005# Copyright (C) 2006 - 2010 Gregor Lingl
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00006# email: glingl@aon.at
7#
8# This software is provided 'as-is', without any express or implied
9# warranty. In no event will the authors be held liable for any damages
10# arising from the use of this software.
11#
12# Permission is granted to anyone to use this software for any purpose,
13# including commercial applications, and to alter it and redistribute it
14# freely, subject to the following restrictions:
15#
16# 1. The origin of this software must not be misrepresented; you must not
17# claim that you wrote the original software. If you use this software
18# in a product, an acknowledgment in the product documentation would be
19# appreciated but is not required.
20# 2. Altered source versions must be plainly marked as such, and must not be
21# misrepresented as being the original software.
22# 3. This notice may not be removed or altered from any source distribution.
23
Guido van Rossumb241b671998-12-04 16:42:46 +000024
Thomas Wouters477c8d52006-05-27 19:21:47 +000025"""
26Turtle graphics is a popular way for introducing programming to
27kids. It was part of the original Logo programming language developed
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000028by Wally Feurzig and Seymour Papert in 1966.
Thomas Wouters477c8d52006-05-27 19:21:47 +000029
Sandro Tosi2a389e42011-08-07 17:12:19 +020030Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
Thomas Wouters477c8d52006-05-27 19:21:47 +000031the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
32the direction it is facing, drawing a line as it moves. Give it the
Sandro Tosi2a389e42011-08-07 17:12:19 +020033command turtle.right(25), and it rotates in-place 25 degrees clockwise.
Thomas Wouters477c8d52006-05-27 19:21:47 +000034
35By combining together these and similar commands, intricate shapes and
36pictures can easily be drawn.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000037
38----- turtle.py
39
40This module is an extended reimplementation of turtle.py from the
Mark Dickinsonf8798f52009-02-20 20:53:56 +000041Python standard distribution up to Python 2.5. (See: http://www.python.org)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000042
43It tries to keep the merits of turtle.py and to be (nearly) 100%
44compatible with it. This means in the first place to enable the
45learning programmer to use all the commands, classes and methods
46interactively when using the module from within IDLE run with
47the -n switch.
48
49Roughly it has the following features added:
50
51- Better animation of the turtle movements, especially of turning the
52 turtle. So the turtles can more easily be used as a visual feedback
53 instrument by the (beginning) programmer.
54
55- Different turtle shapes, gif-images as turtle shapes, user defined
56 and user controllable turtle shapes, among them compound
Mark Dickinsonf8798f52009-02-20 20:53:56 +000057 (multicolored) shapes. Turtle shapes can be stretched and tilted, which
Mark Dickinson0fc61cc2009-02-20 20:50:21 +000058 makes turtles very versatile geometrical objects.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000059
60- Fine control over turtle movement and screen updates via delay(),
61 and enhanced tracer() and speed() methods.
62
63- Aliases for the most commonly used commands, like fd for forward etc.,
64 following the early Logo traditions. This reduces the boring work of
65 typing long sequences of commands, which often occur in a natural way
66 when kids try to program fancy pictures on their first encounter with
Mark Dickinsonf8798f52009-02-20 20:53:56 +000067 turtle graphics.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000068
69- Turtles now have an undo()-method with configurable undo-buffer.
70
71- Some simple commands/methods for creating event driven programs
72 (mouse-, key-, timer-events). Especially useful for programming games.
73
74- A scrollable Canvas class. The default scrollable Canvas can be
75 extended interactively as needed while playing around with the turtle(s).
76
77- A TurtleScreen class with methods controlling background color or
78 background image, window and canvas size and other properties of the
79 TurtleScreen.
80
81- There is a method, setworldcoordinates(), to install a user defined
82 coordinate-system for the TurtleScreen.
83
84- The implementation uses a 2-vector class named Vec2D, derived from tuple.
85 This class is public, so it can be imported by the application programmer,
86 which makes certain types of computations very natural and compact.
87
88- Appearance of the TurtleScreen and the Turtles at startup/import can be
89 configured by means of a turtle.cfg configuration file.
90 The default configuration mimics the appearance of the old turtle module.
91
92- If configured appropriately the module reads in docstrings from a docstring
93 dictionary in some different language, supplied separately and replaces
Mark Dickinsonf8798f52009-02-20 20:53:56 +000094 the English ones by those read in. There is a utility function
95 write_docstringdict() to write a dictionary with the original (English)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000096 docstrings to disc, so it can serve as a template for translations.
97
98Behind the scenes there are some features included with possible
Ezio Melottie130a522011-10-19 10:58:56 +030099extensions in mind. These will be commented and documented elsewhere.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000100
Thomas Wouters477c8d52006-05-27 19:21:47 +0000101"""
102
Georg Brandleaa84ef2009-05-05 08:14:33 +0000103_ver = "turtle 1.1b- - for Python 3.1 - 4. 5. 2009"
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000104
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000105# print(_ver)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000106
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000107import tkinter as TK
108import types
109import math
110import time
Alexander Belopolskyc1a68362010-10-27 13:25:45 +0000111import inspect
Guido van Rossumb241b671998-12-04 16:42:46 +0000112
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000113from os.path import isfile, split, join
114from copy import deepcopy
Georg Brandleaa84ef2009-05-05 08:14:33 +0000115from tkinter import simpledialog
Guido van Rossumb241b671998-12-04 16:42:46 +0000116
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000117_tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
118 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
119_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
120 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
Georg Brandleaa84ef2009-05-05 08:14:33 +0000121 'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
122 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000123 'register_shape', 'resetscreen', 'screensize', 'setup',
Georg Brandleaa84ef2009-05-05 08:14:33 +0000124 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000125 'window_height', 'window_width']
126_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
127 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
128 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
Georg Brandl46afef32009-10-14 18:46:15 +0000129 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000130 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
131 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
132 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
133 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
134 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
Georg Brandleaa84ef2009-05-05 08:14:33 +0000135 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
136 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000137 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000138 'write', 'xcor', 'ycor']
Georg Brandleaa84ef2009-05-05 08:14:33 +0000139_tg_utilities = ['write_docstringdict', 'done']
Thomas Wouters477c8d52006-05-27 19:21:47 +0000140
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000141__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
142 _tg_utilities) # + _math_functions)
Guido van Rossumb241b671998-12-04 16:42:46 +0000143
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000144_alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
145 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
146 'turtlesize', 'up', 'width']
Thomas Wouters477c8d52006-05-27 19:21:47 +0000147
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000148_CFG = {"width" : 0.5, # Screen
149 "height" : 0.75,
150 "canvwidth" : 400,
151 "canvheight": 300,
152 "leftright": None,
153 "topbottom": None,
154 "mode": "standard", # TurtleScreen
155 "colormode": 1.0,
156 "delay": 10,
157 "undobuffersize": 1000, # RawTurtle
158 "shape": "classic",
159 "pencolor" : "black",
160 "fillcolor" : "black",
161 "resizemode" : "noresize",
162 "visible" : True,
163 "language": "english", # docstrings
164 "exampleturtle": "turtle",
165 "examplescreen": "screen",
166 "title": "Python Turtle Graphics",
167 "using_IDLE": False
168 }
Guido van Rossumb241b671998-12-04 16:42:46 +0000169
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000170def config_dict(filename):
171 """Convert content of config-file into dictionary."""
Florent Xicluna7dde7922010-09-03 19:52:03 +0000172 with open(filename, "r") as f:
173 cfglines = f.readlines()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000174 cfgdict = {}
175 for line in cfglines:
176 line = line.strip()
177 if not line or line.startswith("#"):
178 continue
179 try:
180 key, value = line.split("=")
181 except:
182 print("Bad line in config-file %s:\n%s" % (filename,line))
183 continue
184 key = key.strip()
185 value = value.strip()
186 if value in ["True", "False", "None", "''", '""']:
187 value = eval(value)
Guido van Rossumb241b671998-12-04 16:42:46 +0000188 else:
189 try:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000190 if "." in value:
191 value = float(value)
192 else:
193 value = int(value)
Guido van Rossumb241b671998-12-04 16:42:46 +0000194 except:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000195 pass # value need not be converted
196 cfgdict[key] = value
197 return cfgdict
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000198
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000199def readconfig(cfgdict):
200 """Read config-files, change configuration-dict accordingly.
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000201
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000202 If there is a turtle.cfg file in the current working directory,
203 read it from there. If this contains an importconfig-value,
204 say 'myway', construct filename turtle_mayway.cfg else use
205 turtle.cfg and read it from the import-directory, where
206 turtle.py is located.
207 Update configuration dictionary first according to config-file,
208 in the import directory, then according to config-file in the
209 current working directory.
210 If no config-file is found, the default configuration is used.
211 """
212 default_cfg = "turtle.cfg"
213 cfgdict1 = {}
214 cfgdict2 = {}
215 if isfile(default_cfg):
216 cfgdict1 = config_dict(default_cfg)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000217 if "importconfig" in cfgdict1:
218 default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
219 try:
220 head, tail = split(__file__)
221 cfg_file2 = join(head, default_cfg)
222 except:
223 cfg_file2 = ""
224 if isfile(cfg_file2):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000225 cfgdict2 = config_dict(cfg_file2)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000226 _CFG.update(cfgdict2)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000227 _CFG.update(cfgdict1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000228
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000229try:
230 readconfig(_CFG)
231except:
232 print ("No configfile read, reason unknown")
233
234
235class Vec2D(tuple):
236 """A 2 dimensional vector class, used as a helper class
237 for implementing turtle graphics.
238 May be useful for turtle graphics programs also.
239 Derived from tuple, so a vector is a tuple!
240
241 Provides (for a, b vectors, k number):
242 a+b vector addition
243 a-b vector subtraction
244 a*b inner product
245 k*a and a*k multiplication with scalar
246 |a| absolute value of a
247 a.rotate(angle) rotation
248 """
249 def __new__(cls, x, y):
250 return tuple.__new__(cls, (x, y))
251 def __add__(self, other):
252 return Vec2D(self[0]+other[0], self[1]+other[1])
253 def __mul__(self, other):
254 if isinstance(other, Vec2D):
255 return self[0]*other[0]+self[1]*other[1]
256 return Vec2D(self[0]*other, self[1]*other)
257 def __rmul__(self, other):
258 if isinstance(other, int) or isinstance(other, float):
259 return Vec2D(self[0]*other, self[1]*other)
260 def __sub__(self, other):
261 return Vec2D(self[0]-other[0], self[1]-other[1])
262 def __neg__(self):
263 return Vec2D(-self[0], -self[1])
264 def __abs__(self):
265 return (self[0]**2 + self[1]**2)**0.5
266 def rotate(self, angle):
267 """rotate self counterclockwise by angle
268 """
269 perp = Vec2D(-self[1], self[0])
270 angle = angle * math.pi / 180.0
271 c, s = math.cos(angle), math.sin(angle)
272 return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
273 def __getnewargs__(self):
274 return (self[0], self[1])
275 def __repr__(self):
276 return "(%.2f,%.2f)" % self
277
278
279##############################################################################
280### From here up to line : Tkinter - Interface for turtle.py ###
Mark Dickinsonf8798f52009-02-20 20:53:56 +0000281### May be replaced by an interface to some different graphics toolkit ###
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000282##############################################################################
283
284## helper functions for Scrolled Canvas, to forward Canvas-methods
285## to ScrolledCanvas class
286
287def __methodDict(cls, _dict):
288 """helper function for Scrolled Canvas"""
289 baseList = list(cls.__bases__)
290 baseList.reverse()
291 for _super in baseList:
292 __methodDict(_super, _dict)
293 for key, value in cls.__dict__.items():
294 if type(value) == types.FunctionType:
295 _dict[key] = value
296
297def __methods(cls):
298 """helper function for Scrolled Canvas"""
299 _dict = {}
300 __methodDict(cls, _dict)
301 return _dict.keys()
302
303__stringBody = (
304 'def %(method)s(self, *args, **kw): return ' +
305 'self.%(attribute)s.%(method)s(*args, **kw)')
306
307def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
308 ### MANY CHANGES ###
309 _dict_1 = {}
310 __methodDict(toClass, _dict_1)
311 _dict = {}
312 mfc = __methods(fromClass)
313 for ex in _dict_1.keys():
314 if ex[:1] == '_' or ex[-1:] == '_' or ex in exclude or ex in mfc:
315 pass
316 else:
317 _dict[ex] = _dict_1[ex]
318
319 for method, func in _dict.items():
320 d = {'method': method, 'func': func}
321 if isinstance(toPart, str):
322 execString = \
323 __stringBody % {'method' : method, 'attribute' : toPart}
324 exec(execString, d)
325 setattr(fromClass, method, d[method]) ### NEWU!
326
327
328class ScrolledCanvas(TK.Frame):
329 """Modeled after the scrolled canvas class from Grayons's Tkinter book.
330
331 Used as the default canvas, which pops up automatically when
332 using turtle graphics functions or the Turtle class.
333 """
334 def __init__(self, master, width=500, height=350,
335 canvwidth=600, canvheight=500):
336 TK.Frame.__init__(self, master, width=width, height=height)
Martin v. Löwis22d297b2008-11-19 09:14:30 +0000337 self._rootwindow = self.winfo_toplevel()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000338 self.width, self.height = width, height
339 self.canvwidth, self.canvheight = canvwidth, canvheight
340 self.bg = "white"
341 self._canvas = TK.Canvas(master, width=width, height=height,
342 bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
343 self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
344 orient=TK.HORIZONTAL)
345 self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
346 self._canvas.configure(xscrollcommand=self.hscroll.set,
347 yscrollcommand=self.vscroll.set)
348 self.rowconfigure(0, weight=1, minsize=0)
349 self.columnconfigure(0, weight=1, minsize=0)
350 self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
351 column=0, rowspan=1, columnspan=1, sticky='news')
352 self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
353 column=1, rowspan=1, columnspan=1, sticky='news')
354 self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
355 column=0, rowspan=1, columnspan=1, sticky='news')
356 self.reset()
Martin v. Löwis22d297b2008-11-19 09:14:30 +0000357 self._rootwindow.bind('<Configure>', self.onResize)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000358
359 def reset(self, canvwidth=None, canvheight=None, bg = None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +0000360 """Adjust canvas and scrollbars according to given canvas size."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000361 if canvwidth:
362 self.canvwidth = canvwidth
363 if canvheight:
364 self.canvheight = canvheight
365 if bg:
366 self.bg = bg
367 self._canvas.config(bg=bg,
368 scrollregion=(-self.canvwidth//2, -self.canvheight//2,
369 self.canvwidth//2, self.canvheight//2))
370 self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
371 self.canvwidth)
372 self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
373 self.canvheight)
374 self.adjustScrolls()
375
376
377 def adjustScrolls(self):
378 """ Adjust scrollbars according to window- and canvas-size.
379 """
380 cwidth = self._canvas.winfo_width()
381 cheight = self._canvas.winfo_height()
382 self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
383 self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
384 if cwidth < self.canvwidth or cheight < self.canvheight:
385 self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
386 column=0, rowspan=1, columnspan=1, sticky='news')
387 self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
388 column=1, rowspan=1, columnspan=1, sticky='news')
389 else:
390 self.hscroll.grid_forget()
391 self.vscroll.grid_forget()
392
393 def onResize(self, event):
394 """self-explanatory"""
395 self.adjustScrolls()
396
397 def bbox(self, *args):
398 """ 'forward' method, which canvas itself has inherited...
399 """
400 return self._canvas.bbox(*args)
401
402 def cget(self, *args, **kwargs):
403 """ 'forward' method, which canvas itself has inherited...
404 """
405 return self._canvas.cget(*args, **kwargs)
406
407 def config(self, *args, **kwargs):
408 """ 'forward' method, which canvas itself has inherited...
409 """
410 self._canvas.config(*args, **kwargs)
411
412 def bind(self, *args, **kwargs):
413 """ 'forward' method, which canvas itself has inherited...
414 """
415 self._canvas.bind(*args, **kwargs)
416
417 def unbind(self, *args, **kwargs):
418 """ 'forward' method, which canvas itself has inherited...
419 """
420 self._canvas.unbind(*args, **kwargs)
421
422 def focus_force(self):
423 """ 'forward' method, which canvas itself has inherited...
424 """
425 self._canvas.focus_force()
426
427__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
428
429
430class _Root(TK.Tk):
431 """Root class for Screen based on Tkinter."""
432 def __init__(self):
433 TK.Tk.__init__(self)
434
435 def setupcanvas(self, width, height, cwidth, cheight):
436 self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
437 self._canvas.pack(expand=1, fill="both")
438
439 def _getcanvas(self):
440 return self._canvas
441
442 def set_geometry(self, width, height, startx, starty):
443 self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
444
445 def ondestroy(self, destroy):
446 self.wm_protocol("WM_DELETE_WINDOW", destroy)
447
448 def win_width(self):
449 return self.winfo_screenwidth()
450
451 def win_height(self):
452 return self.winfo_screenheight()
453
454Canvas = TK.Canvas
455
456
457class TurtleScreenBase(object):
458 """Provide the basic graphics functionality.
459 Interface between Tkinter and turtle.py.
460
461 To port turtle.py to some different graphics toolkit
462 a corresponding TurtleScreenBase class has to be implemented.
463 """
464
465 @staticmethod
466 def _blankimage():
467 """return a blank image object
468 """
469 img = TK.PhotoImage(width=1, height=1)
470 img.blank()
471 return img
472
473 @staticmethod
474 def _image(filename):
475 """return an image object containing the
476 imagedata from a gif-file named filename.
477 """
478 return TK.PhotoImage(file=filename)
479
480 def __init__(self, cv):
481 self.cv = cv
482 if isinstance(cv, ScrolledCanvas):
483 w = self.cv.canvwidth
484 h = self.cv.canvheight
485 else: # expected: ordinary TK.Canvas
486 w = int(self.cv.cget("width"))
487 h = int(self.cv.cget("height"))
488 self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
489 self.canvwidth = w
490 self.canvheight = h
491 self.xscale = self.yscale = 1.0
492
493 def _createpoly(self):
494 """Create an invisible polygon item on canvas self.cv)
495 """
496 return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
497
498 def _drawpoly(self, polyitem, coordlist, fill=None,
499 outline=None, width=None, top=False):
500 """Configure polygonitem polyitem according to provided
501 arguments:
502 coordlist is sequence of coordinates
503 fill is filling color
504 outline is outline color
505 top is a boolean value, which specifies if polyitem
506 will be put on top of the canvas' displaylist so it
507 will not be covered by other items.
508 """
509 cl = []
510 for x, y in coordlist:
511 cl.append(x * self.xscale)
512 cl.append(-y * self.yscale)
513 self.cv.coords(polyitem, *cl)
514 if fill is not None:
515 self.cv.itemconfigure(polyitem, fill=fill)
516 if outline is not None:
517 self.cv.itemconfigure(polyitem, outline=outline)
518 if width is not None:
519 self.cv.itemconfigure(polyitem, width=width)
520 if top:
521 self.cv.tag_raise(polyitem)
522
523 def _createline(self):
524 """Create an invisible line item on canvas self.cv)
525 """
526 return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
527 capstyle = TK.ROUND)
528
529 def _drawline(self, lineitem, coordlist=None,
530 fill=None, width=None, top=False):
531 """Configure lineitem according to provided arguments:
532 coordlist is sequence of coordinates
533 fill is drawing color
534 width is width of drawn line.
535 top is a boolean value, which specifies if polyitem
536 will be put on top of the canvas' displaylist so it
537 will not be covered by other items.
538 """
539 if coordlist is not None:
540 cl = []
541 for x, y in coordlist:
542 cl.append(x * self.xscale)
543 cl.append(-y * self.yscale)
544 self.cv.coords(lineitem, *cl)
545 if fill is not None:
546 self.cv.itemconfigure(lineitem, fill=fill)
547 if width is not None:
548 self.cv.itemconfigure(lineitem, width=width)
549 if top:
550 self.cv.tag_raise(lineitem)
551
552 def _delete(self, item):
553 """Delete graphics item from canvas.
554 If item is"all" delete all graphics items.
555 """
556 self.cv.delete(item)
557
558 def _update(self):
559 """Redraw graphics items on canvas
560 """
561 self.cv.update()
562
563 def _delay(self, delay):
564 """Delay subsequent canvas actions for delay ms."""
565 self.cv.after(delay)
566
567 def _iscolorstring(self, color):
568 """Check if the string color is a legal Tkinter color string.
569 """
570 try:
571 rgb = self.cv.winfo_rgb(color)
572 ok = True
573 except TK.TclError:
574 ok = False
575 return ok
576
577 def _bgcolor(self, color=None):
578 """Set canvas' backgroundcolor if color is not None,
579 else return backgroundcolor."""
580 if color is not None:
581 self.cv.config(bg = color)
582 self._update()
583 else:
584 return self.cv.cget("bg")
585
586 def _write(self, pos, txt, align, font, pencolor):
587 """Write txt at pos in canvas with specified font
588 and color.
589 Return text item and x-coord of right bottom corner
590 of text's bounding box."""
591 x, y = pos
592 x = x * self.xscale
593 y = y * self.yscale
594 anchor = {"left":"sw", "center":"s", "right":"se" }
595 item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
596 fill = pencolor, font = font)
597 x0, y0, x1, y1 = self.cv.bbox(item)
598 self.cv.update()
599 return item, x1-1
600
601## def _dot(self, pos, size, color):
602## """may be implemented for some other graphics toolkit"""
603
604 def _onclick(self, item, fun, num=1, add=None):
605 """Bind fun to mouse-click event on turtle.
606 fun must be a function with two arguments, the coordinates
607 of the clicked point on the canvas.
608 num, the number of the mouse-button defaults to 1
609 """
610 if fun is None:
611 self.cv.tag_unbind(item, "<Button-%s>" % num)
612 else:
613 def eventfun(event):
614 x, y = (self.cv.canvasx(event.x)/self.xscale,
615 -self.cv.canvasy(event.y)/self.yscale)
616 fun(x, y)
617 self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
618
619 def _onrelease(self, item, fun, num=1, add=None):
620 """Bind fun to mouse-button-release event on turtle.
621 fun must be a function with two arguments, the coordinates
622 of the point on the canvas where mouse button is released.
623 num, the number of the mouse-button defaults to 1
624
625 If a turtle is clicked, first _onclick-event will be performed,
626 then _onscreensclick-event.
627 """
628 if fun is None:
629 self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
630 else:
631 def eventfun(event):
632 x, y = (self.cv.canvasx(event.x)/self.xscale,
633 -self.cv.canvasy(event.y)/self.yscale)
634 fun(x, y)
635 self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
636 eventfun, add)
637
638 def _ondrag(self, item, fun, num=1, add=None):
639 """Bind fun to mouse-move-event (with pressed mouse button) on turtle.
640 fun must be a function with two arguments, the coordinates of the
641 actual mouse position on the canvas.
642 num, the number of the mouse-button defaults to 1
643
644 Every sequence of mouse-move-events on a turtle is preceded by a
645 mouse-click event on that turtle.
646 """
647 if fun is None:
648 self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
649 else:
650 def eventfun(event):
651 try:
652 x, y = (self.cv.canvasx(event.x)/self.xscale,
653 -self.cv.canvasy(event.y)/self.yscale)
654 fun(x, y)
655 except:
656 pass
657 self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
658
659 def _onscreenclick(self, fun, num=1, add=None):
660 """Bind fun to mouse-click event on canvas.
661 fun must be a function with two arguments, the coordinates
662 of the clicked point on the canvas.
663 num, the number of the mouse-button defaults to 1
664
665 If a turtle is clicked, first _onclick-event will be performed,
666 then _onscreensclick-event.
667 """
668 if fun is None:
669 self.cv.unbind("<Button-%s>" % num)
670 else:
671 def eventfun(event):
672 x, y = (self.cv.canvasx(event.x)/self.xscale,
673 -self.cv.canvasy(event.y)/self.yscale)
674 fun(x, y)
675 self.cv.bind("<Button-%s>" % num, eventfun, add)
676
Georg Brandleaa84ef2009-05-05 08:14:33 +0000677 def _onkeyrelease(self, fun, key):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000678 """Bind fun to key-release event of key.
679 Canvas must have focus. See method listen
680 """
681 if fun is None:
682 self.cv.unbind("<KeyRelease-%s>" % key, None)
683 else:
684 def eventfun(event):
685 fun()
686 self.cv.bind("<KeyRelease-%s>" % key, eventfun)
687
Georg Brandleaa84ef2009-05-05 08:14:33 +0000688 def _onkeypress(self, fun, key=None):
689 """If key is given, bind fun to key-press event of key.
690 Otherwise bind fun to any key-press.
691 Canvas must have focus. See method listen.
692 """
693 if fun is None:
694 if key is None:
695 self.cv.unbind("<KeyPress>", None)
696 else:
697 self.cv.unbind("<KeyPress-%s>" % key, None)
698 else:
699 def eventfun(event):
700 fun()
701 if key is None:
702 self.cv.bind("<KeyPress>", eventfun)
703 else:
704 self.cv.bind("<KeyPress-%s>" % key, eventfun)
705
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000706 def _listen(self):
707 """Set focus on canvas (in order to collect key-events)
708 """
709 self.cv.focus_force()
710
711 def _ontimer(self, fun, t):
712 """Install a timer, which calls fun after t milliseconds.
713 """
714 if t == 0:
715 self.cv.after_idle(fun)
716 else:
717 self.cv.after(t, fun)
718
719 def _createimage(self, image):
720 """Create and return image item on canvas.
721 """
722 return self.cv.create_image(0, 0, image=image)
723
724 def _drawimage(self, item, pos, image):
725 """Configure image item as to draw image object
726 at position (x,y) on canvas)
727 """
728 x, y = pos
729 self.cv.coords(item, (x * self.xscale, -y * self.yscale))
730 self.cv.itemconfig(item, image=image)
731
732 def _setbgpic(self, item, image):
733 """Configure image item as to draw image object
734 at center of canvas. Set item to the first item
735 in the displaylist, so it will be drawn below
736 any other item ."""
737 self.cv.itemconfig(item, image=image)
738 self.cv.tag_lower(item)
739
740 def _type(self, item):
741 """Return 'line' or 'polygon' or 'image' depending on
742 type of item.
743 """
744 return self.cv.type(item)
745
746 def _pointlist(self, item):
747 """returns list of coordinate-pairs of points of item
748 Example (for insiders):
749 >>> from turtle import *
750 >>> getscreen()._pointlist(getturtle().turtle._item)
751 [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
752 (9.9999999999999982, 0.0)]
753 >>> """
Alexander Belopolsky022f0492010-11-22 19:40:51 +0000754 cl = self.cv.coords(item)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000755 pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
756 return pl
757
758 def _setscrollregion(self, srx1, sry1, srx2, sry2):
759 self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
760
761 def _rescale(self, xscalefactor, yscalefactor):
762 items = self.cv.find_all()
763 for item in items:
764 coordinates = list(self.cv.coords(item))
765 newcoordlist = []
766 while coordinates:
767 x, y = coordinates[:2]
768 newcoordlist.append(x * xscalefactor)
769 newcoordlist.append(y * yscalefactor)
770 coordinates = coordinates[2:]
771 self.cv.coords(item, *newcoordlist)
772
773 def _resize(self, canvwidth=None, canvheight=None, bg=None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +0000774 """Resize the canvas the turtles are drawing on. Does
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000775 not alter the drawing window.
776 """
777 # needs amendment
778 if not isinstance(self.cv, ScrolledCanvas):
779 return self.canvwidth, self.canvheight
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000780 if canvwidth is canvheight is bg is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000781 return self.cv.canvwidth, self.cv.canvheight
782 if canvwidth is not None:
783 self.canvwidth = canvwidth
784 if canvheight is not None:
785 self.canvheight = canvheight
786 self.cv.reset(canvwidth, canvheight, bg)
787
788 def _window_size(self):
789 """ Return the width and height of the turtle window.
790 """
791 width = self.cv.winfo_width()
792 if width <= 1: # the window isn't managed by a geometry manager
793 width = self.cv['width']
794 height = self.cv.winfo_height()
795 if height <= 1: # the window isn't managed by a geometry manager
796 height = self.cv['height']
797 return width, height
798
Georg Brandleaa84ef2009-05-05 08:14:33 +0000799 def mainloop(self):
800 """Starts event loop - calling Tkinter's mainloop function.
801
802 No argument.
803
804 Must be last statement in a turtle graphics program.
805 Must NOT be used if a script is run from within IDLE in -n mode
806 (No subprocess) - for interactive use of turtle graphics.
807
808 Example (for a TurtleScreen instance named screen):
809 >>> screen.mainloop()
810
811 """
812 TK.mainloop()
813
814 def textinput(self, title, prompt):
815 """Pop up a dialog window for input of a string.
816
817 Arguments: title is the title of the dialog window,
818 prompt is a text mostly describing what information to input.
819
820 Return the string input
821 If the dialog is canceled, return None.
822
823 Example (for a TurtleScreen instance named screen):
824 >>> screen.textinput("NIM", "Name of first player:")
825
826 """
827 return simpledialog.askstring(title, prompt)
828
829 def numinput(self, title, prompt, default=None, minval=None, maxval=None):
830 """Pop up a dialog window for input of a number.
831
832 Arguments: title is the title of the dialog window,
833 prompt is a text mostly describing what numerical information to input.
834 default: default value
835 minval: minimum value for imput
836 maxval: maximum value for input
837
838 The number input must be in the range minval .. maxval if these are
839 given. If not, a hint is issued and the dialog remains open for
840 correction. Return the number input.
841 If the dialog is canceled, return None.
842
843 Example (for a TurtleScreen instance named screen):
844 >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000)
845
846 """
847 return simpledialog.askfloat(title, prompt, initialvalue=default,
848 minvalue=minval, maxvalue=maxval)
849
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000850
851##############################################################################
852### End of Tkinter - interface ###
853##############################################################################
854
855
856class Terminator (Exception):
857 """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
858
859 Thus stops execution of turtle graphics script. Main purpose: use in
860 in the Demo-Viewer turtle.Demo.py.
861 """
862 pass
863
864
865class TurtleGraphicsError(Exception):
866 """Some TurtleGraphics Error
867 """
868
869
870class Shape(object):
871 """Data structure modeling shapes.
872
873 attribute _type is one of "polygon", "image", "compound"
874 attribute _data is - depending on _type a poygon-tuple,
875 an image or a list constructed using the addcomponent method.
876 """
877 def __init__(self, type_, data=None):
878 self._type = type_
879 if type_ == "polygon":
880 if isinstance(data, list):
881 data = tuple(data)
882 elif type_ == "image":
883 if isinstance(data, str):
884 if data.lower().endswith(".gif") and isfile(data):
885 data = TurtleScreen._image(data)
886 # else data assumed to be Photoimage
887 elif type_ == "compound":
888 data = []
889 else:
890 raise TurtleGraphicsError("There is no shape type %s" % type_)
891 self._data = data
892
893 def addcomponent(self, poly, fill, outline=None):
894 """Add component to a shape of type compound.
895
896 Arguments: poly is a polygon, i. e. a tuple of number pairs.
897 fill is the fillcolor of the component,
898 outline is the outline color of the component.
899
900 call (for a Shapeobject namend s):
901 -- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000902
903 Example:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000904 >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
905 >>> s = Shape("compound")
906 >>> s.addcomponent(poly, "red", "blue")
Petri Lehtinen9aa20af2011-12-02 21:24:14 +0200907 >>> # .. add more components and then use register_shape()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000908 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000909 if self._type != "compound":
910 raise TurtleGraphicsError("Cannot add component to %s Shape"
911 % self._type)
912 if outline is None:
913 outline = fill
914 self._data.append([poly, fill, outline])
Guido van Rossumb241b671998-12-04 16:42:46 +0000915
Thomas Wouters477c8d52006-05-27 19:21:47 +0000916
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000917class Tbuffer(object):
918 """Ring buffer used as undobuffer for RawTurtle objects."""
919 def __init__(self, bufsize=10):
920 self.bufsize = bufsize
921 self.buffer = [[None]] * bufsize
922 self.ptr = -1
923 self.cumulate = False
924 def reset(self, bufsize=None):
925 if bufsize is None:
926 for i in range(self.bufsize):
927 self.buffer[i] = [None]
928 else:
929 self.bufsize = bufsize
930 self.buffer = [[None]] * bufsize
931 self.ptr = -1
932 def push(self, item):
933 if self.bufsize > 0:
934 if not self.cumulate:
935 self.ptr = (self.ptr + 1) % self.bufsize
936 self.buffer[self.ptr] = item
937 else:
938 self.buffer[self.ptr].append(item)
939 def pop(self):
940 if self.bufsize > 0:
941 item = self.buffer[self.ptr]
942 if item is None:
943 return None
944 else:
945 self.buffer[self.ptr] = [None]
946 self.ptr = (self.ptr - 1) % self.bufsize
947 return (item)
948 def nr_of_items(self):
949 return self.bufsize - self.buffer.count([None])
950 def __repr__(self):
951 return str(self.buffer) + " " + str(self.ptr)
952
953
954
955class TurtleScreen(TurtleScreenBase):
956 """Provides screen oriented methods like setbg etc.
957
958 Only relies upon the methods of TurtleScreenBase and NOT
959 upon components of the underlying graphics toolkit -
960 which is Tkinter in this case.
961 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000962 _RUNNING = True
963
964 def __init__(self, cv, mode=_CFG["mode"],
965 colormode=_CFG["colormode"], delay=_CFG["delay"]):
966 self._shapes = {
967 "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
968 "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
969 (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
970 (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
971 (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
972 (2,14))),
973 "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
974 (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
975 (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
976 (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
977 (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
978 (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
979 "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
980 (-10,-10))),
981 "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
982 (-10,-5.77))),
983 "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
984 "blank" : Shape("image", self._blankimage())
985 }
986
987 self._bgpics = {"nopic" : ""}
988
989 TurtleScreenBase.__init__(self, cv)
990 self._mode = mode
991 self._delayvalue = delay
992 self._colormode = _CFG["colormode"]
993 self._keys = []
994 self.clear()
995
996 def clear(self):
997 """Delete all drawings and all turtles from the TurtleScreen.
998
Georg Brandleaa84ef2009-05-05 08:14:33 +0000999 No argument.
1000
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001001 Reset empty TurtleScreen to its initial state: white background,
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001002 no backgroundimage, no eventbindings and tracing on.
1003
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001004 Example (for a TurtleScreen instance named screen):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001005 >>> screen.clear()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001006
1007 Note: this method is not available as function.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001008 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001009 self._delayvalue = _CFG["delay"]
1010 self._colormode = _CFG["colormode"]
1011 self._delete("all")
1012 self._bgpic = self._createimage("")
1013 self._bgpicname = "nopic"
1014 self._tracing = 1
1015 self._updatecounter = 0
1016 self._turtles = []
1017 self.bgcolor("white")
1018 for btn in 1, 2, 3:
1019 self.onclick(None, btn)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001020 self.onkeypress(None)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001021 for key in self._keys[:]:
1022 self.onkey(None, key)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001023 self.onkeypress(None, key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001024 Turtle._pen = None
Guido van Rossumb241b671998-12-04 16:42:46 +00001025
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001026 def mode(self, mode=None):
1027 """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001028
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001029 Optional argument:
1030 mode -- on of the strings 'standard', 'logo' or 'world'
1031
1032 Mode 'standard' is compatible with turtle.py.
1033 Mode 'logo' is compatible with most Logo-Turtle-Graphics.
1034 Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
1035 this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
1036 If mode is not given, return the current mode.
1037
1038 Mode Initial turtle heading positive angles
1039 ------------|-------------------------|-------------------
1040 'standard' to the right (east) counterclockwise
1041 'logo' upward (north) clockwise
1042
1043 Examples:
1044 >>> mode('logo') # resets turtle heading to north
1045 >>> mode()
1046 'logo'
Thomas Wouters477c8d52006-05-27 19:21:47 +00001047 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001048 if mode is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001049 return self._mode
1050 mode = mode.lower()
1051 if mode not in ["standard", "logo", "world"]:
1052 raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
1053 self._mode = mode
1054 if mode in ["standard", "logo"]:
1055 self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
1056 self.canvwidth//2, self.canvheight//2)
1057 self.xscale = self.yscale = 1.0
1058 self.reset()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001059
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001060 def setworldcoordinates(self, llx, lly, urx, ury):
1061 """Set up a user defined coordinate-system.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001062
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001063 Arguments:
1064 llx -- a number, x-coordinate of lower left corner of canvas
1065 lly -- a number, y-coordinate of lower left corner of canvas
1066 urx -- a number, x-coordinate of upper right corner of canvas
1067 ury -- a number, y-coordinate of upper right corner of canvas
1068
1069 Set up user coodinat-system and switch to mode 'world' if necessary.
1070 This performs a screen.reset. If mode 'world' is already active,
1071 all drawings are redrawn according to the new coordinates.
1072
1073 But ATTENTION: in user-defined coordinatesystems angles may appear
1074 distorted. (see Screen.mode())
1075
1076 Example (for a TurtleScreen instance named screen):
1077 >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
1078 >>> for _ in range(36):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001079 ... left(10)
1080 ... forward(0.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001081 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001082 if self.mode() != "world":
1083 self.mode("world")
1084 xspan = float(urx - llx)
1085 yspan = float(ury - lly)
1086 wx, wy = self._window_size()
1087 self.screensize(wx-20, wy-20)
1088 oldxscale, oldyscale = self.xscale, self.yscale
1089 self.xscale = self.canvwidth / xspan
1090 self.yscale = self.canvheight / yspan
1091 srx1 = llx * self.xscale
1092 sry1 = -ury * self.yscale
1093 srx2 = self.canvwidth + srx1
1094 sry2 = self.canvheight + sry1
1095 self._setscrollregion(srx1, sry1, srx2, sry2)
1096 self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
1097 self.update()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001098
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001099 def register_shape(self, name, shape=None):
1100 """Adds a turtle shape to TurtleScreen's shapelist.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001101
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001102 Arguments:
1103 (1) name is the name of a gif-file and shape is None.
1104 Installs the corresponding image shape.
1105 !! Image-shapes DO NOT rotate when turning the turtle,
1106 !! so they do not display the heading of the turtle!
1107 (2) name is an arbitrary string and shape is a tuple
1108 of pairs of coordinates. Installs the corresponding
1109 polygon shape
1110 (3) name is an arbitrary string and shape is a
1111 (compound) Shape object. Installs the corresponding
1112 compound shape.
1113 To use a shape, you have to issue the command shape(shapename).
Thomas Wouters477c8d52006-05-27 19:21:47 +00001114
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001115 call: register_shape("turtle.gif")
1116 --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
1117
1118 Example (for a TurtleScreen instance named screen):
1119 >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
1120
Thomas Wouters477c8d52006-05-27 19:21:47 +00001121 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001122 if shape is None:
1123 # image
1124 if name.lower().endswith(".gif"):
1125 shape = Shape("image", self._image(name))
1126 else:
1127 raise TurtleGraphicsError("Bad arguments for register_shape.\n"
1128 + "Use help(register_shape)" )
1129 elif isinstance(shape, tuple):
1130 shape = Shape("polygon", shape)
1131 ## else shape assumed to be Shape-instance
1132 self._shapes[name] = shape
Guido van Rossumbffa52f2002-09-29 00:25:51 +00001133
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001134 def _colorstr(self, color):
1135 """Return color string corresponding to args.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001136
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001137 Argument may be a string or a tuple of three
1138 numbers corresponding to actual colormode,
1139 i.e. in the range 0<=n<=colormode.
1140
1141 If the argument doesn't represent a color,
1142 an error is raised.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001143 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001144 if len(color) == 1:
1145 color = color[0]
1146 if isinstance(color, str):
1147 if self._iscolorstring(color) or color == "":
1148 return color
1149 else:
1150 raise TurtleGraphicsError("bad color string: %s" % str(color))
1151 try:
1152 r, g, b = color
1153 except:
1154 raise TurtleGraphicsError("bad color arguments: %s" % str(color))
1155 if self._colormode == 1.0:
1156 r, g, b = [round(255.0*x) for x in (r, g, b)]
1157 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
1158 raise TurtleGraphicsError("bad color sequence: %s" % str(color))
1159 return "#%02x%02x%02x" % (r, g, b)
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001160
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001161 def _color(self, cstr):
1162 if not cstr.startswith("#"):
1163 return cstr
1164 if len(cstr) == 7:
1165 cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
1166 elif len(cstr) == 4:
1167 cl = [16*int(cstr[h], 16) for h in cstr[1:]]
1168 else:
1169 raise TurtleGraphicsError("bad colorstring: %s" % cstr)
1170 return tuple([c * self._colormode/255 for c in cl])
Thomas Wouters477c8d52006-05-27 19:21:47 +00001171
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001172 def colormode(self, cmode=None):
1173 """Return the colormode or set it to 1.0 or 255.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001174
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001175 Optional argument:
1176 cmode -- one of the values 1.0 or 255
Thomas Wouters477c8d52006-05-27 19:21:47 +00001177
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001178 r, g, b values of colortriples have to be in range 0..cmode.
1179
1180 Example (for a TurtleScreen instance named screen):
1181 >>> screen.colormode()
1182 1.0
1183 >>> screen.colormode(255)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001184 >>> pencolor(240,160,80)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001185 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001186 if cmode is None:
1187 return self._colormode
1188 if cmode == 1.0:
1189 self._colormode = float(cmode)
1190 elif cmode == 255:
1191 self._colormode = int(cmode)
1192
1193 def reset(self):
1194 """Reset all Turtles on the Screen to their initial state.
1195
1196 No argument.
1197
1198 Example (for a TurtleScreen instance named screen):
1199 >>> screen.reset()
1200 """
1201 for turtle in self._turtles:
1202 turtle._setmode(self._mode)
1203 turtle.reset()
1204
1205 def turtles(self):
1206 """Return the list of turtles on the screen.
1207
1208 Example (for a TurtleScreen instance named screen):
1209 >>> screen.turtles()
1210 [<turtle.Turtle object at 0x00E11FB0>]
1211 """
1212 return self._turtles
1213
1214 def bgcolor(self, *args):
1215 """Set or return backgroundcolor of the TurtleScreen.
1216
1217 Arguments (if given): a color string or three numbers
1218 in the range 0..colormode or a 3-tuple of such numbers.
1219
1220 Example (for a TurtleScreen instance named screen):
1221 >>> screen.bgcolor("orange")
1222 >>> screen.bgcolor()
1223 'orange'
1224 >>> screen.bgcolor(0.5,0,0.5)
1225 >>> screen.bgcolor()
1226 '#800080'
1227 """
1228 if args:
1229 color = self._colorstr(args)
1230 else:
1231 color = None
1232 color = self._bgcolor(color)
1233 if color is not None:
1234 color = self._color(color)
1235 return color
1236
1237 def tracer(self, n=None, delay=None):
1238 """Turns turtle animation on/off and set delay for update drawings.
1239
1240 Optional arguments:
1241 n -- nonnegative integer
1242 delay -- nonnegative integer
1243
1244 If n is given, only each n-th regular screen update is really performed.
1245 (Can be used to accelerate the drawing of complex graphics.)
1246 Second arguments sets delay value (see RawTurtle.delay())
1247
1248 Example (for a TurtleScreen instance named screen):
1249 >>> screen.tracer(8, 25)
1250 >>> dist = 2
1251 >>> for i in range(200):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001252 ... fd(dist)
1253 ... rt(90)
1254 ... dist += 2
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001255 """
1256 if n is None:
1257 return self._tracing
1258 self._tracing = int(n)
1259 self._updatecounter = 0
1260 if delay is not None:
1261 self._delayvalue = int(delay)
1262 if self._tracing:
1263 self.update()
1264
1265 def delay(self, delay=None):
1266 """ Return or set the drawing delay in milliseconds.
1267
1268 Optional argument:
1269 delay -- positive integer
1270
1271 Example (for a TurtleScreen instance named screen):
1272 >>> screen.delay(15)
1273 >>> screen.delay()
1274 15
1275 """
1276 if delay is None:
1277 return self._delayvalue
1278 self._delayvalue = int(delay)
1279
1280 def _incrementudc(self):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001281 """Increment upadate counter."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001282 if not TurtleScreen._RUNNING:
1283 TurtleScreen._RUNNNING = True
1284 raise Terminator
1285 if self._tracing > 0:
1286 self._updatecounter += 1
1287 self._updatecounter %= self._tracing
1288
1289 def update(self):
1290 """Perform a TurtleScreen update.
1291 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00001292 tracing = self._tracing
1293 self._tracing = True
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001294 for t in self.turtles():
1295 t._update_data()
1296 t._drawturtle()
Georg Brandleaa84ef2009-05-05 08:14:33 +00001297 self._tracing = tracing
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001298 self._update()
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001299
1300 def window_width(self):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001301 """ Return the width of the turtle window.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001302
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001303 Example (for a TurtleScreen instance named screen):
1304 >>> screen.window_width()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001305 640
1306 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001307 return self._window_size()[0]
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001308
1309 def window_height(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001310 """ Return the height of the turtle window.
1311
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001312 Example (for a TurtleScreen instance named screen):
1313 >>> screen.window_height()
1314 480
Thomas Wouters477c8d52006-05-27 19:21:47 +00001315 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001316 return self._window_size()[1]
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001317
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001318 def getcanvas(self):
1319 """Return the Canvas of this TurtleScreen.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001320
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001321 No argument.
1322
1323 Example (for a Screen instance named screen):
1324 >>> cv = screen.getcanvas()
1325 >>> cv
1326 <turtle.ScrolledCanvas instance at 0x010742D8>
Thomas Wouters477c8d52006-05-27 19:21:47 +00001327 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001328 return self.cv
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001329
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001330 def getshapes(self):
1331 """Return a list of names of all currently available turtle shapes.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001332
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001333 No argument.
1334
1335 Example (for a TurtleScreen instance named screen):
1336 >>> screen.getshapes()
1337 ['arrow', 'blank', 'circle', ... , 'turtle']
1338 """
1339 return sorted(self._shapes.keys())
1340
1341 def onclick(self, fun, btn=1, add=None):
1342 """Bind fun to mouse-click event on canvas.
1343
1344 Arguments:
1345 fun -- a function with two arguments, the coordinates of the
1346 clicked point on the canvas.
1347 num -- the number of the mouse-button, defaults to 1
1348
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001349 Example (for a TurtleScreen instance named screen)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001350
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001351 >>> screen.onclick(goto)
1352 >>> # Subsequently clicking into the TurtleScreen will
1353 >>> # make the turtle move to the clicked point.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001354 >>> screen.onclick(None)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001355 """
1356 self._onscreenclick(fun, btn, add)
1357
1358 def onkey(self, fun, key):
1359 """Bind fun to key-release event of key.
1360
1361 Arguments:
1362 fun -- a function with no arguments
1363 key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1364
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001365 In order to be able to register key-events, TurtleScreen
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001366 must have focus. (See method listen.)
1367
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001368 Example (for a TurtleScreen instance named screen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001369
1370 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001371 ... fd(50)
1372 ... lt(60)
1373 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001374 >>> screen.onkey(f, "Up")
1375 >>> screen.listen()
1376
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001377 Subsequently the turtle can be moved by repeatedly pressing
1378 the up-arrow key, consequently drawing a hexagon
1379
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001380 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001381 if fun is None:
Georg Brandleaa84ef2009-05-05 08:14:33 +00001382 if key in self._keys:
1383 self._keys.remove(key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001384 elif key not in self._keys:
1385 self._keys.append(key)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001386 self._onkeyrelease(fun, key)
1387
1388 def onkeypress(self, fun, key=None):
1389 """Bind fun to key-press event of key if key is given,
1390 or to any key-press-event if no key is given.
1391
1392 Arguments:
1393 fun -- a function with no arguments
1394 key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1395
1396 In order to be able to register key-events, TurtleScreen
1397 must have focus. (See method listen.)
1398
1399 Example (for a TurtleScreen instance named screen
1400 and a Turtle instance named turtle):
1401
1402 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001403 ... fd(50)
1404 ... lt(60)
1405 ...
1406 >>> screen.onkeypress(f, "Up")
Georg Brandleaa84ef2009-05-05 08:14:33 +00001407 >>> screen.listen()
1408
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001409 Subsequently the turtle can be moved by repeatedly pressing
1410 the up-arrow key, or by keeping pressed the up-arrow key.
1411 consequently drawing a hexagon.
Georg Brandleaa84ef2009-05-05 08:14:33 +00001412 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001413 if fun is None:
Georg Brandleaa84ef2009-05-05 08:14:33 +00001414 if key in self._keys:
1415 self._keys.remove(key)
1416 elif key is not None and key not in self._keys:
1417 self._keys.append(key)
1418 self._onkeypress(fun, key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001419
1420 def listen(self, xdummy=None, ydummy=None):
1421 """Set focus on TurtleScreen (in order to collect key-events)
1422
1423 No arguments.
1424 Dummy arguments are provided in order
1425 to be able to pass listen to the onclick method.
1426
1427 Example (for a TurtleScreen instance named screen):
1428 >>> screen.listen()
1429 """
1430 self._listen()
1431
1432 def ontimer(self, fun, t=0):
1433 """Install a timer, which calls fun after t milliseconds.
1434
1435 Arguments:
1436 fun -- a function with no arguments.
1437 t -- a number >= 0
1438
1439 Example (for a TurtleScreen instance named screen):
1440
1441 >>> running = True
1442 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001443 ... if running:
1444 ... fd(50)
1445 ... lt(60)
1446 ... screen.ontimer(f, 250)
1447 ...
1448 >>> f() # makes the turtle marching around
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001449 >>> running = False
1450 """
1451 self._ontimer(fun, t)
1452
1453 def bgpic(self, picname=None):
1454 """Set background image or return name of current backgroundimage.
1455
1456 Optional argument:
1457 picname -- a string, name of a gif-file or "nopic".
1458
Ezio Melotti42da6632011-03-15 05:18:48 +02001459 If picname is a filename, set the corresponding image as background.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001460 If picname is "nopic", delete backgroundimage, if present.
1461 If picname is None, return the filename of the current backgroundimage.
1462
1463 Example (for a TurtleScreen instance named screen):
1464 >>> screen.bgpic()
1465 'nopic'
1466 >>> screen.bgpic("landscape.gif")
1467 >>> screen.bgpic()
1468 'landscape.gif'
1469 """
1470 if picname is None:
1471 return self._bgpicname
1472 if picname not in self._bgpics:
1473 self._bgpics[picname] = self._image(picname)
1474 self._setbgpic(self._bgpic, self._bgpics[picname])
1475 self._bgpicname = picname
1476
1477 def screensize(self, canvwidth=None, canvheight=None, bg=None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001478 """Resize the canvas the turtles are drawing on.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001479
1480 Optional arguments:
1481 canvwidth -- positive integer, new width of canvas in pixels
1482 canvheight -- positive integer, new height of canvas in pixels
Ezio Melotti13925002011-03-16 11:05:33 +02001483 bg -- colorstring or color-tuple, new backgroundcolor
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001484 If no arguments are given, return current (canvaswidth, canvasheight)
1485
1486 Do not alter the drawing window. To observe hidden parts of
1487 the canvas use the scrollbars. (Can make visible those parts
1488 of a drawing, which were outside the canvas before!)
1489
1490 Example (for a Turtle instance named turtle):
1491 >>> turtle.screensize(2000,1500)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001492 >>> # e.g. to search for an erroneously escaped turtle ;-)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001493 """
1494 return self._resize(canvwidth, canvheight, bg)
1495
1496 onscreenclick = onclick
1497 resetscreen = reset
1498 clearscreen = clear
1499 addshape = register_shape
Georg Brandleaa84ef2009-05-05 08:14:33 +00001500 onkeyrelease = onkey
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001501
1502class TNavigator(object):
1503 """Navigation part of the RawTurtle.
1504 Implements methods for turtle movement.
1505 """
1506 START_ORIENTATION = {
1507 "standard": Vec2D(1.0, 0.0),
1508 "world" : Vec2D(1.0, 0.0),
1509 "logo" : Vec2D(0.0, 1.0) }
1510 DEFAULT_MODE = "standard"
1511 DEFAULT_ANGLEOFFSET = 0
1512 DEFAULT_ANGLEORIENT = 1
1513
1514 def __init__(self, mode=DEFAULT_MODE):
1515 self._angleOffset = self.DEFAULT_ANGLEOFFSET
1516 self._angleOrient = self.DEFAULT_ANGLEORIENT
1517 self._mode = mode
1518 self.undobuffer = None
1519 self.degrees()
1520 self._mode = None
1521 self._setmode(mode)
1522 TNavigator.reset(self)
1523
1524 def reset(self):
1525 """reset turtle to its initial values
1526
1527 Will be overwritten by parent class
1528 """
1529 self._position = Vec2D(0.0, 0.0)
1530 self._orient = TNavigator.START_ORIENTATION[self._mode]
1531
1532 def _setmode(self, mode=None):
1533 """Set turtle-mode to 'standard', 'world' or 'logo'.
1534 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001535 if mode is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001536 return self._mode
1537 if mode not in ["standard", "logo", "world"]:
1538 return
1539 self._mode = mode
1540 if mode in ["standard", "world"]:
1541 self._angleOffset = 0
1542 self._angleOrient = 1
1543 else: # mode == "logo":
1544 self._angleOffset = self._fullcircle/4.
1545 self._angleOrient = -1
1546
1547 def _setDegreesPerAU(self, fullcircle):
1548 """Helper function for degrees() and radians()"""
1549 self._fullcircle = fullcircle
1550 self._degreesPerAU = 360/fullcircle
1551 if self._mode == "standard":
1552 self._angleOffset = 0
1553 else:
1554 self._angleOffset = fullcircle/4.
1555
1556 def degrees(self, fullcircle=360.0):
1557 """ Set angle measurement units to degrees.
1558
1559 Optional argument:
1560 fullcircle - a number
1561
1562 Set angle measurement units, i. e. set number
1563 of 'degrees' for a full circle. Dafault value is
1564 360 degrees.
1565
1566 Example (for a Turtle instance named turtle):
1567 >>> turtle.left(90)
1568 >>> turtle.heading()
1569 90
Alexander Belopolsky3cdfb122010-10-29 17:16:49 +00001570
1571 Change angle measurement unit to grad (also known as gon,
1572 grade, or gradian and equals 1/100-th of the right angle.)
1573 >>> turtle.degrees(400.0)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001574 >>> turtle.heading()
1575 100
1576
1577 """
1578 self._setDegreesPerAU(fullcircle)
1579
1580 def radians(self):
1581 """ Set the angle measurement units to radians.
1582
1583 No arguments.
1584
1585 Example (for a Turtle instance named turtle):
1586 >>> turtle.heading()
1587 90
1588 >>> turtle.radians()
1589 >>> turtle.heading()
1590 1.5707963267948966
1591 """
1592 self._setDegreesPerAU(2*math.pi)
1593
1594 def _go(self, distance):
1595 """move turtle forward by specified distance"""
1596 ende = self._position + self._orient * distance
1597 self._goto(ende)
1598
1599 def _rotate(self, angle):
1600 """Turn turtle counterclockwise by specified angle if angle > 0."""
1601 angle *= self._degreesPerAU
1602 self._orient = self._orient.rotate(angle)
1603
1604 def _goto(self, end):
1605 """move turtle to position end."""
1606 self._position = end
1607
1608 def forward(self, distance):
1609 """Move the turtle forward by the specified distance.
1610
1611 Aliases: forward | fd
1612
1613 Argument:
1614 distance -- a number (integer or float)
1615
1616 Move the turtle forward by the specified distance, in the direction
1617 the turtle is headed.
1618
1619 Example (for a Turtle instance named turtle):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001620 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001621 (0.00, 0.00)
1622 >>> turtle.forward(25)
1623 >>> turtle.position()
1624 (25.00,0.00)
1625 >>> turtle.forward(-75)
1626 >>> turtle.position()
1627 (-50.00,0.00)
1628 """
1629 self._go(distance)
1630
1631 def back(self, distance):
1632 """Move the turtle backward by distance.
1633
1634 Aliases: back | backward | bk
1635
1636 Argument:
1637 distance -- a number
1638
1639 Move the turtle backward by distance ,opposite to the direction the
1640 turtle is headed. Do not change the turtle's heading.
1641
1642 Example (for a Turtle instance named turtle):
1643 >>> turtle.position()
1644 (0.00, 0.00)
1645 >>> turtle.backward(30)
1646 >>> turtle.position()
1647 (-30.00, 0.00)
1648 """
1649 self._go(-distance)
1650
1651 def right(self, angle):
1652 """Turn turtle right by angle units.
1653
1654 Aliases: right | rt
1655
1656 Argument:
1657 angle -- a number (integer or float)
1658
1659 Turn turtle right by angle units. (Units are by default degrees,
1660 but can be set via the degrees() and radians() functions.)
1661 Angle orientation depends on mode. (See this.)
1662
1663 Example (for a Turtle instance named turtle):
1664 >>> turtle.heading()
1665 22.0
1666 >>> turtle.right(45)
1667 >>> turtle.heading()
1668 337.0
1669 """
1670 self._rotate(-angle)
1671
1672 def left(self, angle):
1673 """Turn turtle left by angle units.
1674
1675 Aliases: left | lt
1676
1677 Argument:
1678 angle -- a number (integer or float)
1679
1680 Turn turtle left by angle units. (Units are by default degrees,
1681 but can be set via the degrees() and radians() functions.)
1682 Angle orientation depends on mode. (See this.)
1683
1684 Example (for a Turtle instance named turtle):
1685 >>> turtle.heading()
1686 22.0
1687 >>> turtle.left(45)
1688 >>> turtle.heading()
1689 67.0
1690 """
1691 self._rotate(angle)
1692
1693 def pos(self):
1694 """Return the turtle's current location (x,y), as a Vec2D-vector.
1695
1696 Aliases: pos | position
1697
1698 No arguments.
1699
1700 Example (for a Turtle instance named turtle):
1701 >>> turtle.pos()
1702 (0.00, 240.00)
1703 """
1704 return self._position
1705
1706 def xcor(self):
1707 """ Return the turtle's x coordinate.
1708
1709 No arguments.
1710
1711 Example (for a Turtle instance named turtle):
1712 >>> reset()
1713 >>> turtle.left(60)
1714 >>> turtle.forward(100)
1715 >>> print turtle.xcor()
1716 50.0
1717 """
1718 return self._position[0]
1719
1720 def ycor(self):
1721 """ Return the turtle's y coordinate
1722 ---
1723 No arguments.
1724
1725 Example (for a Turtle instance named turtle):
1726 >>> reset()
1727 >>> turtle.left(60)
1728 >>> turtle.forward(100)
1729 >>> print turtle.ycor()
1730 86.6025403784
1731 """
1732 return self._position[1]
1733
1734
1735 def goto(self, x, y=None):
1736 """Move turtle to an absolute position.
1737
1738 Aliases: setpos | setposition | goto:
1739
1740 Arguments:
1741 x -- a number or a pair/vector of numbers
1742 y -- a number None
1743
1744 call: goto(x, y) # two coordinates
1745 --or: goto((x, y)) # a pair (tuple) of coordinates
1746 --or: goto(vec) # e.g. as returned by pos()
1747
1748 Move turtle to an absolute position. If the pen is down,
1749 a line will be drawn. The turtle's orientation does not change.
1750
1751 Example (for a Turtle instance named turtle):
1752 >>> tp = turtle.pos()
1753 >>> tp
1754 (0.00, 0.00)
1755 >>> turtle.setpos(60,30)
1756 >>> turtle.pos()
1757 (60.00,30.00)
1758 >>> turtle.setpos((20,80))
1759 >>> turtle.pos()
1760 (20.00,80.00)
1761 >>> turtle.setpos(tp)
1762 >>> turtle.pos()
1763 (0.00,0.00)
1764 """
1765 if y is None:
1766 self._goto(Vec2D(*x))
1767 else:
1768 self._goto(Vec2D(x, y))
1769
1770 def home(self):
1771 """Move turtle to the origin - coordinates (0,0).
1772
1773 No arguments.
1774
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001775 Move turtle to the origin - coordinates (0,0) and set its
1776 heading to its start-orientation (which depends on mode).
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001777
1778 Example (for a Turtle instance named turtle):
1779 >>> turtle.home()
1780 """
1781 self.goto(0, 0)
1782 self.setheading(0)
1783
1784 def setx(self, x):
1785 """Set the turtle's first coordinate to x
1786
1787 Argument:
1788 x -- a number (integer or float)
1789
1790 Set the turtle's first coordinate to x, leave second coordinate
1791 unchanged.
1792
1793 Example (for a Turtle instance named turtle):
1794 >>> turtle.position()
1795 (0.00, 240.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001796 >>> turtle.setx(10)
1797 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001798 (10.00, 240.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001799 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001800 self._goto(Vec2D(x, self._position[1]))
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001801
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001802 def sety(self, y):
1803 """Set the turtle's second coordinate to y
Thomas Wouters477c8d52006-05-27 19:21:47 +00001804
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001805 Argument:
1806 y -- a number (integer or float)
1807
1808 Set the turtle's first coordinate to x, second coordinate remains
1809 unchanged.
1810
1811 Example (for a Turtle instance named turtle):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001812 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001813 (0.00, 40.00)
1814 >>> turtle.sety(-10)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001815 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001816 (0.00, -10.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001817 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001818 self._goto(Vec2D(self._position[0], y))
Guido van Rossumb241b671998-12-04 16:42:46 +00001819
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001820 def distance(self, x, y=None):
1821 """Return the distance from the turtle to (x,y) in turtle step units.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001822
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001823 Arguments:
1824 x -- a number or a pair/vector of numbers or a turtle instance
1825 y -- a number None None
Thomas Wouters477c8d52006-05-27 19:21:47 +00001826
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001827 call: distance(x, y) # two coordinates
1828 --or: distance((x, y)) # a pair (tuple) of coordinates
1829 --or: distance(vec) # e.g. as returned by pos()
1830 --or: distance(mypen) # where mypen is another turtle
1831
1832 Example (for a Turtle instance named turtle):
1833 >>> turtle.pos()
1834 (0.00, 0.00)
1835 >>> turtle.distance(30,40)
1836 50.0
1837 >>> pen = Turtle()
1838 >>> pen.forward(77)
1839 >>> turtle.distance(pen)
1840 77.0
1841 """
1842 if y is not None:
1843 pos = Vec2D(x, y)
1844 if isinstance(x, Vec2D):
1845 pos = x
1846 elif isinstance(x, tuple):
1847 pos = Vec2D(*x)
1848 elif isinstance(x, TNavigator):
1849 pos = x._position
1850 return abs(pos - self._position)
1851
1852 def towards(self, x, y=None):
1853 """Return the angle of the line from the turtle's position to (x, y).
1854
1855 Arguments:
1856 x -- a number or a pair/vector of numbers or a turtle instance
1857 y -- a number None None
1858
1859 call: distance(x, y) # two coordinates
1860 --or: distance((x, y)) # a pair (tuple) of coordinates
1861 --or: distance(vec) # e.g. as returned by pos()
1862 --or: distance(mypen) # where mypen is another turtle
1863
1864 Return the angle, between the line from turtle-position to position
1865 specified by x, y and the turtle's start orientation. (Depends on
1866 modes - "standard" or "logo")
1867
1868 Example (for a Turtle instance named turtle):
1869 >>> turtle.pos()
1870 (10.00, 10.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001871 >>> turtle.towards(0,0)
1872 225.0
1873 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001874 if y is not None:
1875 pos = Vec2D(x, y)
1876 if isinstance(x, Vec2D):
1877 pos = x
1878 elif isinstance(x, tuple):
1879 pos = Vec2D(*x)
1880 elif isinstance(x, TNavigator):
1881 pos = x._position
1882 x, y = pos - self._position
1883 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1884 result /= self._degreesPerAU
1885 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1886
1887 def heading(self):
1888 """ Return the turtle's current heading.
1889
1890 No arguments.
1891
1892 Example (for a Turtle instance named turtle):
1893 >>> turtle.left(67)
1894 >>> turtle.heading()
1895 67.0
1896 """
1897 x, y = self._orient
1898 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1899 result /= self._degreesPerAU
1900 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1901
1902 def setheading(self, to_angle):
1903 """Set the orientation of the turtle to to_angle.
1904
1905 Aliases: setheading | seth
1906
1907 Argument:
1908 to_angle -- a number (integer or float)
1909
1910 Set the orientation of the turtle to to_angle.
1911 Here are some common directions in degrees:
1912
1913 standard - mode: logo-mode:
1914 -------------------|--------------------
1915 0 - east 0 - north
1916 90 - north 90 - east
1917 180 - west 180 - south
1918 270 - south 270 - west
1919
1920 Example (for a Turtle instance named turtle):
1921 >>> turtle.setheading(90)
1922 >>> turtle.heading()
1923 90
1924 """
1925 angle = (to_angle - self.heading())*self._angleOrient
1926 full = self._fullcircle
1927 angle = (angle+full/2.)%full - full/2.
1928 self._rotate(angle)
1929
1930 def circle(self, radius, extent = None, steps = None):
1931 """ Draw a circle with given radius.
1932
1933 Arguments:
1934 radius -- a number
1935 extent (optional) -- a number
1936 steps (optional) -- an integer
1937
1938 Draw a circle with given radius. The center is radius units left
1939 of the turtle; extent - an angle - determines which part of the
1940 circle is drawn. If extent is not given, draw the entire circle.
1941 If extent is not a full circle, one endpoint of the arc is the
1942 current pen position. Draw the arc in counterclockwise direction
1943 if radius is positive, otherwise in clockwise direction. Finally
1944 the direction of the turtle is changed by the amount of extent.
1945
1946 As the circle is approximated by an inscribed regular polygon,
1947 steps determines the number of steps to use. If not given,
1948 it will be calculated automatically. Maybe used to draw regular
1949 polygons.
1950
1951 call: circle(radius) # full circle
1952 --or: circle(radius, extent) # arc
1953 --or: circle(radius, extent, steps)
1954 --or: circle(radius, steps=6) # 6-sided polygon
1955
1956 Example (for a Turtle instance named turtle):
1957 >>> turtle.circle(50)
1958 >>> turtle.circle(120, 180) # semicircle
1959 """
1960 if self.undobuffer:
1961 self.undobuffer.push(["seq"])
1962 self.undobuffer.cumulate = True
1963 speed = self.speed()
1964 if extent is None:
1965 extent = self._fullcircle
1966 if steps is None:
1967 frac = abs(extent)/self._fullcircle
1968 steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
1969 w = 1.0 * extent / steps
1970 w2 = 0.5 * w
1971 l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
1972 if radius < 0:
1973 l, w, w2 = -l, -w, -w2
1974 tr = self._tracer()
1975 dl = self._delay()
1976 if speed == 0:
1977 self._tracer(0, 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001978 else:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001979 self.speed(0)
1980 self._rotate(w2)
1981 for i in range(steps):
1982 self.speed(speed)
1983 self._go(l)
1984 self.speed(0)
1985 self._rotate(w)
1986 self._rotate(-w2)
1987 if speed == 0:
1988 self._tracer(tr, dl)
1989 self.speed(speed)
1990 if self.undobuffer:
1991 self.undobuffer.cumulate = False
Thomas Wouters477c8d52006-05-27 19:21:47 +00001992
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001993## three dummy methods to be implemented by child class:
Thomas Wouters477c8d52006-05-27 19:21:47 +00001994
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001995 def speed(self, s=0):
1996 """dummy method - to be overwritten by child class"""
1997 def _tracer(self, a=None, b=None):
1998 """dummy method - to be overwritten by child class"""
1999 def _delay(self, n=None):
2000 """dummy method - to be overwritten by child class"""
Thomas Wouters477c8d52006-05-27 19:21:47 +00002001
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002002 fd = forward
2003 bk = back
2004 backward = back
2005 rt = right
2006 lt = left
2007 position = pos
2008 setpos = goto
2009 setposition = goto
2010 seth = setheading
Thomas Wouters477c8d52006-05-27 19:21:47 +00002011
Thomas Wouters477c8d52006-05-27 19:21:47 +00002012
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002013class TPen(object):
2014 """Drawing part of the RawTurtle.
2015 Implements drawing properties.
2016 """
2017 def __init__(self, resizemode=_CFG["resizemode"]):
2018 self._resizemode = resizemode # or "user" or "noresize"
2019 self.undobuffer = None
2020 TPen._reset(self)
Thomas Wouters477c8d52006-05-27 19:21:47 +00002021
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002022 def _reset(self, pencolor=_CFG["pencolor"],
2023 fillcolor=_CFG["fillcolor"]):
2024 self._pensize = 1
2025 self._shown = True
2026 self._pencolor = pencolor
2027 self._fillcolor = fillcolor
2028 self._drawing = True
2029 self._speed = 3
Georg Brandleaa84ef2009-05-05 08:14:33 +00002030 self._stretchfactor = (1., 1.)
2031 self._shearfactor = 0.
2032 self._tilt = 0.
2033 self._shapetrafo = (1., 0., 0., 1.)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002034 self._outlinewidth = 1
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002035
2036 def resizemode(self, rmode=None):
2037 """Set resizemode to one of the values: "auto", "user", "noresize".
2038
2039 (Optional) Argument:
2040 rmode -- one of the strings "auto", "user", "noresize"
2041
2042 Different resizemodes have the following effects:
2043 - "auto" adapts the appearance of the turtle
2044 corresponding to the value of pensize.
2045 - "user" adapts the appearance of the turtle according to the
2046 values of stretchfactor and outlinewidth (outline),
2047 which are set by shapesize()
2048 - "noresize" no adaption of the turtle's appearance takes place.
2049 If no argument is given, return current resizemode.
2050 resizemode("user") is called by a call of shapesize with arguments.
2051
2052
2053 Examples (for a Turtle instance named turtle):
2054 >>> turtle.resizemode("noresize")
2055 >>> turtle.resizemode()
2056 'noresize'
Thomas Wouters477c8d52006-05-27 19:21:47 +00002057 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002058 if rmode is None:
2059 return self._resizemode
2060 rmode = rmode.lower()
2061 if rmode in ["auto", "user", "noresize"]:
2062 self.pen(resizemode=rmode)
Guido van Rossumb241b671998-12-04 16:42:46 +00002063
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002064 def pensize(self, width=None):
2065 """Set or return the line thickness.
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002066
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002067 Aliases: pensize | width
Thomas Wouters477c8d52006-05-27 19:21:47 +00002068
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002069 Argument:
2070 width -- positive number
Thomas Wouters477c8d52006-05-27 19:21:47 +00002071
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002072 Set the line thickness to width or return it. If resizemode is set
2073 to "auto" and turtleshape is a polygon, that polygon is drawn with
2074 the same line thickness. If no argument is given, current pensize
2075 is returned.
Thomas Wouters477c8d52006-05-27 19:21:47 +00002076
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002077 Example (for a Turtle instance named turtle):
2078 >>> turtle.pensize()
2079 1
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002080 >>> turtle.pensize(10) # from here on lines of width 10 are drawn
Thomas Wouters477c8d52006-05-27 19:21:47 +00002081 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002082 if width is None:
2083 return self._pensize
2084 self.pen(pensize=width)
Thomas Wouters477c8d52006-05-27 19:21:47 +00002085
2086
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002087 def penup(self):
2088 """Pull the pen up -- no drawing when moving.
Thomas Wouters477c8d52006-05-27 19:21:47 +00002089
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002090 Aliases: penup | pu | up
Thomas Wouters477c8d52006-05-27 19:21:47 +00002091
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002092 No argument
2093
2094 Example (for a Turtle instance named turtle):
2095 >>> turtle.penup()
Thomas Wouters477c8d52006-05-27 19:21:47 +00002096 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002097 if not self._drawing:
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002098 return
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002099 self.pen(pendown=False)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002100
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002101 def pendown(self):
2102 """Pull the pen down -- drawing when moving.
2103
2104 Aliases: pendown | pd | down
2105
2106 No argument.
2107
2108 Example (for a Turtle instance named turtle):
2109 >>> turtle.pendown()
2110 """
2111 if self._drawing:
2112 return
2113 self.pen(pendown=True)
2114
2115 def isdown(self):
2116 """Return True if pen is down, False if it's up.
2117
2118 No argument.
2119
2120 Example (for a Turtle instance named turtle):
2121 >>> turtle.penup()
2122 >>> turtle.isdown()
2123 False
2124 >>> turtle.pendown()
2125 >>> turtle.isdown()
2126 True
2127 """
2128 return self._drawing
2129
2130 def speed(self, speed=None):
2131 """ Return or set the turtle's speed.
2132
2133 Optional argument:
2134 speed -- an integer in the range 0..10 or a speedstring (see below)
2135
2136 Set the turtle's speed to an integer value in the range 0 .. 10.
2137 If no argument is given: return current speed.
2138
2139 If input is a number greater than 10 or smaller than 0.5,
2140 speed is set to 0.
2141 Speedstrings are mapped to speedvalues in the following way:
2142 'fastest' : 0
2143 'fast' : 10
2144 'normal' : 6
2145 'slow' : 3
2146 'slowest' : 1
2147 speeds from 1 to 10 enforce increasingly faster animation of
2148 line drawing and turtle turning.
2149
2150 Attention:
2151 speed = 0 : *no* animation takes place. forward/back makes turtle jump
2152 and likewise left/right make the turtle turn instantly.
2153
2154 Example (for a Turtle instance named turtle):
2155 >>> turtle.speed(3)
2156 """
2157 speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
2158 if speed is None:
2159 return self._speed
2160 if speed in speeds:
2161 speed = speeds[speed]
2162 elif 0.5 < speed < 10.5:
2163 speed = int(round(speed))
2164 else:
2165 speed = 0
2166 self.pen(speed=speed)
2167
2168 def color(self, *args):
2169 """Return or set the pencolor and fillcolor.
2170
2171 Arguments:
2172 Several input formats are allowed.
2173 They use 0, 1, 2, or 3 arguments as follows:
2174
2175 color()
2176 Return the current pencolor and the current fillcolor
2177 as a pair of color specification strings as are returned
2178 by pencolor and fillcolor.
2179 color(colorstring), color((r,g,b)), color(r,g,b)
2180 inputs as in pencolor, set both, fillcolor and pencolor,
2181 to the given value.
2182 color(colorstring1, colorstring2),
2183 color((r1,g1,b1), (r2,g2,b2))
2184 equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
2185 and analogously, if the other input format is used.
2186
2187 If turtleshape is a polygon, outline and interior of that polygon
2188 is drawn with the newly set colors.
2189 For mor info see: pencolor, fillcolor
2190
2191 Example (for a Turtle instance named turtle):
2192 >>> turtle.color('red', 'green')
2193 >>> turtle.color()
2194 ('red', 'green')
2195 >>> colormode(255)
2196 >>> color((40, 80, 120), (160, 200, 240))
2197 >>> color()
2198 ('#285078', '#a0c8f0')
2199 """
2200 if args:
2201 l = len(args)
2202 if l == 1:
2203 pcolor = fcolor = args[0]
2204 elif l == 2:
2205 pcolor, fcolor = args
2206 elif l == 3:
2207 pcolor = fcolor = args
2208 pcolor = self._colorstr(pcolor)
2209 fcolor = self._colorstr(fcolor)
2210 self.pen(pencolor=pcolor, fillcolor=fcolor)
2211 else:
2212 return self._color(self._pencolor), self._color(self._fillcolor)
2213
2214 def pencolor(self, *args):
2215 """ Return or set the pencolor.
2216
2217 Arguments:
2218 Four input formats are allowed:
2219 - pencolor()
2220 Return the current pencolor as color specification string,
2221 possibly in hex-number format (see example).
2222 May be used as input to another color/pencolor/fillcolor call.
2223 - pencolor(colorstring)
2224 s is a Tk color specification string, such as "red" or "yellow"
2225 - pencolor((r, g, b))
2226 *a tuple* of r, g, and b, which represent, an RGB color,
2227 and each of r, g, and b are in the range 0..colormode,
2228 where colormode is either 1.0 or 255
2229 - pencolor(r, g, b)
2230 r, g, and b represent an RGB color, and each of r, g, and b
2231 are in the range 0..colormode
2232
2233 If turtleshape is a polygon, the outline of that polygon is drawn
2234 with the newly set pencolor.
2235
2236 Example (for a Turtle instance named turtle):
2237 >>> turtle.pencolor('brown')
2238 >>> tup = (0.2, 0.8, 0.55)
2239 >>> turtle.pencolor(tup)
2240 >>> turtle.pencolor()
2241 '#33cc8c'
2242 """
2243 if args:
2244 color = self._colorstr(args)
2245 if color == self._pencolor:
2246 return
2247 self.pen(pencolor=color)
2248 else:
2249 return self._color(self._pencolor)
2250
2251 def fillcolor(self, *args):
2252 """ Return or set the fillcolor.
2253
2254 Arguments:
2255 Four input formats are allowed:
2256 - fillcolor()
2257 Return the current fillcolor as color specification string,
2258 possibly in hex-number format (see example).
2259 May be used as input to another color/pencolor/fillcolor call.
2260 - fillcolor(colorstring)
2261 s is a Tk color specification string, such as "red" or "yellow"
2262 - fillcolor((r, g, b))
2263 *a tuple* of r, g, and b, which represent, an RGB color,
2264 and each of r, g, and b are in the range 0..colormode,
2265 where colormode is either 1.0 or 255
2266 - fillcolor(r, g, b)
2267 r, g, and b represent an RGB color, and each of r, g, and b
2268 are in the range 0..colormode
2269
2270 If turtleshape is a polygon, the interior of that polygon is drawn
2271 with the newly set fillcolor.
2272
2273 Example (for a Turtle instance named turtle):
2274 >>> turtle.fillcolor('violet')
2275 >>> col = turtle.pencolor()
2276 >>> turtle.fillcolor(col)
2277 >>> turtle.fillcolor(0, .5, 0)
2278 """
2279 if args:
2280 color = self._colorstr(args)
2281 if color == self._fillcolor:
2282 return
2283 self.pen(fillcolor=color)
2284 else:
2285 return self._color(self._fillcolor)
2286
2287 def showturtle(self):
2288 """Makes the turtle visible.
2289
2290 Aliases: showturtle | st
2291
2292 No argument.
2293
2294 Example (for a Turtle instance named turtle):
2295 >>> turtle.hideturtle()
2296 >>> turtle.showturtle()
2297 """
2298 self.pen(shown=True)
2299
2300 def hideturtle(self):
2301 """Makes the turtle invisible.
2302
2303 Aliases: hideturtle | ht
2304
2305 No argument.
2306
2307 It's a good idea to do this while you're in the
2308 middle of a complicated drawing, because hiding
2309 the turtle speeds up the drawing observably.
2310
2311 Example (for a Turtle instance named turtle):
2312 >>> turtle.hideturtle()
2313 """
2314 self.pen(shown=False)
2315
2316 def isvisible(self):
2317 """Return True if the Turtle is shown, False if it's hidden.
2318
2319 No argument.
2320
2321 Example (for a Turtle instance named turtle):
2322 >>> turtle.hideturtle()
2323 >>> print turtle.isvisible():
2324 False
2325 """
2326 return self._shown
2327
2328 def pen(self, pen=None, **pendict):
2329 """Return or set the pen's attributes.
2330
2331 Arguments:
2332 pen -- a dictionary with some or all of the below listed keys.
2333 **pendict -- one or more keyword-arguments with the below
2334 listed keys as keywords.
2335
2336 Return or set the pen's attributes in a 'pen-dictionary'
2337 with the following key/value pairs:
2338 "shown" : True/False
2339 "pendown" : True/False
2340 "pencolor" : color-string or color-tuple
2341 "fillcolor" : color-string or color-tuple
2342 "pensize" : positive number
2343 "speed" : number in range 0..10
2344 "resizemode" : "auto" or "user" or "noresize"
2345 "stretchfactor": (positive number, positive number)
Georg Brandleaa84ef2009-05-05 08:14:33 +00002346 "shearfactor": number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002347 "outline" : positive number
2348 "tilt" : number
2349
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002350 This dictionary can be used as argument for a subsequent
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002351 pen()-call to restore the former pen-state. Moreover one
2352 or more of these attributes can be provided as keyword-arguments.
2353 This can be used to set several pen attributes in one statement.
Guido van Rossumb241b671998-12-04 16:42:46 +00002354
2355
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002356 Examples (for a Turtle instance named turtle):
2357 >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
2358 >>> turtle.pen()
2359 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2360 'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002361 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002362 >>> penstate=turtle.pen()
2363 >>> turtle.color("yellow","")
2364 >>> turtle.penup()
2365 >>> turtle.pen()
2366 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2367 'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002368 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002369 >>> p.pen(penstate, fillcolor="green")
2370 >>> p.pen()
2371 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2372 'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002373 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002374 """
2375 _pd = {"shown" : self._shown,
2376 "pendown" : self._drawing,
2377 "pencolor" : self._pencolor,
2378 "fillcolor" : self._fillcolor,
2379 "pensize" : self._pensize,
2380 "speed" : self._speed,
2381 "resizemode" : self._resizemode,
2382 "stretchfactor" : self._stretchfactor,
Georg Brandleaa84ef2009-05-05 08:14:33 +00002383 "shearfactor" : self._shearfactor,
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002384 "outline" : self._outlinewidth,
2385 "tilt" : self._tilt
2386 }
Guido van Rossumb241b671998-12-04 16:42:46 +00002387
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002388 if not (pen or pendict):
2389 return _pd
2390
2391 if isinstance(pen, dict):
2392 p = pen
2393 else:
2394 p = {}
2395 p.update(pendict)
2396
2397 _p_buf = {}
2398 for key in p:
2399 _p_buf[key] = _pd[key]
2400
2401 if self.undobuffer:
2402 self.undobuffer.push(("pen", _p_buf))
2403
2404 newLine = False
2405 if "pendown" in p:
2406 if self._drawing != p["pendown"]:
2407 newLine = True
2408 if "pencolor" in p:
2409 if isinstance(p["pencolor"], tuple):
2410 p["pencolor"] = self._colorstr((p["pencolor"],))
2411 if self._pencolor != p["pencolor"]:
2412 newLine = True
2413 if "pensize" in p:
2414 if self._pensize != p["pensize"]:
2415 newLine = True
2416 if newLine:
2417 self._newLine()
2418 if "pendown" in p:
2419 self._drawing = p["pendown"]
2420 if "pencolor" in p:
2421 self._pencolor = p["pencolor"]
2422 if "pensize" in p:
2423 self._pensize = p["pensize"]
2424 if "fillcolor" in p:
2425 if isinstance(p["fillcolor"], tuple):
2426 p["fillcolor"] = self._colorstr((p["fillcolor"],))
2427 self._fillcolor = p["fillcolor"]
2428 if "speed" in p:
2429 self._speed = p["speed"]
2430 if "resizemode" in p:
2431 self._resizemode = p["resizemode"]
2432 if "stretchfactor" in p:
2433 sf = p["stretchfactor"]
2434 if isinstance(sf, (int, float)):
2435 sf = (sf, sf)
2436 self._stretchfactor = sf
Georg Brandleaa84ef2009-05-05 08:14:33 +00002437 if "shearfactor" in p:
2438 self._shearfactor = p["shearfactor"]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002439 if "outline" in p:
2440 self._outlinewidth = p["outline"]
2441 if "shown" in p:
2442 self._shown = p["shown"]
2443 if "tilt" in p:
2444 self._tilt = p["tilt"]
Georg Brandleaa84ef2009-05-05 08:14:33 +00002445 if "stretchfactor" in p or "tilt" in p or "shearfactor" in p:
2446 scx, scy = self._stretchfactor
2447 shf = self._shearfactor
2448 sa, ca = math.sin(self._tilt), math.cos(self._tilt)
2449 self._shapetrafo = ( scx*ca, scy*(shf*ca + sa),
2450 -scx*sa, scy*(ca - shf*sa))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002451 self._update()
2452
2453## three dummy methods to be implemented by child class:
2454
2455 def _newLine(self, usePos = True):
2456 """dummy method - to be overwritten by child class"""
2457 def _update(self, count=True, forced=False):
2458 """dummy method - to be overwritten by child class"""
2459 def _color(self, args):
2460 """dummy method - to be overwritten by child class"""
2461 def _colorstr(self, args):
2462 """dummy method - to be overwritten by child class"""
2463
2464 width = pensize
2465 up = penup
2466 pu = penup
2467 pd = pendown
2468 down = pendown
2469 st = showturtle
2470 ht = hideturtle
2471
2472
2473class _TurtleImage(object):
2474 """Helper class: Datatype to store Turtle attributes
2475 """
2476
2477 def __init__(self, screen, shapeIndex):
2478 self.screen = screen
2479 self._type = None
2480 self._setshape(shapeIndex)
2481
2482 def _setshape(self, shapeIndex):
Georg Brandleaa84ef2009-05-05 08:14:33 +00002483 screen = self.screen
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002484 self.shapeIndex = shapeIndex
2485 if self._type == "polygon" == screen._shapes[shapeIndex]._type:
2486 return
2487 if self._type == "image" == screen._shapes[shapeIndex]._type:
2488 return
2489 if self._type in ["image", "polygon"]:
2490 screen._delete(self._item)
2491 elif self._type == "compound":
2492 for item in self._item:
2493 screen._delete(item)
2494 self._type = screen._shapes[shapeIndex]._type
2495 if self._type == "polygon":
2496 self._item = screen._createpoly()
2497 elif self._type == "image":
2498 self._item = screen._createimage(screen._shapes["blank"]._data)
2499 elif self._type == "compound":
2500 self._item = [screen._createpoly() for item in
2501 screen._shapes[shapeIndex]._data]
2502
2503
2504class RawTurtle(TPen, TNavigator):
2505 """Animation part of the RawTurtle.
2506 Puts RawTurtle upon a TurtleScreen and provides tools for
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002507 its animation.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002508 """
2509 screens = []
2510
2511 def __init__(self, canvas=None,
2512 shape=_CFG["shape"],
2513 undobuffersize=_CFG["undobuffersize"],
2514 visible=_CFG["visible"]):
Martin v. Löwis601149b2008-09-29 22:19:08 +00002515 if isinstance(canvas, _Screen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002516 self.screen = canvas
2517 elif isinstance(canvas, TurtleScreen):
2518 if canvas not in RawTurtle.screens:
2519 RawTurtle.screens.append(canvas)
2520 self.screen = canvas
2521 elif isinstance(canvas, (ScrolledCanvas, Canvas)):
2522 for screen in RawTurtle.screens:
2523 if screen.cv == canvas:
2524 self.screen = screen
2525 break
2526 else:
2527 self.screen = TurtleScreen(canvas)
2528 RawTurtle.screens.append(self.screen)
2529 else:
2530 raise TurtleGraphicsError("bad cavas argument %s" % canvas)
2531
2532 screen = self.screen
2533 TNavigator.__init__(self, screen.mode())
2534 TPen.__init__(self)
2535 screen._turtles.append(self)
2536 self.drawingLineItem = screen._createline()
2537 self.turtle = _TurtleImage(screen, shape)
2538 self._poly = None
2539 self._creatingPoly = False
2540 self._fillitem = self._fillpath = None
2541 self._shown = visible
2542 self._hidden_from_screen = False
2543 self.currentLineItem = screen._createline()
2544 self.currentLine = [self._position]
2545 self.items = [self.currentLineItem]
2546 self.stampItems = []
2547 self._undobuffersize = undobuffersize
2548 self.undobuffer = Tbuffer(undobuffersize)
2549 self._update()
2550
2551 def reset(self):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002552 """Delete the turtle's drawings and restore its default values.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002553
2554 No argument.
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002555
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002556 Delete the turtle's drawings from the screen, re-center the turtle
2557 and set variables to the default values.
2558
2559 Example (for a Turtle instance named turtle):
2560 >>> turtle.position()
2561 (0.00,-22.00)
2562 >>> turtle.heading()
2563 100.0
2564 >>> turtle.reset()
2565 >>> turtle.position()
2566 (0.00,0.00)
2567 >>> turtle.heading()
2568 0.0
2569 """
2570 TNavigator.reset(self)
2571 TPen._reset(self)
2572 self._clear()
2573 self._drawturtle()
2574 self._update()
2575
2576 def setundobuffer(self, size):
2577 """Set or disable undobuffer.
2578
2579 Argument:
2580 size -- an integer or None
2581
2582 If size is an integer an empty undobuffer of given size is installed.
2583 Size gives the maximum number of turtle-actions that can be undone
2584 by the undo() function.
2585 If size is None, no undobuffer is present.
2586
2587 Example (for a Turtle instance named turtle):
2588 >>> turtle.setundobuffer(42)
2589 """
2590 if size is None:
2591 self.undobuffer = None
2592 else:
2593 self.undobuffer = Tbuffer(size)
2594
2595 def undobufferentries(self):
2596 """Return count of entries in the undobuffer.
2597
2598 No argument.
2599
2600 Example (for a Turtle instance named turtle):
2601 >>> while undobufferentries():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002602 ... undo()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002603 """
2604 if self.undobuffer is None:
2605 return 0
2606 return self.undobuffer.nr_of_items()
2607
2608 def _clear(self):
2609 """Delete all of pen's drawings"""
2610 self._fillitem = self._fillpath = None
2611 for item in self.items:
2612 self.screen._delete(item)
2613 self.currentLineItem = self.screen._createline()
2614 self.currentLine = []
2615 if self._drawing:
2616 self.currentLine.append(self._position)
2617 self.items = [self.currentLineItem]
2618 self.clearstamps()
2619 self.setundobuffer(self._undobuffersize)
2620
2621
2622 def clear(self):
2623 """Delete the turtle's drawings from the screen. Do not move turtle.
2624
2625 No arguments.
2626
2627 Delete the turtle's drawings from the screen. Do not move turtle.
2628 State and position of the turtle as well as drawings of other
2629 turtles are not affected.
2630
2631 Examples (for a Turtle instance named turtle):
2632 >>> turtle.clear()
2633 """
2634 self._clear()
2635 self._update()
2636
2637 def _update_data(self):
2638 self.screen._incrementudc()
2639 if self.screen._updatecounter != 0:
2640 return
2641 if len(self.currentLine)>1:
2642 self.screen._drawline(self.currentLineItem, self.currentLine,
2643 self._pencolor, self._pensize)
2644
2645 def _update(self):
2646 """Perform a Turtle-data update.
2647 """
2648 screen = self.screen
2649 if screen._tracing == 0:
2650 return
2651 elif screen._tracing == 1:
2652 self._update_data()
2653 self._drawturtle()
2654 screen._update() # TurtleScreenBase
2655 screen._delay(screen._delayvalue) # TurtleScreenBase
2656 else:
2657 self._update_data()
2658 if screen._updatecounter == 0:
2659 for t in screen.turtles():
2660 t._drawturtle()
2661 screen._update()
2662
2663 def _tracer(self, flag=None, delay=None):
2664 """Turns turtle animation on/off and set delay for update drawings.
2665
2666 Optional arguments:
2667 n -- nonnegative integer
2668 delay -- nonnegative integer
2669
2670 If n is given, only each n-th regular screen update is really performed.
2671 (Can be used to accelerate the drawing of complex graphics.)
2672 Second arguments sets delay value (see RawTurtle.delay())
2673
2674 Example (for a Turtle instance named turtle):
2675 >>> turtle.tracer(8, 25)
2676 >>> dist = 2
2677 >>> for i in range(200):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002678 ... turtle.fd(dist)
2679 ... turtle.rt(90)
2680 ... dist += 2
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002681 """
2682 return self.screen.tracer(flag, delay)
2683
2684 def _color(self, args):
2685 return self.screen._color(args)
2686
2687 def _colorstr(self, args):
2688 return self.screen._colorstr(args)
2689
2690 def _cc(self, args):
2691 """Convert colortriples to hexstrings.
2692 """
2693 if isinstance(args, str):
2694 return args
2695 try:
2696 r, g, b = args
2697 except:
2698 raise TurtleGraphicsError("bad color arguments: %s" % str(args))
2699 if self.screen._colormode == 1.0:
2700 r, g, b = [round(255.0*x) for x in (r, g, b)]
2701 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
2702 raise TurtleGraphicsError("bad color sequence: %s" % str(args))
2703 return "#%02x%02x%02x" % (r, g, b)
2704
2705 def clone(self):
2706 """Create and return a clone of the turtle.
2707
2708 No argument.
2709
2710 Create and return a clone of the turtle with same position, heading
2711 and turtle properties.
2712
2713 Example (for a Turtle instance named mick):
2714 mick = Turtle()
2715 joe = mick.clone()
2716 """
2717 screen = self.screen
2718 self._newLine(self._drawing)
2719
2720 turtle = self.turtle
2721 self.screen = None
2722 self.turtle = None # too make self deepcopy-able
2723
2724 q = deepcopy(self)
2725
2726 self.screen = screen
2727 self.turtle = turtle
2728
2729 q.screen = screen
2730 q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
2731
2732 screen._turtles.append(q)
2733 ttype = screen._shapes[self.turtle.shapeIndex]._type
2734 if ttype == "polygon":
2735 q.turtle._item = screen._createpoly()
2736 elif ttype == "image":
2737 q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
2738 elif ttype == "compound":
2739 q.turtle._item = [screen._createpoly() for item in
2740 screen._shapes[self.turtle.shapeIndex]._data]
2741 q.currentLineItem = screen._createline()
2742 q._update()
2743 return q
2744
2745 def shape(self, name=None):
2746 """Set turtle shape to shape with given name / return current shapename.
2747
2748 Optional argument:
2749 name -- a string, which is a valid shapename
2750
2751 Set turtle shape to shape with given name or, if name is not given,
2752 return name of current shape.
2753 Shape with name must exist in the TurtleScreen's shape dictionary.
2754 Initially there are the following polygon shapes:
2755 'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
2756 To learn about how to deal with shapes see Screen-method register_shape.
2757
2758 Example (for a Turtle instance named turtle):
2759 >>> turtle.shape()
2760 'arrow'
2761 >>> turtle.shape("turtle")
2762 >>> turtle.shape()
2763 'turtle'
2764 """
2765 if name is None:
2766 return self.turtle.shapeIndex
2767 if not name in self.screen.getshapes():
2768 raise TurtleGraphicsError("There is no shape named %s" % name)
2769 self.turtle._setshape(name)
2770 self._update()
2771
2772 def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
2773 """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
2774
2775 Optinonal arguments:
2776 stretch_wid : positive number
2777 stretch_len : positive number
2778 outline : positive number
2779
2780 Return or set the pen's attributes x/y-stretchfactors and/or outline.
2781 Set resizemode to "user".
2782 If and only if resizemode is set to "user", the turtle will be displayed
2783 stretched according to its stretchfactors:
2784 stretch_wid is stretchfactor perpendicular to orientation
2785 stretch_len is stretchfactor in direction of turtles orientation.
2786 outline determines the width of the shapes's outline.
2787
2788 Examples (for a Turtle instance named turtle):
2789 >>> turtle.resizemode("user")
2790 >>> turtle.shapesize(5, 5, 12)
2791 >>> turtle.shapesize(outline=8)
2792 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00002793 if stretch_wid is stretch_len is outline is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002794 stretch_wid, stretch_len = self._stretchfactor
2795 return stretch_wid, stretch_len, self._outlinewidth
Georg Brandleaa84ef2009-05-05 08:14:33 +00002796 if stretch_wid == 0 or stretch_len == 0:
2797 raise TurtleGraphicsError("stretch_wid/stretch_len must not be zero")
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002798 if stretch_wid is not None:
2799 if stretch_len is None:
2800 stretchfactor = stretch_wid, stretch_wid
2801 else:
2802 stretchfactor = stretch_wid, stretch_len
2803 elif stretch_len is not None:
2804 stretchfactor = self._stretchfactor[0], stretch_len
2805 else:
2806 stretchfactor = self._stretchfactor
2807 if outline is None:
2808 outline = self._outlinewidth
2809 self.pen(resizemode="user",
2810 stretchfactor=stretchfactor, outline=outline)
2811
Georg Brandleaa84ef2009-05-05 08:14:33 +00002812 def shearfactor(self, shear=None):
2813 """Set or return the current shearfactor.
2814
2815 Optional argument: shear -- number, tangent of the shear angle
2816
2817 Shear the turtleshape according to the given shearfactor shear,
2818 which is the tangent of the shear angle. DO NOT change the
2819 turtle's heading (direction of movement).
2820 If shear is not given: return the current shearfactor, i. e. the
2821 tangent of the shear angle, by which lines parallel to the
2822 heading of the turtle are sheared.
2823
2824 Examples (for a Turtle instance named turtle):
2825 >>> turtle.shape("circle")
2826 >>> turtle.shapesize(5,2)
2827 >>> turtle.shearfactor(0.5)
2828 >>> turtle.shearfactor()
2829 >>> 0.5
2830 """
2831 if shear is None:
2832 return self._shearfactor
2833 self.pen(resizemode="user", shearfactor=shear)
2834
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002835 def settiltangle(self, angle):
2836 """Rotate the turtleshape to point in the specified direction
2837
Georg Brandleaa84ef2009-05-05 08:14:33 +00002838 Argument: angle -- number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002839
2840 Rotate the turtleshape to point in the direction specified by angle,
2841 regardless of its current tilt-angle. DO NOT change the turtle's
2842 heading (direction of movement).
2843
2844
2845 Examples (for a Turtle instance named turtle):
2846 >>> turtle.shape("circle")
2847 >>> turtle.shapesize(5,2)
2848 >>> turtle.settiltangle(45)
2849 >>> stamp()
2850 >>> turtle.fd(50)
2851 >>> turtle.settiltangle(-45)
2852 >>> stamp()
2853 >>> turtle.fd(50)
2854 """
2855 tilt = -angle * self._degreesPerAU * self._angleOrient
2856 tilt = (tilt * math.pi / 180.0) % (2*math.pi)
2857 self.pen(resizemode="user", tilt=tilt)
2858
Georg Brandleaa84ef2009-05-05 08:14:33 +00002859 def tiltangle(self, angle=None):
2860 """Set or return the current tilt-angle.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002861
Georg Brandleaa84ef2009-05-05 08:14:33 +00002862 Optional argument: angle -- number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002863
Georg Brandleaa84ef2009-05-05 08:14:33 +00002864 Rotate the turtleshape to point in the direction specified by angle,
2865 regardless of its current tilt-angle. DO NOT change the turtle's
2866 heading (direction of movement).
2867 If angle is not given: return the current tilt-angle, i. e. the angle
2868 between the orientation of the turtleshape and the heading of the
2869 turtle (its direction of movement).
2870
2871 Deprecated since Python 3.1
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002872
2873 Examples (for a Turtle instance named turtle):
2874 >>> turtle.shape("circle")
2875 >>> turtle.shapesize(5,2)
2876 >>> turtle.tilt(45)
2877 >>> turtle.tiltangle()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002878 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00002879 if angle is None:
2880 tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
2881 return (tilt / self._degreesPerAU) % self._fullcircle
2882 else:
2883 self.settiltangle(angle)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002884
2885 def tilt(self, angle):
2886 """Rotate the turtleshape by angle.
2887
2888 Argument:
2889 angle - a number
2890
2891 Rotate the turtleshape by angle from its current tilt-angle,
2892 but do NOT change the turtle's heading (direction of movement).
2893
2894 Examples (for a Turtle instance named turtle):
2895 >>> turtle.shape("circle")
2896 >>> turtle.shapesize(5,2)
2897 >>> turtle.tilt(30)
2898 >>> turtle.fd(50)
2899 >>> turtle.tilt(30)
2900 >>> turtle.fd(50)
2901 """
2902 self.settiltangle(angle + self.tiltangle())
2903
Georg Brandleaa84ef2009-05-05 08:14:33 +00002904 def shapetransform(self, t11=None, t12=None, t21=None, t22=None):
2905 """Set or return the current transformation matrix of the turtle shape.
2906
2907 Optional arguments: t11, t12, t21, t22 -- numbers.
2908
2909 If none of the matrix elements are given, return the transformation
2910 matrix.
2911 Otherwise set the given elements and transform the turtleshape
2912 according to the matrix consisting of first row t11, t12 and
2913 second row t21, 22.
2914 Modify stretchfactor, shearfactor and tiltangle according to the
2915 given matrix.
2916
2917 Examples (for a Turtle instance named turtle):
2918 >>> turtle.shape("square")
2919 >>> turtle.shapesize(4,2)
2920 >>> turtle.shearfactor(-0.5)
2921 >>> turtle.shapetransform()
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002922 (4.0, -1.0, -0.0, 2.0)
Georg Brandleaa84ef2009-05-05 08:14:33 +00002923 """
2924 if t11 is t12 is t21 is t22 is None:
2925 return self._shapetrafo
2926 m11, m12, m21, m22 = self._shapetrafo
2927 if t11 is not None: m11 = t11
2928 if t12 is not None: m12 = t12
2929 if t21 is not None: m21 = t21
2930 if t22 is not None: m22 = t22
2931 if t11 * t22 - t12 * t21 == 0:
2932 raise TurtleGraphicsError("Bad shape transform matrix: must not be singular")
2933 self._shapetrafo = (m11, m12, m21, m22)
2934 alfa = math.atan2(-m21, m11) % (2 * math.pi)
2935 sa, ca = math.sin(alfa), math.cos(alfa)
2936 a11, a12, a21, a22 = (ca*m11 - sa*m21, ca*m12 - sa*m22,
2937 sa*m11 + ca*m21, sa*m12 + ca*m22)
2938 self._stretchfactor = a11, a22
2939 self._shearfactor = a12/a22
2940 self._tilt = alfa
2941 self._update()
2942
2943
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002944 def _polytrafo(self, poly):
2945 """Computes transformed polygon shapes from a shape
2946 according to current position and heading.
2947 """
2948 screen = self.screen
2949 p0, p1 = self._position
2950 e0, e1 = self._orient
2951 e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
2952 e0, e1 = (1.0 / abs(e)) * e
2953 return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
2954 for (x, y) in poly]
2955
Georg Brandleaa84ef2009-05-05 08:14:33 +00002956 def get_shapepoly(self):
2957 """Return the current shape polygon as tuple of coordinate pairs.
2958
2959 No argument.
2960
2961 Examples (for a Turtle instance named turtle):
2962 >>> turtle.shape("square")
2963 >>> turtle.shapetransform(4, -1, 0, 2)
2964 >>> turtle.get_shapepoly()
2965 ((50, -20), (30, 20), (-50, 20), (-30, -20))
2966
2967 """
2968 shape = self.screen._shapes[self.turtle.shapeIndex]
2969 if shape._type == "polygon":
2970 return self._getshapepoly(shape._data, shape._type == "compound")
2971 # else return None
2972
2973 def _getshapepoly(self, polygon, compound=False):
2974 """Calculate transformed shape polygon according to resizemode
2975 and shapetransform.
2976 """
2977 if self._resizemode == "user" or compound:
2978 t11, t12, t21, t22 = self._shapetrafo
2979 elif self._resizemode == "auto":
2980 l = max(1, self._pensize/5.0)
2981 t11, t12, t21, t22 = l, 0, 0, l
2982 elif self._resizemode == "noresize":
2983 return polygon
2984 return tuple([(t11*x + t12*y, t21*x + t22*y) for (x, y) in polygon])
2985
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002986 def _drawturtle(self):
2987 """Manages the correct rendering of the turtle with respect to
Mark Dickinson934896d2009-02-21 20:59:32 +00002988 its shape, resizemode, stretch and tilt etc."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002989 screen = self.screen
2990 shape = screen._shapes[self.turtle.shapeIndex]
2991 ttype = shape._type
2992 titem = self.turtle._item
2993 if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
2994 self._hidden_from_screen = False
2995 tshape = shape._data
2996 if ttype == "polygon":
Georg Brandleaa84ef2009-05-05 08:14:33 +00002997 if self._resizemode == "noresize": w = 1
2998 elif self._resizemode == "auto": w = self._pensize
2999 else: w =self._outlinewidth
3000 shape = self._polytrafo(self._getshapepoly(tshape))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003001 fc, oc = self._fillcolor, self._pencolor
3002 screen._drawpoly(titem, shape, fill=fc, outline=oc,
3003 width=w, top=True)
3004 elif ttype == "image":
3005 screen._drawimage(titem, self._position, tshape)
3006 elif ttype == "compound":
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003007 for item, (poly, fc, oc) in zip(titem, tshape):
Georg Brandleaa84ef2009-05-05 08:14:33 +00003008 poly = self._polytrafo(self._getshapepoly(poly, True))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003009 screen._drawpoly(item, poly, fill=self._cc(fc),
Georg Brandleaa84ef2009-05-05 08:14:33 +00003010 outline=self._cc(oc), width=self._outlinewidth, top=True)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003011 else:
3012 if self._hidden_from_screen:
3013 return
3014 if ttype == "polygon":
3015 screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
3016 elif ttype == "image":
3017 screen._drawimage(titem, self._position,
3018 screen._shapes["blank"]._data)
3019 elif ttype == "compound":
3020 for item in titem:
3021 screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
3022 self._hidden_from_screen = True
3023
3024############################## stamp stuff ###############################
3025
3026 def stamp(self):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00003027 """Stamp a copy of the turtleshape onto the canvas and return its id.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003028
3029 No argument.
3030
3031 Stamp a copy of the turtle shape onto the canvas at the current
3032 turtle position. Return a stamp_id for that stamp, which can be
3033 used to delete it by calling clearstamp(stamp_id).
3034
3035 Example (for a Turtle instance named turtle):
3036 >>> turtle.color("blue")
3037 >>> turtle.stamp()
3038 13
3039 >>> turtle.fd(50)
3040 """
3041 screen = self.screen
3042 shape = screen._shapes[self.turtle.shapeIndex]
3043 ttype = shape._type
3044 tshape = shape._data
3045 if ttype == "polygon":
3046 stitem = screen._createpoly()
Georg Brandleaa84ef2009-05-05 08:14:33 +00003047 if self._resizemode == "noresize": w = 1
3048 elif self._resizemode == "auto": w = self._pensize
3049 else: w =self._outlinewidth
3050 shape = self._polytrafo(self._getshapepoly(tshape))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003051 fc, oc = self._fillcolor, self._pencolor
3052 screen._drawpoly(stitem, shape, fill=fc, outline=oc,
3053 width=w, top=True)
3054 elif ttype == "image":
3055 stitem = screen._createimage("")
3056 screen._drawimage(stitem, self._position, tshape)
3057 elif ttype == "compound":
3058 stitem = []
3059 for element in tshape:
3060 item = screen._createpoly()
3061 stitem.append(item)
3062 stitem = tuple(stitem)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003063 for item, (poly, fc, oc) in zip(stitem, tshape):
Georg Brandleaa84ef2009-05-05 08:14:33 +00003064 poly = self._polytrafo(self._getshapepoly(poly, True))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003065 screen._drawpoly(item, poly, fill=self._cc(fc),
Georg Brandleaa84ef2009-05-05 08:14:33 +00003066 outline=self._cc(oc), width=self._outlinewidth, top=True)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003067 self.stampItems.append(stitem)
3068 self.undobuffer.push(("stamp", stitem))
3069 return stitem
3070
3071 def _clearstamp(self, stampid):
3072 """does the work for clearstamp() and clearstamps()
3073 """
3074 if stampid in self.stampItems:
3075 if isinstance(stampid, tuple):
3076 for subitem in stampid:
3077 self.screen._delete(subitem)
3078 else:
3079 self.screen._delete(stampid)
3080 self.stampItems.remove(stampid)
3081 # Delete stampitem from undobuffer if necessary
3082 # if clearstamp is called directly.
3083 item = ("stamp", stampid)
3084 buf = self.undobuffer
3085 if item not in buf.buffer:
3086 return
3087 index = buf.buffer.index(item)
3088 buf.buffer.remove(item)
3089 if index <= buf.ptr:
3090 buf.ptr = (buf.ptr - 1) % buf.bufsize
3091 buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
3092
3093 def clearstamp(self, stampid):
3094 """Delete stamp with given stampid
3095
3096 Argument:
3097 stampid - an integer, must be return value of previous stamp() call.
3098
3099 Example (for a Turtle instance named turtle):
3100 >>> turtle.color("blue")
3101 >>> astamp = turtle.stamp()
3102 >>> turtle.fd(50)
3103 >>> turtle.clearstamp(astamp)
3104 """
3105 self._clearstamp(stampid)
3106 self._update()
3107
3108 def clearstamps(self, n=None):
3109 """Delete all or first/last n of turtle's stamps.
3110
3111 Optional argument:
3112 n -- an integer
3113
3114 If n is None, delete all of pen's stamps,
3115 else if n > 0 delete first n stamps
3116 else if n < 0 delete last n stamps.
3117
3118 Example (for a Turtle instance named turtle):
3119 >>> for i in range(8):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003120 ... turtle.stamp(); turtle.fd(30)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003121 ...
3122 >>> turtle.clearstamps(2)
3123 >>> turtle.clearstamps(-2)
3124 >>> turtle.clearstamps()
3125 """
3126 if n is None:
3127 toDelete = self.stampItems[:]
3128 elif n >= 0:
3129 toDelete = self.stampItems[:n]
3130 else:
3131 toDelete = self.stampItems[n:]
3132 for item in toDelete:
3133 self._clearstamp(item)
3134 self._update()
3135
3136 def _goto(self, end):
3137 """Move the pen to the point end, thereby drawing a line
3138 if pen is down. All other methodes for turtle movement depend
3139 on this one.
3140 """
Alexander Belopolsky1842d0c2010-10-28 20:13:52 +00003141 ## Version with undo-stuff
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003142 go_modes = ( self._drawing,
3143 self._pencolor,
3144 self._pensize,
3145 isinstance(self._fillpath, list))
3146 screen = self.screen
3147 undo_entry = ("go", self._position, end, go_modes,
3148 (self.currentLineItem,
3149 self.currentLine[:],
3150 screen._pointlist(self.currentLineItem),
3151 self.items[:])
3152 )
3153 if self.undobuffer:
3154 self.undobuffer.push(undo_entry)
3155 start = self._position
3156 if self._speed and screen._tracing == 1:
3157 diff = (end-start)
3158 diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3159 nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3160 delta = diff * (1.0/nhops)
3161 for n in range(1, nhops):
3162 if n == 1:
3163 top = True
3164 else:
3165 top = False
3166 self._position = start + delta * n
3167 if self._drawing:
3168 screen._drawline(self.drawingLineItem,
3169 (start, self._position),
3170 self._pencolor, self._pensize, top)
3171 self._update()
3172 if self._drawing:
3173 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3174 fill="", width=self._pensize)
3175 # Turtle now at end,
3176 if self._drawing: # now update currentLine
3177 self.currentLine.append(end)
3178 if isinstance(self._fillpath, list):
3179 self._fillpath.append(end)
3180 ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
3181 self._position = end
3182 if self._creatingPoly:
3183 self._poly.append(end)
3184 if len(self.currentLine) > 42: # 42! answer to the ultimate question
3185 # of life, the universe and everything
3186 self._newLine()
3187 self._update() #count=True)
3188
3189 def _undogoto(self, entry):
3190 """Reverse a _goto. Used for undo()
3191 """
3192 old, new, go_modes, coodata = entry
3193 drawing, pc, ps, filling = go_modes
3194 cLI, cL, pl, items = coodata
3195 screen = self.screen
3196 if abs(self._position - new) > 0.5:
3197 print ("undogoto: HALLO-DA-STIMMT-WAS-NICHT!")
3198 # restore former situation
3199 self.currentLineItem = cLI
3200 self.currentLine = cL
3201
3202 if pl == [(0, 0), (0, 0)]:
3203 usepc = ""
3204 else:
3205 usepc = pc
3206 screen._drawline(cLI, pl, fill=usepc, width=ps)
3207
3208 todelete = [i for i in self.items if (i not in items) and
3209 (screen._type(i) == "line")]
3210 for i in todelete:
3211 screen._delete(i)
3212 self.items.remove(i)
3213
3214 start = old
3215 if self._speed and screen._tracing == 1:
3216 diff = old - new
3217 diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3218 nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3219 delta = diff * (1.0/nhops)
3220 for n in range(1, nhops):
3221 if n == 1:
3222 top = True
3223 else:
3224 top = False
3225 self._position = new + delta * n
3226 if drawing:
3227 screen._drawline(self.drawingLineItem,
3228 (start, self._position),
3229 pc, ps, top)
3230 self._update()
3231 if drawing:
3232 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3233 fill="", width=ps)
3234 # Turtle now at position old,
3235 self._position = old
Ezio Melotti13925002011-03-16 11:05:33 +02003236 ## if undo is done during creating a polygon, the last vertex
3237 ## will be deleted. if the polygon is entirely deleted,
3238 ## creatingPoly will be set to False.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003239 ## Polygons created before the last one will not be affected by undo()
3240 if self._creatingPoly:
3241 if len(self._poly) > 0:
3242 self._poly.pop()
3243 if self._poly == []:
3244 self._creatingPoly = False
3245 self._poly = None
3246 if filling:
3247 if self._fillpath == []:
3248 self._fillpath = None
3249 print("Unwahrscheinlich in _undogoto!")
3250 elif self._fillpath is not None:
3251 self._fillpath.pop()
3252 self._update() #count=True)
3253
3254 def _rotate(self, angle):
3255 """Turns pen clockwise by angle.
3256 """
3257 if self.undobuffer:
3258 self.undobuffer.push(("rot", angle, self._degreesPerAU))
3259 angle *= self._degreesPerAU
3260 neworient = self._orient.rotate(angle)
3261 tracing = self.screen._tracing
3262 if tracing == 1 and self._speed > 0:
3263 anglevel = 3.0 * self._speed
3264 steps = 1 + int(abs(angle)/anglevel)
3265 delta = 1.0*angle/steps
3266 for _ in range(steps):
3267 self._orient = self._orient.rotate(delta)
3268 self._update()
3269 self._orient = neworient
3270 self._update()
3271
3272 def _newLine(self, usePos=True):
3273 """Closes current line item and starts a new one.
3274 Remark: if current line became too long, animation
3275 performance (via _drawline) slowed down considerably.
3276 """
3277 if len(self.currentLine) > 1:
3278 self.screen._drawline(self.currentLineItem, self.currentLine,
3279 self._pencolor, self._pensize)
3280 self.currentLineItem = self.screen._createline()
3281 self.items.append(self.currentLineItem)
3282 else:
3283 self.screen._drawline(self.currentLineItem, top=True)
3284 self.currentLine = []
3285 if usePos:
3286 self.currentLine = [self._position]
3287
3288 def filling(self):
3289 """Return fillstate (True if filling, False else).
3290
3291 No argument.
3292
3293 Example (for a Turtle instance named turtle):
3294 >>> turtle.begin_fill()
3295 >>> if turtle.filling():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003296 ... turtle.pensize(5)
3297 ... else:
3298 ... turtle.pensize(3)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003299 """
3300 return isinstance(self._fillpath, list)
3301
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003302 def begin_fill(self):
3303 """Called just before drawing a shape to be filled.
3304
3305 No argument.
3306
3307 Example (for a Turtle instance named turtle):
3308 >>> turtle.color("black", "red")
3309 >>> turtle.begin_fill()
3310 >>> turtle.circle(60)
3311 >>> turtle.end_fill()
3312 """
3313 if not self.filling():
3314 self._fillitem = self.screen._createpoly()
3315 self.items.append(self._fillitem)
3316 self._fillpath = [self._position]
3317 self._newLine()
3318 if self.undobuffer:
3319 self.undobuffer.push(("beginfill", self._fillitem))
3320 self._update()
3321
3322
3323 def end_fill(self):
3324 """Fill the shape drawn after the call begin_fill().
3325
3326 No argument.
3327
3328 Example (for a Turtle instance named turtle):
3329 >>> turtle.color("black", "red")
3330 >>> turtle.begin_fill()
3331 >>> turtle.circle(60)
3332 >>> turtle.end_fill()
3333 """
3334 if self.filling():
3335 if len(self._fillpath) > 2:
3336 self.screen._drawpoly(self._fillitem, self._fillpath,
3337 fill=self._fillcolor)
3338 if self.undobuffer:
3339 self.undobuffer.push(("dofill", self._fillitem))
3340 self._fillitem = self._fillpath = None
3341 self._update()
3342
3343 def dot(self, size=None, *color):
3344 """Draw a dot with diameter size, using color.
3345
Ezio Melotti42da6632011-03-15 05:18:48 +02003346 Optional arguments:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003347 size -- an integer >= 1 (if given)
3348 color -- a colorstring or a numeric color tuple
3349
3350 Draw a circular dot with diameter size, using color.
3351 If size is not given, the maximum of pensize+4 and 2*pensize is used.
3352
3353 Example (for a Turtle instance named turtle):
3354 >>> turtle.dot()
3355 >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
3356 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003357 if not color:
3358 if isinstance(size, (str, tuple)):
3359 color = self._colorstr(size)
3360 size = self._pensize + max(self._pensize, 4)
3361 else:
3362 color = self._pencolor
3363 if not size:
3364 size = self._pensize + max(self._pensize, 4)
3365 else:
3366 if size is None:
3367 size = self._pensize + max(self._pensize, 4)
3368 color = self._colorstr(color)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003369 if hasattr(self.screen, "_dot"):
3370 item = self.screen._dot(self._position, size, color)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003371 self.items.append(item)
3372 if self.undobuffer:
3373 self.undobuffer.push(("dot", item))
3374 else:
3375 pen = self.pen()
3376 if self.undobuffer:
3377 self.undobuffer.push(["seq"])
3378 self.undobuffer.cumulate = True
3379 try:
3380 if self.resizemode() == 'auto':
3381 self.ht()
3382 self.pendown()
3383 self.pensize(size)
3384 self.pencolor(color)
3385 self.forward(0)
3386 finally:
3387 self.pen(pen)
3388 if self.undobuffer:
3389 self.undobuffer.cumulate = False
3390
3391 def _write(self, txt, align, font):
3392 """Performs the writing for write()
3393 """
3394 item, end = self.screen._write(self._position, txt, align, font,
3395 self._pencolor)
3396 self.items.append(item)
3397 if self.undobuffer:
3398 self.undobuffer.push(("wri", item))
3399 return end
3400
3401 def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
3402 """Write text at the current turtle position.
3403
3404 Arguments:
3405 arg -- info, which is to be written to the TurtleScreen
3406 move (optional) -- True/False
3407 align (optional) -- one of the strings "left", "center" or right"
3408 font (optional) -- a triple (fontname, fontsize, fonttype)
3409
3410 Write text - the string representation of arg - at the current
3411 turtle position according to align ("left", "center" or right")
3412 and with the given font.
3413 If move is True, the pen is moved to the bottom-right corner
3414 of the text. By default, move is False.
3415
3416 Example (for a Turtle instance named turtle):
3417 >>> turtle.write('Home = ', True, align="center")
3418 >>> turtle.write((0,0), True)
3419 """
3420 if self.undobuffer:
3421 self.undobuffer.push(["seq"])
3422 self.undobuffer.cumulate = True
3423 end = self._write(str(arg), align.lower(), font)
3424 if move:
3425 x, y = self.pos()
3426 self.setpos(end, y)
3427 if self.undobuffer:
3428 self.undobuffer.cumulate = False
3429
3430 def begin_poly(self):
3431 """Start recording the vertices of a polygon.
3432
3433 No argument.
3434
3435 Start recording the vertices of a polygon. Current turtle position
3436 is first point of polygon.
3437
3438 Example (for a Turtle instance named turtle):
3439 >>> turtle.begin_poly()
3440 """
3441 self._poly = [self._position]
3442 self._creatingPoly = True
3443
3444 def end_poly(self):
3445 """Stop recording the vertices of a polygon.
3446
3447 No argument.
3448
3449 Stop recording the vertices of a polygon. Current turtle position is
3450 last point of polygon. This will be connected with the first point.
3451
3452 Example (for a Turtle instance named turtle):
3453 >>> turtle.end_poly()
3454 """
3455 self._creatingPoly = False
3456
3457 def get_poly(self):
3458 """Return the lastly recorded polygon.
3459
3460 No argument.
3461
3462 Example (for a Turtle instance named turtle):
3463 >>> p = turtle.get_poly()
3464 >>> turtle.register_shape("myFavouriteShape", p)
3465 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00003466 ## check if there is any poly?
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003467 if self._poly is not None:
3468 return tuple(self._poly)
3469
3470 def getscreen(self):
3471 """Return the TurtleScreen object, the turtle is drawing on.
3472
3473 No argument.
3474
3475 Return the TurtleScreen object, the turtle is drawing on.
3476 So TurtleScreen-methods can be called for that object.
3477
3478 Example (for a Turtle instance named turtle):
3479 >>> ts = turtle.getscreen()
3480 >>> ts
3481 <turtle.TurtleScreen object at 0x0106B770>
3482 >>> ts.bgcolor("pink")
3483 """
3484 return self.screen
3485
3486 def getturtle(self):
3487 """Return the Turtleobject itself.
3488
3489 No argument.
3490
3491 Only reasonable use: as a function to return the 'anonymous turtle':
3492
3493 Example:
3494 >>> pet = getturtle()
3495 >>> pet.fd(50)
3496 >>> pet
3497 <turtle.Turtle object at 0x0187D810>
3498 >>> turtles()
3499 [<turtle.Turtle object at 0x0187D810>]
3500 """
3501 return self
3502
3503 getpen = getturtle
3504
3505
3506 ################################################################
3507 ### screen oriented methods recurring to methods of TurtleScreen
3508 ################################################################
3509
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003510 def _delay(self, delay=None):
3511 """Set delay value which determines speed of turtle animation.
3512 """
3513 return self.screen.delay(delay)
3514
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003515 def onclick(self, fun, btn=1, add=None):
3516 """Bind fun to mouse-click event on this turtle on canvas.
3517
3518 Arguments:
3519 fun -- a function with two arguments, to which will be assigned
3520 the coordinates of the clicked point on the canvas.
3521 num -- number of the mouse-button defaults to 1 (left mouse button).
3522 add -- True or False. If True, new binding will be added, otherwise
3523 it will replace a former binding.
3524
3525 Example for the anonymous turtle, i. e. the procedural way:
3526
3527 >>> def turn(x, y):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003528 ... left(360)
3529 ...
3530 >>> onclick(turn) # Now clicking into the turtle will turn it.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003531 >>> onclick(None) # event-binding will be removed
3532 """
3533 self.screen._onclick(self.turtle._item, fun, btn, add)
3534 self._update()
3535
3536 def onrelease(self, fun, btn=1, add=None):
3537 """Bind fun to mouse-button-release event on this turtle on canvas.
3538
3539 Arguments:
3540 fun -- a function with two arguments, to which will be assigned
3541 the coordinates of the clicked point on the canvas.
3542 num -- number of the mouse-button defaults to 1 (left mouse button).
3543
3544 Example (for a MyTurtle instance named joe):
3545 >>> class MyTurtle(Turtle):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003546 ... def glow(self,x,y):
3547 ... self.fillcolor("red")
3548 ... def unglow(self,x,y):
3549 ... self.fillcolor("")
3550 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003551 >>> joe = MyTurtle()
3552 >>> joe.onclick(joe.glow)
3553 >>> joe.onrelease(joe.unglow)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003554
3555 Clicking on joe turns fillcolor red, unclicking turns it to
3556 transparent.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003557 """
3558 self.screen._onrelease(self.turtle._item, fun, btn, add)
3559 self._update()
3560
3561 def ondrag(self, fun, btn=1, add=None):
3562 """Bind fun to mouse-move event on this turtle on canvas.
3563
3564 Arguments:
3565 fun -- a function with two arguments, to which will be assigned
3566 the coordinates of the clicked point on the canvas.
3567 num -- number of the mouse-button defaults to 1 (left mouse button).
3568
3569 Every sequence of mouse-move-events on a turtle is preceded by a
3570 mouse-click event on that turtle.
3571
3572 Example (for a Turtle instance named turtle):
3573 >>> turtle.ondrag(turtle.goto)
3574
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003575 Subsequently clicking and dragging a Turtle will move it
3576 across the screen thereby producing handdrawings (if pen is
3577 down).
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003578 """
3579 self.screen._ondrag(self.turtle._item, fun, btn, add)
3580
3581
3582 def _undo(self, action, data):
3583 """Does the main part of the work for undo()
3584 """
3585 if self.undobuffer is None:
3586 return
3587 if action == "rot":
3588 angle, degPAU = data
3589 self._rotate(-angle*degPAU/self._degreesPerAU)
3590 dummy = self.undobuffer.pop()
3591 elif action == "stamp":
3592 stitem = data[0]
3593 self.clearstamp(stitem)
3594 elif action == "go":
3595 self._undogoto(data)
3596 elif action in ["wri", "dot"]:
3597 item = data[0]
3598 self.screen._delete(item)
3599 self.items.remove(item)
3600 elif action == "dofill":
3601 item = data[0]
3602 self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
3603 fill="", outline="")
3604 elif action == "beginfill":
3605 item = data[0]
3606 self._fillitem = self._fillpath = None
3607 if item in self.items:
3608 self.screen._delete(item)
3609 self.items.remove(item)
3610 elif action == "pen":
3611 TPen.pen(self, data[0])
3612 self.undobuffer.pop()
3613
3614 def undo(self):
3615 """undo (repeatedly) the last turtle action.
3616
3617 No argument.
3618
3619 undo (repeatedly) the last turtle action.
3620 Number of available undo actions is determined by the size of
3621 the undobuffer.
3622
3623 Example (for a Turtle instance named turtle):
3624 >>> for i in range(4):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003625 ... turtle.fd(50); turtle.lt(80)
3626 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003627 >>> for i in range(8):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003628 ... turtle.undo()
3629 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003630 """
3631 if self.undobuffer is None:
3632 return
3633 item = self.undobuffer.pop()
3634 action = item[0]
3635 data = item[1:]
3636 if action == "seq":
3637 while data:
3638 item = data.pop()
3639 self._undo(item[0], item[1:])
3640 else:
3641 self._undo(action, data)
3642
3643 turtlesize = shapesize
3644
3645RawPen = RawTurtle
3646
Martin v. Löwis601149b2008-09-29 22:19:08 +00003647### Screen - Singleton ########################
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003648
Martin v. Löwis601149b2008-09-29 22:19:08 +00003649def Screen():
3650 """Return the singleton screen object.
3651 If none exists at the moment, create a new one and return it,
3652 else return the existing one."""
3653 if Turtle._screen is None:
3654 Turtle._screen = _Screen()
3655 return Turtle._screen
3656
3657class _Screen(TurtleScreen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003658
3659 _root = None
3660 _canvas = None
3661 _title = _CFG["title"]
3662
Guido van Rossumb241b671998-12-04 16:42:46 +00003663 def __init__(self):
Martin v. Löwis601149b2008-09-29 22:19:08 +00003664 # XXX there is no need for this code to be conditional,
3665 # as there will be only a single _Screen instance, anyway
3666 # XXX actually, the turtle demo is injecting root window,
3667 # so perhaps the conditional creation of a root should be
3668 # preserved (perhaps by passing it as an optional parameter)
3669 if _Screen._root is None:
3670 _Screen._root = self._root = _Root()
3671 self._root.title(_Screen._title)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003672 self._root.ondestroy(self._destroy)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003673 if _Screen._canvas is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003674 width = _CFG["width"]
3675 height = _CFG["height"]
3676 canvwidth = _CFG["canvwidth"]
3677 canvheight = _CFG["canvheight"]
3678 leftright = _CFG["leftright"]
3679 topbottom = _CFG["topbottom"]
3680 self._root.setupcanvas(width, height, canvwidth, canvheight)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003681 _Screen._canvas = self._root._getcanvas()
Martin v. Löwis601149b2008-09-29 22:19:08 +00003682 TurtleScreen.__init__(self, _Screen._canvas)
Georg Brandleaa84ef2009-05-05 08:14:33 +00003683 self.setup(width, height, leftright, topbottom)
Thomas Wouters477c8d52006-05-27 19:21:47 +00003684
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003685 def setup(self, width=_CFG["width"], height=_CFG["height"],
3686 startx=_CFG["leftright"], starty=_CFG["topbottom"]):
3687 """ Set the size and position of the main window.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003688
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003689 Arguments:
3690 width: as integer a size in pixels, as float a fraction of the screen.
3691 Default is 50% of screen.
3692 height: as integer the height in pixels, as float a fraction of the
3693 screen. Default is 75% of screen.
3694 startx: if positive, starting position in pixels from the left
3695 edge of the screen, if negative from the right edge
3696 Default, startx=None is to center window horizontally.
3697 starty: if positive, starting position in pixels from the top
3698 edge of the screen, if negative from the bottom edge
3699 Default, starty=None is to center window vertically.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003700
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003701 Examples (for a Screen instance named screen):
3702 >>> screen.setup (width=200, height=200, startx=0, starty=0)
3703
3704 sets window to 200x200 pixels, in upper left of screen
3705
3706 >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
3707
3708 sets window to 75% of screen by 50% of screen and centers
3709 """
3710 if not hasattr(self._root, "set_geometry"):
3711 return
3712 sw = self._root.win_width()
3713 sh = self._root.win_height()
3714 if isinstance(width, float) and 0 <= width <= 1:
3715 width = sw*width
3716 if startx is None:
3717 startx = (sw - width) / 2
3718 if isinstance(height, float) and 0 <= height <= 1:
3719 height = sh*height
3720 if starty is None:
3721 starty = (sh - height) / 2
3722 self._root.set_geometry(width, height, startx, starty)
Georg Brandleaa84ef2009-05-05 08:14:33 +00003723 self.update()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003724
3725 def title(self, titlestring):
3726 """Set title of turtle-window
3727
3728 Argument:
3729 titlestring -- a string, to appear in the titlebar of the
3730 turtle graphics window.
3731
3732 This is a method of Screen-class. Not available for TurtleScreen-
3733 objects.
3734
3735 Example (for a Screen instance named screen):
3736 >>> screen.title("Welcome to the turtle-zoo!")
3737 """
Martin v. Löwis601149b2008-09-29 22:19:08 +00003738 if _Screen._root is not None:
3739 _Screen._root.title(titlestring)
3740 _Screen._title = titlestring
Guido van Rossumb241b671998-12-04 16:42:46 +00003741
3742 def _destroy(self):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003743 root = self._root
Martin v. Löwis601149b2008-09-29 22:19:08 +00003744 if root is _Screen._root:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003745 Turtle._pen = None
3746 Turtle._screen = None
Martin v. Löwis601149b2008-09-29 22:19:08 +00003747 _Screen._root = None
3748 _Screen._canvas = None
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003749 TurtleScreen._RUNNING = True
Guido van Rossumb241b671998-12-04 16:42:46 +00003750 root.destroy()
Fred Draked038ca82000-10-23 18:31:14 +00003751
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003752 def bye(self):
3753 """Shut the turtlegraphics window.
3754
3755 Example (for a TurtleScreen instance named screen):
3756 >>> screen.bye()
3757 """
3758 self._destroy()
3759
3760 def exitonclick(self):
3761 """Go into mainloop until the mouse is clicked.
3762
3763 No arguments.
3764
3765 Bind bye() method to mouseclick on TurtleScreen.
3766 If "using_IDLE" - value in configuration dictionary is False
3767 (default value), enter mainloop.
3768 If IDLE with -n switch (no subprocess) is used, this value should be
3769 set to True in turtle.cfg. In this case IDLE's mainloop
3770 is active also for the client script.
3771
3772 This is a method of the Screen-class and not available for
3773 TurtleScreen instances.
3774
3775 Example (for a Screen instance named screen):
3776 >>> screen.exitonclick()
3777
3778 """
3779 def exitGracefully(x, y):
3780 """Screen.bye() with two dummy-parameters"""
3781 self.bye()
3782 self.onclick(exitGracefully)
3783 if _CFG["using_IDLE"]:
3784 return
3785 try:
3786 mainloop()
3787 except AttributeError:
3788 exit(0)
3789
3790
3791class Turtle(RawTurtle):
Ezio Melotti13925002011-03-16 11:05:33 +02003792 """RawTurtle auto-creating (scrolled) canvas.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003793
3794 When a Turtle object is created or a function derived from some
3795 Turtle method is called a TurtleScreen object is automatically created.
3796 """
3797 _pen = None
3798 _screen = None
3799
3800 def __init__(self,
3801 shape=_CFG["shape"],
3802 undobuffersize=_CFG["undobuffersize"],
3803 visible=_CFG["visible"]):
3804 if Turtle._screen is None:
3805 Turtle._screen = Screen()
3806 RawTurtle.__init__(self, Turtle._screen,
3807 shape=shape,
3808 undobuffersize=undobuffersize,
3809 visible=visible)
3810
3811Pen = Turtle
3812
Guido van Rossumb241b671998-12-04 16:42:46 +00003813def _getpen():
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003814 """Create the 'anonymous' turtle if not already present."""
3815 if Turtle._pen is None:
3816 Turtle._pen = Turtle()
3817 return Turtle._pen
Thomas Wouters477c8d52006-05-27 19:21:47 +00003818
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003819def _getscreen():
3820 """Create a TurtleScreen if not already present."""
3821 if Turtle._screen is None:
3822 Turtle._screen = Screen()
3823 return Turtle._screen
Thomas Wouters477c8d52006-05-27 19:21:47 +00003824
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003825def write_docstringdict(filename="turtle_docstringdict"):
3826 """Create and write docstring-dictionary to file.
Guido van Rossumb241b671998-12-04 16:42:46 +00003827
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003828 Optional argument:
3829 filename -- a string, used as filename
3830 default value is turtle_docstringdict
Thomas Wouters477c8d52006-05-27 19:21:47 +00003831
Ezio Melotti13925002011-03-16 11:05:33 +02003832 Has to be called explicitly, (not used by the turtle-graphics classes)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003833 The docstring dictionary will be written to the Python script <filname>.py
3834 It is intended to serve as a template for translation of the docstrings
3835 into different languages.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003836 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003837 docsdict = {}
Thomas Wouters477c8d52006-05-27 19:21:47 +00003838
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003839 for methodname in _tg_screen_functions:
Martin v. Löwis601149b2008-09-29 22:19:08 +00003840 key = "_Screen."+methodname
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003841 docsdict[key] = eval(key).__doc__
3842 for methodname in _tg_turtle_functions:
3843 key = "Turtle."+methodname
3844 docsdict[key] = eval(key).__doc__
Thomas Wouters477c8d52006-05-27 19:21:47 +00003845
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003846 f = open("%s.py" % filename,"w")
3847 keys = sorted([x for x in docsdict.keys()
3848 if x.split('.')[1] not in _alias_list])
3849 f.write('docsdict = {\n\n')
3850 for key in keys[:-1]:
3851 f.write('%s :\n' % repr(key))
3852 f.write(' """%s\n""",\n\n' % docsdict[key])
3853 key = keys[-1]
3854 f.write('%s :\n' % repr(key))
3855 f.write(' """%s\n"""\n\n' % docsdict[key])
3856 f.write("}\n")
3857 f.close()
Thomas Wouters477c8d52006-05-27 19:21:47 +00003858
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003859def read_docstrings(lang):
3860 """Read in docstrings from lang-specific docstring dictionary.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003861
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003862 Transfer docstrings, translated to lang, from a dictionary-file
3863 to the methods of classes Screen and Turtle and - in revised form -
3864 to the corresponding functions.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003865 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003866 modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
3867 module = __import__(modname)
3868 docsdict = module.docsdict
3869 for key in docsdict:
3870 try:
3871# eval(key).im_func.__doc__ = docsdict[key]
3872 eval(key).__doc__ = docsdict[key]
3873 except:
3874 print("Bad docstring-entry: %s" % key)
Thomas Wouters477c8d52006-05-27 19:21:47 +00003875
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003876_LANGUAGE = _CFG["language"]
Guido van Rossumb241b671998-12-04 16:42:46 +00003877
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003878try:
3879 if _LANGUAGE != "english":
3880 read_docstrings(_LANGUAGE)
3881except ImportError:
3882 print("Cannot find docsdict for", _LANGUAGE)
3883except:
3884 print ("Unknown Error when trying to import %s-docstring-dictionary" %
3885 _LANGUAGE)
3886
3887
3888def getmethparlist(ob):
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003889 """Get strings describing the arguments for the given object
3890
3891 Returns a pair of strings representing function parameter lists
3892 including parenthesis. The first string is suitable for use in
3893 function definition and the second is suitable for use in function
3894 call. The "self" parameter is not included.
3895 """
3896 defText = callText = ""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003897 # bit of a hack for methods - turn it into a function
3898 # but we drop the "self" param.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003899 # Try and build one for Python defined functions
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003900 args, varargs, varkw = inspect.getargs(ob.__code__)
3901 items2 = args[1:]
3902 realArgs = args[1:]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003903 defaults = ob.__defaults__ or []
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003904 defaults = ["=%r" % (value,) for value in defaults]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003905 defaults = [""] * (len(realArgs)-len(defaults)) + defaults
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003906 items1 = [arg + dflt for arg, dflt in zip(realArgs, defaults)]
3907 if varargs is not None:
3908 items1.append("*" + varargs)
3909 items2.append("*" + varargs)
3910 if varkw is not None:
3911 items1.append("**" + varkw)
3912 items2.append("**" + varkw)
3913 defText = ", ".join(items1)
3914 defText = "(%s)" % defText
3915 callText = ", ".join(items2)
3916 callText = "(%s)" % callText
3917 return defText, callText
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003918
3919def _turtle_docrevise(docstr):
3920 """To reduce docstrings from RawTurtle class for functions
3921 """
3922 import re
3923 if docstr is None:
3924 return None
3925 turtlename = _CFG["exampleturtle"]
3926 newdocstr = docstr.replace("%s." % turtlename,"")
3927 parexp = re.compile(r' \(.+ %s\):' % turtlename)
3928 newdocstr = parexp.sub(":", newdocstr)
3929 return newdocstr
3930
3931def _screen_docrevise(docstr):
3932 """To reduce docstrings from TurtleScreen class for functions
3933 """
3934 import re
3935 if docstr is None:
3936 return None
3937 screenname = _CFG["examplescreen"]
3938 newdocstr = docstr.replace("%s." % screenname,"")
3939 parexp = re.compile(r' \(.+ %s\):' % screenname)
3940 newdocstr = parexp.sub(":", newdocstr)
3941 return newdocstr
3942
3943## The following mechanism makes all methods of RawTurtle and Turtle available
3944## as functions. So we can enhance, change, add, delete methods to these
3945## classes and do not need to change anything here.
3946
3947
3948for methodname in _tg_screen_functions:
Martin v. Löwis601149b2008-09-29 22:19:08 +00003949 pl1, pl2 = getmethparlist(eval('_Screen.' + methodname))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003950 if pl1 == "":
3951 print(">>>>>>", pl1, pl2)
3952 continue
3953 defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
3954 {'key':methodname, 'pl1':pl1, 'pl2':pl2})
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003955 exec(defstr)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003956 eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003957
3958for methodname in _tg_turtle_functions:
3959 pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
3960 if pl1 == "":
3961 print(">>>>>>", pl1, pl2)
3962 continue
3963 defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" %
3964 {'key':methodname, 'pl1':pl1, 'pl2':pl2})
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003965 exec(defstr)
3966 eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__)
3967
3968
Georg Brandleaa84ef2009-05-05 08:14:33 +00003969done = mainloop
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003970
3971if __name__ == "__main__":
3972 def switchpen():
3973 if isdown():
3974 pu()
3975 else:
3976 pd()
3977
3978 def demo1():
3979 """Demo of old turtle.py - module"""
3980 reset()
3981 tracer(True)
3982 up()
3983 backward(100)
3984 down()
3985 # draw 3 squares; the last filled
3986 width(3)
3987 for i in range(3):
3988 if i == 2:
3989 begin_fill()
3990 for _ in range(4):
3991 forward(20)
3992 left(90)
3993 if i == 2:
3994 color("maroon")
3995 end_fill()
3996 up()
3997 forward(30)
3998 down()
3999 width(1)
4000 color("black")
4001 # move out of the way
4002 tracer(False)
4003 up()
4004 right(90)
4005 forward(100)
4006 right(90)
4007 forward(100)
4008 right(180)
4009 down()
4010 # some text
4011 write("startstart", 1)
4012 write("start", 1)
4013 color("red")
4014 # staircase
4015 for i in range(5):
Guido van Rossumb241b671998-12-04 16:42:46 +00004016 forward(20)
4017 left(90)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004018 forward(20)
4019 right(90)
4020 # filled staircase
4021 tracer(True)
4022 begin_fill()
4023 for i in range(5):
4024 forward(20)
4025 left(90)
4026 forward(20)
4027 right(90)
4028 end_fill()
4029 # more text
Thomas Wouters477c8d52006-05-27 19:21:47 +00004030
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004031 def demo2():
4032 """Demo of some new features."""
4033 speed(1)
4034 st()
4035 pensize(3)
4036 setheading(towards(0, 0))
4037 radius = distance(0, 0)/2.0
4038 rt(90)
4039 for _ in range(18):
4040 switchpen()
4041 circle(radius, 10)
4042 write("wait a moment...")
4043 while undobufferentries():
4044 undo()
4045 reset()
4046 lt(90)
4047 colormode(255)
4048 laenge = 10
4049 pencolor("green")
4050 pensize(3)
4051 lt(180)
4052 for i in range(-2, 16):
4053 if i > 0:
4054 begin_fill()
4055 fillcolor(255-15*i, 0, 15*i)
4056 for _ in range(3):
4057 fd(laenge)
4058 lt(120)
4059 end_fill()
4060 laenge += 10
4061 lt(15)
4062 speed((speed()+1)%12)
4063 #end_fill()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004064
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004065 lt(120)
4066 pu()
4067 fd(70)
4068 rt(30)
4069 pd()
4070 color("red","yellow")
4071 speed(0)
4072 begin_fill()
4073 for _ in range(4):
4074 circle(50, 90)
4075 rt(90)
4076 fd(30)
4077 rt(90)
4078 end_fill()
4079 lt(90)
4080 pu()
4081 fd(30)
4082 pd()
4083 shape("turtle")
Thomas Wouters477c8d52006-05-27 19:21:47 +00004084
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004085 tri = getturtle()
4086 tri.resizemode("auto")
4087 turtle = Turtle()
4088 turtle.resizemode("auto")
4089 turtle.shape("turtle")
4090 turtle.reset()
4091 turtle.left(90)
4092 turtle.speed(0)
4093 turtle.up()
4094 turtle.goto(280, 40)
4095 turtle.lt(30)
4096 turtle.down()
4097 turtle.speed(6)
4098 turtle.color("blue","orange")
4099 turtle.pensize(2)
4100 tri.speed(6)
Thomas Wouters477c8d52006-05-27 19:21:47 +00004101 setheading(towards(turtle))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004102 count = 1
4103 while tri.distance(turtle) > 4:
4104 turtle.fd(3.5)
4105 turtle.lt(0.6)
4106 tri.setheading(tri.towards(turtle))
4107 tri.fd(4)
4108 if count % 20 == 0:
4109 turtle.stamp()
4110 tri.stamp()
4111 switchpen()
4112 count += 1
4113 tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
4114 tri.pencolor("black")
4115 tri.pencolor("red")
Thomas Wouters477c8d52006-05-27 19:21:47 +00004116
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004117 def baba(xdummy, ydummy):
4118 clearscreen()
4119 bye()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004120
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004121 time.sleep(2)
Guido van Rossumb241b671998-12-04 16:42:46 +00004122
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004123 while undobufferentries():
4124 tri.undo()
4125 turtle.undo()
4126 tri.fd(50)
4127 tri.write(" Click me!", font = ("Courier", 12, "bold") )
4128 tri.onclick(baba, 1)
4129
4130 demo1()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004131 demo2()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004132 exitonclick()