blob: 599f645fd0ca6d5d93e88a20b1201b41bbf10e41 [file] [log] [blame]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001#
2# turtle.py: a Tkinter based turtle graphics module for Python
Georg Brandleaa84ef2009-05-05 08:14:33 +00003# Version 1.1b - 4. 5. 2009
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004#
Benjamin Peterson46a99002010-01-09 18:45:30 +00005# Copyright (C) 2006 - 2010 Gregor Lingl
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00006# email: glingl@aon.at
7#
8# This software is provided 'as-is', without any express or implied
9# warranty. In no event will the authors be held liable for any damages
10# arising from the use of this software.
11#
12# Permission is granted to anyone to use this software for any purpose,
13# including commercial applications, and to alter it and redistribute it
14# freely, subject to the following restrictions:
15#
16# 1. The origin of this software must not be misrepresented; you must not
17# claim that you wrote the original software. If you use this software
18# in a product, an acknowledgment in the product documentation would be
19# appreciated but is not required.
20# 2. Altered source versions must be plainly marked as such, and must not be
21# misrepresented as being the original software.
22# 3. This notice may not be removed or altered from any source distribution.
23
Guido van Rossumb241b671998-12-04 16:42:46 +000024
Thomas Wouters477c8d52006-05-27 19:21:47 +000025"""
26Turtle graphics is a popular way for introducing programming to
27kids. It was part of the original Logo programming language developed
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000028by Wally Feurzig and Seymour Papert in 1966.
Thomas Wouters477c8d52006-05-27 19:21:47 +000029
Sandro Tosi2a389e42011-08-07 17:12:19 +020030Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
Thomas Wouters477c8d52006-05-27 19:21:47 +000031the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
32the direction it is facing, drawing a line as it moves. Give it the
Sandro Tosi2a389e42011-08-07 17:12:19 +020033command turtle.right(25), and it rotates in-place 25 degrees clockwise.
Thomas Wouters477c8d52006-05-27 19:21:47 +000034
35By combining together these and similar commands, intricate shapes and
36pictures can easily be drawn.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000037
38----- turtle.py
39
40This module is an extended reimplementation of turtle.py from the
Mark Dickinsonf8798f52009-02-20 20:53:56 +000041Python standard distribution up to Python 2.5. (See: http://www.python.org)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000042
43It tries to keep the merits of turtle.py and to be (nearly) 100%
44compatible with it. This means in the first place to enable the
45learning programmer to use all the commands, classes and methods
46interactively when using the module from within IDLE run with
47the -n switch.
48
49Roughly it has the following features added:
50
51- Better animation of the turtle movements, especially of turning the
52 turtle. So the turtles can more easily be used as a visual feedback
53 instrument by the (beginning) programmer.
54
55- Different turtle shapes, gif-images as turtle shapes, user defined
56 and user controllable turtle shapes, among them compound
Mark Dickinsonf8798f52009-02-20 20:53:56 +000057 (multicolored) shapes. Turtle shapes can be stretched and tilted, which
Mark Dickinson0fc61cc2009-02-20 20:50:21 +000058 makes turtles very versatile geometrical objects.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000059
60- Fine control over turtle movement and screen updates via delay(),
61 and enhanced tracer() and speed() methods.
62
63- Aliases for the most commonly used commands, like fd for forward etc.,
64 following the early Logo traditions. This reduces the boring work of
65 typing long sequences of commands, which often occur in a natural way
66 when kids try to program fancy pictures on their first encounter with
Mark Dickinsonf8798f52009-02-20 20:53:56 +000067 turtle graphics.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000068
69- Turtles now have an undo()-method with configurable undo-buffer.
70
71- Some simple commands/methods for creating event driven programs
72 (mouse-, key-, timer-events). Especially useful for programming games.
73
74- A scrollable Canvas class. The default scrollable Canvas can be
75 extended interactively as needed while playing around with the turtle(s).
76
77- A TurtleScreen class with methods controlling background color or
78 background image, window and canvas size and other properties of the
79 TurtleScreen.
80
81- There is a method, setworldcoordinates(), to install a user defined
82 coordinate-system for the TurtleScreen.
83
84- The implementation uses a 2-vector class named Vec2D, derived from tuple.
85 This class is public, so it can be imported by the application programmer,
86 which makes certain types of computations very natural and compact.
87
88- Appearance of the TurtleScreen and the Turtles at startup/import can be
89 configured by means of a turtle.cfg configuration file.
90 The default configuration mimics the appearance of the old turtle module.
91
92- If configured appropriately the module reads in docstrings from a docstring
93 dictionary in some different language, supplied separately and replaces
Mark Dickinsonf8798f52009-02-20 20:53:56 +000094 the English ones by those read in. There is a utility function
95 write_docstringdict() to write a dictionary with the original (English)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +000096 docstrings to disc, so it can serve as a template for translations.
97
98Behind the scenes there are some features included with possible
Ezio Melottie130a522011-10-19 10:58:56 +030099extensions in mind. These will be commented and documented elsewhere.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000100
Thomas Wouters477c8d52006-05-27 19:21:47 +0000101"""
102
Georg Brandleaa84ef2009-05-05 08:14:33 +0000103_ver = "turtle 1.1b- - for Python 3.1 - 4. 5. 2009"
Guido van Rossumfd2ede22002-09-23 16:55:05 +0000104
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000105# print(_ver)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000106
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000107import tkinter as TK
108import types
109import math
110import time
Alexander Belopolskyc1a68362010-10-27 13:25:45 +0000111import inspect
Ned Deily09ae5442014-04-19 19:11:14 -0700112import sys
Guido van Rossumb241b671998-12-04 16:42:46 +0000113
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000114from os.path import isfile, split, join
115from copy import deepcopy
Georg Brandleaa84ef2009-05-05 08:14:33 +0000116from tkinter import simpledialog
Guido van Rossumb241b671998-12-04 16:42:46 +0000117
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000118_tg_classes = ['ScrolledCanvas', 'TurtleScreen', 'Screen',
119 'RawTurtle', 'Turtle', 'RawPen', 'Pen', 'Shape', 'Vec2D']
120_tg_screen_functions = ['addshape', 'bgcolor', 'bgpic', 'bye',
121 'clearscreen', 'colormode', 'delay', 'exitonclick', 'getcanvas',
Georg Brandleaa84ef2009-05-05 08:14:33 +0000122 'getshapes', 'listen', 'mainloop', 'mode', 'numinput',
123 'onkey', 'onkeypress', 'onkeyrelease', 'onscreenclick', 'ontimer',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000124 'register_shape', 'resetscreen', 'screensize', 'setup',
Georg Brandleaa84ef2009-05-05 08:14:33 +0000125 'setworldcoordinates', 'textinput', 'title', 'tracer', 'turtles', 'update',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000126 'window_height', 'window_width']
127_tg_turtle_functions = ['back', 'backward', 'begin_fill', 'begin_poly', 'bk',
128 'circle', 'clear', 'clearstamp', 'clearstamps', 'clone', 'color',
129 'degrees', 'distance', 'dot', 'down', 'end_fill', 'end_poly', 'fd',
Georg Brandl46afef32009-10-14 18:46:15 +0000130 'fillcolor', 'filling', 'forward', 'get_poly', 'getpen', 'getscreen', 'get_shapepoly',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000131 'getturtle', 'goto', 'heading', 'hideturtle', 'home', 'ht', 'isdown',
132 'isvisible', 'left', 'lt', 'onclick', 'ondrag', 'onrelease', 'pd',
133 'pen', 'pencolor', 'pendown', 'pensize', 'penup', 'pos', 'position',
134 'pu', 'radians', 'right', 'reset', 'resizemode', 'rt',
135 'seth', 'setheading', 'setpos', 'setposition', 'settiltangle',
Georg Brandleaa84ef2009-05-05 08:14:33 +0000136 'setundobuffer', 'setx', 'sety', 'shape', 'shapesize', 'shapetransform', 'shearfactor', 'showturtle',
137 'speed', 'st', 'stamp', 'tilt', 'tiltangle', 'towards',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000138 'turtlesize', 'undo', 'undobufferentries', 'up', 'width',
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000139 'write', 'xcor', 'ycor']
Georg Brandleaa84ef2009-05-05 08:14:33 +0000140_tg_utilities = ['write_docstringdict', 'done']
Thomas Wouters477c8d52006-05-27 19:21:47 +0000141
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000142__all__ = (_tg_classes + _tg_screen_functions + _tg_turtle_functions +
143 _tg_utilities) # + _math_functions)
Guido van Rossumb241b671998-12-04 16:42:46 +0000144
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000145_alias_list = ['addshape', 'backward', 'bk', 'fd', 'ht', 'lt', 'pd', 'pos',
146 'pu', 'rt', 'seth', 'setpos', 'setposition', 'st',
147 'turtlesize', 'up', 'width']
Thomas Wouters477c8d52006-05-27 19:21:47 +0000148
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000149_CFG = {"width" : 0.5, # Screen
150 "height" : 0.75,
151 "canvwidth" : 400,
152 "canvheight": 300,
153 "leftright": None,
154 "topbottom": None,
155 "mode": "standard", # TurtleScreen
156 "colormode": 1.0,
157 "delay": 10,
158 "undobuffersize": 1000, # RawTurtle
159 "shape": "classic",
160 "pencolor" : "black",
161 "fillcolor" : "black",
162 "resizemode" : "noresize",
163 "visible" : True,
164 "language": "english", # docstrings
165 "exampleturtle": "turtle",
166 "examplescreen": "screen",
167 "title": "Python Turtle Graphics",
168 "using_IDLE": False
169 }
Guido van Rossumb241b671998-12-04 16:42:46 +0000170
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000171def config_dict(filename):
172 """Convert content of config-file into dictionary."""
Florent Xicluna7dde7922010-09-03 19:52:03 +0000173 with open(filename, "r") as f:
174 cfglines = f.readlines()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000175 cfgdict = {}
176 for line in cfglines:
177 line = line.strip()
178 if not line or line.startswith("#"):
179 continue
180 try:
181 key, value = line.split("=")
182 except:
183 print("Bad line in config-file %s:\n%s" % (filename,line))
184 continue
185 key = key.strip()
186 value = value.strip()
187 if value in ["True", "False", "None", "''", '""']:
188 value = eval(value)
Guido van Rossumb241b671998-12-04 16:42:46 +0000189 else:
190 try:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000191 if "." in value:
192 value = float(value)
193 else:
194 value = int(value)
Guido van Rossumb241b671998-12-04 16:42:46 +0000195 except:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000196 pass # value need not be converted
197 cfgdict[key] = value
198 return cfgdict
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000199
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000200def readconfig(cfgdict):
201 """Read config-files, change configuration-dict accordingly.
Guido van Rossum3c7a25a2001-08-09 16:42:07 +0000202
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000203 If there is a turtle.cfg file in the current working directory,
204 read it from there. If this contains an importconfig-value,
205 say 'myway', construct filename turtle_mayway.cfg else use
206 turtle.cfg and read it from the import-directory, where
207 turtle.py is located.
208 Update configuration dictionary first according to config-file,
209 in the import directory, then according to config-file in the
210 current working directory.
211 If no config-file is found, the default configuration is used.
212 """
213 default_cfg = "turtle.cfg"
214 cfgdict1 = {}
215 cfgdict2 = {}
216 if isfile(default_cfg):
217 cfgdict1 = config_dict(default_cfg)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000218 if "importconfig" in cfgdict1:
219 default_cfg = "turtle_%s.cfg" % cfgdict1["importconfig"]
220 try:
221 head, tail = split(__file__)
222 cfg_file2 = join(head, default_cfg)
223 except:
224 cfg_file2 = ""
225 if isfile(cfg_file2):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000226 cfgdict2 = config_dict(cfg_file2)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000227 _CFG.update(cfgdict2)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000228 _CFG.update(cfgdict1)
Thomas Wouters477c8d52006-05-27 19:21:47 +0000229
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000230try:
231 readconfig(_CFG)
232except:
233 print ("No configfile read, reason unknown")
234
235
236class Vec2D(tuple):
237 """A 2 dimensional vector class, used as a helper class
238 for implementing turtle graphics.
239 May be useful for turtle graphics programs also.
240 Derived from tuple, so a vector is a tuple!
241
242 Provides (for a, b vectors, k number):
243 a+b vector addition
244 a-b vector subtraction
245 a*b inner product
246 k*a and a*k multiplication with scalar
247 |a| absolute value of a
248 a.rotate(angle) rotation
249 """
250 def __new__(cls, x, y):
251 return tuple.__new__(cls, (x, y))
252 def __add__(self, other):
253 return Vec2D(self[0]+other[0], self[1]+other[1])
254 def __mul__(self, other):
255 if isinstance(other, Vec2D):
256 return self[0]*other[0]+self[1]*other[1]
257 return Vec2D(self[0]*other, self[1]*other)
258 def __rmul__(self, other):
259 if isinstance(other, int) or isinstance(other, float):
260 return Vec2D(self[0]*other, self[1]*other)
261 def __sub__(self, other):
262 return Vec2D(self[0]-other[0], self[1]-other[1])
263 def __neg__(self):
264 return Vec2D(-self[0], -self[1])
265 def __abs__(self):
266 return (self[0]**2 + self[1]**2)**0.5
267 def rotate(self, angle):
268 """rotate self counterclockwise by angle
269 """
270 perp = Vec2D(-self[1], self[0])
271 angle = angle * math.pi / 180.0
272 c, s = math.cos(angle), math.sin(angle)
273 return Vec2D(self[0]*c+perp[0]*s, self[1]*c+perp[1]*s)
274 def __getnewargs__(self):
275 return (self[0], self[1])
276 def __repr__(self):
277 return "(%.2f,%.2f)" % self
278
279
280##############################################################################
281### From here up to line : Tkinter - Interface for turtle.py ###
Mark Dickinsonf8798f52009-02-20 20:53:56 +0000282### May be replaced by an interface to some different graphics toolkit ###
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000283##############################################################################
284
285## helper functions for Scrolled Canvas, to forward Canvas-methods
286## to ScrolledCanvas class
287
288def __methodDict(cls, _dict):
289 """helper function for Scrolled Canvas"""
290 baseList = list(cls.__bases__)
291 baseList.reverse()
292 for _super in baseList:
293 __methodDict(_super, _dict)
294 for key, value in cls.__dict__.items():
295 if type(value) == types.FunctionType:
296 _dict[key] = value
297
298def __methods(cls):
299 """helper function for Scrolled Canvas"""
300 _dict = {}
301 __methodDict(cls, _dict)
302 return _dict.keys()
303
304__stringBody = (
305 'def %(method)s(self, *args, **kw): return ' +
306 'self.%(attribute)s.%(method)s(*args, **kw)')
307
308def __forwardmethods(fromClass, toClass, toPart, exclude = ()):
309 ### MANY CHANGES ###
310 _dict_1 = {}
311 __methodDict(toClass, _dict_1)
312 _dict = {}
313 mfc = __methods(fromClass)
314 for ex in _dict_1.keys():
315 if ex[:1] == '_' or ex[-1:] == '_' or ex in exclude or ex in mfc:
316 pass
317 else:
318 _dict[ex] = _dict_1[ex]
319
320 for method, func in _dict.items():
321 d = {'method': method, 'func': func}
322 if isinstance(toPart, str):
323 execString = \
324 __stringBody % {'method' : method, 'attribute' : toPart}
325 exec(execString, d)
326 setattr(fromClass, method, d[method]) ### NEWU!
327
328
329class ScrolledCanvas(TK.Frame):
330 """Modeled after the scrolled canvas class from Grayons's Tkinter book.
331
332 Used as the default canvas, which pops up automatically when
333 using turtle graphics functions or the Turtle class.
334 """
335 def __init__(self, master, width=500, height=350,
336 canvwidth=600, canvheight=500):
337 TK.Frame.__init__(self, master, width=width, height=height)
Martin v. Löwis22d297b2008-11-19 09:14:30 +0000338 self._rootwindow = self.winfo_toplevel()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000339 self.width, self.height = width, height
340 self.canvwidth, self.canvheight = canvwidth, canvheight
341 self.bg = "white"
342 self._canvas = TK.Canvas(master, width=width, height=height,
343 bg=self.bg, relief=TK.SUNKEN, borderwidth=2)
344 self.hscroll = TK.Scrollbar(master, command=self._canvas.xview,
345 orient=TK.HORIZONTAL)
346 self.vscroll = TK.Scrollbar(master, command=self._canvas.yview)
347 self._canvas.configure(xscrollcommand=self.hscroll.set,
348 yscrollcommand=self.vscroll.set)
349 self.rowconfigure(0, weight=1, minsize=0)
350 self.columnconfigure(0, weight=1, minsize=0)
351 self._canvas.grid(padx=1, in_ = self, pady=1, row=0,
352 column=0, rowspan=1, columnspan=1, sticky='news')
353 self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
354 column=1, rowspan=1, columnspan=1, sticky='news')
355 self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
356 column=0, rowspan=1, columnspan=1, sticky='news')
357 self.reset()
Martin v. Löwis22d297b2008-11-19 09:14:30 +0000358 self._rootwindow.bind('<Configure>', self.onResize)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000359
360 def reset(self, canvwidth=None, canvheight=None, bg = None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +0000361 """Adjust canvas and scrollbars according to given canvas size."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000362 if canvwidth:
363 self.canvwidth = canvwidth
364 if canvheight:
365 self.canvheight = canvheight
366 if bg:
367 self.bg = bg
368 self._canvas.config(bg=bg,
369 scrollregion=(-self.canvwidth//2, -self.canvheight//2,
370 self.canvwidth//2, self.canvheight//2))
371 self._canvas.xview_moveto(0.5*(self.canvwidth - self.width + 30) /
372 self.canvwidth)
373 self._canvas.yview_moveto(0.5*(self.canvheight- self.height + 30) /
374 self.canvheight)
375 self.adjustScrolls()
376
377
378 def adjustScrolls(self):
379 """ Adjust scrollbars according to window- and canvas-size.
380 """
381 cwidth = self._canvas.winfo_width()
382 cheight = self._canvas.winfo_height()
383 self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)
384 self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)
385 if cwidth < self.canvwidth or cheight < self.canvheight:
386 self.hscroll.grid(padx=1, in_ = self, pady=1, row=1,
387 column=0, rowspan=1, columnspan=1, sticky='news')
388 self.vscroll.grid(padx=1, in_ = self, pady=1, row=0,
389 column=1, rowspan=1, columnspan=1, sticky='news')
390 else:
391 self.hscroll.grid_forget()
392 self.vscroll.grid_forget()
393
394 def onResize(self, event):
395 """self-explanatory"""
396 self.adjustScrolls()
397
398 def bbox(self, *args):
399 """ 'forward' method, which canvas itself has inherited...
400 """
401 return self._canvas.bbox(*args)
402
403 def cget(self, *args, **kwargs):
404 """ 'forward' method, which canvas itself has inherited...
405 """
406 return self._canvas.cget(*args, **kwargs)
407
408 def config(self, *args, **kwargs):
409 """ 'forward' method, which canvas itself has inherited...
410 """
411 self._canvas.config(*args, **kwargs)
412
413 def bind(self, *args, **kwargs):
414 """ 'forward' method, which canvas itself has inherited...
415 """
416 self._canvas.bind(*args, **kwargs)
417
418 def unbind(self, *args, **kwargs):
419 """ 'forward' method, which canvas itself has inherited...
420 """
421 self._canvas.unbind(*args, **kwargs)
422
423 def focus_force(self):
424 """ 'forward' method, which canvas itself has inherited...
425 """
426 self._canvas.focus_force()
427
428__forwardmethods(ScrolledCanvas, TK.Canvas, '_canvas')
429
430
431class _Root(TK.Tk):
432 """Root class for Screen based on Tkinter."""
433 def __init__(self):
434 TK.Tk.__init__(self)
435
436 def setupcanvas(self, width, height, cwidth, cheight):
437 self._canvas = ScrolledCanvas(self, width, height, cwidth, cheight)
438 self._canvas.pack(expand=1, fill="both")
439
440 def _getcanvas(self):
441 return self._canvas
442
443 def set_geometry(self, width, height, startx, starty):
444 self.geometry("%dx%d%+d%+d"%(width, height, startx, starty))
445
446 def ondestroy(self, destroy):
447 self.wm_protocol("WM_DELETE_WINDOW", destroy)
448
449 def win_width(self):
450 return self.winfo_screenwidth()
451
452 def win_height(self):
453 return self.winfo_screenheight()
454
455Canvas = TK.Canvas
456
457
458class TurtleScreenBase(object):
459 """Provide the basic graphics functionality.
460 Interface between Tkinter and turtle.py.
461
462 To port turtle.py to some different graphics toolkit
463 a corresponding TurtleScreenBase class has to be implemented.
464 """
465
466 @staticmethod
467 def _blankimage():
468 """return a blank image object
469 """
470 img = TK.PhotoImage(width=1, height=1)
471 img.blank()
472 return img
473
474 @staticmethod
475 def _image(filename):
476 """return an image object containing the
477 imagedata from a gif-file named filename.
478 """
479 return TK.PhotoImage(file=filename)
480
481 def __init__(self, cv):
482 self.cv = cv
483 if isinstance(cv, ScrolledCanvas):
484 w = self.cv.canvwidth
485 h = self.cv.canvheight
486 else: # expected: ordinary TK.Canvas
487 w = int(self.cv.cget("width"))
488 h = int(self.cv.cget("height"))
489 self.cv.config(scrollregion = (-w//2, -h//2, w//2, h//2 ))
490 self.canvwidth = w
491 self.canvheight = h
492 self.xscale = self.yscale = 1.0
493
494 def _createpoly(self):
495 """Create an invisible polygon item on canvas self.cv)
496 """
497 return self.cv.create_polygon((0, 0, 0, 0, 0, 0), fill="", outline="")
498
499 def _drawpoly(self, polyitem, coordlist, fill=None,
500 outline=None, width=None, top=False):
501 """Configure polygonitem polyitem according to provided
502 arguments:
503 coordlist is sequence of coordinates
504 fill is filling color
505 outline is outline color
506 top is a boolean value, which specifies if polyitem
507 will be put on top of the canvas' displaylist so it
508 will not be covered by other items.
509 """
510 cl = []
511 for x, y in coordlist:
512 cl.append(x * self.xscale)
513 cl.append(-y * self.yscale)
514 self.cv.coords(polyitem, *cl)
515 if fill is not None:
516 self.cv.itemconfigure(polyitem, fill=fill)
517 if outline is not None:
518 self.cv.itemconfigure(polyitem, outline=outline)
519 if width is not None:
520 self.cv.itemconfigure(polyitem, width=width)
521 if top:
522 self.cv.tag_raise(polyitem)
523
524 def _createline(self):
525 """Create an invisible line item on canvas self.cv)
526 """
527 return self.cv.create_line(0, 0, 0, 0, fill="", width=2,
528 capstyle = TK.ROUND)
529
530 def _drawline(self, lineitem, coordlist=None,
531 fill=None, width=None, top=False):
532 """Configure lineitem according to provided arguments:
533 coordlist is sequence of coordinates
534 fill is drawing color
535 width is width of drawn line.
536 top is a boolean value, which specifies if polyitem
537 will be put on top of the canvas' displaylist so it
538 will not be covered by other items.
539 """
540 if coordlist is not None:
541 cl = []
542 for x, y in coordlist:
543 cl.append(x * self.xscale)
544 cl.append(-y * self.yscale)
545 self.cv.coords(lineitem, *cl)
546 if fill is not None:
547 self.cv.itemconfigure(lineitem, fill=fill)
548 if width is not None:
549 self.cv.itemconfigure(lineitem, width=width)
550 if top:
551 self.cv.tag_raise(lineitem)
552
553 def _delete(self, item):
554 """Delete graphics item from canvas.
555 If item is"all" delete all graphics items.
556 """
557 self.cv.delete(item)
558
559 def _update(self):
560 """Redraw graphics items on canvas
561 """
562 self.cv.update()
563
564 def _delay(self, delay):
565 """Delay subsequent canvas actions for delay ms."""
566 self.cv.after(delay)
567
568 def _iscolorstring(self, color):
569 """Check if the string color is a legal Tkinter color string.
570 """
571 try:
572 rgb = self.cv.winfo_rgb(color)
573 ok = True
574 except TK.TclError:
575 ok = False
576 return ok
577
578 def _bgcolor(self, color=None):
579 """Set canvas' backgroundcolor if color is not None,
580 else return backgroundcolor."""
581 if color is not None:
582 self.cv.config(bg = color)
583 self._update()
584 else:
585 return self.cv.cget("bg")
586
587 def _write(self, pos, txt, align, font, pencolor):
588 """Write txt at pos in canvas with specified font
589 and color.
590 Return text item and x-coord of right bottom corner
591 of text's bounding box."""
592 x, y = pos
593 x = x * self.xscale
594 y = y * self.yscale
595 anchor = {"left":"sw", "center":"s", "right":"se" }
596 item = self.cv.create_text(x-1, -y, text = txt, anchor = anchor[align],
597 fill = pencolor, font = font)
598 x0, y0, x1, y1 = self.cv.bbox(item)
599 self.cv.update()
600 return item, x1-1
601
602## def _dot(self, pos, size, color):
603## """may be implemented for some other graphics toolkit"""
604
605 def _onclick(self, item, fun, num=1, add=None):
606 """Bind fun to mouse-click event on turtle.
607 fun must be a function with two arguments, the coordinates
608 of the clicked point on the canvas.
609 num, the number of the mouse-button defaults to 1
610 """
611 if fun is None:
612 self.cv.tag_unbind(item, "<Button-%s>" % num)
613 else:
614 def eventfun(event):
615 x, y = (self.cv.canvasx(event.x)/self.xscale,
616 -self.cv.canvasy(event.y)/self.yscale)
617 fun(x, y)
618 self.cv.tag_bind(item, "<Button-%s>" % num, eventfun, add)
619
620 def _onrelease(self, item, fun, num=1, add=None):
621 """Bind fun to mouse-button-release event on turtle.
622 fun must be a function with two arguments, the coordinates
623 of the point on the canvas where mouse button is released.
624 num, the number of the mouse-button defaults to 1
625
626 If a turtle is clicked, first _onclick-event will be performed,
627 then _onscreensclick-event.
628 """
629 if fun is None:
630 self.cv.tag_unbind(item, "<Button%s-ButtonRelease>" % num)
631 else:
632 def eventfun(event):
633 x, y = (self.cv.canvasx(event.x)/self.xscale,
634 -self.cv.canvasy(event.y)/self.yscale)
635 fun(x, y)
636 self.cv.tag_bind(item, "<Button%s-ButtonRelease>" % num,
637 eventfun, add)
638
639 def _ondrag(self, item, fun, num=1, add=None):
640 """Bind fun to mouse-move-event (with pressed mouse button) on turtle.
641 fun must be a function with two arguments, the coordinates of the
642 actual mouse position on the canvas.
643 num, the number of the mouse-button defaults to 1
644
645 Every sequence of mouse-move-events on a turtle is preceded by a
646 mouse-click event on that turtle.
647 """
648 if fun is None:
649 self.cv.tag_unbind(item, "<Button%s-Motion>" % num)
650 else:
651 def eventfun(event):
652 try:
653 x, y = (self.cv.canvasx(event.x)/self.xscale,
654 -self.cv.canvasy(event.y)/self.yscale)
655 fun(x, y)
656 except:
657 pass
658 self.cv.tag_bind(item, "<Button%s-Motion>" % num, eventfun, add)
659
660 def _onscreenclick(self, fun, num=1, add=None):
661 """Bind fun to mouse-click event on canvas.
662 fun must be a function with two arguments, the coordinates
663 of the clicked point on the canvas.
664 num, the number of the mouse-button defaults to 1
665
666 If a turtle is clicked, first _onclick-event will be performed,
667 then _onscreensclick-event.
668 """
669 if fun is None:
670 self.cv.unbind("<Button-%s>" % num)
671 else:
672 def eventfun(event):
673 x, y = (self.cv.canvasx(event.x)/self.xscale,
674 -self.cv.canvasy(event.y)/self.yscale)
675 fun(x, y)
676 self.cv.bind("<Button-%s>" % num, eventfun, add)
677
Georg Brandleaa84ef2009-05-05 08:14:33 +0000678 def _onkeyrelease(self, fun, key):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000679 """Bind fun to key-release event of key.
680 Canvas must have focus. See method listen
681 """
682 if fun is None:
683 self.cv.unbind("<KeyRelease-%s>" % key, None)
684 else:
685 def eventfun(event):
686 fun()
687 self.cv.bind("<KeyRelease-%s>" % key, eventfun)
688
Georg Brandleaa84ef2009-05-05 08:14:33 +0000689 def _onkeypress(self, fun, key=None):
690 """If key is given, bind fun to key-press event of key.
691 Otherwise bind fun to any key-press.
692 Canvas must have focus. See method listen.
693 """
694 if fun is None:
695 if key is None:
696 self.cv.unbind("<KeyPress>", None)
697 else:
698 self.cv.unbind("<KeyPress-%s>" % key, None)
699 else:
700 def eventfun(event):
701 fun()
702 if key is None:
703 self.cv.bind("<KeyPress>", eventfun)
704 else:
705 self.cv.bind("<KeyPress-%s>" % key, eventfun)
706
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000707 def _listen(self):
708 """Set focus on canvas (in order to collect key-events)
709 """
710 self.cv.focus_force()
711
712 def _ontimer(self, fun, t):
713 """Install a timer, which calls fun after t milliseconds.
714 """
715 if t == 0:
716 self.cv.after_idle(fun)
717 else:
718 self.cv.after(t, fun)
719
720 def _createimage(self, image):
721 """Create and return image item on canvas.
722 """
723 return self.cv.create_image(0, 0, image=image)
724
725 def _drawimage(self, item, pos, image):
726 """Configure image item as to draw image object
727 at position (x,y) on canvas)
728 """
729 x, y = pos
730 self.cv.coords(item, (x * self.xscale, -y * self.yscale))
731 self.cv.itemconfig(item, image=image)
732
733 def _setbgpic(self, item, image):
734 """Configure image item as to draw image object
735 at center of canvas. Set item to the first item
736 in the displaylist, so it will be drawn below
737 any other item ."""
738 self.cv.itemconfig(item, image=image)
739 self.cv.tag_lower(item)
740
741 def _type(self, item):
742 """Return 'line' or 'polygon' or 'image' depending on
743 type of item.
744 """
745 return self.cv.type(item)
746
747 def _pointlist(self, item):
748 """returns list of coordinate-pairs of points of item
749 Example (for insiders):
750 >>> from turtle import *
751 >>> getscreen()._pointlist(getturtle().turtle._item)
752 [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
753 (9.9999999999999982, 0.0)]
754 >>> """
Alexander Belopolsky022f0492010-11-22 19:40:51 +0000755 cl = self.cv.coords(item)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000756 pl = [(cl[i], -cl[i+1]) for i in range(0, len(cl), 2)]
757 return pl
758
759 def _setscrollregion(self, srx1, sry1, srx2, sry2):
760 self.cv.config(scrollregion=(srx1, sry1, srx2, sry2))
761
762 def _rescale(self, xscalefactor, yscalefactor):
763 items = self.cv.find_all()
764 for item in items:
765 coordinates = list(self.cv.coords(item))
766 newcoordlist = []
767 while coordinates:
768 x, y = coordinates[:2]
769 newcoordlist.append(x * xscalefactor)
770 newcoordlist.append(y * yscalefactor)
771 coordinates = coordinates[2:]
772 self.cv.coords(item, *newcoordlist)
773
774 def _resize(self, canvwidth=None, canvheight=None, bg=None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +0000775 """Resize the canvas the turtles are drawing on. Does
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000776 not alter the drawing window.
777 """
778 # needs amendment
779 if not isinstance(self.cv, ScrolledCanvas):
780 return self.canvwidth, self.canvheight
Florent Xiclunafd1b0932010-03-28 00:25:02 +0000781 if canvwidth is canvheight is bg is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000782 return self.cv.canvwidth, self.cv.canvheight
783 if canvwidth is not None:
784 self.canvwidth = canvwidth
785 if canvheight is not None:
786 self.canvheight = canvheight
787 self.cv.reset(canvwidth, canvheight, bg)
788
789 def _window_size(self):
790 """ Return the width and height of the turtle window.
791 """
792 width = self.cv.winfo_width()
793 if width <= 1: # the window isn't managed by a geometry manager
794 width = self.cv['width']
795 height = self.cv.winfo_height()
796 if height <= 1: # the window isn't managed by a geometry manager
797 height = self.cv['height']
798 return width, height
799
Georg Brandleaa84ef2009-05-05 08:14:33 +0000800 def mainloop(self):
801 """Starts event loop - calling Tkinter's mainloop function.
802
803 No argument.
804
805 Must be last statement in a turtle graphics program.
806 Must NOT be used if a script is run from within IDLE in -n mode
807 (No subprocess) - for interactive use of turtle graphics.
808
809 Example (for a TurtleScreen instance named screen):
810 >>> screen.mainloop()
811
812 """
813 TK.mainloop()
814
815 def textinput(self, title, prompt):
816 """Pop up a dialog window for input of a string.
817
818 Arguments: title is the title of the dialog window,
819 prompt is a text mostly describing what information to input.
820
821 Return the string input
822 If the dialog is canceled, return None.
823
824 Example (for a TurtleScreen instance named screen):
825 >>> screen.textinput("NIM", "Name of first player:")
826
827 """
828 return simpledialog.askstring(title, prompt)
829
830 def numinput(self, title, prompt, default=None, minval=None, maxval=None):
831 """Pop up a dialog window for input of a number.
832
833 Arguments: title is the title of the dialog window,
834 prompt is a text mostly describing what numerical information to input.
835 default: default value
836 minval: minimum value for imput
837 maxval: maximum value for input
838
839 The number input must be in the range minval .. maxval if these are
840 given. If not, a hint is issued and the dialog remains open for
841 correction. Return the number input.
842 If the dialog is canceled, return None.
843
844 Example (for a TurtleScreen instance named screen):
845 >>> screen.numinput("Poker", "Your stakes:", 1000, minval=10, maxval=10000)
846
847 """
848 return simpledialog.askfloat(title, prompt, initialvalue=default,
849 minvalue=minval, maxvalue=maxval)
850
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000851
852##############################################################################
853### End of Tkinter - interface ###
854##############################################################################
855
856
857class Terminator (Exception):
858 """Will be raised in TurtleScreen.update, if _RUNNING becomes False.
859
Terry Jan Reedyc30b7b12013-03-11 17:57:08 -0400860 This stops execution of a turtle graphics script.
861 Main purpose: use in the Demo-Viewer turtle.Demo.py.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000862 """
863 pass
864
865
866class TurtleGraphicsError(Exception):
867 """Some TurtleGraphics Error
868 """
869
870
871class Shape(object):
872 """Data structure modeling shapes.
873
874 attribute _type is one of "polygon", "image", "compound"
875 attribute _data is - depending on _type a poygon-tuple,
876 an image or a list constructed using the addcomponent method.
877 """
878 def __init__(self, type_, data=None):
879 self._type = type_
880 if type_ == "polygon":
881 if isinstance(data, list):
882 data = tuple(data)
883 elif type_ == "image":
884 if isinstance(data, str):
885 if data.lower().endswith(".gif") and isfile(data):
886 data = TurtleScreen._image(data)
887 # else data assumed to be Photoimage
888 elif type_ == "compound":
889 data = []
890 else:
891 raise TurtleGraphicsError("There is no shape type %s" % type_)
892 self._data = data
893
894 def addcomponent(self, poly, fill, outline=None):
895 """Add component to a shape of type compound.
896
897 Arguments: poly is a polygon, i. e. a tuple of number pairs.
898 fill is the fillcolor of the component,
899 outline is the outline color of the component.
900
901 call (for a Shapeobject namend s):
902 -- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
Thomas Wouters477c8d52006-05-27 19:21:47 +0000903
904 Example:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000905 >>> poly = ((0,0),(10,-5),(0,10),(-10,-5))
906 >>> s = Shape("compound")
907 >>> s.addcomponent(poly, "red", "blue")
Petri Lehtinen9aa20af2011-12-02 21:24:14 +0200908 >>> # .. add more components and then use register_shape()
Thomas Wouters477c8d52006-05-27 19:21:47 +0000909 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000910 if self._type != "compound":
911 raise TurtleGraphicsError("Cannot add component to %s Shape"
912 % self._type)
913 if outline is None:
914 outline = fill
915 self._data.append([poly, fill, outline])
Guido van Rossumb241b671998-12-04 16:42:46 +0000916
Thomas Wouters477c8d52006-05-27 19:21:47 +0000917
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000918class Tbuffer(object):
919 """Ring buffer used as undobuffer for RawTurtle objects."""
920 def __init__(self, bufsize=10):
921 self.bufsize = bufsize
922 self.buffer = [[None]] * bufsize
923 self.ptr = -1
924 self.cumulate = False
925 def reset(self, bufsize=None):
926 if bufsize is None:
927 for i in range(self.bufsize):
928 self.buffer[i] = [None]
929 else:
930 self.bufsize = bufsize
931 self.buffer = [[None]] * bufsize
932 self.ptr = -1
933 def push(self, item):
934 if self.bufsize > 0:
935 if not self.cumulate:
936 self.ptr = (self.ptr + 1) % self.bufsize
937 self.buffer[self.ptr] = item
938 else:
939 self.buffer[self.ptr].append(item)
940 def pop(self):
941 if self.bufsize > 0:
942 item = self.buffer[self.ptr]
943 if item is None:
944 return None
945 else:
946 self.buffer[self.ptr] = [None]
947 self.ptr = (self.ptr - 1) % self.bufsize
948 return (item)
949 def nr_of_items(self):
950 return self.bufsize - self.buffer.count([None])
951 def __repr__(self):
952 return str(self.buffer) + " " + str(self.ptr)
953
954
955
956class TurtleScreen(TurtleScreenBase):
957 """Provides screen oriented methods like setbg etc.
958
959 Only relies upon the methods of TurtleScreenBase and NOT
960 upon components of the underlying graphics toolkit -
961 which is Tkinter in this case.
962 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +0000963 _RUNNING = True
964
965 def __init__(self, cv, mode=_CFG["mode"],
966 colormode=_CFG["colormode"], delay=_CFG["delay"]):
967 self._shapes = {
968 "arrow" : Shape("polygon", ((-10,0), (10,0), (0,10))),
969 "turtle" : Shape("polygon", ((0,16), (-2,14), (-1,10), (-4,7),
970 (-7,9), (-9,8), (-6,5), (-7,1), (-5,-3), (-8,-6),
971 (-6,-8), (-4,-5), (0,-7), (4,-5), (6,-8), (8,-6),
972 (5,-3), (7,1), (6,5), (9,8), (7,9), (4,7), (1,10),
973 (2,14))),
974 "circle" : Shape("polygon", ((10,0), (9.51,3.09), (8.09,5.88),
975 (5.88,8.09), (3.09,9.51), (0,10), (-3.09,9.51),
976 (-5.88,8.09), (-8.09,5.88), (-9.51,3.09), (-10,0),
977 (-9.51,-3.09), (-8.09,-5.88), (-5.88,-8.09),
978 (-3.09,-9.51), (-0.00,-10.00), (3.09,-9.51),
979 (5.88,-8.09), (8.09,-5.88), (9.51,-3.09))),
980 "square" : Shape("polygon", ((10,-10), (10,10), (-10,10),
981 (-10,-10))),
982 "triangle" : Shape("polygon", ((10,-5.77), (0,11.55),
983 (-10,-5.77))),
984 "classic": Shape("polygon", ((0,0),(-5,-9),(0,-7),(5,-9))),
985 "blank" : Shape("image", self._blankimage())
986 }
987
988 self._bgpics = {"nopic" : ""}
989
990 TurtleScreenBase.__init__(self, cv)
991 self._mode = mode
992 self._delayvalue = delay
993 self._colormode = _CFG["colormode"]
994 self._keys = []
995 self.clear()
Ned Deily09ae5442014-04-19 19:11:14 -0700996 if sys.platform == 'darwin':
997 # Force Turtle window to the front on OS X. This is needed because
998 # the Turtle window will show behind the Terminal window when you
999 # start the demo from the command line.
1000 cv._rootwindow.call('wm', 'attributes', '.', '-topmost', '1')
1001 cv._rootwindow.call('wm', 'attributes', '.', '-topmost', '0')
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001002
1003 def clear(self):
1004 """Delete all drawings and all turtles from the TurtleScreen.
1005
Georg Brandleaa84ef2009-05-05 08:14:33 +00001006 No argument.
1007
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001008 Reset empty TurtleScreen to its initial state: white background,
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001009 no backgroundimage, no eventbindings and tracing on.
1010
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001011 Example (for a TurtleScreen instance named screen):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001012 >>> screen.clear()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001013
1014 Note: this method is not available as function.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001015 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001016 self._delayvalue = _CFG["delay"]
1017 self._colormode = _CFG["colormode"]
1018 self._delete("all")
1019 self._bgpic = self._createimage("")
1020 self._bgpicname = "nopic"
1021 self._tracing = 1
1022 self._updatecounter = 0
1023 self._turtles = []
1024 self.bgcolor("white")
1025 for btn in 1, 2, 3:
1026 self.onclick(None, btn)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001027 self.onkeypress(None)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001028 for key in self._keys[:]:
1029 self.onkey(None, key)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001030 self.onkeypress(None, key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001031 Turtle._pen = None
Guido van Rossumb241b671998-12-04 16:42:46 +00001032
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001033 def mode(self, mode=None):
1034 """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001035
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001036 Optional argument:
1037 mode -- on of the strings 'standard', 'logo' or 'world'
1038
1039 Mode 'standard' is compatible with turtle.py.
1040 Mode 'logo' is compatible with most Logo-Turtle-Graphics.
1041 Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
1042 this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
1043 If mode is not given, return the current mode.
1044
1045 Mode Initial turtle heading positive angles
1046 ------------|-------------------------|-------------------
1047 'standard' to the right (east) counterclockwise
1048 'logo' upward (north) clockwise
1049
1050 Examples:
1051 >>> mode('logo') # resets turtle heading to north
1052 >>> mode()
1053 'logo'
Thomas Wouters477c8d52006-05-27 19:21:47 +00001054 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001055 if mode is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001056 return self._mode
1057 mode = mode.lower()
1058 if mode not in ["standard", "logo", "world"]:
1059 raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
1060 self._mode = mode
1061 if mode in ["standard", "logo"]:
1062 self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
1063 self.canvwidth//2, self.canvheight//2)
1064 self.xscale = self.yscale = 1.0
1065 self.reset()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001066
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001067 def setworldcoordinates(self, llx, lly, urx, ury):
1068 """Set up a user defined coordinate-system.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001069
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001070 Arguments:
1071 llx -- a number, x-coordinate of lower left corner of canvas
1072 lly -- a number, y-coordinate of lower left corner of canvas
1073 urx -- a number, x-coordinate of upper right corner of canvas
1074 ury -- a number, y-coordinate of upper right corner of canvas
1075
1076 Set up user coodinat-system and switch to mode 'world' if necessary.
1077 This performs a screen.reset. If mode 'world' is already active,
1078 all drawings are redrawn according to the new coordinates.
1079
1080 But ATTENTION: in user-defined coordinatesystems angles may appear
1081 distorted. (see Screen.mode())
1082
1083 Example (for a TurtleScreen instance named screen):
1084 >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
1085 >>> for _ in range(36):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001086 ... left(10)
1087 ... forward(0.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001088 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001089 if self.mode() != "world":
1090 self.mode("world")
1091 xspan = float(urx - llx)
1092 yspan = float(ury - lly)
1093 wx, wy = self._window_size()
1094 self.screensize(wx-20, wy-20)
1095 oldxscale, oldyscale = self.xscale, self.yscale
1096 self.xscale = self.canvwidth / xspan
1097 self.yscale = self.canvheight / yspan
1098 srx1 = llx * self.xscale
1099 sry1 = -ury * self.yscale
1100 srx2 = self.canvwidth + srx1
1101 sry2 = self.canvheight + sry1
1102 self._setscrollregion(srx1, sry1, srx2, sry2)
1103 self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
1104 self.update()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001105
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001106 def register_shape(self, name, shape=None):
1107 """Adds a turtle shape to TurtleScreen's shapelist.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001108
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001109 Arguments:
1110 (1) name is the name of a gif-file and shape is None.
1111 Installs the corresponding image shape.
1112 !! Image-shapes DO NOT rotate when turning the turtle,
1113 !! so they do not display the heading of the turtle!
1114 (2) name is an arbitrary string and shape is a tuple
1115 of pairs of coordinates. Installs the corresponding
1116 polygon shape
1117 (3) name is an arbitrary string and shape is a
1118 (compound) Shape object. Installs the corresponding
1119 compound shape.
1120 To use a shape, you have to issue the command shape(shapename).
Thomas Wouters477c8d52006-05-27 19:21:47 +00001121
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001122 call: register_shape("turtle.gif")
1123 --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
1124
1125 Example (for a TurtleScreen instance named screen):
1126 >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
1127
Thomas Wouters477c8d52006-05-27 19:21:47 +00001128 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001129 if shape is None:
1130 # image
1131 if name.lower().endswith(".gif"):
1132 shape = Shape("image", self._image(name))
1133 else:
1134 raise TurtleGraphicsError("Bad arguments for register_shape.\n"
1135 + "Use help(register_shape)" )
1136 elif isinstance(shape, tuple):
1137 shape = Shape("polygon", shape)
1138 ## else shape assumed to be Shape-instance
1139 self._shapes[name] = shape
Guido van Rossumbffa52f2002-09-29 00:25:51 +00001140
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001141 def _colorstr(self, color):
1142 """Return color string corresponding to args.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001143
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001144 Argument may be a string or a tuple of three
1145 numbers corresponding to actual colormode,
1146 i.e. in the range 0<=n<=colormode.
1147
1148 If the argument doesn't represent a color,
1149 an error is raised.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001150 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001151 if len(color) == 1:
1152 color = color[0]
1153 if isinstance(color, str):
1154 if self._iscolorstring(color) or color == "":
1155 return color
1156 else:
1157 raise TurtleGraphicsError("bad color string: %s" % str(color))
1158 try:
1159 r, g, b = color
1160 except:
1161 raise TurtleGraphicsError("bad color arguments: %s" % str(color))
1162 if self._colormode == 1.0:
1163 r, g, b = [round(255.0*x) for x in (r, g, b)]
1164 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
1165 raise TurtleGraphicsError("bad color sequence: %s" % str(color))
1166 return "#%02x%02x%02x" % (r, g, b)
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001167
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001168 def _color(self, cstr):
1169 if not cstr.startswith("#"):
1170 return cstr
1171 if len(cstr) == 7:
1172 cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
1173 elif len(cstr) == 4:
1174 cl = [16*int(cstr[h], 16) for h in cstr[1:]]
1175 else:
1176 raise TurtleGraphicsError("bad colorstring: %s" % cstr)
1177 return tuple([c * self._colormode/255 for c in cl])
Thomas Wouters477c8d52006-05-27 19:21:47 +00001178
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001179 def colormode(self, cmode=None):
1180 """Return the colormode or set it to 1.0 or 255.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001181
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001182 Optional argument:
1183 cmode -- one of the values 1.0 or 255
Thomas Wouters477c8d52006-05-27 19:21:47 +00001184
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001185 r, g, b values of colortriples have to be in range 0..cmode.
1186
1187 Example (for a TurtleScreen instance named screen):
1188 >>> screen.colormode()
1189 1.0
1190 >>> screen.colormode(255)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001191 >>> pencolor(240,160,80)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001192 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001193 if cmode is None:
1194 return self._colormode
1195 if cmode == 1.0:
1196 self._colormode = float(cmode)
1197 elif cmode == 255:
1198 self._colormode = int(cmode)
1199
1200 def reset(self):
1201 """Reset all Turtles on the Screen to their initial state.
1202
1203 No argument.
1204
1205 Example (for a TurtleScreen instance named screen):
1206 >>> screen.reset()
1207 """
1208 for turtle in self._turtles:
1209 turtle._setmode(self._mode)
1210 turtle.reset()
1211
1212 def turtles(self):
1213 """Return the list of turtles on the screen.
1214
1215 Example (for a TurtleScreen instance named screen):
1216 >>> screen.turtles()
1217 [<turtle.Turtle object at 0x00E11FB0>]
1218 """
1219 return self._turtles
1220
1221 def bgcolor(self, *args):
1222 """Set or return backgroundcolor of the TurtleScreen.
1223
1224 Arguments (if given): a color string or three numbers
1225 in the range 0..colormode or a 3-tuple of such numbers.
1226
1227 Example (for a TurtleScreen instance named screen):
1228 >>> screen.bgcolor("orange")
1229 >>> screen.bgcolor()
1230 'orange'
1231 >>> screen.bgcolor(0.5,0,0.5)
1232 >>> screen.bgcolor()
1233 '#800080'
1234 """
1235 if args:
1236 color = self._colorstr(args)
1237 else:
1238 color = None
1239 color = self._bgcolor(color)
1240 if color is not None:
1241 color = self._color(color)
1242 return color
1243
1244 def tracer(self, n=None, delay=None):
1245 """Turns turtle animation on/off and set delay for update drawings.
1246
1247 Optional arguments:
1248 n -- nonnegative integer
1249 delay -- nonnegative integer
1250
1251 If n is given, only each n-th regular screen update is really performed.
1252 (Can be used to accelerate the drawing of complex graphics.)
1253 Second arguments sets delay value (see RawTurtle.delay())
1254
1255 Example (for a TurtleScreen instance named screen):
1256 >>> screen.tracer(8, 25)
1257 >>> dist = 2
1258 >>> for i in range(200):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001259 ... fd(dist)
1260 ... rt(90)
1261 ... dist += 2
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001262 """
1263 if n is None:
1264 return self._tracing
1265 self._tracing = int(n)
1266 self._updatecounter = 0
1267 if delay is not None:
1268 self._delayvalue = int(delay)
1269 if self._tracing:
1270 self.update()
1271
1272 def delay(self, delay=None):
1273 """ Return or set the drawing delay in milliseconds.
1274
1275 Optional argument:
1276 delay -- positive integer
1277
1278 Example (for a TurtleScreen instance named screen):
1279 >>> screen.delay(15)
1280 >>> screen.delay()
1281 15
1282 """
1283 if delay is None:
1284 return self._delayvalue
1285 self._delayvalue = int(delay)
1286
1287 def _incrementudc(self):
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03001288 """Increment update counter."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001289 if not TurtleScreen._RUNNING:
1290 TurtleScreen._RUNNNING = True
1291 raise Terminator
1292 if self._tracing > 0:
1293 self._updatecounter += 1
1294 self._updatecounter %= self._tracing
1295
1296 def update(self):
1297 """Perform a TurtleScreen update.
1298 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00001299 tracing = self._tracing
1300 self._tracing = True
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001301 for t in self.turtles():
1302 t._update_data()
1303 t._drawturtle()
Georg Brandleaa84ef2009-05-05 08:14:33 +00001304 self._tracing = tracing
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001305 self._update()
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001306
1307 def window_width(self):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001308 """ Return the width of the turtle window.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001309
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001310 Example (for a TurtleScreen instance named screen):
1311 >>> screen.window_width()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001312 640
1313 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001314 return self._window_size()[0]
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001315
1316 def window_height(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001317 """ Return the height of the turtle window.
1318
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001319 Example (for a TurtleScreen instance named screen):
1320 >>> screen.window_height()
1321 480
Thomas Wouters477c8d52006-05-27 19:21:47 +00001322 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001323 return self._window_size()[1]
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001324
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001325 def getcanvas(self):
1326 """Return the Canvas of this TurtleScreen.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001327
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001328 No argument.
1329
1330 Example (for a Screen instance named screen):
1331 >>> cv = screen.getcanvas()
1332 >>> cv
1333 <turtle.ScrolledCanvas instance at 0x010742D8>
Thomas Wouters477c8d52006-05-27 19:21:47 +00001334 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001335 return self.cv
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001336
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001337 def getshapes(self):
1338 """Return a list of names of all currently available turtle shapes.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001339
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001340 No argument.
1341
1342 Example (for a TurtleScreen instance named screen):
1343 >>> screen.getshapes()
1344 ['arrow', 'blank', 'circle', ... , 'turtle']
1345 """
1346 return sorted(self._shapes.keys())
1347
1348 def onclick(self, fun, btn=1, add=None):
1349 """Bind fun to mouse-click event on canvas.
1350
1351 Arguments:
1352 fun -- a function with two arguments, the coordinates of the
1353 clicked point on the canvas.
1354 num -- the number of the mouse-button, defaults to 1
1355
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001356 Example (for a TurtleScreen instance named screen)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001357
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001358 >>> screen.onclick(goto)
1359 >>> # Subsequently clicking into the TurtleScreen will
1360 >>> # make the turtle move to the clicked point.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001361 >>> screen.onclick(None)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001362 """
1363 self._onscreenclick(fun, btn, add)
1364
1365 def onkey(self, fun, key):
1366 """Bind fun to key-release event of key.
1367
1368 Arguments:
1369 fun -- a function with no arguments
1370 key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1371
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001372 In order to be able to register key-events, TurtleScreen
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001373 must have focus. (See method listen.)
1374
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001375 Example (for a TurtleScreen instance named screen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001376
1377 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001378 ... fd(50)
1379 ... lt(60)
1380 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001381 >>> screen.onkey(f, "Up")
1382 >>> screen.listen()
1383
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001384 Subsequently the turtle can be moved by repeatedly pressing
1385 the up-arrow key, consequently drawing a hexagon
1386
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001387 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001388 if fun is None:
Georg Brandleaa84ef2009-05-05 08:14:33 +00001389 if key in self._keys:
1390 self._keys.remove(key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001391 elif key not in self._keys:
1392 self._keys.append(key)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001393 self._onkeyrelease(fun, key)
1394
1395 def onkeypress(self, fun, key=None):
1396 """Bind fun to key-press event of key if key is given,
1397 or to any key-press-event if no key is given.
1398
1399 Arguments:
1400 fun -- a function with no arguments
1401 key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1402
1403 In order to be able to register key-events, TurtleScreen
1404 must have focus. (See method listen.)
1405
1406 Example (for a TurtleScreen instance named screen
1407 and a Turtle instance named turtle):
1408
1409 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001410 ... fd(50)
1411 ... lt(60)
1412 ...
1413 >>> screen.onkeypress(f, "Up")
Georg Brandleaa84ef2009-05-05 08:14:33 +00001414 >>> screen.listen()
1415
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001416 Subsequently the turtle can be moved by repeatedly pressing
1417 the up-arrow key, or by keeping pressed the up-arrow key.
1418 consequently drawing a hexagon.
Georg Brandleaa84ef2009-05-05 08:14:33 +00001419 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001420 if fun is None:
Georg Brandleaa84ef2009-05-05 08:14:33 +00001421 if key in self._keys:
1422 self._keys.remove(key)
1423 elif key is not None and key not in self._keys:
1424 self._keys.append(key)
1425 self._onkeypress(fun, key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001426
1427 def listen(self, xdummy=None, ydummy=None):
1428 """Set focus on TurtleScreen (in order to collect key-events)
1429
1430 No arguments.
1431 Dummy arguments are provided in order
1432 to be able to pass listen to the onclick method.
1433
1434 Example (for a TurtleScreen instance named screen):
1435 >>> screen.listen()
1436 """
1437 self._listen()
1438
1439 def ontimer(self, fun, t=0):
1440 """Install a timer, which calls fun after t milliseconds.
1441
1442 Arguments:
1443 fun -- a function with no arguments.
1444 t -- a number >= 0
1445
1446 Example (for a TurtleScreen instance named screen):
1447
1448 >>> running = True
1449 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001450 ... if running:
1451 ... fd(50)
1452 ... lt(60)
1453 ... screen.ontimer(f, 250)
1454 ...
1455 >>> f() # makes the turtle marching around
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001456 >>> running = False
1457 """
1458 self._ontimer(fun, t)
1459
1460 def bgpic(self, picname=None):
1461 """Set background image or return name of current backgroundimage.
1462
1463 Optional argument:
1464 picname -- a string, name of a gif-file or "nopic".
1465
Ezio Melotti42da6632011-03-15 05:18:48 +02001466 If picname is a filename, set the corresponding image as background.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001467 If picname is "nopic", delete backgroundimage, if present.
1468 If picname is None, return the filename of the current backgroundimage.
1469
1470 Example (for a TurtleScreen instance named screen):
1471 >>> screen.bgpic()
1472 'nopic'
1473 >>> screen.bgpic("landscape.gif")
1474 >>> screen.bgpic()
1475 'landscape.gif'
1476 """
1477 if picname is None:
1478 return self._bgpicname
1479 if picname not in self._bgpics:
1480 self._bgpics[picname] = self._image(picname)
1481 self._setbgpic(self._bgpic, self._bgpics[picname])
1482 self._bgpicname = picname
1483
1484 def screensize(self, canvwidth=None, canvheight=None, bg=None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001485 """Resize the canvas the turtles are drawing on.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001486
1487 Optional arguments:
1488 canvwidth -- positive integer, new width of canvas in pixels
1489 canvheight -- positive integer, new height of canvas in pixels
Ezio Melotti13925002011-03-16 11:05:33 +02001490 bg -- colorstring or color-tuple, new backgroundcolor
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001491 If no arguments are given, return current (canvaswidth, canvasheight)
1492
1493 Do not alter the drawing window. To observe hidden parts of
1494 the canvas use the scrollbars. (Can make visible those parts
1495 of a drawing, which were outside the canvas before!)
1496
1497 Example (for a Turtle instance named turtle):
1498 >>> turtle.screensize(2000,1500)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001499 >>> # e.g. to search for an erroneously escaped turtle ;-)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001500 """
1501 return self._resize(canvwidth, canvheight, bg)
1502
1503 onscreenclick = onclick
1504 resetscreen = reset
1505 clearscreen = clear
1506 addshape = register_shape
Georg Brandleaa84ef2009-05-05 08:14:33 +00001507 onkeyrelease = onkey
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001508
1509class TNavigator(object):
1510 """Navigation part of the RawTurtle.
1511 Implements methods for turtle movement.
1512 """
1513 START_ORIENTATION = {
1514 "standard": Vec2D(1.0, 0.0),
1515 "world" : Vec2D(1.0, 0.0),
1516 "logo" : Vec2D(0.0, 1.0) }
1517 DEFAULT_MODE = "standard"
1518 DEFAULT_ANGLEOFFSET = 0
1519 DEFAULT_ANGLEORIENT = 1
1520
1521 def __init__(self, mode=DEFAULT_MODE):
1522 self._angleOffset = self.DEFAULT_ANGLEOFFSET
1523 self._angleOrient = self.DEFAULT_ANGLEORIENT
1524 self._mode = mode
1525 self.undobuffer = None
1526 self.degrees()
1527 self._mode = None
1528 self._setmode(mode)
1529 TNavigator.reset(self)
1530
1531 def reset(self):
1532 """reset turtle to its initial values
1533
1534 Will be overwritten by parent class
1535 """
1536 self._position = Vec2D(0.0, 0.0)
1537 self._orient = TNavigator.START_ORIENTATION[self._mode]
1538
1539 def _setmode(self, mode=None):
1540 """Set turtle-mode to 'standard', 'world' or 'logo'.
1541 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001542 if mode is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001543 return self._mode
1544 if mode not in ["standard", "logo", "world"]:
1545 return
1546 self._mode = mode
1547 if mode in ["standard", "world"]:
1548 self._angleOffset = 0
1549 self._angleOrient = 1
1550 else: # mode == "logo":
1551 self._angleOffset = self._fullcircle/4.
1552 self._angleOrient = -1
1553
1554 def _setDegreesPerAU(self, fullcircle):
1555 """Helper function for degrees() and radians()"""
1556 self._fullcircle = fullcircle
1557 self._degreesPerAU = 360/fullcircle
1558 if self._mode == "standard":
1559 self._angleOffset = 0
1560 else:
1561 self._angleOffset = fullcircle/4.
1562
1563 def degrees(self, fullcircle=360.0):
1564 """ Set angle measurement units to degrees.
1565
1566 Optional argument:
1567 fullcircle - a number
1568
1569 Set angle measurement units, i. e. set number
1570 of 'degrees' for a full circle. Dafault value is
1571 360 degrees.
1572
1573 Example (for a Turtle instance named turtle):
1574 >>> turtle.left(90)
1575 >>> turtle.heading()
1576 90
Alexander Belopolsky3cdfb122010-10-29 17:16:49 +00001577
1578 Change angle measurement unit to grad (also known as gon,
1579 grade, or gradian and equals 1/100-th of the right angle.)
1580 >>> turtle.degrees(400.0)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001581 >>> turtle.heading()
1582 100
1583
1584 """
1585 self._setDegreesPerAU(fullcircle)
1586
1587 def radians(self):
1588 """ Set the angle measurement units to radians.
1589
1590 No arguments.
1591
1592 Example (for a Turtle instance named turtle):
1593 >>> turtle.heading()
1594 90
1595 >>> turtle.radians()
1596 >>> turtle.heading()
1597 1.5707963267948966
1598 """
1599 self._setDegreesPerAU(2*math.pi)
1600
1601 def _go(self, distance):
1602 """move turtle forward by specified distance"""
1603 ende = self._position + self._orient * distance
1604 self._goto(ende)
1605
1606 def _rotate(self, angle):
1607 """Turn turtle counterclockwise by specified angle if angle > 0."""
1608 angle *= self._degreesPerAU
1609 self._orient = self._orient.rotate(angle)
1610
1611 def _goto(self, end):
1612 """move turtle to position end."""
1613 self._position = end
1614
1615 def forward(self, distance):
1616 """Move the turtle forward by the specified distance.
1617
1618 Aliases: forward | fd
1619
1620 Argument:
1621 distance -- a number (integer or float)
1622
1623 Move the turtle forward by the specified distance, in the direction
1624 the turtle is headed.
1625
1626 Example (for a Turtle instance named turtle):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001627 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001628 (0.00, 0.00)
1629 >>> turtle.forward(25)
1630 >>> turtle.position()
1631 (25.00,0.00)
1632 >>> turtle.forward(-75)
1633 >>> turtle.position()
1634 (-50.00,0.00)
1635 """
1636 self._go(distance)
1637
1638 def back(self, distance):
1639 """Move the turtle backward by distance.
1640
1641 Aliases: back | backward | bk
1642
1643 Argument:
1644 distance -- a number
1645
1646 Move the turtle backward by distance ,opposite to the direction the
1647 turtle is headed. Do not change the turtle's heading.
1648
1649 Example (for a Turtle instance named turtle):
1650 >>> turtle.position()
1651 (0.00, 0.00)
1652 >>> turtle.backward(30)
1653 >>> turtle.position()
1654 (-30.00, 0.00)
1655 """
1656 self._go(-distance)
1657
1658 def right(self, angle):
1659 """Turn turtle right by angle units.
1660
1661 Aliases: right | rt
1662
1663 Argument:
1664 angle -- a number (integer or float)
1665
1666 Turn turtle right by angle units. (Units are by default degrees,
1667 but can be set via the degrees() and radians() functions.)
1668 Angle orientation depends on mode. (See this.)
1669
1670 Example (for a Turtle instance named turtle):
1671 >>> turtle.heading()
1672 22.0
1673 >>> turtle.right(45)
1674 >>> turtle.heading()
1675 337.0
1676 """
1677 self._rotate(-angle)
1678
1679 def left(self, angle):
1680 """Turn turtle left by angle units.
1681
1682 Aliases: left | lt
1683
1684 Argument:
1685 angle -- a number (integer or float)
1686
1687 Turn turtle left by angle units. (Units are by default degrees,
1688 but can be set via the degrees() and radians() functions.)
1689 Angle orientation depends on mode. (See this.)
1690
1691 Example (for a Turtle instance named turtle):
1692 >>> turtle.heading()
1693 22.0
1694 >>> turtle.left(45)
1695 >>> turtle.heading()
1696 67.0
1697 """
1698 self._rotate(angle)
1699
1700 def pos(self):
1701 """Return the turtle's current location (x,y), as a Vec2D-vector.
1702
1703 Aliases: pos | position
1704
1705 No arguments.
1706
1707 Example (for a Turtle instance named turtle):
1708 >>> turtle.pos()
1709 (0.00, 240.00)
1710 """
1711 return self._position
1712
1713 def xcor(self):
1714 """ Return the turtle's x coordinate.
1715
1716 No arguments.
1717
1718 Example (for a Turtle instance named turtle):
1719 >>> reset()
1720 >>> turtle.left(60)
1721 >>> turtle.forward(100)
1722 >>> print turtle.xcor()
1723 50.0
1724 """
1725 return self._position[0]
1726
1727 def ycor(self):
1728 """ Return the turtle's y coordinate
1729 ---
1730 No arguments.
1731
1732 Example (for a Turtle instance named turtle):
1733 >>> reset()
1734 >>> turtle.left(60)
1735 >>> turtle.forward(100)
1736 >>> print turtle.ycor()
1737 86.6025403784
1738 """
1739 return self._position[1]
1740
1741
1742 def goto(self, x, y=None):
1743 """Move turtle to an absolute position.
1744
1745 Aliases: setpos | setposition | goto:
1746
1747 Arguments:
1748 x -- a number or a pair/vector of numbers
1749 y -- a number None
1750
1751 call: goto(x, y) # two coordinates
1752 --or: goto((x, y)) # a pair (tuple) of coordinates
1753 --or: goto(vec) # e.g. as returned by pos()
1754
1755 Move turtle to an absolute position. If the pen is down,
1756 a line will be drawn. The turtle's orientation does not change.
1757
1758 Example (for a Turtle instance named turtle):
1759 >>> tp = turtle.pos()
1760 >>> tp
1761 (0.00, 0.00)
1762 >>> turtle.setpos(60,30)
1763 >>> turtle.pos()
1764 (60.00,30.00)
1765 >>> turtle.setpos((20,80))
1766 >>> turtle.pos()
1767 (20.00,80.00)
1768 >>> turtle.setpos(tp)
1769 >>> turtle.pos()
1770 (0.00,0.00)
1771 """
1772 if y is None:
1773 self._goto(Vec2D(*x))
1774 else:
1775 self._goto(Vec2D(x, y))
1776
1777 def home(self):
1778 """Move turtle to the origin - coordinates (0,0).
1779
1780 No arguments.
1781
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001782 Move turtle to the origin - coordinates (0,0) and set its
1783 heading to its start-orientation (which depends on mode).
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001784
1785 Example (for a Turtle instance named turtle):
1786 >>> turtle.home()
1787 """
1788 self.goto(0, 0)
1789 self.setheading(0)
1790
1791 def setx(self, x):
1792 """Set the turtle's first coordinate to x
1793
1794 Argument:
1795 x -- a number (integer or float)
1796
1797 Set the turtle's first coordinate to x, leave second coordinate
1798 unchanged.
1799
1800 Example (for a Turtle instance named turtle):
1801 >>> turtle.position()
1802 (0.00, 240.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001803 >>> turtle.setx(10)
1804 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001805 (10.00, 240.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001806 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001807 self._goto(Vec2D(x, self._position[1]))
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001808
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001809 def sety(self, y):
1810 """Set the turtle's second coordinate to y
Thomas Wouters477c8d52006-05-27 19:21:47 +00001811
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001812 Argument:
1813 y -- a number (integer or float)
1814
1815 Set the turtle's first coordinate to x, second coordinate remains
1816 unchanged.
1817
1818 Example (for a Turtle instance named turtle):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001819 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001820 (0.00, 40.00)
1821 >>> turtle.sety(-10)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001822 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001823 (0.00, -10.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001824 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001825 self._goto(Vec2D(self._position[0], y))
Guido van Rossumb241b671998-12-04 16:42:46 +00001826
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001827 def distance(self, x, y=None):
1828 """Return the distance from the turtle to (x,y) in turtle step units.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001829
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001830 Arguments:
1831 x -- a number or a pair/vector of numbers or a turtle instance
1832 y -- a number None None
Thomas Wouters477c8d52006-05-27 19:21:47 +00001833
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001834 call: distance(x, y) # two coordinates
1835 --or: distance((x, y)) # a pair (tuple) of coordinates
1836 --or: distance(vec) # e.g. as returned by pos()
1837 --or: distance(mypen) # where mypen is another turtle
1838
1839 Example (for a Turtle instance named turtle):
1840 >>> turtle.pos()
1841 (0.00, 0.00)
1842 >>> turtle.distance(30,40)
1843 50.0
1844 >>> pen = Turtle()
1845 >>> pen.forward(77)
1846 >>> turtle.distance(pen)
1847 77.0
1848 """
1849 if y is not None:
1850 pos = Vec2D(x, y)
1851 if isinstance(x, Vec2D):
1852 pos = x
1853 elif isinstance(x, tuple):
1854 pos = Vec2D(*x)
1855 elif isinstance(x, TNavigator):
1856 pos = x._position
1857 return abs(pos - self._position)
1858
1859 def towards(self, x, y=None):
1860 """Return the angle of the line from the turtle's position to (x, y).
1861
1862 Arguments:
1863 x -- a number or a pair/vector of numbers or a turtle instance
1864 y -- a number None None
1865
1866 call: distance(x, y) # two coordinates
1867 --or: distance((x, y)) # a pair (tuple) of coordinates
1868 --or: distance(vec) # e.g. as returned by pos()
1869 --or: distance(mypen) # where mypen is another turtle
1870
1871 Return the angle, between the line from turtle-position to position
1872 specified by x, y and the turtle's start orientation. (Depends on
1873 modes - "standard" or "logo")
1874
1875 Example (for a Turtle instance named turtle):
1876 >>> turtle.pos()
1877 (10.00, 10.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001878 >>> turtle.towards(0,0)
1879 225.0
1880 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001881 if y is not None:
1882 pos = Vec2D(x, y)
1883 if isinstance(x, Vec2D):
1884 pos = x
1885 elif isinstance(x, tuple):
1886 pos = Vec2D(*x)
1887 elif isinstance(x, TNavigator):
1888 pos = x._position
1889 x, y = pos - self._position
1890 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1891 result /= self._degreesPerAU
1892 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1893
1894 def heading(self):
1895 """ Return the turtle's current heading.
1896
1897 No arguments.
1898
1899 Example (for a Turtle instance named turtle):
1900 >>> turtle.left(67)
1901 >>> turtle.heading()
1902 67.0
1903 """
1904 x, y = self._orient
1905 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1906 result /= self._degreesPerAU
1907 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1908
1909 def setheading(self, to_angle):
1910 """Set the orientation of the turtle to to_angle.
1911
1912 Aliases: setheading | seth
1913
1914 Argument:
1915 to_angle -- a number (integer or float)
1916
1917 Set the orientation of the turtle to to_angle.
1918 Here are some common directions in degrees:
1919
1920 standard - mode: logo-mode:
1921 -------------------|--------------------
1922 0 - east 0 - north
1923 90 - north 90 - east
1924 180 - west 180 - south
1925 270 - south 270 - west
1926
1927 Example (for a Turtle instance named turtle):
1928 >>> turtle.setheading(90)
1929 >>> turtle.heading()
1930 90
1931 """
1932 angle = (to_angle - self.heading())*self._angleOrient
1933 full = self._fullcircle
1934 angle = (angle+full/2.)%full - full/2.
1935 self._rotate(angle)
1936
1937 def circle(self, radius, extent = None, steps = None):
1938 """ Draw a circle with given radius.
1939
1940 Arguments:
1941 radius -- a number
1942 extent (optional) -- a number
1943 steps (optional) -- an integer
1944
1945 Draw a circle with given radius. The center is radius units left
1946 of the turtle; extent - an angle - determines which part of the
1947 circle is drawn. If extent is not given, draw the entire circle.
1948 If extent is not a full circle, one endpoint of the arc is the
1949 current pen position. Draw the arc in counterclockwise direction
1950 if radius is positive, otherwise in clockwise direction. Finally
1951 the direction of the turtle is changed by the amount of extent.
1952
1953 As the circle is approximated by an inscribed regular polygon,
1954 steps determines the number of steps to use. If not given,
1955 it will be calculated automatically. Maybe used to draw regular
1956 polygons.
1957
1958 call: circle(radius) # full circle
1959 --or: circle(radius, extent) # arc
1960 --or: circle(radius, extent, steps)
1961 --or: circle(radius, steps=6) # 6-sided polygon
1962
1963 Example (for a Turtle instance named turtle):
1964 >>> turtle.circle(50)
1965 >>> turtle.circle(120, 180) # semicircle
1966 """
1967 if self.undobuffer:
1968 self.undobuffer.push(["seq"])
1969 self.undobuffer.cumulate = True
1970 speed = self.speed()
1971 if extent is None:
1972 extent = self._fullcircle
1973 if steps is None:
1974 frac = abs(extent)/self._fullcircle
1975 steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
1976 w = 1.0 * extent / steps
1977 w2 = 0.5 * w
1978 l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
1979 if radius < 0:
1980 l, w, w2 = -l, -w, -w2
1981 tr = self._tracer()
1982 dl = self._delay()
1983 if speed == 0:
1984 self._tracer(0, 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001985 else:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001986 self.speed(0)
1987 self._rotate(w2)
1988 for i in range(steps):
1989 self.speed(speed)
1990 self._go(l)
1991 self.speed(0)
1992 self._rotate(w)
1993 self._rotate(-w2)
1994 if speed == 0:
1995 self._tracer(tr, dl)
1996 self.speed(speed)
1997 if self.undobuffer:
1998 self.undobuffer.cumulate = False
Thomas Wouters477c8d52006-05-27 19:21:47 +00001999
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002000## three dummy methods to be implemented by child class:
Thomas Wouters477c8d52006-05-27 19:21:47 +00002001
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002002 def speed(self, s=0):
2003 """dummy method - to be overwritten by child class"""
2004 def _tracer(self, a=None, b=None):
2005 """dummy method - to be overwritten by child class"""
2006 def _delay(self, n=None):
2007 """dummy method - to be overwritten by child class"""
Thomas Wouters477c8d52006-05-27 19:21:47 +00002008
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002009 fd = forward
2010 bk = back
2011 backward = back
2012 rt = right
2013 lt = left
2014 position = pos
2015 setpos = goto
2016 setposition = goto
2017 seth = setheading
Thomas Wouters477c8d52006-05-27 19:21:47 +00002018
Thomas Wouters477c8d52006-05-27 19:21:47 +00002019
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002020class TPen(object):
2021 """Drawing part of the RawTurtle.
2022 Implements drawing properties.
2023 """
2024 def __init__(self, resizemode=_CFG["resizemode"]):
2025 self._resizemode = resizemode # or "user" or "noresize"
2026 self.undobuffer = None
2027 TPen._reset(self)
Thomas Wouters477c8d52006-05-27 19:21:47 +00002028
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002029 def _reset(self, pencolor=_CFG["pencolor"],
2030 fillcolor=_CFG["fillcolor"]):
2031 self._pensize = 1
2032 self._shown = True
2033 self._pencolor = pencolor
2034 self._fillcolor = fillcolor
2035 self._drawing = True
2036 self._speed = 3
Georg Brandleaa84ef2009-05-05 08:14:33 +00002037 self._stretchfactor = (1., 1.)
2038 self._shearfactor = 0.
2039 self._tilt = 0.
2040 self._shapetrafo = (1., 0., 0., 1.)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002041 self._outlinewidth = 1
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002042
2043 def resizemode(self, rmode=None):
2044 """Set resizemode to one of the values: "auto", "user", "noresize".
2045
2046 (Optional) Argument:
2047 rmode -- one of the strings "auto", "user", "noresize"
2048
2049 Different resizemodes have the following effects:
2050 - "auto" adapts the appearance of the turtle
2051 corresponding to the value of pensize.
2052 - "user" adapts the appearance of the turtle according to the
2053 values of stretchfactor and outlinewidth (outline),
2054 which are set by shapesize()
2055 - "noresize" no adaption of the turtle's appearance takes place.
2056 If no argument is given, return current resizemode.
2057 resizemode("user") is called by a call of shapesize with arguments.
2058
2059
2060 Examples (for a Turtle instance named turtle):
2061 >>> turtle.resizemode("noresize")
2062 >>> turtle.resizemode()
2063 'noresize'
Thomas Wouters477c8d52006-05-27 19:21:47 +00002064 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002065 if rmode is None:
2066 return self._resizemode
2067 rmode = rmode.lower()
2068 if rmode in ["auto", "user", "noresize"]:
2069 self.pen(resizemode=rmode)
Guido van Rossumb241b671998-12-04 16:42:46 +00002070
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002071 def pensize(self, width=None):
2072 """Set or return the line thickness.
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002073
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002074 Aliases: pensize | width
Thomas Wouters477c8d52006-05-27 19:21:47 +00002075
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002076 Argument:
2077 width -- positive number
Thomas Wouters477c8d52006-05-27 19:21:47 +00002078
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002079 Set the line thickness to width or return it. If resizemode is set
2080 to "auto" and turtleshape is a polygon, that polygon is drawn with
2081 the same line thickness. If no argument is given, current pensize
2082 is returned.
Thomas Wouters477c8d52006-05-27 19:21:47 +00002083
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002084 Example (for a Turtle instance named turtle):
2085 >>> turtle.pensize()
2086 1
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002087 >>> turtle.pensize(10) # from here on lines of width 10 are drawn
Thomas Wouters477c8d52006-05-27 19:21:47 +00002088 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002089 if width is None:
2090 return self._pensize
2091 self.pen(pensize=width)
Thomas Wouters477c8d52006-05-27 19:21:47 +00002092
2093
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002094 def penup(self):
2095 """Pull the pen up -- no drawing when moving.
Thomas Wouters477c8d52006-05-27 19:21:47 +00002096
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002097 Aliases: penup | pu | up
Thomas Wouters477c8d52006-05-27 19:21:47 +00002098
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002099 No argument
2100
2101 Example (for a Turtle instance named turtle):
2102 >>> turtle.penup()
Thomas Wouters477c8d52006-05-27 19:21:47 +00002103 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002104 if not self._drawing:
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002105 return
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002106 self.pen(pendown=False)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002107
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002108 def pendown(self):
2109 """Pull the pen down -- drawing when moving.
2110
2111 Aliases: pendown | pd | down
2112
2113 No argument.
2114
2115 Example (for a Turtle instance named turtle):
2116 >>> turtle.pendown()
2117 """
2118 if self._drawing:
2119 return
2120 self.pen(pendown=True)
2121
2122 def isdown(self):
2123 """Return True if pen is down, False if it's up.
2124
2125 No argument.
2126
2127 Example (for a Turtle instance named turtle):
2128 >>> turtle.penup()
2129 >>> turtle.isdown()
2130 False
2131 >>> turtle.pendown()
2132 >>> turtle.isdown()
2133 True
2134 """
2135 return self._drawing
2136
2137 def speed(self, speed=None):
2138 """ Return or set the turtle's speed.
2139
2140 Optional argument:
2141 speed -- an integer in the range 0..10 or a speedstring (see below)
2142
2143 Set the turtle's speed to an integer value in the range 0 .. 10.
2144 If no argument is given: return current speed.
2145
2146 If input is a number greater than 10 or smaller than 0.5,
2147 speed is set to 0.
2148 Speedstrings are mapped to speedvalues in the following way:
2149 'fastest' : 0
2150 'fast' : 10
2151 'normal' : 6
2152 'slow' : 3
2153 'slowest' : 1
2154 speeds from 1 to 10 enforce increasingly faster animation of
2155 line drawing and turtle turning.
2156
2157 Attention:
2158 speed = 0 : *no* animation takes place. forward/back makes turtle jump
2159 and likewise left/right make the turtle turn instantly.
2160
2161 Example (for a Turtle instance named turtle):
2162 >>> turtle.speed(3)
2163 """
2164 speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
2165 if speed is None:
2166 return self._speed
2167 if speed in speeds:
2168 speed = speeds[speed]
2169 elif 0.5 < speed < 10.5:
2170 speed = int(round(speed))
2171 else:
2172 speed = 0
2173 self.pen(speed=speed)
2174
2175 def color(self, *args):
2176 """Return or set the pencolor and fillcolor.
2177
2178 Arguments:
2179 Several input formats are allowed.
2180 They use 0, 1, 2, or 3 arguments as follows:
2181
2182 color()
2183 Return the current pencolor and the current fillcolor
2184 as a pair of color specification strings as are returned
2185 by pencolor and fillcolor.
2186 color(colorstring), color((r,g,b)), color(r,g,b)
2187 inputs as in pencolor, set both, fillcolor and pencolor,
2188 to the given value.
2189 color(colorstring1, colorstring2),
2190 color((r1,g1,b1), (r2,g2,b2))
2191 equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
2192 and analogously, if the other input format is used.
2193
2194 If turtleshape is a polygon, outline and interior of that polygon
2195 is drawn with the newly set colors.
2196 For mor info see: pencolor, fillcolor
2197
2198 Example (for a Turtle instance named turtle):
2199 >>> turtle.color('red', 'green')
2200 >>> turtle.color()
2201 ('red', 'green')
2202 >>> colormode(255)
2203 >>> color((40, 80, 120), (160, 200, 240))
2204 >>> color()
2205 ('#285078', '#a0c8f0')
2206 """
2207 if args:
2208 l = len(args)
2209 if l == 1:
2210 pcolor = fcolor = args[0]
2211 elif l == 2:
2212 pcolor, fcolor = args
2213 elif l == 3:
2214 pcolor = fcolor = args
2215 pcolor = self._colorstr(pcolor)
2216 fcolor = self._colorstr(fcolor)
2217 self.pen(pencolor=pcolor, fillcolor=fcolor)
2218 else:
2219 return self._color(self._pencolor), self._color(self._fillcolor)
2220
2221 def pencolor(self, *args):
2222 """ Return or set the pencolor.
2223
2224 Arguments:
2225 Four input formats are allowed:
2226 - pencolor()
2227 Return the current pencolor as color specification string,
2228 possibly in hex-number format (see example).
2229 May be used as input to another color/pencolor/fillcolor call.
2230 - pencolor(colorstring)
2231 s is a Tk color specification string, such as "red" or "yellow"
2232 - pencolor((r, g, b))
2233 *a tuple* of r, g, and b, which represent, an RGB color,
2234 and each of r, g, and b are in the range 0..colormode,
2235 where colormode is either 1.0 or 255
2236 - pencolor(r, g, b)
2237 r, g, and b represent an RGB color, and each of r, g, and b
2238 are in the range 0..colormode
2239
2240 If turtleshape is a polygon, the outline of that polygon is drawn
2241 with the newly set pencolor.
2242
2243 Example (for a Turtle instance named turtle):
2244 >>> turtle.pencolor('brown')
2245 >>> tup = (0.2, 0.8, 0.55)
2246 >>> turtle.pencolor(tup)
2247 >>> turtle.pencolor()
2248 '#33cc8c'
2249 """
2250 if args:
2251 color = self._colorstr(args)
2252 if color == self._pencolor:
2253 return
2254 self.pen(pencolor=color)
2255 else:
2256 return self._color(self._pencolor)
2257
2258 def fillcolor(self, *args):
2259 """ Return or set the fillcolor.
2260
2261 Arguments:
2262 Four input formats are allowed:
2263 - fillcolor()
2264 Return the current fillcolor as color specification string,
2265 possibly in hex-number format (see example).
2266 May be used as input to another color/pencolor/fillcolor call.
2267 - fillcolor(colorstring)
2268 s is a Tk color specification string, such as "red" or "yellow"
2269 - fillcolor((r, g, b))
2270 *a tuple* of r, g, and b, which represent, an RGB color,
2271 and each of r, g, and b are in the range 0..colormode,
2272 where colormode is either 1.0 or 255
2273 - fillcolor(r, g, b)
2274 r, g, and b represent an RGB color, and each of r, g, and b
2275 are in the range 0..colormode
2276
2277 If turtleshape is a polygon, the interior of that polygon is drawn
2278 with the newly set fillcolor.
2279
2280 Example (for a Turtle instance named turtle):
2281 >>> turtle.fillcolor('violet')
2282 >>> col = turtle.pencolor()
2283 >>> turtle.fillcolor(col)
2284 >>> turtle.fillcolor(0, .5, 0)
2285 """
2286 if args:
2287 color = self._colorstr(args)
2288 if color == self._fillcolor:
2289 return
2290 self.pen(fillcolor=color)
2291 else:
2292 return self._color(self._fillcolor)
2293
2294 def showturtle(self):
2295 """Makes the turtle visible.
2296
2297 Aliases: showturtle | st
2298
2299 No argument.
2300
2301 Example (for a Turtle instance named turtle):
2302 >>> turtle.hideturtle()
2303 >>> turtle.showturtle()
2304 """
2305 self.pen(shown=True)
2306
2307 def hideturtle(self):
2308 """Makes the turtle invisible.
2309
2310 Aliases: hideturtle | ht
2311
2312 No argument.
2313
2314 It's a good idea to do this while you're in the
2315 middle of a complicated drawing, because hiding
2316 the turtle speeds up the drawing observably.
2317
2318 Example (for a Turtle instance named turtle):
2319 >>> turtle.hideturtle()
2320 """
2321 self.pen(shown=False)
2322
2323 def isvisible(self):
2324 """Return True if the Turtle is shown, False if it's hidden.
2325
2326 No argument.
2327
2328 Example (for a Turtle instance named turtle):
2329 >>> turtle.hideturtle()
2330 >>> print turtle.isvisible():
2331 False
2332 """
2333 return self._shown
2334
2335 def pen(self, pen=None, **pendict):
2336 """Return or set the pen's attributes.
2337
2338 Arguments:
2339 pen -- a dictionary with some or all of the below listed keys.
2340 **pendict -- one or more keyword-arguments with the below
2341 listed keys as keywords.
2342
2343 Return or set the pen's attributes in a 'pen-dictionary'
2344 with the following key/value pairs:
2345 "shown" : True/False
2346 "pendown" : True/False
2347 "pencolor" : color-string or color-tuple
2348 "fillcolor" : color-string or color-tuple
2349 "pensize" : positive number
2350 "speed" : number in range 0..10
2351 "resizemode" : "auto" or "user" or "noresize"
2352 "stretchfactor": (positive number, positive number)
Georg Brandleaa84ef2009-05-05 08:14:33 +00002353 "shearfactor": number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002354 "outline" : positive number
2355 "tilt" : number
2356
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002357 This dictionary can be used as argument for a subsequent
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002358 pen()-call to restore the former pen-state. Moreover one
2359 or more of these attributes can be provided as keyword-arguments.
2360 This can be used to set several pen attributes in one statement.
Guido van Rossumb241b671998-12-04 16:42:46 +00002361
2362
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002363 Examples (for a Turtle instance named turtle):
2364 >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
2365 >>> turtle.pen()
2366 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2367 'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002368 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002369 >>> penstate=turtle.pen()
2370 >>> turtle.color("yellow","")
2371 >>> turtle.penup()
2372 >>> turtle.pen()
2373 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2374 'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002375 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002376 >>> p.pen(penstate, fillcolor="green")
2377 >>> p.pen()
2378 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2379 'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002380 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002381 """
2382 _pd = {"shown" : self._shown,
2383 "pendown" : self._drawing,
2384 "pencolor" : self._pencolor,
2385 "fillcolor" : self._fillcolor,
2386 "pensize" : self._pensize,
2387 "speed" : self._speed,
2388 "resizemode" : self._resizemode,
2389 "stretchfactor" : self._stretchfactor,
Georg Brandleaa84ef2009-05-05 08:14:33 +00002390 "shearfactor" : self._shearfactor,
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002391 "outline" : self._outlinewidth,
2392 "tilt" : self._tilt
2393 }
Guido van Rossumb241b671998-12-04 16:42:46 +00002394
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002395 if not (pen or pendict):
2396 return _pd
2397
2398 if isinstance(pen, dict):
2399 p = pen
2400 else:
2401 p = {}
2402 p.update(pendict)
2403
2404 _p_buf = {}
2405 for key in p:
2406 _p_buf[key] = _pd[key]
2407
2408 if self.undobuffer:
2409 self.undobuffer.push(("pen", _p_buf))
2410
2411 newLine = False
2412 if "pendown" in p:
2413 if self._drawing != p["pendown"]:
2414 newLine = True
2415 if "pencolor" in p:
2416 if isinstance(p["pencolor"], tuple):
2417 p["pencolor"] = self._colorstr((p["pencolor"],))
2418 if self._pencolor != p["pencolor"]:
2419 newLine = True
2420 if "pensize" in p:
2421 if self._pensize != p["pensize"]:
2422 newLine = True
2423 if newLine:
2424 self._newLine()
2425 if "pendown" in p:
2426 self._drawing = p["pendown"]
2427 if "pencolor" in p:
2428 self._pencolor = p["pencolor"]
2429 if "pensize" in p:
2430 self._pensize = p["pensize"]
2431 if "fillcolor" in p:
2432 if isinstance(p["fillcolor"], tuple):
2433 p["fillcolor"] = self._colorstr((p["fillcolor"],))
2434 self._fillcolor = p["fillcolor"]
2435 if "speed" in p:
2436 self._speed = p["speed"]
2437 if "resizemode" in p:
2438 self._resizemode = p["resizemode"]
2439 if "stretchfactor" in p:
2440 sf = p["stretchfactor"]
2441 if isinstance(sf, (int, float)):
2442 sf = (sf, sf)
2443 self._stretchfactor = sf
Georg Brandleaa84ef2009-05-05 08:14:33 +00002444 if "shearfactor" in p:
2445 self._shearfactor = p["shearfactor"]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002446 if "outline" in p:
2447 self._outlinewidth = p["outline"]
2448 if "shown" in p:
2449 self._shown = p["shown"]
2450 if "tilt" in p:
2451 self._tilt = p["tilt"]
Georg Brandleaa84ef2009-05-05 08:14:33 +00002452 if "stretchfactor" in p or "tilt" in p or "shearfactor" in p:
2453 scx, scy = self._stretchfactor
2454 shf = self._shearfactor
2455 sa, ca = math.sin(self._tilt), math.cos(self._tilt)
2456 self._shapetrafo = ( scx*ca, scy*(shf*ca + sa),
2457 -scx*sa, scy*(ca - shf*sa))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002458 self._update()
2459
2460## three dummy methods to be implemented by child class:
2461
2462 def _newLine(self, usePos = True):
2463 """dummy method - to be overwritten by child class"""
2464 def _update(self, count=True, forced=False):
2465 """dummy method - to be overwritten by child class"""
2466 def _color(self, args):
2467 """dummy method - to be overwritten by child class"""
2468 def _colorstr(self, args):
2469 """dummy method - to be overwritten by child class"""
2470
2471 width = pensize
2472 up = penup
2473 pu = penup
2474 pd = pendown
2475 down = pendown
2476 st = showturtle
2477 ht = hideturtle
2478
2479
2480class _TurtleImage(object):
2481 """Helper class: Datatype to store Turtle attributes
2482 """
2483
2484 def __init__(self, screen, shapeIndex):
2485 self.screen = screen
2486 self._type = None
2487 self._setshape(shapeIndex)
2488
2489 def _setshape(self, shapeIndex):
Georg Brandleaa84ef2009-05-05 08:14:33 +00002490 screen = self.screen
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002491 self.shapeIndex = shapeIndex
2492 if self._type == "polygon" == screen._shapes[shapeIndex]._type:
2493 return
2494 if self._type == "image" == screen._shapes[shapeIndex]._type:
2495 return
2496 if self._type in ["image", "polygon"]:
2497 screen._delete(self._item)
2498 elif self._type == "compound":
2499 for item in self._item:
2500 screen._delete(item)
2501 self._type = screen._shapes[shapeIndex]._type
2502 if self._type == "polygon":
2503 self._item = screen._createpoly()
2504 elif self._type == "image":
2505 self._item = screen._createimage(screen._shapes["blank"]._data)
2506 elif self._type == "compound":
2507 self._item = [screen._createpoly() for item in
2508 screen._shapes[shapeIndex]._data]
2509
2510
2511class RawTurtle(TPen, TNavigator):
2512 """Animation part of the RawTurtle.
2513 Puts RawTurtle upon a TurtleScreen and provides tools for
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002514 its animation.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002515 """
2516 screens = []
2517
2518 def __init__(self, canvas=None,
2519 shape=_CFG["shape"],
2520 undobuffersize=_CFG["undobuffersize"],
2521 visible=_CFG["visible"]):
Martin v. Löwis601149b2008-09-29 22:19:08 +00002522 if isinstance(canvas, _Screen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002523 self.screen = canvas
2524 elif isinstance(canvas, TurtleScreen):
2525 if canvas not in RawTurtle.screens:
2526 RawTurtle.screens.append(canvas)
2527 self.screen = canvas
2528 elif isinstance(canvas, (ScrolledCanvas, Canvas)):
2529 for screen in RawTurtle.screens:
2530 if screen.cv == canvas:
2531 self.screen = screen
2532 break
2533 else:
2534 self.screen = TurtleScreen(canvas)
2535 RawTurtle.screens.append(self.screen)
2536 else:
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03002537 raise TurtleGraphicsError("bad canvas argument %s" % canvas)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002538
2539 screen = self.screen
2540 TNavigator.__init__(self, screen.mode())
2541 TPen.__init__(self)
2542 screen._turtles.append(self)
2543 self.drawingLineItem = screen._createline()
2544 self.turtle = _TurtleImage(screen, shape)
2545 self._poly = None
2546 self._creatingPoly = False
2547 self._fillitem = self._fillpath = None
2548 self._shown = visible
2549 self._hidden_from_screen = False
2550 self.currentLineItem = screen._createline()
2551 self.currentLine = [self._position]
2552 self.items = [self.currentLineItem]
2553 self.stampItems = []
2554 self._undobuffersize = undobuffersize
2555 self.undobuffer = Tbuffer(undobuffersize)
2556 self._update()
2557
2558 def reset(self):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002559 """Delete the turtle's drawings and restore its default values.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002560
2561 No argument.
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002562
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002563 Delete the turtle's drawings from the screen, re-center the turtle
2564 and set variables to the default values.
2565
2566 Example (for a Turtle instance named turtle):
2567 >>> turtle.position()
2568 (0.00,-22.00)
2569 >>> turtle.heading()
2570 100.0
2571 >>> turtle.reset()
2572 >>> turtle.position()
2573 (0.00,0.00)
2574 >>> turtle.heading()
2575 0.0
2576 """
2577 TNavigator.reset(self)
2578 TPen._reset(self)
2579 self._clear()
2580 self._drawturtle()
2581 self._update()
2582
2583 def setundobuffer(self, size):
2584 """Set or disable undobuffer.
2585
2586 Argument:
2587 size -- an integer or None
2588
2589 If size is an integer an empty undobuffer of given size is installed.
2590 Size gives the maximum number of turtle-actions that can be undone
2591 by the undo() function.
2592 If size is None, no undobuffer is present.
2593
2594 Example (for a Turtle instance named turtle):
2595 >>> turtle.setundobuffer(42)
2596 """
2597 if size is None:
2598 self.undobuffer = None
2599 else:
2600 self.undobuffer = Tbuffer(size)
2601
2602 def undobufferentries(self):
2603 """Return count of entries in the undobuffer.
2604
2605 No argument.
2606
2607 Example (for a Turtle instance named turtle):
2608 >>> while undobufferentries():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002609 ... undo()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002610 """
2611 if self.undobuffer is None:
2612 return 0
2613 return self.undobuffer.nr_of_items()
2614
2615 def _clear(self):
2616 """Delete all of pen's drawings"""
2617 self._fillitem = self._fillpath = None
2618 for item in self.items:
2619 self.screen._delete(item)
2620 self.currentLineItem = self.screen._createline()
2621 self.currentLine = []
2622 if self._drawing:
2623 self.currentLine.append(self._position)
2624 self.items = [self.currentLineItem]
2625 self.clearstamps()
2626 self.setundobuffer(self._undobuffersize)
2627
2628
2629 def clear(self):
2630 """Delete the turtle's drawings from the screen. Do not move turtle.
2631
2632 No arguments.
2633
2634 Delete the turtle's drawings from the screen. Do not move turtle.
2635 State and position of the turtle as well as drawings of other
2636 turtles are not affected.
2637
2638 Examples (for a Turtle instance named turtle):
2639 >>> turtle.clear()
2640 """
2641 self._clear()
2642 self._update()
2643
2644 def _update_data(self):
2645 self.screen._incrementudc()
2646 if self.screen._updatecounter != 0:
2647 return
2648 if len(self.currentLine)>1:
2649 self.screen._drawline(self.currentLineItem, self.currentLine,
2650 self._pencolor, self._pensize)
2651
2652 def _update(self):
2653 """Perform a Turtle-data update.
2654 """
2655 screen = self.screen
2656 if screen._tracing == 0:
2657 return
2658 elif screen._tracing == 1:
2659 self._update_data()
2660 self._drawturtle()
2661 screen._update() # TurtleScreenBase
2662 screen._delay(screen._delayvalue) # TurtleScreenBase
2663 else:
2664 self._update_data()
2665 if screen._updatecounter == 0:
2666 for t in screen.turtles():
2667 t._drawturtle()
2668 screen._update()
2669
2670 def _tracer(self, flag=None, delay=None):
2671 """Turns turtle animation on/off and set delay for update drawings.
2672
2673 Optional arguments:
2674 n -- nonnegative integer
2675 delay -- nonnegative integer
2676
2677 If n is given, only each n-th regular screen update is really performed.
2678 (Can be used to accelerate the drawing of complex graphics.)
2679 Second arguments sets delay value (see RawTurtle.delay())
2680
2681 Example (for a Turtle instance named turtle):
2682 >>> turtle.tracer(8, 25)
2683 >>> dist = 2
2684 >>> for i in range(200):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002685 ... turtle.fd(dist)
2686 ... turtle.rt(90)
2687 ... dist += 2
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002688 """
2689 return self.screen.tracer(flag, delay)
2690
2691 def _color(self, args):
2692 return self.screen._color(args)
2693
2694 def _colorstr(self, args):
2695 return self.screen._colorstr(args)
2696
2697 def _cc(self, args):
2698 """Convert colortriples to hexstrings.
2699 """
2700 if isinstance(args, str):
2701 return args
2702 try:
2703 r, g, b = args
2704 except:
2705 raise TurtleGraphicsError("bad color arguments: %s" % str(args))
2706 if self.screen._colormode == 1.0:
2707 r, g, b = [round(255.0*x) for x in (r, g, b)]
2708 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
2709 raise TurtleGraphicsError("bad color sequence: %s" % str(args))
2710 return "#%02x%02x%02x" % (r, g, b)
2711
2712 def clone(self):
2713 """Create and return a clone of the turtle.
2714
2715 No argument.
2716
2717 Create and return a clone of the turtle with same position, heading
2718 and turtle properties.
2719
2720 Example (for a Turtle instance named mick):
2721 mick = Turtle()
2722 joe = mick.clone()
2723 """
2724 screen = self.screen
2725 self._newLine(self._drawing)
2726
2727 turtle = self.turtle
2728 self.screen = None
2729 self.turtle = None # too make self deepcopy-able
2730
2731 q = deepcopy(self)
2732
2733 self.screen = screen
2734 self.turtle = turtle
2735
2736 q.screen = screen
2737 q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
2738
2739 screen._turtles.append(q)
2740 ttype = screen._shapes[self.turtle.shapeIndex]._type
2741 if ttype == "polygon":
2742 q.turtle._item = screen._createpoly()
2743 elif ttype == "image":
2744 q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
2745 elif ttype == "compound":
2746 q.turtle._item = [screen._createpoly() for item in
2747 screen._shapes[self.turtle.shapeIndex]._data]
2748 q.currentLineItem = screen._createline()
2749 q._update()
2750 return q
2751
2752 def shape(self, name=None):
2753 """Set turtle shape to shape with given name / return current shapename.
2754
2755 Optional argument:
2756 name -- a string, which is a valid shapename
2757
2758 Set turtle shape to shape with given name or, if name is not given,
2759 return name of current shape.
2760 Shape with name must exist in the TurtleScreen's shape dictionary.
2761 Initially there are the following polygon shapes:
2762 'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
2763 To learn about how to deal with shapes see Screen-method register_shape.
2764
2765 Example (for a Turtle instance named turtle):
2766 >>> turtle.shape()
2767 'arrow'
2768 >>> turtle.shape("turtle")
2769 >>> turtle.shape()
2770 'turtle'
2771 """
2772 if name is None:
2773 return self.turtle.shapeIndex
2774 if not name in self.screen.getshapes():
2775 raise TurtleGraphicsError("There is no shape named %s" % name)
2776 self.turtle._setshape(name)
2777 self._update()
2778
2779 def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
2780 """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
2781
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03002782 Optional arguments:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002783 stretch_wid : positive number
2784 stretch_len : positive number
2785 outline : positive number
2786
2787 Return or set the pen's attributes x/y-stretchfactors and/or outline.
2788 Set resizemode to "user".
2789 If and only if resizemode is set to "user", the turtle will be displayed
2790 stretched according to its stretchfactors:
2791 stretch_wid is stretchfactor perpendicular to orientation
2792 stretch_len is stretchfactor in direction of turtles orientation.
2793 outline determines the width of the shapes's outline.
2794
2795 Examples (for a Turtle instance named turtle):
2796 >>> turtle.resizemode("user")
2797 >>> turtle.shapesize(5, 5, 12)
2798 >>> turtle.shapesize(outline=8)
2799 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00002800 if stretch_wid is stretch_len is outline is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002801 stretch_wid, stretch_len = self._stretchfactor
2802 return stretch_wid, stretch_len, self._outlinewidth
Georg Brandleaa84ef2009-05-05 08:14:33 +00002803 if stretch_wid == 0 or stretch_len == 0:
2804 raise TurtleGraphicsError("stretch_wid/stretch_len must not be zero")
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002805 if stretch_wid is not None:
2806 if stretch_len is None:
2807 stretchfactor = stretch_wid, stretch_wid
2808 else:
2809 stretchfactor = stretch_wid, stretch_len
2810 elif stretch_len is not None:
2811 stretchfactor = self._stretchfactor[0], stretch_len
2812 else:
2813 stretchfactor = self._stretchfactor
2814 if outline is None:
2815 outline = self._outlinewidth
2816 self.pen(resizemode="user",
2817 stretchfactor=stretchfactor, outline=outline)
2818
Georg Brandleaa84ef2009-05-05 08:14:33 +00002819 def shearfactor(self, shear=None):
2820 """Set or return the current shearfactor.
2821
2822 Optional argument: shear -- number, tangent of the shear angle
2823
2824 Shear the turtleshape according to the given shearfactor shear,
2825 which is the tangent of the shear angle. DO NOT change the
2826 turtle's heading (direction of movement).
2827 If shear is not given: return the current shearfactor, i. e. the
2828 tangent of the shear angle, by which lines parallel to the
2829 heading of the turtle are sheared.
2830
2831 Examples (for a Turtle instance named turtle):
2832 >>> turtle.shape("circle")
2833 >>> turtle.shapesize(5,2)
2834 >>> turtle.shearfactor(0.5)
2835 >>> turtle.shearfactor()
2836 >>> 0.5
2837 """
2838 if shear is None:
2839 return self._shearfactor
2840 self.pen(resizemode="user", shearfactor=shear)
2841
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002842 def settiltangle(self, angle):
2843 """Rotate the turtleshape to point in the specified direction
2844
Georg Brandleaa84ef2009-05-05 08:14:33 +00002845 Argument: angle -- number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002846
2847 Rotate the turtleshape to point in the direction specified by angle,
2848 regardless of its current tilt-angle. DO NOT change the turtle's
2849 heading (direction of movement).
2850
2851
2852 Examples (for a Turtle instance named turtle):
2853 >>> turtle.shape("circle")
2854 >>> turtle.shapesize(5,2)
2855 >>> turtle.settiltangle(45)
2856 >>> stamp()
2857 >>> turtle.fd(50)
2858 >>> turtle.settiltangle(-45)
2859 >>> stamp()
2860 >>> turtle.fd(50)
2861 """
2862 tilt = -angle * self._degreesPerAU * self._angleOrient
2863 tilt = (tilt * math.pi / 180.0) % (2*math.pi)
2864 self.pen(resizemode="user", tilt=tilt)
2865
Georg Brandleaa84ef2009-05-05 08:14:33 +00002866 def tiltangle(self, angle=None):
2867 """Set or return the current tilt-angle.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002868
Georg Brandleaa84ef2009-05-05 08:14:33 +00002869 Optional argument: angle -- number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002870
Georg Brandleaa84ef2009-05-05 08:14:33 +00002871 Rotate the turtleshape to point in the direction specified by angle,
2872 regardless of its current tilt-angle. DO NOT change the turtle's
2873 heading (direction of movement).
2874 If angle is not given: return the current tilt-angle, i. e. the angle
2875 between the orientation of the turtleshape and the heading of the
2876 turtle (its direction of movement).
2877
2878 Deprecated since Python 3.1
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002879
2880 Examples (for a Turtle instance named turtle):
2881 >>> turtle.shape("circle")
2882 >>> turtle.shapesize(5,2)
2883 >>> turtle.tilt(45)
2884 >>> turtle.tiltangle()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002885 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00002886 if angle is None:
2887 tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
2888 return (tilt / self._degreesPerAU) % self._fullcircle
2889 else:
2890 self.settiltangle(angle)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002891
2892 def tilt(self, angle):
2893 """Rotate the turtleshape by angle.
2894
2895 Argument:
2896 angle - a number
2897
2898 Rotate the turtleshape by angle from its current tilt-angle,
2899 but do NOT change the turtle's heading (direction of movement).
2900
2901 Examples (for a Turtle instance named turtle):
2902 >>> turtle.shape("circle")
2903 >>> turtle.shapesize(5,2)
2904 >>> turtle.tilt(30)
2905 >>> turtle.fd(50)
2906 >>> turtle.tilt(30)
2907 >>> turtle.fd(50)
2908 """
2909 self.settiltangle(angle + self.tiltangle())
2910
Georg Brandleaa84ef2009-05-05 08:14:33 +00002911 def shapetransform(self, t11=None, t12=None, t21=None, t22=None):
2912 """Set or return the current transformation matrix of the turtle shape.
2913
2914 Optional arguments: t11, t12, t21, t22 -- numbers.
2915
2916 If none of the matrix elements are given, return the transformation
2917 matrix.
2918 Otherwise set the given elements and transform the turtleshape
2919 according to the matrix consisting of first row t11, t12 and
2920 second row t21, 22.
2921 Modify stretchfactor, shearfactor and tiltangle according to the
2922 given matrix.
2923
2924 Examples (for a Turtle instance named turtle):
2925 >>> turtle.shape("square")
2926 >>> turtle.shapesize(4,2)
2927 >>> turtle.shearfactor(-0.5)
2928 >>> turtle.shapetransform()
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002929 (4.0, -1.0, -0.0, 2.0)
Georg Brandleaa84ef2009-05-05 08:14:33 +00002930 """
2931 if t11 is t12 is t21 is t22 is None:
2932 return self._shapetrafo
2933 m11, m12, m21, m22 = self._shapetrafo
2934 if t11 is not None: m11 = t11
2935 if t12 is not None: m12 = t12
2936 if t21 is not None: m21 = t21
2937 if t22 is not None: m22 = t22
2938 if t11 * t22 - t12 * t21 == 0:
2939 raise TurtleGraphicsError("Bad shape transform matrix: must not be singular")
2940 self._shapetrafo = (m11, m12, m21, m22)
2941 alfa = math.atan2(-m21, m11) % (2 * math.pi)
2942 sa, ca = math.sin(alfa), math.cos(alfa)
2943 a11, a12, a21, a22 = (ca*m11 - sa*m21, ca*m12 - sa*m22,
2944 sa*m11 + ca*m21, sa*m12 + ca*m22)
2945 self._stretchfactor = a11, a22
2946 self._shearfactor = a12/a22
2947 self._tilt = alfa
2948 self._update()
2949
2950
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002951 def _polytrafo(self, poly):
2952 """Computes transformed polygon shapes from a shape
2953 according to current position and heading.
2954 """
2955 screen = self.screen
2956 p0, p1 = self._position
2957 e0, e1 = self._orient
2958 e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
2959 e0, e1 = (1.0 / abs(e)) * e
2960 return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
2961 for (x, y) in poly]
2962
Georg Brandleaa84ef2009-05-05 08:14:33 +00002963 def get_shapepoly(self):
2964 """Return the current shape polygon as tuple of coordinate pairs.
2965
2966 No argument.
2967
2968 Examples (for a Turtle instance named turtle):
2969 >>> turtle.shape("square")
2970 >>> turtle.shapetransform(4, -1, 0, 2)
2971 >>> turtle.get_shapepoly()
2972 ((50, -20), (30, 20), (-50, 20), (-30, -20))
2973
2974 """
2975 shape = self.screen._shapes[self.turtle.shapeIndex]
2976 if shape._type == "polygon":
2977 return self._getshapepoly(shape._data, shape._type == "compound")
2978 # else return None
2979
2980 def _getshapepoly(self, polygon, compound=False):
2981 """Calculate transformed shape polygon according to resizemode
2982 and shapetransform.
2983 """
2984 if self._resizemode == "user" or compound:
2985 t11, t12, t21, t22 = self._shapetrafo
2986 elif self._resizemode == "auto":
2987 l = max(1, self._pensize/5.0)
2988 t11, t12, t21, t22 = l, 0, 0, l
2989 elif self._resizemode == "noresize":
2990 return polygon
2991 return tuple([(t11*x + t12*y, t21*x + t22*y) for (x, y) in polygon])
2992
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002993 def _drawturtle(self):
2994 """Manages the correct rendering of the turtle with respect to
Mark Dickinson934896d2009-02-21 20:59:32 +00002995 its shape, resizemode, stretch and tilt etc."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002996 screen = self.screen
2997 shape = screen._shapes[self.turtle.shapeIndex]
2998 ttype = shape._type
2999 titem = self.turtle._item
3000 if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
3001 self._hidden_from_screen = False
3002 tshape = shape._data
3003 if ttype == "polygon":
Georg Brandleaa84ef2009-05-05 08:14:33 +00003004 if self._resizemode == "noresize": w = 1
3005 elif self._resizemode == "auto": w = self._pensize
3006 else: w =self._outlinewidth
3007 shape = self._polytrafo(self._getshapepoly(tshape))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003008 fc, oc = self._fillcolor, self._pencolor
3009 screen._drawpoly(titem, shape, fill=fc, outline=oc,
3010 width=w, top=True)
3011 elif ttype == "image":
3012 screen._drawimage(titem, self._position, tshape)
3013 elif ttype == "compound":
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003014 for item, (poly, fc, oc) in zip(titem, tshape):
Georg Brandleaa84ef2009-05-05 08:14:33 +00003015 poly = self._polytrafo(self._getshapepoly(poly, True))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003016 screen._drawpoly(item, poly, fill=self._cc(fc),
Georg Brandleaa84ef2009-05-05 08:14:33 +00003017 outline=self._cc(oc), width=self._outlinewidth, top=True)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003018 else:
3019 if self._hidden_from_screen:
3020 return
3021 if ttype == "polygon":
3022 screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
3023 elif ttype == "image":
3024 screen._drawimage(titem, self._position,
3025 screen._shapes["blank"]._data)
3026 elif ttype == "compound":
3027 for item in titem:
3028 screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
3029 self._hidden_from_screen = True
3030
3031############################## stamp stuff ###############################
3032
3033 def stamp(self):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00003034 """Stamp a copy of the turtleshape onto the canvas and return its id.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003035
3036 No argument.
3037
3038 Stamp a copy of the turtle shape onto the canvas at the current
3039 turtle position. Return a stamp_id for that stamp, which can be
3040 used to delete it by calling clearstamp(stamp_id).
3041
3042 Example (for a Turtle instance named turtle):
3043 >>> turtle.color("blue")
3044 >>> turtle.stamp()
3045 13
3046 >>> turtle.fd(50)
3047 """
3048 screen = self.screen
3049 shape = screen._shapes[self.turtle.shapeIndex]
3050 ttype = shape._type
3051 tshape = shape._data
3052 if ttype == "polygon":
3053 stitem = screen._createpoly()
Georg Brandleaa84ef2009-05-05 08:14:33 +00003054 if self._resizemode == "noresize": w = 1
3055 elif self._resizemode == "auto": w = self._pensize
3056 else: w =self._outlinewidth
3057 shape = self._polytrafo(self._getshapepoly(tshape))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003058 fc, oc = self._fillcolor, self._pencolor
3059 screen._drawpoly(stitem, shape, fill=fc, outline=oc,
3060 width=w, top=True)
3061 elif ttype == "image":
3062 stitem = screen._createimage("")
3063 screen._drawimage(stitem, self._position, tshape)
3064 elif ttype == "compound":
3065 stitem = []
3066 for element in tshape:
3067 item = screen._createpoly()
3068 stitem.append(item)
3069 stitem = tuple(stitem)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003070 for item, (poly, fc, oc) in zip(stitem, tshape):
Georg Brandleaa84ef2009-05-05 08:14:33 +00003071 poly = self._polytrafo(self._getshapepoly(poly, True))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003072 screen._drawpoly(item, poly, fill=self._cc(fc),
Georg Brandleaa84ef2009-05-05 08:14:33 +00003073 outline=self._cc(oc), width=self._outlinewidth, top=True)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003074 self.stampItems.append(stitem)
3075 self.undobuffer.push(("stamp", stitem))
3076 return stitem
3077
3078 def _clearstamp(self, stampid):
3079 """does the work for clearstamp() and clearstamps()
3080 """
3081 if stampid in self.stampItems:
3082 if isinstance(stampid, tuple):
3083 for subitem in stampid:
3084 self.screen._delete(subitem)
3085 else:
3086 self.screen._delete(stampid)
3087 self.stampItems.remove(stampid)
3088 # Delete stampitem from undobuffer if necessary
3089 # if clearstamp is called directly.
3090 item = ("stamp", stampid)
3091 buf = self.undobuffer
3092 if item not in buf.buffer:
3093 return
3094 index = buf.buffer.index(item)
3095 buf.buffer.remove(item)
3096 if index <= buf.ptr:
3097 buf.ptr = (buf.ptr - 1) % buf.bufsize
3098 buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
3099
3100 def clearstamp(self, stampid):
3101 """Delete stamp with given stampid
3102
3103 Argument:
3104 stampid - an integer, must be return value of previous stamp() call.
3105
3106 Example (for a Turtle instance named turtle):
3107 >>> turtle.color("blue")
3108 >>> astamp = turtle.stamp()
3109 >>> turtle.fd(50)
3110 >>> turtle.clearstamp(astamp)
3111 """
3112 self._clearstamp(stampid)
3113 self._update()
3114
3115 def clearstamps(self, n=None):
3116 """Delete all or first/last n of turtle's stamps.
3117
3118 Optional argument:
3119 n -- an integer
3120
3121 If n is None, delete all of pen's stamps,
3122 else if n > 0 delete first n stamps
3123 else if n < 0 delete last n stamps.
3124
3125 Example (for a Turtle instance named turtle):
3126 >>> for i in range(8):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003127 ... turtle.stamp(); turtle.fd(30)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003128 ...
3129 >>> turtle.clearstamps(2)
3130 >>> turtle.clearstamps(-2)
3131 >>> turtle.clearstamps()
3132 """
3133 if n is None:
3134 toDelete = self.stampItems[:]
3135 elif n >= 0:
3136 toDelete = self.stampItems[:n]
3137 else:
3138 toDelete = self.stampItems[n:]
3139 for item in toDelete:
3140 self._clearstamp(item)
3141 self._update()
3142
3143 def _goto(self, end):
3144 """Move the pen to the point end, thereby drawing a line
Ezio Melotti30b9d5d2013-08-17 15:50:46 +03003145 if pen is down. All other methods for turtle movement depend
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003146 on this one.
3147 """
Alexander Belopolsky1842d0c2010-10-28 20:13:52 +00003148 ## Version with undo-stuff
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003149 go_modes = ( self._drawing,
3150 self._pencolor,
3151 self._pensize,
3152 isinstance(self._fillpath, list))
3153 screen = self.screen
3154 undo_entry = ("go", self._position, end, go_modes,
3155 (self.currentLineItem,
3156 self.currentLine[:],
3157 screen._pointlist(self.currentLineItem),
3158 self.items[:])
3159 )
3160 if self.undobuffer:
3161 self.undobuffer.push(undo_entry)
3162 start = self._position
3163 if self._speed and screen._tracing == 1:
3164 diff = (end-start)
3165 diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3166 nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3167 delta = diff * (1.0/nhops)
3168 for n in range(1, nhops):
3169 if n == 1:
3170 top = True
3171 else:
3172 top = False
3173 self._position = start + delta * n
3174 if self._drawing:
3175 screen._drawline(self.drawingLineItem,
3176 (start, self._position),
3177 self._pencolor, self._pensize, top)
3178 self._update()
3179 if self._drawing:
3180 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3181 fill="", width=self._pensize)
3182 # Turtle now at end,
3183 if self._drawing: # now update currentLine
3184 self.currentLine.append(end)
3185 if isinstance(self._fillpath, list):
3186 self._fillpath.append(end)
3187 ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
3188 self._position = end
3189 if self._creatingPoly:
3190 self._poly.append(end)
3191 if len(self.currentLine) > 42: # 42! answer to the ultimate question
3192 # of life, the universe and everything
3193 self._newLine()
3194 self._update() #count=True)
3195
3196 def _undogoto(self, entry):
3197 """Reverse a _goto. Used for undo()
3198 """
3199 old, new, go_modes, coodata = entry
3200 drawing, pc, ps, filling = go_modes
3201 cLI, cL, pl, items = coodata
3202 screen = self.screen
3203 if abs(self._position - new) > 0.5:
3204 print ("undogoto: HALLO-DA-STIMMT-WAS-NICHT!")
3205 # restore former situation
3206 self.currentLineItem = cLI
3207 self.currentLine = cL
3208
3209 if pl == [(0, 0), (0, 0)]:
3210 usepc = ""
3211 else:
3212 usepc = pc
3213 screen._drawline(cLI, pl, fill=usepc, width=ps)
3214
3215 todelete = [i for i in self.items if (i not in items) and
3216 (screen._type(i) == "line")]
3217 for i in todelete:
3218 screen._delete(i)
3219 self.items.remove(i)
3220
3221 start = old
3222 if self._speed and screen._tracing == 1:
3223 diff = old - new
3224 diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3225 nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3226 delta = diff * (1.0/nhops)
3227 for n in range(1, nhops):
3228 if n == 1:
3229 top = True
3230 else:
3231 top = False
3232 self._position = new + delta * n
3233 if drawing:
3234 screen._drawline(self.drawingLineItem,
3235 (start, self._position),
3236 pc, ps, top)
3237 self._update()
3238 if drawing:
3239 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3240 fill="", width=ps)
3241 # Turtle now at position old,
3242 self._position = old
Ezio Melotti13925002011-03-16 11:05:33 +02003243 ## if undo is done during creating a polygon, the last vertex
3244 ## will be deleted. if the polygon is entirely deleted,
3245 ## creatingPoly will be set to False.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003246 ## Polygons created before the last one will not be affected by undo()
3247 if self._creatingPoly:
3248 if len(self._poly) > 0:
3249 self._poly.pop()
3250 if self._poly == []:
3251 self._creatingPoly = False
3252 self._poly = None
3253 if filling:
3254 if self._fillpath == []:
3255 self._fillpath = None
3256 print("Unwahrscheinlich in _undogoto!")
3257 elif self._fillpath is not None:
3258 self._fillpath.pop()
3259 self._update() #count=True)
3260
3261 def _rotate(self, angle):
3262 """Turns pen clockwise by angle.
3263 """
3264 if self.undobuffer:
3265 self.undobuffer.push(("rot", angle, self._degreesPerAU))
3266 angle *= self._degreesPerAU
3267 neworient = self._orient.rotate(angle)
3268 tracing = self.screen._tracing
3269 if tracing == 1 and self._speed > 0:
3270 anglevel = 3.0 * self._speed
3271 steps = 1 + int(abs(angle)/anglevel)
3272 delta = 1.0*angle/steps
3273 for _ in range(steps):
3274 self._orient = self._orient.rotate(delta)
3275 self._update()
3276 self._orient = neworient
3277 self._update()
3278
3279 def _newLine(self, usePos=True):
3280 """Closes current line item and starts a new one.
3281 Remark: if current line became too long, animation
3282 performance (via _drawline) slowed down considerably.
3283 """
3284 if len(self.currentLine) > 1:
3285 self.screen._drawline(self.currentLineItem, self.currentLine,
3286 self._pencolor, self._pensize)
3287 self.currentLineItem = self.screen._createline()
3288 self.items.append(self.currentLineItem)
3289 else:
3290 self.screen._drawline(self.currentLineItem, top=True)
3291 self.currentLine = []
3292 if usePos:
3293 self.currentLine = [self._position]
3294
3295 def filling(self):
3296 """Return fillstate (True if filling, False else).
3297
3298 No argument.
3299
3300 Example (for a Turtle instance named turtle):
3301 >>> turtle.begin_fill()
3302 >>> if turtle.filling():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003303 ... turtle.pensize(5)
3304 ... else:
3305 ... turtle.pensize(3)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003306 """
3307 return isinstance(self._fillpath, list)
3308
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003309 def begin_fill(self):
3310 """Called just before drawing a shape to be filled.
3311
3312 No argument.
3313
3314 Example (for a Turtle instance named turtle):
3315 >>> turtle.color("black", "red")
3316 >>> turtle.begin_fill()
3317 >>> turtle.circle(60)
3318 >>> turtle.end_fill()
3319 """
3320 if not self.filling():
3321 self._fillitem = self.screen._createpoly()
3322 self.items.append(self._fillitem)
3323 self._fillpath = [self._position]
3324 self._newLine()
3325 if self.undobuffer:
3326 self.undobuffer.push(("beginfill", self._fillitem))
3327 self._update()
3328
3329
3330 def end_fill(self):
3331 """Fill the shape drawn after the call begin_fill().
3332
3333 No argument.
3334
3335 Example (for a Turtle instance named turtle):
3336 >>> turtle.color("black", "red")
3337 >>> turtle.begin_fill()
3338 >>> turtle.circle(60)
3339 >>> turtle.end_fill()
3340 """
3341 if self.filling():
3342 if len(self._fillpath) > 2:
3343 self.screen._drawpoly(self._fillitem, self._fillpath,
3344 fill=self._fillcolor)
3345 if self.undobuffer:
3346 self.undobuffer.push(("dofill", self._fillitem))
3347 self._fillitem = self._fillpath = None
3348 self._update()
3349
3350 def dot(self, size=None, *color):
3351 """Draw a dot with diameter size, using color.
3352
Ezio Melotti42da6632011-03-15 05:18:48 +02003353 Optional arguments:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003354 size -- an integer >= 1 (if given)
3355 color -- a colorstring or a numeric color tuple
3356
3357 Draw a circular dot with diameter size, using color.
3358 If size is not given, the maximum of pensize+4 and 2*pensize is used.
3359
3360 Example (for a Turtle instance named turtle):
3361 >>> turtle.dot()
3362 >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
3363 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003364 if not color:
3365 if isinstance(size, (str, tuple)):
3366 color = self._colorstr(size)
3367 size = self._pensize + max(self._pensize, 4)
3368 else:
3369 color = self._pencolor
3370 if not size:
3371 size = self._pensize + max(self._pensize, 4)
3372 else:
3373 if size is None:
3374 size = self._pensize + max(self._pensize, 4)
3375 color = self._colorstr(color)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003376 if hasattr(self.screen, "_dot"):
3377 item = self.screen._dot(self._position, size, color)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003378 self.items.append(item)
3379 if self.undobuffer:
3380 self.undobuffer.push(("dot", item))
3381 else:
3382 pen = self.pen()
3383 if self.undobuffer:
3384 self.undobuffer.push(["seq"])
3385 self.undobuffer.cumulate = True
3386 try:
3387 if self.resizemode() == 'auto':
3388 self.ht()
3389 self.pendown()
3390 self.pensize(size)
3391 self.pencolor(color)
3392 self.forward(0)
3393 finally:
3394 self.pen(pen)
3395 if self.undobuffer:
3396 self.undobuffer.cumulate = False
3397
3398 def _write(self, txt, align, font):
3399 """Performs the writing for write()
3400 """
3401 item, end = self.screen._write(self._position, txt, align, font,
3402 self._pencolor)
3403 self.items.append(item)
3404 if self.undobuffer:
3405 self.undobuffer.push(("wri", item))
3406 return end
3407
3408 def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
3409 """Write text at the current turtle position.
3410
3411 Arguments:
3412 arg -- info, which is to be written to the TurtleScreen
3413 move (optional) -- True/False
3414 align (optional) -- one of the strings "left", "center" or right"
3415 font (optional) -- a triple (fontname, fontsize, fonttype)
3416
3417 Write text - the string representation of arg - at the current
3418 turtle position according to align ("left", "center" or right")
3419 and with the given font.
3420 If move is True, the pen is moved to the bottom-right corner
3421 of the text. By default, move is False.
3422
3423 Example (for a Turtle instance named turtle):
3424 >>> turtle.write('Home = ', True, align="center")
3425 >>> turtle.write((0,0), True)
3426 """
3427 if self.undobuffer:
3428 self.undobuffer.push(["seq"])
3429 self.undobuffer.cumulate = True
3430 end = self._write(str(arg), align.lower(), font)
3431 if move:
3432 x, y = self.pos()
3433 self.setpos(end, y)
3434 if self.undobuffer:
3435 self.undobuffer.cumulate = False
3436
3437 def begin_poly(self):
3438 """Start recording the vertices of a polygon.
3439
3440 No argument.
3441
3442 Start recording the vertices of a polygon. Current turtle position
3443 is first point of polygon.
3444
3445 Example (for a Turtle instance named turtle):
3446 >>> turtle.begin_poly()
3447 """
3448 self._poly = [self._position]
3449 self._creatingPoly = True
3450
3451 def end_poly(self):
3452 """Stop recording the vertices of a polygon.
3453
3454 No argument.
3455
3456 Stop recording the vertices of a polygon. Current turtle position is
3457 last point of polygon. This will be connected with the first point.
3458
3459 Example (for a Turtle instance named turtle):
3460 >>> turtle.end_poly()
3461 """
3462 self._creatingPoly = False
3463
3464 def get_poly(self):
3465 """Return the lastly recorded polygon.
3466
3467 No argument.
3468
3469 Example (for a Turtle instance named turtle):
3470 >>> p = turtle.get_poly()
3471 >>> turtle.register_shape("myFavouriteShape", p)
3472 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00003473 ## check if there is any poly?
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003474 if self._poly is not None:
3475 return tuple(self._poly)
3476
3477 def getscreen(self):
3478 """Return the TurtleScreen object, the turtle is drawing on.
3479
3480 No argument.
3481
3482 Return the TurtleScreen object, the turtle is drawing on.
3483 So TurtleScreen-methods can be called for that object.
3484
3485 Example (for a Turtle instance named turtle):
3486 >>> ts = turtle.getscreen()
3487 >>> ts
3488 <turtle.TurtleScreen object at 0x0106B770>
3489 >>> ts.bgcolor("pink")
3490 """
3491 return self.screen
3492
3493 def getturtle(self):
3494 """Return the Turtleobject itself.
3495
3496 No argument.
3497
3498 Only reasonable use: as a function to return the 'anonymous turtle':
3499
3500 Example:
3501 >>> pet = getturtle()
3502 >>> pet.fd(50)
3503 >>> pet
3504 <turtle.Turtle object at 0x0187D810>
3505 >>> turtles()
3506 [<turtle.Turtle object at 0x0187D810>]
3507 """
3508 return self
3509
3510 getpen = getturtle
3511
3512
3513 ################################################################
3514 ### screen oriented methods recurring to methods of TurtleScreen
3515 ################################################################
3516
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003517 def _delay(self, delay=None):
3518 """Set delay value which determines speed of turtle animation.
3519 """
3520 return self.screen.delay(delay)
3521
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003522 def onclick(self, fun, btn=1, add=None):
3523 """Bind fun to mouse-click event on this turtle on canvas.
3524
3525 Arguments:
3526 fun -- a function with two arguments, to which will be assigned
3527 the coordinates of the clicked point on the canvas.
3528 num -- number of the mouse-button defaults to 1 (left mouse button).
3529 add -- True or False. If True, new binding will be added, otherwise
3530 it will replace a former binding.
3531
3532 Example for the anonymous turtle, i. e. the procedural way:
3533
3534 >>> def turn(x, y):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003535 ... left(360)
3536 ...
3537 >>> onclick(turn) # Now clicking into the turtle will turn it.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003538 >>> onclick(None) # event-binding will be removed
3539 """
3540 self.screen._onclick(self.turtle._item, fun, btn, add)
3541 self._update()
3542
3543 def onrelease(self, fun, btn=1, add=None):
3544 """Bind fun to mouse-button-release event on this turtle on canvas.
3545
3546 Arguments:
3547 fun -- a function with two arguments, to which will be assigned
3548 the coordinates of the clicked point on the canvas.
3549 num -- number of the mouse-button defaults to 1 (left mouse button).
3550
3551 Example (for a MyTurtle instance named joe):
3552 >>> class MyTurtle(Turtle):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003553 ... def glow(self,x,y):
3554 ... self.fillcolor("red")
3555 ... def unglow(self,x,y):
3556 ... self.fillcolor("")
3557 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003558 >>> joe = MyTurtle()
3559 >>> joe.onclick(joe.glow)
3560 >>> joe.onrelease(joe.unglow)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003561
3562 Clicking on joe turns fillcolor red, unclicking turns it to
3563 transparent.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003564 """
3565 self.screen._onrelease(self.turtle._item, fun, btn, add)
3566 self._update()
3567
3568 def ondrag(self, fun, btn=1, add=None):
3569 """Bind fun to mouse-move event on this turtle on canvas.
3570
3571 Arguments:
3572 fun -- a function with two arguments, to which will be assigned
3573 the coordinates of the clicked point on the canvas.
3574 num -- number of the mouse-button defaults to 1 (left mouse button).
3575
3576 Every sequence of mouse-move-events on a turtle is preceded by a
3577 mouse-click event on that turtle.
3578
3579 Example (for a Turtle instance named turtle):
3580 >>> turtle.ondrag(turtle.goto)
3581
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003582 Subsequently clicking and dragging a Turtle will move it
3583 across the screen thereby producing handdrawings (if pen is
3584 down).
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003585 """
3586 self.screen._ondrag(self.turtle._item, fun, btn, add)
3587
3588
3589 def _undo(self, action, data):
3590 """Does the main part of the work for undo()
3591 """
3592 if self.undobuffer is None:
3593 return
3594 if action == "rot":
3595 angle, degPAU = data
3596 self._rotate(-angle*degPAU/self._degreesPerAU)
3597 dummy = self.undobuffer.pop()
3598 elif action == "stamp":
3599 stitem = data[0]
3600 self.clearstamp(stitem)
3601 elif action == "go":
3602 self._undogoto(data)
3603 elif action in ["wri", "dot"]:
3604 item = data[0]
3605 self.screen._delete(item)
3606 self.items.remove(item)
3607 elif action == "dofill":
3608 item = data[0]
3609 self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
3610 fill="", outline="")
3611 elif action == "beginfill":
3612 item = data[0]
3613 self._fillitem = self._fillpath = None
3614 if item in self.items:
3615 self.screen._delete(item)
3616 self.items.remove(item)
3617 elif action == "pen":
3618 TPen.pen(self, data[0])
3619 self.undobuffer.pop()
3620
3621 def undo(self):
3622 """undo (repeatedly) the last turtle action.
3623
3624 No argument.
3625
3626 undo (repeatedly) the last turtle action.
3627 Number of available undo actions is determined by the size of
3628 the undobuffer.
3629
3630 Example (for a Turtle instance named turtle):
3631 >>> for i in range(4):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003632 ... turtle.fd(50); turtle.lt(80)
3633 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003634 >>> for i in range(8):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003635 ... turtle.undo()
3636 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003637 """
3638 if self.undobuffer is None:
3639 return
3640 item = self.undobuffer.pop()
3641 action = item[0]
3642 data = item[1:]
3643 if action == "seq":
3644 while data:
3645 item = data.pop()
3646 self._undo(item[0], item[1:])
3647 else:
3648 self._undo(action, data)
3649
3650 turtlesize = shapesize
3651
3652RawPen = RawTurtle
3653
Martin v. Löwis601149b2008-09-29 22:19:08 +00003654### Screen - Singleton ########################
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003655
Martin v. Löwis601149b2008-09-29 22:19:08 +00003656def Screen():
3657 """Return the singleton screen object.
3658 If none exists at the moment, create a new one and return it,
3659 else return the existing one."""
3660 if Turtle._screen is None:
3661 Turtle._screen = _Screen()
3662 return Turtle._screen
3663
3664class _Screen(TurtleScreen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003665
3666 _root = None
3667 _canvas = None
3668 _title = _CFG["title"]
3669
Guido van Rossumb241b671998-12-04 16:42:46 +00003670 def __init__(self):
Martin v. Löwis601149b2008-09-29 22:19:08 +00003671 # XXX there is no need for this code to be conditional,
3672 # as there will be only a single _Screen instance, anyway
3673 # XXX actually, the turtle demo is injecting root window,
3674 # so perhaps the conditional creation of a root should be
3675 # preserved (perhaps by passing it as an optional parameter)
3676 if _Screen._root is None:
3677 _Screen._root = self._root = _Root()
3678 self._root.title(_Screen._title)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003679 self._root.ondestroy(self._destroy)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003680 if _Screen._canvas is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003681 width = _CFG["width"]
3682 height = _CFG["height"]
3683 canvwidth = _CFG["canvwidth"]
3684 canvheight = _CFG["canvheight"]
3685 leftright = _CFG["leftright"]
3686 topbottom = _CFG["topbottom"]
3687 self._root.setupcanvas(width, height, canvwidth, canvheight)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003688 _Screen._canvas = self._root._getcanvas()
Martin v. Löwis601149b2008-09-29 22:19:08 +00003689 TurtleScreen.__init__(self, _Screen._canvas)
Georg Brandleaa84ef2009-05-05 08:14:33 +00003690 self.setup(width, height, leftright, topbottom)
Thomas Wouters477c8d52006-05-27 19:21:47 +00003691
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003692 def setup(self, width=_CFG["width"], height=_CFG["height"],
3693 startx=_CFG["leftright"], starty=_CFG["topbottom"]):
3694 """ Set the size and position of the main window.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003695
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003696 Arguments:
3697 width: as integer a size in pixels, as float a fraction of the screen.
3698 Default is 50% of screen.
3699 height: as integer the height in pixels, as float a fraction of the
3700 screen. Default is 75% of screen.
3701 startx: if positive, starting position in pixels from the left
3702 edge of the screen, if negative from the right edge
3703 Default, startx=None is to center window horizontally.
3704 starty: if positive, starting position in pixels from the top
3705 edge of the screen, if negative from the bottom edge
3706 Default, starty=None is to center window vertically.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003707
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003708 Examples (for a Screen instance named screen):
3709 >>> screen.setup (width=200, height=200, startx=0, starty=0)
3710
3711 sets window to 200x200 pixels, in upper left of screen
3712
3713 >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
3714
3715 sets window to 75% of screen by 50% of screen and centers
3716 """
3717 if not hasattr(self._root, "set_geometry"):
3718 return
3719 sw = self._root.win_width()
3720 sh = self._root.win_height()
3721 if isinstance(width, float) and 0 <= width <= 1:
3722 width = sw*width
3723 if startx is None:
3724 startx = (sw - width) / 2
3725 if isinstance(height, float) and 0 <= height <= 1:
3726 height = sh*height
3727 if starty is None:
3728 starty = (sh - height) / 2
3729 self._root.set_geometry(width, height, startx, starty)
Georg Brandleaa84ef2009-05-05 08:14:33 +00003730 self.update()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003731
3732 def title(self, titlestring):
3733 """Set title of turtle-window
3734
3735 Argument:
3736 titlestring -- a string, to appear in the titlebar of the
3737 turtle graphics window.
3738
3739 This is a method of Screen-class. Not available for TurtleScreen-
3740 objects.
3741
3742 Example (for a Screen instance named screen):
3743 >>> screen.title("Welcome to the turtle-zoo!")
3744 """
Martin v. Löwis601149b2008-09-29 22:19:08 +00003745 if _Screen._root is not None:
3746 _Screen._root.title(titlestring)
3747 _Screen._title = titlestring
Guido van Rossumb241b671998-12-04 16:42:46 +00003748
3749 def _destroy(self):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003750 root = self._root
Martin v. Löwis601149b2008-09-29 22:19:08 +00003751 if root is _Screen._root:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003752 Turtle._pen = None
3753 Turtle._screen = None
Martin v. Löwis601149b2008-09-29 22:19:08 +00003754 _Screen._root = None
3755 _Screen._canvas = None
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003756 TurtleScreen._RUNNING = True
Guido van Rossumb241b671998-12-04 16:42:46 +00003757 root.destroy()
Fred Draked038ca82000-10-23 18:31:14 +00003758
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003759 def bye(self):
3760 """Shut the turtlegraphics window.
3761
3762 Example (for a TurtleScreen instance named screen):
3763 >>> screen.bye()
3764 """
3765 self._destroy()
3766
3767 def exitonclick(self):
3768 """Go into mainloop until the mouse is clicked.
3769
3770 No arguments.
3771
3772 Bind bye() method to mouseclick on TurtleScreen.
3773 If "using_IDLE" - value in configuration dictionary is False
3774 (default value), enter mainloop.
3775 If IDLE with -n switch (no subprocess) is used, this value should be
3776 set to True in turtle.cfg. In this case IDLE's mainloop
3777 is active also for the client script.
3778
3779 This is a method of the Screen-class and not available for
3780 TurtleScreen instances.
3781
3782 Example (for a Screen instance named screen):
3783 >>> screen.exitonclick()
3784
3785 """
3786 def exitGracefully(x, y):
3787 """Screen.bye() with two dummy-parameters"""
3788 self.bye()
3789 self.onclick(exitGracefully)
3790 if _CFG["using_IDLE"]:
3791 return
3792 try:
3793 mainloop()
3794 except AttributeError:
3795 exit(0)
3796
3797
3798class Turtle(RawTurtle):
Ezio Melotti13925002011-03-16 11:05:33 +02003799 """RawTurtle auto-creating (scrolled) canvas.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003800
3801 When a Turtle object is created or a function derived from some
3802 Turtle method is called a TurtleScreen object is automatically created.
3803 """
3804 _pen = None
3805 _screen = None
3806
3807 def __init__(self,
3808 shape=_CFG["shape"],
3809 undobuffersize=_CFG["undobuffersize"],
3810 visible=_CFG["visible"]):
3811 if Turtle._screen is None:
3812 Turtle._screen = Screen()
3813 RawTurtle.__init__(self, Turtle._screen,
3814 shape=shape,
3815 undobuffersize=undobuffersize,
3816 visible=visible)
3817
3818Pen = Turtle
3819
Guido van Rossumb241b671998-12-04 16:42:46 +00003820def _getpen():
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003821 """Create the 'anonymous' turtle if not already present."""
3822 if Turtle._pen is None:
3823 Turtle._pen = Turtle()
3824 return Turtle._pen
Thomas Wouters477c8d52006-05-27 19:21:47 +00003825
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003826def _getscreen():
3827 """Create a TurtleScreen if not already present."""
3828 if Turtle._screen is None:
3829 Turtle._screen = Screen()
3830 return Turtle._screen
Thomas Wouters477c8d52006-05-27 19:21:47 +00003831
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003832def write_docstringdict(filename="turtle_docstringdict"):
3833 """Create and write docstring-dictionary to file.
Guido van Rossumb241b671998-12-04 16:42:46 +00003834
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003835 Optional argument:
3836 filename -- a string, used as filename
3837 default value is turtle_docstringdict
Thomas Wouters477c8d52006-05-27 19:21:47 +00003838
Ezio Melotti13925002011-03-16 11:05:33 +02003839 Has to be called explicitly, (not used by the turtle-graphics classes)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003840 The docstring dictionary will be written to the Python script <filname>.py
3841 It is intended to serve as a template for translation of the docstrings
3842 into different languages.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003843 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003844 docsdict = {}
Thomas Wouters477c8d52006-05-27 19:21:47 +00003845
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003846 for methodname in _tg_screen_functions:
Martin v. Löwis601149b2008-09-29 22:19:08 +00003847 key = "_Screen."+methodname
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003848 docsdict[key] = eval(key).__doc__
3849 for methodname in _tg_turtle_functions:
3850 key = "Turtle."+methodname
3851 docsdict[key] = eval(key).__doc__
Thomas Wouters477c8d52006-05-27 19:21:47 +00003852
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01003853 with open("%s.py" % filename,"w") as f:
3854 keys = sorted([x for x in docsdict.keys()
3855 if x.split('.')[1] not in _alias_list])
3856 f.write('docsdict = {\n\n')
3857 for key in keys[:-1]:
3858 f.write('%s :\n' % repr(key))
3859 f.write(' """%s\n""",\n\n' % docsdict[key])
3860 key = keys[-1]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003861 f.write('%s :\n' % repr(key))
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01003862 f.write(' """%s\n"""\n\n' % docsdict[key])
3863 f.write("}\n")
3864 f.close()
Thomas Wouters477c8d52006-05-27 19:21:47 +00003865
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003866def read_docstrings(lang):
3867 """Read in docstrings from lang-specific docstring dictionary.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003868
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003869 Transfer docstrings, translated to lang, from a dictionary-file
3870 to the methods of classes Screen and Turtle and - in revised form -
3871 to the corresponding functions.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003872 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003873 modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
3874 module = __import__(modname)
3875 docsdict = module.docsdict
3876 for key in docsdict:
3877 try:
3878# eval(key).im_func.__doc__ = docsdict[key]
3879 eval(key).__doc__ = docsdict[key]
3880 except:
3881 print("Bad docstring-entry: %s" % key)
Thomas Wouters477c8d52006-05-27 19:21:47 +00003882
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003883_LANGUAGE = _CFG["language"]
Guido van Rossumb241b671998-12-04 16:42:46 +00003884
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003885try:
3886 if _LANGUAGE != "english":
3887 read_docstrings(_LANGUAGE)
3888except ImportError:
3889 print("Cannot find docsdict for", _LANGUAGE)
3890except:
3891 print ("Unknown Error when trying to import %s-docstring-dictionary" %
3892 _LANGUAGE)
3893
3894
3895def getmethparlist(ob):
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003896 """Get strings describing the arguments for the given object
3897
3898 Returns a pair of strings representing function parameter lists
3899 including parenthesis. The first string is suitable for use in
3900 function definition and the second is suitable for use in function
3901 call. The "self" parameter is not included.
3902 """
3903 defText = callText = ""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003904 # bit of a hack for methods - turn it into a function
3905 # but we drop the "self" param.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003906 # Try and build one for Python defined functions
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003907 args, varargs, varkw = inspect.getargs(ob.__code__)
3908 items2 = args[1:]
3909 realArgs = args[1:]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003910 defaults = ob.__defaults__ or []
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003911 defaults = ["=%r" % (value,) for value in defaults]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003912 defaults = [""] * (len(realArgs)-len(defaults)) + defaults
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003913 items1 = [arg + dflt for arg, dflt in zip(realArgs, defaults)]
3914 if varargs is not None:
3915 items1.append("*" + varargs)
3916 items2.append("*" + varargs)
3917 if varkw is not None:
3918 items1.append("**" + varkw)
3919 items2.append("**" + varkw)
3920 defText = ", ".join(items1)
3921 defText = "(%s)" % defText
3922 callText = ", ".join(items2)
3923 callText = "(%s)" % callText
3924 return defText, callText
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003925
3926def _turtle_docrevise(docstr):
3927 """To reduce docstrings from RawTurtle class for functions
3928 """
3929 import re
3930 if docstr is None:
3931 return None
3932 turtlename = _CFG["exampleturtle"]
3933 newdocstr = docstr.replace("%s." % turtlename,"")
3934 parexp = re.compile(r' \(.+ %s\):' % turtlename)
3935 newdocstr = parexp.sub(":", newdocstr)
3936 return newdocstr
3937
3938def _screen_docrevise(docstr):
3939 """To reduce docstrings from TurtleScreen class for functions
3940 """
3941 import re
3942 if docstr is None:
3943 return None
3944 screenname = _CFG["examplescreen"]
3945 newdocstr = docstr.replace("%s." % screenname,"")
3946 parexp = re.compile(r' \(.+ %s\):' % screenname)
3947 newdocstr = parexp.sub(":", newdocstr)
3948 return newdocstr
3949
3950## The following mechanism makes all methods of RawTurtle and Turtle available
3951## as functions. So we can enhance, change, add, delete methods to these
3952## classes and do not need to change anything here.
3953
3954
3955for methodname in _tg_screen_functions:
Martin v. Löwis601149b2008-09-29 22:19:08 +00003956 pl1, pl2 = getmethparlist(eval('_Screen.' + methodname))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003957 if pl1 == "":
3958 print(">>>>>>", pl1, pl2)
3959 continue
3960 defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
3961 {'key':methodname, 'pl1':pl1, 'pl2':pl2})
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003962 exec(defstr)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003963 eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003964
3965for methodname in _tg_turtle_functions:
3966 pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
3967 if pl1 == "":
3968 print(">>>>>>", pl1, pl2)
3969 continue
3970 defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" %
3971 {'key':methodname, 'pl1':pl1, 'pl2':pl2})
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003972 exec(defstr)
3973 eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__)
3974
3975
Georg Brandleaa84ef2009-05-05 08:14:33 +00003976done = mainloop
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003977
3978if __name__ == "__main__":
3979 def switchpen():
3980 if isdown():
3981 pu()
3982 else:
3983 pd()
3984
3985 def demo1():
3986 """Demo of old turtle.py - module"""
3987 reset()
3988 tracer(True)
3989 up()
3990 backward(100)
3991 down()
3992 # draw 3 squares; the last filled
3993 width(3)
3994 for i in range(3):
3995 if i == 2:
3996 begin_fill()
3997 for _ in range(4):
3998 forward(20)
3999 left(90)
4000 if i == 2:
4001 color("maroon")
4002 end_fill()
4003 up()
4004 forward(30)
4005 down()
4006 width(1)
4007 color("black")
4008 # move out of the way
4009 tracer(False)
4010 up()
4011 right(90)
4012 forward(100)
4013 right(90)
4014 forward(100)
4015 right(180)
4016 down()
4017 # some text
4018 write("startstart", 1)
4019 write("start", 1)
4020 color("red")
4021 # staircase
4022 for i in range(5):
Guido van Rossumb241b671998-12-04 16:42:46 +00004023 forward(20)
4024 left(90)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004025 forward(20)
4026 right(90)
4027 # filled staircase
4028 tracer(True)
4029 begin_fill()
4030 for i in range(5):
4031 forward(20)
4032 left(90)
4033 forward(20)
4034 right(90)
4035 end_fill()
4036 # more text
Thomas Wouters477c8d52006-05-27 19:21:47 +00004037
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004038 def demo2():
4039 """Demo of some new features."""
4040 speed(1)
4041 st()
4042 pensize(3)
4043 setheading(towards(0, 0))
4044 radius = distance(0, 0)/2.0
4045 rt(90)
4046 for _ in range(18):
4047 switchpen()
4048 circle(radius, 10)
4049 write("wait a moment...")
4050 while undobufferentries():
4051 undo()
4052 reset()
4053 lt(90)
4054 colormode(255)
4055 laenge = 10
4056 pencolor("green")
4057 pensize(3)
4058 lt(180)
4059 for i in range(-2, 16):
4060 if i > 0:
4061 begin_fill()
4062 fillcolor(255-15*i, 0, 15*i)
4063 for _ in range(3):
4064 fd(laenge)
4065 lt(120)
4066 end_fill()
4067 laenge += 10
4068 lt(15)
4069 speed((speed()+1)%12)
4070 #end_fill()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004071
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004072 lt(120)
4073 pu()
4074 fd(70)
4075 rt(30)
4076 pd()
4077 color("red","yellow")
4078 speed(0)
4079 begin_fill()
4080 for _ in range(4):
4081 circle(50, 90)
4082 rt(90)
4083 fd(30)
4084 rt(90)
4085 end_fill()
4086 lt(90)
4087 pu()
4088 fd(30)
4089 pd()
4090 shape("turtle")
Thomas Wouters477c8d52006-05-27 19:21:47 +00004091
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004092 tri = getturtle()
4093 tri.resizemode("auto")
4094 turtle = Turtle()
4095 turtle.resizemode("auto")
4096 turtle.shape("turtle")
4097 turtle.reset()
4098 turtle.left(90)
4099 turtle.speed(0)
4100 turtle.up()
4101 turtle.goto(280, 40)
4102 turtle.lt(30)
4103 turtle.down()
4104 turtle.speed(6)
4105 turtle.color("blue","orange")
4106 turtle.pensize(2)
4107 tri.speed(6)
Thomas Wouters477c8d52006-05-27 19:21:47 +00004108 setheading(towards(turtle))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004109 count = 1
4110 while tri.distance(turtle) > 4:
4111 turtle.fd(3.5)
4112 turtle.lt(0.6)
4113 tri.setheading(tri.towards(turtle))
4114 tri.fd(4)
4115 if count % 20 == 0:
4116 turtle.stamp()
4117 tri.stamp()
4118 switchpen()
4119 count += 1
4120 tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
4121 tri.pencolor("black")
4122 tri.pencolor("red")
Thomas Wouters477c8d52006-05-27 19:21:47 +00004123
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004124 def baba(xdummy, ydummy):
4125 clearscreen()
4126 bye()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004127
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004128 time.sleep(2)
Guido van Rossumb241b671998-12-04 16:42:46 +00004129
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004130 while undobufferentries():
4131 tri.undo()
4132 turtle.undo()
4133 tri.fd(50)
4134 tri.write(" Click me!", font = ("Courier", 12, "bold") )
4135 tri.onclick(baba, 1)
4136
4137 demo1()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004138 demo2()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004139 exitonclick()