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