Home | History | Annotate | Download | only in lib-tk
      1 #
      2 # turtle.py: a Tkinter based turtle graphics module for Python
      3 # Version 1.0.1 - 24. 9. 2009
      4 #
      5 # Copyright (C) 2006 - 2010  Gregor Lingl
      6 # email: glingl (at] aon.at
      7 #
      8 # This software is provided 'as-is', without any express or implied
      9 # warranty.  In no event will the authors be held liable for any damages
     10 # arising from the use of this software.
     11 #
     12 # Permission is granted to anyone to use this software for any purpose,
     13 # including commercial applications, and to alter it and redistribute it
     14 # freely, subject to the following restrictions:
     15 #
     16 # 1. The origin of this software must not be misrepresented; you must not
     17 #    claim that you wrote the original software. If you use this software
     18 #    in a product, an acknowledgment in the product documentation would be
     19 #    appreciated but is not required.
     20 # 2. Altered source versions must be plainly marked as such, and must not be
     21 #    misrepresented as being the original software.
     22 # 3. This notice may not be removed or altered from any source distribution.
     23 
     24 
     25 """
     26 Turtle graphics is a popular way for introducing programming to
     27 kids. It was part of the original Logo programming language developed
     28 by Wally Feurzig and Seymour Papert in 1966.
     29 
     30 Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
     31 the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
     32 the direction it is facing, drawing a line as it moves. Give it the
     33 command turtle.right(25), and it rotates in-place 25 degrees clockwise.
     34 
     35 By combining together these and similar commands, intricate shapes and
     36 pictures can easily be drawn.
     37 
     38 ----- turtle.py
     39 
     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)
     42 
     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
     47 the -n switch.
     48 
     49 Roughly it has the following features added:
     50 
     51 - Better animation of the turtle movements, especially of turning the
     52   turtle. So the turtles can more easily be used as a visual feedback
     53   instrument by the (beginning) programmer.
     54 
     55 - Different turtle shapes, gif-images as turtle shapes, user defined
     56   and user controllable turtle shapes, among them compound
     57   (multicolored) shapes. Turtle shapes can be stretched and tilted, which
     58   makes turtles very versatile geometrical objects.
     59 
     60 - Fine control over turtle movement and screen updates via delay(),
     61   and enhanced tracer() and speed() methods.
     62 
     63 - Aliases for the most commonly used commands, like fd for forward etc.,
     64   following the early Logo traditions. This reduces the boring work of
     65   typing long sequences of commands, which often occur in a natural way
     66   when kids try to program fancy pictures on their first encounter with
     67   turtle graphics.
     68 
     69 - Turtles now have an undo()-method with configurable undo-buffer.
     70 
     71 - Some simple commands/methods for creating event driven programs
     72   (mouse-, key-, timer-events). Especially useful for programming games.
     73 
     74 - A scrollable Canvas class. The default scrollable Canvas can be
     75   extended interactively as needed while playing around with the turtle(s).
     76 
     77 - A TurtleScreen class with methods controlling background color or
     78   background image, window and canvas size and other properties of the
     79   TurtleScreen.
     80 
     81 - There is a method, setworldcoordinates(), to install a user defined
     82   coordinate-system for the TurtleScreen.
     83 
     84 - The implementation uses a 2-vector class named Vec2D, derived from tuple.
     85   This class is public, so it can be imported by the application programmer,
     86   which makes certain types of computations very natural and compact.
     87 
     88 - Appearance of the TurtleScreen and the Turtles at startup/import can be
     89   configured by means of a turtle.cfg configuration file.
     90   The default configuration mimics the appearance of the old turtle module.
     91 
     92 - If configured appropriately the module reads in docstrings from a docstring
     93   dictionary in some different language, supplied separately  and replaces
     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.
     97 
     98 Behind the scenes there are some features included with possible
     99 extensions in mind. These will be commented and documented elsewhere.
    100 
    101 """
    102 
    103 _ver = "turtle 1.0b1 - for Python 2.6   -  30. 5. 2008, 18:08"
    104 
    105 #print _ver
    106 
    107 import Tkinter as TK
    108 import types
    109 import math
    110 import time
    111 import os
    112 
    113 from os.path import isfile, split, join
    114 from copy import deepcopy
    115 
    116 from math import *    ## for compatibility with old turtle module
    117 
    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']
    143 
    144 __all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
    145            _tg_utilities + ['Terminator'] + _math_functions)
    146 
    147 _alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
    148                'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
    149                'turtlesize', 'up', 'width']
    150 
    151 _CFG = {"width" : 0.5,               # Screen
    152         "height" : 0.75,
    153         "canvwidth" : 400,
    154         "canvheight": 300,
    155         "leftright": None,
    156         "topbottom": None,
    157         "mode": "standard",          # TurtleScreen
    158         "colormode": 1.0,
    159         "delay": 10,
    160         "undobuffersize": 1000,      # RawTurtle
    161         "shape": "classic",
    162         "pencolor" : "black",
    163         "fillcolor" : "black",
    164         "resizemode" : "noresize",
    165         "visible" : True,
    166         "language": "english",        # docstrings
    167         "exampleturtle": "turtle",
    168         "examplescreen": "screen",
    169         "title": "Python Turtle Graphics",
    170         "using_IDLE": False
    171        }
    172 
    173 ##print "cwd:", os.getcwd()
    174 ##print "__file__:", __file__
    175 ##
    176 ##def show(dictionary):
    177 ##    print "=========================="
    178 ##    for key in sorted(dictionary.keys()):
    179 ##        print key, ":", dictionary[key]
    180 ##    print "=========================="
    181 ##    print
    182 
    183 def config_dict(filename):
    184     """Convert content of config-file into dictionary."""
    185     f = open(filename, "r")
    186     cfglines = f.readlines()
    187     f.close()
    188     cfgdict = {}
    189     for line in cfglines:
    190         line = line.strip()
    191         if not line or line.startswith("#"):
    192             continue
    193         try:
    194             key, value = line.split("=")
    195         except ValueError:
    196             print "Bad line in config-file %s:\n%s" % (filename,line)
    197             continue
    198         key = key.strip()
    199         value = value.strip()
    200         if value in ["True", "False", "None", "''", '""']:
    201             value = eval(value)
    202         else:
    203             try:
    204                 if "." in value:
    205                     value = float(value)
    206                 else:
    207                     value = int(value)
    208             except ValueError:
    209                 pass # value need not be converted
    210         cfgdict[key] = value
    211     return cfgdict
    212 
    213 def readconfig(cfgdict):
    214     """Read config-files, change configuration-dict accordingly.
    215 
    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.
    225     """
    226     default_cfg = "turtle.cfg"
    227     cfgdict1 = {}
    228     cfgdict2 = {}
    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"]
    234     try:
    235         head, tail = split(__file__)
    236         cfg_file2 = join(head, default_cfg)
    237     except BaseException:
    238         cfg_file2 = ""
    239     if isfile(cfg_file2):
    240         #print "2. Loading config-file %s:" % cfg_file2
    241         cfgdict2 = config_dict(cfg_file2)
    242 ##    show(_CFG)
    243 ##    show(cfgdict2)
    244     _CFG.update(cfgdict2)
    245 ##    show(_CFG)
    246 ##    show(cfgdict1)
    247     _CFG.update(cfgdict1)
    248 ##    show(_CFG)
    249 
    250 try:
    251     readconfig(_CFG)
    252 except BaseException:
    253     print "No configfile read, reason unknown"
    254 
    255 
    256 class Vec2D(tuple):
    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!
    261 
    262     Provides (for a, b vectors, k number):
    263        a+b vector addition
    264        a-b vector subtraction
    265        a*b inner product
    266        k*a and a*k multiplication with scalar
    267        |a| absolute value of a
    268        a.rotate(angle) rotation
    269     """
    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])
    283     def __neg__(self):
    284         return Vec2D(-self[0], -self[1])
    285     def __abs__(self):
    286         return (self[0]**2 + self[1]**2)**0.5
    287     def rotate(self, angle):
    288         """rotate self counterclockwise by angle
    289         """
    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])
    296     def __repr__(self):
    297         return "(%.2f,%.2f)" % self
    298 
    299 
    300 ##############################################################################
    301 ### From here up to line    : Tkinter - Interface for turtle.py            ###
    302 ### May be replaced by an interface to some different graphics toolkit     ###
    303 ##############################################################################
    304 
    305 ## helper functions for Scrolled Canvas, to forward Canvas-methods
    306 ## to ScrolledCanvas class
    307 
    308 def __methodDict(cls, _dict):
    309     """helper function for Scrolled Canvas"""
    310     baseList = list(cls.__bases__)
    311     baseList.reverse()
    312     for _super in baseList:
    313         __methodDict(_super, _dict)
    314     for key, value in cls.__dict__.items():
    315         if type(value) == types.FunctionType:
    316             _dict[key] = value
    317 
    318 def __methods(cls):
    319     """helper function for Scrolled Canvas"""
    320     _dict = {}
    321     __methodDict(cls, _dict)
    322     return _dict.keys()
    323 
    324 __stringBody = (
    325     'def %(method)s(self, *args, **kw): return ' +
    326     'self.%(attribute)s.%(method)s(*args, **kw)')
    327 
    328 def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
    329     """Helper functions for Scrolled Canvas, used to forward
    330     ScrolledCanvas-methods to Tkinter.Canvas class.
    331     """
    332     _dict = {}
    333     __methodDict(toClass, _dict)
    334     for ex in _dict.keys():
    335         if ex[:1] == '_' or ex[-1:] == '_':
    336             del _dict[ex]
    337     for ex in exclude:
    338         if ex in _dict:
    339             del _dict[ex]
    340     for ex in __methods(fromClass):
    341         if ex in _dict:
    342             del _dict[ex]
    343 
    344     for method, func in _dict.items():
    345         d = {'method': method, 'func': func}
    346         if type(toPart) == types.StringType:
    347             execString = \
    348                 __stringBody % {'method' : method, 'attribute' : toPart}
    349         exec execString in d
    350         fromClass.__dict__[method] = d[method]
    351 
    352 
    353 class ScrolledCanvas(TK.Frame):
    354     """Modeled after the scrolled canvas class from Grayons's Tkinter book.
    355 
    356     Used as the default canvas, which pops up automatically when
    357     using turtle graphics functions or the Turtle class.
    358     """
    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._rootwindow = self.winfo_toplevel()
    363         self.width, self.height = width, height
    364         self.canvwidth, self.canvheight = canvwidth, canvheight
    365         self.bg = "white"
    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')
    381         self.reset()
    382         self._rootwindow.bind('<Configure>', self.onResize)
    383 
    384     def reset(self, canvwidth=None, canvheight=None, bg = None):
    385         """Adjust canvas and scrollbars according to given canvas size."""
    386         if canvwidth:
    387             self.canvwidth = canvwidth
    388         if canvheight:
    389             self.canvheight = canvheight
    390         if bg:
    391             self.bg = bg
    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) /
    396                                                                self.canvwidth)
    397         self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
    398                                                               self.canvheight)
    399         self.adjustScrolls()
    400 
    401 
    402     def adjustScrolls(self):
    403         """ Adjust scrollbars according to window- and canvas-size.
    404         """
    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')
    414         else:
    415             self.hscroll.grid_forget()
    416             self.vscroll.grid_forget()
    417 
    418     def onResize(self, event):
    419         """self-explanatory"""
    420         self.adjustScrolls()
    421 
    422     def bbox(self, *args):
    423         """ 'forward' method, which canvas itself has inherited...
    424         """
    425         return self._canvas.bbox(*args)
    426 
    427     def cget(self, *args, **kwargs):
    428         """ 'forward' method, which canvas itself has inherited...
    429         """
    430         return self._canvas.cget(*args, **kwargs)
    431 
    432     def config(self, *args, **kwargs):
    433         """ 'forward' method, which canvas itself has inherited...
    434         """
    435         self._canvas.config(*args, **kwargs)
    436 
    437     def bind(self, *args, **kwargs):
    438         """ 'forward' method, which canvas itself has inherited...
    439         """
    440         self._canvas.bind(*args, **kwargs)
    441 
    442     def unbind(self, *args, **kwargs):
    443         """ 'forward' method, which canvas itself has inherited...
    444         """
    445         self._canvas.unbind(*args, **kwargs)
    446 
    447     def focus_force(self):
    448         """ 'forward' method, which canvas itself has inherited...
    449         """
    450         self._canvas.focus_force()
    451 
    452 __forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
    453 
    454 
    455 class _Root(TK.Tk):
    456     """Root class for Screen based on Tkinter."""
    457     def __init__(self):
    458         TK.Tk.__init__(self)
    459 
    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")
    463 
    464     def _getcanvas(self):
    465         return self._canvas
    466 
    467     def set_geometry(self, width, height, startx, starty):
    468         self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
    469 
    470     def ondestroy(self, destroy):
    471         self.wm_protocol("WM_DELETE_WINDOW", destroy)
    472 
    473     def win_width(self):
    474         return self.winfo_screenwidth()
    475 
    476     def win_height(self):
    477         return self.winfo_screenheight()
    478 
    479 Canvas = TK.Canvas
    480 
    481 
    482 class TurtleScreenBase(object):
    483     """Provide the basic graphics functionality.
    484        Interface between Tkinter and turtle.py.
    485 
    486        To port turtle.py to some different graphics toolkit
    487        a corresponding TurtleScreenBase class has to be implemented.
    488     """
    489 
    490     @staticmethod
    491     def _blankimage():
    492         """return a blank image object
    493         """
    494         img = TK.PhotoImage(width=1, height=1)
    495         img.blank()
    496         return img
    497 
    498     @staticmethod
    499     def _image(filename):
    500         """return an image object containing the
    501         imagedata from a gif-file named filename.
    502         """
    503         return TK.PhotoImage(file=filename)
    504 
    505     def __init__(self, cv):
    506         self.cv = 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 ))
    514         self.canvwidth = w
    515         self.canvheight = h
    516         self.xscale = self.yscale = 1.0
    517 
    518     def _createpoly(self):
    519         """Create an invisible polygon item on canvas self.cv)
    520         """
    521         return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
    522 
    523     def _drawpoly(self, polyitem, coordlist, fill=None,
    524                   outline=None, width=None, top=False):
    525         """Configure polygonitem polyitem according to provided
    526         arguments:
    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.
    533         """
    534         cl = []
    535         for x, y in coordlist:
    536             cl.append(x * self.xscale)
    537             cl.append(-y * self.yscale)
    538         self.cv.coords(polyitem, *cl)
    539         if fill is not None:
    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)
    545         if top:
    546             self.cv.tag_raise(polyitem)
    547 
    548     def _createline(self):
    549         """Create an invisible line item on canvas self.cv)
    550         """
    551         return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
    552                                    capstyle = TK.ROUND)
    553 
    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.
    563         """
    564         if coordlist is not None:
    565             cl = []
    566             for x, y in coordlist:
    567                 cl.append(x * self.xscale)
    568                 cl.append(-y * self.yscale)
    569             self.cv.coords(lineitem, *cl)
    570         if fill is not None:
    571             self.cv.itemconfigure(lineitem, fill=fill)
    572         if width is not None:
    573             self.cv.itemconfigure(lineitem, width=width)
    574         if top:
    575             self.cv.tag_raise(lineitem)
    576 
    577     def _delete(self, item):
    578         """Delete graphics item from canvas.
    579         If item is"all" delete all graphics items.
    580         """
    581         self.cv.delete(item)
    582 
    583     def _update(self):
    584         """Redraw graphics items on canvas
    585         """
    586         self.cv.update()
    587 
    588     def _delay(self, delay):
    589         """Delay subsequent canvas actions for delay ms."""
    590         self.cv.after(delay)
    591 
    592     def _iscolorstring(self, color):
    593         """Check if the string color is a legal Tkinter color string.
    594         """
    595         try:
    596             rgb = self.cv.winfo_rgb(color)
    597             ok = True
    598         except TK.TclError:
    599             ok = False
    600         return ok
    601 
    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)
    607             self._update()
    608         else:
    609             return self.cv.cget("bg")
    610 
    611     def _write(self, pos, txt, align, font, pencolor):
    612         """Write txt at pos in canvas with specified font
    613         and color.
    614         Return text item and x-coord of right bottom corner
    615         of text's bounding box."""
    616         x, y = pos
    617         x = x * self.xscale
    618         y = y * self.yscale
    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)
    623         self.cv.update()
    624         return item, x1-1
    625 
    626 ##    def _dot(self, pos, size, color):
    627 ##        """may be implemented for some other graphics toolkit"""
    628 
    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
    634         """
    635         if fun is None:
    636             self.cv.tag_unbind(item, "<Button-%s>" % num)
    637         else:
    638             def eventfun(event):
    639                 x, y = (self.cv.canvasx(event.x)/self.xscale,
    640                         -self.cv.canvasy(event.y)/self.yscale)
    641                 fun(x, y)
    642             self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
    643 
    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
    649 
    650         If a turtle is clicked, first _onclick-event will be performed,
    651         then _onscreensclick-event.
    652         """
    653         if fun is None:
    654             self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
    655         else:
    656             def eventfun(event):
    657                 x, y = (self.cv.canvasx(event.x)/self.xscale,
    658                         -self.cv.canvasy(event.y)/self.yscale)
    659                 fun(x, y)
    660             self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
    661                              eventfun, add)
    662 
    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
    668 
    669         Every sequence of mouse-move-events on a turtle is preceded by a
    670         mouse-click event on that turtle.
    671         """
    672         if fun is None:
    673             self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
    674         else:
    675             def eventfun(event):
    676                 try:
    677                     x, y = (self.cv.canvasx(event.x)/self.xscale,
    678                            -self.cv.canvasy(event.y)/self.yscale)
    679                     fun(x, y)
    680                 except BaseException:
    681                     pass
    682             self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
    683 
    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
    689 
    690         If a turtle is clicked, first _onclick-event will be performed,
    691         then _onscreensclick-event.
    692         """
    693         if fun is None:
    694             self.cv.unbind("<Button-%s>" % num)
    695         else:
    696             def eventfun(event):
    697                 x, y = (self.cv.canvasx(event.x)/self.xscale,
    698                         -self.cv.canvasy(event.y)/self.yscale)
    699                 fun(x, y)
    700             self.cv.bind("<Button-%s>" % num, eventfun, add)
    701 
    702     def _onkey(self, fun, key):
    703         """Bind fun to key-release event of key.
    704         Canvas must have focus. See method listen
    705         """
    706         if fun is None:
    707             self.cv.unbind("<KeyRelease-%s>" % key, None)
    708         else:
    709             def eventfun(event):
    710                 fun()
    711             self.cv.bind("<KeyRelease-%s>" % key, eventfun)
    712 
    713     def _listen(self):
    714         """Set focus on canvas (in order to collect key-events)
    715         """
    716         self.cv.focus_force()
    717 
    718     def _ontimer(self, fun, t):
    719         """Install a timer, which calls fun after t milliseconds.
    720         """
    721         if t == 0:
    722             self.cv.after_idle(fun)
    723         else:
    724             self.cv.after(t, fun)
    725 
    726     def _createimage(self, image):
    727         """Create and return image item on canvas.
    728         """
    729         return self.cv.create_image(0, 0, image=image)
    730 
    731     def _drawimage(self, item, pos, image):
    732         """Configure image item as to draw image object
    733         at position (x,y) on canvas)
    734         """
    735         x, y = pos
    736         self.cv.coords(item, (x * self.xscale, -y * self.yscale))
    737         self.cv.itemconfig(item, image=image)
    738 
    739     def _setbgpic(self, item, image):
    740         """Configure image item as to draw image object
    741         at center of canvas. Set item to the first item
    742         in the displaylist, so it will be drawn below
    743         any other item ."""
    744         self.cv.itemconfig(item, image=image)
    745         self.cv.tag_lower(item)
    746 
    747     def _type(self, item):
    748         """Return 'line' or 'polygon' or 'image' depending on
    749         type of item.
    750         """
    751         return self.cv.type(item)
    752 
    753     def _pointlist(self, item):
    754         """returns list of coordinate-pairs of points of item
    755         Example (for insiders):
    756         >>> from turtle import *
    757         >>> getscreen()._pointlist(getturtle().turtle._item)
    758         [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
    759         (9.9999999999999982, 0.0)]
    760         >>> """
    761         cl = self.cv.coords(item)
    762         pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
    763         return  pl
    764 
    765     def _setscrollregion(self, srx1, sry1, srx2, sry2):
    766         self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
    767 
    768     def _rescale(self, xscalefactor, yscalefactor):
    769         items = self.cv.find_all()
    770         for item in items:
    771             coordinates = self.cv.coords(item)
    772             newcoordlist = []
    773             while coordinates:
    774                 x, y = coordinates[:2]
    775                 newcoordlist.append(x * xscalefactor)
    776                 newcoordlist.append(y * yscalefactor)
    777                 coordinates = coordinates[2:]
    778             self.cv.coords(item, *newcoordlist)
    779 
    780     def _resize(self, canvwidth=None, canvheight=None, bg=None):
    781         """Resize the canvas the turtles are drawing on. Does
    782         not alter the drawing window.
    783         """
    784         # needs amendment
    785         if not isinstance(self.cv, ScrolledCanvas):
    786             return self.canvwidth, self.canvheight
    787         if canvwidth is canvheight is bg is None:
    788             return self.cv.canvwidth, self.cv.canvheight
    789         if canvwidth is not None:
    790             self.canvwidth = canvwidth
    791         if canvheight is not None:
    792             self.canvheight = canvheight
    793         self.cv.reset(canvwidth, canvheight, bg)
    794 
    795     def _window_size(self):
    796         """ Return the width and height of the turtle window.
    797         """
    798         width = self.cv.winfo_width()
    799         if width <= 1:  # the window isn't managed by a geometry manager
    800             width = self.cv['width']
    801         height = self.cv.winfo_height()
    802         if height <= 1: # the window isn't managed by a geometry manager
    803             height = self.cv['height']
    804         return width, height
    805 
    806 
    807 ##############################################################################
    808 ###                  End of Tkinter - interface                            ###
    809 ##############################################################################
    810 
    811 
    812 class Terminator (Exception):
    813     """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
    814 
    815     This stops execution of a turtle graphics script.
    816     Main purpose: use in the Demo-Viewer turtle.Demo.py.
    817     """
    818     pass
    819 
    820 
    821 class TurtleGraphicsError(Exception):
    822     """Some TurtleGraphics Error
    823     """
    824 
    825 
    826 class Shape(object):
    827     """Data structure modeling shapes.
    828 
    829     attribute _type is one of "polygon", "image", "compound"
    830     attribute _data is - depending on _type a poygon-tuple,
    831     an image or a list constructed using the addcomponent method.
    832     """
    833     def __init__(self, type_, data=None):
    834         self._type = type_
    835         if type_ == "polygon":
    836             if isinstance(data, list):
    837                 data = tuple(data)
    838         elif type_ == "image":
    839             if isinstance(data, basestring):
    840                 if data.lower().endswith(".gif") and isfile(data):
    841                     data = TurtleScreen._image(data)
    842                 # else data assumed to be Photoimage
    843         elif type_ == "compound":
    844             data = []
    845         else:
    846             raise TurtleGraphicsError("There is no shape type %s" % type_)
    847         self._data = data
    848 
    849     def addcomponent(self, poly, fill, outline=None):
    850         """Add component to a shape of type compound.
    851 
    852         Arguments: poly is a polygon, i. e. a tuple of number pairs.
    853         fill is the fillcolor of the component,
    854         outline is the outline color of the component.
    855 
    856         call (for a Shapeobject namend s):
    857         --   s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
    858 
    859         Example:
    860         >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
    861         >>> s = Shape("compound")
    862         >>> s.addcomponent(poly, "red", "blue")
    863         >>> # .. add more components and then use register_shape()
    864         """
    865         if self._type != "compound":
    866             raise TurtleGraphicsError("Cannot add component to %s Shape"
    867                                                                 % self._type)
    868         if outline is None:
    869             outline = fill
    870         self._data.append([poly, fill, outline])
    871 
    872 
    873 class Tbuffer(object):
    874     """Ring buffer used as undobuffer for RawTurtle objects."""
    875     def __init__(self, bufsize=10):
    876         self.bufsize = bufsize
    877         self.buffer = [[None]] * bufsize
    878         self.ptr = -1
    879         self.cumulate = False
    880     def reset(self, bufsize=None):
    881         if bufsize is None:
    882             for i in range(self.bufsize):
    883                 self.buffer[i] = [None]
    884         else:
    885             self.bufsize = bufsize
    886             self.buffer = [[None]] * bufsize
    887         self.ptr = -1
    888     def push(self, item):
    889         if self.bufsize > 0:
    890             if not self.cumulate:
    891                 self.ptr = (self.ptr + 1) % self.bufsize
    892                 self.buffer[self.ptr] = item
    893             else:
    894                 self.buffer[self.ptr].append(item)
    895     def pop(self):
    896         if self.bufsize > 0:
    897             item = self.buffer[self.ptr]
    898             if item is None:
    899                 return None
    900             else:
    901                 self.buffer[self.ptr] = [None]
    902                 self.ptr = (self.ptr - 1) % self.bufsize
    903                 return (item)
    904     def nr_of_items(self):
    905         return self.bufsize - self.buffer.count([None])
    906     def __repr__(self):
    907         return str(self.buffer) + " " + str(self.ptr)
    908 
    909 
    910 
    911 class TurtleScreen(TurtleScreenBase):
    912     """Provides screen oriented methods like setbg etc.
    913 
    914     Only relies upon the methods of TurtleScreenBase and NOT
    915     upon components of the underlying graphics toolkit -
    916     which is Tkinter in this case.
    917     """
    918 #    _STANDARD_DELAY = 5
    919     _RUNNING = True
    920 
    921     def __init__(self, cv, mode=_CFG["mode"],
    922                  colormode=_CFG["colormode"], delay=_CFG["delay"]):
    923         self._shapes = {
    924                    "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
    925                   "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
    926                               (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
    927                               (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
    928                               (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
    929                               (2,14))),
    930                   "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
    931                               (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
    932                               (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
    933                               (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
    934                               (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
    935                               (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
    936                   "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
    937                               (-10,-10))),
    938                 "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
    939                               (-10,-5.77))),
    940                   "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
    941                    "blank" : Shape("image", self._blankimage())
    942                   }
    943 
    944         self._bgpics = {"nopic" : ""}
    945 
    946         TurtleScreenBase.__init__(self, cv)
    947         self._mode = mode
    948         self._delayvalue = delay
    949         self._colormode = _CFG["colormode"]
    950         self._keys = []
    951         self.clear()
    952 
    953     def clear(self):
    954         """Delete all drawings and all turtles from the TurtleScreen.
    955 
    956         Reset empty TurtleScreen to its initial state: white background,
    957         no backgroundimage, no eventbindings and tracing on.
    958 
    959         No argument.
    960 
    961         Example (for a TurtleScreen instance named screen):
    962         >>> screen.clear()
    963 
    964         Note: this method is not available as function.
    965         """
    966         self._delayvalue = _CFG["delay"]
    967         self._colormode = _CFG["colormode"]
    968         self._delete("all")
    969         self._bgpic = self._createimage("")
    970         self._bgpicname = "nopic"
    971         self._tracing = 1
    972         self._updatecounter = 0
    973         self._turtles = []
    974         self.bgcolor("white")
    975         for btn in 1, 2, 3:
    976             self.onclick(None, btn)
    977         for key in self._keys[:]:
    978             self.onkey(None, key)
    979         Turtle._pen = None
    980 
    981     def mode(self, mode=None):
    982         """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
    983 
    984         Optional argument:
    985         mode -- one of the strings 'standard', 'logo' or 'world'
    986 
    987         Mode 'standard' is compatible with turtle.py.
    988         Mode 'logo' is compatible with most Logo-Turtle-Graphics.
    989         Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
    990         this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
    991         If mode is not given, return the current mode.
    992 
    993              Mode      Initial turtle heading     positive angles
    994          ------------|-------------------------|-------------------
    995           'standard'    to the right (east)       counterclockwise
    996             'logo'        upward    (north)         clockwise
    997 
    998         Examples:
    999         >>> mode('logo')   # resets turtle heading to north
   1000         >>> mode()
   1001         'logo'
   1002         """
   1003         if mode is None:
   1004             return self._mode
   1005         mode = mode.lower()
   1006         if mode not in ["standard", "logo", "world"]:
   1007             raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
   1008         self._mode = mode
   1009         if mode in ["standard", "logo"]:
   1010             self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
   1011                                        self.canvwidth//2, self.canvheight//2)
   1012             self.xscale = self.yscale = 1.0
   1013         self.reset()
   1014 
   1015     def setworldcoordinates(self, llx, lly, urx, ury):
   1016         """Set up a user defined coordinate-system.
   1017 
   1018         Arguments:
   1019         llx -- a number, x-coordinate of lower left corner of canvas
   1020         lly -- a number, y-coordinate of lower left corner of canvas
   1021         urx -- a number, x-coordinate of upper right corner of canvas
   1022         ury -- a number, y-coordinate of upper right corner of canvas
   1023 
   1024         Set up user coodinat-system and switch to mode 'world' if necessary.
   1025         This performs a screen.reset. If mode 'world' is already active,
   1026         all drawings are redrawn according to the new coordinates.
   1027 
   1028         But ATTENTION: in user-defined coordinatesystems angles may appear
   1029         distorted. (see Screen.mode())
   1030 
   1031         Example (for a TurtleScreen instance named screen):
   1032         >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
   1033         >>> for _ in range(36):
   1034         ...     left(10)
   1035         ...     forward(0.5)
   1036         """
   1037         if self.mode() != "world":
   1038             self.mode("world")
   1039         xspan = float(urx - llx)
   1040         yspan = float(ury - lly)
   1041         wx, wy = self._window_size()
   1042         self.screensize(wx-20, wy-20)
   1043         oldxscale, oldyscale = self.xscale, self.yscale
   1044         self.xscale = self.canvwidth / xspan
   1045         self.yscale = self.canvheight / yspan
   1046         srx1 = llx * self.xscale
   1047         sry1 = -ury * self.yscale
   1048         srx2 = self.canvwidth + srx1
   1049         sry2 = self.canvheight + sry1
   1050         self._setscrollregion(srx1, sry1, srx2, sry2)
   1051         self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
   1052         self.update()
   1053 
   1054     def register_shape(self, name, shape=None):
   1055         """Adds a turtle shape to TurtleScreen's shapelist.
   1056 
   1057         Arguments:
   1058         (1) name is the name of a gif-file and shape is None.
   1059             Installs the corresponding image shape.
   1060             !! Image-shapes DO NOT rotate when turning the turtle,
   1061             !! so they do not display the heading of the turtle!
   1062         (2) name is an arbitrary string and shape is a tuple
   1063             of pairs of coordinates. Installs the corresponding
   1064             polygon shape
   1065         (3) name is an arbitrary string and shape is a
   1066             (compound) Shape object. Installs the corresponding
   1067             compound shape.
   1068         To use a shape, you have to issue the command shape(shapename).
   1069 
   1070         call: register_shape("turtle.gif")
   1071         --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
   1072 
   1073         Example (for a TurtleScreen instance named screen):
   1074         >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
   1075 
   1076         """
   1077         if shape is None:
   1078             # image
   1079             if name.lower().endswith(".gif"):
   1080                 shape = Shape("image", self._image(name))
   1081             else:
   1082                 raise TurtleGraphicsError("Bad arguments for register_shape.\n"
   1083                                           + "Use  help(register_shape)" )
   1084         elif isinstance(shape, tuple):
   1085             shape = Shape("polygon", shape)
   1086         ## else shape assumed to be Shape-instance
   1087         self._shapes[name] = shape
   1088         # print "shape added:" , self._shapes
   1089 
   1090     def _colorstr(self, color):
   1091         """Return color string corresponding to args.
   1092 
   1093         Argument may be a string or a tuple of three
   1094         numbers corresponding to actual colormode,
   1095         i.e. in the range 0<=n<=colormode.
   1096 
   1097         If the argument doesn't represent a color,
   1098         an error is raised.
   1099         """
   1100         if len(color) == 1:
   1101             color = color[0]
   1102         if isinstance(color, basestring):
   1103             if self._iscolorstring(color) or color == "":
   1104                 return color
   1105             else:
   1106                 raise TurtleGraphicsError("bad color string: %s" % str(color))
   1107         try:
   1108             r, g, b = color
   1109         except (TypeError, ValueError):
   1110             raise TurtleGraphicsError("bad color arguments: %s" % str(color))
   1111         if self._colormode == 1.0:
   1112             r, g, b = [round(255.0*x) for x in (r, g, b)]
   1113         if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
   1114             raise TurtleGraphicsError("bad color sequence: %s" % str(color))
   1115         return "#%02x%02x%02x" % (r, g, b)
   1116 
   1117     def _color(self, cstr):
   1118         if not cstr.startswith("#"):
   1119             return cstr
   1120         if len(cstr) == 7:
   1121             cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
   1122         elif len(cstr) == 4:
   1123             cl = [16*int(cstr[h], 16) for h in cstr[1:]]
   1124         else:
   1125             raise TurtleGraphicsError("bad colorstring: %s" % cstr)
   1126         return tuple([c * self._colormode/255 for c in cl])
   1127 
   1128     def colormode(self, cmode=None):
   1129         """Return the colormode or set it to 1.0 or 255.
   1130 
   1131         Optional argument:
   1132         cmode -- one of the values 1.0 or 255
   1133 
   1134         r, g, b values of colortriples have to be in range 0..cmode.
   1135 
   1136         Example (for a TurtleScreen instance named screen):
   1137         >>> screen.colormode()
   1138         1.0
   1139         >>> screen.colormode(255)
   1140         >>> pencolor(240,160,80)
   1141         """
   1142         if cmode is None:
   1143             return self._colormode
   1144         if cmode == 1.0:
   1145             self._colormode = float(cmode)
   1146         elif cmode == 255:
   1147             self._colormode = int(cmode)
   1148 
   1149     def reset(self):
   1150         """Reset all Turtles on the Screen to their initial state.
   1151 
   1152         No argument.
   1153 
   1154         Example (for a TurtleScreen instance named screen):
   1155         >>> screen.reset()
   1156         """
   1157         for turtle in self._turtles:
   1158             turtle._setmode(self._mode)
   1159             turtle.reset()
   1160 
   1161     def turtles(self):
   1162         """Return the list of turtles on the screen.
   1163 
   1164         Example (for a TurtleScreen instance named screen):
   1165         >>> screen.turtles()
   1166         [<turtle.Turtle object at 0x00E11FB0>]
   1167         """
   1168         return self._turtles
   1169 
   1170     def bgcolor(self, *args):
   1171         """Set or return backgroundcolor of the TurtleScreen.
   1172 
   1173         Arguments (if given): a color string or three numbers
   1174         in the range 0..colormode or a 3-tuple of such numbers.
   1175 
   1176         Example (for a TurtleScreen instance named screen):
   1177         >>> screen.bgcolor("orange")
   1178         >>> screen.bgcolor()
   1179         'orange'
   1180         >>> screen.bgcolor(0.5,0,0.5)
   1181         >>> screen.bgcolor()
   1182         '#800080'
   1183         """
   1184         if args:
   1185             color = self._colorstr(args)
   1186         else:
   1187             color = None
   1188         color = self._bgcolor(color)
   1189         if color is not None:
   1190             color = self._color(color)
   1191         return color
   1192 
   1193     def tracer(self, n=None, delay=None):
   1194         """Turns turtle animation on/off and set delay for update drawings.
   1195 
   1196         Optional arguments:
   1197         n -- nonnegative  integer
   1198         delay -- nonnegative  integer
   1199 
   1200         If n is given, only each n-th regular screen update is really performed.
   1201         (Can be used to accelerate the drawing of complex graphics.)
   1202         Second arguments sets delay value (see RawTurtle.delay())
   1203 
   1204         Example (for a TurtleScreen instance named screen):
   1205         >>> screen.tracer(8, 25)
   1206         >>> dist = 2
   1207         >>> for i in range(200):
   1208         ...     fd(dist)
   1209         ...     rt(90)
   1210         ...     dist += 2
   1211         """
   1212         if n is None:
   1213             return self._tracing
   1214         self._tracing = int(n)
   1215         self._updatecounter = 0
   1216         if delay is not None:
   1217             self._delayvalue = int(delay)
   1218         if self._tracing:
   1219             self.update()
   1220 
   1221     def delay(self, delay=None):
   1222         """ Return or set the drawing delay in milliseconds.
   1223 
   1224         Optional argument:
   1225         delay -- positive integer
   1226 
   1227         Example (for a TurtleScreen instance named screen):
   1228         >>> screen.delay(15)
   1229         >>> screen.delay()
   1230         15
   1231         """
   1232         if delay is None:
   1233             return self._delayvalue
   1234         self._delayvalue = int(delay)
   1235 
   1236     def _incrementudc(self):
   1237         """Increment update counter."""
   1238         if not TurtleScreen._RUNNING:
   1239             TurtleScreen._RUNNING = True
   1240             raise Terminator
   1241         if self._tracing > 0:
   1242             self._updatecounter += 1
   1243             self._updatecounter %= self._tracing
   1244 
   1245     def update(self):
   1246         """Perform a TurtleScreen update.
   1247         """
   1248         tracing = self._tracing
   1249         self._tracing = True
   1250         for t in self.turtles():
   1251             t._update_data()
   1252             t._drawturtle()
   1253         self._tracing = tracing
   1254         self._update()
   1255 
   1256     def window_width(self):
   1257         """ Return the width of the turtle window.
   1258 
   1259         Example (for a TurtleScreen instance named screen):
   1260         >>> screen.window_width()
   1261         640
   1262         """
   1263         return self._window_size()[0]
   1264 
   1265     def window_height(self):
   1266         """ Return the height of the turtle window.
   1267 
   1268         Example (for a TurtleScreen instance named screen):
   1269         >>> screen.window_height()
   1270         480
   1271         """
   1272         return self._window_size()[1]
   1273 
   1274     def getcanvas(self):
   1275         """Return the Canvas of this TurtleScreen.
   1276 
   1277         No argument.
   1278 
   1279         Example (for a Screen instance named screen):
   1280         >>> cv = screen.getcanvas()
   1281         >>> cv
   1282         <turtle.ScrolledCanvas instance at 0x010742D8>
   1283         """
   1284         return self.cv
   1285 
   1286     def getshapes(self):
   1287         """Return a list of names of all currently available turtle shapes.
   1288 
   1289         No argument.
   1290 
   1291         Example (for a TurtleScreen instance named screen):
   1292         >>> screen.getshapes()
   1293         ['arrow', 'blank', 'circle', ... , 'turtle']
   1294         """
   1295         return sorted(self._shapes.keys())
   1296 
   1297     def onclick(self, fun, btn=1, add=None):
   1298         """Bind fun to mouse-click event on canvas.
   1299 
   1300         Arguments:
   1301         fun -- a function with two arguments, the coordinates of the
   1302                clicked point on the canvas.
   1303         num -- the number of the mouse-button, defaults to 1
   1304 
   1305         Example (for a TurtleScreen instance named screen
   1306         and a Turtle instance named turtle):
   1307 
   1308         >>> screen.onclick(goto)
   1309         >>> # Subsequently clicking into the TurtleScreen will
   1310         >>> # make the turtle move to the clicked point.
   1311         >>> screen.onclick(None)
   1312         """
   1313         self._onscreenclick(fun, btn, add)
   1314 
   1315     def onkey(self, fun, key):
   1316         """Bind fun to key-release event of key.
   1317 
   1318         Arguments:
   1319         fun -- a function with no arguments
   1320         key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
   1321 
   1322         In order to be able to register key-events, TurtleScreen
   1323         must have focus. (See method listen.)
   1324 
   1325         Example (for a TurtleScreen instance named screen):
   1326 
   1327         >>> def f():
   1328         ...     fd(50)
   1329         ...     lt(60)
   1330         ...
   1331         >>> screen.onkey(f, "Up")
   1332         >>> screen.listen()
   1333 
   1334         Subsequently the turtle can be moved by repeatedly pressing
   1335         the up-arrow key, consequently drawing a hexagon
   1336 
   1337         """
   1338         if fun is None:
   1339             if key in self._keys:
   1340                 self._keys.remove(key)
   1341         elif key not in self._keys:
   1342             self._keys.append(key)
   1343         self._onkey(fun, key)
   1344 
   1345     def listen(self, xdummy=None, ydummy=None):
   1346         """Set focus on TurtleScreen (in order to collect key-events)
   1347 
   1348         No arguments.
   1349         Dummy arguments are provided in order
   1350         to be able to pass listen to the onclick method.
   1351 
   1352         Example (for a TurtleScreen instance named screen):
   1353         >>> screen.listen()
   1354         """
   1355         self._listen()
   1356 
   1357     def ontimer(self, fun, t=0):
   1358         """Install a timer, which calls fun after t milliseconds.
   1359 
   1360         Arguments:
   1361         fun -- a function with no arguments.
   1362         t -- a number >= 0
   1363 
   1364         Example (for a TurtleScreen instance named screen):
   1365 
   1366         >>> running = True
   1367         >>> def f():
   1368         ...     if running:
   1369         ...             fd(50)
   1370         ...             lt(60)
   1371         ...             screen.ontimer(f, 250)
   1372         ...
   1373         >>> f()   # makes the turtle marching around
   1374         >>> running = False
   1375         """
   1376         self._ontimer(fun, t)
   1377 
   1378     def bgpic(self, picname=None):
   1379         """Set background image or return name of current backgroundimage.
   1380 
   1381         Optional argument:
   1382         picname -- a string, name of a gif-file or "nopic".
   1383 
   1384         If picname is a filename, set the corresponding image as background.
   1385         If picname is "nopic", delete backgroundimage, if present.
   1386         If picname is None, return the filename of the current backgroundimage.
   1387 
   1388         Example (for a TurtleScreen instance named screen):
   1389         >>> screen.bgpic()
   1390         'nopic'
   1391         >>> screen.bgpic("landscape.gif")
   1392         >>> screen.bgpic()
   1393         'landscape.gif'
   1394         """
   1395         if picname is None:
   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
   1401 
   1402     def screensize(self, canvwidth=None, canvheight=None, bg=None):
   1403         """Resize the canvas the turtles are drawing on.
   1404 
   1405         Optional arguments:
   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-tuple, new backgroundcolor
   1409         If no arguments are given, return current (canvaswidth, canvasheight)
   1410 
   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!)
   1414 
   1415         Example (for a Turtle instance named turtle):
   1416         >>> turtle.screensize(2000,1500)
   1417         >>> # e. g. to search for an erroneously escaped turtle ;-)
   1418         """
   1419         return self._resize(canvwidth, canvheight, bg)
   1420 
   1421     onscreenclick = onclick
   1422     resetscreen = reset
   1423     clearscreen = clear
   1424     addshape = register_shape
   1425 
   1426 class TNavigator(object):
   1427     """Navigation part of the RawTurtle.
   1428     Implements methods for turtle movement.
   1429     """
   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
   1437 
   1438     def __init__(self, mode=DEFAULT_MODE):
   1439         self._angleOffset = self.DEFAULT_ANGLEOFFSET
   1440         self._angleOrient = self.DEFAULT_ANGLEORIENT
   1441         self._mode = mode
   1442         self.undobuffer = None
   1443         self.degrees()
   1444         self._mode = None
   1445         self._setmode(mode)
   1446         TNavigator.reset(self)
   1447 
   1448     def reset(self):
   1449         """reset turtle to its initial values
   1450 
   1451         Will be overwritten by parent class
   1452         """
   1453         self._position = Vec2D(0.0, 0.0)
   1454         self._orient =  TNavigator.START_ORIENTATION[self._mode]
   1455 
   1456     def _setmode(self, mode=None):
   1457         """Set turtle-mode to 'standard', 'world' or 'logo'.
   1458         """
   1459         if mode is None:
   1460             return self._mode
   1461         if mode not in ["standard", "logo", "world"]:
   1462             return
   1463         self._mode = mode
   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
   1470 
   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
   1477         else:
   1478             self._angleOffset = fullcircle/4.
   1479 
   1480     def degrees(self, fullcircle=360.0):
   1481         """ Set angle measurement units to degrees.
   1482 
   1483         Optional argument:
   1484         fullcircle -  a number
   1485 
   1486         Set angle measurement units, i. e. set number
   1487         of 'degrees' for a full circle. Dafault value is
   1488         360 degrees.
   1489 
   1490         Example (for a Turtle instance named turtle):
   1491         >>> turtle.left(90)
   1492         >>> turtle.heading()
   1493         90
   1494 
   1495         Change angle measurement unit to grad (also known as gon,
   1496         grade, or gradian and equals 1/100-th of the right angle.)
   1497         >>> turtle.degrees(400.0)
   1498         >>> turtle.heading()
   1499         100
   1500 
   1501         """
   1502         self._setDegreesPerAU(fullcircle)
   1503 
   1504     def radians(self):
   1505         """ Set the angle measurement units to radians.
   1506 
   1507         No arguments.
   1508 
   1509         Example (for a Turtle instance named turtle):
   1510         >>> turtle.heading()
   1511         90
   1512         >>> turtle.radians()
   1513         >>> turtle.heading()
   1514         1.5707963267948966
   1515         """
   1516         self._setDegreesPerAU(2*math.pi)
   1517 
   1518     def _go(self, distance):
   1519         """move turtle forward by specified distance"""
   1520         ende = self._position + self._orient * distance
   1521         self._goto(ende)
   1522 
   1523     def _rotate(self, angle):
   1524         """Turn turtle counterclockwise by specified angle if angle > 0."""
   1525         angle *= self._degreesPerAU
   1526         self._orient = self._orient.rotate(angle)
   1527 
   1528     def _goto(self, end):
   1529         """move turtle to position end."""
   1530         self._position = end
   1531 
   1532     def forward(self, distance):
   1533         """Move the turtle forward by the specified distance.
   1534 
   1535         Aliases: forward | fd
   1536 
   1537         Argument:
   1538         distance -- a number (integer or float)
   1539 
   1540         Move the turtle forward by the specified distance, in the direction
   1541         the turtle is headed.
   1542 
   1543         Example (for a Turtle instance named turtle):
   1544         >>> turtle.position()
   1545         (0.00, 0.00)
   1546         >>> turtle.forward(25)
   1547         >>> turtle.position()
   1548         (25.00,0.00)
   1549         >>> turtle.forward(-75)
   1550         >>> turtle.position()
   1551         (-50.00,0.00)
   1552         """
   1553         self._go(distance)
   1554 
   1555     def back(self, distance):
   1556         """Move the turtle backward by distance.
   1557 
   1558         Aliases: back | backward | bk
   1559 
   1560         Argument:
   1561         distance -- a number
   1562 
   1563         Move the turtle backward by distance ,opposite to the direction the
   1564         turtle is headed. Do not change the turtle's heading.
   1565 
   1566         Example (for a Turtle instance named turtle):
   1567         >>> turtle.position()
   1568         (0.00, 0.00)
   1569         >>> turtle.backward(30)
   1570         >>> turtle.position()
   1571         (-30.00, 0.00)
   1572         """
   1573         self._go(-distance)
   1574 
   1575     def right(self, angle):
   1576         """Turn turtle right by angle units.
   1577 
   1578         Aliases: right | rt
   1579 
   1580         Argument:
   1581         angle -- a number (integer or float)
   1582 
   1583         Turn turtle right by angle units. (Units are by default degrees,
   1584         but can be set via the degrees() and radians() functions.)
   1585         Angle orientation depends on mode. (See this.)
   1586 
   1587         Example (for a Turtle instance named turtle):
   1588         >>> turtle.heading()
   1589         22.0
   1590         >>> turtle.right(45)
   1591         >>> turtle.heading()
   1592         337.0
   1593         """
   1594         self._rotate(-angle)
   1595 
   1596     def left(self, angle):
   1597         """Turn turtle left by angle units.
   1598 
   1599         Aliases: left | lt
   1600 
   1601         Argument:
   1602         angle -- a number (integer or float)
   1603 
   1604         Turn turtle left by angle units. (Units are by default degrees,
   1605         but can be set via the degrees() and radians() functions.)
   1606         Angle orientation depends on mode. (See this.)
   1607 
   1608         Example (for a Turtle instance named turtle):
   1609         >>> turtle.heading()
   1610         22.0
   1611         >>> turtle.left(45)
   1612         >>> turtle.heading()
   1613         67.0
   1614         """
   1615         self._rotate(angle)
   1616 
   1617     def pos(self):
   1618         """Return the turtle's current location (x,y), as a Vec2D-vector.
   1619 
   1620         Aliases: pos | position
   1621 
   1622         No arguments.
   1623 
   1624         Example (for a Turtle instance named turtle):
   1625         >>> turtle.pos()
   1626         (0.00, 240.00)
   1627         """
   1628         return self._position
   1629 
   1630     def xcor(self):
   1631         """ Return the turtle's x coordinate.
   1632 
   1633         No arguments.
   1634 
   1635         Example (for a Turtle instance named turtle):
   1636         >>> reset()
   1637         >>> turtle.left(60)
   1638         >>> turtle.forward(100)
   1639         >>> print turtle.xcor()
   1640         50.0
   1641         """
   1642         return self._position[0]
   1643 
   1644     def ycor(self):
   1645         """ Return the turtle's y coordinate
   1646         ---
   1647         No arguments.
   1648 
   1649         Example (for a Turtle instance named turtle):
   1650         >>> reset()
   1651         >>> turtle.left(60)
   1652         >>> turtle.forward(100)
   1653         >>> print turtle.ycor()
   1654         86.6025403784
   1655         """
   1656         return self._position[1]
   1657 
   1658 
   1659     def goto(self, x, y=None):
   1660         """Move turtle to an absolute position.
   1661 
   1662         Aliases: setpos | setposition | goto:
   1663 
   1664         Arguments:
   1665         x -- a number      or     a pair/vector of numbers
   1666         y -- a number             None
   1667 
   1668         call: goto(x, y)         # two coordinates
   1669         --or: goto((x, y))       # a pair (tuple) of coordinates
   1670         --or: goto(vec)          # e.g. as returned by pos()
   1671 
   1672         Move turtle to an absolute position. If the pen is down,
   1673         a line will be drawn. The turtle's orientation does not change.
   1674 
   1675         Example (for a Turtle instance named turtle):
   1676         >>> tp = turtle.pos()
   1677         >>> tp
   1678         (0.00, 0.00)
   1679         >>> turtle.setpos(60,30)
   1680         >>> turtle.pos()
   1681         (60.00,30.00)
   1682         >>> turtle.setpos((20,80))
   1683         >>> turtle.pos()
   1684         (20.00,80.00)
   1685         >>> turtle.setpos(tp)
   1686         >>> turtle.pos()
   1687         (0.00,0.00)
   1688         """
   1689         if y is None:
   1690             self._goto(Vec2D(*x))
   1691         else:
   1692             self._goto(Vec2D(x, y))
   1693 
   1694     def home(self):
   1695         """Move turtle to the origin - coordinates (0,0).
   1696 
   1697         No arguments.
   1698 
   1699         Move turtle to the origin - coordinates (0,0) and set its
   1700         heading to its start-orientation (which depends on mode).
   1701 
   1702         Example (for a Turtle instance named turtle):
   1703         >>> turtle.home()
   1704         """
   1705         self.goto(0, 0)
   1706         self.setheading(0)
   1707 
   1708     def setx(self, x):
   1709         """Set the turtle's first coordinate to x
   1710 
   1711         Argument:
   1712         x -- a number (integer or float)
   1713 
   1714         Set the turtle's first coordinate to x, leave second coordinate
   1715         unchanged.
   1716 
   1717         Example (for a Turtle instance named turtle):
   1718         >>> turtle.position()
   1719         (0.00, 240.00)
   1720         >>> turtle.setx(10)
   1721         >>> turtle.position()
   1722         (10.00, 240.00)
   1723         """
   1724         self._goto(Vec2D(x, self._position[1]))
   1725 
   1726     def sety(self, y):
   1727         """Set the turtle's second coordinate to y
   1728 
   1729         Argument:
   1730         y -- a number (integer or float)
   1731 
   1732         Set the turtle's first coordinate to x, second coordinate remains
   1733         unchanged.
   1734 
   1735         Example (for a Turtle instance named turtle):
   1736         >>> turtle.position()
   1737         (0.00, 40.00)
   1738         >>> turtle.sety(-10)
   1739         >>> turtle.position()
   1740         (0.00, -10.00)
   1741         """
   1742         self._goto(Vec2D(self._position[0], y))
   1743 
   1744     def distance(self, x, y=None):
   1745         """Return the distance from the turtle to (x,y) in turtle step units.
   1746 
   1747         Arguments:
   1748         x -- a number   or  a pair/vector of numbers   or   a turtle instance
   1749         y -- a number       None                            None
   1750 
   1751         call: distance(x, y)         # two coordinates
   1752         --or: distance((x, y))       # a pair (tuple) of coordinates
   1753         --or: distance(vec)          # e.g. as returned by pos()
   1754         --or: distance(mypen)        # where mypen is another turtle
   1755 
   1756         Example (for a Turtle instance named turtle):
   1757         >>> turtle.pos()
   1758         (0.00, 0.00)
   1759         >>> turtle.distance(30,40)
   1760         50.0
   1761         >>> pen = Turtle()
   1762         >>> pen.forward(77)
   1763         >>> turtle.distance(pen)
   1764         77.0
   1765         """
   1766         if y is not None:
   1767             pos = Vec2D(x, y)
   1768         if isinstance(x, Vec2D):
   1769             pos = x
   1770         elif isinstance(x, tuple):
   1771             pos = Vec2D(*x)
   1772         elif isinstance(x, TNavigator):
   1773             pos = x._position
   1774         return abs(pos - self._position)
   1775 
   1776     def towards(self, x, y=None):
   1777         """Return the angle of the line from the turtle's position to (x, y).
   1778 
   1779         Arguments:
   1780         x -- a number   or  a pair/vector of numbers   or   a turtle instance
   1781         y -- a number       None                            None
   1782 
   1783         call: distance(x, y)         # two coordinates
   1784         --or: distance((x, y))       # a pair (tuple) of coordinates
   1785         --or: distance(vec)          # e.g. as returned by pos()
   1786         --or: distance(mypen)        # where mypen is another turtle
   1787 
   1788         Return the angle, between the line from turtle-position to position
   1789         specified by x, y and the turtle's start orientation. (Depends on
   1790         modes - "standard" or "logo")
   1791 
   1792         Example (for a Turtle instance named turtle):
   1793         >>> turtle.pos()
   1794         (10.00, 10.00)
   1795         >>> turtle.towards(0,0)
   1796         225.0
   1797         """
   1798         if y is not None:
   1799             pos = Vec2D(x, y)
   1800         if isinstance(x, Vec2D):
   1801             pos = x
   1802         elif isinstance(x, tuple):
   1803             pos = Vec2D(*x)
   1804         elif isinstance(x, TNavigator):
   1805             pos = x._position
   1806         x, y = pos - self._position
   1807         result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
   1808         result /= self._degreesPerAU
   1809         return (self._angleOffset + self._angleOrient*result) % self._fullcircle
   1810 
   1811     def heading(self):
   1812         """ Return the turtle's current heading.
   1813 
   1814         No arguments.
   1815 
   1816         Example (for a Turtle instance named turtle):
   1817         >>> turtle.left(67)
   1818         >>> turtle.heading()
   1819         67.0
   1820         """
   1821         x, y = self._orient
   1822         result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
   1823         result /= self._degreesPerAU
   1824         return (self._angleOffset + self._angleOrient*result) % self._fullcircle
   1825 
   1826     def setheading(self, to_angle):
   1827         """Set the orientation of the turtle to to_angle.
   1828 
   1829         Aliases:  setheading | seth
   1830 
   1831         Argument:
   1832         to_angle -- a number (integer or float)
   1833 
   1834         Set the orientation of the turtle to to_angle.
   1835         Here are some common directions in degrees:
   1836 
   1837          standard - mode:          logo-mode:
   1838         -------------------|--------------------
   1839            0 - east                0 - north
   1840           90 - north              90 - east
   1841          180 - west              180 - south
   1842          270 - south             270 - west
   1843 
   1844         Example (for a Turtle instance named turtle):
   1845         >>> turtle.setheading(90)
   1846         >>> turtle.heading()
   1847         90
   1848         """
   1849         angle = (to_angle - self.heading())*self._angleOrient
   1850         full = self._fullcircle
   1851         angle = (angle+full/2.)%full - full/2.
   1852         self._rotate(angle)
   1853 
   1854     def circle(self, radius, extent = None, steps = None):
   1855         """ Draw a circle with given radius.
   1856 
   1857         Arguments:
   1858         radius -- a number
   1859         extent (optional) -- a number
   1860         steps (optional) -- an integer
   1861 
   1862         Draw a circle with given radius. The center is radius units left
   1863         of the turtle; extent - an angle - determines which part of the
   1864         circle is drawn. If extent is not given, draw the entire circle.
   1865         If extent is not a full circle, one endpoint of the arc is the
   1866         current pen position. Draw the arc in counterclockwise direction
   1867         if radius is positive, otherwise in clockwise direction. Finally
   1868         the direction of the turtle is changed by the amount of extent.
   1869 
   1870         As the circle is approximated by an inscribed regular polygon,
   1871         steps determines the number of steps to use. If not given,
   1872         it will be calculated automatically. Maybe used to draw regular
   1873         polygons.
   1874 
   1875         call: circle(radius)                  # full circle
   1876         --or: circle(radius, extent)          # arc
   1877         --or: circle(radius, extent, steps)
   1878         --or: circle(radius, steps=6)         # 6-sided polygon
   1879 
   1880         Example (for a Turtle instance named turtle):
   1881         >>> turtle.circle(50)
   1882         >>> turtle.circle(120, 180)  # semicircle
   1883         """
   1884         if self.undobuffer:
   1885             self.undobuffer.push(["seq"])
   1886             self.undobuffer.cumulate = True
   1887         speed = self.speed()
   1888         if extent is None:
   1889             extent = self._fullcircle
   1890         if steps is None:
   1891             frac = abs(extent)/self._fullcircle
   1892             steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
   1893         w = 1.0 * extent / steps
   1894         w2 = 0.5 * w
   1895         l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
   1896         if radius < 0:
   1897             l, w, w2 = -l, -w, -w2
   1898         tr = self.tracer()
   1899         dl = self._delay()
   1900         if speed == 0:
   1901             self.tracer(0, 0)
   1902         else:
   1903             self.speed(0)
   1904         self._rotate(w2)
   1905         for i in range(steps):
   1906             self.speed(speed)
   1907             self._go(l)
   1908             self.speed(0)
   1909             self._rotate(w)
   1910         self._rotate(-w2)
   1911         if speed == 0:
   1912             self.tracer(tr, dl)
   1913         self.speed(speed)
   1914         if self.undobuffer:
   1915             self.undobuffer.cumulate = False
   1916 
   1917 ## three dummy methods to be implemented by child class:
   1918 
   1919     def speed(self, s=0):
   1920         """dummy method - to be overwritten by child class"""
   1921     def tracer(self, a=None, b=None):
   1922         """dummy method - to be overwritten by child class"""
   1923     def _delay(self, n=None):
   1924         """dummy method - to be overwritten by child class"""
   1925 
   1926     fd = forward
   1927     bk = back
   1928     backward = back
   1929     rt = right
   1930     lt = left
   1931     position = pos
   1932     setpos = goto
   1933     setposition = goto
   1934     seth = setheading
   1935 
   1936 
   1937 class TPen(object):
   1938     """Drawing part of the RawTurtle.
   1939     Implements drawing properties.
   1940     """
   1941     def __init__(self, resizemode=_CFG["resizemode"]):
   1942         self._resizemode = resizemode # or "user" or "noresize"
   1943         self.undobuffer = None
   1944         TPen._reset(self)
   1945 
   1946     def _reset(self, pencolor=_CFG["pencolor"],
   1947                      fillcolor=_CFG["fillcolor"]):
   1948         self._pensize = 1
   1949         self._shown = True
   1950         self._pencolor = pencolor
   1951         self._fillcolor = fillcolor
   1952         self._drawing = True
   1953         self._speed = 3
   1954         self._stretchfactor = (1, 1)
   1955         self._tilt = 0
   1956         self._outlinewidth = 1
   1957         ### self.screen = None  # to override by child class
   1958 
   1959     def resizemode(self, rmode=None):
   1960         """Set resizemode to one of the values: "auto", "user", "noresize".
   1961 
   1962         (Optional) Argument:
   1963         rmode -- one of the strings "auto", "user", "noresize"
   1964 
   1965         Different resizemodes have the following effects:
   1966           - "auto" adapts the appearance of the turtle
   1967                    corresponding to the value of pensize.
   1968           - "user" adapts the appearance of the turtle according to the
   1969                    values of stretchfactor and outlinewidth (outline),
   1970                    which are set by shapesize()
   1971           - "noresize" no adaption of the turtle's appearance takes place.
   1972         If no argument is given, return current resizemode.
   1973         resizemode("user") is called by a call of shapesize with arguments.
   1974 
   1975 
   1976         Examples (for a Turtle instance named turtle):
   1977         >>> turtle.resizemode("noresize")
   1978         >>> turtle.resizemode()
   1979         'noresize'
   1980         """
   1981         if rmode is None:
   1982             return self._resizemode
   1983         rmode = rmode.lower()
   1984         if rmode in ["auto", "user", "noresize"]:
   1985             self.pen(resizemode=rmode)
   1986 
   1987     def pensize(self, width=None):
   1988         """Set or return the line thickness.
   1989 
   1990         Aliases:  pensize | width
   1991 
   1992         Argument:
   1993         width -- positive number
   1994 
   1995         Set the line thickness to width or return it. If resizemode is set
   1996         to "auto" and turtleshape is a polygon, that polygon is drawn with
   1997         the same line thickness. If no argument is given, current pensize
   1998         is returned.
   1999 
   2000         Example (for a Turtle instance named turtle):
   2001         >>> turtle.pensize()
   2002         1
   2003         >>> turtle.pensize(10)   # from here on lines of width 10 are drawn
   2004         """
   2005         if width is None:
   2006             return self._pensize
   2007         self.pen(pensize=width)
   2008 
   2009 
   2010     def penup(self):
   2011         """Pull the pen up -- no drawing when moving.
   2012 
   2013         Aliases: penup | pu | up
   2014 
   2015         No argument
   2016 
   2017         Example (for a Turtle instance named turtle):
   2018         >>> turtle.penup()
   2019         """
   2020         if not self._drawing:
   2021             return
   2022         self.pen(pendown=False)
   2023 
   2024     def pendown(self):
   2025         """Pull the pen down -- drawing when moving.
   2026 
   2027         Aliases: pendown | pd | down
   2028 
   2029         No argument.
   2030 
   2031         Example (for a Turtle instance named turtle):
   2032         >>> turtle.pendown()
   2033         """
   2034         if self._drawing:
   2035             return
   2036         self.pen(pendown=True)
   2037 
   2038     def isdown(self):
   2039         """Return True if pen is down, False if it's up.
   2040 
   2041         No argument.
   2042 
   2043         Example (for a Turtle instance named turtle):
   2044         >>> turtle.penup()
   2045         >>> turtle.isdown()
   2046         False
   2047         >>> turtle.pendown()
   2048         >>> turtle.isdown()
   2049         True
   2050         """
   2051         return self._drawing
   2052 
   2053     def speed(self, speed=None):
   2054         """ Return or set the turtle's speed.
   2055 
   2056         Optional argument:
   2057         speed -- an integer in the range 0..10 or a speedstring (see below)
   2058 
   2059         Set the turtle's speed to an integer value in the range 0 .. 10.
   2060         If no argument is given: return current speed.
   2061 
   2062         If input is a number greater than 10 or smaller than 0.5,
   2063         speed is set to 0.
   2064         Speedstrings  are mapped to speedvalues in the following way:
   2065             'fastest' :  0
   2066             'fast'    :  10
   2067             'normal'  :  6
   2068             'slow'    :  3
   2069             'slowest' :  1
   2070         speeds from 1 to 10 enforce increasingly faster animation of
   2071         line drawing and turtle turning.
   2072 
   2073         Attention:
   2074         speed = 0 : *no* animation takes place. forward/back makes turtle jump
   2075         and likewise left/right make the turtle turn instantly.
   2076 
   2077         Example (for a Turtle instance named turtle):
   2078         >>> turtle.speed(3)
   2079         """
   2080         speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
   2081         if speed is None:
   2082             return self._speed
   2083         if speed in speeds:
   2084             speed = speeds[speed]
   2085         elif 0.5 < speed < 10.5:
   2086             speed = int(round(speed))
   2087         else:
   2088             speed = 0
   2089         self.pen(speed=speed)
   2090 
   2091     def color(self, *args):
   2092         """Return or set the pencolor and fillcolor.
   2093 
   2094         Arguments:
   2095         Several input formats are allowed.
   2096         They use 0, 1, 2, or 3 arguments as follows:
   2097 
   2098         color()
   2099             Return the current pencolor and the current fillcolor
   2100             as a pair of color specification strings as are returned
   2101             by pencolor and fillcolor.
   2102         color(colorstring), color((r,g,b)), color(r,g,b)
   2103             inputs as in pencolor, set both, fillcolor and pencolor,
   2104             to the given value.
   2105         color(colorstring1, colorstring2),
   2106         color((r1,g1,b1), (r2,g2,b2))
   2107             equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
   2108             and analogously, if the other input format is used.
   2109 
   2110         If turtleshape is a polygon, outline and interior of that polygon
   2111         is drawn with the newly set colors.
   2112         For mor info see: pencolor, fillcolor
   2113 
   2114         Example (for a Turtle instance named turtle):
   2115         >>> turtle.color('red', 'green')
   2116         >>> turtle.color()
   2117         ('red', 'green')
   2118         >>> colormode(255)
   2119         >>> color((40, 80, 120), (160, 200, 240))
   2120         >>> color()
   2121         ('#285078', '#a0c8f0')
   2122         """
   2123         if args:
   2124             l = len(args)
   2125             if l == 1:
   2126                 pcolor = fcolor = args[0]
   2127             elif l == 2:
   2128                 pcolor, fcolor = args
   2129             elif l == 3:
   2130                 pcolor = fcolor = args
   2131             pcolor = self._colorstr(pcolor)
   2132             fcolor = self._colorstr(fcolor)
   2133             self.pen(pencolor=pcolor, fillcolor=fcolor)
   2134         else:
   2135             return self._color(self._pencolor), self._color(self._fillcolor)
   2136 
   2137     def pencolor(self, *args):
   2138         """ Return or set the pencolor.
   2139 
   2140         Arguments:
   2141         Four input formats are allowed:
   2142           - pencolor()
   2143             Return the current pencolor as color specification string,
   2144             possibly in hex-number format (see example).
   2145             May be used as input to another color/pencolor/fillcolor call.
   2146           - pencolor(colorstring)
   2147             s is a Tk color specification string, such as "red" or "yellow"
   2148           - pencolor((r, g, b))
   2149             *a tuple* of r, g, and b, which represent, an RGB color,
   2150             and each of r, g, and b are in the range 0..colormode,
   2151             where colormode is either 1.0 or 255
   2152           - pencolor(r, g, b)
   2153             r, g, and b represent an RGB color, and each of r, g, and b
   2154             are in the range 0..colormode
   2155 
   2156         If turtleshape is a polygon, the outline of that polygon is drawn
   2157         with the newly set pencolor.
   2158 
   2159         Example (for a Turtle instance named turtle):
   2160         >>> turtle.pencolor('brown')
   2161         >>> tup = (0.2, 0.8, 0.55)
   2162         >>> turtle.pencolor(tup)
   2163         >>> turtle.pencolor()
   2164         '#33cc8c'
   2165         """
   2166         if args:
   2167             color = self._colorstr(args)
   2168             if color == self._pencolor:
   2169                 return
   2170             self.pen(pencolor=color)
   2171         else:
   2172             return self._color(self._pencolor)
   2173 
   2174     def fillcolor(self, *args):
   2175         """ Return or set the fillcolor.
   2176 
   2177         Arguments:
   2178         Four input formats are allowed:
   2179           - fillcolor()
   2180             Return the current fillcolor as color specification string,
   2181             possibly in hex-number format (see example).
   2182             May be used as input to another color/pencolor/fillcolor call.
   2183           - fillcolor(colorstring)
   2184             s is a Tk color specification string, such as "red" or "yellow"
   2185           - fillcolor((r, g, b))
   2186             *a tuple* of r, g, and b, which represent, an RGB color,
   2187             and each of r, g, and b are in the range 0..colormode,
   2188             where colormode is either 1.0 or 255
   2189           - fillcolor(r, g, b)
   2190             r, g, and b represent an RGB color, and each of r, g, and b
   2191             are in the range 0..colormode
   2192 
   2193         If turtleshape is a polygon, the interior of that polygon is drawn
   2194         with the newly set fillcolor.
   2195 
   2196         Example (for a Turtle instance named turtle):
   2197         >>> turtle.fillcolor('violet')
   2198         >>> col = turtle.pencolor()
   2199         >>> turtle.fillcolor(col)
   2200         >>> turtle.fillcolor(0, .5, 0)
   2201         """
   2202         if args:
   2203             color = self._colorstr(args)
   2204             if color == self._fillcolor:
   2205                 return
   2206             self.pen(fillcolor=color)
   2207         else:
   2208             return self._color(self._fillcolor)
   2209 
   2210     def showturtle(self):
   2211         """Makes the turtle visible.
   2212 
   2213         Aliases: showturtle | st
   2214 
   2215         No argument.
   2216 
   2217         Example (for a Turtle instance named turtle):
   2218         >>> turtle.hideturtle()
   2219         >>> turtle.showturtle()
   2220         """
   2221         self.pen(shown=True)
   2222 
   2223     def hideturtle(self):
   2224         """Makes the turtle invisible.
   2225 
   2226         Aliases: hideturtle | ht
   2227 
   2228         No argument.
   2229 
   2230         It's a good idea to do this while you're in the
   2231         middle of a complicated drawing, because hiding
   2232         the turtle speeds up the drawing observably.
   2233 
   2234         Example (for a Turtle instance named turtle):
   2235         >>> turtle.hideturtle()
   2236         """
   2237         self.pen(shown=False)
   2238 
   2239     def isvisible(self):
   2240         """Return True if the Turtle is shown, False if it's hidden.
   2241 
   2242         No argument.
   2243 
   2244         Example (for a Turtle instance named turtle):
   2245         >>> turtle.hideturtle()
   2246         >>> print turtle.isvisible():
   2247         False
   2248         """
   2249         return self._shown
   2250 
   2251     def pen(self, pen=None, **pendict):
   2252         """Return or set the pen's attributes.
   2253 
   2254         Arguments:
   2255             pen -- a dictionary with some or all of the below listed keys.
   2256             **pendict -- one or more keyword-arguments with the below
   2257                          listed keys as keywords.
   2258 
   2259         Return or set the pen's attributes in a 'pen-dictionary'
   2260         with the following key/value pairs:
   2261            "shown"      :   True/False
   2262            "pendown"    :   True/False
   2263            "pencolor"   :   color-string or color-tuple
   2264            "fillcolor"  :   color-string or color-tuple
   2265            "pensize"    :   positive number
   2266            "speed"      :   number in range 0..10
   2267            "resizemode" :   "auto" or "user" or "noresize"
   2268            "stretchfactor": (positive number, positive number)
   2269            "outline"    :   positive number
   2270            "tilt"       :   number
   2271 
   2272         This dictionary can be used as argument for a subsequent
   2273         pen()-call to restore the former pen-state. Moreover one
   2274         or more of these attributes can be provided as keyword-arguments.
   2275         This can be used to set several pen attributes in one statement.
   2276 
   2277 
   2278         Examples (for a Turtle instance named turtle):
   2279         >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
   2280         >>> turtle.pen()
   2281         {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
   2282         'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
   2283         'stretchfactor': (1,1), 'speed': 3}
   2284         >>> penstate=turtle.pen()
   2285         >>> turtle.color("yellow","")
   2286         >>> turtle.penup()
   2287         >>> turtle.pen()
   2288         {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
   2289         'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
   2290         'stretchfactor': (1,1), 'speed': 3}
   2291         >>> p.pen(penstate, fillcolor="green")
   2292         >>> p.pen()
   2293         {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
   2294         'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
   2295         'stretchfactor': (1,1), 'speed': 3}
   2296         """
   2297         _pd =  {"shown"         : self._shown,
   2298                 "pendown"       : self._drawing,
   2299                 "pencolor"      : self._pencolor,
   2300                 "fillcolor"     : self._fillcolor,
   2301                 "pensize"       : self._pensize,
   2302                 "speed"         : self._speed,
   2303                 "resizemode"    : self._resizemode,
   2304                 "stretchfactor" : self._stretchfactor,
   2305                 "outline"       : self._outlinewidth,
   2306                 "tilt"          : self._tilt
   2307                }
   2308 
   2309         if not (pen or pendict):
   2310             return _pd
   2311 
   2312         if isinstance(pen, dict):
   2313             p = pen
   2314         else:
   2315             p = {}
   2316         p.update(pendict)
   2317 
   2318         _p_buf = {}
   2319         for key in p:
   2320             _p_buf[key] = _pd[key]
   2321 
   2322         if self.undobuffer:
   2323             self.undobuffer.push(("pen", _p_buf))
   2324 
   2325         newLine = False
   2326         if "pendown" in p:
   2327             if self._drawing != p["pendown"]:
   2328                 newLine = True
   2329         if "pencolor" in p:
   2330             if isinstance(p["pencolor"], tuple):
   2331                 p["pencolor"] = self._colorstr((p["pencolor"],))
   2332             if self._pencolor != p["pencolor"]:
   2333                 newLine = True
   2334         if "pensize" in p:
   2335             if self._pensize != p["pensize"]:
   2336                 newLine = True
   2337         if newLine:
   2338             self._newLine()
   2339         if "pendown" in p:
   2340             self._drawing = p["pendown"]
   2341         if "pencolor" in p:
   2342             self._pencolor = p["pencolor"]
   2343         if "pensize" in p:
   2344             self._pensize = p["pensize"]
   2345         if "fillcolor" in p:
   2346             if isinstance(p["fillcolor"], tuple):
   2347                 p["fillcolor"] = self._colorstr((p["fillcolor"],))
   2348             self._fillcolor = p["fillcolor"]
   2349         if "speed" in p:
   2350             self._speed = p["speed"]
   2351         if "resizemode" in p:
   2352             self._resizemode = p["resizemode"]
   2353         if "stretchfactor" in p:
   2354             sf = p["stretchfactor"]
   2355             if isinstance(sf, (int, float)):
   2356                 sf = (sf, sf)
   2357             self._stretchfactor = sf
   2358         if "outline" in p:
   2359             self._outlinewidth = p["outline"]
   2360         if "shown" in p:
   2361             self._shown = p["shown"]
   2362         if "tilt" in p:
   2363             self._tilt = p["tilt"]
   2364         self._update()
   2365 
   2366 ## three dummy methods to be implemented by child class:
   2367 
   2368     def _newLine(self, usePos = True):
   2369         """dummy method - to be overwritten by child class"""
   2370     def _update(self, count=True, forced=False):
   2371         """dummy method - to be overwritten by child class"""
   2372     def _color(self, args):
   2373         """dummy method - to be overwritten by child class"""
   2374     def _colorstr(self, args):
   2375         """dummy method - to be overwritten by child class"""
   2376 
   2377     width = pensize
   2378     up = penup
   2379     pu = penup
   2380     pd = pendown
   2381     down = pendown
   2382     st = showturtle
   2383     ht = hideturtle
   2384 
   2385 
   2386 class _TurtleImage(object):
   2387     """Helper class: Datatype to store Turtle attributes
   2388     """
   2389 
   2390     def __init__(self, screen, shapeIndex):
   2391         self.screen = screen
   2392         self._type = None
   2393         self._setshape(shapeIndex)
   2394 
   2395     def _setshape(self, shapeIndex):
   2396         screen = self.screen # RawTurtle.screens[self.screenIndex]
   2397         self.shapeIndex = shapeIndex
   2398         if self._type == "polygon" == screen._shapes[shapeIndex]._type:
   2399             return
   2400         if self._type == "image" == screen._shapes[shapeIndex]._type:
   2401             return
   2402         if self._type in ["image", "polygon"]:
   2403             screen._delete(self._item)
   2404         elif self._type == "compound":
   2405             for item in self._item:
   2406                 screen._delete(item)
   2407         self._type = screen._shapes[shapeIndex]._type
   2408         if self._type == "polygon":
   2409             self._item = screen._createpoly()
   2410         elif self._type == "image":
   2411             self._item = screen._createimage(screen._shapes["blank"]._data)
   2412         elif self._type == "compound":
   2413             self._item = [screen._createpoly() for item in
   2414                                           screen._shapes[shapeIndex]._data]
   2415 
   2416 
   2417 class RawTurtle(TPen, TNavigator):
   2418     """Animation part of the RawTurtle.
   2419     Puts RawTurtle upon a TurtleScreen and provides tools for
   2420     its animation.
   2421     """
   2422     screens = []
   2423 
   2424     def __init__(self, canvas=None,
   2425                  shape=_CFG["shape"],
   2426                  undobuffersize=_CFG["undobuffersize"],
   2427                  visible=_CFG["visible"]):
   2428         if isinstance(canvas, _Screen):
   2429             self.screen = canvas
   2430         elif isinstance(canvas, TurtleScreen):
   2431             if canvas not in RawTurtle.screens:
   2432                 RawTurtle.screens.append(canvas)
   2433             self.screen = canvas
   2434         elif isinstance(canvas, (ScrolledCanvas, Canvas)):
   2435             for screen in RawTurtle.screens:
   2436                 if screen.cv == canvas:
   2437                     self.screen = screen
   2438                     break
   2439             else:
   2440                 self.screen = TurtleScreen(canvas)
   2441                 RawTurtle.screens.append(self.screen)
   2442         else:
   2443             raise TurtleGraphicsError("bad canvas argument %s" % canvas)
   2444 
   2445         screen = self.screen
   2446         TNavigator.__init__(self, screen.mode())
   2447         TPen.__init__(self)
   2448         screen._turtles.append(self)
   2449         self.drawingLineItem = screen._createline()
   2450         self.turtle = _TurtleImage(screen, shape)
   2451         self._poly = None
   2452         self._creatingPoly = False
   2453         self._fillitem = self._fillpath = None
   2454         self._shown = visible
   2455         self._hidden_from_screen = False
   2456         self.currentLineItem = screen._createline()
   2457         self.currentLine = [self._position]
   2458         self.items = [self.currentLineItem]
   2459         self.stampItems = []
   2460         self._undobuffersize = undobuffersize
   2461         self.undobuffer = Tbuffer(undobuffersize)
   2462         self._update()
   2463 
   2464     def reset(self):
   2465         """Delete the turtle's drawings and restore its default values.
   2466 
   2467         No argument.
   2468 ,
   2469         Delete the turtle's drawings from the screen, re-center the turtle
   2470         and set variables to the default values.
   2471 
   2472         Example (for a Turtle instance named turtle):
   2473         >>> turtle.position()
   2474         (0.00,-22.00)
   2475         >>> turtle.heading()
   2476         100.0
   2477         >>> turtle.reset()
   2478         >>> turtle.position()
   2479         (0.00,0.00)
   2480         >>> turtle.heading()
   2481         0.0
   2482         """
   2483         TNavigator.reset(self)
   2484         TPen._reset(self)
   2485         self._clear()
   2486         self._drawturtle()
   2487         self._update()
   2488 
   2489     def setundobuffer(self, size):
   2490         """Set or disable undobuffer.
   2491 
   2492         Argument:
   2493         size -- an integer or None
   2494 
   2495         If size is an integer an empty undobuffer of given size is installed.
   2496         Size gives the maximum number of turtle-actions that can be undone
   2497         by the undo() function.
   2498         If size is None, no undobuffer is present.
   2499 
   2500         Example (for a Turtle instance named turtle):
   2501         >>> turtle.setundobuffer(42)
   2502         """
   2503         if size is None or size <= 0:
   2504             self.undobuffer = None
   2505         else:
   2506             self.undobuffer = Tbuffer(size)
   2507 
   2508     def undobufferentries(self):
   2509         """Return count of entries in the undobuffer.
   2510 
   2511         No argument.
   2512 
   2513         Example (for a Turtle instance named turtle):
   2514         >>> while undobufferentries():
   2515         ...     undo()
   2516         """
   2517         if self.undobuffer is None:
   2518             return 0
   2519         return self.undobuffer.nr_of_items()
   2520 
   2521     def _clear(self):
   2522         """Delete all of pen's drawings"""
   2523         self._fillitem = self._fillpath = None
   2524         for item in self.items:
   2525             self.screen._delete(item)
   2526         self.currentLineItem = self.screen._createline()
   2527         self.currentLine = []
   2528         if self._drawing:
   2529             self.currentLine.append(self._position)
   2530         self.items = [self.currentLineItem]
   2531         self.clearstamps()
   2532         self.setundobuffer(self._undobuffersize)
   2533 
   2534 
   2535     def clear(self):
   2536         """Delete the turtle's drawings from the screen. Do not move turtle.
   2537 
   2538         No arguments.
   2539 
   2540         Delete the turtle's drawings from the screen. Do not move turtle.
   2541         State and position of the turtle as well as drawings of other
   2542         turtles are not affected.
   2543 
   2544         Examples (for a Turtle instance named turtle):
   2545         >>> turtle.clear()
   2546         """
   2547         self._clear()
   2548         self._update()
   2549 
   2550     def _update_data(self):
   2551         self.screen._incrementudc()
   2552         if self.screen._updatecounter != 0:
   2553             return
   2554         if len(self.currentLine)>1:
   2555             self.screen._drawline(self.currentLineItem, self.currentLine,
   2556                                   self._pencolor, self._pensize)
   2557 
   2558     def _update(self):
   2559         """Perform a Turtle-data update.
   2560         """
   2561         screen = self.screen
   2562         if screen._tracing == 0:
   2563             return
   2564         elif screen._tracing == 1:
   2565             self._update_data()
   2566             self._drawturtle()
   2567             screen._update()                  # TurtleScreenBase
   2568             screen._delay(screen._delayvalue) # TurtleScreenBase
   2569         else:
   2570             self._update_data()
   2571             if screen._updatecounter == 0:
   2572                 for t in screen.turtles():
   2573                     t._drawturtle()
   2574                 screen._update()
   2575 
   2576     def tracer(self, flag=None, delay=None):
   2577         """Turns turtle animation on/off and set delay for update drawings.
   2578 
   2579         Optional arguments:
   2580         n -- nonnegative  integer
   2581         delay -- nonnegative  integer
   2582 
   2583         If n is given, only each n-th regular screen update is really performed.
   2584         (Can be used to accelerate the drawing of complex graphics.)
   2585         Second arguments sets delay value (see RawTurtle.delay())
   2586 
   2587         Example (for a Turtle instance named turtle):
   2588         >>> turtle.tracer(8, 25)
   2589         >>> dist = 2
   2590         >>> for i in range(200):
   2591         ...     turtle.fd(dist)
   2592         ...     turtle.rt(90)
   2593         ...     dist += 2
   2594         """
   2595         return self.screen.tracer(flag, delay)
   2596 
   2597     def _color(self, args):
   2598         return self.screen._color(args)
   2599 
   2600     def _colorstr(self, args):
   2601         return self.screen._colorstr(args)
   2602 
   2603     def _cc(self, args):
   2604         """Convert colortriples to hexstrings.
   2605         """
   2606         if isinstance(args, basestring):
   2607             return args
   2608         try:
   2609             r, g, b = args
   2610         except (TypeError, ValueError):
   2611             raise TurtleGraphicsError("bad color arguments: %s" % str(args))
   2612         if self.screen._colormode == 1.0:
   2613             r, g, b = [round(255.0*x) for x in (r, g, b)]
   2614         if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
   2615             raise TurtleGraphicsError("bad color sequence: %s" % str(args))
   2616         return "#%02x%02x%02x" % (r, g, b)
   2617 
   2618     def clone(self):
   2619         """Create and return a clone of the turtle.
   2620 
   2621         No argument.
   2622 
   2623         Create and return a clone of the turtle with same position, heading
   2624         and turtle properties.
   2625 
   2626         Example (for a Turtle instance named mick):
   2627         mick = Turtle()
   2628         joe = mick.clone()
   2629         """
   2630         screen = self.screen
   2631         self._newLine(self._drawing)
   2632 
   2633         turtle = self.turtle
   2634         self.screen = None
   2635         self.turtle = None  # too make self deepcopy-able
   2636 
   2637         q = deepcopy(self)
   2638 
   2639         self.screen = screen
   2640         self.turtle = turtle
   2641 
   2642         q.screen = screen
   2643         q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
   2644 
   2645         screen._turtles.append(q)
   2646         ttype = screen._shapes[self.turtle.shapeIndex]._type
   2647         if ttype == "polygon":
   2648             q.turtle._item = screen._createpoly()
   2649         elif ttype == "image":
   2650             q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
   2651         elif ttype == "compound":
   2652             q.turtle._item = [screen._createpoly() for item in
   2653                               screen._shapes[self.turtle.shapeIndex]._data]
   2654         q.currentLineItem = screen._createline()
   2655         q._update()
   2656         return q
   2657 
   2658     def shape(self, name=None):
   2659         """Set turtle shape to shape with given name / return current shapename.
   2660 
   2661         Optional argument:
   2662         name -- a string, which is a valid shapename
   2663 
   2664         Set turtle shape to shape with given name or, if name is not given,
   2665         return name of current shape.
   2666         Shape with name must exist in the TurtleScreen's shape dictionary.
   2667         Initially there are the following polygon shapes:
   2668         'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
   2669         To learn about how to deal with shapes see Screen-method register_shape.
   2670 
   2671         Example (for a Turtle instance named turtle):
   2672         >>> turtle.shape()
   2673         'arrow'
   2674         >>> turtle.shape("turtle")
   2675         >>> turtle.shape()
   2676         'turtle'
   2677         """
   2678         if name is None:
   2679             return self.turtle.shapeIndex
   2680         if not name in self.screen.getshapes():
   2681             raise TurtleGraphicsError("There is no shape named %s" % name)
   2682         self.turtle._setshape(name)
   2683         self._update()
   2684 
   2685     def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
   2686         """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
   2687 
   2688         Optional arguments:
   2689            stretch_wid : positive number
   2690            stretch_len : positive number
   2691            outline  : positive number
   2692 
   2693         Return or set the pen's attributes x/y-stretchfactors and/or outline.
   2694         Set resizemode to "user".
   2695         If and only if resizemode is set to "user", the turtle will be displayed
   2696         stretched according to its stretchfactors:
   2697         stretch_wid is stretchfactor perpendicular to orientation
   2698         stretch_len is stretchfactor in direction of turtles orientation.
   2699         outline determines the width of the shapes's outline.
   2700 
   2701         Examples (for a Turtle instance named turtle):
   2702         >>> turtle.resizemode("user")
   2703         >>> turtle.shapesize(5, 5, 12)
   2704         >>> turtle.shapesize(outline=8)
   2705         """
   2706         if stretch_wid is stretch_len is outline is None:
   2707             stretch_wid, stretch_len = self._stretchfactor
   2708             return stretch_wid, stretch_len, self._outlinewidth
   2709         if stretch_wid is not None:
   2710             if stretch_len is None:
   2711                 stretchfactor = stretch_wid, stretch_wid
   2712             else:
   2713                 stretchfactor = stretch_wid, stretch_len
   2714         elif stretch_len is not None:
   2715             stretchfactor = self._stretchfactor[0], stretch_len
   2716         else:
   2717             stretchfactor = self._stretchfactor
   2718         if outline is None:
   2719             outline = self._outlinewidth
   2720         self.pen(resizemode="user",
   2721                  stretchfactor=stretchfactor, outline=outline)
   2722 
   2723     def settiltangle(self, angle):
   2724         """Rotate the turtleshape to point in the specified direction
   2725 
   2726         Optional argument:
   2727         angle -- number
   2728 
   2729         Rotate the turtleshape to point in the direction specified by angle,
   2730         regardless of its current tilt-angle. DO NOT change the turtle's
   2731         heading (direction of movement).
   2732 
   2733 
   2734         Examples (for a Turtle instance named turtle):
   2735         >>> turtle.shape("circle")
   2736         >>> turtle.shapesize(5,2)
   2737         >>> turtle.settiltangle(45)
   2738         >>> stamp()
   2739         >>> turtle.fd(50)
   2740         >>> turtle.settiltangle(-45)
   2741         >>> stamp()
   2742         >>> turtle.fd(50)
   2743         """
   2744         tilt = -angle * self._degreesPerAU * self._angleOrient
   2745         tilt = (tilt * math.pi / 180.0) % (2*math.pi)
   2746         self.pen(resizemode="user", tilt=tilt)
   2747 
   2748     def tiltangle(self):
   2749         """Return the current tilt-angle.
   2750 
   2751         No argument.
   2752 
   2753         Return the current tilt-angle, i. e. the angle between the
   2754         orientation of the turtleshape and the heading of the turtle
   2755         (its direction of movement).
   2756 
   2757         Examples (for a Turtle instance named turtle):
   2758         >>> turtle.shape("circle")
   2759         >>> turtle.shapesize(5,2)
   2760         >>> turtle.tilt(45)
   2761         >>> turtle.tiltangle()
   2762         """
   2763         tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
   2764         return (tilt / self._degreesPerAU) % self._fullcircle
   2765 
   2766     def tilt(self, angle):
   2767         """Rotate the turtleshape by angle.
   2768 
   2769         Argument:
   2770         angle - a number
   2771 
   2772         Rotate the turtleshape by angle from its current tilt-angle,
   2773         but do NOT change the turtle's heading (direction of movement).
   2774 
   2775         Examples (for a Turtle instance named turtle):
   2776         >>> turtle.shape("circle")
   2777         >>> turtle.shapesize(5,2)
   2778         >>> turtle.tilt(30)
   2779         >>> turtle.fd(50)
   2780         >>> turtle.tilt(30)
   2781         >>> turtle.fd(50)
   2782         """
   2783         self.settiltangle(angle + self.tiltangle())
   2784 
   2785     def _polytrafo(self, poly):
   2786         """Computes transformed polygon shapes from a shape
   2787         according to current position and heading.
   2788         """
   2789         screen = self.screen
   2790         p0, p1 = self._position
   2791         e0, e1 = self._orient
   2792         e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
   2793         e0, e1 = (1.0 / abs(e)) * e
   2794         return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
   2795                                                            for (x, y) in poly]
   2796 
   2797     def _drawturtle(self):
   2798         """Manages the correct rendering of the turtle with respect to
   2799         its shape, resizemode, stretch and tilt etc."""
   2800         screen = self.screen
   2801         shape = screen._shapes[self.turtle.shapeIndex]
   2802         ttype = shape._type
   2803         titem = self.turtle._item
   2804         if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
   2805             self._hidden_from_screen = False
   2806             tshape = shape._data
   2807             if ttype == "polygon":
   2808                 if self._resizemode == "noresize":
   2809                     w = 1
   2810                     shape = tshape
   2811                 else:
   2812                     if self._resizemode == "auto":
   2813                         lx = ly = max(1, self._pensize/5.0)
   2814                         w = self._pensize
   2815                         tiltangle = 0
   2816                     elif self._resizemode == "user":
   2817                         lx, ly = self._stretchfactor
   2818                         w = self._outlinewidth
   2819                         tiltangle = self._tilt
   2820                     shape = [(lx*x, ly*y) for (x, y) in tshape]
   2821                     t0, t1 = math.sin(tiltangle), math.cos(tiltangle)
   2822                     shape = [(t1*x+t0*y, -t0*x+t1*y) for (x, y) in shape]
   2823                 shape = self._polytrafo(shape)
   2824                 fc, oc = self._fillcolor, self._pencolor
   2825                 screen._drawpoly(titem, shape, fill=fc, outline=oc,
   2826                                                       width=w, top=True)
   2827             elif ttype == "image":
   2828                 screen._drawimage(titem, self._position, tshape)
   2829             elif ttype == "compound":
   2830                 lx, ly = self._stretchfactor
   2831                 w = self._outlinewidth
   2832                 for item, (poly, fc, oc) in zip(titem, tshape):
   2833                     poly = [(lx*x, ly*y) for (x, y) in poly]
   2834                     poly = self._polytrafo(poly)
   2835                     screen._drawpoly(item, poly, fill=self._cc(fc),
   2836                                      outline=self._cc(oc), width=w, top=True)
   2837         else:
   2838             if self._hidden_from_screen:
   2839                 return
   2840             if ttype == "polygon":
   2841                 screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
   2842             elif ttype == "image":
   2843                 screen._drawimage(titem, self._position,
   2844                                           screen._shapes["blank"]._data)
   2845             elif ttype == "compound":
   2846                 for item in titem:
   2847                     screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
   2848             self._hidden_from_screen = True
   2849 
   2850 ##############################  stamp stuff  ###############################
   2851 
   2852     def stamp(self):
   2853         """Stamp a copy of the turtleshape onto the canvas and return its id.
   2854 
   2855         No argument.
   2856 
   2857         Stamp a copy of the turtle shape onto the canvas at the current
   2858         turtle position. Return a stamp_id for that stamp, which can be
   2859         used to delete it by calling clearstamp(stamp_id).
   2860 
   2861         Example (for a Turtle instance named turtle):
   2862         >>> turtle.color("blue")
   2863         >>> turtle.stamp()
   2864         13
   2865         >>> turtle.fd(50)
   2866         """
   2867         screen = self.screen
   2868         shape = screen._shapes[self.turtle.shapeIndex]
   2869         ttype = shape._type
   2870         tshape = shape._data
   2871         if ttype == "polygon":
   2872             stitem = screen._createpoly()
   2873             if self._resizemode == "noresize":
   2874                 w = 1
   2875                 shape = tshape
   2876             else:
   2877                 if self._resizemode == "auto":
   2878                     lx = ly = max(1, self._pensize/5.0)
   2879                     w = self._pensize
   2880                     tiltangle = 0
   2881                 elif self._resizemode == "user":
   2882                     lx, ly = self._stretchfactor
   2883                     w = self._outlinewidth
   2884                     tiltangle = self._tilt
   2885                 shape = [(lx*x, ly*y) for (x, y) in tshape]
   2886                 t0, t1 = math.sin(tiltangle), math.cos(tiltangle)
   2887                 shape = [(t1*x+t0*y, -t0*x+t1*y) for (x, y) in shape]
   2888             shape = self._polytrafo(shape)
   2889             fc, oc = self._fillcolor, self._pencolor
   2890             screen._drawpoly(stitem, shape, fill=fc, outline=oc,
   2891                                                   width=w, top=True)
   2892         elif ttype == "image":
   2893             stitem = screen._createimage("")
   2894             screen._drawimage(stitem, self._position, tshape)
   2895         elif ttype == "compound":
   2896             stitem = []
   2897             for element in tshape:
   2898                 item = screen._createpoly()
   2899                 stitem.append(item)
   2900             stitem = tuple(stitem)
   2901             lx, ly = self._stretchfactor
   2902             w = self._outlinewidth
   2903             for item, (poly, fc, oc) in zip(stitem, tshape):
   2904                 poly = [(lx*x, ly*y) for (x, y) in poly]
   2905                 poly = self._polytrafo(poly)
   2906                 screen._drawpoly(item, poly, fill=self._cc(fc),
   2907                                  outline=self._cc(oc), width=w, top=True)
   2908         self.stampItems.append(stitem)
   2909         self.undobuffer.push(("stamp", stitem))
   2910         return stitem
   2911 
   2912     def _clearstamp(self, stampid):
   2913         """does the work for clearstamp() and clearstamps()
   2914         """
   2915         if stampid in self.stampItems:
   2916             if isinstance(stampid, tuple):
   2917                 for subitem in stampid:
   2918                     self.screen._delete(subitem)
   2919             else:
   2920                 self.screen._delete(stampid)
   2921             self.stampItems.remove(stampid)
   2922         # Delete stampitem from undobuffer if necessary
   2923         # if clearstamp is called directly.
   2924         item = ("stamp", stampid)
   2925         buf = self.undobuffer
   2926         if item not in buf.buffer:
   2927             return
   2928         index = buf.buffer.index(item)
   2929         buf.buffer.remove(item)
   2930         if index <= buf.ptr:
   2931             buf.ptr = (buf.ptr - 1) % buf.bufsize
   2932         buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
   2933 
   2934     def clearstamp(self, stampid):
   2935         """Delete stamp with given stampid
   2936 
   2937         Argument:
   2938         stampid - an integer, must be return value of previous stamp() call.
   2939 
   2940         Example (for a Turtle instance named turtle):
   2941         >>> turtle.color("blue")
   2942         >>> astamp = turtle.stamp()
   2943         >>> turtle.fd(50)
   2944         >>> turtle.clearstamp(astamp)
   2945         """
   2946         self._clearstamp(stampid)
   2947         self._update()
   2948 
   2949     def clearstamps(self, n=None):
   2950         """Delete all or first/last n of turtle's stamps.
   2951 
   2952         Optional argument:
   2953         n -- an integer
   2954 
   2955         If n is None, delete all of pen's stamps,
   2956         else if n > 0 delete first n stamps
   2957         else if n < 0 delete last n stamps.
   2958 
   2959         Example (for a Turtle instance named turtle):
   2960         >>> for i in range(8):
   2961         ...     turtle.stamp(); turtle.fd(30)
   2962         ...
   2963         >>> turtle.clearstamps(2)
   2964         >>> turtle.clearstamps(-2)
   2965         >>> turtle.clearstamps()
   2966         """
   2967         if n is None:
   2968             toDelete = self.stampItems[:]
   2969         elif n >= 0:
   2970             toDelete = self.stampItems[:n]
   2971         else:
   2972             toDelete = self.stampItems[n:]
   2973         for item in toDelete:
   2974             self._clearstamp(item)
   2975         self._update()
   2976 
   2977     def _goto(self, end):
   2978         """Move the pen to the point end, thereby drawing a line
   2979         if pen is down. All other methods for turtle movement depend
   2980         on this one.
   2981         """
   2982         ## Version mit undo-stuff
   2983         go_modes = ( self._drawing,
   2984                      self._pencolor,
   2985                      self._pensize,
   2986                      isinstance(self._fillpath, list))
   2987         screen = self.screen
   2988         undo_entry = ("go", self._position, end, go_modes,
   2989                       (self.currentLineItem,
   2990                       self.currentLine[:],
   2991                       screen._pointlist(self.currentLineItem),
   2992                       self.items[:])
   2993                       )
   2994         if self.undobuffer:
   2995             self.undobuffer.push(undo_entry)
   2996         start = self._position
   2997         if self._speed and screen._tracing == 1:
   2998             diff = (end-start)
   2999             diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
   3000             nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
   3001             delta = diff * (1.0/nhops)
   3002             for n in range(1, nhops):
   3003                 if n == 1:
   3004                     top = True
   3005                 else:
   3006                     top = False
   3007                 self._position = start + delta * n
   3008                 if self._drawing:
   3009                     screen._drawline(self.drawingLineItem,
   3010                                      (start, self._position),
   3011                                      self._pencolor, self._pensize, top)
   3012                 self._update()
   3013             if self._drawing:
   3014                 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
   3015                                                fill="", width=self._pensize)
   3016         # Turtle now at end,
   3017         if self._drawing: # now update currentLine
   3018             self.currentLine.append(end)
   3019         if isinstance(self._fillpath, list):
   3020             self._fillpath.append(end)
   3021         ######    vererbung!!!!!!!!!!!!!!!!!!!!!!
   3022         self._position = end
   3023         if self._creatingPoly:
   3024             self._poly.append(end)
   3025         if len(self.currentLine) > 42: # 42! answer to the ultimate question
   3026                                        # of life, the universe and everything
   3027             self._newLine()
   3028         self._update() #count=True)
   3029 
   3030     def _undogoto(self, entry):
   3031         """Reverse a _goto. Used for undo()
   3032         """
   3033         old, new, go_modes, coodata = entry
   3034         drawing, pc, ps, filling = go_modes
   3035         cLI, cL, pl, items = coodata
   3036         screen = self.screen
   3037         if abs(self._position - new) > 0.5:
   3038             print "undogoto: HALLO-DA-STIMMT-WAS-NICHT!"
   3039         # restore former situation
   3040         self.currentLineItem = cLI
   3041         self.currentLine = cL
   3042 
   3043         if pl == [(0, 0), (0, 0)]:
   3044             usepc = ""
   3045         else:
   3046             usepc = pc
   3047         screen._drawline(cLI, pl, fill=usepc, width=ps)
   3048 
   3049         todelete = [i for i in self.items if (i not in items) and
   3050                                        (screen._type(i) == "line")]
   3051         for i in todelete:
   3052             screen._delete(i)
   3053             self.items.remove(i)
   3054 
   3055         start = old
   3056         if self._speed and screen._tracing == 1:
   3057             diff = old - new
   3058             diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
   3059             nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
   3060             delta = diff * (1.0/nhops)
   3061             for n in range(1, nhops):
   3062                 if n == 1:
   3063                     top = True
   3064                 else:
   3065                     top = False
   3066                 self._position = new + delta * n
   3067                 if drawing:
   3068                     screen._drawline(self.drawingLineItem,
   3069                                      (start, self._position),
   3070                                      pc, ps, top)
   3071                 self._update()
   3072             if drawing:
   3073                 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
   3074                                                fill="", width=ps)
   3075         # Turtle now at position old,
   3076         self._position = old
   3077         ##  if undo is done during creating a polygon, the last vertex
   3078         ##  will be deleted. if the polygon is entirely deleted,
   3079         ##  creatingPoly will be set to False.
   3080         ##  Polygons created before the last one will not be affected by undo()
   3081         if self._creatingPoly:
   3082             if len(self._poly) > 0:
   3083                 self._poly.pop()
   3084             if self._poly == []:
   3085                 self._creatingPoly = False
   3086                 self._poly = None
   3087         if filling:
   3088             if self._fillpath == []:
   3089                 self._fillpath = None
   3090                 print "Unwahrscheinlich in _undogoto!"
   3091             elif self._fillpath is not None:
   3092                 self._fillpath.pop()
   3093         self._update() #count=True)
   3094 
   3095     def _rotate(self, angle):
   3096         """Turns pen clockwise by angle.
   3097         """
   3098         if self.undobuffer:
   3099             self.undobuffer.push(("rot", angle, self._degreesPerAU))
   3100         angle *= self._degreesPerAU
   3101         neworient = self._orient.rotate(angle)
   3102         tracing = self.screen._tracing
   3103         if tracing == 1 and self._speed > 0:
   3104             anglevel = 3.0 * self._speed
   3105             steps = 1 + int(abs(angle)/anglevel)
   3106             delta = 1.0*angle/steps
   3107             for _ in range(steps):
   3108                 self._orient = self._orient.rotate(delta)
   3109                 self._update()
   3110         self._orient = neworient
   3111         self._update()
   3112 
   3113     def _newLine(self, usePos=True):
   3114         """Closes current line item and starts a new one.
   3115            Remark: if current line became too long, animation
   3116            performance (via _drawline) slowed down considerably.
   3117         """
   3118         if len(self.currentLine) > 1:
   3119             self.screen._drawline(self.currentLineItem, self.currentLine,
   3120                                       self._pencolor, self._pensize)
   3121             self.currentLineItem = self.screen._createline()
   3122             self.items.append(self.currentLineItem)
   3123         else:
   3124             self.screen._drawline(self.currentLineItem, top=True)
   3125         self.currentLine = []
   3126         if usePos:
   3127             self.currentLine = [self._position]
   3128 
   3129     def fill(self, flag=None):
   3130         """Call fill(True) before drawing a shape to fill, fill(False) when done.
   3131 
   3132         Optional argument:
   3133         flag -- True/False (or 1/0 respectively)
   3134 
   3135         Call fill(True) before drawing the shape you want to fill,
   3136         and  fill(False) when done.
   3137         When used without argument: return fillstate (True if filling,
   3138         False else)
   3139 
   3140         Example (for a Turtle instance named turtle):
   3141         >>> turtle.fill(True)
   3142         >>> turtle.forward(100)
   3143         >>> turtle.left(90)
   3144         >>> turtle.forward(100)
   3145         >>> turtle.left(90)
   3146         >>> turtle.forward(100)
   3147         >>> turtle.left(90)
   3148         >>> turtle.forward(100)
   3149         >>> turtle.fill(False)
   3150         """
   3151         filling = isinstance(self._fillpath, list)
   3152         if flag is None:
   3153             return filling
   3154         screen = self.screen
   3155         entry1 = entry2 = ()
   3156         if filling:
   3157             if len(self._fillpath) > 2:
   3158                 self.screen._drawpoly(self._fillitem, self._fillpath,
   3159                                       fill=self._fillcolor)
   3160                 entry1 = ("dofill", self._fillitem)
   3161         if flag:
   3162             self._fillitem = self.screen._createpoly()
   3163             self.items.append(self._fillitem)
   3164             self._fillpath = [self._position]
   3165             entry2 = ("beginfill", self._fillitem) # , self._fillpath)
   3166             self._newLine()
   3167         else:
   3168             self._fillitem = self._fillpath = None
   3169         if self.undobuffer:
   3170             if entry1 == ():
   3171                 if entry2 != ():
   3172                     self.undobuffer.push(entry2)
   3173             else:
   3174                 if entry2 == ():
   3175                     self.undobuffer.push(entry1)
   3176                 else:
   3177                     self.undobuffer.push(["seq", entry1, entry2])
   3178         self._update()
   3179 
   3180     def begin_fill(self):
   3181         """Called just before drawing a shape to be filled.
   3182 
   3183         No argument.
   3184 
   3185         Example (for a Turtle instance named turtle):
   3186         >>> turtle.begin_fill()
   3187         >>> turtle.forward(100)
   3188         >>> turtle.left(90)
   3189         >>> turtle.forward(100)
   3190         >>> turtle.left(90)
   3191         >>> turtle.forward(100)
   3192         >>> turtle.left(90)
   3193         >>> turtle.forward(100)
   3194         >>> turtle.end_fill()
   3195         """
   3196         self.fill(True)
   3197 
   3198     def end_fill(self):
   3199         """Fill the shape drawn after the call begin_fill().
   3200 
   3201         No argument.
   3202 
   3203         Example (for a Turtle instance named turtle):
   3204         >>> turtle.begin_fill()
   3205         >>> turtle.forward(100)
   3206         >>> turtle.left(90)
   3207         >>> turtle.forward(100)
   3208         >>> turtle.left(90)
   3209         >>> turtle.forward(100)
   3210         >>> turtle.left(90)
   3211         >>> turtle.forward(100)
   3212         >>> turtle.end_fill()
   3213         """
   3214         self.fill(False)
   3215 
   3216     def dot(self, size=None, *color):
   3217         """Draw a dot with diameter size, using color.
   3218 
   3219         Optional arguments:
   3220         size -- an integer >= 1 (if given)
   3221         color -- a colorstring or a numeric color tuple
   3222 
   3223         Draw a circular dot with diameter size, using color.
   3224         If size is not given, the maximum of pensize+4 and 2*pensize is used.
   3225 
   3226         Example (for a Turtle instance named turtle):
   3227         >>> turtle.dot()
   3228         >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
   3229         """
   3230         #print "dot-1:", size, color
   3231         if not color:
   3232             if isinstance(size, (basestring, tuple)):
   3233                 color = self._colorstr(size)
   3234                 size = self._pensize + max(self._pensize, 4)
   3235             else:
   3236                 color = self._pencolor
   3237                 if not size:
   3238                     size = self._pensize + max(self._pensize, 4)
   3239         else:
   3240             if size is None:
   3241                 size = self._pensize + max(self._pensize, 4)
   3242             color = self._colorstr(color)
   3243         #print "dot-2:", size, color
   3244         if hasattr(self.screen, "_dot"):
   3245             item = self.screen._dot(self._position, size, color)
   3246             #print "dot:", size, color, "item:", item
   3247             self.items.append(item)
   3248             if self.undobuffer:
   3249                 self.undobuffer.push(("dot", item))
   3250         else:
   3251             pen = self.pen()
   3252             if self.undobuffer:
   3253                 self.undobuffer.push(["seq"])
   3254                 self.undobuffer.cumulate = True
   3255             try:
   3256                 if self.resizemode() == 'auto':
   3257                     self.ht()
   3258                 self.pendown()
   3259                 self.pensize(size)
   3260                 self.pencolor(color)
   3261                 self.forward(0)
   3262             finally:
   3263                 self.pen(pen)
   3264             if self.undobuffer:
   3265                 self.undobuffer.cumulate = False
   3266 
   3267     def _write(self, txt, align, font):
   3268         """Performs the writing for write()
   3269         """
   3270         item, end = self.screen._write(self._position, txt, align, font,
   3271                                                           self._pencolor)
   3272         self.items.append(item)
   3273         if self.undobuffer:
   3274             self.undobuffer.push(("wri", item))
   3275         return end
   3276 
   3277     def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
   3278         """Write text at the current turtle position.
   3279 
   3280         Arguments:
   3281         arg -- info, which is to be written to the TurtleScreen
   3282         move (optional) -- True/False
   3283         align (optional) -- one of the strings "left", "center" or right"
   3284         font (optional) -- a triple (fontname, fontsize, fonttype)
   3285 
   3286         Write text - the string representation of arg - at the current
   3287         turtle position according to align ("left", "center" or right")
   3288         and with the given font.
   3289         If move is True, the pen is moved to the bottom-right corner
   3290         of the text. By default, move is False.
   3291 
   3292         Example (for a Turtle instance named turtle):
   3293         >>> turtle.write('Home = ', True, align="center")
   3294         >>> turtle.write((0,0), True)
   3295         """
   3296         if self.undobuffer:
   3297             self.undobuffer.push(["seq"])
   3298             self.undobuffer.cumulate = True
   3299         end = self._write(str(arg), align.lower(), font)
   3300         if move:
   3301             x, y = self.pos()
   3302             self.setpos(end, y)
   3303         if self.undobuffer:
   3304             self.undobuffer.cumulate = False
   3305 
   3306     def begin_poly(self):
   3307         """Start recording the vertices of a polygon.
   3308 
   3309         No argument.
   3310 
   3311         Start recording the vertices of a polygon. Current turtle position
   3312         is first point of polygon.
   3313 
   3314         Example (for a Turtle instance named turtle):
   3315         >>> turtle.begin_poly()
   3316         """
   3317         self._poly = [self._position]
   3318         self._creatingPoly = True
   3319 
   3320     def end_poly(self):
   3321         """Stop recording the vertices of a polygon.
   3322 
   3323         No argument.
   3324 
   3325         Stop recording the vertices of a polygon. Current turtle position is
   3326         last point of polygon. This will be connected with the first point.
   3327 
   3328         Example (for a Turtle instance named turtle):
   3329         >>> turtle.end_poly()
   3330         """
   3331         self._creatingPoly = False
   3332 
   3333     def get_poly(self):
   3334         """Return the lastly recorded polygon.
   3335 
   3336         No argument.
   3337 
   3338         Example (for a Turtle instance named turtle):
   3339         >>> p = turtle.get_poly()
   3340         >>> turtle.register_shape("myFavouriteShape", p)
   3341         """
   3342         ## check if there is any poly?  -- 1st solution:
   3343         if self._poly is not None:
   3344             return tuple(self._poly)
   3345 
   3346     def getscreen(self):
   3347         """Return the TurtleScreen object, the turtle is drawing  on.
   3348 
   3349         No argument.
   3350 
   3351         Return the TurtleScreen object, the turtle is drawing  on.
   3352         So TurtleScreen-methods can be called for that object.
   3353 
   3354         Example (for a Turtle instance named turtle):
   3355         >>> ts = turtle.getscreen()
   3356         >>> ts
   3357         <turtle.TurtleScreen object at 0x0106B770>
   3358         >>> ts.bgcolor("pink")
   3359         """
   3360         return self.screen
   3361 
   3362     def getturtle(self):
   3363         """Return the Turtleobject itself.
   3364 
   3365         No argument.
   3366 
   3367         Only reasonable use: as a function to return the 'anonymous turtle':
   3368 
   3369         Example:
   3370         >>> pet = getturtle()
   3371         >>> pet.fd(50)
   3372         >>> pet
   3373         <turtle.Turtle object at 0x0187D810>
   3374         >>> turtles()
   3375         [<turtle.Turtle object at 0x0187D810>]
   3376         """
   3377         return self
   3378 
   3379     getpen = getturtle
   3380 
   3381 
   3382     ################################################################
   3383     ### screen oriented methods recurring to methods of TurtleScreen
   3384     ################################################################
   3385 
   3386     def window_width(self):
   3387         """ Returns the width of the turtle window.
   3388 
   3389         No argument.
   3390 
   3391         Example (for a TurtleScreen instance named screen):
   3392         >>> screen.window_width()
   3393         640
   3394         """
   3395         return self.screen._window_size()[0]
   3396 
   3397     def window_height(self):
   3398         """ Return the height of the turtle window.
   3399 
   3400         No argument.
   3401 
   3402         Example (for a TurtleScreen instance named screen):
   3403         >>> screen.window_height()
   3404         480
   3405         """
   3406         return self.screen._window_size()[1]
   3407 
   3408     def _delay(self, delay=None):
   3409         """Set delay value which determines speed of turtle animation.
   3410         """
   3411         return self.screen.delay(delay)
   3412 
   3413     #####   event binding methods   #####
   3414 
   3415     def onclick(self, fun, btn=1, add=None):
   3416         """Bind fun to mouse-click event on this turtle on canvas.
   3417 
   3418         Arguments:
   3419         fun --  a function with two arguments, to which will be assigned
   3420                 the coordinates of the clicked point on the canvas.
   3421         num --  number of the mouse-button defaults to 1 (left mouse button).
   3422         add --  True or False. If True, new binding will be added, otherwise
   3423                 it will replace a former binding.
   3424 
   3425         Example for the anonymous turtle, i. e. the procedural way:
   3426 
   3427         >>> def turn(x, y):
   3428         ...     left(360)
   3429         ...
   3430         >>> onclick(turn)  # Now clicking into the turtle will turn it.
   3431         >>> onclick(None)  # event-binding will be removed
   3432         """
   3433         self.screen._onclick(self.turtle._item, fun, btn, add)
   3434         self._update()
   3435 
   3436     def onrelease(self, fun, btn=1, add=None):
   3437         """Bind fun to mouse-button-release event on this turtle on canvas.
   3438 
   3439         Arguments:
   3440         fun -- a function with two arguments, to which will be assigned
   3441                 the coordinates of the clicked point on the canvas.
   3442         num --  number of the mouse-button defaults to 1 (left mouse button).
   3443 
   3444         Example (for a MyTurtle instance named joe):
   3445         >>> class MyTurtle(Turtle):
   3446         ...     def glow(self,x,y):
   3447         ...             self.fillcolor("red")
   3448         ...     def unglow(self,x,y):
   3449         ...             self.fillcolor("")
   3450         ...
   3451         >>> joe = MyTurtle()
   3452         >>> joe.onclick(joe.glow)
   3453         >>> joe.onrelease(joe.unglow)
   3454 
   3455         Clicking on joe turns fillcolor red, unclicking turns it to
   3456         transparent.
   3457         """
   3458         self.screen._onrelease(self.turtle._item, fun, btn, add)
   3459         self._update()
   3460 
   3461     def ondrag(self, fun, btn=1, add=None):
   3462         """Bind fun to mouse-move event on this turtle on canvas.
   3463 
   3464         Arguments:
   3465         fun -- a function with two arguments, to which will be assigned
   3466                the coordinates of the clicked point on the canvas.
   3467         num -- number of the mouse-button defaults to 1 (left mouse button).
   3468 
   3469         Every sequence of mouse-move-events on a turtle is preceded by a
   3470         mouse-click event on that turtle.
   3471 
   3472         Example (for a Turtle instance named turtle):
   3473         >>> turtle.ondrag(turtle.goto)
   3474 
   3475         Subsequently clicking and dragging a Turtle will move it
   3476         across the screen thereby producing handdrawings (if pen is
   3477         down).
   3478         """
   3479         self.screen._ondrag(self.turtle._item, fun, btn, add)
   3480 
   3481 
   3482     def _undo(self, action, data):
   3483         """Does the main part of the work for undo()
   3484         """
   3485         if self.undobuffer is None:
   3486             return
   3487         if action == "rot":
   3488             angle, degPAU = data
   3489             self._rotate(-angle*degPAU/self._degreesPerAU)
   3490             dummy = self.undobuffer.pop()
   3491         elif action == "stamp":
   3492             stitem = data[0]
   3493             self.clearstamp(stitem)
   3494         elif action == "go":
   3495             self._undogoto(data)
   3496         elif action in ["wri", "dot"]:
   3497             item = data[0]
   3498             self.screen._delete(item)
   3499             self.items.remove(item)
   3500         elif action == "dofill":
   3501             item = data[0]
   3502             self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
   3503                                   fill="", outline="")
   3504         elif action == "beginfill":
   3505             item = data[0]
   3506             self._fillitem = self._fillpath = None
   3507             self.screen._delete(item)
   3508             self.items.remove(item)
   3509         elif action == "pen":
   3510             TPen.pen(self, data[0])
   3511             self.undobuffer.pop()
   3512 
   3513     def undo(self):
   3514         """undo (repeatedly) the last turtle action.
   3515 
   3516         No argument.
   3517 
   3518         undo (repeatedly) the last turtle action.
   3519         Number of available undo actions is determined by the size of
   3520         the undobuffer.
   3521 
   3522         Example (for a Turtle instance named turtle):
   3523         >>> for i in range(4):
   3524         ...     turtle.fd(50); turtle.lt(80)
   3525         ...
   3526         >>> for i in range(8):
   3527         ...     turtle.undo()
   3528         ...
   3529         """
   3530         if self.undobuffer is None:
   3531             return
   3532         item = self.undobuffer.pop()
   3533         action = item[0]
   3534         data = item[1:]
   3535         if action == "seq":
   3536             while data:
   3537                 item = data.pop()
   3538                 self._undo(item[0], item[1:])
   3539         else:
   3540             self._undo(action, data)
   3541 
   3542     turtlesize = shapesize
   3543 
   3544 RawPen = RawTurtle
   3545 
   3546 ###  Screen - Singleton  ########################
   3547 
   3548 def Screen():
   3549     """Return the singleton screen object.
   3550     If none exists at the moment, create a new one and return it,
   3551     else return the existing one."""
   3552     if Turtle._screen is None:
   3553         Turtle._screen = _Screen()
   3554     return Turtle._screen
   3555 
   3556 class _Screen(TurtleScreen):
   3557 
   3558     _root = None
   3559     _canvas = None
   3560     _title = _CFG["title"]
   3561 
   3562     def __init__(self):
   3563         # XXX there is no need for this code to be conditional,
   3564         # as there will be only a single _Screen instance, anyway
   3565         # XXX actually, the turtle demo is injecting root window,
   3566         # so perhaps the conditional creation of a root should be
   3567         # preserved (perhaps by passing it as an optional parameter)
   3568         if _Screen._root is None:
   3569             _Screen._root = self._root = _Root()
   3570             self._root.title(_Screen._title)
   3571             self._root.ondestroy(self._destroy)
   3572         if _Screen._canvas is None:
   3573             width = _CFG["width"]
   3574             height = _CFG["height"]
   3575             canvwidth = _CFG["canvwidth"]
   3576             canvheight = _CFG["canvheight"]
   3577             leftright = _CFG["leftright"]
   3578             topbottom = _CFG["topbottom"]
   3579             self._root.setupcanvas(width, height, canvwidth, canvheight)
   3580             _Screen._canvas = self._root._getcanvas()
   3581             TurtleScreen.__init__(self, _Screen._canvas)
   3582             self.setup(width, height, leftright, topbottom)
   3583 
   3584     def setup(self, width=_CFG["width"], height=_CFG["height"],
   3585               startx=_CFG["leftright"], starty=_CFG["topbottom"]):
   3586         """ Set the size and position of the main window.
   3587 
   3588         Arguments:
   3589         width: as integer a size in pixels, as float a fraction of the screen.
   3590           Default is 50% of screen.
   3591         height: as integer the height in pixels, as float a fraction of the
   3592           screen. Default is 75% of screen.
   3593         startx: if positive, starting position in pixels from the left
   3594           edge of the screen, if negative from the right edge
   3595           Default, startx=None is to center window horizontally.
   3596         starty: if positive, starting position in pixels from the top
   3597           edge of the screen, if negative from the bottom edge
   3598           Default, starty=None is to center window vertically.
   3599 
   3600         Examples (for a Screen instance named screen):
   3601         >>> screen.setup (width=200, height=200, startx=0, starty=0)
   3602 
   3603         sets window to 200x200 pixels, in upper left of screen
   3604 
   3605         >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
   3606 
   3607         sets window to 75% of screen by 50% of screen and centers
   3608         """
   3609         if not hasattr(self._root, "set_geometry"):
   3610             return
   3611         sw = self._root.win_width()
   3612         sh = self._root.win_height()
   3613         if isinstance(width, float) and 0 <= width <= 1:
   3614             width = sw*width
   3615         if startx is None:
   3616             startx = (sw - width) / 2
   3617         if isinstance(height, float) and 0 <= height <= 1:
   3618             height = sh*height
   3619         if starty is None:
   3620             starty = (sh - height) / 2
   3621         self._root.set_geometry(width, height, startx, starty)
   3622         self.update()
   3623 
   3624     def title(self, titlestring):
   3625         """Set title of turtle-window
   3626 
   3627         Argument:
   3628         titlestring -- a string, to appear in the titlebar of the
   3629                        turtle graphics window.
   3630 
   3631         This is a method of Screen-class. Not available for TurtleScreen-
   3632         objects.
   3633 
   3634         Example (for a Screen instance named screen):
   3635         >>> screen.title("Welcome to the turtle-zoo!")
   3636         """
   3637         if _Screen._root is not None:
   3638             _Screen._root.title(titlestring)
   3639         _Screen._title = titlestring
   3640 
   3641     def _destroy(self):
   3642         root = self._root
   3643         if root is _Screen._root:
   3644             Turtle._pen = None
   3645             Turtle._screen = None
   3646             _Screen._root = None
   3647             _Screen._canvas = None
   3648         TurtleScreen._RUNNING = False
   3649         root.destroy()
   3650 
   3651     def bye(self):
   3652         """Shut the turtlegraphics window.
   3653 
   3654         Example (for a TurtleScreen instance named screen):
   3655         >>> screen.bye()
   3656         """
   3657         self._destroy()
   3658 
   3659     def exitonclick(self):
   3660         """Go into mainloop until the mouse is clicked.
   3661 
   3662         No arguments.
   3663 
   3664         Bind bye() method to mouseclick on TurtleScreen.
   3665         If "using_IDLE" - value in configuration dictionary is False
   3666         (default value), enter mainloop.
   3667         If IDLE with -n switch (no subprocess) is used, this value should be
   3668         set to True in turtle.cfg. In this case IDLE's mainloop
   3669         is active also for the client script.
   3670 
   3671         This is a method of the Screen-class and not available for
   3672         TurtleScreen instances.
   3673 
   3674         Example (for a Screen instance named screen):
   3675         >>> screen.exitonclick()
   3676 
   3677         """
   3678         def exitGracefully(x, y):
   3679             """Screen.bye() with two dummy-parameters"""
   3680             self.bye()
   3681         self.onclick(exitGracefully)
   3682         if _CFG["using_IDLE"]:
   3683             return
   3684         try:
   3685             mainloop()
   3686         except AttributeError:
   3687             exit(0)
   3688 
   3689 class Turtle(RawTurtle):
   3690     """RawTurtle auto-creating (scrolled) canvas.
   3691 
   3692     When a Turtle object is created or a function derived from some
   3693     Turtle method is called a TurtleScreen object is automatically created.
   3694     """
   3695     _pen = None
   3696     _screen = None
   3697 
   3698     def __init__(self,
   3699                  shape=_CFG["shape"],
   3700                  undobuffersize=_CFG["undobuffersize"],
   3701                  visible=_CFG["visible"]):
   3702         if Turtle._screen is None:
   3703             Turtle._screen = Screen()
   3704         RawTurtle.__init__(self, Turtle._screen,
   3705                            shape=shape,
   3706                            undobuffersize=undobuffersize,
   3707                            visible=visible)
   3708 
   3709 Pen = Turtle
   3710 
   3711 def write_docstringdict(filename="turtle_docstringdict"):
   3712     """Create and write docstring-dictionary to file.
   3713 
   3714     Optional argument:
   3715     filename -- a string, used as filename
   3716                 default value is turtle_docstringdict
   3717 
   3718     Has to be called explicitly, (not used by the turtle-graphics classes)
   3719     The docstring dictionary will be written to the Python script <filname>.py
   3720     It is intended to serve as a template for translation of the docstrings
   3721     into different languages.
   3722     """
   3723     docsdict = {}
   3724 
   3725     for methodname in _tg_screen_functions:
   3726         key = "_Screen."+methodname
   3727         docsdict[key] = eval(key).__doc__
   3728     for methodname in _tg_turtle_functions:
   3729         key = "Turtle."+methodname
   3730         docsdict[key] = eval(key).__doc__
   3731 
   3732     f = open("%s.py" % filename,"w")
   3733     keys = sorted([x for x in docsdict.keys()
   3734                         if x.split('.')[1] not in _alias_list])
   3735     f.write('docsdict = {\n\n')
   3736     for key in keys[:-1]:
   3737         f.write('%s :\n' % repr(key))
   3738         f.write('        """%s\n""",\n\n' % docsdict[key])
   3739     key = keys[-1]
   3740     f.write('%s :\n' % repr(key))
   3741     f.write('        """%s\n"""\n\n' % docsdict[key])
   3742     f.write("}\n")
   3743     f.close()
   3744 
   3745 def read_docstrings(lang):
   3746     """Read in docstrings from lang-specific docstring dictionary.
   3747 
   3748     Transfer docstrings, translated to lang, from a dictionary-file
   3749     to the methods of classes Screen and Turtle and - in revised form -
   3750     to the corresponding functions.
   3751     """
   3752     modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
   3753     module = __import__(modname)
   3754     docsdict = module.docsdict
   3755     for key in docsdict:
   3756         #print key
   3757         try:
   3758             eval(key).im_func.__doc__ = docsdict[key]
   3759         except BaseException:
   3760             print "Bad docstring-entry: %s" % key
   3761 
   3762 _LANGUAGE = _CFG["language"]
   3763 
   3764 try:
   3765     if _LANGUAGE != "english":
   3766         read_docstrings(_LANGUAGE)
   3767 except ImportError:
   3768     print "Cannot find docsdict for", _LANGUAGE
   3769 except BaseException:
   3770     print ("Unknown Error when trying to import %s-docstring-dictionary" %
   3771                                                                   _LANGUAGE)
   3772 
   3773 
   3774 def getmethparlist(ob):
   3775     "Get strings describing the arguments for the given object"
   3776     argText1 = argText2 = ""
   3777     # bit of a hack for methods - turn it into a function
   3778     # but we drop the "self" param.
   3779     if type(ob)==types.MethodType:
   3780         fob = ob.im_func
   3781         argOffset = 1
   3782     else:
   3783         fob = ob
   3784         argOffset = 0
   3785     # Try and build one for Python defined functions
   3786     if type(fob) in [types.FunctionType, types.LambdaType]:
   3787         try:
   3788             counter = fob.func_code.co_argcount
   3789             items2 = list(fob.func_code.co_varnames[argOffset:counter])
   3790             realArgs = fob.func_code.co_varnames[argOffset:counter]
   3791             defaults = fob.func_defaults or []
   3792             defaults = list(map(lambda name: "=%s" % repr(name), defaults))
   3793             defaults = [""] * (len(realArgs)-len(defaults)) + defaults
   3794             items1 = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
   3795             if fob.func_code.co_flags & 0x4:
   3796                 items1.append("*"+fob.func_code.co_varnames[counter])
   3797                 items2.append("*"+fob.func_code.co_varnames[counter])
   3798                 counter += 1
   3799             if fob.func_code.co_flags & 0x8:
   3800                 items1.append("**"+fob.func_code.co_varnames[counter])
   3801                 items2.append("**"+fob.func_code.co_varnames[counter])
   3802             argText1 = ", ".join(items1)
   3803             argText1 = "(%s)" % argText1
   3804             argText2 = ", ".join(items2)
   3805             argText2 = "(%s)" % argText2
   3806         except:
   3807             pass
   3808     return argText1, argText2
   3809 
   3810 def _turtle_docrevise(docstr):
   3811     """To reduce docstrings from RawTurtle class for functions
   3812     """
   3813     import re
   3814     if docstr is None:
   3815         return None
   3816     turtlename = _CFG["exampleturtle"]
   3817     newdocstr = docstr.replace("%s." % turtlename,"")
   3818     parexp = re.compile(r' \(.+ %s\):' % turtlename)
   3819     newdocstr = parexp.sub(":", newdocstr)
   3820     return newdocstr
   3821 
   3822 def _screen_docrevise(docstr):
   3823     """To reduce docstrings from TurtleScreen class for functions
   3824     """
   3825     import re
   3826     if docstr is None:
   3827         return None
   3828     screenname = _CFG["examplescreen"]
   3829     newdocstr = docstr.replace("%s." % screenname,"")
   3830     parexp = re.compile(r' \(.+ %s\):' % screenname)
   3831     newdocstr = parexp.sub(":", newdocstr)
   3832     return newdocstr
   3833 
   3834 ## The following mechanism makes all methods of RawTurtle and Turtle available
   3835 ## as functions. So we can enhance, change, add, delete methods to these
   3836 ## classes and do not need to change anything here.
   3837 
   3838 __func_body = """\
   3839 def {name}{paramslist}:
   3840     if {obj} is None:
   3841         if not TurtleScreen._RUNNING:
   3842             TurtleScreen._RUNNING = True
   3843             raise Terminator
   3844         {obj} = {init}
   3845     try:
   3846         return {obj}.{name}{argslist}
   3847     except TK.TclError:
   3848         if not TurtleScreen._RUNNING:
   3849             TurtleScreen._RUNNING = True
   3850             raise Terminator
   3851         raise
   3852 """
   3853 
   3854 def _make_global_funcs(functions, cls, obj, init, docrevise):
   3855     for methodname in functions:
   3856         method = getattr(cls, methodname)
   3857         pl1, pl2 = getmethparlist(method)
   3858         if pl1 == "":
   3859             print ">>>>>>", pl1, pl2
   3860             continue
   3861         defstr = __func_body.format(obj=obj, init=init, name=methodname,
   3862                                     paramslist=pl1, argslist=pl2)
   3863         exec defstr in globals()
   3864         globals()[methodname].__doc__ = docrevise(method.__doc__)
   3865 
   3866 _make_global_funcs(_tg_screen_functions, _Screen,
   3867                    'Turtle._screen', 'Screen()', _screen_docrevise)
   3868 _make_global_funcs(_tg_turtle_functions, Turtle,
   3869                    'Turtle._pen', 'Turtle()', _turtle_docrevise)
   3870 
   3871 
   3872 done = mainloop = TK.mainloop
   3873 
   3874 if __name__ == "__main__":
   3875     def switchpen():
   3876         if isdown():
   3877             pu()
   3878         else:
   3879             pd()
   3880 
   3881     def demo1():
   3882         """Demo of old turtle.py - module"""
   3883         reset()
   3884         tracer(True)
   3885         up()
   3886         backward(100)
   3887         down()
   3888         # draw 3 squares; the last filled
   3889         width(3)
   3890         for i in range(3):
   3891             if i == 2:
   3892                 fill(1)
   3893             for _ in range(4):
   3894                 forward(20)
   3895                 left(90)
   3896             if i == 2:
   3897                 color("maroon")
   3898                 fill(0)
   3899             up()
   3900             forward(30)
   3901             down()
   3902         width(1)
   3903         color("black")
   3904         # move out of the way
   3905         tracer(False)
   3906         up()
   3907         right(90)
   3908         forward(100)
   3909         right(90)
   3910         forward(100)
   3911         right(180)
   3912         down()
   3913         # some text
   3914         write("startstart", 1)
   3915         write(u"start", 1)
   3916         color("red")
   3917         # staircase
   3918         for i in range(5):
   3919             forward(20)
   3920             left(90)
   3921             forward(20)
   3922             right(90)
   3923         # filled staircase
   3924         tracer(True)
   3925         fill(1)
   3926         for i in range(5):
   3927             forward(20)
   3928             left(90)
   3929             forward(20)
   3930             right(90)
   3931         fill(0)
   3932         # more text
   3933 
   3934     def demo2():
   3935         """Demo of some new features."""
   3936         speed(1)
   3937         st()
   3938         pensize(3)
   3939         setheading(towards(0, 0))
   3940         radius = distance(0, 0)/2.0
   3941         rt(90)
   3942         for _ in range(18):
   3943             switchpen()
   3944             circle(radius, 10)
   3945         write("wait a moment...")
   3946         while undobufferentries():
   3947             undo()
   3948         reset()
   3949         lt(90)
   3950         colormode(255)
   3951         laenge = 10
   3952         pencolor("green")
   3953         pensize(3)
   3954         lt(180)
   3955         for i in range(-2, 16):
   3956             if i > 0:
   3957                 begin_fill()
   3958                 fillcolor(255-15*i, 0, 15*i)
   3959             for _ in range(3):
   3960                 fd(laenge)
   3961                 lt(120)
   3962             laenge += 10
   3963             lt(15)
   3964             speed((speed()+1)%12)
   3965         end_fill()
   3966 
   3967         lt(120)
   3968         pu()
   3969         fd(70)
   3970         rt(30)
   3971         pd()
   3972         color("red","yellow")
   3973         speed(0)
   3974         fill(1)
   3975         for _ in range(4):
   3976             circle(50, 90)
   3977             rt(90)
   3978             fd(30)
   3979             rt(90)
   3980         fill(0)
   3981         lt(90)
   3982         pu()
   3983         fd(30)
   3984         pd()
   3985         shape("turtle")
   3986 
   3987         tri = getturtle()
   3988         tri.resizemode("auto")
   3989         turtle = Turtle()
   3990         turtle.resizemode(u"auto")
   3991         turtle.shape("turtle")
   3992         turtle.reset()
   3993         turtle.left(90)
   3994         turtle.speed(0)
   3995         turtle.up()
   3996         turtle.goto(280, 40)
   3997         turtle.lt(30)
   3998         turtle.down()
   3999         turtle.speed(6)
   4000         turtle.color("blue",u"orange")
   4001         turtle.pensize(2)
   4002         tri.speed(6)
   4003         setheading(towards(turtle))
   4004         count = 1
   4005         while tri.distance(turtle) > 4:
   4006             turtle.fd(3.5)
   4007             turtle.lt(0.6)
   4008             tri.setheading(tri.towards(turtle))
   4009             tri.fd(4)
   4010             if count % 20 == 0:
   4011                 turtle.stamp()
   4012                 tri.stamp()
   4013                 switchpen()
   4014             count += 1
   4015         tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align=u"right")
   4016         tri.pencolor("black")
   4017         tri.pencolor(u"red")
   4018 
   4019         def baba(xdummy, ydummy):
   4020             clearscreen()
   4021             bye()
   4022 
   4023         time.sleep(2)
   4024 
   4025         while undobufferentries():
   4026             tri.undo()
   4027             turtle.undo()
   4028         tri.fd(50)
   4029         tri.write("  Click me!", font = ("Courier", 12, "bold") )
   4030         tri.onclick(baba, 1)
   4031 
   4032     demo1()
   4033     demo2()
   4034     exitonclick()
   4035