13
35
By combining together these and similar commands, intricate shapes and
14
36
pictures can easily be drawn.
40
This module is an extended reimplementation of turtle.py from the
41
Python standard distribution up to Python 2.5. (See: http:\\www.python.org)
43
It tries to keep the merits of turtle.py and to be (nearly) 100%
44
compatible with it. This means in the first place to enable the
45
learning programmer to use all the commands, classes and methods
46
interactively when using the module from within IDLE run with
49
Roughly it has the following features added:
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.
55
- Different turtle shapes, gif-images as turtle shapes, user defined
56
and user controllable turtle shapes, among them compound
57
(multicolored) shapes. Turtle shapes can be stgretched and tilted, which
58
makes turtles zu very versatile geometrical objects.
60
- Fine control over turtle movement and screen updates via delay(),
61
and enhanced tracer() and speed() methods.
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
69
- Turtles now have an undo()-method with configurable undo-buffer.
71
- Some simple commands/methods for creating event driven programs
72
(mouse-, key-, timer-events). Especially useful for programming games.
74
- A scrollable Canvas class. The default scrollable Canvas can be
75
extended interactively as needed while playing around with the turtle(s).
77
- A TurtleScreen class with methods controlling background color or
78
background image, window and canvas size and other properties of the
81
- There is a method, setworldcoordinates(), to install a user defined
82
coordinate-system for the TurtleScreen.
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.
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.
92
- If configured appropriately the module reads in docstrings from a docstring
93
dictionary in some different language, supplied separately and replaces
94
the english ones by those read in. There is a utility function
95
write_docstringdict() to write a dictionary with the original (english)
96
docstrings to disc, so it can serve as a template for translations.
98
Behind the scenes there are some features included with possible
99
extensionsin in mind. These will be commented and documented elsewhere.
17
from math import * # Also for export
18
from time import sleep
21
speeds = ['fastest', 'fast', 'normal', 'slow', 'slowest']
23
class Error(Exception):
103
_ver = "turtle 1.0b1 - for Python 2.6 - 30. 5. 2008, 18:08"
113
from os.path import isfile, split, join
114
from copy import deepcopy
116
from math import * ## for compatibility with old turtle module
118
_tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
119
'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
120
_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
121
'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
122
'getshapes', 'listen', 'mode', 'onkey', 'onscreenclick', 'ontimer',
123
'register_shape', 'resetscreen', 'screensize', 'setup',
124
'setworldcoordinates', 'title', 'tracer', 'turtles', 'update',
125
'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',
129
'fill', 'fillcolor', 'forward', 'get_poly', 'getpen', 'getscreen',
130
'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',
135
'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'showturtle',
136
'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards', 'tracer',
137
'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
138
'window_height', 'window_width', 'write', 'xcor', 'ycor']
139
_tg_utilities = ['write_docstringdict', 'done', 'mainloop']
140
_math_functions = ['acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'cosh',
141
'e', 'exp', 'fabs', 'floor', 'fmod', 'frexp', 'hypot', 'ldexp', 'log',
142
'log10', 'modf', 'pi', 'pow', 'sin', 'sinh', 'sqrt', 'tan', 'tanh']
144
__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
145
_tg_utilities + _math_functions)
147
_alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
148
'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
149
'turtlesize', 'up', 'width']
151
_CFG = {"width" : 0.5, # Screen
157
"mode": "standard", # TurtleScreen
160
"undobuffersize": 1000, # RawTurtle
162
"pencolor" : "black",
163
"fillcolor" : "black",
164
"resizemode" : "noresize",
166
"language": "english", # docstrings
167
"exampleturtle": "turtle",
168
"examplescreen": "screen",
169
"title": "Python Turtle Graphics",
173
##print "cwd:", os.getcwd()
174
##print "__file__:", __file__
176
##def show(dictionary):
177
## print "=========================="
178
## for key in sorted(dictionary.keys()):
179
## print key, ":", dictionary[key]
180
## print "=========================="
183
def config_dict(filename):
184
"""Convert content of config-file into dictionary."""
185
f = open(filename, "r")
186
cfglines = f.readlines()
189
for line in cfglines:
191
if not line or line.startswith("#"):
194
key, value = line.split("=")
196
print "Bad line in config-file %s:\n%s" % (filename,line)
199
value = value.strip()
200
if value in ["True", "False", "None", "''", '""']:
209
pass # value need not be converted
213
def readconfig(cfgdict):
214
"""Read config-files, change configuration-dict accordingly.
216
If there is a turtle.cfg file in the current working directory,
217
read it from there. If this contains an importconfig-value,
218
say 'myway', construct filename turtle_mayway.cfg else use
219
turtle.cfg and read it from the import-directory, where
220
turtle.py is located.
221
Update configuration dictionary first according to config-file,
222
in the import directory, then according to config-file in the
223
current working directory.
224
If no config-file is found, the default configuration is used.
226
default_cfg = "turtle.cfg"
229
if isfile(default_cfg):
230
cfgdict1 = config_dict(default_cfg)
231
#print "1. Loading config-file %s from: %s" % (default_cfg, os.getcwd())
232
if "importconfig" in cfgdict1:
233
default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
235
head, tail = split(__file__)
236
cfg_file2 = join(head, default_cfg)
239
if isfile(cfg_file2):
240
#print "2. Loading config-file %s:" % cfg_file2
241
cfgdict2 = config_dict(cfg_file2)
244
_CFG.update(cfgdict2)
247
_CFG.update(cfgdict1)
253
print "No configfile read, reason unknown"
257
"""A 2 dimensional vector class, used as a helper class
258
for implementing turtle graphics.
259
May be useful for turtle graphics programs also.
260
Derived from tuple, so a vector is a tuple!
262
Provides (for a, b vectors, k number):
264
a-b vector subtraction
266
k*a and a*k multiplication with scalar
267
|a| absolute value of a
268
a.rotate(angle) rotation
270
def __new__(cls, x, y):
271
return tuple.__new__(cls, (x, y))
272
def __add__(self, other):
273
return Vec2D(self[0]+other[0], self[1]+other[1])
274
def __mul__(self, other):
275
if isinstance(other, Vec2D):
276
return self[0]*other[0]+self[1]*other[1]
277
return Vec2D(self[0]*other, self[1]*other)
278
def __rmul__(self, other):
279
if isinstance(other, int) or isinstance(other, float):
280
return Vec2D(self[0]*other, self[1]*other)
281
def __sub__(self, other):
282
return Vec2D(self[0]-other[0], self[1]-other[1])
284
return Vec2D(-self[0], -self[1])
286
return (self[0]**2 + self[1]**2)**0.5
287
def rotate(self, angle):
288
"""rotate self counterclockwise by angle
290
perp = Vec2D(-self[1], self[0])
291
angle = angle * math.pi / 180.0
292
c, s = math.cos(angle), math.sin(angle)
293
return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
294
def __getnewargs__(self):
295
return (self[0], self[1])
297
return "(%.2f,%.2f)" % self
300
##############################################################################
301
### From here up to line : Tkinter - Interface for turtle.py ###
302
### May be replaced by an interface to some different graphcis-toolkit ###
303
##############################################################################
305
## helper functions for Scrolled Canvas, to forward Canvas-methods
306
## to ScrolledCanvas class
308
def __methodDict(cls, _dict):
309
"""helper function for Scrolled Canvas"""
310
baseList = list(cls.__bases__)
312
for _super in baseList:
313
__methodDict(_super, _dict)
314
for key, value in cls.__dict__.items():
315
if type(value) == types.FunctionType:
319
"""helper function for Scrolled Canvas"""
321
__methodDict(cls, _dict)
325
'def %(method)s(self, *args, **kw): return ' +
326
'self.%(attribute)s.%(method)s(*args, **kw)')
328
def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
329
"""Helper functions for Scrolled Canvas, used to forward
330
ScrolledCanvas-methods to Tkinter.Canvas class.
333
__methodDict(toClass, _dict)
334
for ex in _dict.keys():
335
if ex[:1] == '_' or ex[-1:] == '_':
338
if _dict.has_key(ex):
340
for ex in __methods(fromClass):
341
if _dict.has_key(ex):
344
for method, func in _dict.items():
345
d = {'method': method, 'func': func}
346
if type(toPart) == types.StringType:
348
__stringBody % {'method' : method, 'attribute' : toPart}
350
fromClass.__dict__[method] = d[method]
353
class ScrolledCanvas(TK.Frame):
354
"""Modeled after the scrolled canvas class from Grayons's Tkinter book.
356
Used as the default canvas, which pops up automatically when
357
using turtle graphics functions or the Turtle class.
359
def __init__(self, master, width=500, height=350,
360
canvwidth=600, canvheight=500):
361
TK.Frame.__init__(self, master, width=width, height=height)
362
self._root = self.winfo_toplevel()
363
self.width, self.height = width, height
364
self.canvwidth, self.canvheight = canvwidth, canvheight
366
self._canvas = TK.Canvas(master, width=width, height=height,
367
bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
368
self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
369
orient=TK.HORIZONTAL)
370
self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
371
self._canvas.configure(xscrollcommand=self.hscroll.set,
372
yscrollcommand=self.vscroll.set)
373
self.rowconfigure(0, weight=1, minsize=0)
374
self.columnconfigure(0, weight=1, minsize=0)
375
self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
376
column=0, rowspan=1, columnspan=1, sticky='news')
377
self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
378
column=1, rowspan=1, columnspan=1, sticky='news')
379
self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
380
column=0, rowspan=1, columnspan=1, sticky='news')
382
self._root.bind('<Configure>', self.onResize)
384
def reset(self, canvwidth=None, canvheight=None, bg = None):
385
"""Ajust canvas and scrollbars according to given canvas size."""
387
self.canvwidth = canvwidth
389
self.canvheight = canvheight
392
self._canvas.config(bg=bg,
393
scrollregion=(-self.canvwidth//2, -self.canvheight//2,
394
self.canvwidth//2, self.canvheight//2))
395
self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
397
self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
402
def adjustScrolls(self):
403
""" Adjust scrollbars according to window- and canvas-size.
405
cwidth = self._canvas.winfo_width()
406
cheight = self._canvas.winfo_height()
407
self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
408
self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
409
if cwidth < self.canvwidth or cheight < self.canvheight:
410
self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
411
column=0, rowspan=1, columnspan=1, sticky='news')
412
self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
413
column=1, rowspan=1, columnspan=1, sticky='news')
415
self.hscroll.grid_forget()
416
self.vscroll.grid_forget()
418
def onResize(self, event):
419
"""self-explanatory"""
422
def bbox(self, *args):
423
""" 'forward' method, which canvas itself has inherited...
425
return self._canvas.bbox(*args)
427
def cget(self, *args, **kwargs):
428
""" 'forward' method, which canvas itself has inherited...
430
return self._canvas.cget(*args, **kwargs)
432
def config(self, *args, **kwargs):
433
""" 'forward' method, which canvas itself has inherited...
435
self._canvas.config(*args, **kwargs)
437
def bind(self, *args, **kwargs):
438
""" 'forward' method, which canvas itself has inherited...
440
self._canvas.bind(*args, **kwargs)
442
def unbind(self, *args, **kwargs):
443
""" 'forward' method, which canvas itself has inherited...
445
self._canvas.unbind(*args, **kwargs)
447
def focus_force(self):
448
""" 'forward' method, which canvas itself has inherited...
450
self._canvas.focus_force()
452
__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
456
"""Root class for Screen based on Tkinter."""
460
def setupcanvas(self, width, height, cwidth, cheight):
461
self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
462
self._canvas.pack(expand=1, fill="both")
464
def _getcanvas(self):
467
def set_geometry(self, width, height, startx, starty):
468
self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
470
def ondestroy(self, destroy):
471
self.wm_protocol("WM_DELETE_WINDOW", destroy)
474
return self.winfo_screenwidth()
476
def win_height(self):
477
return self.winfo_screenheight()
482
class TurtleScreenBase(object):
483
"""Provide the basic graphics functionality.
484
Interface between Tkinter and turtle.py.
486
To port turtle.py to some different graphics toolkit
487
a corresponding TurtleScreenBase class has to be implemented.
492
"""return a blank image object
494
img = TK.PhotoImage(width=1, height=1)
499
def _image(filename):
500
"""return an image object containing the
501
imagedata from a gif-file named filename.
503
return TK.PhotoImage(file=filename)
505
def __init__(self, cv):
507
if isinstance(cv, ScrolledCanvas):
508
w = self.cv.canvwidth
509
h = self.cv.canvheight
510
else: # expected: ordinary TK.Canvas
511
w = int(self.cv.cget("width"))
512
h = int(self.cv.cget("height"))
513
self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
516
self.xscale = self.yscale = 1.0
518
def _createpoly(self):
519
"""Create an invisible polygon item on canvas self.cv)
521
return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
523
def _drawpoly(self, polyitem, coordlist, fill=None,
524
outline=None, width=None, top=False):
525
"""Configure polygonitem polyitem according to provided
527
coordlist is sequence of coordinates
528
fill is filling color
529
outline is outline color
530
top is a boolean value, which specifies if polyitem
531
will be put on top of the canvas' displaylist so it
532
will not be covered by other items.
535
for x, y in coordlist:
536
cl.append(x * self.xscale)
537
cl.append(-y * self.yscale)
538
self.cv.coords(polyitem, *cl)
540
self.cv.itemconfigure(polyitem, fill=fill)
541
if outline is not None:
542
self.cv.itemconfigure(polyitem, outline=outline)
543
if width is not None:
544
self.cv.itemconfigure(polyitem, width=width)
546
self.cv.tag_raise(polyitem)
548
def _createline(self):
549
"""Create an invisible line item on canvas self.cv)
551
return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
554
def _drawline(self, lineitem, coordlist=None,
555
fill=None, width=None, top=False):
556
"""Configure lineitem according to provided arguments:
557
coordlist is sequence of coordinates
558
fill is drawing color
559
width is width of drawn line.
560
top is a boolean value, which specifies if polyitem
561
will be put on top of the canvas' displaylist so it
562
will not be covered by other items.
564
if coordlist is not None:
566
for x, y in coordlist:
567
cl.append(x * self.xscale)
568
cl.append(-y * self.yscale)
569
self.cv.coords(lineitem, *cl)
571
self.cv.itemconfigure(lineitem, fill=fill)
572
if width is not None:
573
self.cv.itemconfigure(lineitem, width=width)
575
self.cv.tag_raise(lineitem)
577
def _delete(self, item):
578
"""Delete graphics item from canvas.
579
If item is"all" delete all graphics items.
584
"""Redraw graphics items on canvas
588
def _delay(self, delay):
589
"""Delay subsequent canvas actions for delay ms."""
592
def _iscolorstring(self, color):
593
"""Check if the string color is a legal Tkinter color string.
596
rgb = self.cv.winfo_rgb(color)
602
def _bgcolor(self, color=None):
603
"""Set canvas' backgroundcolor if color is not None,
604
else return backgroundcolor."""
605
if color is not None:
606
self.cv.config(bg = color)
609
return self.cv.cget("bg")
611
def _write(self, pos, txt, align, font, pencolor):
612
"""Write txt at pos in canvas with specified font
614
Return text item and x-coord of right bottom corner
615
of text's bounding box."""
619
anchor = {"left":"sw", "center":"s", "right":"se" }
620
item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
621
fill = pencolor, font = font)
622
x0, y0, x1, y1 = self.cv.bbox(item)
626
## def _dot(self, pos, size, color):
627
## """may be implemented for some other graphics toolkit"""
629
def _onclick(self, item, fun, num=1, add=None):
630
"""Bind fun to mouse-click event on turtle.
631
fun must be a function with two arguments, the coordinates
632
of the clicked point on the canvas.
633
num, the number of the mouse-button defaults to 1
636
self.cv.tag_unbind(item, "<Button-%s>" % num)
639
x, y = (self.cv.canvasx(event.x)/self.xscale,
640
-self.cv.canvasy(event.y)/self.yscale)
642
self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
644
def _onrelease(self, item, fun, num=1, add=None):
645
"""Bind fun to mouse-button-release event on turtle.
646
fun must be a function with two arguments, the coordinates
647
of the point on the canvas where mouse button is released.
648
num, the number of the mouse-button defaults to 1
650
If a turtle is clicked, first _onclick-event will be performed,
651
then _onscreensclick-event.
654
self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
657
x, y = (self.cv.canvasx(event.x)/self.xscale,
658
-self.cv.canvasy(event.y)/self.yscale)
660
self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
663
def _ondrag(self, item, fun, num=1, add=None):
664
"""Bind fun to mouse-move-event (with pressed mouse button) on turtle.
665
fun must be a function with two arguments, the coordinates of the
666
actual mouse position on the canvas.
667
num, the number of the mouse-button defaults to 1
669
Every sequence of mouse-move-events on a turtle is preceded by a
670
mouse-click event on that turtle.
673
self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
677
x, y = (self.cv.canvasx(event.x)/self.xscale,
678
-self.cv.canvasy(event.y)/self.yscale)
682
self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
684
def _onscreenclick(self, fun, num=1, add=None):
685
"""Bind fun to mouse-click event on canvas.
686
fun must be a function with two arguments, the coordinates
687
of the clicked point on the canvas.
688
num, the number of the mouse-button defaults to 1
690
If a turtle is clicked, first _onclick-event will be performed,
691
then _onscreensclick-event.
694
self.cv.unbind("<Button-%s>" % num)
697
x, y = (self.cv.canvasx(event.x)/self.xscale,
698
-self.cv.canvasy(event.y)/self.yscale)
700
self.cv.bind("<Button-%s>" % num, eventfun, add)
702
def _onkey(self, fun, key):
703
"""Bind fun to key-release event of key.
704
Canvas must have focus. See method listen
707
self.cv.unbind("<KeyRelease-%s>" % key, None)
711
self.cv.bind("<KeyRelease-%s>" % key, eventfun)
714
"""Set focus on canvas (in order to collect key-events)
716
self.cv.focus_force()
718
def _ontimer(self, fun, t):
719
"""Install a timer, which calls fun after t milliseconds.
722
self.cv.after_idle(fun)
724
self.cv.after(t, fun)
726
def _createimage(self, image):
727
"""Create and return image item on canvas.
729
return self.cv.create_image(0, 0, image=image)
731
def _drawimage(self, item, (x, y), image):
732
"""Configure image item as to draw image object
733
at position (x,y) on canvas)
735
self.cv.coords(item, (x, -y))
736
self.cv.itemconfig(item, image=image)
738
def _setbgpic(self, item, image):
739
"""Configure image item as to draw image object
740
at center of canvas. Set item to the first item
741
in the displaylist, so it will be drawn below
743
self.cv.itemconfig(item, image=image)
744
self.cv.tag_lower(item)
746
def _type(self, item):
747
"""Return 'line' or 'polygon' or 'image' depending on
750
return self.cv.type(item)
752
def _pointlist(self, item):
753
"""returns list of coordinate-pairs of points of item
754
Example (for insiders):
755
>>> from turtle import *
756
>>> getscreen()._pointlist(getturtle().turtle._item)
757
[(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
758
(9.9999999999999982, 0.0)]
760
cl = self.cv.coords(item)
761
pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
764
def _setscrollregion(self, srx1, sry1, srx2, sry2):
765
self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
767
def _rescale(self, xscalefactor, yscalefactor):
768
items = self.cv.find_all()
770
coordinates = self.cv.coords(item)
773
x, y = coordinates[:2]
774
newcoordlist.append(x * xscalefactor)
775
newcoordlist.append(y * yscalefactor)
776
coordinates = coordinates[2:]
777
self.cv.coords(item, *newcoordlist)
779
def _resize(self, canvwidth=None, canvheight=None, bg=None):
780
"""Resize the canvas, the turtles are drawing on. Does
781
not alter the drawing window.
784
if not isinstance(self.cv, ScrolledCanvas):
785
return self.canvwidth, self.canvheight
786
if canvwidth is None and canvheight is None and bg is None:
787
return self.cv.canvwidth, self.cv.canvheight
788
if canvwidth is not None:
789
self.canvwidth = canvwidth
790
if canvheight is not None:
791
self.canvheight = canvheight
792
self.cv.reset(canvwidth, canvheight, bg)
794
def _window_size(self):
795
""" Return the width and height of the turtle window.
797
width = self.cv.winfo_width()
798
if width <= 1: # the window isn't managed by a geometry manager
799
width = self.cv['width']
800
height = self.cv.winfo_height()
801
if height <= 1: # the window isn't managed by a geometry manager
802
height = self.cv['height']
806
##############################################################################
807
### End of Tkinter - interface ###
808
##############################################################################
811
class Terminator (Exception):
812
"""Will be raised in TurtleScreen.update, if _RUNNING becomes False.
814
Thus stops execution of turtle graphics script. Main purpose: use in
815
in the Demo-Viewer turtle.Demo.py.
28
def __init__(self, canvas):
820
class TurtleGraphicsError(Exception):
821
"""Some TurtleGraphics Error
826
"""Data structure modeling shapes.
828
attribute _type is one of "polygon", "image", "compound"
829
attribute _data is - depending on _type a poygon-tuple,
830
an image or a list constructed using the addcomponent method.
832
def __init__(self, type_, data=None):
834
if type_ == "polygon":
835
if isinstance(data, list):
837
elif type_ == "image":
838
if isinstance(data, str):
839
if data.lower().endswith(".gif") and isfile(data):
840
data = TurtleScreen._image(data)
841
# else data assumed to be Photoimage
842
elif type_ == "compound":
845
raise TurtleGraphicsError("There is no shape type %s" % type_)
848
def addcomponent(self, poly, fill, outline=None):
849
"""Add component to a shape of type compound.
851
Arguments: poly is a polygon, i. e. a tuple of number pairs.
852
fill is the fillcolor of the component,
853
outline is the outline color of the component.
855
call (for a Shapeobject namend s):
856
-- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
859
>>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
860
>>> s = Shape("compound")
861
>>> s.addcomponent(poly, "red", "blue")
862
### .. add more components and then use register_shape()
864
if self._type != "compound":
865
raise TurtleGraphicsError("Cannot add component to %s Shape"
869
self._data.append([poly, fill, outline])
872
class Tbuffer(object):
873
"""Ring buffer used as undobuffer for RawTurtle objects."""
874
def __init__(self, bufsize=10):
875
self.bufsize = bufsize
876
self.buffer = [[None]] * bufsize
878
self.cumulate = False
879
def reset(self, bufsize=None):
881
for i in range(self.bufsize):
882
self.buffer[i] = [None]
884
self.bufsize = bufsize
885
self.buffer = [[None]] * bufsize
887
def push(self, item):
889
if not self.cumulate:
890
self.ptr = (self.ptr + 1) % self.bufsize
891
self.buffer[self.ptr] = item
893
self.buffer[self.ptr].append(item)
896
item = self.buffer[self.ptr]
900
self.buffer[self.ptr] = [None]
901
self.ptr = (self.ptr - 1) % self.bufsize
903
def nr_of_items(self):
904
return self.bufsize - self.buffer.count([None])
906
return str(self.buffer) + " " + str(self.ptr)
910
class TurtleScreen(TurtleScreenBase):
911
"""Provides screen oriented methods like setbg etc.
913
Only relies upon the methods of TurtleScreenBase and NOT
914
upon components of the underlying graphics toolkit -
915
which is Tkinter in this case.
917
# _STANDARD_DELAY = 5
920
def __init__(self, cv, mode=_CFG["mode"],
921
colormode=_CFG["colormode"], delay=_CFG["delay"]):
923
"arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
924
"turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
925
(-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
926
(-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
927
(5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
929
"circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
930
(5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
931
(-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
932
(-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
933
(-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
934
(5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
935
"square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
937
"triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
939
"classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
940
"blank" : Shape("image", self._blankimage())
943
self._bgpics = {"nopic" : ""}
945
TurtleScreenBase.__init__(self, cv)
947
self._delayvalue = delay
948
self._colormode = _CFG["colormode"]
953
"""Delete all drawings and all turtles from the TurtleScreen.
955
Reset empty TurtleScreen to it's initial state: white background,
956
no backgroundimage, no eventbindings and tracing on.
960
Example (for a TurtleScreen instance named screen):
963
Note: this method is not available as function.
965
self._delayvalue = _CFG["delay"]
966
self._colormode = _CFG["colormode"]
968
self._bgpic = self._createimage("")
969
self._bgpicname = "nopic"
33
self._delay = 10 # default delay for drawing
971
self._updatecounter = 0
973
self.bgcolor("white")
975
self.onclick(None, btn)
976
for key in self._keys[:]:
977
self.onkey(None, key)
980
def mode(self, mode=None):
981
"""Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
984
mode -- on of the strings 'standard', 'logo' or 'world'
986
Mode 'standard' is compatible with turtle.py.
987
Mode 'logo' is compatible with most Logo-Turtle-Graphics.
988
Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
989
this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
990
If mode is not given, return the current mode.
992
Mode Initial turtle heading positive angles
993
------------|-------------------------|-------------------
994
'standard' to the right (east) counterclockwise
995
'logo' upward (north) clockwise
998
>>> mode('logo') # resets turtle heading to north
1005
if mode not in ["standard", "logo", "world"]:
1006
raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
1008
if mode in ["standard", "logo"]:
1009
self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
1010
self.canvwidth//2, self.canvheight//2)
1011
self.xscale = self.yscale = 1.0
1014
def setworldcoordinates(self, llx, lly, urx, ury):
1015
"""Set up a user defined coordinate-system.
1018
llx -- a number, x-coordinate of lower left corner of canvas
1019
lly -- a number, y-coordinate of lower left corner of canvas
1020
urx -- a number, x-coordinate of upper right corner of canvas
1021
ury -- a number, y-coordinate of upper right corner of canvas
1023
Set up user coodinat-system and switch to mode 'world' if necessary.
1024
This performs a screen.reset. If mode 'world' is already active,
1025
all drawings are redrawn according to the new coordinates.
1027
But ATTENTION: in user-defined coordinatesystems angles may appear
1028
distorted. (see Screen.mode())
1030
Example (for a TurtleScreen instance named screen):
1031
>>> screen.setworldcoordinates(-10,-0.5,50,1.5)
1032
>>> for _ in range(36):
1036
if self.mode() != "world":
1038
xspan = float(urx - llx)
1039
yspan = float(ury - lly)
1040
wx, wy = self._window_size()
1041
self.screensize(wx-20, wy-20)
1042
oldxscale, oldyscale = self.xscale, self.yscale
1043
self.xscale = self.canvwidth / xspan
1044
self.yscale = self.canvheight / yspan
1045
srx1 = llx * self.xscale
1046
sry1 = -ury * self.yscale
1047
srx2 = self.canvwidth + srx1
1048
sry2 = self.canvheight + sry1
1049
self._setscrollregion(srx1, sry1, srx2, sry2)
1050
self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
1053
def register_shape(self, name, shape=None):
1054
"""Adds a turtle shape to TurtleScreen's shapelist.
1057
(1) name is the name of a gif-file and shape is None.
1058
Installs the corresponding image shape.
1059
!! Image-shapes DO NOT rotate when turning the turtle,
1060
!! so they do not display the heading of the turtle!
1061
(2) name is an arbitrary string and shape is a tuple
1062
of pairs of coordinates. Installs the corresponding
1064
(3) name is an arbitrary string and shape is a
1065
(compound) Shape object. Installs the corresponding
1067
To use a shape, you have to issue the command shape(shapename).
1069
call: register_shape("turtle.gif")
1070
--or: register_shape("tri", ((0,0), (10,10), (-10,10)))
1072
Example (for a TurtleScreen instance named screen):
1073
>>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
1078
if name.lower().endswith(".gif"):
1079
shape = Shape("image", self._image(name))
1081
raise TurtleGraphicsError("Bad arguments for register_shape.\n"
1082
+ "Use help(register_shape)" )
1083
elif isinstance(shape, tuple):
1084
shape = Shape("polygon", shape)
1085
## else shape assumed to be Shape-instance
1086
self._shapes[name] = shape
1087
# print "shape added:" , self._shapes
1089
def _colorstr(self, color):
1090
"""Return color string corresponding to args.
1092
Argument may be a string or a tuple of three
1093
numbers corresponding to actual colormode,
1094
i.e. in the range 0<=n<=colormode.
1096
If the argument doesn't represent a color,
1101
if isinstance(color, str):
1102
if self._iscolorstring(color) or color == "":
1105
raise TurtleGraphicsError("bad color string: %s" % str(color))
1109
raise TurtleGraphicsError("bad color arguments: %s" % str(color))
1110
if self._colormode == 1.0:
1111
r, g, b = [round(255.0*x) for x in (r, g, b)]
1112
if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
1113
raise TurtleGraphicsError("bad color sequence: %s" % str(color))
1114
return "#%02x%02x%02x" % (r, g, b)
1116
def _color(self, cstr):
1117
if not cstr.startswith("#"):
1120
cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
1121
elif len(cstr) == 4:
1122
cl = [16*int(cstr[h], 16) for h in cstr[1:]]
1124
raise TurtleGraphicsError("bad colorstring: %s" % cstr)
1125
return tuple([c * self._colormode/255 for c in cl])
1127
def colormode(self, cmode=None):
1128
"""Return the colormode or set it to 1.0 or 255.
1131
cmode -- one of the values 1.0 or 255
1133
r, g, b values of colortriples have to be in range 0..cmode.
1135
Example (for a TurtleScreen instance named screen):
1136
>>> screen.colormode()
1138
>>> screen.colormode(255)
1139
>>> turtle.pencolor(240,160,80)
1142
return self._colormode
1144
self._colormode = float(cmode)
1146
self._colormode = int(cmode)
1149
"""Reset all Turtles on the Screen to their initial state.
1153
Example (for a TurtleScreen instance named screen):
1156
for turtle in self._turtles:
1157
turtle._setmode(self._mode)
1161
"""Return the list of turtles on the screen.
1163
Example (for a TurtleScreen instance named screen):
1164
>>> screen.turtles()
1165
[<turtle.Turtle object at 0x00E11FB0>]
1167
return self._turtles
1169
def bgcolor(self, *args):
1170
"""Set or return backgroundcolor of the TurtleScreen.
1172
Arguments (if given): a color string or three numbers
1173
in the range 0..colormode or a 3-tuple of such numbers.
1175
Example (for a TurtleScreen instance named screen):
1176
>>> screen.bgcolor("orange")
1177
>>> screen.bgcolor()
1179
>>> screen.bgcolor(0.5,0,0.5)
1180
>>> screen.bgcolor()
1184
color = self._colorstr(args)
1187
color = self._bgcolor(color)
1188
if color is not None:
1189
color = self._color(color)
1192
def tracer(self, n=None, delay=None):
1193
"""Turns turtle animation on/off and set delay for update drawings.
1196
n -- nonnegative integer
1197
delay -- nonnegative integer
1199
If n is given, only each n-th regular screen update is really performed.
1200
(Can be used to accelerate the drawing of complex graphics.)
1201
Second arguments sets delay value (see RawTurtle.delay())
1203
Example (for a TurtleScreen instance named screen):
1204
>>> screen.tracer(8, 25)
1206
>>> for i in range(200):
1212
return self._tracing
1213
self._tracing = int(n)
1214
self._updatecounter = 0
1215
if delay is not None:
1216
self._delayvalue = int(delay)
1220
def delay(self, delay=None):
1221
""" Return or set the drawing delay in milliseconds.
1224
delay -- positive integer
1226
Example (for a TurtleScreen instance named screen):
1227
>>> screen.delay(15)
1232
return self._delayvalue
1233
self._delayvalue = int(delay)
1235
def _incrementudc(self):
1236
"Increment upadate counter."""
1237
if not TurtleScreen._RUNNING:
1238
TurtleScreen._RUNNNING = True
1240
if self._tracing > 0:
1241
self._updatecounter += 1
1242
self._updatecounter %= self._tracing
1245
"""Perform a TurtleScreen update.
1247
for t in self.turtles():
1252
def window_width(self):
1253
""" Return the width of the turtle window.
1255
Example (for a TurtleScreen instance named screen):
1256
>>> screen.window_width()
1259
return self._window_size()[0]
1261
def window_height(self):
1262
""" Return the height of the turtle window.
1264
Example (for a TurtleScreen instance named screen):
1265
>>> screen.window_height()
1268
return self._window_size()[1]
1270
def getcanvas(self):
1271
"""Return the Canvas of this TurtleScreen.
1275
Example (for a Screen instance named screen):
1276
>>> cv = screen.getcanvas()
1278
<turtle.ScrolledCanvas instance at 0x010742D8>
1282
def getshapes(self):
1283
"""Return a list of names of all currently available turtle shapes.
1287
Example (for a TurtleScreen instance named screen):
1288
>>> screen.getshapes()
1289
['arrow', 'blank', 'circle', ... , 'turtle']
1291
return sorted(self._shapes.keys())
1293
def onclick(self, fun, btn=1, add=None):
1294
"""Bind fun to mouse-click event on canvas.
1297
fun -- a function with two arguments, the coordinates of the
1298
clicked point on the canvas.
1299
num -- the number of the mouse-button, defaults to 1
1301
Example (for a TurtleScreen instance named screen
1302
and a Turtle instance named turtle):
1304
>>> screen.onclick(turtle.goto)
1306
### Subsequently clicking into the TurtleScreen will
1307
### make the turtle move to the clicked point.
1308
>>> screen.onclick(None)
1310
### event-binding will be removed
1312
self._onscreenclick(fun, btn, add)
1314
def onkey(self, fun, key):
1315
"""Bind fun to key-release event of key.
1318
fun -- a function with no arguments
1319
key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1321
In order ro be able to register key-events, TurtleScreen
1322
must have focus. (See method listen.)
1324
Example (for a TurtleScreen instance named screen
1325
and a Turtle instance named turtle):
1332
>>> screen.onkey(f, "Up")
1335
### Subsequently the turtle can be moved by
1336
### repeatedly pressing the up-arrow key,
1337
### consequently drawing a hexagon
1340
self._keys.remove(key)
1341
elif key not in self._keys:
1342
self._keys.append(key)
1343
self._onkey(fun, key)
1345
def listen(self, xdummy=None, ydummy=None):
1346
"""Set focus on TurtleScreen (in order to collect key-events)
1349
Dummy arguments are provided in order
1350
to be able to pass listen to the onclick method.
1352
Example (for a TurtleScreen instance named screen):
1357
def ontimer(self, fun, t=0):
1358
"""Install a timer, which calls fun after t milliseconds.
1361
fun -- a function with no arguments.
1364
Example (for a TurtleScreen instance named screen):
1371
screen.ontimer(f, 250)
1373
>>> f() ### makes the turtle marching around
1376
self._ontimer(fun, t)
1378
def bgpic(self, picname=None):
1379
"""Set background image or return name of current backgroundimage.
1382
picname -- a string, name of a gif-file or "nopic".
1384
If picname is a filename, set the corresponing image as background.
1385
If picname is "nopic", delete backgroundimage, if present.
1386
If picname is None, return the filename of the current backgroundimage.
1388
Example (for a TurtleScreen instance named screen):
1391
>>> screen.bgpic("landscape.gif")
1396
return self._bgpicname
1397
if picname not in self._bgpics:
1398
self._bgpics[picname] = self._image(picname)
1399
self._setbgpic(self._bgpic, self._bgpics[picname])
1400
self._bgpicname = picname
1402
def screensize(self, canvwidth=None, canvheight=None, bg=None):
1403
"""Resize the canvas, the turtles are drawing on.
1406
canvwidth -- positive integer, new width of canvas in pixels
1407
canvheight -- positive integer, new height of canvas in pixels
1408
bg -- colorstring or color-tupel, new backgroundcolor
1409
If no arguments are given, return current (canvaswidth, canvasheight)
1411
Do not alter the drawing window. To observe hidden parts of
1412
the canvas use the scrollbars. (Can make visible those parts
1413
of a drawing, which were outside the canvas before!)
1415
Example (for a Turtle instance named turtle):
1416
>>> turtle.screensize(2000,1500)
1417
### e. g. to search for an erroneously escaped turtle ;-)
1419
return self._resize(canvwidth, canvheight, bg)
1421
onscreenclick = onclick
1424
addshape = register_shape
1426
class TNavigator(object):
1427
"""Navigation part of the RawTurtle.
1428
Implements methods for turtle movement.
1430
START_ORIENTATION = {
1431
"standard": Vec2D(1.0, 0.0),
1432
"world" : Vec2D(1.0, 0.0),
1433
"logo" : Vec2D(0.0, 1.0) }
1434
DEFAULT_MODE = "standard"
1435
DEFAULT_ANGLEOFFSET = 0
1436
DEFAULT_ANGLEORIENT = 1
1438
def __init__(self, mode=DEFAULT_MODE):
1439
self._angleOffset = self.DEFAULT_ANGLEOFFSET
1440
self._angleOrient = self.DEFAULT_ANGLEORIENT
1442
self.undobuffer = None
1446
TNavigator.reset(self)
1449
"""reset turtle to its initial values
1451
Will be overwritten by parent class
1453
self._position = Vec2D(0.0, 0.0)
1454
self._orient = TNavigator.START_ORIENTATION[self._mode]
1456
def _setmode(self, mode=None):
1457
"""Set turtle-mode to 'standard', 'world' or 'logo'.
1461
if mode not in ["standard", "logo", "world"]:
1464
if mode in ["standard", "world"]:
1465
self._angleOffset = 0
1466
self._angleOrient = 1
1467
else: # mode == "logo":
1468
self._angleOffset = self._fullcircle/4.
1469
self._angleOrient = -1
1471
def _setDegreesPerAU(self, fullcircle):
1472
"""Helper function for degrees() and radians()"""
1473
self._fullcircle = fullcircle
1474
self._degreesPerAU = 360/fullcircle
1475
if self._mode == "standard":
1476
self._angleOffset = 0
1478
self._angleOffset = fullcircle/4.
38
1480
def degrees(self, fullcircle=360.0):
39
1481
""" Set angle measurement units to degrees.
1484
fullcircle - a number
1486
Set angle measurement units, i. e. set number
1487
of 'degrees' for a full circle. Dafault value is
1490
Example (for a Turtle instance named turtle):
1492
>>> turtle.heading()
1494
>>> turtle.degrees(400.0) # angle measurement in gon
1495
>>> turtle.heading()
44
# Don't try to change _angle if it is 0, because
45
# _fullcircle might not be set, yet
47
self._angle = (self._angle / self._fullcircle) * fullcircle
48
self._fullcircle = fullcircle
49
self._invradian = pi / (fullcircle * 0.5)
1499
self._setDegreesPerAU(fullcircle)
51
1501
def radians(self):
52
1502
""" Set the angle measurement units to radians.
1506
Example (for a Turtle instance named turtle):
1507
>>> turtle.heading()
55
1509
>>> turtle.radians()
60
""" Clear the screen, re-center the pen, and set variables to
76
width = canvas.winfo_width()
77
height = canvas.winfo_height()
79
width = canvas['width']
81
height = canvas['height']
82
self._origin = float(width)/2.0, float(height)/2.0
83
self._position = self._origin
91
canvas._root().tkraise()
94
""" Clear the screen. The turtle does not move.
100
canvas = self._canvas
105
self._delete_turtle()
108
def tracer(self, flag):
109
""" Set tracing on if flag is True, and off if it is False.
110
Tracing means line are drawn more slowly, with an
111
animation of an arrow along the line.
114
>>> turtle.tracer(False) # turns off Tracer
117
if not self._tracing:
118
self._delete_turtle()
1510
>>> turtle.heading()
1513
self._setDegreesPerAU(2*math.pi)
1515
def _go(self, distance):
1516
"""move turtle forward by specified distance"""
1517
ende = self._position + self._orient * distance
1520
def _rotate(self, angle):
1521
"""Turn turtle counterclockwise by specified angle if angle > 0."""
1522
angle *= self._degreesPerAU
1523
self._orient = self._orient.rotate(angle)
1525
def _goto(self, end):
1526
"""move turtle to position end."""
1527
self._position = end
121
1529
def forward(self, distance):
122
""" Go forward distance steps.
1530
"""Move the turtle forward by the specified distance.
1532
Aliases: forward | fd
1535
distance -- a number (integer or float)
1537
Move the turtle forward by the specified distance, in the direction
1538
the turtle is headed.
1540
Example (for a Turtle instance named turtle):
125
1541
>>> turtle.position()
127
1543
>>> turtle.forward(25)
128
1544
>>> turtle.position()
130
1546
>>> turtle.forward(-75)
131
1547
>>> turtle.position()
134
x0, y0 = start = self._position
135
x1 = x0 + distance * cos(self._angle*self._invradian)
136
y1 = y0 - distance * sin(self._angle*self._invradian)
139
def backward(self, distance):
140
""" Go backwards distance steps.
142
The turtle's heading does not change.
1552
def back(self, distance):
1553
"""Move the turtle backward by distance.
1555
Aliases: back | backward | bk
1558
distance -- a number
1560
Move the turtle backward by distance ,opposite to the direction the
1561
turtle is headed. Do not change the turtle's heading.
1563
Example (for a Turtle instance named turtle):
145
1564
>>> turtle.position()
147
1566
>>> turtle.backward(30)
148
1567
>>> turtle.position()
151
self.forward(-distance)
153
def left(self, angle):
154
""" Turn left angle units (units are by default degrees,
155
but can be set via the degrees() and radians() functions.)
157
When viewed from above, the turning happens in-place around
167
self._angle = (self._angle + angle) % self._fullcircle
170
1572
def right(self, angle):
171
""" Turn right angle units (units are by default degrees,
1573
"""Turn turtle right by angle units.
1578
angle -- a number (integer or float)
1580
Turn turtle right by angle units. (Units are by default degrees,
172
1581
but can be set via the degrees() and radians() functions.)
174
When viewed from above, the turning happens in-place around
1582
Angle orientation depends on mode. (See this.)
1584
Example (for a Turtle instance named turtle):
178
1585
>>> turtle.heading()
180
1587
>>> turtle.right(45)
181
1588
>>> turtle.heading()
187
""" Pull the pen up -- no drawing when moving.
195
""" Put the pen down -- draw when moving.
202
def width(self, width):
203
""" Set the line to thickness to width.
208
self._width = float(width)
210
def color(self, *args):
211
""" Set the pen color.
213
Three input formats are allowed:
216
s is a Tk specification string, such as "red" or "yellow"
219
*a tuple* of r, g, and b, which represent, an RGB color,
220
and each of r, g, and b are in the range [0..1]
223
r, g, and b represent an RGB color, and each of r, g, and b
224
are in the range [0..1]
228
>>> turtle.color('brown')
229
>>> tup = (0.2, 0.8, 0.55)
230
>>> turtle.color(tup)
231
>>> turtle.color(0, .5, 0)
234
raise Error, "no color arguments"
237
if type(color) == type(""):
238
# Test the color first
240
id = self._canvas.create_line(0, 0, 0, 0, fill=color)
241
except Tkinter.TclError:
242
raise Error, "bad color string: %r" % (color,)
243
self._set_color(color)
248
raise Error, "bad color sequence: %r" % (color,)
1591
self._rotate(-angle)
1593
def left(self, angle):
1594
"""Turn turtle left by angle units.
1599
angle -- a number (integer or float)
1601
Turn turtle left by angle units. (Units are by default degrees,
1602
but can be set via the degrees() and radians() functions.)
1603
Angle orientation depends on mode. (See this.)
1605
Example (for a Turtle instance named turtle):
1606
>>> turtle.heading()
1609
>>> turtle.heading()
1615
"""Return the turtle's current location (x,y), as a Vec2D-vector.
1617
Aliases: pos | position
1621
Example (for a Turtle instance named turtle):
1625
return self._position
1628
""" Return the turtle's x coordinate.
1632
Example (for a Turtle instance named turtle):
1635
>>> turtle.forward(100)
1636
>>> print turtle.xcor()
1639
return self._position[0]
1642
""" Return the turtle's y coordinate
1646
Example (for a Turtle instance named turtle):
1649
>>> turtle.forward(100)
1650
>>> print turtle.ycor()
1653
return self._position[1]
1656
def goto(self, x, y=None):
1657
"""Move turtle to an absolute position.
1659
Aliases: setpos | setposition | goto:
1662
x -- a number or a pair/vector of numbers
1665
call: goto(x, y) # two coordinates
1666
--or: goto((x, y)) # a pair (tuple) of coordinates
1667
--or: goto(vec) # e.g. as returned by pos()
1669
Move turtle to an absolute position. If the pen is down,
1670
a line will be drawn. The turtle's orientation does not change.
1672
Example (for a Turtle instance named turtle):
1673
>>> tp = turtle.pos()
1676
>>> turtle.setpos(60,30)
1679
>>> turtle.setpos((20,80))
1682
>>> turtle.setpos(tp)
1687
self._goto(Vec2D(*x))
253
raise Error, "bad color arguments: %r" % (args,)
259
self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
261
def _set_color(self,color):
265
def write(self, text, move=False):
266
""" Write text at the current pen position.
268
If move is true, the pen is moved to the bottom-right corner
269
of the text. By default, move is False.
272
>>> turtle.write('The race is on!')
273
>>> turtle.write('Home = (0, 0)', True)
275
x, y = self._position
276
x = x-1 # correction -- calibrated for Windows
277
item = self._canvas.create_text(x, y,
278
text=str(text), anchor="sw",
280
self._items.append(item)
282
x0, y0, x1, y1 = self._canvas.bbox(item)
286
def fill(self, flag):
287
""" Call fill(1) before drawing the shape you
288
want to fill, and fill(0) when done.
292
>>> turtle.forward(100)
294
>>> turtle.forward(100)
296
>>> turtle.forward(100)
298
>>> turtle.forward(100)
302
path = tuple(self._path)
303
smooth = self._filling < 0
305
item = self._canvas._create('polygon', path,
306
{'fill': self._color,
308
self._items.append(item)
312
self._path.append(self._position)
314
def begin_fill(self):
315
""" Called just before drawing a shape to be filled.
316
Must eventually be followed by a corresponding end_fill() call.
317
Otherwise it will be ignored.
320
>>> turtle.begin_fill()
321
>>> turtle.forward(100)
323
>>> turtle.forward(100)
325
>>> turtle.forward(100)
327
>>> turtle.forward(100)
328
>>> turtle.end_fill()
330
self._path = [self._position]
334
""" Called after drawing a shape to be filled.
337
>>> turtle.begin_fill()
338
>>> turtle.forward(100)
340
>>> turtle.forward(100)
342
>>> turtle.forward(100)
344
>>> turtle.forward(100)
345
>>> turtle.end_fill()
349
def circle(self, radius, extent = None):
1689
self._goto(Vec2D(x, y))
1692
"""Move turtle to the origin - coordinates (0,0).
1696
Move turtle to the origin - coordinates (0,0) and set it's
1697
heading to it's start-orientation (which depends on mode).
1699
Example (for a Turtle instance named turtle):
1706
"""Set the turtle's first coordinate to x
1709
x -- a number (integer or float)
1711
Set the turtle's first coordinate to x, leave second coordinate
1714
Example (for a Turtle instance named turtle):
1715
>>> turtle.position()
1718
>>> turtle.position()
1721
self._goto(Vec2D(x, self._position[1]))
1724
"""Set the turtle's second coordinate to y
1727
y -- a number (integer or float)
1729
Set the turtle's first coordinate to x, second coordinate remains
1732
Example (for a Turtle instance named turtle):
1733
>>> turtle.position()
1735
>>> turtle.sety(-10)
1736
>>> turtle.position()
1739
self._goto(Vec2D(self._position[0], y))
1741
def distance(self, x, y=None):
1742
"""Return the distance from the turtle to (x,y) in turtle step units.
1745
x -- a number or a pair/vector of numbers or a turtle instance
1746
y -- a number None None
1748
call: distance(x, y) # two coordinates
1749
--or: distance((x, y)) # a pair (tuple) of coordinates
1750
--or: distance(vec) # e.g. as returned by pos()
1751
--or: distance(mypen) # where mypen is another turtle
1753
Example (for a Turtle instance named turtle):
1756
>>> turtle.distance(30,40)
1760
>>> turtle.distance(pen)
1765
if isinstance(x, Vec2D):
1767
elif isinstance(x, tuple):
1769
elif isinstance(x, TNavigator):
1771
return abs(pos - self._position)
1773
def towards(self, x, y=None):
1774
"""Return the angle of the line from the turtle's position to (x, y).
1777
x -- a number or a pair/vector of numbers or a turtle instance
1778
y -- a number None None
1780
call: distance(x, y) # two coordinates
1781
--or: distance((x, y)) # a pair (tuple) of coordinates
1782
--or: distance(vec) # e.g. as returned by pos()
1783
--or: distance(mypen) # where mypen is another turtle
1785
Return the angle, between the line from turtle-position to position
1786
specified by x, y and the turtle's start orientation. (Depends on
1787
modes - "standard" or "logo")
1789
Example (for a Turtle instance named turtle):
1792
>>> turtle.towards(0,0)
1797
if isinstance(x, Vec2D):
1799
elif isinstance(x, tuple):
1801
elif isinstance(x, TNavigator):
1803
x, y = pos - self._position
1804
result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1805
result /= self._degreesPerAU
1806
return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1809
""" Return the turtle's current heading.
1813
Example (for a Turtle instance named turtle):
1815
>>> turtle.heading()
1819
result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1820
result /= self._degreesPerAU
1821
return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1823
def setheading(self, to_angle):
1824
"""Set the orientation of the turtle to to_angle.
1826
Aliases: setheading | seth
1829
to_angle -- a number (integer or float)
1831
Set the orientation of the turtle to to_angle.
1832
Here are some common directions in degrees:
1834
standard - mode: logo-mode:
1835
-------------------|--------------------
1837
90 - north 90 - east
1838
180 - west 180 - south
1839
270 - south 270 - west
1841
Example (for a Turtle instance named turtle):
1842
>>> turtle.setheading(90)
1843
>>> turtle.heading()
1846
angle = (to_angle - self.heading())*self._angleOrient
1847
full = self._fullcircle
1848
angle = (angle+full/2.)%full - full/2.
1851
def circle(self, radius, extent = None, steps = None):
350
1852
""" Draw a circle with given radius.
351
The center is radius units left of the turtle; extent
352
determines which part of the circle is drawn. If not given,
353
the entire circle is drawn.
1856
extent (optional) -- a number
1857
steps (optional) -- an integer
1859
Draw a circle with given radius. The center is radius units left
1860
of the turtle; extent - an angle - determines which part of the
1861
circle is drawn. If extent is not given, draw the entire circle.
355
1862
If extent is not a full circle, one endpoint of the arc is the
356
current pen position. The arc is drawn in a counter clockwise
357
direction if radius is positive, otherwise in a clockwise
358
direction. In the process, the direction of the turtle is
359
changed by the amount of the extent.
1863
current pen position. Draw the arc in counterclockwise direction
1864
if radius is positive, otherwise in clockwise direction. Finally
1865
the direction of the turtle is changed by the amount of extent.
1867
As the circle is approximated by an inscribed regular polygon,
1868
steps determines the number of steps to use. If not given,
1869
it will be calculated automatically. Maybe used to draw regular
1872
call: circle(radius) # full circle
1873
--or: circle(radius, extent) # arc
1874
--or: circle(radius, extent, steps)
1875
--or: circle(radius, steps=6) # 6-sided polygon
1877
Example (for a Turtle instance named turtle):
361
1878
>>> turtle.circle(50)
362
>>> turtle.circle(120, 180) # half a circle
1879
>>> turtle.circle(120, 180) # semicircle
1882
self.undobuffer.push(["seq"])
1883
self.undobuffer.cumulate = True
1884
speed = self.speed()
364
1885
if extent is None:
365
1886
extent = self._fullcircle
366
frac = abs(extent)/self._fullcircle
367
steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
1888
frac = abs(extent)/self._fullcircle
1889
steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
368
1890
w = 1.0 * extent / steps
370
l = 2.0 * radius * sin(w2*self._invradian)
1892
l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
372
1894
l, w, w2 = -l, -w, -w2
374
1902
for i in range(steps):
380
""" Return the turtle's current heading.
388
def setheading(self, angle):
389
""" Set the turtle facing the given angle.
391
Here are some common directions in degrees:
399
>>> turtle.setheading(90)
402
>>> turtle.setheading(128)
1912
self.undobuffer.cumulate = False
1914
## three dummy methods to be implemented by child class:
1916
def speed(self, s=0):
1917
"""dummy method - to be overwritten by child class"""
1918
def tracer(self, a=None, b=None):
1919
"""dummy method - to be overwritten by child class"""
1920
def _delay(self, n=None):
1921
"""dummy method - to be overwritten by child class"""
1935
"""Drawing part of the RawTurtle.
1936
Implements drawing properties.
1938
def __init__(self, resizemode=_CFG["resizemode"]):
1939
self._resizemode = resizemode # or "user" or "noresize"
1940
self.undobuffer = None
1943
def _reset(self, pencolor=_CFG["pencolor"],
1944
fillcolor=_CFG["fillcolor"]):
1947
self._pencolor = pencolor
1948
self._fillcolor = fillcolor
1949
self._drawing = True
1951
self._stretchfactor = (1, 1)
1953
self._outlinewidth = 1
1954
### self.screen = None # to override by child class
1956
def resizemode(self, rmode=None):
1957
"""Set resizemode to one of the values: "auto", "user", "noresize".
1959
(Optional) Argument:
1960
rmode -- one of the strings "auto", "user", "noresize"
1962
Different resizemodes have the following effects:
1963
- "auto" adapts the appearance of the turtle
1964
corresponding to the value of pensize.
1965
- "user" adapts the appearance of the turtle according to the
1966
values of stretchfactor and outlinewidth (outline),
1967
which are set by shapesize()
1968
- "noresize" no adaption of the turtle's appearance takes place.
1969
If no argument is given, return current resizemode.
1970
resizemode("user") is called by a call of shapesize with arguments.
1973
Examples (for a Turtle instance named turtle):
1974
>>> turtle.resizemode("noresize")
1975
>>> turtle.resizemode()
1979
return self._resizemode
1980
rmode = rmode.lower()
1981
if rmode in ["auto", "user", "noresize"]:
1982
self.pen(resizemode=rmode)
1984
def pensize(self, width=None):
1985
"""Set or return the line thickness.
1987
Aliases: pensize | width
1990
width -- positive number
1992
Set the line thickness to width or return it. If resizemode is set
1993
to "auto" and turtleshape is a polygon, that polygon is drawn with
1994
the same line thickness. If no argument is given, current pensize
1997
Example (for a Turtle instance named turtle):
1998
>>> turtle.pensize()
2000
turtle.pensize(10) # from here on lines of width 10 are drawn
2003
return self._pensize
2004
self.pen(pensize=width)
2008
"""Pull the pen up -- no drawing when moving.
2010
Aliases: penup | pu | up
2014
Example (for a Turtle instance named turtle):
2017
if not self._drawing:
2019
self.pen(pendown=False)
2022
"""Pull the pen down -- drawing when moving.
2024
Aliases: pendown | pd | down
2028
Example (for a Turtle instance named turtle):
2029
>>> turtle.pendown()
2033
self.pen(pendown=True)
2036
"""Return True if pen is down, False if it's up.
2040
Example (for a Turtle instance named turtle):
2044
>>> turtle.pendown()
2048
return self._drawing
2050
def speed(self, speed=None):
2051
""" Return or set the turtle's speed.
2054
speed -- an integer in the range 0..10 or a speedstring (see below)
2056
Set the turtle's speed to an integer value in the range 0 .. 10.
2057
If no argument is given: return current speed.
2059
If input is a number greater than 10 or smaller than 0.5,
2061
Speedstrings are mapped to speedvalues in the following way:
2067
speeds from 1 to 10 enforce increasingly faster animation of
2068
line drawing and turtle turning.
2071
speed = 0 : *no* animation takes place. forward/back makes turtle jump
2072
and likewise left/right make the turtle turn instantly.
2074
Example (for a Turtle instance named turtle):
2077
speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
2081
speed = speeds[speed]
2082
elif 0.5 < speed < 10.5:
2083
speed = int(round(speed))
2086
self.pen(speed=speed)
2088
def color(self, *args):
2089
"""Return or set the pencolor and fillcolor.
2092
Several input formats are allowed.
2093
They use 0, 1, 2, or 3 arguments as follows:
2096
Return the current pencolor and the current fillcolor
2097
as a pair of color specification strings as are returned
2098
by pencolor and fillcolor.
2099
color(colorstring), color((r,g,b)), color(r,g,b)
2100
inputs as in pencolor, set both, fillcolor and pencolor,
2102
color(colorstring1, colorstring2),
2103
color((r1,g1,b1), (r2,g2,b2))
2104
equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
2105
and analogously, if the other input format is used.
2107
If turtleshape is a polygon, outline and interior of that polygon
2108
is drawn with the newly set colors.
2109
For mor info see: pencolor, fillcolor
2111
Example (for a Turtle instance named turtle):
2112
>>> turtle.color('red', 'green')
2116
>>> color((40, 80, 120), (160, 200, 240))
2118
('#285078', '#a0c8f0')
2123
pcolor = fcolor = args[0]
2125
pcolor, fcolor = args
2127
pcolor = fcolor = args
2128
pcolor = self._colorstr(pcolor)
2129
fcolor = self._colorstr(fcolor)
2130
self.pen(pencolor=pcolor, fillcolor=fcolor)
2132
return self._color(self._pencolor), self._color(self._fillcolor)
2134
def pencolor(self, *args):
2135
""" Return or set the pencolor.
2138
Four input formats are allowed:
2140
Return the current pencolor as color specification string,
2141
possibly in hex-number format (see example).
2142
May be used as input to another color/pencolor/fillcolor call.
2143
- pencolor(colorstring)
2144
s is a Tk color specification string, such as "red" or "yellow"
2145
- pencolor((r, g, b))
2146
*a tuple* of r, g, and b, which represent, an RGB color,
2147
and each of r, g, and b are in the range 0..colormode,
2148
where colormode is either 1.0 or 255
2150
r, g, and b represent an RGB color, and each of r, g, and b
2151
are in the range 0..colormode
2153
If turtleshape is a polygon, the outline of that polygon is drawn
2154
with the newly set pencolor.
2156
Example (for a Turtle instance named turtle):
2157
>>> turtle.pencolor('brown')
2158
>>> tup = (0.2, 0.8, 0.55)
2159
>>> turtle.pencolor(tup)
2160
>>> turtle.pencolor()
2164
color = self._colorstr(args)
2165
if color == self._pencolor:
2167
self.pen(pencolor=color)
2169
return self._color(self._pencolor)
2171
def fillcolor(self, *args):
2172
""" Return or set the fillcolor.
2175
Four input formats are allowed:
2177
Return the current fillcolor as color specification string,
2178
possibly in hex-number format (see example).
2179
May be used as input to another color/pencolor/fillcolor call.
2180
- fillcolor(colorstring)
2181
s is a Tk color specification string, such as "red" or "yellow"
2182
- fillcolor((r, g, b))
2183
*a tuple* of r, g, and b, which represent, an RGB color,
2184
and each of r, g, and b are in the range 0..colormode,
2185
where colormode is either 1.0 or 255
2186
- fillcolor(r, g, b)
2187
r, g, and b represent an RGB color, and each of r, g, and b
2188
are in the range 0..colormode
2190
If turtleshape is a polygon, the interior of that polygon is drawn
2191
with the newly set fillcolor.
2193
Example (for a Turtle instance named turtle):
2194
>>> turtle.fillcolor('violet')
2195
>>> col = turtle.pencolor()
2196
>>> turtle.fillcolor(col)
2197
>>> turtle.fillcolor(0, .5, 0)
2200
color = self._colorstr(args)
2201
if color == self._fillcolor:
2203
self.pen(fillcolor=color)
2205
return self._color(self._fillcolor)
2207
def showturtle(self):
2208
"""Makes the turtle visible.
2210
Aliases: showturtle | st
2214
Example (for a Turtle instance named turtle):
2215
>>> turtle.hideturtle()
2216
>>> turtle.showturtle()
2218
self.pen(shown=True)
2220
def hideturtle(self):
2221
"""Makes the turtle invisible.
2223
Aliases: hideturtle | ht
2227
It's a good idea to do this while you're in the
2228
middle of a complicated drawing, because hiding
2229
the turtle speeds up the drawing observably.
2231
Example (for a Turtle instance named turtle):
2232
>>> turtle.hideturtle()
2234
self.pen(shown=False)
2236
def isvisible(self):
2237
"""Return True if the Turtle is shown, False if it's hidden.
2241
Example (for a Turtle instance named turtle):
2242
>>> turtle.hideturtle()
2243
>>> print turtle.isvisible():
2248
def pen(self, pen=None, **pendict):
2249
"""Return or set the pen's attributes.
2252
pen -- a dictionary with some or all of the below listed keys.
2253
**pendict -- one or more keyword-arguments with the below
2254
listed keys as keywords.
2256
Return or set the pen's attributes in a 'pen-dictionary'
2257
with the following key/value pairs:
2258
"shown" : True/False
2259
"pendown" : True/False
2260
"pencolor" : color-string or color-tuple
2261
"fillcolor" : color-string or color-tuple
2262
"pensize" : positive number
2263
"speed" : number in range 0..10
2264
"resizemode" : "auto" or "user" or "noresize"
2265
"stretchfactor": (positive number, positive number)
2266
"outline" : positive number
2269
This dicionary can be used as argument for a subsequent
2270
pen()-call to restore the former pen-state. Moreover one
2271
or more of these attributes can be provided as keyword-arguments.
2272
This can be used to set several pen attributes in one statement.
2275
Examples (for a Turtle instance named turtle):
2276
>>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
2278
{'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2279
'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
2280
'stretchfactor': (1,1), 'speed': 3}
2281
>>> penstate=turtle.pen()
2282
>>> turtle.color("yellow","")
2285
{'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2286
'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
2287
'stretchfactor': (1,1), 'speed': 3}
2288
>>> p.pen(penstate, fillcolor="green")
2290
{'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2291
'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
2292
'stretchfactor': (1,1), 'speed': 3}
2294
_pd = {"shown" : self._shown,
2295
"pendown" : self._drawing,
2296
"pencolor" : self._pencolor,
2297
"fillcolor" : self._fillcolor,
2298
"pensize" : self._pensize,
2299
"speed" : self._speed,
2300
"resizemode" : self._resizemode,
2301
"stretchfactor" : self._stretchfactor,
2302
"outline" : self._outlinewidth,
2306
if not (pen or pendict):
2309
if isinstance(pen, dict):
2317
_p_buf[key] = _pd[key]
2320
self.undobuffer.push(("pen", _p_buf))
2324
if self._drawing != p["pendown"]:
2327
if isinstance(p["pencolor"], tuple):
2328
p["pencolor"] = self._colorstr((p["pencolor"],))
2329
if self._pencolor != p["pencolor"]:
2332
if self._pensize != p["pensize"]:
2337
self._drawing = p["pendown"]
2339
self._pencolor = p["pencolor"]
2341
self._pensize = p["pensize"]
2342
if "fillcolor" in p:
2343
if isinstance(p["fillcolor"], tuple):
2344
p["fillcolor"] = self._colorstr((p["fillcolor"],))
2345
self._fillcolor = p["fillcolor"]
2347
self._speed = p["speed"]
2348
if "resizemode" in p:
2349
self._resizemode = p["resizemode"]
2350
if "stretchfactor" in p:
2351
sf = p["stretchfactor"]
2352
if isinstance(sf, (int, float)):
2354
self._stretchfactor = sf
2356
self._outlinewidth = p["outline"]
2358
self._shown = p["shown"]
2360
self._tilt = p["tilt"]
2363
## three dummy methods to be implemented by child class:
2365
def _newLine(self, usePos = True):
2366
"""dummy method - to be overwritten by child class"""
2367
def _update(self, count=True, forced=False):
2368
"""dummy method - to be overwritten by child class"""
2369
def _color(self, args):
2370
"""dummy method - to be overwritten by child class"""
2371
def _colorstr(self, args):
2372
"""dummy method - to be overwritten by child class"""
2383
class _TurtleImage(object):
2384
"""Helper class: Datatype to store Turtle attributes
2387
def __init__(self, screen, shapeIndex):
2388
self.screen = screen
2390
self._setshape(shapeIndex)
2392
def _setshape(self, shapeIndex):
2393
screen = self.screen # RawTurtle.screens[self.screenIndex]
2394
self.shapeIndex = shapeIndex
2395
if self._type == "polygon" == screen._shapes[shapeIndex]._type:
2397
if self._type == "image" == screen._shapes[shapeIndex]._type:
2399
if self._type in ["image", "polygon"]:
2400
screen._delete(self._item)
2401
elif self._type == "compound":
2402
for item in self._item:
2403
screen._delete(item)
2404
self._type = screen._shapes[shapeIndex]._type
2405
if self._type == "polygon":
2406
self._item = screen._createpoly()
2407
elif self._type == "image":
2408
self._item = screen._createimage(screen._shapes["blank"]._data)
2409
elif self._type == "compound":
2410
self._item = [screen._createpoly() for item in
2411
screen._shapes[shapeIndex]._data]
2414
class RawTurtle(TPen, TNavigator):
2415
"""Animation part of the RawTurtle.
2416
Puts RawTurtle upon a TurtleScreen and provides tools for
2421
def __init__(self, canvas=None,
2422
shape=_CFG["shape"],
2423
undobuffersize=_CFG["undobuffersize"],
2424
visible=_CFG["visible"]):
2425
if isinstance(canvas, Screen):
2426
self.screen = canvas
2427
elif isinstance(canvas, TurtleScreen):
2428
if canvas not in RawTurtle.screens:
2429
RawTurtle.screens.append(canvas)
2430
self.screen = canvas
2431
elif isinstance(canvas, (ScrolledCanvas, Canvas)):
2432
for screen in RawTurtle.screens:
2433
if screen.cv == canvas:
2434
self.screen = screen
2437
self.screen = TurtleScreen(canvas)
2438
RawTurtle.screens.append(self.screen)
2440
raise TurtleGraphicsError("bad cavas argument %s" % canvas)
2442
screen = self.screen
2443
TNavigator.__init__(self, screen.mode())
2445
screen._turtles.append(self)
2446
self.drawingLineItem = screen._createline()
2447
self.turtle = _TurtleImage(screen, shape)
2449
self._creatingPoly = False
2450
self._fillitem = self._fillpath = None
2451
self._shown = visible
2452
self._hidden_from_screen = False
2453
self.currentLineItem = screen._createline()
2454
self.currentLine = [self._position]
2455
self.items = [self.currentLineItem]
2456
self.stampItems = []
2457
self._undobuffersize = undobuffersize
2458
self.undobuffer = Tbuffer(undobuffersize)
2462
"""Delete the turtle's drawings and restore it's default values.
2466
Delete the turtle's drawings from the screen, re-center the turtle
2467
and set variables to the default values.
2469
Example (for a Turtle instance named turtle):
2470
>>> turtle.position()
2472
>>> turtle.heading()
2475
>>> turtle.position()
2477
>>> turtle.heading()
2480
TNavigator.reset(self)
2486
def setundobuffer(self, size):
2487
"""Set or disable undobuffer.
2490
size -- an integer or None
2492
If size is an integer an empty undobuffer of given size is installed.
2493
Size gives the maximum number of turtle-actions that can be undone
2494
by the undo() function.
2495
If size is None, no undobuffer is present.
2497
Example (for a Turtle instance named turtle):
2498
>>> turtle.setundobuffer(42)
2501
self.undobuffer = None
2503
self.undobuffer = Tbuffer(size)
2505
def undobufferentries(self):
2506
"""Return count of entries in the undobuffer.
2510
Example (for a Turtle instance named turtle):
2511
>>> while undobufferentries():
2514
if self.undobuffer is None:
2516
return self.undobuffer.nr_of_items()
2519
"""Delete all of pen's drawings"""
2520
self._fillitem = self._fillpath = None
2521
for item in self.items:
2522
self.screen._delete(item)
2523
self.currentLineItem = self.screen._createline()
2524
self.currentLine = []
2526
self.currentLine.append(self._position)
2527
self.items = [self.currentLineItem]
2529
self.setundobuffer(self._undobuffersize)
2533
"""Delete the turtle's drawings from the screen. Do not move turtle.
2537
Delete the turtle's drawings from the screen. Do not move turtle.
2538
State and position of the turtle as well as drawings of other
2539
turtles are not affected.
2541
Examples (for a Turtle instance named turtle):
2547
def _update_data(self):
2548
self.screen._incrementudc()
2549
if self.screen._updatecounter != 0:
2551
if len(self.currentLine)>1:
2552
self.screen._drawline(self.currentLineItem, self.currentLine,
2553
self._pencolor, self._pensize)
2556
"""Perform a Turtle-data update.
2558
screen = self.screen
2559
if screen._tracing == 0:
2561
elif screen._tracing == 1:
2564
screen._update() # TurtleScreenBase
2565
screen._delay(screen._delayvalue) # TurtleScreenBase
2568
if screen._updatecounter == 0:
2569
for t in screen.turtles():
2573
def tracer(self, flag=None, delay=None):
2574
"""Turns turtle animation on/off and set delay for update drawings.
2577
n -- nonnegative integer
2578
delay -- nonnegative integer
2580
If n is given, only each n-th regular screen update is really performed.
2581
(Can be used to accelerate the drawing of complex graphics.)
2582
Second arguments sets delay value (see RawTurtle.delay())
2584
Example (for a Turtle instance named turtle):
2585
>>> turtle.tracer(8, 25)
2587
>>> for i in range(200):
2592
return self.screen.tracer(flag, delay)
2594
def _color(self, args):
2595
return self.screen._color(args)
2597
def _colorstr(self, args):
2598
return self.screen._colorstr(args)
2600
def _cc(self, args):
2601
"""Convert colortriples to hexstrings.
2603
if isinstance(args, str):
2608
raise TurtleGraphicsError("bad color arguments: %s" % str(args))
2609
if self.screen._colormode == 1.0:
2610
r, g, b = [round(255.0*x) for x in (r, g, b)]
2611
if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
2612
raise TurtleGraphicsError("bad color sequence: %s" % str(args))
2613
return "#%02x%02x%02x" % (r, g, b)
2616
"""Create and return a clone of the turtle.
2620
Create and return a clone of the turtle with same position, heading
2621
and turtle properties.
2623
Example (for a Turtle instance named mick):
2627
screen = self.screen
2628
self._newLine(self._drawing)
2630
turtle = self.turtle
2632
self.turtle = None # too make self deepcopy-able
2636
self.screen = screen
2637
self.turtle = turtle
2640
q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
2642
screen._turtles.append(q)
2643
ttype = screen._shapes[self.turtle.shapeIndex]._type
2644
if ttype == "polygon":
2645
q.turtle._item = screen._createpoly()
2646
elif ttype == "image":
2647
q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
2648
elif ttype == "compound":
2649
q.turtle._item = [screen._createpoly() for item in
2650
screen._shapes[self.turtle.shapeIndex]._data]
2651
q.currentLineItem = screen._createline()
2655
def shape(self, name=None):
2656
"""Set turtle shape to shape with given name / return current shapename.
2659
name -- a string, which is a valid shapename
2661
Set turtle shape to shape with given name or, if name is not given,
2662
return name of current shape.
2663
Shape with name must exist in the TurtleScreen's shape dictionary.
2664
Initially there are the following polygon shapes:
2665
'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
2666
To learn about how to deal with shapes see Screen-method register_shape.
2668
Example (for a Turtle instance named turtle):
2671
>>> turtle.shape("turtle")
2676
return self.turtle.shapeIndex
2677
if not name in self.screen.getshapes():
2678
raise TurtleGraphicsError("There is no shape named %s" % name)
2679
self.turtle._setshape(name)
2682
def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
2683
"""Set/return turtle's stretchfactors/outline. Set resizemode to "user".
2685
Optinonal arguments:
2686
stretch_wid : positive number
2687
stretch_len : positive number
2688
outline : positive number
2690
Return or set the pen's attributes x/y-stretchfactors and/or outline.
2691
Set resizemode to "user".
2692
If and only if resizemode is set to "user", the turtle will be displayed
2693
stretched according to its stretchfactors:
2694
stretch_wid is stretchfactor perpendicular to orientation
2695
stretch_len is stretchfactor in direction of turtles orientation.
2696
outline determines the width of the shapes's outline.
2698
Examples (for a Turtle instance named turtle):
2699
>>> turtle.resizemode("user")
2700
>>> turtle.shapesize(5, 5, 12)
2701
>>> turtle.shapesize(outline=8)
2703
if stretch_wid is None and stretch_len is None and outline == None:
2704
stretch_wid, stretch_len = self._stretchfactor
2705
return stretch_wid, stretch_len, self._outlinewidth
2706
if stretch_wid is not None:
2707
if stretch_len is None:
2708
stretchfactor = stretch_wid, stretch_wid
2710
stretchfactor = stretch_wid, stretch_len
2711
elif stretch_len is not None:
2712
stretchfactor = self._stretchfactor[0], stretch_len
2714
stretchfactor = self._stretchfactor
2716
outline = self._outlinewidth
2717
self.pen(resizemode="user",
2718
stretchfactor=stretchfactor, outline=outline)
2720
def settiltangle(self, angle):
2721
"""Rotate the turtleshape to point in the specified direction
2726
Rotate the turtleshape to point in the direction specified by angle,
2727
regardless of its current tilt-angle. DO NOT change the turtle's
2728
heading (direction of movement).
2731
Examples (for a Turtle instance named turtle):
2732
>>> turtle.shape("circle")
2733
>>> turtle.shapesize(5,2)
2734
>>> turtle.settiltangle(45)
2737
>>> turtle.settiltangle(-45)
2741
tilt = -angle * self._degreesPerAU * self._angleOrient
2742
tilt = (tilt * math.pi / 180.0) % (2*math.pi)
2743
self.pen(resizemode="user", tilt=tilt)
2745
def tiltangle(self):
2746
"""Return the current tilt-angle.
2750
Return the current tilt-angle, i. e. the angle between the
2751
orientation of the turtleshape and the heading of the turtle
2752
(it's direction of movement).
2754
Examples (for a Turtle instance named turtle):
2755
>>> turtle.shape("circle")
2756
>>> turtle.shapesize(5,2)
2758
>>> turtle.tiltangle()
2761
tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
2762
return (tilt / self._degreesPerAU) % self._fullcircle
2764
def tilt(self, angle):
2765
"""Rotate the turtleshape by angle.
2770
Rotate the turtleshape by angle from its current tilt-angle,
2771
but do NOT change the turtle's heading (direction of movement).
2773
Examples (for a Turtle instance named turtle):
2774
>>> turtle.shape("circle")
2775
>>> turtle.shapesize(5,2)
2781
self.settiltangle(angle + self.tiltangle())
2783
def _polytrafo(self, poly):
2784
"""Computes transformed polygon shapes from a shape
2785
according to current position and heading.
2787
screen = self.screen
2788
p0, p1 = self._position
2789
e0, e1 = self._orient
2790
e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
2791
e0, e1 = (1.0 / abs(e)) * e
2792
return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
2795
def _drawturtle(self):
2796
"""Manages the correct rendering of the turtle with respect to
2797
it's shape, resizemode, strech and tilt etc."""
2798
screen = self.screen
2799
shape = screen._shapes[self.turtle.shapeIndex]
2801
titem = self.turtle._item
2802
if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
2803
self._hidden_from_screen = False
2804
tshape = shape._data
2805
if ttype == "polygon":
2806
if self._resizemode == "noresize":
2810
if self._resizemode == "auto":
2811
lx = ly = max(1, self._pensize/5.0)
2814
elif self._resizemode == "user":
2815
lx, ly = self._stretchfactor
2816
w = self._outlinewidth
2817
tiltangle = self._tilt
2818
shape = [(lx*x, ly*y) for (x, y) in tshape]
2819
t0, t1 = math.sin(tiltangle), math.cos(tiltangle)
2820
shape = [(t1*x+t0*y, -t0*x+t1*y) for (x, y) in shape]
2821
shape = self._polytrafo(shape)
2822
fc, oc = self._fillcolor, self._pencolor
2823
screen._drawpoly(titem, shape, fill=fc, outline=oc,
2825
elif ttype == "image":
2826
screen._drawimage(titem, self._position, tshape)
2827
elif ttype == "compound":
2828
lx, ly = self._stretchfactor
2829
w = self._outlinewidth
2830
for item, (poly, fc, oc) in zip(titem, tshape):
2831
poly = [(lx*x, ly*y) for (x, y) in poly]
2832
poly = self._polytrafo(poly)
2833
screen._drawpoly(item, poly, fill=self._cc(fc),
2834
outline=self._cc(oc), width=w, top=True)
2836
if self._hidden_from_screen:
2838
if ttype == "polygon":
2839
screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
2840
elif ttype == "image":
2841
screen._drawimage(titem, self._position,
2842
screen._shapes["blank"]._data)
2843
elif ttype == "compound":
2845
screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
2846
self._hidden_from_screen = True
2848
############################## stamp stuff ###############################
2851
"""Stamp a copy of the turtleshape onto the canvas and return it's id.
2855
Stamp a copy of the turtle shape onto the canvas at the current
2856
turtle position. Return a stamp_id for that stamp, which can be
2857
used to delete it by calling clearstamp(stamp_id).
2859
Example (for a Turtle instance named turtle):
2860
>>> turtle.color("blue")
2865
screen = self.screen
2866
shape = screen._shapes[self.turtle.shapeIndex]
2868
tshape = shape._data
2869
if ttype == "polygon":
2870
stitem = screen._createpoly()
2871
if self._resizemode == "noresize":
2875
if self._resizemode == "auto":
2876
lx = ly = max(1, self._pensize/5.0)
2879
elif self._resizemode == "user":
2880
lx, ly = self._stretchfactor
2881
w = self._outlinewidth
2882
tiltangle = self._tilt
2883
shape = [(lx*x, ly*y) for (x, y) in tshape]
2884
t0, t1 = math.sin(tiltangle), math.cos(tiltangle)
2885
shape = [(t1*x+t0*y, -t0*x+t1*y) for (x, y) in shape]
2886
shape = self._polytrafo(shape)
2887
fc, oc = self._fillcolor, self._pencolor
2888
screen._drawpoly(stitem, shape, fill=fc, outline=oc,
2890
elif ttype == "image":
2891
stitem = screen._createimage("")
2892
screen._drawimage(stitem, self._position, tshape)
2893
elif ttype == "compound":
2895
for element in tshape:
2896
item = screen._createpoly()
2898
stitem = tuple(stitem)
2899
lx, ly = self._stretchfactor
2900
w = self._outlinewidth
2901
for item, (poly, fc, oc) in zip(stitem, tshape):
2902
poly = [(lx*x, ly*y) for (x, y) in poly]
2903
poly = self._polytrafo(poly)
2904
screen._drawpoly(item, poly, fill=self._cc(fc),
2905
outline=self._cc(oc), width=w, top=True)
2906
self.stampItems.append(stitem)
2907
self.undobuffer.push(("stamp", stitem))
2910
def _clearstamp(self, stampid):
2911
"""does the work for clearstamp() and clearstamps()
2913
if stampid in self.stampItems:
2914
if isinstance(stampid, tuple):
2915
for subitem in stampid:
2916
self.screen._delete(subitem)
2918
self.screen._delete(stampid)
2919
self.stampItems.remove(stampid)
2920
# Delete stampitem from undobuffer if necessary
2921
# if clearstamp is called directly.
2922
item = ("stamp", stampid)
2923
buf = self.undobuffer
2924
if item not in buf.buffer:
2926
index = buf.buffer.index(item)
2927
buf.buffer.remove(item)
2928
if index <= buf.ptr:
2929
buf.ptr = (buf.ptr - 1) % buf.bufsize
2930
buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
2932
def clearstamp(self, stampid):
2933
"""Delete stamp with given stampid
2936
stampid - an integer, must be return value of previous stamp() call.
2938
Example (for a Turtle instance named turtle):
2939
>>> turtle.color("blue")
2940
>>> astamp = turtle.stamp()
2942
>>> turtle.clearstamp(astamp)
2944
self._clearstamp(stampid)
2947
def clearstamps(self, n=None):
2948
"""Delete all or first/last n of turtle's stamps.
2953
If n is None, delete all of pen's stamps,
2954
else if n > 0 delete first n stamps
2955
else if n < 0 delete last n stamps.
2957
Example (for a Turtle instance named turtle):
2958
>>> for i in range(8):
2959
turtle.stamp(); turtle.fd(30)
2961
>>> turtle.clearstamps(2)
2962
>>> turtle.clearstamps(-2)
2963
>>> turtle.clearstamps()
2966
toDelete = self.stampItems[:]
2968
toDelete = self.stampItems[:n]
2970
toDelete = self.stampItems[n:]
2971
for item in toDelete:
2972
self._clearstamp(item)
2975
def _goto(self, end):
2976
"""Move the pen to the point end, thereby drawing a line
2977
if pen is down. All other methodes for turtle movement depend
2980
## Version mit undo-stuff
2981
go_modes = ( self._drawing,
2984
isinstance(self._fillpath, list))
2985
screen = self.screen
2986
undo_entry = ("go", self._position, end, go_modes,
2987
(self.currentLineItem,
2988
self.currentLine[:],
2989
screen._pointlist(self.currentLineItem),
2993
self.undobuffer.push(undo_entry)
2994
start = self._position
2995
if self._speed and screen._tracing == 1:
2997
diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
2998
nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
2999
delta = diff * (1.0/nhops)
3000
for n in range(1, nhops):
3005
self._position = start + delta * n
3007
screen._drawline(self.drawingLineItem,
3008
(start, self._position),
3009
self._pencolor, self._pensize, top)
3012
screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3013
fill="", width=self._pensize)
3014
# Turtle now at end,
3015
if self._drawing: # now update currentLine
3016
self.currentLine.append(end)
3017
if isinstance(self._fillpath, list):
3018
self._fillpath.append(end)
3019
###### vererbung!!!!!!!!!!!!!!!!!!!!!!
3020
self._position = end
3021
if self._creatingPoly:
3022
self._poly.append(end)
3023
if len(self.currentLine) > 42: # 42! answer to the ultimate question
3024
# of life, the universe and everything
3026
self._update() #count=True)
3028
def _undogoto(self, entry):
3029
"""Reverse a _goto. Used for undo()
3031
old, new, go_modes, coodata = entry
3032
drawing, pc, ps, filling = go_modes
3033
cLI, cL, pl, items = coodata
3034
screen = self.screen
3035
if abs(self._position - new) > 0.5:
3036
print "undogoto: HALLO-DA-STIMMT-WAS-NICHT!"
3037
# restore former situation
3038
self.currentLineItem = cLI
3039
self.currentLine = cL
3041
if pl == [(0, 0), (0, 0)]:
3045
screen._drawline(cLI, pl, fill=usepc, width=ps)
3047
todelete = [i for i in self.items if (i not in items) and
3048
(screen._type(i) == "line")]
3051
self.items.remove(i)
3054
if self._speed and screen._tracing == 1:
3056
diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3057
nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3058
delta = diff * (1.0/nhops)
3059
for n in range(1, nhops):
3064
self._position = new + delta * n
3066
screen._drawline(self.drawingLineItem,
3067
(start, self._position),
3071
screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3073
# Turtle now at position old,
3074
self._position = old
3075
## if undo is done during crating a polygon, the last vertex
3076
## will be deleted. if the polygon is entirel deleted,
3077
## creatigPoly will be set to False.
3078
## Polygons created before the last one will not be affected by undo()
3079
if self._creatingPoly:
3080
if len(self._poly) > 0:
3082
if self._poly == []:
3083
self._creatingPoly = False
3086
if self._fillpath == []:
3087
self._fillpath = None
3088
print "Unwahrscheinlich in _undogoto!"
3089
elif self._fillpath is not None:
3090
self._fillpath.pop()
3091
self._update() #count=True)
3093
def _rotate(self, angle):
3094
"""Turns pen clockwise by angle.
3097
self.undobuffer.push(("rot", angle, self._degreesPerAU))
3098
angle *= self._degreesPerAU
3099
neworient = self._orient.rotate(angle)
3100
tracing = self.screen._tracing
3101
if tracing == 1 and self._speed > 0:
3102
anglevel = 3.0 * self._speed
3103
steps = 1 + int(abs(angle)/anglevel)
3104
delta = 1.0*angle/steps
3105
for _ in range(steps):
3106
self._orient = self._orient.rotate(delta)
3108
self._orient = neworient
3111
def _newLine(self, usePos=True):
3112
"""Closes current line item and starts a new one.
3113
Remark: if current line became too long, animation
3114
performance (via _drawline) slowed down considerably.
3116
if len(self.currentLine) > 1:
3117
self.screen._drawline(self.currentLineItem, self.currentLine,
3118
self._pencolor, self._pensize)
3119
self.currentLineItem = self.screen._createline()
3120
self.items.append(self.currentLineItem)
3122
self.screen._drawline(self.currentLineItem, top=True)
3123
self.currentLine = []
3125
self.currentLine = [self._position]
3127
def fill(self, flag=None):
3128
"""Call fill(True) before drawing a shape to fill, fill(False) when done.
3131
flag -- True/False (or 1/0 respectively)
3133
Call fill(True) before drawing the shape you want to fill,
3134
and fill(False) when done.
3135
When used without argument: return fillstate (True if filling,
3138
Example (for a Turtle instance named turtle):
3139
>>> turtle.fill(True)
3140
>>> turtle.forward(100)
3142
>>> turtle.forward(100)
3144
>>> turtle.forward(100)
3146
>>> turtle.forward(100)
3147
>>> turtle.fill(False)
3149
filling = isinstance(self._fillpath, list)
3152
screen = self.screen
3153
entry1 = entry2 = ()
3155
if len(self._fillpath) > 2:
3156
self.screen._drawpoly(self._fillitem, self._fillpath,
3157
fill=self._fillcolor)
3158
entry1 = ("dofill", self._fillitem)
3160
self._fillitem = self.screen._createpoly()
3161
self.items.append(self._fillitem)
3162
self._fillpath = [self._position]
3163
entry2 = ("beginfill", self._fillitem) # , self._fillpath)
3166
self._fillitem = self._fillpath = None
3170
self.undobuffer.push(entry2)
3173
self.undobuffer.push(entry1)
3175
self.undobuffer.push(["seq", entry1, entry2])
3178
def begin_fill(self):
3179
"""Called just before drawing a shape to be filled.
3183
Example (for a Turtle instance named turtle):
3184
>>> turtle.begin_fill()
3185
>>> turtle.forward(100)
3187
>>> turtle.forward(100)
3189
>>> turtle.forward(100)
3191
>>> turtle.forward(100)
3192
>>> turtle.end_fill()
3197
"""Fill the shape drawn after the call begin_fill().
3201
Example (for a Turtle instance named turtle):
3202
>>> turtle.begin_fill()
3203
>>> turtle.forward(100)
3205
>>> turtle.forward(100)
3207
>>> turtle.forward(100)
3209
>>> turtle.forward(100)
3210
>>> turtle.end_fill()
3214
def dot(self, size=None, *color):
3215
"""Draw a dot with diameter size, using color.
3218
size -- an integer >= 1 (if given)
3219
color -- a colorstring or a numeric color tuple
3221
Draw a circular dot with diameter size, using color.
3222
If size is not given, the maximum of pensize+4 and 2*pensize is used.
3224
Example (for a Turtle instance named turtle):
3226
>>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
3228
#print "dot-1:", size, color
3230
if isinstance(size, (str, tuple)):
3231
color = self._colorstr(size)
3232
size = self._pensize + max(self._pensize, 4)
3234
color = self._pencolor
3236
size = self._pensize + max(self._pensize, 4)
3239
size = self._pensize + max(self._pensize, 4)
3240
color = self._colorstr(color)
3241
#print "dot-2:", size, color
3242
if hasattr(self.screen, "_dot"):
3243
item = self.screen._dot(self._position, size, color)
3244
#print "dot:", size, color, "item:", item
3245
self.items.append(item)
3247
self.undobuffer.push(("dot", item))
3251
self.undobuffer.push(["seq"])
3252
self.undobuffer.cumulate = True
3254
if self.resizemode() == 'auto':
3258
self.pencolor(color)
3263
self.undobuffer.cumulate = False
3265
def _write(self, txt, align, font):
3266
"""Performs the writing for write()
3268
item, end = self.screen._write(self._position, txt, align, font,
3270
self.items.append(item)
3272
self.undobuffer.push(("wri", item))
3275
def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
3276
"""Write text at the current turtle position.
3279
arg -- info, which is to be written to the TurtleScreen
3280
move (optional) -- True/False
3281
align (optional) -- one of the strings "left", "center" or right"
3282
font (optional) -- a triple (fontname, fontsize, fonttype)
3284
Write text - the string representation of arg - at the current
3285
turtle position according to align ("left", "center" or right")
3286
and with the given font.
3287
If move is True, the pen is moved to the bottom-right corner
3288
of the text. By default, move is False.
3290
Example (for a Turtle instance named turtle):
3291
>>> turtle.write('Home = ', True, align="center")
3292
>>> turtle.write((0,0), True)
3295
self.undobuffer.push(["seq"])
3296
self.undobuffer.cumulate = True
3297
end = self._write(str(arg), align.lower(), font)
3302
self.undobuffer.cumulate = False
3304
def begin_poly(self):
3305
"""Start recording the vertices of a polygon.
3309
Start recording the vertices of a polygon. Current turtle position
3310
is first point of polygon.
3312
Example (for a Turtle instance named turtle):
3313
>>> turtle.begin_poly()
3315
self._poly = [self._position]
3316
self._creatingPoly = True
3319
"""Stop recording the vertices of a polygon.
3323
Stop recording the vertices of a polygon. Current turtle position is
3324
last point of polygon. This will be connected with the first point.
3326
Example (for a Turtle instance named turtle):
3327
>>> turtle.end_poly()
3329
self._creatingPoly = False
3332
"""Return the lastly recorded polygon.
3336
Example (for a Turtle instance named turtle):
3337
>>> p = turtle.get_poly()
3338
>>> turtle.register_shape("myFavouriteShape", p)
3340
## check if there is any poly? -- 1st solution:
3341
if self._poly is not None:
3342
return tuple(self._poly)
3344
def getscreen(self):
3345
"""Return the TurtleScreen object, the turtle is drawing on.
3349
Return the TurtleScreen object, the turtle is drawing on.
3350
So TurtleScreen-methods can be called for that object.
3352
Example (for a Turtle instance named turtle):
3353
>>> ts = turtle.getscreen()
3355
<turtle.TurtleScreen object at 0x0106B770>
3356
>>> ts.bgcolor("pink")
3360
def getturtle(self):
3361
"""Return the Turtleobject itself.
3365
Only reasonable use: as a function to return the 'anonymous turtle':
3368
>>> pet = getturtle()
3371
<turtle.Turtle object at 0x0187D810>
3373
[<turtle.Turtle object at 0x0187D810>]
3380
################################################################
3381
### screen oriented methods recurring to methods of TurtleScreen
3382
################################################################
409
3384
def window_width(self):
410
3385
""" Returns the width of the turtle window.
413
>>> turtle.window_width()
3389
Example (for a TurtleScreen instance named screen):
3390
>>> screen.window_width()
416
width = self._canvas.winfo_width()
417
if width <= 1: # the window isn't managed by a geometry manager
418
width = self._canvas['width']
3393
return self.screen._window_size()[0]
421
3395
def window_height(self):
422
3396
""" Return the height of the turtle window.
425
>>> turtle.window_height()
428
height = self._canvas.winfo_height()
429
if height <= 1: # the window isn't managed by a geometry manager
430
height = self._canvas['height']
434
""" Return the current (x, y) location of the turtle.
437
>>> turtle.position()
440
x0, y0 = self._origin
441
x1, y1 = self._position
442
return [x1-x0, -y1+y0]
444
def setx(self, xpos):
445
""" Set the turtle's x coordinate to be xpos.
448
>>> turtle.position()
451
>>> turtle.position()
454
x0, y0 = self._origin
455
x1, y1 = self._position
456
self._goto(x0+xpos, y1)
458
def sety(self, ypos):
459
""" Set the turtle's y coordinate to be ypos.
462
>>> turtle.position()
465
>>> turtle.position()
468
x0, y0 = self._origin
469
x1, y1 = self._position
470
self._goto(x1, y0-ypos)
472
def towards(self, *args):
473
"""Returs the angle, which corresponds to the line
474
from turtle-position to point (x,y).
476
Argument can be two coordinates or one pair of coordinates
477
or a RawPen/Pen instance.
480
>>> turtle.position()
482
>>> turtle.towards(0,0)
489
if isinstance(arg, RawPen):
490
x, y = arg.position()
493
x0, y0 = self.position()
496
return (atan2(dy,dx) / self._invradian) % self._fullcircle
498
def goto(self, *args):
499
""" Go to the given point.
501
If the pen is down, then a line will be drawn. The turtle's
502
orientation does not change.
504
Two input formats are accepted:
513
>>> turtle.position()
515
>>> turtle.goto(50, -45)
516
>>> turtle.position()
523
raise Error, "bad point argument: %r" % (args[0],)
528
raise Error, "bad coordinates: %r" % (args[0],)
529
x0, y0 = self._origin
530
self._goto(x0+x, y0-y)
532
def _goto(self, x1, y1):
533
x0, y0 = self._position
534
self._position = map(float, (x1, y1))
536
self._path.append(self._position)
541
distance = hypot(dx, dy)
542
nhops = int(distance)
543
item = self._canvas.create_line(x0, y0, x0, y0,
548
for i in range(1, 1+nhops):
549
x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
550
self._canvas.coords(item, x0, y0, x, y)
551
self._draw_turtle((x,y))
552
self._canvas.update()
553
self._canvas.after(self._delay)
555
self._canvas.coords(item, x0, y0, x1, y1)
556
self._canvas.itemconfigure(item, arrow="none")
557
except Tkinter.TclError:
558
# Probably the window was closed!
561
item = self._canvas.create_line(x0, y0, x1, y1,
565
self._items.append(item)
568
def speed(self, speed):
569
""" Set the turtle's speed.
571
speed must one of these five strings:
573
'fastest' is a 0 ms delay
574
'fast' is a 5 ms delay
575
'normal' is a 10 ms delay
576
'slow' is a 15 ms delay
577
'slowest' is a 20 ms delay
580
>>> turtle.speed('slow')
583
speed = speed.strip().lower()
584
self._delay = speeds.index(speed) * 5
586
raise ValueError("%r is not a valid speed. speed must be "
587
"one of %s" % (speed, speeds))
590
def delay(self, delay):
591
""" Set the drawing delay in milliseconds.
593
This is intended to allow finer control of the drawing speed
594
than the speed() method
600
raise ValueError("delay must be greater than or equal to 0")
601
self._delay = int(delay)
603
def _draw_turtle(self, position=[]):
604
if not self._tracing:
605
self._canvas.update()
608
position = self._position
611
dx = distance * cos(self._angle*self._invradian)
612
dy = distance * sin(self._angle*self._invradian)
613
self._delete_turtle()
614
self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
619
self._canvas.update()
621
def _delete_turtle(self):
623
self._canvas.delete(self._arrow)
630
_width = 0.50 # 50% of window width
631
_height = 0.75 # 75% of window height
634
_title = "Turtle Graphics" # default title
3400
Example (for a TurtleScreen instance named screen):
3401
>>> screen.window_height()
3404
return self.screen._window_size()[1]
3406
def _delay(self, delay=None):
3407
"""Set delay value which determines speed of turtle animation.
3409
return self.screen.delay(delay)
3411
##### event binding methods #####
3413
def onclick(self, fun, btn=1, add=None):
3414
"""Bind fun to mouse-click event on this turtle on canvas.
3417
fun -- a function with two arguments, to which will be assigned
3418
the coordinates of the clicked point on the canvas.
3419
num -- number of the mouse-button defaults to 1 (left mouse button).
3420
add -- True or False. If True, new binding will be added, otherwise
3421
it will replace a former binding.
3423
Example for the anonymous turtle, i. e. the procedural way:
3428
>>> onclick(turn) # Now clicking into the turtle will turn it.
3429
>>> onclick(None) # event-binding will be removed
3431
self.screen._onclick(self.turtle._item, fun, btn, add)
3434
def onrelease(self, fun, btn=1, add=None):
3435
"""Bind fun to mouse-button-release event on this turtle on canvas.
3438
fun -- a function with two arguments, to which will be assigned
3439
the coordinates of the clicked point on the canvas.
3440
num -- number of the mouse-button defaults to 1 (left mouse button).
3442
Example (for a MyTurtle instance named joe):
3443
>>> class MyTurtle(Turtle):
3445
self.fillcolor("red")
3446
def unglow(self,x,y):
3449
>>> joe = MyTurtle()
3450
>>> joe.onclick(joe.glow)
3451
>>> joe.onrelease(joe.unglow)
3452
### clicking on joe turns fillcolor red,
3453
### unclicking turns it to transparent.
3455
self.screen._onrelease(self.turtle._item, fun, btn, add)
3458
def ondrag(self, fun, btn=1, add=None):
3459
"""Bind fun to mouse-move event on this turtle on canvas.
3462
fun -- a function with two arguments, to which will be assigned
3463
the coordinates of the clicked point on the canvas.
3464
num -- number of the mouse-button defaults to 1 (left mouse button).
3466
Every sequence of mouse-move-events on a turtle is preceded by a
3467
mouse-click event on that turtle.
3469
Example (for a Turtle instance named turtle):
3470
>>> turtle.ondrag(turtle.goto)
3472
### Subsequently clicking and dragging a Turtle will
3473
### move it across the screen thereby producing handdrawings
3474
### (if pen is down).
3476
self.screen._ondrag(self.turtle._item, fun, btn, add)
3479
def _undo(self, action, data):
3480
"""Does the main part of the work for undo()
3482
if self.undobuffer is None:
3485
angle, degPAU = data
3486
self._rotate(-angle*degPAU/self._degreesPerAU)
3487
dummy = self.undobuffer.pop()
3488
elif action == "stamp":
3490
self.clearstamp(stitem)
3491
elif action == "go":
3492
self._undogoto(data)
3493
elif action in ["wri", "dot"]:
3495
self.screen._delete(item)
3496
self.items.remove(item)
3497
elif action == "dofill":
3499
self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
3500
fill="", outline="")
3501
elif action == "beginfill":
3503
self._fillitem = self._fillpath = None
3504
self.screen._delete(item)
3505
self.items.remove(item)
3506
elif action == "pen":
3507
TPen.pen(self, data[0])
3508
self.undobuffer.pop()
3511
"""undo (repeatedly) the last turtle action.
3515
undo (repeatedly) the last turtle action.
3516
Number of available undo actions is determined by the size of
3519
Example (for a Turtle instance named turtle):
3520
>>> for i in range(4):
3521
turtle.fd(50); turtle.lt(80)
3523
>>> for i in range(8):
3526
if self.undobuffer is None:
3528
item = self.undobuffer.pop()
3534
self._undo(item[0], item[1:])
3536
self._undo(action, data)
3538
turtlesize = shapesize
3542
### Screen - Klasse ########################
3544
class Screen(TurtleScreen):
3548
_title = _CFG["title"]
3554
def __new__(cls, *args, **kwargs):
3555
obj = object.__new__(cls, *args, **kwargs)
3556
obj.__dict__ = cls._shared_state
638
3559
def __init__(self):
639
global _root, _canvas
642
_root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
646
# XXX Should have scroll bars
647
_canvas = Tkinter.Canvas(_root, background="white")
648
_canvas.pack(expand=1, fill="both")
650
setup(width=_width, height= _height, startx=_startx, starty=_starty)
652
RawPen.__init__(self, _canvas)
3560
if Screen._root is None:
3561
Screen._root = self._root = _Root()
3562
self._root.title(Screen._title)
3563
self._root.ondestroy(self._destroy)
3564
if Screen._canvas is None:
3565
width = _CFG["width"]
3566
height = _CFG["height"]
3567
canvwidth = _CFG["canvwidth"]
3568
canvheight = _CFG["canvheight"]
3569
leftright = _CFG["leftright"]
3570
topbottom = _CFG["topbottom"]
3571
self._root.setupcanvas(width, height, canvwidth, canvheight)
3572
Screen._canvas = self._root._getcanvas()
3573
self.setup(width, height, leftright, topbottom)
3574
TurtleScreen.__init__(self, Screen._canvas)
3575
Turtle._screen = self
3577
def setup(self, width=_CFG["width"], height=_CFG["height"],
3578
startx=_CFG["leftright"], starty=_CFG["topbottom"]):
3579
""" Set the size and position of the main window.
3582
width: as integer a size in pixels, as float a fraction of the screen.
3583
Default is 50% of screen.
3584
height: as integer the height in pixels, as float a fraction of the
3585
screen. Default is 75% of screen.
3586
startx: if positive, starting position in pixels from the left
3587
edge of the screen, if negative from the right edge
3588
Default, startx=None is to center window horizontally.
3589
starty: if positive, starting position in pixels from the top
3590
edge of the screen, if negative from the bottom edge
3591
Default, starty=None is to center window vertically.
3593
Examples (for a Screen instance named screen):
3594
>>> screen.setup (width=200, height=200, startx=0, starty=0)
3596
sets window to 200x200 pixels, in upper left of screen
3598
>>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
3600
sets window to 75% of screen by 50% of screen and centers
3602
if not hasattr(self._root, "set_geometry"):
3604
sw = self._root.win_width()
3605
sh = self._root.win_height()
3606
if isinstance(width, float) and 0 <= width <= 1:
3609
startx = (sw - width) / 2
3610
if isinstance(height, float) and 0 <= height <= 1:
3613
starty = (sh - height) / 2
3614
self._root.set_geometry(width, height, startx, starty)
3616
def title(self, titlestring):
3617
"""Set title of turtle-window
3620
titlestring -- a string, to appear in the titlebar of the
3621
turtle graphics window.
3623
This is a method of Screen-class. Not available for TurtleScreen-
3626
Example (for a Screen instance named screen):
3627
>>> screen.title("Welcome to the turtle-zoo!")
3629
if Screen._root is not None:
3630
Screen._root.title(titlestring)
3631
Screen._title = titlestring
654
3633
def _destroy(self):
655
global _root, _canvas, _pen
656
root = self._canvas._root()
3635
if root is Screen._root:
3637
Turtle._screen = None
3639
Screen._canvas = None
3640
TurtleScreen._RUNNING = True
3644
"""Shut the turtlegraphics window.
3646
Example (for a TurtleScreen instance named screen):
3651
def exitonclick(self):
3652
"""Go into mainloop until the mouse is clicked.
3656
Bind bye() method to mouseclick on TurtleScreen.
3657
If "using_IDLE" - value in configuration dictionary is False
3658
(default value), enter mainloop.
3659
If IDLE with -n switch (no subprocess) is used, this value should be
3660
set to True in turtle.cfg. In this case IDLE's mainloop
3661
is active also for the client script.
3663
This is a method of the Screen-class and not available for
3664
TurtleScreen instances.
3666
Example (for a Screen instance named screen):
3667
>>> screen.exitonclick()
3670
def exitGracefully(x, y):
3671
"""Screen.bye() with two dummy-parameters"""
3673
self.onclick(exitGracefully)
3674
if _CFG["using_IDLE"]:
3678
except AttributeError:
3682
class Turtle(RawTurtle):
3683
"""RawTurtle auto-crating (scrolled) canvas.
3685
When a Turtle object is created or a function derived from some
3686
Turtle method is called a TurtleScreen object is automatically created.
3692
shape=_CFG["shape"],
3693
undobuffersize=_CFG["undobuffersize"],
3694
visible=_CFG["visible"]):
3695
if Turtle._screen is None:
3696
Turtle._screen = Screen()
3697
RawTurtle.__init__(self, Turtle._screen,
3699
undobuffersize=undobuffersize,
672
"""For documentation of the following functions see
673
the RawPen methods with the same names
676
def degrees(): _getpen().degrees()
677
def radians(): _getpen().radians()
678
def reset(): _getpen().reset()
679
def clear(): _getpen().clear()
680
def tracer(flag): _getpen().tracer(flag)
681
def forward(distance): _getpen().forward(distance)
682
def backward(distance): _getpen().backward(distance)
683
def left(angle): _getpen().left(angle)
684
def right(angle): _getpen().right(angle)
685
def up(): _getpen().up()
686
def down(): _getpen().down()
687
def width(width): _getpen().width(width)
688
def color(*args): _getpen().color(*args)
689
def write(arg, move=0): _getpen().write(arg, move)
690
def fill(flag): _getpen().fill(flag)
691
def begin_fill(): _getpen().begin_fill()
692
def end_fill(): _getpen().end_fill()
693
def circle(radius, extent=None): _getpen().circle(radius, extent)
694
def goto(*args): _getpen().goto(*args)
695
def heading(): return _getpen().heading()
696
def setheading(angle): _getpen().setheading(angle)
697
def position(): return _getpen().position()
698
def window_width(): return _getpen().window_width()
699
def window_height(): return _getpen().window_height()
700
def setx(xpos): _getpen().setx(xpos)
701
def sety(ypos): _getpen().sety(ypos)
702
def towards(*args): return _getpen().towards(*args)
704
def done(): _root.mainloop()
705
def delay(delay): return _getpen().delay(delay)
706
def speed(speed): return _getpen().speed(speed)
708
for methodname in dir(RawPen):
709
""" copies RawPen docstrings to module functions of same name """
710
if not methodname.startswith("_"):
711
eval(methodname).__doc__ = RawPen.__dict__[methodname].__doc__
714
def setup(**geometry):
715
""" Sets the size and position of the main window.
717
Keywords are width, height, startx and starty:
719
width: either a size in pixels or a fraction of the screen.
720
Default is 50% of screen.
721
height: either the height in pixels or a fraction of the screen.
722
Default is 75% of screen.
724
Setting either width or height to None before drawing will force
725
use of default geometry as in older versions of turtle.py
727
startx: starting position in pixels from the left edge of the screen.
728
Default is to center window. Setting startx to None is the default
729
and centers window horizontally on screen.
731
starty: starting position in pixels from the top edge of the screen.
732
Default is to center window. Setting starty to None is the default
733
and centers window vertically on screen.
736
>>> setup (width=200, height=200, startx=0, starty=0)
738
sets window to 200x200 pixels, in upper left of screen
740
>>> setup(width=.75, height=0.5, startx=None, starty=None)
742
sets window to 75% of screen by 50% of screen and centers
744
>>> setup(width=None)
746
forces use of default geometry as in older versions of turtle.py
749
global _width, _height, _startx, _starty
751
width = geometry.get('width',_width)
752
if width >= 0 or width is None:
755
raise ValueError, "width can not be less than 0"
757
height = geometry.get('height',_height)
758
if height >= 0 or height is None:
761
raise ValueError, "height can not be less than 0"
763
startx = geometry.get('startx', _startx)
764
if startx >= 0 or startx is None:
767
raise ValueError, "startx can not be less than 0"
769
starty = geometry.get('starty', _starty)
770
if starty >= 0 or starty is None:
773
raise ValueError, "startx can not be less than 0"
776
if _root and _width and _height:
778
_width = _root.winfo_screenwidth() * +width
780
_height = _root.winfo_screenheight() * _height
782
# center window on screen
784
_startx = (_root.winfo_screenwidth() - _width) / 2
787
_starty = (_root.winfo_screenheight() - _height) / 2
789
_root.geometry("%dx%d+%d+%d" % (_width, _height, _startx, _starty))
792
"""Set the window title.
794
By default this is set to 'Turtle Graphics'
797
>>> title("My Window")
809
# draw 3 squares; the last filled
3705
"""Create the 'anonymous' turtle if not already present."""
3706
if Turtle._pen is None:
3707
Turtle._pen = Turtle()
3711
"""Create a TurtleScreen if not already present."""
3712
if Turtle._screen is None:
3713
Turtle._screen = Screen()
3714
return Turtle._screen
3716
def write_docstringdict(filename="turtle_docstringdict"):
3717
"""Create and write docstring-dictionary to file.
3720
filename -- a string, used as filename
3721
default value is turtle_docstringdict
3723
Has to be called explicitely, (not used by the turtle-graphics classes)
3724
The docstring dictionary will be written to the Python script <filname>.py
3725
It is intended to serve as a template for translation of the docstrings
3726
into different languages.
3730
for methodname in _tg_screen_functions:
3731
key = "Screen."+methodname
3732
docsdict[key] = eval(key).__doc__
3733
for methodname in _tg_turtle_functions:
3734
key = "Turtle."+methodname
3735
docsdict[key] = eval(key).__doc__
3737
f = open("%s.py" % filename,"w")
3738
keys = sorted([x for x in docsdict.keys()
3739
if x.split('.')[1] not in _alias_list])
3740
f.write('docsdict = {\n\n')
3741
for key in keys[:-1]:
3742
f.write('%s :\n' % repr(key))
3743
f.write(' """%s\n""",\n\n' % docsdict[key])
3745
f.write('%s :\n' % repr(key))
3746
f.write(' """%s\n"""\n\n' % docsdict[key])
3750
def read_docstrings(lang):
3751
"""Read in docstrings from lang-specific docstring dictionary.
3753
Transfer docstrings, translated to lang, from a dictionary-file
3754
to the methods of classes Screen and Turtle and - in revised form -
3755
to the corresponding functions.
3757
modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
3758
module = __import__(modname)
3759
docsdict = module.docsdict
3760
for key in docsdict:
3763
eval(key).im_func.__doc__ = docsdict[key]
3765
print "Bad docstring-entry: %s" % key
3767
_LANGUAGE = _CFG["language"]
3770
if _LANGUAGE != "english":
3771
read_docstrings(_LANGUAGE)
3773
print "Cannot find docsdict for", _LANGUAGE
3775
print ("Unknown Error when trying to import %s-docstring-dictionary" %
3779
def getmethparlist(ob):
3780
"Get strings describing the arguments for the given object"
3781
argText1 = argText2 = ""
3782
# bit of a hack for methods - turn it into a function
3783
# but we drop the "self" param.
3784
if type(ob)==types.MethodType:
3790
# Try and build one for Python defined functions
3791
if type(fob) in [types.FunctionType, types.LambdaType]:
3793
counter = fob.func_code.co_argcount
3794
items2 = list(fob.func_code.co_varnames[argOffset:counter])
3795
realArgs = fob.func_code.co_varnames[argOffset:counter]
3796
defaults = fob.func_defaults or []
3797
defaults = list(map(lambda name: "=%s" % repr(name), defaults))
3798
defaults = [""] * (len(realArgs)-len(defaults)) + defaults
3799
items1 = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
3800
if fob.func_code.co_flags & 0x4:
3801
items1.append("*"+fob.func_code.co_varnames[counter])
3802
items2.append("*"+fob.func_code.co_varnames[counter])
3804
if fob.func_code.co_flags & 0x8:
3805
items1.append("**"+fob.func_code.co_varnames[counter])
3806
items2.append("**"+fob.func_code.co_varnames[counter])
3807
argText1 = ", ".join(items1)
3808
argText1 = "(%s)" % argText1
3809
argText2 = ", ".join(items2)
3810
argText2 = "(%s)" % argText2
3813
return argText1, argText2
3815
def _turtle_docrevise(docstr):
3816
"""To reduce docstrings from RawTurtle class for functions
3821
turtlename = _CFG["exampleturtle"]
3822
newdocstr = docstr.replace("%s." % turtlename,"")
3823
parexp = re.compile(r' \(.+ %s\):' % turtlename)
3824
newdocstr = parexp.sub(":", newdocstr)
3827
def _screen_docrevise(docstr):
3828
"""To reduce docstrings from TurtleScreen class for functions
3833
screenname = _CFG["examplescreen"]
3834
newdocstr = docstr.replace("%s." % screenname,"")
3835
parexp = re.compile(r' \(.+ %s\):' % screenname)
3836
newdocstr = parexp.sub(":", newdocstr)
3839
## The following mechanism makes all methods of RawTurtle and Turtle available
3840
## as functions. So we can enhance, change, add, delete methods to these
3841
## classes and do not need to change anything here.
3844
for methodname in _tg_screen_functions:
3845
pl1, pl2 = getmethparlist(eval('Screen.' + methodname))
3847
print ">>>>>>", pl1, pl2
3849
defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
3850
{'key':methodname, 'pl1':pl1, 'pl2':pl2})
3852
eval(methodname).__doc__ = _screen_docrevise(eval('Screen.'+methodname).__doc__)
3854
for methodname in _tg_turtle_functions:
3855
pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
3857
print ">>>>>>", pl1, pl2
3859
defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" %
3860
{'key':methodname, 'pl1':pl1, 'pl2':pl2})
3862
eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__)
3865
done = mainloop = TK.mainloop
3866
del pl1, pl2, defstr
3868
if __name__ == "__main__":
3876
"""Demo of old turtle.py - module"""
825
# move out of the way
835
write("startstart", 1)
857
# exercises some new and improved features
861
# draw a segmented half-circle
862
setheading(towards(0,0))
864
r = (x**2+y**2)**.5/2.0
3882
# draw 3 squares; the last filled
880
# draw a series of triangles
886
for i in range(-2,16):
888
color(1.0-0.05*i,0,0.05*i)
902
# draw and fill a concave shape
925
# create a second turtle and make the original pursue and catch it
929
turtle.speed('normal')
939
# turn default turtle towards new turtle object
940
setheading(towards(turtle))
941
while ( abs(position()[0]-turtle.position()[0])>4 or
942
abs(position()[1]-turtle.position()[1])>4):
945
# turn default turtle towards new turtle object
3898
# move out of the way
3908
write("startstart", 1)
3929
"""Demo of some new features."""
3933
setheading(towards(0, 0))
3934
radius = distance(0, 0)/2.0
3939
write("wait a moment...")
3940
while undobufferentries():
3949
for i in range(-2, 16):
3952
fillcolor(255-15*i, 0, 15*i)
3958
speed((speed()+1)%12)
3966
color("red","yellow")
3982
tri.resizemode("auto")
3984
turtle.resizemode("auto")
3985
turtle.shape("turtle")
3990
turtle.goto(280, 40)
3994
turtle.color("blue","orange")
946
3997
setheading(towards(turtle))
948
write("CAUGHT! ", move=True)
952
if __name__ == '__main__':
3999
while tri.distance(turtle) > 4:
4002
tri.setheading(tri.towards(turtle))
4009
tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
4010
tri.pencolor("black")
4013
def baba(xdummy, ydummy):
4019
while undobufferentries():
4023
tri.write(" Click me!", font = ("Courier", 12, "bold") )
4024
tri.onclick(baba, 1)