summaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Lib/turtle.py
diff options
context:
space:
mode:
authororivej <[email protected]>2022-02-10 16:44:49 +0300
committerDaniil Cherednik <[email protected]>2022-02-10 16:44:49 +0300
commit718c552901d703c502ccbefdfc3c9028d608b947 (patch)
tree46534a98bbefcd7b1f3faa5b52c138ab27db75b7 /contrib/tools/python3/src/Lib/turtle.py
parente9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (diff)
Restoring authorship annotation for <[email protected]>. Commit 1 of 2.
Diffstat (limited to 'contrib/tools/python3/src/Lib/turtle.py')
-rw-r--r--contrib/tools/python3/src/Lib/turtle.py8248
1 files changed, 4124 insertions, 4124 deletions
diff --git a/contrib/tools/python3/src/Lib/turtle.py b/contrib/tools/python3/src/Lib/turtle.py
index 9c8f6ced250..9d5a3f4a886 100644
--- a/contrib/tools/python3/src/Lib/turtle.py
+++ b/contrib/tools/python3/src/Lib/turtle.py
@@ -1,4141 +1,4141 @@
-#
-# turtle.py: a Tkinter based turtle graphics module for Python
-# Version 1.1b - 4. 5. 2009
-#
-# Copyright (C) 2006 - 2010 Gregor Lingl
-#
-# This software is provided 'as-is', without any express or implied
-# warranty. In no event will the authors be held liable for any damages
-# arising from the use of this software.
-#
-# Permission is granted to anyone to use this software for any purpose,
-# including commercial applications, and to alter it and redistribute it
-# freely, subject to the following restrictions:
-#
-# 1. The origin of this software must not be misrepresented; you must not
-# claim that you wrote the original software. If you use this software
-# in a product, an acknowledgment in the product documentation would be
-# appreciated but is not required.
-# 2. Altered source versions must be plainly marked as such, and must not be
-# misrepresented as being the original software.
-# 3. This notice may not be removed or altered from any source distribution.
-
-
-"""
-Turtle graphics is a popular way for introducing programming to
-kids. It was part of the original Logo programming language developed
-by Wally Feurzig and Seymour Papert in 1966.
-
-Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
-the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
-the direction it is facing, drawing a line as it moves. Give it the
-command turtle.right(25), and it rotates in-place 25 degrees clockwise.
-
-By combining together these and similar commands, intricate shapes and
-pictures can easily be drawn.
-
------ turtle.py
-
-This module is an extended reimplementation of turtle.py from the
+#
+# turtle.py: a Tkinter based turtle graphics module for Python
+# Version 1.1b - 4. 5. 2009
+#
+# Copyright (C) 2006 - 2010 Gregor Lingl
+#
+# This software is provided 'as-is', without any express or implied
+# warranty. In no event will the authors be held liable for any damages
+# arising from the use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software
+# in a product, an acknowledgment in the product documentation would be
+# appreciated but is not required.
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+# 3. This notice may not be removed or altered from any source distribution.
+
+
+"""
+Turtle graphics is a popular way for introducing programming to
+kids. It was part of the original Logo programming language developed
+by Wally Feurzig and Seymour Papert in 1966.
+
+Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
+the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
+the direction it is facing, drawing a line as it moves. Give it the
+command turtle.right(25), and it rotates in-place 25 degrees clockwise.
+
+By combining together these and similar commands, intricate shapes and
+pictures can easily be drawn.
+
+----- turtle.py
+
+This module is an extended reimplementation of turtle.py from the
Python standard distribution up to Python 2.5. (See: https://www.python.org)
-
-It tries to keep the merits of turtle.py and to be (nearly) 100%
-compatible with it. This means in the first place to enable the
-learning programmer to use all the commands, classes and methods
-interactively when using the module from within IDLE run with
-the -n switch.
-
-Roughly it has the following features added:
-
-- Better animation of the turtle movements, especially of turning the
- turtle. So the turtles can more easily be used as a visual feedback
- instrument by the (beginning) programmer.
-
-- Different turtle shapes, gif-images as turtle shapes, user defined
- and user controllable turtle shapes, among them compound
- (multicolored) shapes. Turtle shapes can be stretched and tilted, which
- makes turtles very versatile geometrical objects.
-
-- Fine control over turtle movement and screen updates via delay(),
- and enhanced tracer() and speed() methods.
-
-- Aliases for the most commonly used commands, like fd for forward etc.,
- following the early Logo traditions. This reduces the boring work of
- typing long sequences of commands, which often occur in a natural way
- when kids try to program fancy pictures on their first encounter with
- turtle graphics.
-
-- Turtles now have an undo()-method with configurable undo-buffer.
-
-- Some simple commands/methods for creating event driven programs
- (mouse-, key-, timer-events). Especially useful for programming games.
-
-- A scrollable Canvas class. The default scrollable Canvas can be
- extended interactively as needed while playing around with the turtle(s).
-
-- A TurtleScreen class with methods controlling background color or
- background image, window and canvas size and other properties of the
- TurtleScreen.
-
-- There is a method, setworldcoordinates(), to install a user defined
- coordinate-system for the TurtleScreen.
-
-- The implementation uses a 2-vector class named Vec2D, derived from tuple.
- This class is public, so it can be imported by the application programmer,
- which makes certain types of computations very natural and compact.
-
-- Appearance of the TurtleScreen and the Turtles at startup/import can be
- configured by means of a turtle.cfg configuration file.
- The default configuration mimics the appearance of the old turtle module.
-
-- If configured appropriately the module reads in docstrings from a docstring
- dictionary in some different language, supplied separately and replaces
- the English ones by those read in. There is a utility function
- write_docstringdict() to write a dictionary with the original (English)
- docstrings to disc, so it can serve as a template for translations.
-
-Behind the scenes there are some features included with possible
-extensions in mind. These will be commented and documented elsewhere.
-
-"""
-
-_ver = "turtle 1.1b- - for Python 3.1 - 4. 5. 2009"
-
-# print(_ver)
-
-import tkinter as TK
-import types
-import math
-import time
-import inspect
-import sys
-
-from os.path import isfile, split, join
-from copy import deepcopy
-from tkinter import simpledialog
-
-_tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
- 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
-_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
- 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
- 'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
- 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
- 'register_shape', 'resetscreen', 'screensize', 'setup',
- 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
- 'window_height', 'window_width']
-_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
- 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
- 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
- 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
- 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
- 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
- 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
- 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
- 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
- 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
- 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
- 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
- 'write', 'xcor', 'ycor']
-_tg_utilities = ['write_docstringdict', 'done']
-
-__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
- _tg_utilities + ['Terminator']) # + _math_functions)
-
-_alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
- 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
- 'turtlesize', 'up', 'width']
-
-_CFG = {"width" : 0.5, # Screen
- "height" : 0.75,
- "canvwidth" : 400,
- "canvheight": 300,
- "leftright": None,
- "topbottom": None,
- "mode": "standard", # TurtleScreen
- "colormode": 1.0,
- "delay": 10,
- "undobuffersize": 1000, # RawTurtle
- "shape": "classic",
- "pencolor" : "black",
- "fillcolor" : "black",
- "resizemode" : "noresize",
- "visible" : True,
- "language": "english", # docstrings
- "exampleturtle": "turtle",
- "examplescreen": "screen",
- "title": "Python Turtle Graphics",
- "using_IDLE": False
- }
-
-def config_dict(filename):
- """Convert content of config-file into dictionary."""
- with open(filename, "r") as f:
- cfglines = f.readlines()
- cfgdict = {}
- for line in cfglines:
- line = line.strip()
- if not line or line.startswith("#"):
- continue
- try:
- key, value = line.split("=")
- except ValueError:
- print("Bad line in config-file %s:\n%s" % (filename,line))
- continue
- key = key.strip()
- value = value.strip()
- if value in ["True", "False", "None", "''", '""']:
- value = eval(value)
- else:
- try:
- if "." in value:
- value = float(value)
- else:
- value = int(value)
- except ValueError:
- pass # value need not be converted
- cfgdict[key] = value
- return cfgdict
-
-def readconfig(cfgdict):
- """Read config-files, change configuration-dict accordingly.
-
- If there is a turtle.cfg file in the current working directory,
- read it from there. If this contains an importconfig-value,
- say 'myway', construct filename turtle_mayway.cfg else use
- turtle.cfg and read it from the import-directory, where
- turtle.py is located.
- Update configuration dictionary first according to config-file,
- in the import directory, then according to config-file in the
- current working directory.
- If no config-file is found, the default configuration is used.
- """
- default_cfg = "turtle.cfg"
- cfgdict1 = {}
- cfgdict2 = {}
- if isfile(default_cfg):
- cfgdict1 = config_dict(default_cfg)
- if "importconfig" in cfgdict1:
- default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
- try:
- head, tail = split(__file__)
- cfg_file2 = join(head, default_cfg)
- except Exception:
- cfg_file2 = ""
- if isfile(cfg_file2):
- cfgdict2 = config_dict(cfg_file2)
- _CFG.update(cfgdict2)
- _CFG.update(cfgdict1)
-
-try:
- readconfig(_CFG)
-except Exception:
- print ("No configfile read, reason unknown")
-
-
-class Vec2D(tuple):
- """A 2 dimensional vector class, used as a helper class
- for implementing turtle graphics.
- May be useful for turtle graphics programs also.
- Derived from tuple, so a vector is a tuple!
-
- Provides (for a, b vectors, k number):
- a+b vector addition
- a-b vector subtraction
- a*b inner product
- k*a and a*k multiplication with scalar
- |a| absolute value of a
- a.rotate(angle) rotation
- """
- def __new__(cls, x, y):
- return tuple.__new__(cls, (x, y))
- def __add__(self, other):
- return Vec2D(self[0]+other[0], self[1]+other[1])
- def __mul__(self, other):
- if isinstance(other, Vec2D):
- return self[0]*other[0]+self[1]*other[1]
- return Vec2D(self[0]*other, self[1]*other)
- def __rmul__(self, other):
- if isinstance(other, int) or isinstance(other, float):
- return Vec2D(self[0]*other, self[1]*other)
+
+It tries to keep the merits of turtle.py and to be (nearly) 100%
+compatible with it. This means in the first place to enable the
+learning programmer to use all the commands, classes and methods
+interactively when using the module from within IDLE run with
+the -n switch.
+
+Roughly it has the following features added:
+
+- Better animation of the turtle movements, especially of turning the
+ turtle. So the turtles can more easily be used as a visual feedback
+ instrument by the (beginning) programmer.
+
+- Different turtle shapes, gif-images as turtle shapes, user defined
+ and user controllable turtle shapes, among them compound
+ (multicolored) shapes. Turtle shapes can be stretched and tilted, which
+ makes turtles very versatile geometrical objects.
+
+- Fine control over turtle movement and screen updates via delay(),
+ and enhanced tracer() and speed() methods.
+
+- Aliases for the most commonly used commands, like fd for forward etc.,
+ following the early Logo traditions. This reduces the boring work of
+ typing long sequences of commands, which often occur in a natural way
+ when kids try to program fancy pictures on their first encounter with
+ turtle graphics.
+
+- Turtles now have an undo()-method with configurable undo-buffer.
+
+- Some simple commands/methods for creating event driven programs
+ (mouse-, key-, timer-events). Especially useful for programming games.
+
+- A scrollable Canvas class. The default scrollable Canvas can be
+ extended interactively as needed while playing around with the turtle(s).
+
+- A TurtleScreen class with methods controlling background color or
+ background image, window and canvas size and other properties of the
+ TurtleScreen.
+
+- There is a method, setworldcoordinates(), to install a user defined
+ coordinate-system for the TurtleScreen.
+
+- The implementation uses a 2-vector class named Vec2D, derived from tuple.
+ This class is public, so it can be imported by the application programmer,
+ which makes certain types of computations very natural and compact.
+
+- Appearance of the TurtleScreen and the Turtles at startup/import can be
+ configured by means of a turtle.cfg configuration file.
+ The default configuration mimics the appearance of the old turtle module.
+
+- If configured appropriately the module reads in docstrings from a docstring
+ dictionary in some different language, supplied separately and replaces
+ the English ones by those read in. There is a utility function
+ write_docstringdict() to write a dictionary with the original (English)
+ docstrings to disc, so it can serve as a template for translations.
+
+Behind the scenes there are some features included with possible
+extensions in mind. These will be commented and documented elsewhere.
+
+"""
+
+_ver = "turtle 1.1b- - for Python 3.1 - 4. 5. 2009"
+
+# print(_ver)
+
+import tkinter as TK
+import types
+import math
+import time
+import inspect
+import sys
+
+from os.path import isfile, split, join
+from copy import deepcopy
+from tkinter import simpledialog
+
+_tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
+ 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
+_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
+ 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
+ 'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
+ 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
+ 'register_shape', 'resetscreen', 'screensize', 'setup',
+ 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
+ 'window_height', 'window_width']
+_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
+ 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
+ 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
+ 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
+ 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
+ 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
+ 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
+ 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
+ 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
+ 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
+ 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
+ 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
+ 'write', 'xcor', 'ycor']
+_tg_utilities = ['write_docstringdict', 'done']
+
+__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
+ _tg_utilities + ['Terminator']) # + _math_functions)
+
+_alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
+ 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
+ 'turtlesize', 'up', 'width']
+
+_CFG = {"width" : 0.5, # Screen
+ "height" : 0.75,
+ "canvwidth" : 400,
+ "canvheight": 300,
+ "leftright": None,
+ "topbottom": None,
+ "mode": "standard", # TurtleScreen
+ "colormode": 1.0,
+ "delay": 10,
+ "undobuffersize": 1000, # RawTurtle
+ "shape": "classic",
+ "pencolor" : "black",
+ "fillcolor" : "black",
+ "resizemode" : "noresize",
+ "visible" : True,
+ "language": "english", # docstrings
+ "exampleturtle": "turtle",
+ "examplescreen": "screen",
+ "title": "Python Turtle Graphics",
+ "using_IDLE": False
+ }
+
+def config_dict(filename):
+ """Convert content of config-file into dictionary."""
+ with open(filename, "r") as f:
+ cfglines = f.readlines()
+ cfgdict = {}
+ for line in cfglines:
+ line = line.strip()
+ if not line or line.startswith("#"):
+ continue
+ try:
+ key, value = line.split("=")
+ except ValueError:
+ print("Bad line in config-file %s:\n%s" % (filename,line))
+ continue
+ key = key.strip()
+ value = value.strip()
+ if value in ["True", "False", "None", "''", '""']:
+ value = eval(value)
+ else:
+ try:
+ if "." in value:
+ value = float(value)
+ else:
+ value = int(value)
+ except ValueError:
+ pass # value need not be converted
+ cfgdict[key] = value
+ return cfgdict
+
+def readconfig(cfgdict):
+ """Read config-files, change configuration-dict accordingly.
+
+ If there is a turtle.cfg file in the current working directory,
+ read it from there. If this contains an importconfig-value,
+ say 'myway', construct filename turtle_mayway.cfg else use
+ turtle.cfg and read it from the import-directory, where
+ turtle.py is located.
+ Update configuration dictionary first according to config-file,
+ in the import directory, then according to config-file in the
+ current working directory.
+ If no config-file is found, the default configuration is used.
+ """
+ default_cfg = "turtle.cfg"
+ cfgdict1 = {}
+ cfgdict2 = {}
+ if isfile(default_cfg):
+ cfgdict1 = config_dict(default_cfg)
+ if "importconfig" in cfgdict1:
+ default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
+ try:
+ head, tail = split(__file__)
+ cfg_file2 = join(head, default_cfg)
+ except Exception:
+ cfg_file2 = ""
+ if isfile(cfg_file2):
+ cfgdict2 = config_dict(cfg_file2)
+ _CFG.update(cfgdict2)
+ _CFG.update(cfgdict1)
+
+try:
+ readconfig(_CFG)
+except Exception:
+ print ("No configfile read, reason unknown")
+
+
+class Vec2D(tuple):
+ """A 2 dimensional vector class, used as a helper class
+ for implementing turtle graphics.
+ May be useful for turtle graphics programs also.
+ Derived from tuple, so a vector is a tuple!
+
+ Provides (for a, b vectors, k number):
+ a+b vector addition
+ a-b vector subtraction
+ a*b inner product
+ k*a and a*k multiplication with scalar
+ |a| absolute value of a
+ a.rotate(angle) rotation
+ """
+ def __new__(cls, x, y):
+ return tuple.__new__(cls, (x, y))
+ def __add__(self, other):
+ return Vec2D(self[0]+other[0], self[1]+other[1])
+ def __mul__(self, other):
+ if isinstance(other, Vec2D):
+ return self[0]*other[0]+self[1]*other[1]
+ return Vec2D(self[0]*other, self[1]*other)
+ def __rmul__(self, other):
+ if isinstance(other, int) or isinstance(other, float):
+ return Vec2D(self[0]*other, self[1]*other)
return NotImplemented
- def __sub__(self, other):
- return Vec2D(self[0]-other[0], self[1]-other[1])
- def __neg__(self):
- return Vec2D(-self[0], -self[1])
- def __abs__(self):
- return (self[0]**2 + self[1]**2)**0.5
- def rotate(self, angle):
- """rotate self counterclockwise by angle
- """
- perp = Vec2D(-self[1], self[0])
- angle = angle * math.pi / 180.0
- c, s = math.cos(angle), math.sin(angle)
- return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
- def __getnewargs__(self):
- return (self[0], self[1])
- def __repr__(self):
- return "(%.2f,%.2f)" % self
-
-
-##############################################################################
-### From here up to line : Tkinter - Interface for turtle.py ###
-### May be replaced by an interface to some different graphics toolkit ###
-##############################################################################
-
-## helper functions for Scrolled Canvas, to forward Canvas-methods
-## to ScrolledCanvas class
-
-def __methodDict(cls, _dict):
- """helper function for Scrolled Canvas"""
- baseList = list(cls.__bases__)
- baseList.reverse()
- for _super in baseList:
- __methodDict(_super, _dict)
- for key, value in cls.__dict__.items():
- if type(value) == types.FunctionType:
- _dict[key] = value
-
-def __methods(cls):
- """helper function for Scrolled Canvas"""
- _dict = {}
- __methodDict(cls, _dict)
- return _dict.keys()
-
-__stringBody = (
- 'def %(method)s(self, *args, **kw): return ' +
- 'self.%(attribute)s.%(method)s(*args, **kw)')
-
-def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
- ### MANY CHANGES ###
- _dict_1 = {}
- __methodDict(toClass, _dict_1)
- _dict = {}
- mfc = __methods(fromClass)
- for ex in _dict_1.keys():
- if ex[:1] == '_' or ex[-1:] == '_' or ex in exclude or ex in mfc:
- pass
- else:
- _dict[ex] = _dict_1[ex]
-
- for method, func in _dict.items():
- d = {'method': method, 'func': func}
- if isinstance(toPart, str):
- execString = \
- __stringBody % {'method' : method, 'attribute' : toPart}
- exec(execString, d)
- setattr(fromClass, method, d[method]) ### NEWU!
-
-
-class ScrolledCanvas(TK.Frame):
- """Modeled after the scrolled canvas class from Grayons's Tkinter book.
-
- Used as the default canvas, which pops up automatically when
- using turtle graphics functions or the Turtle class.
- """
- def __init__(self, master, width=500, height=350,
- canvwidth=600, canvheight=500):
- TK.Frame.__init__(self, master, width=width, height=height)
- self._rootwindow = self.winfo_toplevel()
- self.width, self.height = width, height
- self.canvwidth, self.canvheight = canvwidth, canvheight
- self.bg = "white"
- self._canvas = TK.Canvas(master, width=width, height=height,
- bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
- self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
- orient=TK.HORIZONTAL)
- self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
- self._canvas.configure(xscrollcommand=self.hscroll.set,
- yscrollcommand=self.vscroll.set)
- self.rowconfigure(0, weight=1, minsize=0)
- self.columnconfigure(0, weight=1, minsize=0)
- self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
- column=0, rowspan=1, columnspan=1, sticky='news')
- self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
- column=1, rowspan=1, columnspan=1, sticky='news')
- self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
- column=0, rowspan=1, columnspan=1, sticky='news')
- self.reset()
- self._rootwindow.bind('<Configure>', self.onResize)
-
- def reset(self, canvwidth=None, canvheight=None, bg = None):
- """Adjust canvas and scrollbars according to given canvas size."""
- if canvwidth:
- self.canvwidth = canvwidth
- if canvheight:
- self.canvheight = canvheight
- if bg:
- self.bg = bg
- self._canvas.config(bg=bg,
- scrollregion=(-self.canvwidth//2, -self.canvheight//2,
- self.canvwidth//2, self.canvheight//2))
- self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
- self.canvwidth)
- self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
- self.canvheight)
- self.adjustScrolls()
-
-
- def adjustScrolls(self):
- """ Adjust scrollbars according to window- and canvas-size.
- """
- cwidth = self._canvas.winfo_width()
- cheight = self._canvas.winfo_height()
- self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
- self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
- if cwidth < self.canvwidth or cheight < self.canvheight:
- self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
- column=0, rowspan=1, columnspan=1, sticky='news')
- self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
- column=1, rowspan=1, columnspan=1, sticky='news')
- else:
- self.hscroll.grid_forget()
- self.vscroll.grid_forget()
-
- def onResize(self, event):
- """self-explanatory"""
- self.adjustScrolls()
-
- def bbox(self, *args):
- """ 'forward' method, which canvas itself has inherited...
- """
- return self._canvas.bbox(*args)
-
- def cget(self, *args, **kwargs):
- """ 'forward' method, which canvas itself has inherited...
- """
- return self._canvas.cget(*args, **kwargs)
-
- def config(self, *args, **kwargs):
- """ 'forward' method, which canvas itself has inherited...
- """
- self._canvas.config(*args, **kwargs)
-
- def bind(self, *args, **kwargs):
- """ 'forward' method, which canvas itself has inherited...
- """
- self._canvas.bind(*args, **kwargs)
-
- def unbind(self, *args, **kwargs):
- """ 'forward' method, which canvas itself has inherited...
- """
- self._canvas.unbind(*args, **kwargs)
-
- def focus_force(self):
- """ 'forward' method, which canvas itself has inherited...
- """
- self._canvas.focus_force()
-
-__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
-
-
-class _Root(TK.Tk):
- """Root class for Screen based on Tkinter."""
- def __init__(self):
- TK.Tk.__init__(self)
-
- def setupcanvas(self, width, height, cwidth, cheight):
- self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
- self._canvas.pack(expand=1, fill="both")
-
- def _getcanvas(self):
- return self._canvas
-
- def set_geometry(self, width, height, startx, starty):
- self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
-
- def ondestroy(self, destroy):
- self.wm_protocol("WM_DELETE_WINDOW", destroy)
-
- def win_width(self):
- return self.winfo_screenwidth()
-
- def win_height(self):
- return self.winfo_screenheight()
-
-Canvas = TK.Canvas
-
-
-class TurtleScreenBase(object):
- """Provide the basic graphics functionality.
- Interface between Tkinter and turtle.py.
-
- To port turtle.py to some different graphics toolkit
- a corresponding TurtleScreenBase class has to be implemented.
- """
-
+ def __sub__(self, other):
+ return Vec2D(self[0]-other[0], self[1]-other[1])
+ def __neg__(self):
+ return Vec2D(-self[0], -self[1])
+ def __abs__(self):
+ return (self[0]**2 + self[1]**2)**0.5
+ def rotate(self, angle):
+ """rotate self counterclockwise by angle
+ """
+ perp = Vec2D(-self[1], self[0])
+ angle = angle * math.pi / 180.0
+ c, s = math.cos(angle), math.sin(angle)
+ return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
+ def __getnewargs__(self):
+ return (self[0], self[1])
+ def __repr__(self):
+ return "(%.2f,%.2f)" % self
+
+
+##############################################################################
+### From here up to line : Tkinter - Interface for turtle.py ###
+### May be replaced by an interface to some different graphics toolkit ###
+##############################################################################
+
+## helper functions for Scrolled Canvas, to forward Canvas-methods
+## to ScrolledCanvas class
+
+def __methodDict(cls, _dict):
+ """helper function for Scrolled Canvas"""
+ baseList = list(cls.__bases__)
+ baseList.reverse()
+ for _super in baseList:
+ __methodDict(_super, _dict)
+ for key, value in cls.__dict__.items():
+ if type(value) == types.FunctionType:
+ _dict[key] = value
+
+def __methods(cls):
+ """helper function for Scrolled Canvas"""
+ _dict = {}
+ __methodDict(cls, _dict)
+ return _dict.keys()
+
+__stringBody = (
+ 'def %(method)s(self, *args, **kw): return ' +
+ 'self.%(attribute)s.%(method)s(*args, **kw)')
+
+def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
+ ### MANY CHANGES ###
+ _dict_1 = {}
+ __methodDict(toClass, _dict_1)
+ _dict = {}
+ mfc = __methods(fromClass)
+ for ex in _dict_1.keys():
+ if ex[:1] == '_' or ex[-1:] == '_' or ex in exclude or ex in mfc:
+ pass
+ else:
+ _dict[ex] = _dict_1[ex]
+
+ for method, func in _dict.items():
+ d = {'method': method, 'func': func}
+ if isinstance(toPart, str):
+ execString = \
+ __stringBody % {'method' : method, 'attribute' : toPart}
+ exec(execString, d)
+ setattr(fromClass, method, d[method]) ### NEWU!
+
+
+class ScrolledCanvas(TK.Frame):
+ """Modeled after the scrolled canvas class from Grayons's Tkinter book.
+
+ Used as the default canvas, which pops up automatically when
+ using turtle graphics functions or the Turtle class.
+ """
+ def __init__(self, master, width=500, height=350,
+ canvwidth=600, canvheight=500):
+ TK.Frame.__init__(self, master, width=width, height=height)
+ self._rootwindow = self.winfo_toplevel()
+ self.width, self.height = width, height
+ self.canvwidth, self.canvheight = canvwidth, canvheight
+ self.bg = "white"
+ self._canvas = TK.Canvas(master, width=width, height=height,
+ bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
+ self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
+ orient=TK.HORIZONTAL)
+ self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
+ self._canvas.configure(xscrollcommand=self.hscroll.set,
+ yscrollcommand=self.vscroll.set)
+ self.rowconfigure(0, weight=1, minsize=0)
+ self.columnconfigure(0, weight=1, minsize=0)
+ self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
+ column=0, rowspan=1, columnspan=1, sticky='news')
+ self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
+ column=1, rowspan=1, columnspan=1, sticky='news')
+ self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
+ column=0, rowspan=1, columnspan=1, sticky='news')
+ self.reset()
+ self._rootwindow.bind('<Configure>', self.onResize)
+
+ def reset(self, canvwidth=None, canvheight=None, bg = None):
+ """Adjust canvas and scrollbars according to given canvas size."""
+ if canvwidth:
+ self.canvwidth = canvwidth
+ if canvheight:
+ self.canvheight = canvheight
+ if bg:
+ self.bg = bg
+ self._canvas.config(bg=bg,
+ scrollregion=(-self.canvwidth//2, -self.canvheight//2,
+ self.canvwidth//2, self.canvheight//2))
+ self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
+ self.canvwidth)
+ self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
+ self.canvheight)
+ self.adjustScrolls()
+
+
+ def adjustScrolls(self):
+ """ Adjust scrollbars according to window- and canvas-size.
+ """
+ cwidth = self._canvas.winfo_width()
+ cheight = self._canvas.winfo_height()
+ self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
+ self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
+ if cwidth < self.canvwidth or cheight < self.canvheight:
+ self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
+ column=0, rowspan=1, columnspan=1, sticky='news')
+ self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
+ column=1, rowspan=1, columnspan=1, sticky='news')
+ else:
+ self.hscroll.grid_forget()
+ self.vscroll.grid_forget()
+
+ def onResize(self, event):
+ """self-explanatory"""
+ self.adjustScrolls()
+
+ def bbox(self, *args):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ return self._canvas.bbox(*args)
+
+ def cget(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ return self._canvas.cget(*args, **kwargs)
+
+ def config(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.config(*args, **kwargs)
+
+ def bind(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.bind(*args, **kwargs)
+
+ def unbind(self, *args, **kwargs):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.unbind(*args, **kwargs)
+
+ def focus_force(self):
+ """ 'forward' method, which canvas itself has inherited...
+ """
+ self._canvas.focus_force()
+
+__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
+
+
+class _Root(TK.Tk):
+ """Root class for Screen based on Tkinter."""
+ def __init__(self):
+ TK.Tk.__init__(self)
+
+ def setupcanvas(self, width, height, cwidth, cheight):
+ self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
+ self._canvas.pack(expand=1, fill="both")
+
+ def _getcanvas(self):
+ return self._canvas
+
+ def set_geometry(self, width, height, startx, starty):
+ self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
+
+ def ondestroy(self, destroy):
+ self.wm_protocol("WM_DELETE_WINDOW", destroy)
+
+ def win_width(self):
+ return self.winfo_screenwidth()
+
+ def win_height(self):
+ return self.winfo_screenheight()
+
+Canvas = TK.Canvas
+
+
+class TurtleScreenBase(object):
+ """Provide the basic graphics functionality.
+ Interface between Tkinter and turtle.py.
+
+ To port turtle.py to some different graphics toolkit
+ a corresponding TurtleScreenBase class has to be implemented.
+ """
+
def _blankimage(self):
- """return a blank image object
- """
+ """return a blank image object
+ """
img = TK.PhotoImage(width=1, height=1, master=self.cv)
- img.blank()
- return img
-
+ img.blank()
+ return img
+
def _image(self, filename):
- """return an image object containing the
- imagedata from a gif-file named filename.
- """
+ """return an image object containing the
+ imagedata from a gif-file named filename.
+ """
return TK.PhotoImage(file=filename, master=self.cv)
-
- def __init__(self, cv):
- self.cv = cv
- if isinstance(cv, ScrolledCanvas):
- w = self.cv.canvwidth
- h = self.cv.canvheight
- else: # expected: ordinary TK.Canvas
- w = int(self.cv.cget("width"))
- h = int(self.cv.cget("height"))
- self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
- self.canvwidth = w
- self.canvheight = h
- self.xscale = self.yscale = 1.0
-
- def _createpoly(self):
- """Create an invisible polygon item on canvas self.cv)
- """
- return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
-
- def _drawpoly(self, polyitem, coordlist, fill=None,
- outline=None, width=None, top=False):
- """Configure polygonitem polyitem according to provided
- arguments:
- coordlist is sequence of coordinates
- fill is filling color
- outline is outline color
- top is a boolean value, which specifies if polyitem
- will be put on top of the canvas' displaylist so it
- will not be covered by other items.
- """
- cl = []
- for x, y in coordlist:
- cl.append(x * self.xscale)
- cl.append(-y * self.yscale)
- self.cv.coords(polyitem, *cl)
- if fill is not None:
- self.cv.itemconfigure(polyitem, fill=fill)
- if outline is not None:
- self.cv.itemconfigure(polyitem, outline=outline)
- if width is not None:
- self.cv.itemconfigure(polyitem, width=width)
- if top:
- self.cv.tag_raise(polyitem)
-
- def _createline(self):
- """Create an invisible line item on canvas self.cv)
- """
- return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
- capstyle = TK.ROUND)
-
- def _drawline(self, lineitem, coordlist=None,
- fill=None, width=None, top=False):
- """Configure lineitem according to provided arguments:
- coordlist is sequence of coordinates
- fill is drawing color
- width is width of drawn line.
- top is a boolean value, which specifies if polyitem
- will be put on top of the canvas' displaylist so it
- will not be covered by other items.
- """
- if coordlist is not None:
- cl = []
- for x, y in coordlist:
- cl.append(x * self.xscale)
- cl.append(-y * self.yscale)
- self.cv.coords(lineitem, *cl)
- if fill is not None:
- self.cv.itemconfigure(lineitem, fill=fill)
- if width is not None:
- self.cv.itemconfigure(lineitem, width=width)
- if top:
- self.cv.tag_raise(lineitem)
-
- def _delete(self, item):
- """Delete graphics item from canvas.
- If item is"all" delete all graphics items.
- """
- self.cv.delete(item)
-
- def _update(self):
- """Redraw graphics items on canvas
- """
- self.cv.update()
-
- def _delay(self, delay):
- """Delay subsequent canvas actions for delay ms."""
- self.cv.after(delay)
-
- def _iscolorstring(self, color):
- """Check if the string color is a legal Tkinter color string.
- """
- try:
- rgb = self.cv.winfo_rgb(color)
- ok = True
- except TK.TclError:
- ok = False
- return ok
-
- def _bgcolor(self, color=None):
- """Set canvas' backgroundcolor if color is not None,
- else return backgroundcolor."""
- if color is not None:
- self.cv.config(bg = color)
- self._update()
- else:
- return self.cv.cget("bg")
-
- def _write(self, pos, txt, align, font, pencolor):
- """Write txt at pos in canvas with specified font
- and color.
- Return text item and x-coord of right bottom corner
- of text's bounding box."""
- x, y = pos
- x = x * self.xscale
- y = y * self.yscale
- anchor = {"left":"sw", "center":"s", "right":"se" }
- item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
- fill = pencolor, font = font)
- x0, y0, x1, y1 = self.cv.bbox(item)
- self.cv.update()
- return item, x1-1
-
-## def _dot(self, pos, size, color):
-## """may be implemented for some other graphics toolkit"""
-
- def _onclick(self, item, fun, num=1, add=None):
- """Bind fun to mouse-click event on turtle.
- fun must be a function with two arguments, the coordinates
- of the clicked point on the canvas.
- num, the number of the mouse-button defaults to 1
- """
- if fun is None:
- self.cv.tag_unbind(item, "<Button-%s>" % num)
- else:
- def eventfun(event):
- x, y = (self.cv.canvasx(event.x)/self.xscale,
- -self.cv.canvasy(event.y)/self.yscale)
- fun(x, y)
- self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
-
- def _onrelease(self, item, fun, num=1, add=None):
- """Bind fun to mouse-button-release event on turtle.
- fun must be a function with two arguments, the coordinates
- of the point on the canvas where mouse button is released.
- num, the number of the mouse-button defaults to 1
-
- If a turtle is clicked, first _onclick-event will be performed,
- then _onscreensclick-event.
- """
- if fun is None:
- self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
- else:
- def eventfun(event):
- x, y = (self.cv.canvasx(event.x)/self.xscale,
- -self.cv.canvasy(event.y)/self.yscale)
- fun(x, y)
- self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
- eventfun, add)
-
- def _ondrag(self, item, fun, num=1, add=None):
- """Bind fun to mouse-move-event (with pressed mouse button) on turtle.
- fun must be a function with two arguments, the coordinates of the
- actual mouse position on the canvas.
- num, the number of the mouse-button defaults to 1
-
- Every sequence of mouse-move-events on a turtle is preceded by a
- mouse-click event on that turtle.
- """
- if fun is None:
- self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
- else:
- def eventfun(event):
- try:
- x, y = (self.cv.canvasx(event.x)/self.xscale,
- -self.cv.canvasy(event.y)/self.yscale)
- fun(x, y)
- except Exception:
- pass
- self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
-
- def _onscreenclick(self, fun, num=1, add=None):
- """Bind fun to mouse-click event on canvas.
- fun must be a function with two arguments, the coordinates
- of the clicked point on the canvas.
- num, the number of the mouse-button defaults to 1
-
- If a turtle is clicked, first _onclick-event will be performed,
- then _onscreensclick-event.
- """
- if fun is None:
- self.cv.unbind("<Button-%s>" % num)
- else:
- def eventfun(event):
- x, y = (self.cv.canvasx(event.x)/self.xscale,
- -self.cv.canvasy(event.y)/self.yscale)
- fun(x, y)
- self.cv.bind("<Button-%s>" % num, eventfun, add)
-
- def _onkeyrelease(self, fun, key):
- """Bind fun to key-release event of key.
- Canvas must have focus. See method listen
- """
- if fun is None:
- self.cv.unbind("<KeyRelease-%s>" % key, None)
- else:
- def eventfun(event):
- fun()
- self.cv.bind("<KeyRelease-%s>" % key, eventfun)
-
- def _onkeypress(self, fun, key=None):
- """If key is given, bind fun to key-press event of key.
- Otherwise bind fun to any key-press.
- Canvas must have focus. See method listen.
- """
- if fun is None:
- if key is None:
- self.cv.unbind("<KeyPress>", None)
- else:
- self.cv.unbind("<KeyPress-%s>" % key, None)
- else:
- def eventfun(event):
- fun()
- if key is None:
- self.cv.bind("<KeyPress>", eventfun)
- else:
- self.cv.bind("<KeyPress-%s>" % key, eventfun)
-
- def _listen(self):
- """Set focus on canvas (in order to collect key-events)
- """
- self.cv.focus_force()
-
- def _ontimer(self, fun, t):
- """Install a timer, which calls fun after t milliseconds.
- """
- if t == 0:
- self.cv.after_idle(fun)
- else:
- self.cv.after(t, fun)
-
- def _createimage(self, image):
- """Create and return image item on canvas.
- """
- return self.cv.create_image(0, 0, image=image)
-
- def _drawimage(self, item, pos, image):
- """Configure image item as to draw image object
- at position (x,y) on canvas)
- """
- x, y = pos
- self.cv.coords(item, (x * self.xscale, -y * self.yscale))
- self.cv.itemconfig(item, image=image)
-
- def _setbgpic(self, item, image):
- """Configure image item as to draw image object
- at center of canvas. Set item to the first item
- in the displaylist, so it will be drawn below
- any other item ."""
- self.cv.itemconfig(item, image=image)
- self.cv.tag_lower(item)
-
- def _type(self, item):
- """Return 'line' or 'polygon' or 'image' depending on
- type of item.
- """
- return self.cv.type(item)
-
- def _pointlist(self, item):
- """returns list of coordinate-pairs of points of item
- Example (for insiders):
- >>> from turtle import *
- >>> getscreen()._pointlist(getturtle().turtle._item)
- [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
- (9.9999999999999982, 0.0)]
- >>> """
- cl = self.cv.coords(item)
- pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
- return pl
-
- def _setscrollregion(self, srx1, sry1, srx2, sry2):
- self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
-
- def _rescale(self, xscalefactor, yscalefactor):
- items = self.cv.find_all()
- for item in items:
- coordinates = list(self.cv.coords(item))
- newcoordlist = []
- while coordinates:
- x, y = coordinates[:2]
- newcoordlist.append(x * xscalefactor)
- newcoordlist.append(y * yscalefactor)
- coordinates = coordinates[2:]
- self.cv.coords(item, *newcoordlist)
-
- def _resize(self, canvwidth=None, canvheight=None, bg=None):
- """Resize the canvas the turtles are drawing on. Does
- not alter the drawing window.
- """
- # needs amendment
- if not isinstance(self.cv, ScrolledCanvas):
- return self.canvwidth, self.canvheight
- if canvwidth is canvheight is bg is None:
- return self.cv.canvwidth, self.cv.canvheight
- if canvwidth is not None:
- self.canvwidth = canvwidth
- if canvheight is not None:
- self.canvheight = canvheight
- self.cv.reset(canvwidth, canvheight, bg)
-
- def _window_size(self):
- """ Return the width and height of the turtle window.
- """
- width = self.cv.winfo_width()
- if width <= 1: # the window isn't managed by a geometry manager
- width = self.cv['width']
- height = self.cv.winfo_height()
- if height <= 1: # the window isn't managed by a geometry manager
- height = self.cv['height']
- return width, height
-
- def mainloop(self):
- """Starts event loop - calling Tkinter's mainloop function.
-
- No argument.
-
- Must be last statement in a turtle graphics program.
- Must NOT be used if a script is run from within IDLE in -n mode
- (No subprocess) - for interactive use of turtle graphics.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.mainloop()
-
- """
+
+ def __init__(self, cv):
+ self.cv = cv
+ if isinstance(cv, ScrolledCanvas):
+ w = self.cv.canvwidth
+ h = self.cv.canvheight
+ else: # expected: ordinary TK.Canvas
+ w = int(self.cv.cget("width"))
+ h = int(self.cv.cget("height"))
+ self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
+ self.canvwidth = w
+ self.canvheight = h
+ self.xscale = self.yscale = 1.0
+
+ def _createpoly(self):
+ """Create an invisible polygon item on canvas self.cv)
+ """
+ return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
+
+ def _drawpoly(self, polyitem, coordlist, fill=None,
+ outline=None, width=None, top=False):
+ """Configure polygonitem polyitem according to provided
+ arguments:
+ coordlist is sequence of coordinates
+ fill is filling color
+ outline is outline color
+ top is a boolean value, which specifies if polyitem
+ will be put on top of the canvas' displaylist so it
+ will not be covered by other items.
+ """
+ cl = []
+ for x, y in coordlist:
+ cl.append(x * self.xscale)
+ cl.append(-y * self.yscale)
+ self.cv.coords(polyitem, *cl)
+ if fill is not None:
+ self.cv.itemconfigure(polyitem, fill=fill)
+ if outline is not None:
+ self.cv.itemconfigure(polyitem, outline=outline)
+ if width is not None:
+ self.cv.itemconfigure(polyitem, width=width)
+ if top:
+ self.cv.tag_raise(polyitem)
+
+ def _createline(self):
+ """Create an invisible line item on canvas self.cv)
+ """
+ return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
+ capstyle = TK.ROUND)
+
+ def _drawline(self, lineitem, coordlist=None,
+ fill=None, width=None, top=False):
+ """Configure lineitem according to provided arguments:
+ coordlist is sequence of coordinates
+ fill is drawing color
+ width is width of drawn line.
+ top is a boolean value, which specifies if polyitem
+ will be put on top of the canvas' displaylist so it
+ will not be covered by other items.
+ """
+ if coordlist is not None:
+ cl = []
+ for x, y in coordlist:
+ cl.append(x * self.xscale)
+ cl.append(-y * self.yscale)
+ self.cv.coords(lineitem, *cl)
+ if fill is not None:
+ self.cv.itemconfigure(lineitem, fill=fill)
+ if width is not None:
+ self.cv.itemconfigure(lineitem, width=width)
+ if top:
+ self.cv.tag_raise(lineitem)
+
+ def _delete(self, item):
+ """Delete graphics item from canvas.
+ If item is"all" delete all graphics items.
+ """
+ self.cv.delete(item)
+
+ def _update(self):
+ """Redraw graphics items on canvas
+ """
+ self.cv.update()
+
+ def _delay(self, delay):
+ """Delay subsequent canvas actions for delay ms."""
+ self.cv.after(delay)
+
+ def _iscolorstring(self, color):
+ """Check if the string color is a legal Tkinter color string.
+ """
+ try:
+ rgb = self.cv.winfo_rgb(color)
+ ok = True
+ except TK.TclError:
+ ok = False
+ return ok
+
+ def _bgcolor(self, color=None):
+ """Set canvas' backgroundcolor if color is not None,
+ else return backgroundcolor."""
+ if color is not None:
+ self.cv.config(bg = color)
+ self._update()
+ else:
+ return self.cv.cget("bg")
+
+ def _write(self, pos, txt, align, font, pencolor):
+ """Write txt at pos in canvas with specified font
+ and color.
+ Return text item and x-coord of right bottom corner
+ of text's bounding box."""
+ x, y = pos
+ x = x * self.xscale
+ y = y * self.yscale
+ anchor = {"left":"sw", "center":"s", "right":"se" }
+ item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
+ fill = pencolor, font = font)
+ x0, y0, x1, y1 = self.cv.bbox(item)
+ self.cv.update()
+ return item, x1-1
+
+## def _dot(self, pos, size, color):
+## """may be implemented for some other graphics toolkit"""
+
+ def _onclick(self, item, fun, num=1, add=None):
+ """Bind fun to mouse-click event on turtle.
+ fun must be a function with two arguments, the coordinates
+ of the clicked point on the canvas.
+ num, the number of the mouse-button defaults to 1
+ """
+ if fun is None:
+ self.cv.tag_unbind(item, "<Button-%s>" % num)
+ else:
+ def eventfun(event):
+ x, y = (self.cv.canvasx(event.x)/self.xscale,
+ -self.cv.canvasy(event.y)/self.yscale)
+ fun(x, y)
+ self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
+
+ def _onrelease(self, item, fun, num=1, add=None):
+ """Bind fun to mouse-button-release event on turtle.
+ fun must be a function with two arguments, the coordinates
+ of the point on the canvas where mouse button is released.
+ num, the number of the mouse-button defaults to 1
+
+ If a turtle is clicked, first _onclick-event will be performed,
+ then _onscreensclick-event.
+ """
+ if fun is None:
+ self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
+ else:
+ def eventfun(event):
+ x, y = (self.cv.canvasx(event.x)/self.xscale,
+ -self.cv.canvasy(event.y)/self.yscale)
+ fun(x, y)
+ self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
+ eventfun, add)
+
+ def _ondrag(self, item, fun, num=1, add=None):
+ """Bind fun to mouse-move-event (with pressed mouse button) on turtle.
+ fun must be a function with two arguments, the coordinates of the
+ actual mouse position on the canvas.
+ num, the number of the mouse-button defaults to 1
+
+ Every sequence of mouse-move-events on a turtle is preceded by a
+ mouse-click event on that turtle.
+ """
+ if fun is None:
+ self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
+ else:
+ def eventfun(event):
+ try:
+ x, y = (self.cv.canvasx(event.x)/self.xscale,
+ -self.cv.canvasy(event.y)/self.yscale)
+ fun(x, y)
+ except Exception:
+ pass
+ self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
+
+ def _onscreenclick(self, fun, num=1, add=None):
+ """Bind fun to mouse-click event on canvas.
+ fun must be a function with two arguments, the coordinates
+ of the clicked point on the canvas.
+ num, the number of the mouse-button defaults to 1
+
+ If a turtle is clicked, first _onclick-event will be performed,
+ then _onscreensclick-event.
+ """
+ if fun is None:
+ self.cv.unbind("<Button-%s>" % num)
+ else:
+ def eventfun(event):
+ x, y = (self.cv.canvasx(event.x)/self.xscale,
+ -self.cv.canvasy(event.y)/self.yscale)
+ fun(x, y)
+ self.cv.bind("<Button-%s>" % num, eventfun, add)
+
+ def _onkeyrelease(self, fun, key):
+ """Bind fun to key-release event of key.
+ Canvas must have focus. See method listen
+ """
+ if fun is None:
+ self.cv.unbind("<KeyRelease-%s>" % key, None)
+ else:
+ def eventfun(event):
+ fun()
+ self.cv.bind("<KeyRelease-%s>" % key, eventfun)
+
+ def _onkeypress(self, fun, key=None):
+ """If key is given, bind fun to key-press event of key.
+ Otherwise bind fun to any key-press.
+ Canvas must have focus. See method listen.
+ """
+ if fun is None:
+ if key is None:
+ self.cv.unbind("<KeyPress>", None)
+ else:
+ self.cv.unbind("<KeyPress-%s>" % key, None)
+ else:
+ def eventfun(event):
+ fun()
+ if key is None:
+ self.cv.bind("<KeyPress>", eventfun)
+ else:
+ self.cv.bind("<KeyPress-%s>" % key, eventfun)
+
+ def _listen(self):
+ """Set focus on canvas (in order to collect key-events)
+ """
+ self.cv.focus_force()
+
+ def _ontimer(self, fun, t):
+ """Install a timer, which calls fun after t milliseconds.
+ """
+ if t == 0:
+ self.cv.after_idle(fun)
+ else:
+ self.cv.after(t, fun)
+
+ def _createimage(self, image):
+ """Create and return image item on canvas.
+ """
+ return self.cv.create_image(0, 0, image=image)
+
+ def _drawimage(self, item, pos, image):
+ """Configure image item as to draw image object
+ at position (x,y) on canvas)
+ """
+ x, y = pos
+ self.cv.coords(item, (x * self.xscale, -y * self.yscale))
+ self.cv.itemconfig(item, image=image)
+
+ def _setbgpic(self, item, image):
+ """Configure image item as to draw image object
+ at center of canvas. Set item to the first item
+ in the displaylist, so it will be drawn below
+ any other item ."""
+ self.cv.itemconfig(item, image=image)
+ self.cv.tag_lower(item)
+
+ def _type(self, item):
+ """Return 'line' or 'polygon' or 'image' depending on
+ type of item.
+ """
+ return self.cv.type(item)
+
+ def _pointlist(self, item):
+ """returns list of coordinate-pairs of points of item
+ Example (for insiders):
+ >>> from turtle import *
+ >>> getscreen()._pointlist(getturtle().turtle._item)
+ [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
+ (9.9999999999999982, 0.0)]
+ >>> """
+ cl = self.cv.coords(item)
+ pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
+ return pl
+
+ def _setscrollregion(self, srx1, sry1, srx2, sry2):
+ self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
+
+ def _rescale(self, xscalefactor, yscalefactor):
+ items = self.cv.find_all()
+ for item in items:
+ coordinates = list(self.cv.coords(item))
+ newcoordlist = []
+ while coordinates:
+ x, y = coordinates[:2]
+ newcoordlist.append(x * xscalefactor)
+ newcoordlist.append(y * yscalefactor)
+ coordinates = coordinates[2:]
+ self.cv.coords(item, *newcoordlist)
+
+ def _resize(self, canvwidth=None, canvheight=None, bg=None):
+ """Resize the canvas the turtles are drawing on. Does
+ not alter the drawing window.
+ """
+ # needs amendment
+ if not isinstance(self.cv, ScrolledCanvas):
+ return self.canvwidth, self.canvheight
+ if canvwidth is canvheight is bg is None:
+ return self.cv.canvwidth, self.cv.canvheight
+ if canvwidth is not None:
+ self.canvwidth = canvwidth
+ if canvheight is not None:
+ self.canvheight = canvheight
+ self.cv.reset(canvwidth, canvheight, bg)
+
+ def _window_size(self):
+ """ Return the width and height of the turtle window.
+ """
+ width = self.cv.winfo_width()
+ if width <= 1: # the window isn't managed by a geometry manager
+ width = self.cv['width']
+ height = self.cv.winfo_height()
+ if height <= 1: # the window isn't managed by a geometry manager
+ height = self.cv['height']
+ return width, height
+
+ def mainloop(self):
+ """Starts event loop - calling Tkinter's mainloop function.
+
+ No argument.
+
+ Must be last statement in a turtle graphics program.
+ Must NOT be used if a script is run from within IDLE in -n mode
+ (No subprocess) - for interactive use of turtle graphics.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.mainloop()
+
+ """
self.cv.tk.mainloop()
-
- def textinput(self, title, prompt):
- """Pop up a dialog window for input of a string.
-
- Arguments: title is the title of the dialog window,
- prompt is a text mostly describing what information to input.
-
- Return the string input
- If the dialog is canceled, return None.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.textinput("NIM", "Name of first player:")
-
- """
+
+ def textinput(self, title, prompt):
+ """Pop up a dialog window for input of a string.
+
+ Arguments: title is the title of the dialog window,
+ prompt is a text mostly describing what information to input.
+
+ Return the string input
+ If the dialog is canceled, return None.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.textinput("NIM", "Name of first player:")
+
+ """
return simpledialog.askstring(title, prompt, parent=self.cv)
-
- def numinput(self, title, prompt, default=None, minval=None, maxval=None):
- """Pop up a dialog window for input of a number.
-
- Arguments: title is the title of the dialog window,
- prompt is a text mostly describing what numerical information to input.
- default: default value
+
+ def numinput(self, title, prompt, default=None, minval=None, maxval=None):
+ """Pop up a dialog window for input of a number.
+
+ Arguments: title is the title of the dialog window,
+ prompt is a text mostly describing what numerical information to input.
+ default: default value
minval: minimum value for input
- maxval: maximum value for input
-
- The number input must be in the range minval .. maxval if these are
- given. If not, a hint is issued and the dialog remains open for
- correction. Return the number input.
- If the dialog is canceled, return None.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000)
-
- """
- return simpledialog.askfloat(title, prompt, initialvalue=default,
+ maxval: maximum value for input
+
+ The number input must be in the range minval .. maxval if these are
+ given. If not, a hint is issued and the dialog remains open for
+ correction. Return the number input.
+ If the dialog is canceled, return None.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000)
+
+ """
+ return simpledialog.askfloat(title, prompt, initialvalue=default,
minvalue=minval, maxvalue=maxval,
parent=self.cv)
-
-
-##############################################################################
-### End of Tkinter - interface ###
-##############################################################################
-
-
-class Terminator (Exception):
- """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
-
- This stops execution of a turtle graphics script.
- Main purpose: use in the Demo-Viewer turtle.Demo.py.
- """
- pass
-
-
-class TurtleGraphicsError(Exception):
- """Some TurtleGraphics Error
- """
-
-
-class Shape(object):
- """Data structure modeling shapes.
-
- attribute _type is one of "polygon", "image", "compound"
- attribute _data is - depending on _type a poygon-tuple,
- an image or a list constructed using the addcomponent method.
- """
- def __init__(self, type_, data=None):
- self._type = type_
- if type_ == "polygon":
- if isinstance(data, list):
- data = tuple(data)
- elif type_ == "image":
- if isinstance(data, str):
- if data.lower().endswith(".gif") and isfile(data):
- data = TurtleScreen._image(data)
- # else data assumed to be Photoimage
- elif type_ == "compound":
- data = []
- else:
- raise TurtleGraphicsError("There is no shape type %s" % type_)
- self._data = data
-
- def addcomponent(self, poly, fill, outline=None):
- """Add component to a shape of type compound.
-
- Arguments: poly is a polygon, i. e. a tuple of number pairs.
- fill is the fillcolor of the component,
- outline is the outline color of the component.
-
- call (for a Shapeobject namend s):
- -- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
-
- Example:
- >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
- >>> s = Shape("compound")
- >>> s.addcomponent(poly, "red", "blue")
- >>> # .. add more components and then use register_shape()
- """
- if self._type != "compound":
- raise TurtleGraphicsError("Cannot add component to %s Shape"
- % self._type)
- if outline is None:
- outline = fill
- self._data.append([poly, fill, outline])
-
-
-class Tbuffer(object):
- """Ring buffer used as undobuffer for RawTurtle objects."""
- def __init__(self, bufsize=10):
- self.bufsize = bufsize
- self.buffer = [[None]] * bufsize
- self.ptr = -1
- self.cumulate = False
- def reset(self, bufsize=None):
- if bufsize is None:
- for i in range(self.bufsize):
- self.buffer[i] = [None]
- else:
- self.bufsize = bufsize
- self.buffer = [[None]] * bufsize
- self.ptr = -1
- def push(self, item):
- if self.bufsize > 0:
- if not self.cumulate:
- self.ptr = (self.ptr + 1) % self.bufsize
- self.buffer[self.ptr] = item
- else:
- self.buffer[self.ptr].append(item)
- def pop(self):
- if self.bufsize > 0:
- item = self.buffer[self.ptr]
- if item is None:
- return None
- else:
- self.buffer[self.ptr] = [None]
- self.ptr = (self.ptr - 1) % self.bufsize
- return (item)
- def nr_of_items(self):
- return self.bufsize - self.buffer.count([None])
- def __repr__(self):
- return str(self.buffer) + " " + str(self.ptr)
-
-
-
-class TurtleScreen(TurtleScreenBase):
- """Provides screen oriented methods like setbg etc.
-
- Only relies upon the methods of TurtleScreenBase and NOT
- upon components of the underlying graphics toolkit -
- which is Tkinter in this case.
- """
- _RUNNING = True
-
- def __init__(self, cv, mode=_CFG["mode"],
- colormode=_CFG["colormode"], delay=_CFG["delay"]):
+
+
+##############################################################################
+### End of Tkinter - interface ###
+##############################################################################
+
+
+class Terminator (Exception):
+ """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
+
+ This stops execution of a turtle graphics script.
+ Main purpose: use in the Demo-Viewer turtle.Demo.py.
+ """
+ pass
+
+
+class TurtleGraphicsError(Exception):
+ """Some TurtleGraphics Error
+ """
+
+
+class Shape(object):
+ """Data structure modeling shapes.
+
+ attribute _type is one of "polygon", "image", "compound"
+ attribute _data is - depending on _type a poygon-tuple,
+ an image or a list constructed using the addcomponent method.
+ """
+ def __init__(self, type_, data=None):
+ self._type = type_
+ if type_ == "polygon":
+ if isinstance(data, list):
+ data = tuple(data)
+ elif type_ == "image":
+ if isinstance(data, str):
+ if data.lower().endswith(".gif") and isfile(data):
+ data = TurtleScreen._image(data)
+ # else data assumed to be Photoimage
+ elif type_ == "compound":
+ data = []
+ else:
+ raise TurtleGraphicsError("There is no shape type %s" % type_)
+ self._data = data
+
+ def addcomponent(self, poly, fill, outline=None):
+ """Add component to a shape of type compound.
+
+ Arguments: poly is a polygon, i. e. a tuple of number pairs.
+ fill is the fillcolor of the component,
+ outline is the outline color of the component.
+
+ call (for a Shapeobject namend s):
+ -- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
+
+ Example:
+ >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
+ >>> s = Shape("compound")
+ >>> s.addcomponent(poly, "red", "blue")
+ >>> # .. add more components and then use register_shape()
+ """
+ if self._type != "compound":
+ raise TurtleGraphicsError("Cannot add component to %s Shape"
+ % self._type)
+ if outline is None:
+ outline = fill
+ self._data.append([poly, fill, outline])
+
+
+class Tbuffer(object):
+ """Ring buffer used as undobuffer for RawTurtle objects."""
+ def __init__(self, bufsize=10):
+ self.bufsize = bufsize
+ self.buffer = [[None]] * bufsize
+ self.ptr = -1
+ self.cumulate = False
+ def reset(self, bufsize=None):
+ if bufsize is None:
+ for i in range(self.bufsize):
+ self.buffer[i] = [None]
+ else:
+ self.bufsize = bufsize
+ self.buffer = [[None]] * bufsize
+ self.ptr = -1
+ def push(self, item):
+ if self.bufsize > 0:
+ if not self.cumulate:
+ self.ptr = (self.ptr + 1) % self.bufsize
+ self.buffer[self.ptr] = item
+ else:
+ self.buffer[self.ptr].append(item)
+ def pop(self):
+ if self.bufsize > 0:
+ item = self.buffer[self.ptr]
+ if item is None:
+ return None
+ else:
+ self.buffer[self.ptr] = [None]
+ self.ptr = (self.ptr - 1) % self.bufsize
+ return (item)
+ def nr_of_items(self):
+ return self.bufsize - self.buffer.count([None])
+ def __repr__(self):
+ return str(self.buffer) + " " + str(self.ptr)
+
+
+
+class TurtleScreen(TurtleScreenBase):
+ """Provides screen oriented methods like setbg etc.
+
+ Only relies upon the methods of TurtleScreenBase and NOT
+ upon components of the underlying graphics toolkit -
+ which is Tkinter in this case.
+ """
+ _RUNNING = True
+
+ def __init__(self, cv, mode=_CFG["mode"],
+ colormode=_CFG["colormode"], delay=_CFG["delay"]):
TurtleScreenBase.__init__(self, cv)
- self._shapes = {
- "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
- "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
- (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
- (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
- (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
- (2,14))),
- "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
- (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
- (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
- (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
- (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
- (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
- "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
- (-10,-10))),
- "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
- (-10,-5.77))),
- "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
- "blank" : Shape("image", self._blankimage())
- }
-
- self._bgpics = {"nopic" : ""}
-
- self._mode = mode
- self._delayvalue = delay
- self._colormode = _CFG["colormode"]
- self._keys = []
- self.clear()
- if sys.platform == 'darwin':
- # Force Turtle window to the front on OS X. This is needed because
- # the Turtle window will show behind the Terminal window when you
- # start the demo from the command line.
- rootwindow = cv.winfo_toplevel()
- rootwindow.call('wm', 'attributes', '.', '-topmost', '1')
- rootwindow.call('wm', 'attributes', '.', '-topmost', '0')
-
- def clear(self):
- """Delete all drawings and all turtles from the TurtleScreen.
-
- No argument.
-
- Reset empty TurtleScreen to its initial state: white background,
- no backgroundimage, no eventbindings and tracing on.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.clear()
-
- Note: this method is not available as function.
- """
- self._delayvalue = _CFG["delay"]
- self._colormode = _CFG["colormode"]
- self._delete("all")
- self._bgpic = self._createimage("")
- self._bgpicname = "nopic"
- self._tracing = 1
- self._updatecounter = 0
- self._turtles = []
- self.bgcolor("white")
- for btn in 1, 2, 3:
- self.onclick(None, btn)
- self.onkeypress(None)
- for key in self._keys[:]:
- self.onkey(None, key)
- self.onkeypress(None, key)
- Turtle._pen = None
-
- def mode(self, mode=None):
- """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
-
- Optional argument:
- mode -- one of the strings 'standard', 'logo' or 'world'
-
- Mode 'standard' is compatible with turtle.py.
- Mode 'logo' is compatible with most Logo-Turtle-Graphics.
- Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
- this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
- If mode is not given, return the current mode.
-
- Mode Initial turtle heading positive angles
- ------------|-------------------------|-------------------
- 'standard' to the right (east) counterclockwise
- 'logo' upward (north) clockwise
-
- Examples:
- >>> mode('logo') # resets turtle heading to north
- >>> mode()
- 'logo'
- """
- if mode is None:
- return self._mode
- mode = mode.lower()
- if mode not in ["standard", "logo", "world"]:
- raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
- self._mode = mode
- if mode in ["standard", "logo"]:
- self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
- self.canvwidth//2, self.canvheight//2)
- self.xscale = self.yscale = 1.0
- self.reset()
-
- def setworldcoordinates(self, llx, lly, urx, ury):
- """Set up a user defined coordinate-system.
-
- Arguments:
- llx -- a number, x-coordinate of lower left corner of canvas
- lly -- a number, y-coordinate of lower left corner of canvas
- urx -- a number, x-coordinate of upper right corner of canvas
- ury -- a number, y-coordinate of upper right corner of canvas
-
- Set up user coodinat-system and switch to mode 'world' if necessary.
- This performs a screen.reset. If mode 'world' is already active,
- all drawings are redrawn according to the new coordinates.
-
- But ATTENTION: in user-defined coordinatesystems angles may appear
- distorted. (see Screen.mode())
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
- >>> for _ in range(36):
- ... left(10)
- ... forward(0.5)
- """
- if self.mode() != "world":
- self.mode("world")
- xspan = float(urx - llx)
- yspan = float(ury - lly)
- wx, wy = self._window_size()
- self.screensize(wx-20, wy-20)
- oldxscale, oldyscale = self.xscale, self.yscale
- self.xscale = self.canvwidth / xspan
- self.yscale = self.canvheight / yspan
- srx1 = llx * self.xscale
- sry1 = -ury * self.yscale
- srx2 = self.canvwidth + srx1
- sry2 = self.canvheight + sry1
- self._setscrollregion(srx1, sry1, srx2, sry2)
- self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
- self.update()
-
- def register_shape(self, name, shape=None):
- """Adds a turtle shape to TurtleScreen's shapelist.
-
- Arguments:
- (1) name is the name of a gif-file and shape is None.
- Installs the corresponding image shape.
- !! Image-shapes DO NOT rotate when turning the turtle,
- !! so they do not display the heading of the turtle!
- (2) name is an arbitrary string and shape is a tuple
- of pairs of coordinates. Installs the corresponding
- polygon shape
- (3) name is an arbitrary string and shape is a
- (compound) Shape object. Installs the corresponding
- compound shape.
- To use a shape, you have to issue the command shape(shapename).
-
- call: register_shape("turtle.gif")
- --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
-
- """
- if shape is None:
- # image
- if name.lower().endswith(".gif"):
- shape = Shape("image", self._image(name))
- else:
- raise TurtleGraphicsError("Bad arguments for register_shape.\n"
- + "Use help(register_shape)" )
- elif isinstance(shape, tuple):
- shape = Shape("polygon", shape)
- ## else shape assumed to be Shape-instance
- self._shapes[name] = shape
-
- def _colorstr(self, color):
- """Return color string corresponding to args.
-
- Argument may be a string or a tuple of three
- numbers corresponding to actual colormode,
- i.e. in the range 0<=n<=colormode.
-
- If the argument doesn't represent a color,
- an error is raised.
- """
- if len(color) == 1:
- color = color[0]
- if isinstance(color, str):
- if self._iscolorstring(color) or color == "":
- return color
- else:
- raise TurtleGraphicsError("bad color string: %s" % str(color))
- try:
- r, g, b = color
- except (TypeError, ValueError):
- raise TurtleGraphicsError("bad color arguments: %s" % str(color))
- if self._colormode == 1.0:
- r, g, b = [round(255.0*x) for x in (r, g, b)]
- if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
- raise TurtleGraphicsError("bad color sequence: %s" % str(color))
- return "#%02x%02x%02x" % (r, g, b)
-
- def _color(self, cstr):
- if not cstr.startswith("#"):
- return cstr
- if len(cstr) == 7:
- cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
- elif len(cstr) == 4:
- cl = [16*int(cstr[h], 16) for h in cstr[1:]]
- else:
- raise TurtleGraphicsError("bad colorstring: %s" % cstr)
- return tuple(c * self._colormode/255 for c in cl)
-
- def colormode(self, cmode=None):
- """Return the colormode or set it to 1.0 or 255.
-
- Optional argument:
- cmode -- one of the values 1.0 or 255
-
- r, g, b values of colortriples have to be in range 0..cmode.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.colormode()
- 1.0
- >>> screen.colormode(255)
- >>> pencolor(240,160,80)
- """
- if cmode is None:
- return self._colormode
- if cmode == 1.0:
- self._colormode = float(cmode)
- elif cmode == 255:
- self._colormode = int(cmode)
-
- def reset(self):
- """Reset all Turtles on the Screen to their initial state.
-
- No argument.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.reset()
- """
- for turtle in self._turtles:
- turtle._setmode(self._mode)
- turtle.reset()
-
- def turtles(self):
- """Return the list of turtles on the screen.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.turtles()
- [<turtle.Turtle object at 0x00E11FB0>]
- """
- return self._turtles
-
- def bgcolor(self, *args):
- """Set or return backgroundcolor of the TurtleScreen.
-
- Arguments (if given): a color string or three numbers
- in the range 0..colormode or a 3-tuple of such numbers.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.bgcolor("orange")
- >>> screen.bgcolor()
- 'orange'
- >>> screen.bgcolor(0.5,0,0.5)
- >>> screen.bgcolor()
- '#800080'
- """
- if args:
- color = self._colorstr(args)
- else:
- color = None
- color = self._bgcolor(color)
- if color is not None:
- color = self._color(color)
- return color
-
- def tracer(self, n=None, delay=None):
- """Turns turtle animation on/off and set delay for update drawings.
-
- Optional arguments:
- n -- nonnegative integer
- delay -- nonnegative integer
-
- If n is given, only each n-th regular screen update is really performed.
- (Can be used to accelerate the drawing of complex graphics.)
- Second arguments sets delay value (see RawTurtle.delay())
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.tracer(8, 25)
- >>> dist = 2
- >>> for i in range(200):
- ... fd(dist)
- ... rt(90)
- ... dist += 2
- """
- if n is None:
- return self._tracing
- self._tracing = int(n)
- self._updatecounter = 0
- if delay is not None:
- self._delayvalue = int(delay)
- if self._tracing:
- self.update()
-
- def delay(self, delay=None):
- """ Return or set the drawing delay in milliseconds.
-
- Optional argument:
- delay -- positive integer
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.delay(15)
- >>> screen.delay()
- 15
- """
- if delay is None:
- return self._delayvalue
- self._delayvalue = int(delay)
-
- def _incrementudc(self):
- """Increment update counter."""
- if not TurtleScreen._RUNNING:
- TurtleScreen._RUNNING = True
- raise Terminator
- if self._tracing > 0:
- self._updatecounter += 1
- self._updatecounter %= self._tracing
-
- def update(self):
- """Perform a TurtleScreen update.
- """
- tracing = self._tracing
- self._tracing = True
- for t in self.turtles():
- t._update_data()
- t._drawturtle()
- self._tracing = tracing
- self._update()
-
- def window_width(self):
- """ Return the width of the turtle window.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.window_width()
- 640
- """
- return self._window_size()[0]
-
- def window_height(self):
- """ Return the height of the turtle window.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.window_height()
- 480
- """
- return self._window_size()[1]
-
- def getcanvas(self):
- """Return the Canvas of this TurtleScreen.
-
- No argument.
-
- Example (for a Screen instance named screen):
- >>> cv = screen.getcanvas()
- >>> cv
- <turtle.ScrolledCanvas instance at 0x010742D8>
- """
- return self.cv
-
- def getshapes(self):
- """Return a list of names of all currently available turtle shapes.
-
- No argument.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.getshapes()
- ['arrow', 'blank', 'circle', ... , 'turtle']
- """
- return sorted(self._shapes.keys())
-
- def onclick(self, fun, btn=1, add=None):
- """Bind fun to mouse-click event on canvas.
-
- Arguments:
- fun -- a function with two arguments, the coordinates of the
- clicked point on the canvas.
- btn -- the number of the mouse-button, defaults to 1
-
- Example (for a TurtleScreen instance named screen)
-
- >>> screen.onclick(goto)
- >>> # Subsequently clicking into the TurtleScreen will
- >>> # make the turtle move to the clicked point.
- >>> screen.onclick(None)
- """
- self._onscreenclick(fun, btn, add)
-
- def onkey(self, fun, key):
- """Bind fun to key-release event of key.
-
- Arguments:
- fun -- a function with no arguments
- key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
-
- In order to be able to register key-events, TurtleScreen
- must have focus. (See method listen.)
-
- Example (for a TurtleScreen instance named screen):
-
- >>> def f():
- ... fd(50)
- ... lt(60)
- ...
- >>> screen.onkey(f, "Up")
- >>> screen.listen()
-
- Subsequently the turtle can be moved by repeatedly pressing
- the up-arrow key, consequently drawing a hexagon
-
- """
- if fun is None:
- if key in self._keys:
- self._keys.remove(key)
- elif key not in self._keys:
- self._keys.append(key)
- self._onkeyrelease(fun, key)
-
- def onkeypress(self, fun, key=None):
- """Bind fun to key-press event of key if key is given,
- or to any key-press-event if no key is given.
-
- Arguments:
- fun -- a function with no arguments
- key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
-
- In order to be able to register key-events, TurtleScreen
- must have focus. (See method listen.)
-
- Example (for a TurtleScreen instance named screen
- and a Turtle instance named turtle):
-
- >>> def f():
- ... fd(50)
- ... lt(60)
- ...
- >>> screen.onkeypress(f, "Up")
- >>> screen.listen()
-
- Subsequently the turtle can be moved by repeatedly pressing
- the up-arrow key, or by keeping pressed the up-arrow key.
- consequently drawing a hexagon.
- """
- if fun is None:
- if key in self._keys:
- self._keys.remove(key)
- elif key is not None and key not in self._keys:
- self._keys.append(key)
- self._onkeypress(fun, key)
-
- def listen(self, xdummy=None, ydummy=None):
- """Set focus on TurtleScreen (in order to collect key-events)
-
- No arguments.
- Dummy arguments are provided in order
- to be able to pass listen to the onclick method.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.listen()
- """
- self._listen()
-
- def ontimer(self, fun, t=0):
- """Install a timer, which calls fun after t milliseconds.
-
- Arguments:
- fun -- a function with no arguments.
- t -- a number >= 0
-
- Example (for a TurtleScreen instance named screen):
-
- >>> running = True
- >>> def f():
- ... if running:
- ... fd(50)
- ... lt(60)
- ... screen.ontimer(f, 250)
- ...
- >>> f() # makes the turtle marching around
- >>> running = False
- """
- self._ontimer(fun, t)
-
- def bgpic(self, picname=None):
- """Set background image or return name of current backgroundimage.
-
- Optional argument:
- picname -- a string, name of a gif-file or "nopic".
-
- If picname is a filename, set the corresponding image as background.
- If picname is "nopic", delete backgroundimage, if present.
- If picname is None, return the filename of the current backgroundimage.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.bgpic()
- 'nopic'
- >>> screen.bgpic("landscape.gif")
- >>> screen.bgpic()
- 'landscape.gif'
- """
- if picname is None:
- return self._bgpicname
- if picname not in self._bgpics:
- self._bgpics[picname] = self._image(picname)
- self._setbgpic(self._bgpic, self._bgpics[picname])
- self._bgpicname = picname
-
- def screensize(self, canvwidth=None, canvheight=None, bg=None):
- """Resize the canvas the turtles are drawing on.
-
- Optional arguments:
- canvwidth -- positive integer, new width of canvas in pixels
- canvheight -- positive integer, new height of canvas in pixels
- bg -- colorstring or color-tuple, new backgroundcolor
- If no arguments are given, return current (canvaswidth, canvasheight)
-
- Do not alter the drawing window. To observe hidden parts of
- the canvas use the scrollbars. (Can make visible those parts
- of a drawing, which were outside the canvas before!)
-
- Example (for a Turtle instance named turtle):
- >>> turtle.screensize(2000,1500)
- >>> # e.g. to search for an erroneously escaped turtle ;-)
- """
- return self._resize(canvwidth, canvheight, bg)
-
- onscreenclick = onclick
- resetscreen = reset
- clearscreen = clear
- addshape = register_shape
- onkeyrelease = onkey
-
-class TNavigator(object):
- """Navigation part of the RawTurtle.
- Implements methods for turtle movement.
- """
- START_ORIENTATION = {
- "standard": Vec2D(1.0, 0.0),
- "world" : Vec2D(1.0, 0.0),
- "logo" : Vec2D(0.0, 1.0) }
- DEFAULT_MODE = "standard"
- DEFAULT_ANGLEOFFSET = 0
- DEFAULT_ANGLEORIENT = 1
-
- def __init__(self, mode=DEFAULT_MODE):
- self._angleOffset = self.DEFAULT_ANGLEOFFSET
- self._angleOrient = self.DEFAULT_ANGLEORIENT
- self._mode = mode
- self.undobuffer = None
- self.degrees()
- self._mode = None
- self._setmode(mode)
- TNavigator.reset(self)
-
- def reset(self):
- """reset turtle to its initial values
-
- Will be overwritten by parent class
- """
- self._position = Vec2D(0.0, 0.0)
- self._orient = TNavigator.START_ORIENTATION[self._mode]
-
- def _setmode(self, mode=None):
- """Set turtle-mode to 'standard', 'world' or 'logo'.
- """
- if mode is None:
- return self._mode
- if mode not in ["standard", "logo", "world"]:
- return
- self._mode = mode
- if mode in ["standard", "world"]:
- self._angleOffset = 0
- self._angleOrient = 1
- else: # mode == "logo":
- self._angleOffset = self._fullcircle/4.
- self._angleOrient = -1
-
- def _setDegreesPerAU(self, fullcircle):
- """Helper function for degrees() and radians()"""
- self._fullcircle = fullcircle
- self._degreesPerAU = 360/fullcircle
- if self._mode == "standard":
- self._angleOffset = 0
- else:
- self._angleOffset = fullcircle/4.
-
- def degrees(self, fullcircle=360.0):
- """ Set angle measurement units to degrees.
-
- Optional argument:
- fullcircle - a number
-
- Set angle measurement units, i. e. set number
+ self._shapes = {
+ "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
+ "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
+ (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
+ (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
+ (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
+ (2,14))),
+ "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
+ (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
+ (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
+ (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
+ (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
+ (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
+ "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
+ (-10,-10))),
+ "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
+ (-10,-5.77))),
+ "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
+ "blank" : Shape("image", self._blankimage())
+ }
+
+ self._bgpics = {"nopic" : ""}
+
+ self._mode = mode
+ self._delayvalue = delay
+ self._colormode = _CFG["colormode"]
+ self._keys = []
+ self.clear()
+ if sys.platform == 'darwin':
+ # Force Turtle window to the front on OS X. This is needed because
+ # the Turtle window will show behind the Terminal window when you
+ # start the demo from the command line.
+ rootwindow = cv.winfo_toplevel()
+ rootwindow.call('wm', 'attributes', '.', '-topmost', '1')
+ rootwindow.call('wm', 'attributes', '.', '-topmost', '0')
+
+ def clear(self):
+ """Delete all drawings and all turtles from the TurtleScreen.
+
+ No argument.
+
+ Reset empty TurtleScreen to its initial state: white background,
+ no backgroundimage, no eventbindings and tracing on.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.clear()
+
+ Note: this method is not available as function.
+ """
+ self._delayvalue = _CFG["delay"]
+ self._colormode = _CFG["colormode"]
+ self._delete("all")
+ self._bgpic = self._createimage("")
+ self._bgpicname = "nopic"
+ self._tracing = 1
+ self._updatecounter = 0
+ self._turtles = []
+ self.bgcolor("white")
+ for btn in 1, 2, 3:
+ self.onclick(None, btn)
+ self.onkeypress(None)
+ for key in self._keys[:]:
+ self.onkey(None, key)
+ self.onkeypress(None, key)
+ Turtle._pen = None
+
+ def mode(self, mode=None):
+ """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
+
+ Optional argument:
+ mode -- one of the strings 'standard', 'logo' or 'world'
+
+ Mode 'standard' is compatible with turtle.py.
+ Mode 'logo' is compatible with most Logo-Turtle-Graphics.
+ Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
+ this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
+ If mode is not given, return the current mode.
+
+ Mode Initial turtle heading positive angles
+ ------------|-------------------------|-------------------
+ 'standard' to the right (east) counterclockwise
+ 'logo' upward (north) clockwise
+
+ Examples:
+ >>> mode('logo') # resets turtle heading to north
+ >>> mode()
+ 'logo'
+ """
+ if mode is None:
+ return self._mode
+ mode = mode.lower()
+ if mode not in ["standard", "logo", "world"]:
+ raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
+ self._mode = mode
+ if mode in ["standard", "logo"]:
+ self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
+ self.canvwidth//2, self.canvheight//2)
+ self.xscale = self.yscale = 1.0
+ self.reset()
+
+ def setworldcoordinates(self, llx, lly, urx, ury):
+ """Set up a user defined coordinate-system.
+
+ Arguments:
+ llx -- a number, x-coordinate of lower left corner of canvas
+ lly -- a number, y-coordinate of lower left corner of canvas
+ urx -- a number, x-coordinate of upper right corner of canvas
+ ury -- a number, y-coordinate of upper right corner of canvas
+
+ Set up user coodinat-system and switch to mode 'world' if necessary.
+ This performs a screen.reset. If mode 'world' is already active,
+ all drawings are redrawn according to the new coordinates.
+
+ But ATTENTION: in user-defined coordinatesystems angles may appear
+ distorted. (see Screen.mode())
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
+ >>> for _ in range(36):
+ ... left(10)
+ ... forward(0.5)
+ """
+ if self.mode() != "world":
+ self.mode("world")
+ xspan = float(urx - llx)
+ yspan = float(ury - lly)
+ wx, wy = self._window_size()
+ self.screensize(wx-20, wy-20)
+ oldxscale, oldyscale = self.xscale, self.yscale
+ self.xscale = self.canvwidth / xspan
+ self.yscale = self.canvheight / yspan
+ srx1 = llx * self.xscale
+ sry1 = -ury * self.yscale
+ srx2 = self.canvwidth + srx1
+ sry2 = self.canvheight + sry1
+ self._setscrollregion(srx1, sry1, srx2, sry2)
+ self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
+ self.update()
+
+ def register_shape(self, name, shape=None):
+ """Adds a turtle shape to TurtleScreen's shapelist.
+
+ Arguments:
+ (1) name is the name of a gif-file and shape is None.
+ Installs the corresponding image shape.
+ !! Image-shapes DO NOT rotate when turning the turtle,
+ !! so they do not display the heading of the turtle!
+ (2) name is an arbitrary string and shape is a tuple
+ of pairs of coordinates. Installs the corresponding
+ polygon shape
+ (3) name is an arbitrary string and shape is a
+ (compound) Shape object. Installs the corresponding
+ compound shape.
+ To use a shape, you have to issue the command shape(shapename).
+
+ call: register_shape("turtle.gif")
+ --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
+
+ """
+ if shape is None:
+ # image
+ if name.lower().endswith(".gif"):
+ shape = Shape("image", self._image(name))
+ else:
+ raise TurtleGraphicsError("Bad arguments for register_shape.\n"
+ + "Use help(register_shape)" )
+ elif isinstance(shape, tuple):
+ shape = Shape("polygon", shape)
+ ## else shape assumed to be Shape-instance
+ self._shapes[name] = shape
+
+ def _colorstr(self, color):
+ """Return color string corresponding to args.
+
+ Argument may be a string or a tuple of three
+ numbers corresponding to actual colormode,
+ i.e. in the range 0<=n<=colormode.
+
+ If the argument doesn't represent a color,
+ an error is raised.
+ """
+ if len(color) == 1:
+ color = color[0]
+ if isinstance(color, str):
+ if self._iscolorstring(color) or color == "":
+ return color
+ else:
+ raise TurtleGraphicsError("bad color string: %s" % str(color))
+ try:
+ r, g, b = color
+ except (TypeError, ValueError):
+ raise TurtleGraphicsError("bad color arguments: %s" % str(color))
+ if self._colormode == 1.0:
+ r, g, b = [round(255.0*x) for x in (r, g, b)]
+ if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
+ raise TurtleGraphicsError("bad color sequence: %s" % str(color))
+ return "#%02x%02x%02x" % (r, g, b)
+
+ def _color(self, cstr):
+ if not cstr.startswith("#"):
+ return cstr
+ if len(cstr) == 7:
+ cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
+ elif len(cstr) == 4:
+ cl = [16*int(cstr[h], 16) for h in cstr[1:]]
+ else:
+ raise TurtleGraphicsError("bad colorstring: %s" % cstr)
+ return tuple(c * self._colormode/255 for c in cl)
+
+ def colormode(self, cmode=None):
+ """Return the colormode or set it to 1.0 or 255.
+
+ Optional argument:
+ cmode -- one of the values 1.0 or 255
+
+ r, g, b values of colortriples have to be in range 0..cmode.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.colormode()
+ 1.0
+ >>> screen.colormode(255)
+ >>> pencolor(240,160,80)
+ """
+ if cmode is None:
+ return self._colormode
+ if cmode == 1.0:
+ self._colormode = float(cmode)
+ elif cmode == 255:
+ self._colormode = int(cmode)
+
+ def reset(self):
+ """Reset all Turtles on the Screen to their initial state.
+
+ No argument.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.reset()
+ """
+ for turtle in self._turtles:
+ turtle._setmode(self._mode)
+ turtle.reset()
+
+ def turtles(self):
+ """Return the list of turtles on the screen.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.turtles()
+ [<turtle.Turtle object at 0x00E11FB0>]
+ """
+ return self._turtles
+
+ def bgcolor(self, *args):
+ """Set or return backgroundcolor of the TurtleScreen.
+
+ Arguments (if given): a color string or three numbers
+ in the range 0..colormode or a 3-tuple of such numbers.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.bgcolor("orange")
+ >>> screen.bgcolor()
+ 'orange'
+ >>> screen.bgcolor(0.5,0,0.5)
+ >>> screen.bgcolor()
+ '#800080'
+ """
+ if args:
+ color = self._colorstr(args)
+ else:
+ color = None
+ color = self._bgcolor(color)
+ if color is not None:
+ color = self._color(color)
+ return color
+
+ def tracer(self, n=None, delay=None):
+ """Turns turtle animation on/off and set delay for update drawings.
+
+ Optional arguments:
+ n -- nonnegative integer
+ delay -- nonnegative integer
+
+ If n is given, only each n-th regular screen update is really performed.
+ (Can be used to accelerate the drawing of complex graphics.)
+ Second arguments sets delay value (see RawTurtle.delay())
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.tracer(8, 25)
+ >>> dist = 2
+ >>> for i in range(200):
+ ... fd(dist)
+ ... rt(90)
+ ... dist += 2
+ """
+ if n is None:
+ return self._tracing
+ self._tracing = int(n)
+ self._updatecounter = 0
+ if delay is not None:
+ self._delayvalue = int(delay)
+ if self._tracing:
+ self.update()
+
+ def delay(self, delay=None):
+ """ Return or set the drawing delay in milliseconds.
+
+ Optional argument:
+ delay -- positive integer
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.delay(15)
+ >>> screen.delay()
+ 15
+ """
+ if delay is None:
+ return self._delayvalue
+ self._delayvalue = int(delay)
+
+ def _incrementudc(self):
+ """Increment update counter."""
+ if not TurtleScreen._RUNNING:
+ TurtleScreen._RUNNING = True
+ raise Terminator
+ if self._tracing > 0:
+ self._updatecounter += 1
+ self._updatecounter %= self._tracing
+
+ def update(self):
+ """Perform a TurtleScreen update.
+ """
+ tracing = self._tracing
+ self._tracing = True
+ for t in self.turtles():
+ t._update_data()
+ t._drawturtle()
+ self._tracing = tracing
+ self._update()
+
+ def window_width(self):
+ """ Return the width of the turtle window.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.window_width()
+ 640
+ """
+ return self._window_size()[0]
+
+ def window_height(self):
+ """ Return the height of the turtle window.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.window_height()
+ 480
+ """
+ return self._window_size()[1]
+
+ def getcanvas(self):
+ """Return the Canvas of this TurtleScreen.
+
+ No argument.
+
+ Example (for a Screen instance named screen):
+ >>> cv = screen.getcanvas()
+ >>> cv
+ <turtle.ScrolledCanvas instance at 0x010742D8>
+ """
+ return self.cv
+
+ def getshapes(self):
+ """Return a list of names of all currently available turtle shapes.
+
+ No argument.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.getshapes()
+ ['arrow', 'blank', 'circle', ... , 'turtle']
+ """
+ return sorted(self._shapes.keys())
+
+ def onclick(self, fun, btn=1, add=None):
+ """Bind fun to mouse-click event on canvas.
+
+ Arguments:
+ fun -- a function with two arguments, the coordinates of the
+ clicked point on the canvas.
+ btn -- the number of the mouse-button, defaults to 1
+
+ Example (for a TurtleScreen instance named screen)
+
+ >>> screen.onclick(goto)
+ >>> # Subsequently clicking into the TurtleScreen will
+ >>> # make the turtle move to the clicked point.
+ >>> screen.onclick(None)
+ """
+ self._onscreenclick(fun, btn, add)
+
+ def onkey(self, fun, key):
+ """Bind fun to key-release event of key.
+
+ Arguments:
+ fun -- a function with no arguments
+ key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
+
+ In order to be able to register key-events, TurtleScreen
+ must have focus. (See method listen.)
+
+ Example (for a TurtleScreen instance named screen):
+
+ >>> def f():
+ ... fd(50)
+ ... lt(60)
+ ...
+ >>> screen.onkey(f, "Up")
+ >>> screen.listen()
+
+ Subsequently the turtle can be moved by repeatedly pressing
+ the up-arrow key, consequently drawing a hexagon
+
+ """
+ if fun is None:
+ if key in self._keys:
+ self._keys.remove(key)
+ elif key not in self._keys:
+ self._keys.append(key)
+ self._onkeyrelease(fun, key)
+
+ def onkeypress(self, fun, key=None):
+ """Bind fun to key-press event of key if key is given,
+ or to any key-press-event if no key is given.
+
+ Arguments:
+ fun -- a function with no arguments
+ key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
+
+ In order to be able to register key-events, TurtleScreen
+ must have focus. (See method listen.)
+
+ Example (for a TurtleScreen instance named screen
+ and a Turtle instance named turtle):
+
+ >>> def f():
+ ... fd(50)
+ ... lt(60)
+ ...
+ >>> screen.onkeypress(f, "Up")
+ >>> screen.listen()
+
+ Subsequently the turtle can be moved by repeatedly pressing
+ the up-arrow key, or by keeping pressed the up-arrow key.
+ consequently drawing a hexagon.
+ """
+ if fun is None:
+ if key in self._keys:
+ self._keys.remove(key)
+ elif key is not None and key not in self._keys:
+ self._keys.append(key)
+ self._onkeypress(fun, key)
+
+ def listen(self, xdummy=None, ydummy=None):
+ """Set focus on TurtleScreen (in order to collect key-events)
+
+ No arguments.
+ Dummy arguments are provided in order
+ to be able to pass listen to the onclick method.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.listen()
+ """
+ self._listen()
+
+ def ontimer(self, fun, t=0):
+ """Install a timer, which calls fun after t milliseconds.
+
+ Arguments:
+ fun -- a function with no arguments.
+ t -- a number >= 0
+
+ Example (for a TurtleScreen instance named screen):
+
+ >>> running = True
+ >>> def f():
+ ... if running:
+ ... fd(50)
+ ... lt(60)
+ ... screen.ontimer(f, 250)
+ ...
+ >>> f() # makes the turtle marching around
+ >>> running = False
+ """
+ self._ontimer(fun, t)
+
+ def bgpic(self, picname=None):
+ """Set background image or return name of current backgroundimage.
+
+ Optional argument:
+ picname -- a string, name of a gif-file or "nopic".
+
+ If picname is a filename, set the corresponding image as background.
+ If picname is "nopic", delete backgroundimage, if present.
+ If picname is None, return the filename of the current backgroundimage.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.bgpic()
+ 'nopic'
+ >>> screen.bgpic("landscape.gif")
+ >>> screen.bgpic()
+ 'landscape.gif'
+ """
+ if picname is None:
+ return self._bgpicname
+ if picname not in self._bgpics:
+ self._bgpics[picname] = self._image(picname)
+ self._setbgpic(self._bgpic, self._bgpics[picname])
+ self._bgpicname = picname
+
+ def screensize(self, canvwidth=None, canvheight=None, bg=None):
+ """Resize the canvas the turtles are drawing on.
+
+ Optional arguments:
+ canvwidth -- positive integer, new width of canvas in pixels
+ canvheight -- positive integer, new height of canvas in pixels
+ bg -- colorstring or color-tuple, new backgroundcolor
+ If no arguments are given, return current (canvaswidth, canvasheight)
+
+ Do not alter the drawing window. To observe hidden parts of
+ the canvas use the scrollbars. (Can make visible those parts
+ of a drawing, which were outside the canvas before!)
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.screensize(2000,1500)
+ >>> # e.g. to search for an erroneously escaped turtle ;-)
+ """
+ return self._resize(canvwidth, canvheight, bg)
+
+ onscreenclick = onclick
+ resetscreen = reset
+ clearscreen = clear
+ addshape = register_shape
+ onkeyrelease = onkey
+
+class TNavigator(object):
+ """Navigation part of the RawTurtle.
+ Implements methods for turtle movement.
+ """
+ START_ORIENTATION = {
+ "standard": Vec2D(1.0, 0.0),
+ "world" : Vec2D(1.0, 0.0),
+ "logo" : Vec2D(0.0, 1.0) }
+ DEFAULT_MODE = "standard"
+ DEFAULT_ANGLEOFFSET = 0
+ DEFAULT_ANGLEORIENT = 1
+
+ def __init__(self, mode=DEFAULT_MODE):
+ self._angleOffset = self.DEFAULT_ANGLEOFFSET
+ self._angleOrient = self.DEFAULT_ANGLEORIENT
+ self._mode = mode
+ self.undobuffer = None
+ self.degrees()
+ self._mode = None
+ self._setmode(mode)
+ TNavigator.reset(self)
+
+ def reset(self):
+ """reset turtle to its initial values
+
+ Will be overwritten by parent class
+ """
+ self._position = Vec2D(0.0, 0.0)
+ self._orient = TNavigator.START_ORIENTATION[self._mode]
+
+ def _setmode(self, mode=None):
+ """Set turtle-mode to 'standard', 'world' or 'logo'.
+ """
+ if mode is None:
+ return self._mode
+ if mode not in ["standard", "logo", "world"]:
+ return
+ self._mode = mode
+ if mode in ["standard", "world"]:
+ self._angleOffset = 0
+ self._angleOrient = 1
+ else: # mode == "logo":
+ self._angleOffset = self._fullcircle/4.
+ self._angleOrient = -1
+
+ def _setDegreesPerAU(self, fullcircle):
+ """Helper function for degrees() and radians()"""
+ self._fullcircle = fullcircle
+ self._degreesPerAU = 360/fullcircle
+ if self._mode == "standard":
+ self._angleOffset = 0
+ else:
+ self._angleOffset = fullcircle/4.
+
+ def degrees(self, fullcircle=360.0):
+ """ Set angle measurement units to degrees.
+
+ Optional argument:
+ fullcircle - a number
+
+ Set angle measurement units, i. e. set number
of 'degrees' for a full circle. Default value is
- 360 degrees.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.left(90)
- >>> turtle.heading()
- 90
-
- Change angle measurement unit to grad (also known as gon,
- grade, or gradian and equals 1/100-th of the right angle.)
- >>> turtle.degrees(400.0)
- >>> turtle.heading()
- 100
-
- """
- self._setDegreesPerAU(fullcircle)
-
- def radians(self):
- """ Set the angle measurement units to radians.
-
- No arguments.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.heading()
- 90
- >>> turtle.radians()
- >>> turtle.heading()
- 1.5707963267948966
- """
- self._setDegreesPerAU(2*math.pi)
-
- def _go(self, distance):
- """move turtle forward by specified distance"""
- ende = self._position + self._orient * distance
- self._goto(ende)
-
- def _rotate(self, angle):
- """Turn turtle counterclockwise by specified angle if angle > 0."""
- angle *= self._degreesPerAU
- self._orient = self._orient.rotate(angle)
-
- def _goto(self, end):
- """move turtle to position end."""
- self._position = end
-
- def forward(self, distance):
- """Move the turtle forward by the specified distance.
-
- Aliases: forward | fd
-
- Argument:
- distance -- a number (integer or float)
-
- Move the turtle forward by the specified distance, in the direction
- the turtle is headed.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.position()
- (0.00, 0.00)
- >>> turtle.forward(25)
- >>> turtle.position()
- (25.00,0.00)
- >>> turtle.forward(-75)
- >>> turtle.position()
- (-50.00,0.00)
- """
- self._go(distance)
-
- def back(self, distance):
- """Move the turtle backward by distance.
-
- Aliases: back | backward | bk
-
- Argument:
- distance -- a number
-
+ 360 degrees.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.left(90)
+ >>> turtle.heading()
+ 90
+
+ Change angle measurement unit to grad (also known as gon,
+ grade, or gradian and equals 1/100-th of the right angle.)
+ >>> turtle.degrees(400.0)
+ >>> turtle.heading()
+ 100
+
+ """
+ self._setDegreesPerAU(fullcircle)
+
+ def radians(self):
+ """ Set the angle measurement units to radians.
+
+ No arguments.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.heading()
+ 90
+ >>> turtle.radians()
+ >>> turtle.heading()
+ 1.5707963267948966
+ """
+ self._setDegreesPerAU(2*math.pi)
+
+ def _go(self, distance):
+ """move turtle forward by specified distance"""
+ ende = self._position + self._orient * distance
+ self._goto(ende)
+
+ def _rotate(self, angle):
+ """Turn turtle counterclockwise by specified angle if angle > 0."""
+ angle *= self._degreesPerAU
+ self._orient = self._orient.rotate(angle)
+
+ def _goto(self, end):
+ """move turtle to position end."""
+ self._position = end
+
+ def forward(self, distance):
+ """Move the turtle forward by the specified distance.
+
+ Aliases: forward | fd
+
+ Argument:
+ distance -- a number (integer or float)
+
+ Move the turtle forward by the specified distance, in the direction
+ the turtle is headed.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.position()
+ (0.00, 0.00)
+ >>> turtle.forward(25)
+ >>> turtle.position()
+ (25.00,0.00)
+ >>> turtle.forward(-75)
+ >>> turtle.position()
+ (-50.00,0.00)
+ """
+ self._go(distance)
+
+ def back(self, distance):
+ """Move the turtle backward by distance.
+
+ Aliases: back | backward | bk
+
+ Argument:
+ distance -- a number
+
Move the turtle backward by distance, opposite to the direction the
- turtle is headed. Do not change the turtle's heading.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.position()
- (0.00, 0.00)
- >>> turtle.backward(30)
- >>> turtle.position()
- (-30.00, 0.00)
- """
- self._go(-distance)
-
- def right(self, angle):
- """Turn turtle right by angle units.
-
- Aliases: right | rt
-
- Argument:
- angle -- a number (integer or float)
-
- Turn turtle right by angle units. (Units are by default degrees,
- but can be set via the degrees() and radians() functions.)
- Angle orientation depends on mode. (See this.)
-
- Example (for a Turtle instance named turtle):
- >>> turtle.heading()
- 22.0
- >>> turtle.right(45)
- >>> turtle.heading()
- 337.0
- """
- self._rotate(-angle)
-
- def left(self, angle):
- """Turn turtle left by angle units.
-
- Aliases: left | lt
-
- Argument:
- angle -- a number (integer or float)
-
- Turn turtle left by angle units. (Units are by default degrees,
- but can be set via the degrees() and radians() functions.)
- Angle orientation depends on mode. (See this.)
-
- Example (for a Turtle instance named turtle):
- >>> turtle.heading()
- 22.0
- >>> turtle.left(45)
- >>> turtle.heading()
- 67.0
- """
- self._rotate(angle)
-
- def pos(self):
- """Return the turtle's current location (x,y), as a Vec2D-vector.
-
- Aliases: pos | position
-
- No arguments.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.pos()
- (0.00, 240.00)
- """
- return self._position
-
- def xcor(self):
- """ Return the turtle's x coordinate.
-
- No arguments.
-
- Example (for a Turtle instance named turtle):
- >>> reset()
- >>> turtle.left(60)
- >>> turtle.forward(100)
- >>> print turtle.xcor()
- 50.0
- """
- return self._position[0]
-
- def ycor(self):
- """ Return the turtle's y coordinate
- ---
- No arguments.
-
- Example (for a Turtle instance named turtle):
- >>> reset()
- >>> turtle.left(60)
- >>> turtle.forward(100)
- >>> print turtle.ycor()
- 86.6025403784
- """
- return self._position[1]
-
-
- def goto(self, x, y=None):
- """Move turtle to an absolute position.
-
- Aliases: setpos | setposition | goto:
-
- Arguments:
- x -- a number or a pair/vector of numbers
- y -- a number None
-
- call: goto(x, y) # two coordinates
- --or: goto((x, y)) # a pair (tuple) of coordinates
- --or: goto(vec) # e.g. as returned by pos()
-
- Move turtle to an absolute position. If the pen is down,
- a line will be drawn. The turtle's orientation does not change.
-
- Example (for a Turtle instance named turtle):
- >>> tp = turtle.pos()
- >>> tp
- (0.00, 0.00)
- >>> turtle.setpos(60,30)
- >>> turtle.pos()
- (60.00,30.00)
- >>> turtle.setpos((20,80))
- >>> turtle.pos()
- (20.00,80.00)
- >>> turtle.setpos(tp)
- >>> turtle.pos()
- (0.00,0.00)
- """
- if y is None:
- self._goto(Vec2D(*x))
- else:
- self._goto(Vec2D(x, y))
-
- def home(self):
- """Move turtle to the origin - coordinates (0,0).
-
- No arguments.
-
- Move turtle to the origin - coordinates (0,0) and set its
- heading to its start-orientation (which depends on mode).
-
- Example (for a Turtle instance named turtle):
- >>> turtle.home()
- """
- self.goto(0, 0)
- self.setheading(0)
-
- def setx(self, x):
- """Set the turtle's first coordinate to x
-
- Argument:
- x -- a number (integer or float)
-
- Set the turtle's first coordinate to x, leave second coordinate
- unchanged.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.position()
- (0.00, 240.00)
- >>> turtle.setx(10)
- >>> turtle.position()
- (10.00, 240.00)
- """
- self._goto(Vec2D(x, self._position[1]))
-
- def sety(self, y):
- """Set the turtle's second coordinate to y
-
- Argument:
- y -- a number (integer or float)
-
- Set the turtle's first coordinate to x, second coordinate remains
- unchanged.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.position()
- (0.00, 40.00)
- >>> turtle.sety(-10)
- >>> turtle.position()
- (0.00, -10.00)
- """
- self._goto(Vec2D(self._position[0], y))
-
- def distance(self, x, y=None):
- """Return the distance from the turtle to (x,y) in turtle step units.
-
- Arguments:
- x -- a number or a pair/vector of numbers or a turtle instance
- y -- a number None None
-
- call: distance(x, y) # two coordinates
- --or: distance((x, y)) # a pair (tuple) of coordinates
- --or: distance(vec) # e.g. as returned by pos()
- --or: distance(mypen) # where mypen is another turtle
-
- Example (for a Turtle instance named turtle):
- >>> turtle.pos()
- (0.00, 0.00)
- >>> turtle.distance(30,40)
- 50.0
- >>> pen = Turtle()
- >>> pen.forward(77)
- >>> turtle.distance(pen)
- 77.0
- """
- if y is not None:
- pos = Vec2D(x, y)
- if isinstance(x, Vec2D):
- pos = x
- elif isinstance(x, tuple):
- pos = Vec2D(*x)
- elif isinstance(x, TNavigator):
- pos = x._position
- return abs(pos - self._position)
-
- def towards(self, x, y=None):
- """Return the angle of the line from the turtle's position to (x, y).
-
- Arguments:
- x -- a number or a pair/vector of numbers or a turtle instance
- y -- a number None None
-
- call: distance(x, y) # two coordinates
- --or: distance((x, y)) # a pair (tuple) of coordinates
- --or: distance(vec) # e.g. as returned by pos()
- --or: distance(mypen) # where mypen is another turtle
-
- Return the angle, between the line from turtle-position to position
- specified by x, y and the turtle's start orientation. (Depends on
- modes - "standard" or "logo")
-
- Example (for a Turtle instance named turtle):
- >>> turtle.pos()
- (10.00, 10.00)
- >>> turtle.towards(0,0)
- 225.0
- """
- if y is not None:
- pos = Vec2D(x, y)
- if isinstance(x, Vec2D):
- pos = x
- elif isinstance(x, tuple):
- pos = Vec2D(*x)
- elif isinstance(x, TNavigator):
- pos = x._position
- x, y = pos - self._position
- result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
- result /= self._degreesPerAU
- return (self._angleOffset + self._angleOrient*result) % self._fullcircle
-
- def heading(self):
- """ Return the turtle's current heading.
-
- No arguments.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.left(67)
- >>> turtle.heading()
- 67.0
- """
- x, y = self._orient
- result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
- result /= self._degreesPerAU
- return (self._angleOffset + self._angleOrient*result) % self._fullcircle
-
- def setheading(self, to_angle):
- """Set the orientation of the turtle to to_angle.
-
- Aliases: setheading | seth
-
- Argument:
- to_angle -- a number (integer or float)
-
- Set the orientation of the turtle to to_angle.
- Here are some common directions in degrees:
-
- standard - mode: logo-mode:
- -------------------|--------------------
- 0 - east 0 - north
- 90 - north 90 - east
- 180 - west 180 - south
- 270 - south 270 - west
-
- Example (for a Turtle instance named turtle):
- >>> turtle.setheading(90)
- >>> turtle.heading()
- 90
- """
- angle = (to_angle - self.heading())*self._angleOrient
- full = self._fullcircle
- angle = (angle+full/2.)%full - full/2.
- self._rotate(angle)
-
- def circle(self, radius, extent = None, steps = None):
- """ Draw a circle with given radius.
-
- Arguments:
- radius -- a number
- extent (optional) -- a number
- steps (optional) -- an integer
-
- Draw a circle with given radius. The center is radius units left
- of the turtle; extent - an angle - determines which part of the
- circle is drawn. If extent is not given, draw the entire circle.
- If extent is not a full circle, one endpoint of the arc is the
- current pen position. Draw the arc in counterclockwise direction
- if radius is positive, otherwise in clockwise direction. Finally
- the direction of the turtle is changed by the amount of extent.
-
- As the circle is approximated by an inscribed regular polygon,
- steps determines the number of steps to use. If not given,
- it will be calculated automatically. Maybe used to draw regular
- polygons.
-
- call: circle(radius) # full circle
- --or: circle(radius, extent) # arc
- --or: circle(radius, extent, steps)
- --or: circle(radius, steps=6) # 6-sided polygon
-
- Example (for a Turtle instance named turtle):
- >>> turtle.circle(50)
- >>> turtle.circle(120, 180) # semicircle
- """
- if self.undobuffer:
- self.undobuffer.push(["seq"])
- self.undobuffer.cumulate = True
- speed = self.speed()
- if extent is None:
- extent = self._fullcircle
- if steps is None:
- frac = abs(extent)/self._fullcircle
- steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
- w = 1.0 * extent / steps
- w2 = 0.5 * w
- l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
- if radius < 0:
- l, w, w2 = -l, -w, -w2
- tr = self._tracer()
- dl = self._delay()
- if speed == 0:
- self._tracer(0, 0)
- else:
- self.speed(0)
- self._rotate(w2)
- for i in range(steps):
- self.speed(speed)
- self._go(l)
- self.speed(0)
- self._rotate(w)
- self._rotate(-w2)
- if speed == 0:
- self._tracer(tr, dl)
- self.speed(speed)
- if self.undobuffer:
- self.undobuffer.cumulate = False
-
-## three dummy methods to be implemented by child class:
-
- def speed(self, s=0):
- """dummy method - to be overwritten by child class"""
- def _tracer(self, a=None, b=None):
- """dummy method - to be overwritten by child class"""
- def _delay(self, n=None):
- """dummy method - to be overwritten by child class"""
-
- fd = forward
- bk = back
- backward = back
- rt = right
- lt = left
- position = pos
- setpos = goto
- setposition = goto
- seth = setheading
-
-
-class TPen(object):
- """Drawing part of the RawTurtle.
- Implements drawing properties.
- """
- def __init__(self, resizemode=_CFG["resizemode"]):
- self._resizemode = resizemode # or "user" or "noresize"
- self.undobuffer = None
- TPen._reset(self)
-
- def _reset(self, pencolor=_CFG["pencolor"],
- fillcolor=_CFG["fillcolor"]):
- self._pensize = 1
- self._shown = True
- self._pencolor = pencolor
- self._fillcolor = fillcolor
- self._drawing = True
- self._speed = 3
- self._stretchfactor = (1., 1.)
- self._shearfactor = 0.
- self._tilt = 0.
- self._shapetrafo = (1., 0., 0., 1.)
- self._outlinewidth = 1
-
- def resizemode(self, rmode=None):
- """Set resizemode to one of the values: "auto", "user", "noresize".
-
- (Optional) Argument:
- rmode -- one of the strings "auto", "user", "noresize"
-
- Different resizemodes have the following effects:
- - "auto" adapts the appearance of the turtle
- corresponding to the value of pensize.
- - "user" adapts the appearance of the turtle according to the
- values of stretchfactor and outlinewidth (outline),
- which are set by shapesize()
- - "noresize" no adaption of the turtle's appearance takes place.
- If no argument is given, return current resizemode.
- resizemode("user") is called by a call of shapesize with arguments.
-
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.resizemode("noresize")
- >>> turtle.resizemode()
- 'noresize'
- """
- if rmode is None:
- return self._resizemode
- rmode = rmode.lower()
- if rmode in ["auto", "user", "noresize"]:
- self.pen(resizemode=rmode)
-
- def pensize(self, width=None):
- """Set or return the line thickness.
-
- Aliases: pensize | width
-
- Argument:
- width -- positive number
-
- Set the line thickness to width or return it. If resizemode is set
- to "auto" and turtleshape is a polygon, that polygon is drawn with
- the same line thickness. If no argument is given, current pensize
- is returned.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.pensize()
- 1
- >>> turtle.pensize(10) # from here on lines of width 10 are drawn
- """
- if width is None:
- return self._pensize
- self.pen(pensize=width)
-
-
- def penup(self):
- """Pull the pen up -- no drawing when moving.
-
- Aliases: penup | pu | up
-
- No argument
-
- Example (for a Turtle instance named turtle):
- >>> turtle.penup()
- """
- if not self._drawing:
- return
- self.pen(pendown=False)
-
- def pendown(self):
- """Pull the pen down -- drawing when moving.
-
- Aliases: pendown | pd | down
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.pendown()
- """
- if self._drawing:
- return
- self.pen(pendown=True)
-
- def isdown(self):
- """Return True if pen is down, False if it's up.
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.penup()
- >>> turtle.isdown()
- False
- >>> turtle.pendown()
- >>> turtle.isdown()
- True
- """
- return self._drawing
-
- def speed(self, speed=None):
- """ Return or set the turtle's speed.
-
- Optional argument:
- speed -- an integer in the range 0..10 or a speedstring (see below)
-
- Set the turtle's speed to an integer value in the range 0 .. 10.
- If no argument is given: return current speed.
-
- If input is a number greater than 10 or smaller than 0.5,
- speed is set to 0.
- Speedstrings are mapped to speedvalues in the following way:
- 'fastest' : 0
- 'fast' : 10
- 'normal' : 6
- 'slow' : 3
- 'slowest' : 1
- speeds from 1 to 10 enforce increasingly faster animation of
- line drawing and turtle turning.
-
- Attention:
- speed = 0 : *no* animation takes place. forward/back makes turtle jump
- and likewise left/right make the turtle turn instantly.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.speed(3)
- """
- speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
- if speed is None:
- return self._speed
- if speed in speeds:
- speed = speeds[speed]
- elif 0.5 < speed < 10.5:
- speed = int(round(speed))
- else:
- speed = 0
- self.pen(speed=speed)
-
- def color(self, *args):
- """Return or set the pencolor and fillcolor.
-
- Arguments:
- Several input formats are allowed.
- They use 0, 1, 2, or 3 arguments as follows:
-
- color()
- Return the current pencolor and the current fillcolor
- as a pair of color specification strings as are returned
- by pencolor and fillcolor.
- color(colorstring), color((r,g,b)), color(r,g,b)
- inputs as in pencolor, set both, fillcolor and pencolor,
- to the given value.
- color(colorstring1, colorstring2),
- color((r1,g1,b1), (r2,g2,b2))
- equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
- and analogously, if the other input format is used.
-
- If turtleshape is a polygon, outline and interior of that polygon
- is drawn with the newly set colors.
- For more info see: pencolor, fillcolor
-
- Example (for a Turtle instance named turtle):
- >>> turtle.color('red', 'green')
- >>> turtle.color()
- ('red', 'green')
- >>> colormode(255)
- >>> color((40, 80, 120), (160, 200, 240))
- >>> color()
- ('#285078', '#a0c8f0')
- """
- if args:
- l = len(args)
- if l == 1:
- pcolor = fcolor = args[0]
- elif l == 2:
- pcolor, fcolor = args
- elif l == 3:
- pcolor = fcolor = args
- pcolor = self._colorstr(pcolor)
- fcolor = self._colorstr(fcolor)
- self.pen(pencolor=pcolor, fillcolor=fcolor)
- else:
- return self._color(self._pencolor), self._color(self._fillcolor)
-
- def pencolor(self, *args):
- """ Return or set the pencolor.
-
- Arguments:
- Four input formats are allowed:
- - pencolor()
- Return the current pencolor as color specification string,
- possibly in hex-number format (see example).
- May be used as input to another color/pencolor/fillcolor call.
- - pencolor(colorstring)
- s is a Tk color specification string, such as "red" or "yellow"
- - pencolor((r, g, b))
- *a tuple* of r, g, and b, which represent, an RGB color,
- and each of r, g, and b are in the range 0..colormode,
- where colormode is either 1.0 or 255
- - pencolor(r, g, b)
- r, g, and b represent an RGB color, and each of r, g, and b
- are in the range 0..colormode
-
- If turtleshape is a polygon, the outline of that polygon is drawn
- with the newly set pencolor.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.pencolor('brown')
- >>> tup = (0.2, 0.8, 0.55)
- >>> turtle.pencolor(tup)
- >>> turtle.pencolor()
- '#33cc8c'
- """
- if args:
- color = self._colorstr(args)
- if color == self._pencolor:
- return
- self.pen(pencolor=color)
- else:
- return self._color(self._pencolor)
-
- def fillcolor(self, *args):
- """ Return or set the fillcolor.
-
- Arguments:
- Four input formats are allowed:
- - fillcolor()
- Return the current fillcolor as color specification string,
- possibly in hex-number format (see example).
- May be used as input to another color/pencolor/fillcolor call.
- - fillcolor(colorstring)
- s is a Tk color specification string, such as "red" or "yellow"
- - fillcolor((r, g, b))
- *a tuple* of r, g, and b, which represent, an RGB color,
- and each of r, g, and b are in the range 0..colormode,
- where colormode is either 1.0 or 255
- - fillcolor(r, g, b)
- r, g, and b represent an RGB color, and each of r, g, and b
- are in the range 0..colormode
-
- If turtleshape is a polygon, the interior of that polygon is drawn
- with the newly set fillcolor.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.fillcolor('violet')
- >>> col = turtle.pencolor()
- >>> turtle.fillcolor(col)
- >>> turtle.fillcolor(0, .5, 0)
- """
- if args:
- color = self._colorstr(args)
- if color == self._fillcolor:
- return
- self.pen(fillcolor=color)
- else:
- return self._color(self._fillcolor)
-
- def showturtle(self):
- """Makes the turtle visible.
-
- Aliases: showturtle | st
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.hideturtle()
- >>> turtle.showturtle()
- """
- self.pen(shown=True)
-
- def hideturtle(self):
- """Makes the turtle invisible.
-
- Aliases: hideturtle | ht
-
- No argument.
-
- It's a good idea to do this while you're in the
- middle of a complicated drawing, because hiding
- the turtle speeds up the drawing observably.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.hideturtle()
- """
- self.pen(shown=False)
-
- def isvisible(self):
- """Return True if the Turtle is shown, False if it's hidden.
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.hideturtle()
- >>> print turtle.isvisible():
- False
- """
- return self._shown
-
- def pen(self, pen=None, **pendict):
- """Return or set the pen's attributes.
-
- Arguments:
- pen -- a dictionary with some or all of the below listed keys.
- **pendict -- one or more keyword-arguments with the below
- listed keys as keywords.
-
- Return or set the pen's attributes in a 'pen-dictionary'
- with the following key/value pairs:
- "shown" : True/False
- "pendown" : True/False
- "pencolor" : color-string or color-tuple
- "fillcolor" : color-string or color-tuple
- "pensize" : positive number
- "speed" : number in range 0..10
- "resizemode" : "auto" or "user" or "noresize"
- "stretchfactor": (positive number, positive number)
- "shearfactor": number
- "outline" : positive number
- "tilt" : number
-
- This dictionary can be used as argument for a subsequent
- pen()-call to restore the former pen-state. Moreover one
- or more of these attributes can be provided as keyword-arguments.
- This can be used to set several pen attributes in one statement.
-
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
- >>> turtle.pen()
- {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
- 'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
- 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
- >>> penstate=turtle.pen()
- >>> turtle.color("yellow","")
- >>> turtle.penup()
- >>> turtle.pen()
- {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
- 'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
- 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
- >>> p.pen(penstate, fillcolor="green")
- >>> p.pen()
- {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
- 'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
- 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
- """
- _pd = {"shown" : self._shown,
- "pendown" : self._drawing,
- "pencolor" : self._pencolor,
- "fillcolor" : self._fillcolor,
- "pensize" : self._pensize,
- "speed" : self._speed,
- "resizemode" : self._resizemode,
- "stretchfactor" : self._stretchfactor,
- "shearfactor" : self._shearfactor,
- "outline" : self._outlinewidth,
- "tilt" : self._tilt
- }
-
- if not (pen or pendict):
- return _pd
-
- if isinstance(pen, dict):
- p = pen
- else:
- p = {}
- p.update(pendict)
-
- _p_buf = {}
- for key in p:
- _p_buf[key] = _pd[key]
-
- if self.undobuffer:
- self.undobuffer.push(("pen", _p_buf))
-
- newLine = False
- if "pendown" in p:
- if self._drawing != p["pendown"]:
- newLine = True
- if "pencolor" in p:
- if isinstance(p["pencolor"], tuple):
- p["pencolor"] = self._colorstr((p["pencolor"],))
- if self._pencolor != p["pencolor"]:
- newLine = True
- if "pensize" in p:
- if self._pensize != p["pensize"]:
- newLine = True
- if newLine:
- self._newLine()
- if "pendown" in p:
- self._drawing = p["pendown"]
- if "pencolor" in p:
- self._pencolor = p["pencolor"]
- if "pensize" in p:
- self._pensize = p["pensize"]
- if "fillcolor" in p:
- if isinstance(p["fillcolor"], tuple):
- p["fillcolor"] = self._colorstr((p["fillcolor"],))
- self._fillcolor = p["fillcolor"]
- if "speed" in p:
- self._speed = p["speed"]
- if "resizemode" in p:
- self._resizemode = p["resizemode"]
- if "stretchfactor" in p:
- sf = p["stretchfactor"]
- if isinstance(sf, (int, float)):
- sf = (sf, sf)
- self._stretchfactor = sf
- if "shearfactor" in p:
- self._shearfactor = p["shearfactor"]
- if "outline" in p:
- self._outlinewidth = p["outline"]
- if "shown" in p:
- self._shown = p["shown"]
- if "tilt" in p:
- self._tilt = p["tilt"]
- if "stretchfactor" in p or "tilt" in p or "shearfactor" in p:
- scx, scy = self._stretchfactor
- shf = self._shearfactor
- sa, ca = math.sin(self._tilt), math.cos(self._tilt)
- self._shapetrafo = ( scx*ca, scy*(shf*ca + sa),
- -scx*sa, scy*(ca - shf*sa))
- self._update()
-
-## three dummy methods to be implemented by child class:
-
- def _newLine(self, usePos = True):
- """dummy method - to be overwritten by child class"""
- def _update(self, count=True, forced=False):
- """dummy method - to be overwritten by child class"""
- def _color(self, args):
- """dummy method - to be overwritten by child class"""
- def _colorstr(self, args):
- """dummy method - to be overwritten by child class"""
-
- width = pensize
- up = penup
- pu = penup
- pd = pendown
- down = pendown
- st = showturtle
- ht = hideturtle
-
-
-class _TurtleImage(object):
- """Helper class: Datatype to store Turtle attributes
- """
-
- def __init__(self, screen, shapeIndex):
- self.screen = screen
- self._type = None
- self._setshape(shapeIndex)
-
- def _setshape(self, shapeIndex):
- screen = self.screen
- self.shapeIndex = shapeIndex
- if self._type == "polygon" == screen._shapes[shapeIndex]._type:
- return
- if self._type == "image" == screen._shapes[shapeIndex]._type:
- return
- if self._type in ["image", "polygon"]:
- screen._delete(self._item)
- elif self._type == "compound":
- for item in self._item:
- screen._delete(item)
- self._type = screen._shapes[shapeIndex]._type
- if self._type == "polygon":
- self._item = screen._createpoly()
- elif self._type == "image":
- self._item = screen._createimage(screen._shapes["blank"]._data)
- elif self._type == "compound":
- self._item = [screen._createpoly() for item in
- screen._shapes[shapeIndex]._data]
-
-
-class RawTurtle(TPen, TNavigator):
- """Animation part of the RawTurtle.
- Puts RawTurtle upon a TurtleScreen and provides tools for
- its animation.
- """
- screens = []
-
- def __init__(self, canvas=None,
- shape=_CFG["shape"],
- undobuffersize=_CFG["undobuffersize"],
- visible=_CFG["visible"]):
- if isinstance(canvas, _Screen):
- self.screen = canvas
- elif isinstance(canvas, TurtleScreen):
- if canvas not in RawTurtle.screens:
- RawTurtle.screens.append(canvas)
- self.screen = canvas
- elif isinstance(canvas, (ScrolledCanvas, Canvas)):
- for screen in RawTurtle.screens:
- if screen.cv == canvas:
- self.screen = screen
- break
- else:
- self.screen = TurtleScreen(canvas)
- RawTurtle.screens.append(self.screen)
- else:
- raise TurtleGraphicsError("bad canvas argument %s" % canvas)
-
- screen = self.screen
- TNavigator.__init__(self, screen.mode())
- TPen.__init__(self)
- screen._turtles.append(self)
- self.drawingLineItem = screen._createline()
- self.turtle = _TurtleImage(screen, shape)
- self._poly = None
- self._creatingPoly = False
- self._fillitem = self._fillpath = None
- self._shown = visible
- self._hidden_from_screen = False
- self.currentLineItem = screen._createline()
- self.currentLine = [self._position]
- self.items = [self.currentLineItem]
- self.stampItems = []
- self._undobuffersize = undobuffersize
- self.undobuffer = Tbuffer(undobuffersize)
- self._update()
-
- def reset(self):
- """Delete the turtle's drawings and restore its default values.
-
- No argument.
-
- Delete the turtle's drawings from the screen, re-center the turtle
- and set variables to the default values.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.position()
- (0.00,-22.00)
- >>> turtle.heading()
- 100.0
- >>> turtle.reset()
- >>> turtle.position()
- (0.00,0.00)
- >>> turtle.heading()
- 0.0
- """
- TNavigator.reset(self)
- TPen._reset(self)
- self._clear()
- self._drawturtle()
- self._update()
-
- def setundobuffer(self, size):
- """Set or disable undobuffer.
-
- Argument:
- size -- an integer or None
-
- If size is an integer an empty undobuffer of given size is installed.
- Size gives the maximum number of turtle-actions that can be undone
- by the undo() function.
- If size is None, no undobuffer is present.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.setundobuffer(42)
- """
- if size is None or size <= 0:
- self.undobuffer = None
- else:
- self.undobuffer = Tbuffer(size)
-
- def undobufferentries(self):
- """Return count of entries in the undobuffer.
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> while undobufferentries():
- ... undo()
- """
- if self.undobuffer is None:
- return 0
- return self.undobuffer.nr_of_items()
-
- def _clear(self):
- """Delete all of pen's drawings"""
- self._fillitem = self._fillpath = None
- for item in self.items:
- self.screen._delete(item)
- self.currentLineItem = self.screen._createline()
- self.currentLine = []
- if self._drawing:
- self.currentLine.append(self._position)
- self.items = [self.currentLineItem]
- self.clearstamps()
- self.setundobuffer(self._undobuffersize)
-
-
- def clear(self):
- """Delete the turtle's drawings from the screen. Do not move turtle.
-
- No arguments.
-
- Delete the turtle's drawings from the screen. Do not move turtle.
- State and position of the turtle as well as drawings of other
- turtles are not affected.
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.clear()
- """
- self._clear()
- self._update()
-
- def _update_data(self):
- self.screen._incrementudc()
- if self.screen._updatecounter != 0:
- return
- if len(self.currentLine)>1:
- self.screen._drawline(self.currentLineItem, self.currentLine,
- self._pencolor, self._pensize)
-
- def _update(self):
- """Perform a Turtle-data update.
- """
- screen = self.screen
- if screen._tracing == 0:
- return
- elif screen._tracing == 1:
- self._update_data()
- self._drawturtle()
- screen._update() # TurtleScreenBase
- screen._delay(screen._delayvalue) # TurtleScreenBase
- else:
- self._update_data()
- if screen._updatecounter == 0:
- for t in screen.turtles():
- t._drawturtle()
- screen._update()
-
- def _tracer(self, flag=None, delay=None):
- """Turns turtle animation on/off and set delay for update drawings.
-
- Optional arguments:
- n -- nonnegative integer
- delay -- nonnegative integer
-
- If n is given, only each n-th regular screen update is really performed.
- (Can be used to accelerate the drawing of complex graphics.)
- Second arguments sets delay value (see RawTurtle.delay())
-
- Example (for a Turtle instance named turtle):
- >>> turtle.tracer(8, 25)
- >>> dist = 2
- >>> for i in range(200):
- ... turtle.fd(dist)
- ... turtle.rt(90)
- ... dist += 2
- """
- return self.screen.tracer(flag, delay)
-
- def _color(self, args):
- return self.screen._color(args)
-
- def _colorstr(self, args):
- return self.screen._colorstr(args)
-
- def _cc(self, args):
- """Convert colortriples to hexstrings.
- """
- if isinstance(args, str):
- return args
- try:
- r, g, b = args
- except (TypeError, ValueError):
- raise TurtleGraphicsError("bad color arguments: %s" % str(args))
- if self.screen._colormode == 1.0:
- r, g, b = [round(255.0*x) for x in (r, g, b)]
- if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
- raise TurtleGraphicsError("bad color sequence: %s" % str(args))
- return "#%02x%02x%02x" % (r, g, b)
-
- def clone(self):
- """Create and return a clone of the turtle.
-
- No argument.
-
- Create and return a clone of the turtle with same position, heading
- and turtle properties.
-
- Example (for a Turtle instance named mick):
- mick = Turtle()
- joe = mick.clone()
- """
- screen = self.screen
- self._newLine(self._drawing)
-
- turtle = self.turtle
- self.screen = None
- self.turtle = None # too make self deepcopy-able
-
- q = deepcopy(self)
-
- self.screen = screen
- self.turtle = turtle
-
- q.screen = screen
- q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
-
- screen._turtles.append(q)
- ttype = screen._shapes[self.turtle.shapeIndex]._type
- if ttype == "polygon":
- q.turtle._item = screen._createpoly()
- elif ttype == "image":
- q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
- elif ttype == "compound":
- q.turtle._item = [screen._createpoly() for item in
- screen._shapes[self.turtle.shapeIndex]._data]
- q.currentLineItem = screen._createline()
- q._update()
- return q
-
- def shape(self, name=None):
- """Set turtle shape to shape with given name / return current shapename.
-
- Optional argument:
- name -- a string, which is a valid shapename
-
- Set turtle shape to shape with given name or, if name is not given,
- return name of current shape.
- Shape with name must exist in the TurtleScreen's shape dictionary.
- Initially there are the following polygon shapes:
- 'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
- To learn about how to deal with shapes see Screen-method register_shape.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.shape()
- 'arrow'
- >>> turtle.shape("turtle")
- >>> turtle.shape()
- 'turtle'
- """
- if name is None:
- return self.turtle.shapeIndex
- if not name in self.screen.getshapes():
- raise TurtleGraphicsError("There is no shape named %s" % name)
- self.turtle._setshape(name)
- self._update()
-
- def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
- """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
-
- Optional arguments:
- stretch_wid : positive number
- stretch_len : positive number
- outline : positive number
-
- Return or set the pen's attributes x/y-stretchfactors and/or outline.
- Set resizemode to "user".
- If and only if resizemode is set to "user", the turtle will be displayed
- stretched according to its stretchfactors:
- stretch_wid is stretchfactor perpendicular to orientation
- stretch_len is stretchfactor in direction of turtles orientation.
- outline determines the width of the shapes's outline.
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.resizemode("user")
- >>> turtle.shapesize(5, 5, 12)
- >>> turtle.shapesize(outline=8)
- """
- if stretch_wid is stretch_len is outline is None:
- stretch_wid, stretch_len = self._stretchfactor
- return stretch_wid, stretch_len, self._outlinewidth
- if stretch_wid == 0 or stretch_len == 0:
- raise TurtleGraphicsError("stretch_wid/stretch_len must not be zero")
- if stretch_wid is not None:
- if stretch_len is None:
- stretchfactor = stretch_wid, stretch_wid
- else:
- stretchfactor = stretch_wid, stretch_len
- elif stretch_len is not None:
- stretchfactor = self._stretchfactor[0], stretch_len
- else:
- stretchfactor = self._stretchfactor
- if outline is None:
- outline = self._outlinewidth
- self.pen(resizemode="user",
- stretchfactor=stretchfactor, outline=outline)
-
- def shearfactor(self, shear=None):
- """Set or return the current shearfactor.
-
- Optional argument: shear -- number, tangent of the shear angle
-
- Shear the turtleshape according to the given shearfactor shear,
- which is the tangent of the shear angle. DO NOT change the
- turtle's heading (direction of movement).
- If shear is not given: return the current shearfactor, i. e. the
- tangent of the shear angle, by which lines parallel to the
- heading of the turtle are sheared.
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.shape("circle")
- >>> turtle.shapesize(5,2)
- >>> turtle.shearfactor(0.5)
- >>> turtle.shearfactor()
- >>> 0.5
- """
- if shear is None:
- return self._shearfactor
- self.pen(resizemode="user", shearfactor=shear)
-
- def settiltangle(self, angle):
- """Rotate the turtleshape to point in the specified direction
-
- Argument: angle -- number
-
- Rotate the turtleshape to point in the direction specified by angle,
- regardless of its current tilt-angle. DO NOT change the turtle's
- heading (direction of movement).
-
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.shape("circle")
- >>> turtle.shapesize(5,2)
- >>> turtle.settiltangle(45)
- >>> stamp()
- >>> turtle.fd(50)
- >>> turtle.settiltangle(-45)
- >>> stamp()
- >>> turtle.fd(50)
- """
- tilt = -angle * self._degreesPerAU * self._angleOrient
- tilt = (tilt * math.pi / 180.0) % (2*math.pi)
- self.pen(resizemode="user", tilt=tilt)
-
- def tiltangle(self, angle=None):
- """Set or return the current tilt-angle.
-
- Optional argument: angle -- number
-
- Rotate the turtleshape to point in the direction specified by angle,
- regardless of its current tilt-angle. DO NOT change the turtle's
- heading (direction of movement).
- If angle is not given: return the current tilt-angle, i. e. the angle
- between the orientation of the turtleshape and the heading of the
- turtle (its direction of movement).
-
+ turtle is headed. Do not change the turtle's heading.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.position()
+ (0.00, 0.00)
+ >>> turtle.backward(30)
+ >>> turtle.position()
+ (-30.00, 0.00)
+ """
+ self._go(-distance)
+
+ def right(self, angle):
+ """Turn turtle right by angle units.
+
+ Aliases: right | rt
+
+ Argument:
+ angle -- a number (integer or float)
+
+ Turn turtle right by angle units. (Units are by default degrees,
+ but can be set via the degrees() and radians() functions.)
+ Angle orientation depends on mode. (See this.)
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.heading()
+ 22.0
+ >>> turtle.right(45)
+ >>> turtle.heading()
+ 337.0
+ """
+ self._rotate(-angle)
+
+ def left(self, angle):
+ """Turn turtle left by angle units.
+
+ Aliases: left | lt
+
+ Argument:
+ angle -- a number (integer or float)
+
+ Turn turtle left by angle units. (Units are by default degrees,
+ but can be set via the degrees() and radians() functions.)
+ Angle orientation depends on mode. (See this.)
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.heading()
+ 22.0
+ >>> turtle.left(45)
+ >>> turtle.heading()
+ 67.0
+ """
+ self._rotate(angle)
+
+ def pos(self):
+ """Return the turtle's current location (x,y), as a Vec2D-vector.
+
+ Aliases: pos | position
+
+ No arguments.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.pos()
+ (0.00, 240.00)
+ """
+ return self._position
+
+ def xcor(self):
+ """ Return the turtle's x coordinate.
+
+ No arguments.
+
+ Example (for a Turtle instance named turtle):
+ >>> reset()
+ >>> turtle.left(60)
+ >>> turtle.forward(100)
+ >>> print turtle.xcor()
+ 50.0
+ """
+ return self._position[0]
+
+ def ycor(self):
+ """ Return the turtle's y coordinate
+ ---
+ No arguments.
+
+ Example (for a Turtle instance named turtle):
+ >>> reset()
+ >>> turtle.left(60)
+ >>> turtle.forward(100)
+ >>> print turtle.ycor()
+ 86.6025403784
+ """
+ return self._position[1]
+
+
+ def goto(self, x, y=None):
+ """Move turtle to an absolute position.
+
+ Aliases: setpos | setposition | goto:
+
+ Arguments:
+ x -- a number or a pair/vector of numbers
+ y -- a number None
+
+ call: goto(x, y) # two coordinates
+ --or: goto((x, y)) # a pair (tuple) of coordinates
+ --or: goto(vec) # e.g. as returned by pos()
+
+ Move turtle to an absolute position. If the pen is down,
+ a line will be drawn. The turtle's orientation does not change.
+
+ Example (for a Turtle instance named turtle):
+ >>> tp = turtle.pos()
+ >>> tp
+ (0.00, 0.00)
+ >>> turtle.setpos(60,30)
+ >>> turtle.pos()
+ (60.00,30.00)
+ >>> turtle.setpos((20,80))
+ >>> turtle.pos()
+ (20.00,80.00)
+ >>> turtle.setpos(tp)
+ >>> turtle.pos()
+ (0.00,0.00)
+ """
+ if y is None:
+ self._goto(Vec2D(*x))
+ else:
+ self._goto(Vec2D(x, y))
+
+ def home(self):
+ """Move turtle to the origin - coordinates (0,0).
+
+ No arguments.
+
+ Move turtle to the origin - coordinates (0,0) and set its
+ heading to its start-orientation (which depends on mode).
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.home()
+ """
+ self.goto(0, 0)
+ self.setheading(0)
+
+ def setx(self, x):
+ """Set the turtle's first coordinate to x
+
+ Argument:
+ x -- a number (integer or float)
+
+ Set the turtle's first coordinate to x, leave second coordinate
+ unchanged.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.position()
+ (0.00, 240.00)
+ >>> turtle.setx(10)
+ >>> turtle.position()
+ (10.00, 240.00)
+ """
+ self._goto(Vec2D(x, self._position[1]))
+
+ def sety(self, y):
+ """Set the turtle's second coordinate to y
+
+ Argument:
+ y -- a number (integer or float)
+
+ Set the turtle's first coordinate to x, second coordinate remains
+ unchanged.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.position()
+ (0.00, 40.00)
+ >>> turtle.sety(-10)
+ >>> turtle.position()
+ (0.00, -10.00)
+ """
+ self._goto(Vec2D(self._position[0], y))
+
+ def distance(self, x, y=None):
+ """Return the distance from the turtle to (x,y) in turtle step units.
+
+ Arguments:
+ x -- a number or a pair/vector of numbers or a turtle instance
+ y -- a number None None
+
+ call: distance(x, y) # two coordinates
+ --or: distance((x, y)) # a pair (tuple) of coordinates
+ --or: distance(vec) # e.g. as returned by pos()
+ --or: distance(mypen) # where mypen is another turtle
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.pos()
+ (0.00, 0.00)
+ >>> turtle.distance(30,40)
+ 50.0
+ >>> pen = Turtle()
+ >>> pen.forward(77)
+ >>> turtle.distance(pen)
+ 77.0
+ """
+ if y is not None:
+ pos = Vec2D(x, y)
+ if isinstance(x, Vec2D):
+ pos = x
+ elif isinstance(x, tuple):
+ pos = Vec2D(*x)
+ elif isinstance(x, TNavigator):
+ pos = x._position
+ return abs(pos - self._position)
+
+ def towards(self, x, y=None):
+ """Return the angle of the line from the turtle's position to (x, y).
+
+ Arguments:
+ x -- a number or a pair/vector of numbers or a turtle instance
+ y -- a number None None
+
+ call: distance(x, y) # two coordinates
+ --or: distance((x, y)) # a pair (tuple) of coordinates
+ --or: distance(vec) # e.g. as returned by pos()
+ --or: distance(mypen) # where mypen is another turtle
+
+ Return the angle, between the line from turtle-position to position
+ specified by x, y and the turtle's start orientation. (Depends on
+ modes - "standard" or "logo")
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.pos()
+ (10.00, 10.00)
+ >>> turtle.towards(0,0)
+ 225.0
+ """
+ if y is not None:
+ pos = Vec2D(x, y)
+ if isinstance(x, Vec2D):
+ pos = x
+ elif isinstance(x, tuple):
+ pos = Vec2D(*x)
+ elif isinstance(x, TNavigator):
+ pos = x._position
+ x, y = pos - self._position
+ result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
+ result /= self._degreesPerAU
+ return (self._angleOffset + self._angleOrient*result) % self._fullcircle
+
+ def heading(self):
+ """ Return the turtle's current heading.
+
+ No arguments.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.left(67)
+ >>> turtle.heading()
+ 67.0
+ """
+ x, y = self._orient
+ result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
+ result /= self._degreesPerAU
+ return (self._angleOffset + self._angleOrient*result) % self._fullcircle
+
+ def setheading(self, to_angle):
+ """Set the orientation of the turtle to to_angle.
+
+ Aliases: setheading | seth
+
+ Argument:
+ to_angle -- a number (integer or float)
+
+ Set the orientation of the turtle to to_angle.
+ Here are some common directions in degrees:
+
+ standard - mode: logo-mode:
+ -------------------|--------------------
+ 0 - east 0 - north
+ 90 - north 90 - east
+ 180 - west 180 - south
+ 270 - south 270 - west
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.setheading(90)
+ >>> turtle.heading()
+ 90
+ """
+ angle = (to_angle - self.heading())*self._angleOrient
+ full = self._fullcircle
+ angle = (angle+full/2.)%full - full/2.
+ self._rotate(angle)
+
+ def circle(self, radius, extent = None, steps = None):
+ """ Draw a circle with given radius.
+
+ Arguments:
+ radius -- a number
+ extent (optional) -- a number
+ steps (optional) -- an integer
+
+ Draw a circle with given radius. The center is radius units left
+ of the turtle; extent - an angle - determines which part of the
+ circle is drawn. If extent is not given, draw the entire circle.
+ If extent is not a full circle, one endpoint of the arc is the
+ current pen position. Draw the arc in counterclockwise direction
+ if radius is positive, otherwise in clockwise direction. Finally
+ the direction of the turtle is changed by the amount of extent.
+
+ As the circle is approximated by an inscribed regular polygon,
+ steps determines the number of steps to use. If not given,
+ it will be calculated automatically. Maybe used to draw regular
+ polygons.
+
+ call: circle(radius) # full circle
+ --or: circle(radius, extent) # arc
+ --or: circle(radius, extent, steps)
+ --or: circle(radius, steps=6) # 6-sided polygon
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.circle(50)
+ >>> turtle.circle(120, 180) # semicircle
+ """
+ if self.undobuffer:
+ self.undobuffer.push(["seq"])
+ self.undobuffer.cumulate = True
+ speed = self.speed()
+ if extent is None:
+ extent = self._fullcircle
+ if steps is None:
+ frac = abs(extent)/self._fullcircle
+ steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
+ w = 1.0 * extent / steps
+ w2 = 0.5 * w
+ l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
+ if radius < 0:
+ l, w, w2 = -l, -w, -w2
+ tr = self._tracer()
+ dl = self._delay()
+ if speed == 0:
+ self._tracer(0, 0)
+ else:
+ self.speed(0)
+ self._rotate(w2)
+ for i in range(steps):
+ self.speed(speed)
+ self._go(l)
+ self.speed(0)
+ self._rotate(w)
+ self._rotate(-w2)
+ if speed == 0:
+ self._tracer(tr, dl)
+ self.speed(speed)
+ if self.undobuffer:
+ self.undobuffer.cumulate = False
+
+## three dummy methods to be implemented by child class:
+
+ def speed(self, s=0):
+ """dummy method - to be overwritten by child class"""
+ def _tracer(self, a=None, b=None):
+ """dummy method - to be overwritten by child class"""
+ def _delay(self, n=None):
+ """dummy method - to be overwritten by child class"""
+
+ fd = forward
+ bk = back
+ backward = back
+ rt = right
+ lt = left
+ position = pos
+ setpos = goto
+ setposition = goto
+ seth = setheading
+
+
+class TPen(object):
+ """Drawing part of the RawTurtle.
+ Implements drawing properties.
+ """
+ def __init__(self, resizemode=_CFG["resizemode"]):
+ self._resizemode = resizemode # or "user" or "noresize"
+ self.undobuffer = None
+ TPen._reset(self)
+
+ def _reset(self, pencolor=_CFG["pencolor"],
+ fillcolor=_CFG["fillcolor"]):
+ self._pensize = 1
+ self._shown = True
+ self._pencolor = pencolor
+ self._fillcolor = fillcolor
+ self._drawing = True
+ self._speed = 3
+ self._stretchfactor = (1., 1.)
+ self._shearfactor = 0.
+ self._tilt = 0.
+ self._shapetrafo = (1., 0., 0., 1.)
+ self._outlinewidth = 1
+
+ def resizemode(self, rmode=None):
+ """Set resizemode to one of the values: "auto", "user", "noresize".
+
+ (Optional) Argument:
+ rmode -- one of the strings "auto", "user", "noresize"
+
+ Different resizemodes have the following effects:
+ - "auto" adapts the appearance of the turtle
+ corresponding to the value of pensize.
+ - "user" adapts the appearance of the turtle according to the
+ values of stretchfactor and outlinewidth (outline),
+ which are set by shapesize()
+ - "noresize" no adaption of the turtle's appearance takes place.
+ If no argument is given, return current resizemode.
+ resizemode("user") is called by a call of shapesize with arguments.
+
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.resizemode("noresize")
+ >>> turtle.resizemode()
+ 'noresize'
+ """
+ if rmode is None:
+ return self._resizemode
+ rmode = rmode.lower()
+ if rmode in ["auto", "user", "noresize"]:
+ self.pen(resizemode=rmode)
+
+ def pensize(self, width=None):
+ """Set or return the line thickness.
+
+ Aliases: pensize | width
+
+ Argument:
+ width -- positive number
+
+ Set the line thickness to width or return it. If resizemode is set
+ to "auto" and turtleshape is a polygon, that polygon is drawn with
+ the same line thickness. If no argument is given, current pensize
+ is returned.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.pensize()
+ 1
+ >>> turtle.pensize(10) # from here on lines of width 10 are drawn
+ """
+ if width is None:
+ return self._pensize
+ self.pen(pensize=width)
+
+
+ def penup(self):
+ """Pull the pen up -- no drawing when moving.
+
+ Aliases: penup | pu | up
+
+ No argument
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.penup()
+ """
+ if not self._drawing:
+ return
+ self.pen(pendown=False)
+
+ def pendown(self):
+ """Pull the pen down -- drawing when moving.
+
+ Aliases: pendown | pd | down
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.pendown()
+ """
+ if self._drawing:
+ return
+ self.pen(pendown=True)
+
+ def isdown(self):
+ """Return True if pen is down, False if it's up.
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.penup()
+ >>> turtle.isdown()
+ False
+ >>> turtle.pendown()
+ >>> turtle.isdown()
+ True
+ """
+ return self._drawing
+
+ def speed(self, speed=None):
+ """ Return or set the turtle's speed.
+
+ Optional argument:
+ speed -- an integer in the range 0..10 or a speedstring (see below)
+
+ Set the turtle's speed to an integer value in the range 0 .. 10.
+ If no argument is given: return current speed.
+
+ If input is a number greater than 10 or smaller than 0.5,
+ speed is set to 0.
+ Speedstrings are mapped to speedvalues in the following way:
+ 'fastest' : 0
+ 'fast' : 10
+ 'normal' : 6
+ 'slow' : 3
+ 'slowest' : 1
+ speeds from 1 to 10 enforce increasingly faster animation of
+ line drawing and turtle turning.
+
+ Attention:
+ speed = 0 : *no* animation takes place. forward/back makes turtle jump
+ and likewise left/right make the turtle turn instantly.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.speed(3)
+ """
+ speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
+ if speed is None:
+ return self._speed
+ if speed in speeds:
+ speed = speeds[speed]
+ elif 0.5 < speed < 10.5:
+ speed = int(round(speed))
+ else:
+ speed = 0
+ self.pen(speed=speed)
+
+ def color(self, *args):
+ """Return or set the pencolor and fillcolor.
+
+ Arguments:
+ Several input formats are allowed.
+ They use 0, 1, 2, or 3 arguments as follows:
+
+ color()
+ Return the current pencolor and the current fillcolor
+ as a pair of color specification strings as are returned
+ by pencolor and fillcolor.
+ color(colorstring), color((r,g,b)), color(r,g,b)
+ inputs as in pencolor, set both, fillcolor and pencolor,
+ to the given value.
+ color(colorstring1, colorstring2),
+ color((r1,g1,b1), (r2,g2,b2))
+ equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
+ and analogously, if the other input format is used.
+
+ If turtleshape is a polygon, outline and interior of that polygon
+ is drawn with the newly set colors.
+ For more info see: pencolor, fillcolor
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.color('red', 'green')
+ >>> turtle.color()
+ ('red', 'green')
+ >>> colormode(255)
+ >>> color((40, 80, 120), (160, 200, 240))
+ >>> color()
+ ('#285078', '#a0c8f0')
+ """
+ if args:
+ l = len(args)
+ if l == 1:
+ pcolor = fcolor = args[0]
+ elif l == 2:
+ pcolor, fcolor = args
+ elif l == 3:
+ pcolor = fcolor = args
+ pcolor = self._colorstr(pcolor)
+ fcolor = self._colorstr(fcolor)
+ self.pen(pencolor=pcolor, fillcolor=fcolor)
+ else:
+ return self._color(self._pencolor), self._color(self._fillcolor)
+
+ def pencolor(self, *args):
+ """ Return or set the pencolor.
+
+ Arguments:
+ Four input formats are allowed:
+ - pencolor()
+ Return the current pencolor as color specification string,
+ possibly in hex-number format (see example).
+ May be used as input to another color/pencolor/fillcolor call.
+ - pencolor(colorstring)
+ s is a Tk color specification string, such as "red" or "yellow"
+ - pencolor((r, g, b))
+ *a tuple* of r, g, and b, which represent, an RGB color,
+ and each of r, g, and b are in the range 0..colormode,
+ where colormode is either 1.0 or 255
+ - pencolor(r, g, b)
+ r, g, and b represent an RGB color, and each of r, g, and b
+ are in the range 0..colormode
+
+ If turtleshape is a polygon, the outline of that polygon is drawn
+ with the newly set pencolor.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.pencolor('brown')
+ >>> tup = (0.2, 0.8, 0.55)
+ >>> turtle.pencolor(tup)
+ >>> turtle.pencolor()
+ '#33cc8c'
+ """
+ if args:
+ color = self._colorstr(args)
+ if color == self._pencolor:
+ return
+ self.pen(pencolor=color)
+ else:
+ return self._color(self._pencolor)
+
+ def fillcolor(self, *args):
+ """ Return or set the fillcolor.
+
+ Arguments:
+ Four input formats are allowed:
+ - fillcolor()
+ Return the current fillcolor as color specification string,
+ possibly in hex-number format (see example).
+ May be used as input to another color/pencolor/fillcolor call.
+ - fillcolor(colorstring)
+ s is a Tk color specification string, such as "red" or "yellow"
+ - fillcolor((r, g, b))
+ *a tuple* of r, g, and b, which represent, an RGB color,
+ and each of r, g, and b are in the range 0..colormode,
+ where colormode is either 1.0 or 255
+ - fillcolor(r, g, b)
+ r, g, and b represent an RGB color, and each of r, g, and b
+ are in the range 0..colormode
+
+ If turtleshape is a polygon, the interior of that polygon is drawn
+ with the newly set fillcolor.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.fillcolor('violet')
+ >>> col = turtle.pencolor()
+ >>> turtle.fillcolor(col)
+ >>> turtle.fillcolor(0, .5, 0)
+ """
+ if args:
+ color = self._colorstr(args)
+ if color == self._fillcolor:
+ return
+ self.pen(fillcolor=color)
+ else:
+ return self._color(self._fillcolor)
+
+ def showturtle(self):
+ """Makes the turtle visible.
+
+ Aliases: showturtle | st
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.hideturtle()
+ >>> turtle.showturtle()
+ """
+ self.pen(shown=True)
+
+ def hideturtle(self):
+ """Makes the turtle invisible.
+
+ Aliases: hideturtle | ht
+
+ No argument.
+
+ It's a good idea to do this while you're in the
+ middle of a complicated drawing, because hiding
+ the turtle speeds up the drawing observably.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.hideturtle()
+ """
+ self.pen(shown=False)
+
+ def isvisible(self):
+ """Return True if the Turtle is shown, False if it's hidden.
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.hideturtle()
+ >>> print turtle.isvisible():
+ False
+ """
+ return self._shown
+
+ def pen(self, pen=None, **pendict):
+ """Return or set the pen's attributes.
+
+ Arguments:
+ pen -- a dictionary with some or all of the below listed keys.
+ **pendict -- one or more keyword-arguments with the below
+ listed keys as keywords.
+
+ Return or set the pen's attributes in a 'pen-dictionary'
+ with the following key/value pairs:
+ "shown" : True/False
+ "pendown" : True/False
+ "pencolor" : color-string or color-tuple
+ "fillcolor" : color-string or color-tuple
+ "pensize" : positive number
+ "speed" : number in range 0..10
+ "resizemode" : "auto" or "user" or "noresize"
+ "stretchfactor": (positive number, positive number)
+ "shearfactor": number
+ "outline" : positive number
+ "tilt" : number
+
+ This dictionary can be used as argument for a subsequent
+ pen()-call to restore the former pen-state. Moreover one
+ or more of these attributes can be provided as keyword-arguments.
+ This can be used to set several pen attributes in one statement.
+
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
+ >>> turtle.pen()
+ {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
+ 'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
+ 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
+ >>> penstate=turtle.pen()
+ >>> turtle.color("yellow","")
+ >>> turtle.penup()
+ >>> turtle.pen()
+ {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
+ 'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
+ 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
+ >>> p.pen(penstate, fillcolor="green")
+ >>> p.pen()
+ {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
+ 'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
+ 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
+ """
+ _pd = {"shown" : self._shown,
+ "pendown" : self._drawing,
+ "pencolor" : self._pencolor,
+ "fillcolor" : self._fillcolor,
+ "pensize" : self._pensize,
+ "speed" : self._speed,
+ "resizemode" : self._resizemode,
+ "stretchfactor" : self._stretchfactor,
+ "shearfactor" : self._shearfactor,
+ "outline" : self._outlinewidth,
+ "tilt" : self._tilt
+ }
+
+ if not (pen or pendict):
+ return _pd
+
+ if isinstance(pen, dict):
+ p = pen
+ else:
+ p = {}
+ p.update(pendict)
+
+ _p_buf = {}
+ for key in p:
+ _p_buf[key] = _pd[key]
+
+ if self.undobuffer:
+ self.undobuffer.push(("pen", _p_buf))
+
+ newLine = False
+ if "pendown" in p:
+ if self._drawing != p["pendown"]:
+ newLine = True
+ if "pencolor" in p:
+ if isinstance(p["pencolor"], tuple):
+ p["pencolor"] = self._colorstr((p["pencolor"],))
+ if self._pencolor != p["pencolor"]:
+ newLine = True
+ if "pensize" in p:
+ if self._pensize != p["pensize"]:
+ newLine = True
+ if newLine:
+ self._newLine()
+ if "pendown" in p:
+ self._drawing = p["pendown"]
+ if "pencolor" in p:
+ self._pencolor = p["pencolor"]
+ if "pensize" in p:
+ self._pensize = p["pensize"]
+ if "fillcolor" in p:
+ if isinstance(p["fillcolor"], tuple):
+ p["fillcolor"] = self._colorstr((p["fillcolor"],))
+ self._fillcolor = p["fillcolor"]
+ if "speed" in p:
+ self._speed = p["speed"]
+ if "resizemode" in p:
+ self._resizemode = p["resizemode"]
+ if "stretchfactor" in p:
+ sf = p["stretchfactor"]
+ if isinstance(sf, (int, float)):
+ sf = (sf, sf)
+ self._stretchfactor = sf
+ if "shearfactor" in p:
+ self._shearfactor = p["shearfactor"]
+ if "outline" in p:
+ self._outlinewidth = p["outline"]
+ if "shown" in p:
+ self._shown = p["shown"]
+ if "tilt" in p:
+ self._tilt = p["tilt"]
+ if "stretchfactor" in p or "tilt" in p or "shearfactor" in p:
+ scx, scy = self._stretchfactor
+ shf = self._shearfactor
+ sa, ca = math.sin(self._tilt), math.cos(self._tilt)
+ self._shapetrafo = ( scx*ca, scy*(shf*ca + sa),
+ -scx*sa, scy*(ca - shf*sa))
+ self._update()
+
+## three dummy methods to be implemented by child class:
+
+ def _newLine(self, usePos = True):
+ """dummy method - to be overwritten by child class"""
+ def _update(self, count=True, forced=False):
+ """dummy method - to be overwritten by child class"""
+ def _color(self, args):
+ """dummy method - to be overwritten by child class"""
+ def _colorstr(self, args):
+ """dummy method - to be overwritten by child class"""
+
+ width = pensize
+ up = penup
+ pu = penup
+ pd = pendown
+ down = pendown
+ st = showturtle
+ ht = hideturtle
+
+
+class _TurtleImage(object):
+ """Helper class: Datatype to store Turtle attributes
+ """
+
+ def __init__(self, screen, shapeIndex):
+ self.screen = screen
+ self._type = None
+ self._setshape(shapeIndex)
+
+ def _setshape(self, shapeIndex):
+ screen = self.screen
+ self.shapeIndex = shapeIndex
+ if self._type == "polygon" == screen._shapes[shapeIndex]._type:
+ return
+ if self._type == "image" == screen._shapes[shapeIndex]._type:
+ return
+ if self._type in ["image", "polygon"]:
+ screen._delete(self._item)
+ elif self._type == "compound":
+ for item in self._item:
+ screen._delete(item)
+ self._type = screen._shapes[shapeIndex]._type
+ if self._type == "polygon":
+ self._item = screen._createpoly()
+ elif self._type == "image":
+ self._item = screen._createimage(screen._shapes["blank"]._data)
+ elif self._type == "compound":
+ self._item = [screen._createpoly() for item in
+ screen._shapes[shapeIndex]._data]
+
+
+class RawTurtle(TPen, TNavigator):
+ """Animation part of the RawTurtle.
+ Puts RawTurtle upon a TurtleScreen and provides tools for
+ its animation.
+ """
+ screens = []
+
+ def __init__(self, canvas=None,
+ shape=_CFG["shape"],
+ undobuffersize=_CFG["undobuffersize"],
+ visible=_CFG["visible"]):
+ if isinstance(canvas, _Screen):
+ self.screen = canvas
+ elif isinstance(canvas, TurtleScreen):
+ if canvas not in RawTurtle.screens:
+ RawTurtle.screens.append(canvas)
+ self.screen = canvas
+ elif isinstance(canvas, (ScrolledCanvas, Canvas)):
+ for screen in RawTurtle.screens:
+ if screen.cv == canvas:
+ self.screen = screen
+ break
+ else:
+ self.screen = TurtleScreen(canvas)
+ RawTurtle.screens.append(self.screen)
+ else:
+ raise TurtleGraphicsError("bad canvas argument %s" % canvas)
+
+ screen = self.screen
+ TNavigator.__init__(self, screen.mode())
+ TPen.__init__(self)
+ screen._turtles.append(self)
+ self.drawingLineItem = screen._createline()
+ self.turtle = _TurtleImage(screen, shape)
+ self._poly = None
+ self._creatingPoly = False
+ self._fillitem = self._fillpath = None
+ self._shown = visible
+ self._hidden_from_screen = False
+ self.currentLineItem = screen._createline()
+ self.currentLine = [self._position]
+ self.items = [self.currentLineItem]
+ self.stampItems = []
+ self._undobuffersize = undobuffersize
+ self.undobuffer = Tbuffer(undobuffersize)
+ self._update()
+
+ def reset(self):
+ """Delete the turtle's drawings and restore its default values.
+
+ No argument.
+
+ Delete the turtle's drawings from the screen, re-center the turtle
+ and set variables to the default values.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.position()
+ (0.00,-22.00)
+ >>> turtle.heading()
+ 100.0
+ >>> turtle.reset()
+ >>> turtle.position()
+ (0.00,0.00)
+ >>> turtle.heading()
+ 0.0
+ """
+ TNavigator.reset(self)
+ TPen._reset(self)
+ self._clear()
+ self._drawturtle()
+ self._update()
+
+ def setundobuffer(self, size):
+ """Set or disable undobuffer.
+
+ Argument:
+ size -- an integer or None
+
+ If size is an integer an empty undobuffer of given size is installed.
+ Size gives the maximum number of turtle-actions that can be undone
+ by the undo() function.
+ If size is None, no undobuffer is present.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.setundobuffer(42)
+ """
+ if size is None or size <= 0:
+ self.undobuffer = None
+ else:
+ self.undobuffer = Tbuffer(size)
+
+ def undobufferentries(self):
+ """Return count of entries in the undobuffer.
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> while undobufferentries():
+ ... undo()
+ """
+ if self.undobuffer is None:
+ return 0
+ return self.undobuffer.nr_of_items()
+
+ def _clear(self):
+ """Delete all of pen's drawings"""
+ self._fillitem = self._fillpath = None
+ for item in self.items:
+ self.screen._delete(item)
+ self.currentLineItem = self.screen._createline()
+ self.currentLine = []
+ if self._drawing:
+ self.currentLine.append(self._position)
+ self.items = [self.currentLineItem]
+ self.clearstamps()
+ self.setundobuffer(self._undobuffersize)
+
+
+ def clear(self):
+ """Delete the turtle's drawings from the screen. Do not move turtle.
+
+ No arguments.
+
+ Delete the turtle's drawings from the screen. Do not move turtle.
+ State and position of the turtle as well as drawings of other
+ turtles are not affected.
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.clear()
+ """
+ self._clear()
+ self._update()
+
+ def _update_data(self):
+ self.screen._incrementudc()
+ if self.screen._updatecounter != 0:
+ return
+ if len(self.currentLine)>1:
+ self.screen._drawline(self.currentLineItem, self.currentLine,
+ self._pencolor, self._pensize)
+
+ def _update(self):
+ """Perform a Turtle-data update.
+ """
+ screen = self.screen
+ if screen._tracing == 0:
+ return
+ elif screen._tracing == 1:
+ self._update_data()
+ self._drawturtle()
+ screen._update() # TurtleScreenBase
+ screen._delay(screen._delayvalue) # TurtleScreenBase
+ else:
+ self._update_data()
+ if screen._updatecounter == 0:
+ for t in screen.turtles():
+ t._drawturtle()
+ screen._update()
+
+ def _tracer(self, flag=None, delay=None):
+ """Turns turtle animation on/off and set delay for update drawings.
+
+ Optional arguments:
+ n -- nonnegative integer
+ delay -- nonnegative integer
+
+ If n is given, only each n-th regular screen update is really performed.
+ (Can be used to accelerate the drawing of complex graphics.)
+ Second arguments sets delay value (see RawTurtle.delay())
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.tracer(8, 25)
+ >>> dist = 2
+ >>> for i in range(200):
+ ... turtle.fd(dist)
+ ... turtle.rt(90)
+ ... dist += 2
+ """
+ return self.screen.tracer(flag, delay)
+
+ def _color(self, args):
+ return self.screen._color(args)
+
+ def _colorstr(self, args):
+ return self.screen._colorstr(args)
+
+ def _cc(self, args):
+ """Convert colortriples to hexstrings.
+ """
+ if isinstance(args, str):
+ return args
+ try:
+ r, g, b = args
+ except (TypeError, ValueError):
+ raise TurtleGraphicsError("bad color arguments: %s" % str(args))
+ if self.screen._colormode == 1.0:
+ r, g, b = [round(255.0*x) for x in (r, g, b)]
+ if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
+ raise TurtleGraphicsError("bad color sequence: %s" % str(args))
+ return "#%02x%02x%02x" % (r, g, b)
+
+ def clone(self):
+ """Create and return a clone of the turtle.
+
+ No argument.
+
+ Create and return a clone of the turtle with same position, heading
+ and turtle properties.
+
+ Example (for a Turtle instance named mick):
+ mick = Turtle()
+ joe = mick.clone()
+ """
+ screen = self.screen
+ self._newLine(self._drawing)
+
+ turtle = self.turtle
+ self.screen = None
+ self.turtle = None # too make self deepcopy-able
+
+ q = deepcopy(self)
+
+ self.screen = screen
+ self.turtle = turtle
+
+ q.screen = screen
+ q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
+
+ screen._turtles.append(q)
+ ttype = screen._shapes[self.turtle.shapeIndex]._type
+ if ttype == "polygon":
+ q.turtle._item = screen._createpoly()
+ elif ttype == "image":
+ q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
+ elif ttype == "compound":
+ q.turtle._item = [screen._createpoly() for item in
+ screen._shapes[self.turtle.shapeIndex]._data]
+ q.currentLineItem = screen._createline()
+ q._update()
+ return q
+
+ def shape(self, name=None):
+ """Set turtle shape to shape with given name / return current shapename.
+
+ Optional argument:
+ name -- a string, which is a valid shapename
+
+ Set turtle shape to shape with given name or, if name is not given,
+ return name of current shape.
+ Shape with name must exist in the TurtleScreen's shape dictionary.
+ Initially there are the following polygon shapes:
+ 'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
+ To learn about how to deal with shapes see Screen-method register_shape.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.shape()
+ 'arrow'
+ >>> turtle.shape("turtle")
+ >>> turtle.shape()
+ 'turtle'
+ """
+ if name is None:
+ return self.turtle.shapeIndex
+ if not name in self.screen.getshapes():
+ raise TurtleGraphicsError("There is no shape named %s" % name)
+ self.turtle._setshape(name)
+ self._update()
+
+ def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
+ """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
+
+ Optional arguments:
+ stretch_wid : positive number
+ stretch_len : positive number
+ outline : positive number
+
+ Return or set the pen's attributes x/y-stretchfactors and/or outline.
+ Set resizemode to "user".
+ If and only if resizemode is set to "user", the turtle will be displayed
+ stretched according to its stretchfactors:
+ stretch_wid is stretchfactor perpendicular to orientation
+ stretch_len is stretchfactor in direction of turtles orientation.
+ outline determines the width of the shapes's outline.
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.resizemode("user")
+ >>> turtle.shapesize(5, 5, 12)
+ >>> turtle.shapesize(outline=8)
+ """
+ if stretch_wid is stretch_len is outline is None:
+ stretch_wid, stretch_len = self._stretchfactor
+ return stretch_wid, stretch_len, self._outlinewidth
+ if stretch_wid == 0 or stretch_len == 0:
+ raise TurtleGraphicsError("stretch_wid/stretch_len must not be zero")
+ if stretch_wid is not None:
+ if stretch_len is None:
+ stretchfactor = stretch_wid, stretch_wid
+ else:
+ stretchfactor = stretch_wid, stretch_len
+ elif stretch_len is not None:
+ stretchfactor = self._stretchfactor[0], stretch_len
+ else:
+ stretchfactor = self._stretchfactor
+ if outline is None:
+ outline = self._outlinewidth
+ self.pen(resizemode="user",
+ stretchfactor=stretchfactor, outline=outline)
+
+ def shearfactor(self, shear=None):
+ """Set or return the current shearfactor.
+
+ Optional argument: shear -- number, tangent of the shear angle
+
+ Shear the turtleshape according to the given shearfactor shear,
+ which is the tangent of the shear angle. DO NOT change the
+ turtle's heading (direction of movement).
+ If shear is not given: return the current shearfactor, i. e. the
+ tangent of the shear angle, by which lines parallel to the
+ heading of the turtle are sheared.
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.shape("circle")
+ >>> turtle.shapesize(5,2)
+ >>> turtle.shearfactor(0.5)
+ >>> turtle.shearfactor()
+ >>> 0.5
+ """
+ if shear is None:
+ return self._shearfactor
+ self.pen(resizemode="user", shearfactor=shear)
+
+ def settiltangle(self, angle):
+ """Rotate the turtleshape to point in the specified direction
+
+ Argument: angle -- number
+
+ Rotate the turtleshape to point in the direction specified by angle,
+ regardless of its current tilt-angle. DO NOT change the turtle's
+ heading (direction of movement).
+
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.shape("circle")
+ >>> turtle.shapesize(5,2)
+ >>> turtle.settiltangle(45)
+ >>> stamp()
+ >>> turtle.fd(50)
+ >>> turtle.settiltangle(-45)
+ >>> stamp()
+ >>> turtle.fd(50)
+ """
+ tilt = -angle * self._degreesPerAU * self._angleOrient
+ tilt = (tilt * math.pi / 180.0) % (2*math.pi)
+ self.pen(resizemode="user", tilt=tilt)
+
+ def tiltangle(self, angle=None):
+ """Set or return the current tilt-angle.
+
+ Optional argument: angle -- number
+
+ Rotate the turtleshape to point in the direction specified by angle,
+ regardless of its current tilt-angle. DO NOT change the turtle's
+ heading (direction of movement).
+ If angle is not given: return the current tilt-angle, i. e. the angle
+ between the orientation of the turtleshape and the heading of the
+ turtle (its direction of movement).
+
(Incorrectly marked as deprecated since Python 3.1, it is really
settiltangle that is deprecated.)
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.shape("circle")
- >>> turtle.shapesize(5,2)
- >>> turtle.tilt(45)
- >>> turtle.tiltangle()
- """
- if angle is None:
- tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
- return (tilt / self._degreesPerAU) % self._fullcircle
- else:
- self.settiltangle(angle)
-
- def tilt(self, angle):
- """Rotate the turtleshape by angle.
-
- Argument:
- angle - a number
-
- Rotate the turtleshape by angle from its current tilt-angle,
- but do NOT change the turtle's heading (direction of movement).
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.shape("circle")
- >>> turtle.shapesize(5,2)
- >>> turtle.tilt(30)
- >>> turtle.fd(50)
- >>> turtle.tilt(30)
- >>> turtle.fd(50)
- """
- self.settiltangle(angle + self.tiltangle())
-
- def shapetransform(self, t11=None, t12=None, t21=None, t22=None):
- """Set or return the current transformation matrix of the turtle shape.
-
- Optional arguments: t11, t12, t21, t22 -- numbers.
-
- If none of the matrix elements are given, return the transformation
- matrix.
- Otherwise set the given elements and transform the turtleshape
- according to the matrix consisting of first row t11, t12 and
- second row t21, 22.
- Modify stretchfactor, shearfactor and tiltangle according to the
- given matrix.
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.shape("square")
- >>> turtle.shapesize(4,2)
- >>> turtle.shearfactor(-0.5)
- >>> turtle.shapetransform()
- (4.0, -1.0, -0.0, 2.0)
- """
- if t11 is t12 is t21 is t22 is None:
- return self._shapetrafo
- m11, m12, m21, m22 = self._shapetrafo
- if t11 is not None: m11 = t11
- if t12 is not None: m12 = t12
- if t21 is not None: m21 = t21
- if t22 is not None: m22 = t22
- if t11 * t22 - t12 * t21 == 0:
- raise TurtleGraphicsError("Bad shape transform matrix: must not be singular")
- self._shapetrafo = (m11, m12, m21, m22)
- alfa = math.atan2(-m21, m11) % (2 * math.pi)
- sa, ca = math.sin(alfa), math.cos(alfa)
- a11, a12, a21, a22 = (ca*m11 - sa*m21, ca*m12 - sa*m22,
- sa*m11 + ca*m21, sa*m12 + ca*m22)
- self._stretchfactor = a11, a22
- self._shearfactor = a12/a22
- self._tilt = alfa
- self.pen(resizemode="user")
-
-
- def _polytrafo(self, poly):
- """Computes transformed polygon shapes from a shape
- according to current position and heading.
- """
- screen = self.screen
- p0, p1 = self._position
- e0, e1 = self._orient
- e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
- e0, e1 = (1.0 / abs(e)) * e
- return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
- for (x, y) in poly]
-
- def get_shapepoly(self):
- """Return the current shape polygon as tuple of coordinate pairs.
-
- No argument.
-
- Examples (for a Turtle instance named turtle):
- >>> turtle.shape("square")
- >>> turtle.shapetransform(4, -1, 0, 2)
- >>> turtle.get_shapepoly()
- ((50, -20), (30, 20), (-50, 20), (-30, -20))
-
- """
- shape = self.screen._shapes[self.turtle.shapeIndex]
- if shape._type == "polygon":
- return self._getshapepoly(shape._data, shape._type == "compound")
- # else return None
-
- def _getshapepoly(self, polygon, compound=False):
- """Calculate transformed shape polygon according to resizemode
- and shapetransform.
- """
- if self._resizemode == "user" or compound:
- t11, t12, t21, t22 = self._shapetrafo
- elif self._resizemode == "auto":
- l = max(1, self._pensize/5.0)
- t11, t12, t21, t22 = l, 0, 0, l
- elif self._resizemode == "noresize":
- return polygon
- return tuple((t11*x + t12*y, t21*x + t22*y) for (x, y) in polygon)
-
- def _drawturtle(self):
- """Manages the correct rendering of the turtle with respect to
- its shape, resizemode, stretch and tilt etc."""
- screen = self.screen
- shape = screen._shapes[self.turtle.shapeIndex]
- ttype = shape._type
- titem = self.turtle._item
- if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
- self._hidden_from_screen = False
- tshape = shape._data
- if ttype == "polygon":
- if self._resizemode == "noresize": w = 1
- elif self._resizemode == "auto": w = self._pensize
- else: w =self._outlinewidth
- shape = self._polytrafo(self._getshapepoly(tshape))
- fc, oc = self._fillcolor, self._pencolor
- screen._drawpoly(titem, shape, fill=fc, outline=oc,
- width=w, top=True)
- elif ttype == "image":
- screen._drawimage(titem, self._position, tshape)
- elif ttype == "compound":
- for item, (poly, fc, oc) in zip(titem, tshape):
- poly = self._polytrafo(self._getshapepoly(poly, True))
- screen._drawpoly(item, poly, fill=self._cc(fc),
- outline=self._cc(oc), width=self._outlinewidth, top=True)
- else:
- if self._hidden_from_screen:
- return
- if ttype == "polygon":
- screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
- elif ttype == "image":
- screen._drawimage(titem, self._position,
- screen._shapes["blank"]._data)
- elif ttype == "compound":
- for item in titem:
- screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
- self._hidden_from_screen = True
-
-############################## stamp stuff ###############################
-
- def stamp(self):
- """Stamp a copy of the turtleshape onto the canvas and return its id.
-
- No argument.
-
- Stamp a copy of the turtle shape onto the canvas at the current
- turtle position. Return a stamp_id for that stamp, which can be
- used to delete it by calling clearstamp(stamp_id).
-
- Example (for a Turtle instance named turtle):
- >>> turtle.color("blue")
- >>> turtle.stamp()
- 13
- >>> turtle.fd(50)
- """
- screen = self.screen
- shape = screen._shapes[self.turtle.shapeIndex]
- ttype = shape._type
- tshape = shape._data
- if ttype == "polygon":
- stitem = screen._createpoly()
- if self._resizemode == "noresize": w = 1
- elif self._resizemode == "auto": w = self._pensize
- else: w =self._outlinewidth
- shape = self._polytrafo(self._getshapepoly(tshape))
- fc, oc = self._fillcolor, self._pencolor
- screen._drawpoly(stitem, shape, fill=fc, outline=oc,
- width=w, top=True)
- elif ttype == "image":
- stitem = screen._createimage("")
- screen._drawimage(stitem, self._position, tshape)
- elif ttype == "compound":
- stitem = []
- for element in tshape:
- item = screen._createpoly()
- stitem.append(item)
- stitem = tuple(stitem)
- for item, (poly, fc, oc) in zip(stitem, tshape):
- poly = self._polytrafo(self._getshapepoly(poly, True))
- screen._drawpoly(item, poly, fill=self._cc(fc),
- outline=self._cc(oc), width=self._outlinewidth, top=True)
- self.stampItems.append(stitem)
- self.undobuffer.push(("stamp", stitem))
- return stitem
-
- def _clearstamp(self, stampid):
- """does the work for clearstamp() and clearstamps()
- """
- if stampid in self.stampItems:
- if isinstance(stampid, tuple):
- for subitem in stampid:
- self.screen._delete(subitem)
- else:
- self.screen._delete(stampid)
- self.stampItems.remove(stampid)
- # Delete stampitem from undobuffer if necessary
- # if clearstamp is called directly.
- item = ("stamp", stampid)
- buf = self.undobuffer
- if item not in buf.buffer:
- return
- index = buf.buffer.index(item)
- buf.buffer.remove(item)
- if index <= buf.ptr:
- buf.ptr = (buf.ptr - 1) % buf.bufsize
- buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
-
- def clearstamp(self, stampid):
- """Delete stamp with given stampid
-
- Argument:
- stampid - an integer, must be return value of previous stamp() call.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.color("blue")
- >>> astamp = turtle.stamp()
- >>> turtle.fd(50)
- >>> turtle.clearstamp(astamp)
- """
- self._clearstamp(stampid)
- self._update()
-
- def clearstamps(self, n=None):
- """Delete all or first/last n of turtle's stamps.
-
- Optional argument:
- n -- an integer
-
- If n is None, delete all of pen's stamps,
- else if n > 0 delete first n stamps
- else if n < 0 delete last n stamps.
-
- Example (for a Turtle instance named turtle):
- >>> for i in range(8):
- ... turtle.stamp(); turtle.fd(30)
- ...
- >>> turtle.clearstamps(2)
- >>> turtle.clearstamps(-2)
- >>> turtle.clearstamps()
- """
- if n is None:
- toDelete = self.stampItems[:]
- elif n >= 0:
- toDelete = self.stampItems[:n]
- else:
- toDelete = self.stampItems[n:]
- for item in toDelete:
- self._clearstamp(item)
- self._update()
-
- def _goto(self, end):
- """Move the pen to the point end, thereby drawing a line
- if pen is down. All other methods for turtle movement depend
- on this one.
- """
- ## Version with undo-stuff
- go_modes = ( self._drawing,
- self._pencolor,
- self._pensize,
- isinstance(self._fillpath, list))
- screen = self.screen
- undo_entry = ("go", self._position, end, go_modes,
- (self.currentLineItem,
- self.currentLine[:],
- screen._pointlist(self.currentLineItem),
- self.items[:])
- )
- if self.undobuffer:
- self.undobuffer.push(undo_entry)
- start = self._position
- if self._speed and screen._tracing == 1:
- diff = (end-start)
- diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
- nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
- delta = diff * (1.0/nhops)
- for n in range(1, nhops):
- if n == 1:
- top = True
- else:
- top = False
- self._position = start + delta * n
- if self._drawing:
- screen._drawline(self.drawingLineItem,
- (start, self._position),
- self._pencolor, self._pensize, top)
- self._update()
- if self._drawing:
- screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
- fill="", width=self._pensize)
- # Turtle now at end,
- if self._drawing: # now update currentLine
- self.currentLine.append(end)
- if isinstance(self._fillpath, list):
- self._fillpath.append(end)
- ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
- self._position = end
- if self._creatingPoly:
- self._poly.append(end)
- if len(self.currentLine) > 42: # 42! answer to the ultimate question
- # of life, the universe and everything
- self._newLine()
- self._update() #count=True)
-
- def _undogoto(self, entry):
- """Reverse a _goto. Used for undo()
- """
- old, new, go_modes, coodata = entry
- drawing, pc, ps, filling = go_modes
- cLI, cL, pl, items = coodata
- screen = self.screen
- if abs(self._position - new) > 0.5:
- print ("undogoto: HALLO-DA-STIMMT-WAS-NICHT!")
- # restore former situation
- self.currentLineItem = cLI
- self.currentLine = cL
-
- if pl == [(0, 0), (0, 0)]:
- usepc = ""
- else:
- usepc = pc
- screen._drawline(cLI, pl, fill=usepc, width=ps)
-
- todelete = [i for i in self.items if (i not in items) and
- (screen._type(i) == "line")]
- for i in todelete:
- screen._delete(i)
- self.items.remove(i)
-
- start = old
- if self._speed and screen._tracing == 1:
- diff = old - new
- diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
- nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
- delta = diff * (1.0/nhops)
- for n in range(1, nhops):
- if n == 1:
- top = True
- else:
- top = False
- self._position = new + delta * n
- if drawing:
- screen._drawline(self.drawingLineItem,
- (start, self._position),
- pc, ps, top)
- self._update()
- if drawing:
- screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
- fill="", width=ps)
- # Turtle now at position old,
- self._position = old
- ## if undo is done during creating a polygon, the last vertex
- ## will be deleted. if the polygon is entirely deleted,
- ## creatingPoly will be set to False.
- ## Polygons created before the last one will not be affected by undo()
- if self._creatingPoly:
- if len(self._poly) > 0:
- self._poly.pop()
- if self._poly == []:
- self._creatingPoly = False
- self._poly = None
- if filling:
- if self._fillpath == []:
- self._fillpath = None
- print("Unwahrscheinlich in _undogoto!")
- elif self._fillpath is not None:
- self._fillpath.pop()
- self._update() #count=True)
-
- def _rotate(self, angle):
- """Turns pen clockwise by angle.
- """
- if self.undobuffer:
- self.undobuffer.push(("rot", angle, self._degreesPerAU))
- angle *= self._degreesPerAU
- neworient = self._orient.rotate(angle)
- tracing = self.screen._tracing
- if tracing == 1 and self._speed > 0:
- anglevel = 3.0 * self._speed
- steps = 1 + int(abs(angle)/anglevel)
- delta = 1.0*angle/steps
- for _ in range(steps):
- self._orient = self._orient.rotate(delta)
- self._update()
- self._orient = neworient
- self._update()
-
- def _newLine(self, usePos=True):
- """Closes current line item and starts a new one.
- Remark: if current line became too long, animation
- performance (via _drawline) slowed down considerably.
- """
- if len(self.currentLine) > 1:
- self.screen._drawline(self.currentLineItem, self.currentLine,
- self._pencolor, self._pensize)
- self.currentLineItem = self.screen._createline()
- self.items.append(self.currentLineItem)
- else:
- self.screen._drawline(self.currentLineItem, top=True)
- self.currentLine = []
- if usePos:
- self.currentLine = [self._position]
-
- def filling(self):
- """Return fillstate (True if filling, False else).
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.begin_fill()
- >>> if turtle.filling():
- ... turtle.pensize(5)
- ... else:
- ... turtle.pensize(3)
- """
- return isinstance(self._fillpath, list)
-
- def begin_fill(self):
- """Called just before drawing a shape to be filled.
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.color("black", "red")
- >>> turtle.begin_fill()
- >>> turtle.circle(60)
- >>> turtle.end_fill()
- """
- if not self.filling():
- self._fillitem = self.screen._createpoly()
- self.items.append(self._fillitem)
- self._fillpath = [self._position]
- self._newLine()
- if self.undobuffer:
- self.undobuffer.push(("beginfill", self._fillitem))
- self._update()
-
-
- def end_fill(self):
- """Fill the shape drawn after the call begin_fill().
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.color("black", "red")
- >>> turtle.begin_fill()
- >>> turtle.circle(60)
- >>> turtle.end_fill()
- """
- if self.filling():
- if len(self._fillpath) > 2:
- self.screen._drawpoly(self._fillitem, self._fillpath,
- fill=self._fillcolor)
- if self.undobuffer:
- self.undobuffer.push(("dofill", self._fillitem))
- self._fillitem = self._fillpath = None
- self._update()
-
- def dot(self, size=None, *color):
- """Draw a dot with diameter size, using color.
-
- Optional arguments:
- size -- an integer >= 1 (if given)
- color -- a colorstring or a numeric color tuple
-
- Draw a circular dot with diameter size, using color.
- If size is not given, the maximum of pensize+4 and 2*pensize is used.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.dot()
- >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
- """
- if not color:
- if isinstance(size, (str, tuple)):
- color = self._colorstr(size)
- size = self._pensize + max(self._pensize, 4)
- else:
- color = self._pencolor
- if not size:
- size = self._pensize + max(self._pensize, 4)
- else:
- if size is None:
- size = self._pensize + max(self._pensize, 4)
- color = self._colorstr(color)
- if hasattr(self.screen, "_dot"):
- item = self.screen._dot(self._position, size, color)
- self.items.append(item)
- if self.undobuffer:
- self.undobuffer.push(("dot", item))
- else:
- pen = self.pen()
- if self.undobuffer:
- self.undobuffer.push(["seq"])
- self.undobuffer.cumulate = True
- try:
- if self.resizemode() == 'auto':
- self.ht()
- self.pendown()
- self.pensize(size)
- self.pencolor(color)
- self.forward(0)
- finally:
- self.pen(pen)
- if self.undobuffer:
- self.undobuffer.cumulate = False
-
- def _write(self, txt, align, font):
- """Performs the writing for write()
- """
- item, end = self.screen._write(self._position, txt, align, font,
- self._pencolor)
- self.items.append(item)
- if self.undobuffer:
- self.undobuffer.push(("wri", item))
- return end
-
- def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
- """Write text at the current turtle position.
-
- Arguments:
- arg -- info, which is to be written to the TurtleScreen
- move (optional) -- True/False
- align (optional) -- one of the strings "left", "center" or right"
- font (optional) -- a triple (fontname, fontsize, fonttype)
-
- Write text - the string representation of arg - at the current
- turtle position according to align ("left", "center" or right")
- and with the given font.
- If move is True, the pen is moved to the bottom-right corner
- of the text. By default, move is False.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.write('Home = ', True, align="center")
- >>> turtle.write((0,0), True)
- """
- if self.undobuffer:
- self.undobuffer.push(["seq"])
- self.undobuffer.cumulate = True
- end = self._write(str(arg), align.lower(), font)
- if move:
- x, y = self.pos()
- self.setpos(end, y)
- if self.undobuffer:
- self.undobuffer.cumulate = False
-
- def begin_poly(self):
- """Start recording the vertices of a polygon.
-
- No argument.
-
- Start recording the vertices of a polygon. Current turtle position
- is first point of polygon.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.begin_poly()
- """
- self._poly = [self._position]
- self._creatingPoly = True
-
- def end_poly(self):
- """Stop recording the vertices of a polygon.
-
- No argument.
-
- Stop recording the vertices of a polygon. Current turtle position is
- last point of polygon. This will be connected with the first point.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.end_poly()
- """
- self._creatingPoly = False
-
- def get_poly(self):
- """Return the lastly recorded polygon.
-
- No argument.
-
- Example (for a Turtle instance named turtle):
- >>> p = turtle.get_poly()
- >>> turtle.register_shape("myFavouriteShape", p)
- """
- ## check if there is any poly?
- if self._poly is not None:
- return tuple(self._poly)
-
- def getscreen(self):
- """Return the TurtleScreen object, the turtle is drawing on.
-
- No argument.
-
- Return the TurtleScreen object, the turtle is drawing on.
- So TurtleScreen-methods can be called for that object.
-
- Example (for a Turtle instance named turtle):
- >>> ts = turtle.getscreen()
- >>> ts
- <turtle.TurtleScreen object at 0x0106B770>
- >>> ts.bgcolor("pink")
- """
- return self.screen
-
- def getturtle(self):
- """Return the Turtleobject itself.
-
- No argument.
-
- Only reasonable use: as a function to return the 'anonymous turtle':
-
- Example:
- >>> pet = getturtle()
- >>> pet.fd(50)
- >>> pet
- <turtle.Turtle object at 0x0187D810>
- >>> turtles()
- [<turtle.Turtle object at 0x0187D810>]
- """
- return self
-
- getpen = getturtle
-
-
- ################################################################
- ### screen oriented methods recurring to methods of TurtleScreen
- ################################################################
-
- def _delay(self, delay=None):
- """Set delay value which determines speed of turtle animation.
- """
- return self.screen.delay(delay)
-
- def onclick(self, fun, btn=1, add=None):
- """Bind fun to mouse-click event on this turtle on canvas.
-
- Arguments:
- fun -- a function with two arguments, to which will be assigned
- the coordinates of the clicked point on the canvas.
- btn -- number of the mouse-button defaults to 1 (left mouse button).
- add -- True or False. If True, new binding will be added, otherwise
- it will replace a former binding.
-
- Example for the anonymous turtle, i. e. the procedural way:
-
- >>> def turn(x, y):
- ... left(360)
- ...
- >>> onclick(turn) # Now clicking into the turtle will turn it.
- >>> onclick(None) # event-binding will be removed
- """
- self.screen._onclick(self.turtle._item, fun, btn, add)
- self._update()
-
- def onrelease(self, fun, btn=1, add=None):
- """Bind fun to mouse-button-release event on this turtle on canvas.
-
- Arguments:
- fun -- a function with two arguments, to which will be assigned
- the coordinates of the clicked point on the canvas.
- btn -- number of the mouse-button defaults to 1 (left mouse button).
-
- Example (for a MyTurtle instance named joe):
- >>> class MyTurtle(Turtle):
- ... def glow(self,x,y):
- ... self.fillcolor("red")
- ... def unglow(self,x,y):
- ... self.fillcolor("")
- ...
- >>> joe = MyTurtle()
- >>> joe.onclick(joe.glow)
- >>> joe.onrelease(joe.unglow)
-
- Clicking on joe turns fillcolor red, unclicking turns it to
- transparent.
- """
- self.screen._onrelease(self.turtle._item, fun, btn, add)
- self._update()
-
- def ondrag(self, fun, btn=1, add=None):
- """Bind fun to mouse-move event on this turtle on canvas.
-
- Arguments:
- fun -- a function with two arguments, to which will be assigned
- the coordinates of the clicked point on the canvas.
- btn -- number of the mouse-button defaults to 1 (left mouse button).
-
- Every sequence of mouse-move-events on a turtle is preceded by a
- mouse-click event on that turtle.
-
- Example (for a Turtle instance named turtle):
- >>> turtle.ondrag(turtle.goto)
-
- Subsequently clicking and dragging a Turtle will move it
- across the screen thereby producing handdrawings (if pen is
- down).
- """
- self.screen._ondrag(self.turtle._item, fun, btn, add)
-
-
- def _undo(self, action, data):
- """Does the main part of the work for undo()
- """
- if self.undobuffer is None:
- return
- if action == "rot":
- angle, degPAU = data
- self._rotate(-angle*degPAU/self._degreesPerAU)
- dummy = self.undobuffer.pop()
- elif action == "stamp":
- stitem = data[0]
- self.clearstamp(stitem)
- elif action == "go":
- self._undogoto(data)
- elif action in ["wri", "dot"]:
- item = data[0]
- self.screen._delete(item)
- self.items.remove(item)
- elif action == "dofill":
- item = data[0]
- self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
- fill="", outline="")
- elif action == "beginfill":
- item = data[0]
- self._fillitem = self._fillpath = None
- if item in self.items:
- self.screen._delete(item)
- self.items.remove(item)
- elif action == "pen":
- TPen.pen(self, data[0])
- self.undobuffer.pop()
-
- def undo(self):
- """undo (repeatedly) the last turtle action.
-
- No argument.
-
- undo (repeatedly) the last turtle action.
- Number of available undo actions is determined by the size of
- the undobuffer.
-
- Example (for a Turtle instance named turtle):
- >>> for i in range(4):
- ... turtle.fd(50); turtle.lt(80)
- ...
- >>> for i in range(8):
- ... turtle.undo()
- ...
- """
- if self.undobuffer is None:
- return
- item = self.undobuffer.pop()
- action = item[0]
- data = item[1:]
- if action == "seq":
- while data:
- item = data.pop()
- self._undo(item[0], item[1:])
- else:
- self._undo(action, data)
-
- turtlesize = shapesize
-
-RawPen = RawTurtle
-
-### Screen - Singleton ########################
-
-def Screen():
- """Return the singleton screen object.
- If none exists at the moment, create a new one and return it,
- else return the existing one."""
- if Turtle._screen is None:
- Turtle._screen = _Screen()
- return Turtle._screen
-
-class _Screen(TurtleScreen):
-
- _root = None
- _canvas = None
- _title = _CFG["title"]
-
- def __init__(self):
- # XXX there is no need for this code to be conditional,
- # as there will be only a single _Screen instance, anyway
- # XXX actually, the turtle demo is injecting root window,
- # so perhaps the conditional creation of a root should be
- # preserved (perhaps by passing it as an optional parameter)
- if _Screen._root is None:
- _Screen._root = self._root = _Root()
- self._root.title(_Screen._title)
- self._root.ondestroy(self._destroy)
- if _Screen._canvas is None:
- width = _CFG["width"]
- height = _CFG["height"]
- canvwidth = _CFG["canvwidth"]
- canvheight = _CFG["canvheight"]
- leftright = _CFG["leftright"]
- topbottom = _CFG["topbottom"]
- self._root.setupcanvas(width, height, canvwidth, canvheight)
- _Screen._canvas = self._root._getcanvas()
- TurtleScreen.__init__(self, _Screen._canvas)
- self.setup(width, height, leftright, topbottom)
-
- def setup(self, width=_CFG["width"], height=_CFG["height"],
- startx=_CFG["leftright"], starty=_CFG["topbottom"]):
- """ Set the size and position of the main window.
-
- Arguments:
- width: as integer a size in pixels, as float a fraction of the screen.
- Default is 50% of screen.
- height: as integer the height in pixels, as float a fraction of the
- screen. Default is 75% of screen.
- startx: if positive, starting position in pixels from the left
- edge of the screen, if negative from the right edge
- Default, startx=None is to center window horizontally.
- starty: if positive, starting position in pixels from the top
- edge of the screen, if negative from the bottom edge
- Default, starty=None is to center window vertically.
-
- Examples (for a Screen instance named screen):
- >>> screen.setup (width=200, height=200, startx=0, starty=0)
-
- sets window to 200x200 pixels, in upper left of screen
-
- >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
-
- sets window to 75% of screen by 50% of screen and centers
- """
- if not hasattr(self._root, "set_geometry"):
- return
- sw = self._root.win_width()
- sh = self._root.win_height()
- if isinstance(width, float) and 0 <= width <= 1:
- width = sw*width
- if startx is None:
- startx = (sw - width) / 2
- if isinstance(height, float) and 0 <= height <= 1:
- height = sh*height
- if starty is None:
- starty = (sh - height) / 2
- self._root.set_geometry(width, height, startx, starty)
- self.update()
-
- def title(self, titlestring):
- """Set title of turtle-window
-
- Argument:
- titlestring -- a string, to appear in the titlebar of the
- turtle graphics window.
-
- This is a method of Screen-class. Not available for TurtleScreen-
- objects.
-
- Example (for a Screen instance named screen):
- >>> screen.title("Welcome to the turtle-zoo!")
- """
- if _Screen._root is not None:
- _Screen._root.title(titlestring)
- _Screen._title = titlestring
-
- def _destroy(self):
- root = self._root
- if root is _Screen._root:
- Turtle._pen = None
- Turtle._screen = None
- _Screen._root = None
- _Screen._canvas = None
- TurtleScreen._RUNNING = False
- root.destroy()
-
- def bye(self):
- """Shut the turtlegraphics window.
-
- Example (for a TurtleScreen instance named screen):
- >>> screen.bye()
- """
- self._destroy()
-
- def exitonclick(self):
- """Go into mainloop until the mouse is clicked.
-
- No arguments.
-
- Bind bye() method to mouseclick on TurtleScreen.
- If "using_IDLE" - value in configuration dictionary is False
- (default value), enter mainloop.
- If IDLE with -n switch (no subprocess) is used, this value should be
- set to True in turtle.cfg. In this case IDLE's mainloop
- is active also for the client script.
-
- This is a method of the Screen-class and not available for
- TurtleScreen instances.
-
- Example (for a Screen instance named screen):
- >>> screen.exitonclick()
-
- """
- def exitGracefully(x, y):
- """Screen.bye() with two dummy-parameters"""
- self.bye()
- self.onclick(exitGracefully)
- if _CFG["using_IDLE"]:
- return
- try:
- mainloop()
- except AttributeError:
- exit(0)
-
-class Turtle(RawTurtle):
- """RawTurtle auto-creating (scrolled) canvas.
-
- When a Turtle object is created or a function derived from some
- Turtle method is called a TurtleScreen object is automatically created.
- """
- _pen = None
- _screen = None
-
- def __init__(self,
- shape=_CFG["shape"],
- undobuffersize=_CFG["undobuffersize"],
- visible=_CFG["visible"]):
- if Turtle._screen is None:
- Turtle._screen = Screen()
- RawTurtle.__init__(self, Turtle._screen,
- shape=shape,
- undobuffersize=undobuffersize,
- visible=visible)
-
-Pen = Turtle
-
-def write_docstringdict(filename="turtle_docstringdict"):
- """Create and write docstring-dictionary to file.
-
- Optional argument:
- filename -- a string, used as filename
- default value is turtle_docstringdict
-
- Has to be called explicitly, (not used by the turtle-graphics classes)
- The docstring dictionary will be written to the Python script <filname>.py
- It is intended to serve as a template for translation of the docstrings
- into different languages.
- """
- docsdict = {}
-
- for methodname in _tg_screen_functions:
- key = "_Screen."+methodname
- docsdict[key] = eval(key).__doc__
- for methodname in _tg_turtle_functions:
- key = "Turtle."+methodname
- docsdict[key] = eval(key).__doc__
-
- with open("%s.py" % filename,"w") as f:
- keys = sorted(x for x in docsdict
- if x.split('.')[1] not in _alias_list)
- f.write('docsdict = {\n\n')
- for key in keys[:-1]:
- f.write('%s :\n' % repr(key))
- f.write(' """%s\n""",\n\n' % docsdict[key])
- key = keys[-1]
- f.write('%s :\n' % repr(key))
- f.write(' """%s\n"""\n\n' % docsdict[key])
- f.write("}\n")
- f.close()
-
-def read_docstrings(lang):
- """Read in docstrings from lang-specific docstring dictionary.
-
- Transfer docstrings, translated to lang, from a dictionary-file
- to the methods of classes Screen and Turtle and - in revised form -
- to the corresponding functions.
- """
- modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
- module = __import__(modname)
- docsdict = module.docsdict
- for key in docsdict:
- try:
-# eval(key).im_func.__doc__ = docsdict[key]
- eval(key).__doc__ = docsdict[key]
- except Exception:
- print("Bad docstring-entry: %s" % key)
-
-_LANGUAGE = _CFG["language"]
-
-try:
- if _LANGUAGE != "english":
- read_docstrings(_LANGUAGE)
-except ImportError:
- print("Cannot find docsdict for", _LANGUAGE)
-except Exception:
- print ("Unknown Error when trying to import %s-docstring-dictionary" %
- _LANGUAGE)
-
-
-def getmethparlist(ob):
- """Get strings describing the arguments for the given object
-
- Returns a pair of strings representing function parameter lists
- including parenthesis. The first string is suitable for use in
- function definition and the second is suitable for use in function
- call. The "self" parameter is not included.
- """
- defText = callText = ""
- # bit of a hack for methods - turn it into a function
- # but we drop the "self" param.
- # Try and build one for Python defined functions
- args, varargs, varkw = inspect.getargs(ob.__code__)
- items2 = args[1:]
- realArgs = args[1:]
- defaults = ob.__defaults__ or []
- defaults = ["=%r" % (value,) for value in defaults]
- defaults = [""] * (len(realArgs)-len(defaults)) + defaults
- items1 = [arg + dflt for arg, dflt in zip(realArgs, defaults)]
- if varargs is not None:
- items1.append("*" + varargs)
- items2.append("*" + varargs)
- if varkw is not None:
- items1.append("**" + varkw)
- items2.append("**" + varkw)
- defText = ", ".join(items1)
- defText = "(%s)" % defText
- callText = ", ".join(items2)
- callText = "(%s)" % callText
- return defText, callText
-
-def _turtle_docrevise(docstr):
- """To reduce docstrings from RawTurtle class for functions
- """
- import re
- if docstr is None:
- return None
- turtlename = _CFG["exampleturtle"]
- newdocstr = docstr.replace("%s." % turtlename,"")
- parexp = re.compile(r' \(.+ %s\):' % turtlename)
- newdocstr = parexp.sub(":", newdocstr)
- return newdocstr
-
-def _screen_docrevise(docstr):
- """To reduce docstrings from TurtleScreen class for functions
- """
- import re
- if docstr is None:
- return None
- screenname = _CFG["examplescreen"]
- newdocstr = docstr.replace("%s." % screenname,"")
- parexp = re.compile(r' \(.+ %s\):' % screenname)
- newdocstr = parexp.sub(":", newdocstr)
- return newdocstr
-
-## The following mechanism makes all methods of RawTurtle and Turtle available
-## as functions. So we can enhance, change, add, delete methods to these
-## classes and do not need to change anything here.
-
-__func_body = """\
-def {name}{paramslist}:
- if {obj} is None:
- if not TurtleScreen._RUNNING:
- TurtleScreen._RUNNING = True
- raise Terminator
- {obj} = {init}
- try:
- return {obj}.{name}{argslist}
- except TK.TclError:
- if not TurtleScreen._RUNNING:
- TurtleScreen._RUNNING = True
- raise Terminator
- raise
-"""
-
-def _make_global_funcs(functions, cls, obj, init, docrevise):
- for methodname in functions:
- method = getattr(cls, methodname)
- pl1, pl2 = getmethparlist(method)
- if pl1 == "":
- print(">>>>>>", pl1, pl2)
- continue
- defstr = __func_body.format(obj=obj, init=init, name=methodname,
- paramslist=pl1, argslist=pl2)
- exec(defstr, globals())
- globals()[methodname].__doc__ = docrevise(method.__doc__)
-
-_make_global_funcs(_tg_screen_functions, _Screen,
- 'Turtle._screen', 'Screen()', _screen_docrevise)
-_make_global_funcs(_tg_turtle_functions, Turtle,
- 'Turtle._pen', 'Turtle()', _turtle_docrevise)
-
-
-done = mainloop
-
-if __name__ == "__main__":
- def switchpen():
- if isdown():
- pu()
- else:
- pd()
-
- def demo1():
- """Demo of old turtle.py - module"""
- reset()
- tracer(True)
- up()
- backward(100)
- down()
- # draw 3 squares; the last filled
- width(3)
- for i in range(3):
- if i == 2:
- begin_fill()
- for _ in range(4):
- forward(20)
- left(90)
- if i == 2:
- color("maroon")
- end_fill()
- up()
- forward(30)
- down()
- width(1)
- color("black")
- # move out of the way
- tracer(False)
- up()
- right(90)
- forward(100)
- right(90)
- forward(100)
- right(180)
- down()
- # some text
- write("startstart", 1)
- write("start", 1)
- color("red")
- # staircase
- for i in range(5):
- forward(20)
- left(90)
- forward(20)
- right(90)
- # filled staircase
- tracer(True)
- begin_fill()
- for i in range(5):
- forward(20)
- left(90)
- forward(20)
- right(90)
- end_fill()
- # more text
-
- def demo2():
- """Demo of some new features."""
- speed(1)
- st()
- pensize(3)
- setheading(towards(0, 0))
- radius = distance(0, 0)/2.0
- rt(90)
- for _ in range(18):
- switchpen()
- circle(radius, 10)
- write("wait a moment...")
- while undobufferentries():
- undo()
- reset()
- lt(90)
- colormode(255)
- laenge = 10
- pencolor("green")
- pensize(3)
- lt(180)
- for i in range(-2, 16):
- if i > 0:
- begin_fill()
- fillcolor(255-15*i, 0, 15*i)
- for _ in range(3):
- fd(laenge)
- lt(120)
- end_fill()
- laenge += 10
- lt(15)
- speed((speed()+1)%12)
- #end_fill()
-
- lt(120)
- pu()
- fd(70)
- rt(30)
- pd()
- color("red","yellow")
- speed(0)
- begin_fill()
- for _ in range(4):
- circle(50, 90)
- rt(90)
- fd(30)
- rt(90)
- end_fill()
- lt(90)
- pu()
- fd(30)
- pd()
- shape("turtle")
-
- tri = getturtle()
- tri.resizemode("auto")
- turtle = Turtle()
- turtle.resizemode("auto")
- turtle.shape("turtle")
- turtle.reset()
- turtle.left(90)
- turtle.speed(0)
- turtle.up()
- turtle.goto(280, 40)
- turtle.lt(30)
- turtle.down()
- turtle.speed(6)
- turtle.color("blue","orange")
- turtle.pensize(2)
- tri.speed(6)
- setheading(towards(turtle))
- count = 1
- while tri.distance(turtle) > 4:
- turtle.fd(3.5)
- turtle.lt(0.6)
- tri.setheading(tri.towards(turtle))
- tri.fd(4)
- if count % 20 == 0:
- turtle.stamp()
- tri.stamp()
- switchpen()
- count += 1
- tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
- tri.pencolor("black")
- tri.pencolor("red")
-
- def baba(xdummy, ydummy):
- clearscreen()
- bye()
-
- time.sleep(2)
-
- while undobufferentries():
- tri.undo()
- turtle.undo()
- tri.fd(50)
- tri.write(" Click me!", font = ("Courier", 12, "bold") )
- tri.onclick(baba, 1)
-
- demo1()
- demo2()
- exitonclick()
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.shape("circle")
+ >>> turtle.shapesize(5,2)
+ >>> turtle.tilt(45)
+ >>> turtle.tiltangle()
+ """
+ if angle is None:
+ tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
+ return (tilt / self._degreesPerAU) % self._fullcircle
+ else:
+ self.settiltangle(angle)
+
+ def tilt(self, angle):
+ """Rotate the turtleshape by angle.
+
+ Argument:
+ angle - a number
+
+ Rotate the turtleshape by angle from its current tilt-angle,
+ but do NOT change the turtle's heading (direction of movement).
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.shape("circle")
+ >>> turtle.shapesize(5,2)
+ >>> turtle.tilt(30)
+ >>> turtle.fd(50)
+ >>> turtle.tilt(30)
+ >>> turtle.fd(50)
+ """
+ self.settiltangle(angle + self.tiltangle())
+
+ def shapetransform(self, t11=None, t12=None, t21=None, t22=None):
+ """Set or return the current transformation matrix of the turtle shape.
+
+ Optional arguments: t11, t12, t21, t22 -- numbers.
+
+ If none of the matrix elements are given, return the transformation
+ matrix.
+ Otherwise set the given elements and transform the turtleshape
+ according to the matrix consisting of first row t11, t12 and
+ second row t21, 22.
+ Modify stretchfactor, shearfactor and tiltangle according to the
+ given matrix.
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.shape("square")
+ >>> turtle.shapesize(4,2)
+ >>> turtle.shearfactor(-0.5)
+ >>> turtle.shapetransform()
+ (4.0, -1.0, -0.0, 2.0)
+ """
+ if t11 is t12 is t21 is t22 is None:
+ return self._shapetrafo
+ m11, m12, m21, m22 = self._shapetrafo
+ if t11 is not None: m11 = t11
+ if t12 is not None: m12 = t12
+ if t21 is not None: m21 = t21
+ if t22 is not None: m22 = t22
+ if t11 * t22 - t12 * t21 == 0:
+ raise TurtleGraphicsError("Bad shape transform matrix: must not be singular")
+ self._shapetrafo = (m11, m12, m21, m22)
+ alfa = math.atan2(-m21, m11) % (2 * math.pi)
+ sa, ca = math.sin(alfa), math.cos(alfa)
+ a11, a12, a21, a22 = (ca*m11 - sa*m21, ca*m12 - sa*m22,
+ sa*m11 + ca*m21, sa*m12 + ca*m22)
+ self._stretchfactor = a11, a22
+ self._shearfactor = a12/a22
+ self._tilt = alfa
+ self.pen(resizemode="user")
+
+
+ def _polytrafo(self, poly):
+ """Computes transformed polygon shapes from a shape
+ according to current position and heading.
+ """
+ screen = self.screen
+ p0, p1 = self._position
+ e0, e1 = self._orient
+ e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
+ e0, e1 = (1.0 / abs(e)) * e
+ return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
+ for (x, y) in poly]
+
+ def get_shapepoly(self):
+ """Return the current shape polygon as tuple of coordinate pairs.
+
+ No argument.
+
+ Examples (for a Turtle instance named turtle):
+ >>> turtle.shape("square")
+ >>> turtle.shapetransform(4, -1, 0, 2)
+ >>> turtle.get_shapepoly()
+ ((50, -20), (30, 20), (-50, 20), (-30, -20))
+
+ """
+ shape = self.screen._shapes[self.turtle.shapeIndex]
+ if shape._type == "polygon":
+ return self._getshapepoly(shape._data, shape._type == "compound")
+ # else return None
+
+ def _getshapepoly(self, polygon, compound=False):
+ """Calculate transformed shape polygon according to resizemode
+ and shapetransform.
+ """
+ if self._resizemode == "user" or compound:
+ t11, t12, t21, t22 = self._shapetrafo
+ elif self._resizemode == "auto":
+ l = max(1, self._pensize/5.0)
+ t11, t12, t21, t22 = l, 0, 0, l
+ elif self._resizemode == "noresize":
+ return polygon
+ return tuple((t11*x + t12*y, t21*x + t22*y) for (x, y) in polygon)
+
+ def _drawturtle(self):
+ """Manages the correct rendering of the turtle with respect to
+ its shape, resizemode, stretch and tilt etc."""
+ screen = self.screen
+ shape = screen._shapes[self.turtle.shapeIndex]
+ ttype = shape._type
+ titem = self.turtle._item
+ if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
+ self._hidden_from_screen = False
+ tshape = shape._data
+ if ttype == "polygon":
+ if self._resizemode == "noresize": w = 1
+ elif self._resizemode == "auto": w = self._pensize
+ else: w =self._outlinewidth
+ shape = self._polytrafo(self._getshapepoly(tshape))
+ fc, oc = self._fillcolor, self._pencolor
+ screen._drawpoly(titem, shape, fill=fc, outline=oc,
+ width=w, top=True)
+ elif ttype == "image":
+ screen._drawimage(titem, self._position, tshape)
+ elif ttype == "compound":
+ for item, (poly, fc, oc) in zip(titem, tshape):
+ poly = self._polytrafo(self._getshapepoly(poly, True))
+ screen._drawpoly(item, poly, fill=self._cc(fc),
+ outline=self._cc(oc), width=self._outlinewidth, top=True)
+ else:
+ if self._hidden_from_screen:
+ return
+ if ttype == "polygon":
+ screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
+ elif ttype == "image":
+ screen._drawimage(titem, self._position,
+ screen._shapes["blank"]._data)
+ elif ttype == "compound":
+ for item in titem:
+ screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
+ self._hidden_from_screen = True
+
+############################## stamp stuff ###############################
+
+ def stamp(self):
+ """Stamp a copy of the turtleshape onto the canvas and return its id.
+
+ No argument.
+
+ Stamp a copy of the turtle shape onto the canvas at the current
+ turtle position. Return a stamp_id for that stamp, which can be
+ used to delete it by calling clearstamp(stamp_id).
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.color("blue")
+ >>> turtle.stamp()
+ 13
+ >>> turtle.fd(50)
+ """
+ screen = self.screen
+ shape = screen._shapes[self.turtle.shapeIndex]
+ ttype = shape._type
+ tshape = shape._data
+ if ttype == "polygon":
+ stitem = screen._createpoly()
+ if self._resizemode == "noresize": w = 1
+ elif self._resizemode == "auto": w = self._pensize
+ else: w =self._outlinewidth
+ shape = self._polytrafo(self._getshapepoly(tshape))
+ fc, oc = self._fillcolor, self._pencolor
+ screen._drawpoly(stitem, shape, fill=fc, outline=oc,
+ width=w, top=True)
+ elif ttype == "image":
+ stitem = screen._createimage("")
+ screen._drawimage(stitem, self._position, tshape)
+ elif ttype == "compound":
+ stitem = []
+ for element in tshape:
+ item = screen._createpoly()
+ stitem.append(item)
+ stitem = tuple(stitem)
+ for item, (poly, fc, oc) in zip(stitem, tshape):
+ poly = self._polytrafo(self._getshapepoly(poly, True))
+ screen._drawpoly(item, poly, fill=self._cc(fc),
+ outline=self._cc(oc), width=self._outlinewidth, top=True)
+ self.stampItems.append(stitem)
+ self.undobuffer.push(("stamp", stitem))
+ return stitem
+
+ def _clearstamp(self, stampid):
+ """does the work for clearstamp() and clearstamps()
+ """
+ if stampid in self.stampItems:
+ if isinstance(stampid, tuple):
+ for subitem in stampid:
+ self.screen._delete(subitem)
+ else:
+ self.screen._delete(stampid)
+ self.stampItems.remove(stampid)
+ # Delete stampitem from undobuffer if necessary
+ # if clearstamp is called directly.
+ item = ("stamp", stampid)
+ buf = self.undobuffer
+ if item not in buf.buffer:
+ return
+ index = buf.buffer.index(item)
+ buf.buffer.remove(item)
+ if index <= buf.ptr:
+ buf.ptr = (buf.ptr - 1) % buf.bufsize
+ buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
+
+ def clearstamp(self, stampid):
+ """Delete stamp with given stampid
+
+ Argument:
+ stampid - an integer, must be return value of previous stamp() call.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.color("blue")
+ >>> astamp = turtle.stamp()
+ >>> turtle.fd(50)
+ >>> turtle.clearstamp(astamp)
+ """
+ self._clearstamp(stampid)
+ self._update()
+
+ def clearstamps(self, n=None):
+ """Delete all or first/last n of turtle's stamps.
+
+ Optional argument:
+ n -- an integer
+
+ If n is None, delete all of pen's stamps,
+ else if n > 0 delete first n stamps
+ else if n < 0 delete last n stamps.
+
+ Example (for a Turtle instance named turtle):
+ >>> for i in range(8):
+ ... turtle.stamp(); turtle.fd(30)
+ ...
+ >>> turtle.clearstamps(2)
+ >>> turtle.clearstamps(-2)
+ >>> turtle.clearstamps()
+ """
+ if n is None:
+ toDelete = self.stampItems[:]
+ elif n >= 0:
+ toDelete = self.stampItems[:n]
+ else:
+ toDelete = self.stampItems[n:]
+ for item in toDelete:
+ self._clearstamp(item)
+ self._update()
+
+ def _goto(self, end):
+ """Move the pen to the point end, thereby drawing a line
+ if pen is down. All other methods for turtle movement depend
+ on this one.
+ """
+ ## Version with undo-stuff
+ go_modes = ( self._drawing,
+ self._pencolor,
+ self._pensize,
+ isinstance(self._fillpath, list))
+ screen = self.screen
+ undo_entry = ("go", self._position, end, go_modes,
+ (self.currentLineItem,
+ self.currentLine[:],
+ screen._pointlist(self.currentLineItem),
+ self.items[:])
+ )
+ if self.undobuffer:
+ self.undobuffer.push(undo_entry)
+ start = self._position
+ if self._speed and screen._tracing == 1:
+ diff = (end-start)
+ diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
+ nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
+ delta = diff * (1.0/nhops)
+ for n in range(1, nhops):
+ if n == 1:
+ top = True
+ else:
+ top = False
+ self._position = start + delta * n
+ if self._drawing:
+ screen._drawline(self.drawingLineItem,
+ (start, self._position),
+ self._pencolor, self._pensize, top)
+ self._update()
+ if self._drawing:
+ screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
+ fill="", width=self._pensize)
+ # Turtle now at end,
+ if self._drawing: # now update currentLine
+ self.currentLine.append(end)
+ if isinstance(self._fillpath, list):
+ self._fillpath.append(end)
+ ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
+ self._position = end
+ if self._creatingPoly:
+ self._poly.append(end)
+ if len(self.currentLine) > 42: # 42! answer to the ultimate question
+ # of life, the universe and everything
+ self._newLine()
+ self._update() #count=True)
+
+ def _undogoto(self, entry):
+ """Reverse a _goto. Used for undo()
+ """
+ old, new, go_modes, coodata = entry
+ drawing, pc, ps, filling = go_modes
+ cLI, cL, pl, items = coodata
+ screen = self.screen
+ if abs(self._position - new) > 0.5:
+ print ("undogoto: HALLO-DA-STIMMT-WAS-NICHT!")
+ # restore former situation
+ self.currentLineItem = cLI
+ self.currentLine = cL
+
+ if pl == [(0, 0), (0, 0)]:
+ usepc = ""
+ else:
+ usepc = pc
+ screen._drawline(cLI, pl, fill=usepc, width=ps)
+
+ todelete = [i for i in self.items if (i not in items) and
+ (screen._type(i) == "line")]
+ for i in todelete:
+ screen._delete(i)
+ self.items.remove(i)
+
+ start = old
+ if self._speed and screen._tracing == 1:
+ diff = old - new
+ diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
+ nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
+ delta = diff * (1.0/nhops)
+ for n in range(1, nhops):
+ if n == 1:
+ top = True
+ else:
+ top = False
+ self._position = new + delta * n
+ if drawing:
+ screen._drawline(self.drawingLineItem,
+ (start, self._position),
+ pc, ps, top)
+ self._update()
+ if drawing:
+ screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
+ fill="", width=ps)
+ # Turtle now at position old,
+ self._position = old
+ ## if undo is done during creating a polygon, the last vertex
+ ## will be deleted. if the polygon is entirely deleted,
+ ## creatingPoly will be set to False.
+ ## Polygons created before the last one will not be affected by undo()
+ if self._creatingPoly:
+ if len(self._poly) > 0:
+ self._poly.pop()
+ if self._poly == []:
+ self._creatingPoly = False
+ self._poly = None
+ if filling:
+ if self._fillpath == []:
+ self._fillpath = None
+ print("Unwahrscheinlich in _undogoto!")
+ elif self._fillpath is not None:
+ self._fillpath.pop()
+ self._update() #count=True)
+
+ def _rotate(self, angle):
+ """Turns pen clockwise by angle.
+ """
+ if self.undobuffer:
+ self.undobuffer.push(("rot", angle, self._degreesPerAU))
+ angle *= self._degreesPerAU
+ neworient = self._orient.rotate(angle)
+ tracing = self.screen._tracing
+ if tracing == 1 and self._speed > 0:
+ anglevel = 3.0 * self._speed
+ steps = 1 + int(abs(angle)/anglevel)
+ delta = 1.0*angle/steps
+ for _ in range(steps):
+ self._orient = self._orient.rotate(delta)
+ self._update()
+ self._orient = neworient
+ self._update()
+
+ def _newLine(self, usePos=True):
+ """Closes current line item and starts a new one.
+ Remark: if current line became too long, animation
+ performance (via _drawline) slowed down considerably.
+ """
+ if len(self.currentLine) > 1:
+ self.screen._drawline(self.currentLineItem, self.currentLine,
+ self._pencolor, self._pensize)
+ self.currentLineItem = self.screen._createline()
+ self.items.append(self.currentLineItem)
+ else:
+ self.screen._drawline(self.currentLineItem, top=True)
+ self.currentLine = []
+ if usePos:
+ self.currentLine = [self._position]
+
+ def filling(self):
+ """Return fillstate (True if filling, False else).
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.begin_fill()
+ >>> if turtle.filling():
+ ... turtle.pensize(5)
+ ... else:
+ ... turtle.pensize(3)
+ """
+ return isinstance(self._fillpath, list)
+
+ def begin_fill(self):
+ """Called just before drawing a shape to be filled.
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.color("black", "red")
+ >>> turtle.begin_fill()
+ >>> turtle.circle(60)
+ >>> turtle.end_fill()
+ """
+ if not self.filling():
+ self._fillitem = self.screen._createpoly()
+ self.items.append(self._fillitem)
+ self._fillpath = [self._position]
+ self._newLine()
+ if self.undobuffer:
+ self.undobuffer.push(("beginfill", self._fillitem))
+ self._update()
+
+
+ def end_fill(self):
+ """Fill the shape drawn after the call begin_fill().
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.color("black", "red")
+ >>> turtle.begin_fill()
+ >>> turtle.circle(60)
+ >>> turtle.end_fill()
+ """
+ if self.filling():
+ if len(self._fillpath) > 2:
+ self.screen._drawpoly(self._fillitem, self._fillpath,
+ fill=self._fillcolor)
+ if self.undobuffer:
+ self.undobuffer.push(("dofill", self._fillitem))
+ self._fillitem = self._fillpath = None
+ self._update()
+
+ def dot(self, size=None, *color):
+ """Draw a dot with diameter size, using color.
+
+ Optional arguments:
+ size -- an integer >= 1 (if given)
+ color -- a colorstring or a numeric color tuple
+
+ Draw a circular dot with diameter size, using color.
+ If size is not given, the maximum of pensize+4 and 2*pensize is used.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.dot()
+ >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
+ """
+ if not color:
+ if isinstance(size, (str, tuple)):
+ color = self._colorstr(size)
+ size = self._pensize + max(self._pensize, 4)
+ else:
+ color = self._pencolor
+ if not size:
+ size = self._pensize + max(self._pensize, 4)
+ else:
+ if size is None:
+ size = self._pensize + max(self._pensize, 4)
+ color = self._colorstr(color)
+ if hasattr(self.screen, "_dot"):
+ item = self.screen._dot(self._position, size, color)
+ self.items.append(item)
+ if self.undobuffer:
+ self.undobuffer.push(("dot", item))
+ else:
+ pen = self.pen()
+ if self.undobuffer:
+ self.undobuffer.push(["seq"])
+ self.undobuffer.cumulate = True
+ try:
+ if self.resizemode() == 'auto':
+ self.ht()
+ self.pendown()
+ self.pensize(size)
+ self.pencolor(color)
+ self.forward(0)
+ finally:
+ self.pen(pen)
+ if self.undobuffer:
+ self.undobuffer.cumulate = False
+
+ def _write(self, txt, align, font):
+ """Performs the writing for write()
+ """
+ item, end = self.screen._write(self._position, txt, align, font,
+ self._pencolor)
+ self.items.append(item)
+ if self.undobuffer:
+ self.undobuffer.push(("wri", item))
+ return end
+
+ def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
+ """Write text at the current turtle position.
+
+ Arguments:
+ arg -- info, which is to be written to the TurtleScreen
+ move (optional) -- True/False
+ align (optional) -- one of the strings "left", "center" or right"
+ font (optional) -- a triple (fontname, fontsize, fonttype)
+
+ Write text - the string representation of arg - at the current
+ turtle position according to align ("left", "center" or right")
+ and with the given font.
+ If move is True, the pen is moved to the bottom-right corner
+ of the text. By default, move is False.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.write('Home = ', True, align="center")
+ >>> turtle.write((0,0), True)
+ """
+ if self.undobuffer:
+ self.undobuffer.push(["seq"])
+ self.undobuffer.cumulate = True
+ end = self._write(str(arg), align.lower(), font)
+ if move:
+ x, y = self.pos()
+ self.setpos(end, y)
+ if self.undobuffer:
+ self.undobuffer.cumulate = False
+
+ def begin_poly(self):
+ """Start recording the vertices of a polygon.
+
+ No argument.
+
+ Start recording the vertices of a polygon. Current turtle position
+ is first point of polygon.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.begin_poly()
+ """
+ self._poly = [self._position]
+ self._creatingPoly = True
+
+ def end_poly(self):
+ """Stop recording the vertices of a polygon.
+
+ No argument.
+
+ Stop recording the vertices of a polygon. Current turtle position is
+ last point of polygon. This will be connected with the first point.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.end_poly()
+ """
+ self._creatingPoly = False
+
+ def get_poly(self):
+ """Return the lastly recorded polygon.
+
+ No argument.
+
+ Example (for a Turtle instance named turtle):
+ >>> p = turtle.get_poly()
+ >>> turtle.register_shape("myFavouriteShape", p)
+ """
+ ## check if there is any poly?
+ if self._poly is not None:
+ return tuple(self._poly)
+
+ def getscreen(self):
+ """Return the TurtleScreen object, the turtle is drawing on.
+
+ No argument.
+
+ Return the TurtleScreen object, the turtle is drawing on.
+ So TurtleScreen-methods can be called for that object.
+
+ Example (for a Turtle instance named turtle):
+ >>> ts = turtle.getscreen()
+ >>> ts
+ <turtle.TurtleScreen object at 0x0106B770>
+ >>> ts.bgcolor("pink")
+ """
+ return self.screen
+
+ def getturtle(self):
+ """Return the Turtleobject itself.
+
+ No argument.
+
+ Only reasonable use: as a function to return the 'anonymous turtle':
+
+ Example:
+ >>> pet = getturtle()
+ >>> pet.fd(50)
+ >>> pet
+ <turtle.Turtle object at 0x0187D810>
+ >>> turtles()
+ [<turtle.Turtle object at 0x0187D810>]
+ """
+ return self
+
+ getpen = getturtle
+
+
+ ################################################################
+ ### screen oriented methods recurring to methods of TurtleScreen
+ ################################################################
+
+ def _delay(self, delay=None):
+ """Set delay value which determines speed of turtle animation.
+ """
+ return self.screen.delay(delay)
+
+ def onclick(self, fun, btn=1, add=None):
+ """Bind fun to mouse-click event on this turtle on canvas.
+
+ Arguments:
+ fun -- a function with two arguments, to which will be assigned
+ the coordinates of the clicked point on the canvas.
+ btn -- number of the mouse-button defaults to 1 (left mouse button).
+ add -- True or False. If True, new binding will be added, otherwise
+ it will replace a former binding.
+
+ Example for the anonymous turtle, i. e. the procedural way:
+
+ >>> def turn(x, y):
+ ... left(360)
+ ...
+ >>> onclick(turn) # Now clicking into the turtle will turn it.
+ >>> onclick(None) # event-binding will be removed
+ """
+ self.screen._onclick(self.turtle._item, fun, btn, add)
+ self._update()
+
+ def onrelease(self, fun, btn=1, add=None):
+ """Bind fun to mouse-button-release event on this turtle on canvas.
+
+ Arguments:
+ fun -- a function with two arguments, to which will be assigned
+ the coordinates of the clicked point on the canvas.
+ btn -- number of the mouse-button defaults to 1 (left mouse button).
+
+ Example (for a MyTurtle instance named joe):
+ >>> class MyTurtle(Turtle):
+ ... def glow(self,x,y):
+ ... self.fillcolor("red")
+ ... def unglow(self,x,y):
+ ... self.fillcolor("")
+ ...
+ >>> joe = MyTurtle()
+ >>> joe.onclick(joe.glow)
+ >>> joe.onrelease(joe.unglow)
+
+ Clicking on joe turns fillcolor red, unclicking turns it to
+ transparent.
+ """
+ self.screen._onrelease(self.turtle._item, fun, btn, add)
+ self._update()
+
+ def ondrag(self, fun, btn=1, add=None):
+ """Bind fun to mouse-move event on this turtle on canvas.
+
+ Arguments:
+ fun -- a function with two arguments, to which will be assigned
+ the coordinates of the clicked point on the canvas.
+ btn -- number of the mouse-button defaults to 1 (left mouse button).
+
+ Every sequence of mouse-move-events on a turtle is preceded by a
+ mouse-click event on that turtle.
+
+ Example (for a Turtle instance named turtle):
+ >>> turtle.ondrag(turtle.goto)
+
+ Subsequently clicking and dragging a Turtle will move it
+ across the screen thereby producing handdrawings (if pen is
+ down).
+ """
+ self.screen._ondrag(self.turtle._item, fun, btn, add)
+
+
+ def _undo(self, action, data):
+ """Does the main part of the work for undo()
+ """
+ if self.undobuffer is None:
+ return
+ if action == "rot":
+ angle, degPAU = data
+ self._rotate(-angle*degPAU/self._degreesPerAU)
+ dummy = self.undobuffer.pop()
+ elif action == "stamp":
+ stitem = data[0]
+ self.clearstamp(stitem)
+ elif action == "go":
+ self._undogoto(data)
+ elif action in ["wri", "dot"]:
+ item = data[0]
+ self.screen._delete(item)
+ self.items.remove(item)
+ elif action == "dofill":
+ item = data[0]
+ self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
+ fill="", outline="")
+ elif action == "beginfill":
+ item = data[0]
+ self._fillitem = self._fillpath = None
+ if item in self.items:
+ self.screen._delete(item)
+ self.items.remove(item)
+ elif action == "pen":
+ TPen.pen(self, data[0])
+ self.undobuffer.pop()
+
+ def undo(self):
+ """undo (repeatedly) the last turtle action.
+
+ No argument.
+
+ undo (repeatedly) the last turtle action.
+ Number of available undo actions is determined by the size of
+ the undobuffer.
+
+ Example (for a Turtle instance named turtle):
+ >>> for i in range(4):
+ ... turtle.fd(50); turtle.lt(80)
+ ...
+ >>> for i in range(8):
+ ... turtle.undo()
+ ...
+ """
+ if self.undobuffer is None:
+ return
+ item = self.undobuffer.pop()
+ action = item[0]
+ data = item[1:]
+ if action == "seq":
+ while data:
+ item = data.pop()
+ self._undo(item[0], item[1:])
+ else:
+ self._undo(action, data)
+
+ turtlesize = shapesize
+
+RawPen = RawTurtle
+
+### Screen - Singleton ########################
+
+def Screen():
+ """Return the singleton screen object.
+ If none exists at the moment, create a new one and return it,
+ else return the existing one."""
+ if Turtle._screen is None:
+ Turtle._screen = _Screen()
+ return Turtle._screen
+
+class _Screen(TurtleScreen):
+
+ _root = None
+ _canvas = None
+ _title = _CFG["title"]
+
+ def __init__(self):
+ # XXX there is no need for this code to be conditional,
+ # as there will be only a single _Screen instance, anyway
+ # XXX actually, the turtle demo is injecting root window,
+ # so perhaps the conditional creation of a root should be
+ # preserved (perhaps by passing it as an optional parameter)
+ if _Screen._root is None:
+ _Screen._root = self._root = _Root()
+ self._root.title(_Screen._title)
+ self._root.ondestroy(self._destroy)
+ if _Screen._canvas is None:
+ width = _CFG["width"]
+ height = _CFG["height"]
+ canvwidth = _CFG["canvwidth"]
+ canvheight = _CFG["canvheight"]
+ leftright = _CFG["leftright"]
+ topbottom = _CFG["topbottom"]
+ self._root.setupcanvas(width, height, canvwidth, canvheight)
+ _Screen._canvas = self._root._getcanvas()
+ TurtleScreen.__init__(self, _Screen._canvas)
+ self.setup(width, height, leftright, topbottom)
+
+ def setup(self, width=_CFG["width"], height=_CFG["height"],
+ startx=_CFG["leftright"], starty=_CFG["topbottom"]):
+ """ Set the size and position of the main window.
+
+ Arguments:
+ width: as integer a size in pixels, as float a fraction of the screen.
+ Default is 50% of screen.
+ height: as integer the height in pixels, as float a fraction of the
+ screen. Default is 75% of screen.
+ startx: if positive, starting position in pixels from the left
+ edge of the screen, if negative from the right edge
+ Default, startx=None is to center window horizontally.
+ starty: if positive, starting position in pixels from the top
+ edge of the screen, if negative from the bottom edge
+ Default, starty=None is to center window vertically.
+
+ Examples (for a Screen instance named screen):
+ >>> screen.setup (width=200, height=200, startx=0, starty=0)
+
+ sets window to 200x200 pixels, in upper left of screen
+
+ >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
+
+ sets window to 75% of screen by 50% of screen and centers
+ """
+ if not hasattr(self._root, "set_geometry"):
+ return
+ sw = self._root.win_width()
+ sh = self._root.win_height()
+ if isinstance(width, float) and 0 <= width <= 1:
+ width = sw*width
+ if startx is None:
+ startx = (sw - width) / 2
+ if isinstance(height, float) and 0 <= height <= 1:
+ height = sh*height
+ if starty is None:
+ starty = (sh - height) / 2
+ self._root.set_geometry(width, height, startx, starty)
+ self.update()
+
+ def title(self, titlestring):
+ """Set title of turtle-window
+
+ Argument:
+ titlestring -- a string, to appear in the titlebar of the
+ turtle graphics window.
+
+ This is a method of Screen-class. Not available for TurtleScreen-
+ objects.
+
+ Example (for a Screen instance named screen):
+ >>> screen.title("Welcome to the turtle-zoo!")
+ """
+ if _Screen._root is not None:
+ _Screen._root.title(titlestring)
+ _Screen._title = titlestring
+
+ def _destroy(self):
+ root = self._root
+ if root is _Screen._root:
+ Turtle._pen = None
+ Turtle._screen = None
+ _Screen._root = None
+ _Screen._canvas = None
+ TurtleScreen._RUNNING = False
+ root.destroy()
+
+ def bye(self):
+ """Shut the turtlegraphics window.
+
+ Example (for a TurtleScreen instance named screen):
+ >>> screen.bye()
+ """
+ self._destroy()
+
+ def exitonclick(self):
+ """Go into mainloop until the mouse is clicked.
+
+ No arguments.
+
+ Bind bye() method to mouseclick on TurtleScreen.
+ If "using_IDLE" - value in configuration dictionary is False
+ (default value), enter mainloop.
+ If IDLE with -n switch (no subprocess) is used, this value should be
+ set to True in turtle.cfg. In this case IDLE's mainloop
+ is active also for the client script.
+
+ This is a method of the Screen-class and not available for
+ TurtleScreen instances.
+
+ Example (for a Screen instance named screen):
+ >>> screen.exitonclick()
+
+ """
+ def exitGracefully(x, y):
+ """Screen.bye() with two dummy-parameters"""
+ self.bye()
+ self.onclick(exitGracefully)
+ if _CFG["using_IDLE"]:
+ return
+ try:
+ mainloop()
+ except AttributeError:
+ exit(0)
+
+class Turtle(RawTurtle):
+ """RawTurtle auto-creating (scrolled) canvas.
+
+ When a Turtle object is created or a function derived from some
+ Turtle method is called a TurtleScreen object is automatically created.
+ """
+ _pen = None
+ _screen = None
+
+ def __init__(self,
+ shape=_CFG["shape"],
+ undobuffersize=_CFG["undobuffersize"],
+ visible=_CFG["visible"]):
+ if Turtle._screen is None:
+ Turtle._screen = Screen()
+ RawTurtle.__init__(self, Turtle._screen,
+ shape=shape,
+ undobuffersize=undobuffersize,
+ visible=visible)
+
+Pen = Turtle
+
+def write_docstringdict(filename="turtle_docstringdict"):
+ """Create and write docstring-dictionary to file.
+
+ Optional argument:
+ filename -- a string, used as filename
+ default value is turtle_docstringdict
+
+ Has to be called explicitly, (not used by the turtle-graphics classes)
+ The docstring dictionary will be written to the Python script <filname>.py
+ It is intended to serve as a template for translation of the docstrings
+ into different languages.
+ """
+ docsdict = {}
+
+ for methodname in _tg_screen_functions:
+ key = "_Screen."+methodname
+ docsdict[key] = eval(key).__doc__
+ for methodname in _tg_turtle_functions:
+ key = "Turtle."+methodname
+ docsdict[key] = eval(key).__doc__
+
+ with open("%s.py" % filename,"w") as f:
+ keys = sorted(x for x in docsdict
+ if x.split('.')[1] not in _alias_list)
+ f.write('docsdict = {\n\n')
+ for key in keys[:-1]:
+ f.write('%s :\n' % repr(key))
+ f.write(' """%s\n""",\n\n' % docsdict[key])
+ key = keys[-1]
+ f.write('%s :\n' % repr(key))
+ f.write(' """%s\n"""\n\n' % docsdict[key])
+ f.write("}\n")
+ f.close()
+
+def read_docstrings(lang):
+ """Read in docstrings from lang-specific docstring dictionary.
+
+ Transfer docstrings, translated to lang, from a dictionary-file
+ to the methods of classes Screen and Turtle and - in revised form -
+ to the corresponding functions.
+ """
+ modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
+ module = __import__(modname)
+ docsdict = module.docsdict
+ for key in docsdict:
+ try:
+# eval(key).im_func.__doc__ = docsdict[key]
+ eval(key).__doc__ = docsdict[key]
+ except Exception:
+ print("Bad docstring-entry: %s" % key)
+
+_LANGUAGE = _CFG["language"]
+
+try:
+ if _LANGUAGE != "english":
+ read_docstrings(_LANGUAGE)
+except ImportError:
+ print("Cannot find docsdict for", _LANGUAGE)
+except Exception:
+ print ("Unknown Error when trying to import %s-docstring-dictionary" %
+ _LANGUAGE)
+
+
+def getmethparlist(ob):
+ """Get strings describing the arguments for the given object
+
+ Returns a pair of strings representing function parameter lists
+ including parenthesis. The first string is suitable for use in
+ function definition and the second is suitable for use in function
+ call. The "self" parameter is not included.
+ """
+ defText = callText = ""
+ # bit of a hack for methods - turn it into a function
+ # but we drop the "self" param.
+ # Try and build one for Python defined functions
+ args, varargs, varkw = inspect.getargs(ob.__code__)
+ items2 = args[1:]
+ realArgs = args[1:]
+ defaults = ob.__defaults__ or []
+ defaults = ["=%r" % (value,) for value in defaults]
+ defaults = [""] * (len(realArgs)-len(defaults)) + defaults
+ items1 = [arg + dflt for arg, dflt in zip(realArgs, defaults)]
+ if varargs is not None:
+ items1.append("*" + varargs)
+ items2.append("*" + varargs)
+ if varkw is not None:
+ items1.append("**" + varkw)
+ items2.append("**" + varkw)
+ defText = ", ".join(items1)
+ defText = "(%s)" % defText
+ callText = ", ".join(items2)
+ callText = "(%s)" % callText
+ return defText, callText
+
+def _turtle_docrevise(docstr):
+ """To reduce docstrings from RawTurtle class for functions
+ """
+ import re
+ if docstr is None:
+ return None
+ turtlename = _CFG["exampleturtle"]
+ newdocstr = docstr.replace("%s." % turtlename,"")
+ parexp = re.compile(r' \(.+ %s\):' % turtlename)
+ newdocstr = parexp.sub(":", newdocstr)
+ return newdocstr
+
+def _screen_docrevise(docstr):
+ """To reduce docstrings from TurtleScreen class for functions
+ """
+ import re
+ if docstr is None:
+ return None
+ screenname = _CFG["examplescreen"]
+ newdocstr = docstr.replace("%s." % screenname,"")
+ parexp = re.compile(r' \(.+ %s\):' % screenname)
+ newdocstr = parexp.sub(":", newdocstr)
+ return newdocstr
+
+## The following mechanism makes all methods of RawTurtle and Turtle available
+## as functions. So we can enhance, change, add, delete methods to these
+## classes and do not need to change anything here.
+
+__func_body = """\
+def {name}{paramslist}:
+ if {obj} is None:
+ if not TurtleScreen._RUNNING:
+ TurtleScreen._RUNNING = True
+ raise Terminator
+ {obj} = {init}
+ try:
+ return {obj}.{name}{argslist}
+ except TK.TclError:
+ if not TurtleScreen._RUNNING:
+ TurtleScreen._RUNNING = True
+ raise Terminator
+ raise
+"""
+
+def _make_global_funcs(functions, cls, obj, init, docrevise):
+ for methodname in functions:
+ method = getattr(cls, methodname)
+ pl1, pl2 = getmethparlist(method)
+ if pl1 == "":
+ print(">>>>>>", pl1, pl2)
+ continue
+ defstr = __func_body.format(obj=obj, init=init, name=methodname,
+ paramslist=pl1, argslist=pl2)
+ exec(defstr, globals())
+ globals()[methodname].__doc__ = docrevise(method.__doc__)
+
+_make_global_funcs(_tg_screen_functions, _Screen,
+ 'Turtle._screen', 'Screen()', _screen_docrevise)
+_make_global_funcs(_tg_turtle_functions, Turtle,
+ 'Turtle._pen', 'Turtle()', _turtle_docrevise)
+
+
+done = mainloop
+
+if __name__ == "__main__":
+ def switchpen():
+ if isdown():
+ pu()
+ else:
+ pd()
+
+ def demo1():
+ """Demo of old turtle.py - module"""
+ reset()
+ tracer(True)
+ up()
+ backward(100)
+ down()
+ # draw 3 squares; the last filled
+ width(3)
+ for i in range(3):
+ if i == 2:
+ begin_fill()
+ for _ in range(4):
+ forward(20)
+ left(90)
+ if i == 2:
+ color("maroon")
+ end_fill()
+ up()
+ forward(30)
+ down()
+ width(1)
+ color("black")
+ # move out of the way
+ tracer(False)
+ up()
+ right(90)
+ forward(100)
+ right(90)
+ forward(100)
+ right(180)
+ down()
+ # some text
+ write("startstart", 1)
+ write("start", 1)
+ color("red")
+ # staircase
+ for i in range(5):
+ forward(20)
+ left(90)
+ forward(20)
+ right(90)
+ # filled staircase
+ tracer(True)
+ begin_fill()
+ for i in range(5):
+ forward(20)
+ left(90)
+ forward(20)
+ right(90)
+ end_fill()
+ # more text
+
+ def demo2():
+ """Demo of some new features."""
+ speed(1)
+ st()
+ pensize(3)
+ setheading(towards(0, 0))
+ radius = distance(0, 0)/2.0
+ rt(90)
+ for _ in range(18):
+ switchpen()
+ circle(radius, 10)
+ write("wait a moment...")
+ while undobufferentries():
+ undo()
+ reset()
+ lt(90)
+ colormode(255)
+ laenge = 10
+ pencolor("green")
+ pensize(3)
+ lt(180)
+ for i in range(-2, 16):
+ if i > 0:
+ begin_fill()
+ fillcolor(255-15*i, 0, 15*i)
+ for _ in range(3):
+ fd(laenge)
+ lt(120)
+ end_fill()
+ laenge += 10
+ lt(15)
+ speed((speed()+1)%12)
+ #end_fill()
+
+ lt(120)
+ pu()
+ fd(70)
+ rt(30)
+ pd()
+ color("red","yellow")
+ speed(0)
+ begin_fill()
+ for _ in range(4):
+ circle(50, 90)
+ rt(90)
+ fd(30)
+ rt(90)
+ end_fill()
+ lt(90)
+ pu()
+ fd(30)
+ pd()
+ shape("turtle")
+
+ tri = getturtle()
+ tri.resizemode("auto")
+ turtle = Turtle()
+ turtle.resizemode("auto")
+ turtle.shape("turtle")
+ turtle.reset()
+ turtle.left(90)
+ turtle.speed(0)
+ turtle.up()
+ turtle.goto(280, 40)
+ turtle.lt(30)
+ turtle.down()
+ turtle.speed(6)
+ turtle.color("blue","orange")
+ turtle.pensize(2)
+ tri.speed(6)
+ setheading(towards(turtle))
+ count = 1
+ while tri.distance(turtle) > 4:
+ turtle.fd(3.5)
+ turtle.lt(0.6)
+ tri.setheading(tri.towards(turtle))
+ tri.fd(4)
+ if count % 20 == 0:
+ turtle.stamp()
+ tri.stamp()
+ switchpen()
+ count += 1
+ tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
+ tri.pencolor("black")
+ tri.pencolor("red")
+
+ def baba(xdummy, ydummy):
+ clearscreen()
+ bye()
+
+ time.sleep(2)
+
+ while undobufferentries():
+ tri.undo()
+ turtle.undo()
+ tri.fd(50)
+ tri.write(" Click me!", font = ("Courier", 12, "bold") )
+ tri.onclick(baba, 1)
+
+ demo1()
+ demo2()
+ exitonclick()