blob: ac0c32cf217223066794131b318d8c4a88827b5a [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
111import os
Alexander Belopolskyc1a68362010-10-27 13:25:45 +0000112import inspect
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
860 Thus stops execution of turtle graphics script. Main purpose: use in
861 in the Demo-Viewer turtle.Demo.py.
862 """
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()
996
997 def clear(self):
998 """Delete all drawings and all turtles from the TurtleScreen.
999
Georg Brandleaa84ef2009-05-05 08:14:33 +00001000 No argument.
1001
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001002 Reset empty TurtleScreen to its initial state: white background,
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001003 no backgroundimage, no eventbindings and tracing on.
1004
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001005 Example (for a TurtleScreen instance named screen):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001006 >>> screen.clear()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001007
1008 Note: this method is not available as function.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001009 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001010 self._delayvalue = _CFG["delay"]
1011 self._colormode = _CFG["colormode"]
1012 self._delete("all")
1013 self._bgpic = self._createimage("")
1014 self._bgpicname = "nopic"
1015 self._tracing = 1
1016 self._updatecounter = 0
1017 self._turtles = []
1018 self.bgcolor("white")
1019 for btn in 1, 2, 3:
1020 self.onclick(None, btn)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001021 self.onkeypress(None)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001022 for key in self._keys[:]:
1023 self.onkey(None, key)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001024 self.onkeypress(None, key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001025 Turtle._pen = None
Guido van Rossumb241b671998-12-04 16:42:46 +00001026
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001027 def mode(self, mode=None):
1028 """Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001029
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001030 Optional argument:
1031 mode -- on of the strings 'standard', 'logo' or 'world'
1032
1033 Mode 'standard' is compatible with turtle.py.
1034 Mode 'logo' is compatible with most Logo-Turtle-Graphics.
1035 Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
1036 this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
1037 If mode is not given, return the current mode.
1038
1039 Mode Initial turtle heading positive angles
1040 ------------|-------------------------|-------------------
1041 'standard' to the right (east) counterclockwise
1042 'logo' upward (north) clockwise
1043
1044 Examples:
1045 >>> mode('logo') # resets turtle heading to north
1046 >>> mode()
1047 'logo'
Thomas Wouters477c8d52006-05-27 19:21:47 +00001048 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001049 if mode is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001050 return self._mode
1051 mode = mode.lower()
1052 if mode not in ["standard", "logo", "world"]:
1053 raise TurtleGraphicsError("No turtle-graphics-mode %s" % mode)
1054 self._mode = mode
1055 if mode in ["standard", "logo"]:
1056 self._setscrollregion(-self.canvwidth//2, -self.canvheight//2,
1057 self.canvwidth//2, self.canvheight//2)
1058 self.xscale = self.yscale = 1.0
1059 self.reset()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001060
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001061 def setworldcoordinates(self, llx, lly, urx, ury):
1062 """Set up a user defined coordinate-system.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001063
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001064 Arguments:
1065 llx -- a number, x-coordinate of lower left corner of canvas
1066 lly -- a number, y-coordinate of lower left corner of canvas
1067 urx -- a number, x-coordinate of upper right corner of canvas
1068 ury -- a number, y-coordinate of upper right corner of canvas
1069
1070 Set up user coodinat-system and switch to mode 'world' if necessary.
1071 This performs a screen.reset. If mode 'world' is already active,
1072 all drawings are redrawn according to the new coordinates.
1073
1074 But ATTENTION: in user-defined coordinatesystems angles may appear
1075 distorted. (see Screen.mode())
1076
1077 Example (for a TurtleScreen instance named screen):
1078 >>> screen.setworldcoordinates(-10,-0.5,50,1.5)
1079 >>> for _ in range(36):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001080 ... left(10)
1081 ... forward(0.5)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001082 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001083 if self.mode() != "world":
1084 self.mode("world")
1085 xspan = float(urx - llx)
1086 yspan = float(ury - lly)
1087 wx, wy = self._window_size()
1088 self.screensize(wx-20, wy-20)
1089 oldxscale, oldyscale = self.xscale, self.yscale
1090 self.xscale = self.canvwidth / xspan
1091 self.yscale = self.canvheight / yspan
1092 srx1 = llx * self.xscale
1093 sry1 = -ury * self.yscale
1094 srx2 = self.canvwidth + srx1
1095 sry2 = self.canvheight + sry1
1096 self._setscrollregion(srx1, sry1, srx2, sry2)
1097 self._rescale(self.xscale/oldxscale, self.yscale/oldyscale)
1098 self.update()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001099
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001100 def register_shape(self, name, shape=None):
1101 """Adds a turtle shape to TurtleScreen's shapelist.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001102
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001103 Arguments:
1104 (1) name is the name of a gif-file and shape is None.
1105 Installs the corresponding image shape.
1106 !! Image-shapes DO NOT rotate when turning the turtle,
1107 !! so they do not display the heading of the turtle!
1108 (2) name is an arbitrary string and shape is a tuple
1109 of pairs of coordinates. Installs the corresponding
1110 polygon shape
1111 (3) name is an arbitrary string and shape is a
1112 (compound) Shape object. Installs the corresponding
1113 compound shape.
1114 To use a shape, you have to issue the command shape(shapename).
Thomas Wouters477c8d52006-05-27 19:21:47 +00001115
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001116 call: register_shape("turtle.gif")
1117 --or: register_shape("tri", ((0,0), (10,10), (-10,10)))
1118
1119 Example (for a TurtleScreen instance named screen):
1120 >>> screen.register_shape("triangle", ((5,-3),(0,5),(-5,-3)))
1121
Thomas Wouters477c8d52006-05-27 19:21:47 +00001122 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001123 if shape is None:
1124 # image
1125 if name.lower().endswith(".gif"):
1126 shape = Shape("image", self._image(name))
1127 else:
1128 raise TurtleGraphicsError("Bad arguments for register_shape.\n"
1129 + "Use help(register_shape)" )
1130 elif isinstance(shape, tuple):
1131 shape = Shape("polygon", shape)
1132 ## else shape assumed to be Shape-instance
1133 self._shapes[name] = shape
Guido van Rossumbffa52f2002-09-29 00:25:51 +00001134
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001135 def _colorstr(self, color):
1136 """Return color string corresponding to args.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001137
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001138 Argument may be a string or a tuple of three
1139 numbers corresponding to actual colormode,
1140 i.e. in the range 0<=n<=colormode.
1141
1142 If the argument doesn't represent a color,
1143 an error is raised.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001144 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001145 if len(color) == 1:
1146 color = color[0]
1147 if isinstance(color, str):
1148 if self._iscolorstring(color) or color == "":
1149 return color
1150 else:
1151 raise TurtleGraphicsError("bad color string: %s" % str(color))
1152 try:
1153 r, g, b = color
1154 except:
1155 raise TurtleGraphicsError("bad color arguments: %s" % str(color))
1156 if self._colormode == 1.0:
1157 r, g, b = [round(255.0*x) for x in (r, g, b)]
1158 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
1159 raise TurtleGraphicsError("bad color sequence: %s" % str(color))
1160 return "#%02x%02x%02x" % (r, g, b)
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001161
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001162 def _color(self, cstr):
1163 if not cstr.startswith("#"):
1164 return cstr
1165 if len(cstr) == 7:
1166 cl = [int(cstr[i:i+2], 16) for i in (1, 3, 5)]
1167 elif len(cstr) == 4:
1168 cl = [16*int(cstr[h], 16) for h in cstr[1:]]
1169 else:
1170 raise TurtleGraphicsError("bad colorstring: %s" % cstr)
1171 return tuple([c * self._colormode/255 for c in cl])
Thomas Wouters477c8d52006-05-27 19:21:47 +00001172
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001173 def colormode(self, cmode=None):
1174 """Return the colormode or set it to 1.0 or 255.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001175
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001176 Optional argument:
1177 cmode -- one of the values 1.0 or 255
Thomas Wouters477c8d52006-05-27 19:21:47 +00001178
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001179 r, g, b values of colortriples have to be in range 0..cmode.
1180
1181 Example (for a TurtleScreen instance named screen):
1182 >>> screen.colormode()
1183 1.0
1184 >>> screen.colormode(255)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001185 >>> pencolor(240,160,80)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001186 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001187 if cmode is None:
1188 return self._colormode
1189 if cmode == 1.0:
1190 self._colormode = float(cmode)
1191 elif cmode == 255:
1192 self._colormode = int(cmode)
1193
1194 def reset(self):
1195 """Reset all Turtles on the Screen to their initial state.
1196
1197 No argument.
1198
1199 Example (for a TurtleScreen instance named screen):
1200 >>> screen.reset()
1201 """
1202 for turtle in self._turtles:
1203 turtle._setmode(self._mode)
1204 turtle.reset()
1205
1206 def turtles(self):
1207 """Return the list of turtles on the screen.
1208
1209 Example (for a TurtleScreen instance named screen):
1210 >>> screen.turtles()
1211 [<turtle.Turtle object at 0x00E11FB0>]
1212 """
1213 return self._turtles
1214
1215 def bgcolor(self, *args):
1216 """Set or return backgroundcolor of the TurtleScreen.
1217
1218 Arguments (if given): a color string or three numbers
1219 in the range 0..colormode or a 3-tuple of such numbers.
1220
1221 Example (for a TurtleScreen instance named screen):
1222 >>> screen.bgcolor("orange")
1223 >>> screen.bgcolor()
1224 'orange'
1225 >>> screen.bgcolor(0.5,0,0.5)
1226 >>> screen.bgcolor()
1227 '#800080'
1228 """
1229 if args:
1230 color = self._colorstr(args)
1231 else:
1232 color = None
1233 color = self._bgcolor(color)
1234 if color is not None:
1235 color = self._color(color)
1236 return color
1237
1238 def tracer(self, n=None, delay=None):
1239 """Turns turtle animation on/off and set delay for update drawings.
1240
1241 Optional arguments:
1242 n -- nonnegative integer
1243 delay -- nonnegative integer
1244
1245 If n is given, only each n-th regular screen update is really performed.
1246 (Can be used to accelerate the drawing of complex graphics.)
1247 Second arguments sets delay value (see RawTurtle.delay())
1248
1249 Example (for a TurtleScreen instance named screen):
1250 >>> screen.tracer(8, 25)
1251 >>> dist = 2
1252 >>> for i in range(200):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001253 ... fd(dist)
1254 ... rt(90)
1255 ... dist += 2
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001256 """
1257 if n is None:
1258 return self._tracing
1259 self._tracing = int(n)
1260 self._updatecounter = 0
1261 if delay is not None:
1262 self._delayvalue = int(delay)
1263 if self._tracing:
1264 self.update()
1265
1266 def delay(self, delay=None):
1267 """ Return or set the drawing delay in milliseconds.
1268
1269 Optional argument:
1270 delay -- positive integer
1271
1272 Example (for a TurtleScreen instance named screen):
1273 >>> screen.delay(15)
1274 >>> screen.delay()
1275 15
1276 """
1277 if delay is None:
1278 return self._delayvalue
1279 self._delayvalue = int(delay)
1280
1281 def _incrementudc(self):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001282 """Increment upadate counter."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001283 if not TurtleScreen._RUNNING:
1284 TurtleScreen._RUNNNING = True
1285 raise Terminator
1286 if self._tracing > 0:
1287 self._updatecounter += 1
1288 self._updatecounter %= self._tracing
1289
1290 def update(self):
1291 """Perform a TurtleScreen update.
1292 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00001293 tracing = self._tracing
1294 self._tracing = True
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001295 for t in self.turtles():
1296 t._update_data()
1297 t._drawturtle()
Georg Brandleaa84ef2009-05-05 08:14:33 +00001298 self._tracing = tracing
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001299 self._update()
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001300
1301 def window_width(self):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001302 """ Return the width of the turtle window.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001303
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001304 Example (for a TurtleScreen instance named screen):
1305 >>> screen.window_width()
Thomas Wouters477c8d52006-05-27 19:21:47 +00001306 640
1307 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001308 return self._window_size()[0]
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001309
1310 def window_height(self):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001311 """ Return the height of the turtle window.
1312
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001313 Example (for a TurtleScreen instance named screen):
1314 >>> screen.window_height()
1315 480
Thomas Wouters477c8d52006-05-27 19:21:47 +00001316 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001317 return self._window_size()[1]
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001318
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001319 def getcanvas(self):
1320 """Return the Canvas of this TurtleScreen.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001321
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001322 No argument.
1323
1324 Example (for a Screen instance named screen):
1325 >>> cv = screen.getcanvas()
1326 >>> cv
1327 <turtle.ScrolledCanvas instance at 0x010742D8>
Thomas Wouters477c8d52006-05-27 19:21:47 +00001328 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001329 return self.cv
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001330
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001331 def getshapes(self):
1332 """Return a list of names of all currently available turtle shapes.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001333
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001334 No argument.
1335
1336 Example (for a TurtleScreen instance named screen):
1337 >>> screen.getshapes()
1338 ['arrow', 'blank', 'circle', ... , 'turtle']
1339 """
1340 return sorted(self._shapes.keys())
1341
1342 def onclick(self, fun, btn=1, add=None):
1343 """Bind fun to mouse-click event on canvas.
1344
1345 Arguments:
1346 fun -- a function with two arguments, the coordinates of the
1347 clicked point on the canvas.
1348 num -- the number of the mouse-button, defaults to 1
1349
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001350 Example (for a TurtleScreen instance named screen)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001351
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001352 >>> screen.onclick(goto)
1353 >>> # Subsequently clicking into the TurtleScreen will
1354 >>> # make the turtle move to the clicked point.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001355 >>> screen.onclick(None)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001356 """
1357 self._onscreenclick(fun, btn, add)
1358
1359 def onkey(self, fun, key):
1360 """Bind fun to key-release event of key.
1361
1362 Arguments:
1363 fun -- a function with no arguments
1364 key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1365
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001366 In order to be able to register key-events, TurtleScreen
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001367 must have focus. (See method listen.)
1368
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001369 Example (for a TurtleScreen instance named screen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001370
1371 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001372 ... fd(50)
1373 ... lt(60)
1374 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001375 >>> screen.onkey(f, "Up")
1376 >>> screen.listen()
1377
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001378 Subsequently the turtle can be moved by repeatedly pressing
1379 the up-arrow key, consequently drawing a hexagon
1380
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001381 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001382 if fun is None:
Georg Brandleaa84ef2009-05-05 08:14:33 +00001383 if key in self._keys:
1384 self._keys.remove(key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001385 elif key not in self._keys:
1386 self._keys.append(key)
Georg Brandleaa84ef2009-05-05 08:14:33 +00001387 self._onkeyrelease(fun, key)
1388
1389 def onkeypress(self, fun, key=None):
1390 """Bind fun to key-press event of key if key is given,
1391 or to any key-press-event if no key is given.
1392
1393 Arguments:
1394 fun -- a function with no arguments
1395 key -- a string: key (e.g. "a") or key-symbol (e.g. "space")
1396
1397 In order to be able to register key-events, TurtleScreen
1398 must have focus. (See method listen.)
1399
1400 Example (for a TurtleScreen instance named screen
1401 and a Turtle instance named turtle):
1402
1403 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001404 ... fd(50)
1405 ... lt(60)
1406 ...
1407 >>> screen.onkeypress(f, "Up")
Georg Brandleaa84ef2009-05-05 08:14:33 +00001408 >>> screen.listen()
1409
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001410 Subsequently the turtle can be moved by repeatedly pressing
1411 the up-arrow key, or by keeping pressed the up-arrow key.
1412 consequently drawing a hexagon.
Georg Brandleaa84ef2009-05-05 08:14:33 +00001413 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001414 if fun is None:
Georg Brandleaa84ef2009-05-05 08:14:33 +00001415 if key in self._keys:
1416 self._keys.remove(key)
1417 elif key is not None and key not in self._keys:
1418 self._keys.append(key)
1419 self._onkeypress(fun, key)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001420
1421 def listen(self, xdummy=None, ydummy=None):
1422 """Set focus on TurtleScreen (in order to collect key-events)
1423
1424 No arguments.
1425 Dummy arguments are provided in order
1426 to be able to pass listen to the onclick method.
1427
1428 Example (for a TurtleScreen instance named screen):
1429 >>> screen.listen()
1430 """
1431 self._listen()
1432
1433 def ontimer(self, fun, t=0):
1434 """Install a timer, which calls fun after t milliseconds.
1435
1436 Arguments:
1437 fun -- a function with no arguments.
1438 t -- a number >= 0
1439
1440 Example (for a TurtleScreen instance named screen):
1441
1442 >>> running = True
1443 >>> def f():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001444 ... if running:
1445 ... fd(50)
1446 ... lt(60)
1447 ... screen.ontimer(f, 250)
1448 ...
1449 >>> f() # makes the turtle marching around
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001450 >>> running = False
1451 """
1452 self._ontimer(fun, t)
1453
1454 def bgpic(self, picname=None):
1455 """Set background image or return name of current backgroundimage.
1456
1457 Optional argument:
1458 picname -- a string, name of a gif-file or "nopic".
1459
Ezio Melotti42da6632011-03-15 05:18:48 +02001460 If picname is a filename, set the corresponding image as background.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001461 If picname is "nopic", delete backgroundimage, if present.
1462 If picname is None, return the filename of the current backgroundimage.
1463
1464 Example (for a TurtleScreen instance named screen):
1465 >>> screen.bgpic()
1466 'nopic'
1467 >>> screen.bgpic("landscape.gif")
1468 >>> screen.bgpic()
1469 'landscape.gif'
1470 """
1471 if picname is None:
1472 return self._bgpicname
1473 if picname not in self._bgpics:
1474 self._bgpics[picname] = self._image(picname)
1475 self._setbgpic(self._bgpic, self._bgpics[picname])
1476 self._bgpicname = picname
1477
1478 def screensize(self, canvwidth=None, canvheight=None, bg=None):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001479 """Resize the canvas the turtles are drawing on.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001480
1481 Optional arguments:
1482 canvwidth -- positive integer, new width of canvas in pixels
1483 canvheight -- positive integer, new height of canvas in pixels
Ezio Melotti13925002011-03-16 11:05:33 +02001484 bg -- colorstring or color-tuple, new backgroundcolor
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001485 If no arguments are given, return current (canvaswidth, canvasheight)
1486
1487 Do not alter the drawing window. To observe hidden parts of
1488 the canvas use the scrollbars. (Can make visible those parts
1489 of a drawing, which were outside the canvas before!)
1490
1491 Example (for a Turtle instance named turtle):
1492 >>> turtle.screensize(2000,1500)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02001493 >>> # e.g. to search for an erroneously escaped turtle ;-)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001494 """
1495 return self._resize(canvwidth, canvheight, bg)
1496
1497 onscreenclick = onclick
1498 resetscreen = reset
1499 clearscreen = clear
1500 addshape = register_shape
Georg Brandleaa84ef2009-05-05 08:14:33 +00001501 onkeyrelease = onkey
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001502
1503class TNavigator(object):
1504 """Navigation part of the RawTurtle.
1505 Implements methods for turtle movement.
1506 """
1507 START_ORIENTATION = {
1508 "standard": Vec2D(1.0, 0.0),
1509 "world" : Vec2D(1.0, 0.0),
1510 "logo" : Vec2D(0.0, 1.0) }
1511 DEFAULT_MODE = "standard"
1512 DEFAULT_ANGLEOFFSET = 0
1513 DEFAULT_ANGLEORIENT = 1
1514
1515 def __init__(self, mode=DEFAULT_MODE):
1516 self._angleOffset = self.DEFAULT_ANGLEOFFSET
1517 self._angleOrient = self.DEFAULT_ANGLEORIENT
1518 self._mode = mode
1519 self.undobuffer = None
1520 self.degrees()
1521 self._mode = None
1522 self._setmode(mode)
1523 TNavigator.reset(self)
1524
1525 def reset(self):
1526 """reset turtle to its initial values
1527
1528 Will be overwritten by parent class
1529 """
1530 self._position = Vec2D(0.0, 0.0)
1531 self._orient = TNavigator.START_ORIENTATION[self._mode]
1532
1533 def _setmode(self, mode=None):
1534 """Set turtle-mode to 'standard', 'world' or 'logo'.
1535 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00001536 if mode is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001537 return self._mode
1538 if mode not in ["standard", "logo", "world"]:
1539 return
1540 self._mode = mode
1541 if mode in ["standard", "world"]:
1542 self._angleOffset = 0
1543 self._angleOrient = 1
1544 else: # mode == "logo":
1545 self._angleOffset = self._fullcircle/4.
1546 self._angleOrient = -1
1547
1548 def _setDegreesPerAU(self, fullcircle):
1549 """Helper function for degrees() and radians()"""
1550 self._fullcircle = fullcircle
1551 self._degreesPerAU = 360/fullcircle
1552 if self._mode == "standard":
1553 self._angleOffset = 0
1554 else:
1555 self._angleOffset = fullcircle/4.
1556
1557 def degrees(self, fullcircle=360.0):
1558 """ Set angle measurement units to degrees.
1559
1560 Optional argument:
1561 fullcircle - a number
1562
1563 Set angle measurement units, i. e. set number
1564 of 'degrees' for a full circle. Dafault value is
1565 360 degrees.
1566
1567 Example (for a Turtle instance named turtle):
1568 >>> turtle.left(90)
1569 >>> turtle.heading()
1570 90
Alexander Belopolsky3cdfb122010-10-29 17:16:49 +00001571
1572 Change angle measurement unit to grad (also known as gon,
1573 grade, or gradian and equals 1/100-th of the right angle.)
1574 >>> turtle.degrees(400.0)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001575 >>> turtle.heading()
1576 100
1577
1578 """
1579 self._setDegreesPerAU(fullcircle)
1580
1581 def radians(self):
1582 """ Set the angle measurement units to radians.
1583
1584 No arguments.
1585
1586 Example (for a Turtle instance named turtle):
1587 >>> turtle.heading()
1588 90
1589 >>> turtle.radians()
1590 >>> turtle.heading()
1591 1.5707963267948966
1592 """
1593 self._setDegreesPerAU(2*math.pi)
1594
1595 def _go(self, distance):
1596 """move turtle forward by specified distance"""
1597 ende = self._position + self._orient * distance
1598 self._goto(ende)
1599
1600 def _rotate(self, angle):
1601 """Turn turtle counterclockwise by specified angle if angle > 0."""
1602 angle *= self._degreesPerAU
1603 self._orient = self._orient.rotate(angle)
1604
1605 def _goto(self, end):
1606 """move turtle to position end."""
1607 self._position = end
1608
1609 def forward(self, distance):
1610 """Move the turtle forward by the specified distance.
1611
1612 Aliases: forward | fd
1613
1614 Argument:
1615 distance -- a number (integer or float)
1616
1617 Move the turtle forward by the specified distance, in the direction
1618 the turtle is headed.
1619
1620 Example (for a Turtle instance named turtle):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001621 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001622 (0.00, 0.00)
1623 >>> turtle.forward(25)
1624 >>> turtle.position()
1625 (25.00,0.00)
1626 >>> turtle.forward(-75)
1627 >>> turtle.position()
1628 (-50.00,0.00)
1629 """
1630 self._go(distance)
1631
1632 def back(self, distance):
1633 """Move the turtle backward by distance.
1634
1635 Aliases: back | backward | bk
1636
1637 Argument:
1638 distance -- a number
1639
1640 Move the turtle backward by distance ,opposite to the direction the
1641 turtle is headed. Do not change the turtle's heading.
1642
1643 Example (for a Turtle instance named turtle):
1644 >>> turtle.position()
1645 (0.00, 0.00)
1646 >>> turtle.backward(30)
1647 >>> turtle.position()
1648 (-30.00, 0.00)
1649 """
1650 self._go(-distance)
1651
1652 def right(self, angle):
1653 """Turn turtle right by angle units.
1654
1655 Aliases: right | rt
1656
1657 Argument:
1658 angle -- a number (integer or float)
1659
1660 Turn turtle right by angle units. (Units are by default degrees,
1661 but can be set via the degrees() and radians() functions.)
1662 Angle orientation depends on mode. (See this.)
1663
1664 Example (for a Turtle instance named turtle):
1665 >>> turtle.heading()
1666 22.0
1667 >>> turtle.right(45)
1668 >>> turtle.heading()
1669 337.0
1670 """
1671 self._rotate(-angle)
1672
1673 def left(self, angle):
1674 """Turn turtle left by angle units.
1675
1676 Aliases: left | lt
1677
1678 Argument:
1679 angle -- a number (integer or float)
1680
1681 Turn turtle left by angle units. (Units are by default degrees,
1682 but can be set via the degrees() and radians() functions.)
1683 Angle orientation depends on mode. (See this.)
1684
1685 Example (for a Turtle instance named turtle):
1686 >>> turtle.heading()
1687 22.0
1688 >>> turtle.left(45)
1689 >>> turtle.heading()
1690 67.0
1691 """
1692 self._rotate(angle)
1693
1694 def pos(self):
1695 """Return the turtle's current location (x,y), as a Vec2D-vector.
1696
1697 Aliases: pos | position
1698
1699 No arguments.
1700
1701 Example (for a Turtle instance named turtle):
1702 >>> turtle.pos()
1703 (0.00, 240.00)
1704 """
1705 return self._position
1706
1707 def xcor(self):
1708 """ Return the turtle's x coordinate.
1709
1710 No arguments.
1711
1712 Example (for a Turtle instance named turtle):
1713 >>> reset()
1714 >>> turtle.left(60)
1715 >>> turtle.forward(100)
1716 >>> print turtle.xcor()
1717 50.0
1718 """
1719 return self._position[0]
1720
1721 def ycor(self):
1722 """ Return the turtle's y coordinate
1723 ---
1724 No arguments.
1725
1726 Example (for a Turtle instance named turtle):
1727 >>> reset()
1728 >>> turtle.left(60)
1729 >>> turtle.forward(100)
1730 >>> print turtle.ycor()
1731 86.6025403784
1732 """
1733 return self._position[1]
1734
1735
1736 def goto(self, x, y=None):
1737 """Move turtle to an absolute position.
1738
1739 Aliases: setpos | setposition | goto:
1740
1741 Arguments:
1742 x -- a number or a pair/vector of numbers
1743 y -- a number None
1744
1745 call: goto(x, y) # two coordinates
1746 --or: goto((x, y)) # a pair (tuple) of coordinates
1747 --or: goto(vec) # e.g. as returned by pos()
1748
1749 Move turtle to an absolute position. If the pen is down,
1750 a line will be drawn. The turtle's orientation does not change.
1751
1752 Example (for a Turtle instance named turtle):
1753 >>> tp = turtle.pos()
1754 >>> tp
1755 (0.00, 0.00)
1756 >>> turtle.setpos(60,30)
1757 >>> turtle.pos()
1758 (60.00,30.00)
1759 >>> turtle.setpos((20,80))
1760 >>> turtle.pos()
1761 (20.00,80.00)
1762 >>> turtle.setpos(tp)
1763 >>> turtle.pos()
1764 (0.00,0.00)
1765 """
1766 if y is None:
1767 self._goto(Vec2D(*x))
1768 else:
1769 self._goto(Vec2D(x, y))
1770
1771 def home(self):
1772 """Move turtle to the origin - coordinates (0,0).
1773
1774 No arguments.
1775
Mark Dickinsonf8798f52009-02-20 20:53:56 +00001776 Move turtle to the origin - coordinates (0,0) and set its
1777 heading to its start-orientation (which depends on mode).
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001778
1779 Example (for a Turtle instance named turtle):
1780 >>> turtle.home()
1781 """
1782 self.goto(0, 0)
1783 self.setheading(0)
1784
1785 def setx(self, x):
1786 """Set the turtle's first coordinate to x
1787
1788 Argument:
1789 x -- a number (integer or float)
1790
1791 Set the turtle's first coordinate to x, leave second coordinate
1792 unchanged.
1793
1794 Example (for a Turtle instance named turtle):
1795 >>> turtle.position()
1796 (0.00, 240.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001797 >>> turtle.setx(10)
1798 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001799 (10.00, 240.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001800 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001801 self._goto(Vec2D(x, self._position[1]))
Guido van Rossumfd2ede22002-09-23 16:55:05 +00001802
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001803 def sety(self, y):
1804 """Set the turtle's second coordinate to y
Thomas Wouters477c8d52006-05-27 19:21:47 +00001805
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001806 Argument:
1807 y -- a number (integer or float)
1808
1809 Set the turtle's first coordinate to x, second coordinate remains
1810 unchanged.
1811
1812 Example (for a Turtle instance named turtle):
Thomas Wouters477c8d52006-05-27 19:21:47 +00001813 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001814 (0.00, 40.00)
1815 >>> turtle.sety(-10)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001816 >>> turtle.position()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001817 (0.00, -10.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001818 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001819 self._goto(Vec2D(self._position[0], y))
Guido van Rossumb241b671998-12-04 16:42:46 +00001820
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001821 def distance(self, x, y=None):
1822 """Return the distance from the turtle to (x,y) in turtle step units.
Thomas Wouters477c8d52006-05-27 19:21:47 +00001823
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001824 Arguments:
1825 x -- a number or a pair/vector of numbers or a turtle instance
1826 y -- a number None None
Thomas Wouters477c8d52006-05-27 19:21:47 +00001827
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001828 call: distance(x, y) # two coordinates
1829 --or: distance((x, y)) # a pair (tuple) of coordinates
1830 --or: distance(vec) # e.g. as returned by pos()
1831 --or: distance(mypen) # where mypen is another turtle
1832
1833 Example (for a Turtle instance named turtle):
1834 >>> turtle.pos()
1835 (0.00, 0.00)
1836 >>> turtle.distance(30,40)
1837 50.0
1838 >>> pen = Turtle()
1839 >>> pen.forward(77)
1840 >>> turtle.distance(pen)
1841 77.0
1842 """
1843 if y is not None:
1844 pos = Vec2D(x, y)
1845 if isinstance(x, Vec2D):
1846 pos = x
1847 elif isinstance(x, tuple):
1848 pos = Vec2D(*x)
1849 elif isinstance(x, TNavigator):
1850 pos = x._position
1851 return abs(pos - self._position)
1852
1853 def towards(self, x, y=None):
1854 """Return the angle of the line from the turtle's position to (x, y).
1855
1856 Arguments:
1857 x -- a number or a pair/vector of numbers or a turtle instance
1858 y -- a number None None
1859
1860 call: distance(x, y) # two coordinates
1861 --or: distance((x, y)) # a pair (tuple) of coordinates
1862 --or: distance(vec) # e.g. as returned by pos()
1863 --or: distance(mypen) # where mypen is another turtle
1864
1865 Return the angle, between the line from turtle-position to position
1866 specified by x, y and the turtle's start orientation. (Depends on
1867 modes - "standard" or "logo")
1868
1869 Example (for a Turtle instance named turtle):
1870 >>> turtle.pos()
1871 (10.00, 10.00)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001872 >>> turtle.towards(0,0)
1873 225.0
1874 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001875 if y is not None:
1876 pos = Vec2D(x, y)
1877 if isinstance(x, Vec2D):
1878 pos = x
1879 elif isinstance(x, tuple):
1880 pos = Vec2D(*x)
1881 elif isinstance(x, TNavigator):
1882 pos = x._position
1883 x, y = pos - self._position
1884 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1885 result /= self._degreesPerAU
1886 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1887
1888 def heading(self):
1889 """ Return the turtle's current heading.
1890
1891 No arguments.
1892
1893 Example (for a Turtle instance named turtle):
1894 >>> turtle.left(67)
1895 >>> turtle.heading()
1896 67.0
1897 """
1898 x, y = self._orient
1899 result = round(math.atan2(y, x)*180.0/math.pi, 10) % 360.0
1900 result /= self._degreesPerAU
1901 return (self._angleOffset + self._angleOrient*result) % self._fullcircle
1902
1903 def setheading(self, to_angle):
1904 """Set the orientation of the turtle to to_angle.
1905
1906 Aliases: setheading | seth
1907
1908 Argument:
1909 to_angle -- a number (integer or float)
1910
1911 Set the orientation of the turtle to to_angle.
1912 Here are some common directions in degrees:
1913
1914 standard - mode: logo-mode:
1915 -------------------|--------------------
1916 0 - east 0 - north
1917 90 - north 90 - east
1918 180 - west 180 - south
1919 270 - south 270 - west
1920
1921 Example (for a Turtle instance named turtle):
1922 >>> turtle.setheading(90)
1923 >>> turtle.heading()
1924 90
1925 """
1926 angle = (to_angle - self.heading())*self._angleOrient
1927 full = self._fullcircle
1928 angle = (angle+full/2.)%full - full/2.
1929 self._rotate(angle)
1930
1931 def circle(self, radius, extent = None, steps = None):
1932 """ Draw a circle with given radius.
1933
1934 Arguments:
1935 radius -- a number
1936 extent (optional) -- a number
1937 steps (optional) -- an integer
1938
1939 Draw a circle with given radius. The center is radius units left
1940 of the turtle; extent - an angle - determines which part of the
1941 circle is drawn. If extent is not given, draw the entire circle.
1942 If extent is not a full circle, one endpoint of the arc is the
1943 current pen position. Draw the arc in counterclockwise direction
1944 if radius is positive, otherwise in clockwise direction. Finally
1945 the direction of the turtle is changed by the amount of extent.
1946
1947 As the circle is approximated by an inscribed regular polygon,
1948 steps determines the number of steps to use. If not given,
1949 it will be calculated automatically. Maybe used to draw regular
1950 polygons.
1951
1952 call: circle(radius) # full circle
1953 --or: circle(radius, extent) # arc
1954 --or: circle(radius, extent, steps)
1955 --or: circle(radius, steps=6) # 6-sided polygon
1956
1957 Example (for a Turtle instance named turtle):
1958 >>> turtle.circle(50)
1959 >>> turtle.circle(120, 180) # semicircle
1960 """
1961 if self.undobuffer:
1962 self.undobuffer.push(["seq"])
1963 self.undobuffer.cumulate = True
1964 speed = self.speed()
1965 if extent is None:
1966 extent = self._fullcircle
1967 if steps is None:
1968 frac = abs(extent)/self._fullcircle
1969 steps = 1+int(min(11+abs(radius)/6.0, 59.0)*frac)
1970 w = 1.0 * extent / steps
1971 w2 = 0.5 * w
1972 l = 2.0 * radius * math.sin(w2*math.pi/180.0*self._degreesPerAU)
1973 if radius < 0:
1974 l, w, w2 = -l, -w, -w2
1975 tr = self._tracer()
1976 dl = self._delay()
1977 if speed == 0:
1978 self._tracer(0, 0)
Thomas Wouters477c8d52006-05-27 19:21:47 +00001979 else:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001980 self.speed(0)
1981 self._rotate(w2)
1982 for i in range(steps):
1983 self.speed(speed)
1984 self._go(l)
1985 self.speed(0)
1986 self._rotate(w)
1987 self._rotate(-w2)
1988 if speed == 0:
1989 self._tracer(tr, dl)
1990 self.speed(speed)
1991 if self.undobuffer:
1992 self.undobuffer.cumulate = False
Thomas Wouters477c8d52006-05-27 19:21:47 +00001993
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001994## three dummy methods to be implemented by child class:
Thomas Wouters477c8d52006-05-27 19:21:47 +00001995
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00001996 def speed(self, s=0):
1997 """dummy method - to be overwritten by child class"""
1998 def _tracer(self, a=None, b=None):
1999 """dummy method - to be overwritten by child class"""
2000 def _delay(self, n=None):
2001 """dummy method - to be overwritten by child class"""
Thomas Wouters477c8d52006-05-27 19:21:47 +00002002
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002003 fd = forward
2004 bk = back
2005 backward = back
2006 rt = right
2007 lt = left
2008 position = pos
2009 setpos = goto
2010 setposition = goto
2011 seth = setheading
Thomas Wouters477c8d52006-05-27 19:21:47 +00002012
Thomas Wouters477c8d52006-05-27 19:21:47 +00002013
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002014class TPen(object):
2015 """Drawing part of the RawTurtle.
2016 Implements drawing properties.
2017 """
2018 def __init__(self, resizemode=_CFG["resizemode"]):
2019 self._resizemode = resizemode # or "user" or "noresize"
2020 self.undobuffer = None
2021 TPen._reset(self)
Thomas Wouters477c8d52006-05-27 19:21:47 +00002022
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002023 def _reset(self, pencolor=_CFG["pencolor"],
2024 fillcolor=_CFG["fillcolor"]):
2025 self._pensize = 1
2026 self._shown = True
2027 self._pencolor = pencolor
2028 self._fillcolor = fillcolor
2029 self._drawing = True
2030 self._speed = 3
Georg Brandleaa84ef2009-05-05 08:14:33 +00002031 self._stretchfactor = (1., 1.)
2032 self._shearfactor = 0.
2033 self._tilt = 0.
2034 self._shapetrafo = (1., 0., 0., 1.)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002035 self._outlinewidth = 1
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002036
2037 def resizemode(self, rmode=None):
2038 """Set resizemode to one of the values: "auto", "user", "noresize".
2039
2040 (Optional) Argument:
2041 rmode -- one of the strings "auto", "user", "noresize"
2042
2043 Different resizemodes have the following effects:
2044 - "auto" adapts the appearance of the turtle
2045 corresponding to the value of pensize.
2046 - "user" adapts the appearance of the turtle according to the
2047 values of stretchfactor and outlinewidth (outline),
2048 which are set by shapesize()
2049 - "noresize" no adaption of the turtle's appearance takes place.
2050 If no argument is given, return current resizemode.
2051 resizemode("user") is called by a call of shapesize with arguments.
2052
2053
2054 Examples (for a Turtle instance named turtle):
2055 >>> turtle.resizemode("noresize")
2056 >>> turtle.resizemode()
2057 'noresize'
Thomas Wouters477c8d52006-05-27 19:21:47 +00002058 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002059 if rmode is None:
2060 return self._resizemode
2061 rmode = rmode.lower()
2062 if rmode in ["auto", "user", "noresize"]:
2063 self.pen(resizemode=rmode)
Guido van Rossumb241b671998-12-04 16:42:46 +00002064
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002065 def pensize(self, width=None):
2066 """Set or return the line thickness.
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002067
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002068 Aliases: pensize | width
Thomas Wouters477c8d52006-05-27 19:21:47 +00002069
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002070 Argument:
2071 width -- positive number
Thomas Wouters477c8d52006-05-27 19:21:47 +00002072
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002073 Set the line thickness to width or return it. If resizemode is set
2074 to "auto" and turtleshape is a polygon, that polygon is drawn with
2075 the same line thickness. If no argument is given, current pensize
2076 is returned.
Thomas Wouters477c8d52006-05-27 19:21:47 +00002077
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002078 Example (for a Turtle instance named turtle):
2079 >>> turtle.pensize()
2080 1
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002081 >>> turtle.pensize(10) # from here on lines of width 10 are drawn
Thomas Wouters477c8d52006-05-27 19:21:47 +00002082 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002083 if width is None:
2084 return self._pensize
2085 self.pen(pensize=width)
Thomas Wouters477c8d52006-05-27 19:21:47 +00002086
2087
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002088 def penup(self):
2089 """Pull the pen up -- no drawing when moving.
Thomas Wouters477c8d52006-05-27 19:21:47 +00002090
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002091 Aliases: penup | pu | up
Thomas Wouters477c8d52006-05-27 19:21:47 +00002092
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002093 No argument
2094
2095 Example (for a Turtle instance named turtle):
2096 >>> turtle.penup()
Thomas Wouters477c8d52006-05-27 19:21:47 +00002097 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002098 if not self._drawing:
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002099 return
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002100 self.pen(pendown=False)
Guido van Rossum3c7a25a2001-08-09 16:42:07 +00002101
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002102 def pendown(self):
2103 """Pull the pen down -- drawing when moving.
2104
2105 Aliases: pendown | pd | down
2106
2107 No argument.
2108
2109 Example (for a Turtle instance named turtle):
2110 >>> turtle.pendown()
2111 """
2112 if self._drawing:
2113 return
2114 self.pen(pendown=True)
2115
2116 def isdown(self):
2117 """Return True if pen is down, False if it's up.
2118
2119 No argument.
2120
2121 Example (for a Turtle instance named turtle):
2122 >>> turtle.penup()
2123 >>> turtle.isdown()
2124 False
2125 >>> turtle.pendown()
2126 >>> turtle.isdown()
2127 True
2128 """
2129 return self._drawing
2130
2131 def speed(self, speed=None):
2132 """ Return or set the turtle's speed.
2133
2134 Optional argument:
2135 speed -- an integer in the range 0..10 or a speedstring (see below)
2136
2137 Set the turtle's speed to an integer value in the range 0 .. 10.
2138 If no argument is given: return current speed.
2139
2140 If input is a number greater than 10 or smaller than 0.5,
2141 speed is set to 0.
2142 Speedstrings are mapped to speedvalues in the following way:
2143 'fastest' : 0
2144 'fast' : 10
2145 'normal' : 6
2146 'slow' : 3
2147 'slowest' : 1
2148 speeds from 1 to 10 enforce increasingly faster animation of
2149 line drawing and turtle turning.
2150
2151 Attention:
2152 speed = 0 : *no* animation takes place. forward/back makes turtle jump
2153 and likewise left/right make the turtle turn instantly.
2154
2155 Example (for a Turtle instance named turtle):
2156 >>> turtle.speed(3)
2157 """
2158 speeds = {'fastest':0, 'fast':10, 'normal':6, 'slow':3, 'slowest':1 }
2159 if speed is None:
2160 return self._speed
2161 if speed in speeds:
2162 speed = speeds[speed]
2163 elif 0.5 < speed < 10.5:
2164 speed = int(round(speed))
2165 else:
2166 speed = 0
2167 self.pen(speed=speed)
2168
2169 def color(self, *args):
2170 """Return or set the pencolor and fillcolor.
2171
2172 Arguments:
2173 Several input formats are allowed.
2174 They use 0, 1, 2, or 3 arguments as follows:
2175
2176 color()
2177 Return the current pencolor and the current fillcolor
2178 as a pair of color specification strings as are returned
2179 by pencolor and fillcolor.
2180 color(colorstring), color((r,g,b)), color(r,g,b)
2181 inputs as in pencolor, set both, fillcolor and pencolor,
2182 to the given value.
2183 color(colorstring1, colorstring2),
2184 color((r1,g1,b1), (r2,g2,b2))
2185 equivalent to pencolor(colorstring1) and fillcolor(colorstring2)
2186 and analogously, if the other input format is used.
2187
2188 If turtleshape is a polygon, outline and interior of that polygon
2189 is drawn with the newly set colors.
2190 For mor info see: pencolor, fillcolor
2191
2192 Example (for a Turtle instance named turtle):
2193 >>> turtle.color('red', 'green')
2194 >>> turtle.color()
2195 ('red', 'green')
2196 >>> colormode(255)
2197 >>> color((40, 80, 120), (160, 200, 240))
2198 >>> color()
2199 ('#285078', '#a0c8f0')
2200 """
2201 if args:
2202 l = len(args)
2203 if l == 1:
2204 pcolor = fcolor = args[0]
2205 elif l == 2:
2206 pcolor, fcolor = args
2207 elif l == 3:
2208 pcolor = fcolor = args
2209 pcolor = self._colorstr(pcolor)
2210 fcolor = self._colorstr(fcolor)
2211 self.pen(pencolor=pcolor, fillcolor=fcolor)
2212 else:
2213 return self._color(self._pencolor), self._color(self._fillcolor)
2214
2215 def pencolor(self, *args):
2216 """ Return or set the pencolor.
2217
2218 Arguments:
2219 Four input formats are allowed:
2220 - pencolor()
2221 Return the current pencolor as color specification string,
2222 possibly in hex-number format (see example).
2223 May be used as input to another color/pencolor/fillcolor call.
2224 - pencolor(colorstring)
2225 s is a Tk color specification string, such as "red" or "yellow"
2226 - pencolor((r, g, b))
2227 *a tuple* of r, g, and b, which represent, an RGB color,
2228 and each of r, g, and b are in the range 0..colormode,
2229 where colormode is either 1.0 or 255
2230 - pencolor(r, g, b)
2231 r, g, and b represent an RGB color, and each of r, g, and b
2232 are in the range 0..colormode
2233
2234 If turtleshape is a polygon, the outline of that polygon is drawn
2235 with the newly set pencolor.
2236
2237 Example (for a Turtle instance named turtle):
2238 >>> turtle.pencolor('brown')
2239 >>> tup = (0.2, 0.8, 0.55)
2240 >>> turtle.pencolor(tup)
2241 >>> turtle.pencolor()
2242 '#33cc8c'
2243 """
2244 if args:
2245 color = self._colorstr(args)
2246 if color == self._pencolor:
2247 return
2248 self.pen(pencolor=color)
2249 else:
2250 return self._color(self._pencolor)
2251
2252 def fillcolor(self, *args):
2253 """ Return or set the fillcolor.
2254
2255 Arguments:
2256 Four input formats are allowed:
2257 - fillcolor()
2258 Return the current fillcolor as color specification string,
2259 possibly in hex-number format (see example).
2260 May be used as input to another color/pencolor/fillcolor call.
2261 - fillcolor(colorstring)
2262 s is a Tk color specification string, such as "red" or "yellow"
2263 - fillcolor((r, g, b))
2264 *a tuple* of r, g, and b, which represent, an RGB color,
2265 and each of r, g, and b are in the range 0..colormode,
2266 where colormode is either 1.0 or 255
2267 - fillcolor(r, g, b)
2268 r, g, and b represent an RGB color, and each of r, g, and b
2269 are in the range 0..colormode
2270
2271 If turtleshape is a polygon, the interior of that polygon is drawn
2272 with the newly set fillcolor.
2273
2274 Example (for a Turtle instance named turtle):
2275 >>> turtle.fillcolor('violet')
2276 >>> col = turtle.pencolor()
2277 >>> turtle.fillcolor(col)
2278 >>> turtle.fillcolor(0, .5, 0)
2279 """
2280 if args:
2281 color = self._colorstr(args)
2282 if color == self._fillcolor:
2283 return
2284 self.pen(fillcolor=color)
2285 else:
2286 return self._color(self._fillcolor)
2287
2288 def showturtle(self):
2289 """Makes the turtle visible.
2290
2291 Aliases: showturtle | st
2292
2293 No argument.
2294
2295 Example (for a Turtle instance named turtle):
2296 >>> turtle.hideturtle()
2297 >>> turtle.showturtle()
2298 """
2299 self.pen(shown=True)
2300
2301 def hideturtle(self):
2302 """Makes the turtle invisible.
2303
2304 Aliases: hideturtle | ht
2305
2306 No argument.
2307
2308 It's a good idea to do this while you're in the
2309 middle of a complicated drawing, because hiding
2310 the turtle speeds up the drawing observably.
2311
2312 Example (for a Turtle instance named turtle):
2313 >>> turtle.hideturtle()
2314 """
2315 self.pen(shown=False)
2316
2317 def isvisible(self):
2318 """Return True if the Turtle is shown, False if it's hidden.
2319
2320 No argument.
2321
2322 Example (for a Turtle instance named turtle):
2323 >>> turtle.hideturtle()
2324 >>> print turtle.isvisible():
2325 False
2326 """
2327 return self._shown
2328
2329 def pen(self, pen=None, **pendict):
2330 """Return or set the pen's attributes.
2331
2332 Arguments:
2333 pen -- a dictionary with some or all of the below listed keys.
2334 **pendict -- one or more keyword-arguments with the below
2335 listed keys as keywords.
2336
2337 Return or set the pen's attributes in a 'pen-dictionary'
2338 with the following key/value pairs:
2339 "shown" : True/False
2340 "pendown" : True/False
2341 "pencolor" : color-string or color-tuple
2342 "fillcolor" : color-string or color-tuple
2343 "pensize" : positive number
2344 "speed" : number in range 0..10
2345 "resizemode" : "auto" or "user" or "noresize"
2346 "stretchfactor": (positive number, positive number)
Georg Brandleaa84ef2009-05-05 08:14:33 +00002347 "shearfactor": number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002348 "outline" : positive number
2349 "tilt" : number
2350
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002351 This dictionary can be used as argument for a subsequent
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002352 pen()-call to restore the former pen-state. Moreover one
2353 or more of these attributes can be provided as keyword-arguments.
2354 This can be used to set several pen attributes in one statement.
Guido van Rossumb241b671998-12-04 16:42:46 +00002355
2356
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002357 Examples (for a Turtle instance named turtle):
2358 >>> turtle.pen(fillcolor="black", pencolor="red", pensize=10)
2359 >>> turtle.pen()
2360 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2361 'pencolor': 'red', 'pendown': True, 'fillcolor': 'black',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002362 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002363 >>> penstate=turtle.pen()
2364 >>> turtle.color("yellow","")
2365 >>> turtle.penup()
2366 >>> turtle.pen()
2367 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2368 'pencolor': 'yellow', 'pendown': False, 'fillcolor': '',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002369 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002370 >>> p.pen(penstate, fillcolor="green")
2371 >>> p.pen()
2372 {'pensize': 10, 'shown': True, 'resizemode': 'auto', 'outline': 1,
2373 'pencolor': 'red', 'pendown': True, 'fillcolor': 'green',
Georg Brandleaa84ef2009-05-05 08:14:33 +00002374 'stretchfactor': (1,1), 'speed': 3, 'shearfactor': 0.0}
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002375 """
2376 _pd = {"shown" : self._shown,
2377 "pendown" : self._drawing,
2378 "pencolor" : self._pencolor,
2379 "fillcolor" : self._fillcolor,
2380 "pensize" : self._pensize,
2381 "speed" : self._speed,
2382 "resizemode" : self._resizemode,
2383 "stretchfactor" : self._stretchfactor,
Georg Brandleaa84ef2009-05-05 08:14:33 +00002384 "shearfactor" : self._shearfactor,
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002385 "outline" : self._outlinewidth,
2386 "tilt" : self._tilt
2387 }
Guido van Rossumb241b671998-12-04 16:42:46 +00002388
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002389 if not (pen or pendict):
2390 return _pd
2391
2392 if isinstance(pen, dict):
2393 p = pen
2394 else:
2395 p = {}
2396 p.update(pendict)
2397
2398 _p_buf = {}
2399 for key in p:
2400 _p_buf[key] = _pd[key]
2401
2402 if self.undobuffer:
2403 self.undobuffer.push(("pen", _p_buf))
2404
2405 newLine = False
2406 if "pendown" in p:
2407 if self._drawing != p["pendown"]:
2408 newLine = True
2409 if "pencolor" in p:
2410 if isinstance(p["pencolor"], tuple):
2411 p["pencolor"] = self._colorstr((p["pencolor"],))
2412 if self._pencolor != p["pencolor"]:
2413 newLine = True
2414 if "pensize" in p:
2415 if self._pensize != p["pensize"]:
2416 newLine = True
2417 if newLine:
2418 self._newLine()
2419 if "pendown" in p:
2420 self._drawing = p["pendown"]
2421 if "pencolor" in p:
2422 self._pencolor = p["pencolor"]
2423 if "pensize" in p:
2424 self._pensize = p["pensize"]
2425 if "fillcolor" in p:
2426 if isinstance(p["fillcolor"], tuple):
2427 p["fillcolor"] = self._colorstr((p["fillcolor"],))
2428 self._fillcolor = p["fillcolor"]
2429 if "speed" in p:
2430 self._speed = p["speed"]
2431 if "resizemode" in p:
2432 self._resizemode = p["resizemode"]
2433 if "stretchfactor" in p:
2434 sf = p["stretchfactor"]
2435 if isinstance(sf, (int, float)):
2436 sf = (sf, sf)
2437 self._stretchfactor = sf
Georg Brandleaa84ef2009-05-05 08:14:33 +00002438 if "shearfactor" in p:
2439 self._shearfactor = p["shearfactor"]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002440 if "outline" in p:
2441 self._outlinewidth = p["outline"]
2442 if "shown" in p:
2443 self._shown = p["shown"]
2444 if "tilt" in p:
2445 self._tilt = p["tilt"]
Georg Brandleaa84ef2009-05-05 08:14:33 +00002446 if "stretchfactor" in p or "tilt" in p or "shearfactor" in p:
2447 scx, scy = self._stretchfactor
2448 shf = self._shearfactor
2449 sa, ca = math.sin(self._tilt), math.cos(self._tilt)
2450 self._shapetrafo = ( scx*ca, scy*(shf*ca + sa),
2451 -scx*sa, scy*(ca - shf*sa))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002452 self._update()
2453
2454## three dummy methods to be implemented by child class:
2455
2456 def _newLine(self, usePos = True):
2457 """dummy method - to be overwritten by child class"""
2458 def _update(self, count=True, forced=False):
2459 """dummy method - to be overwritten by child class"""
2460 def _color(self, args):
2461 """dummy method - to be overwritten by child class"""
2462 def _colorstr(self, args):
2463 """dummy method - to be overwritten by child class"""
2464
2465 width = pensize
2466 up = penup
2467 pu = penup
2468 pd = pendown
2469 down = pendown
2470 st = showturtle
2471 ht = hideturtle
2472
2473
2474class _TurtleImage(object):
2475 """Helper class: Datatype to store Turtle attributes
2476 """
2477
2478 def __init__(self, screen, shapeIndex):
2479 self.screen = screen
2480 self._type = None
2481 self._setshape(shapeIndex)
2482
2483 def _setshape(self, shapeIndex):
Georg Brandleaa84ef2009-05-05 08:14:33 +00002484 screen = self.screen
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002485 self.shapeIndex = shapeIndex
2486 if self._type == "polygon" == screen._shapes[shapeIndex]._type:
2487 return
2488 if self._type == "image" == screen._shapes[shapeIndex]._type:
2489 return
2490 if self._type in ["image", "polygon"]:
2491 screen._delete(self._item)
2492 elif self._type == "compound":
2493 for item in self._item:
2494 screen._delete(item)
2495 self._type = screen._shapes[shapeIndex]._type
2496 if self._type == "polygon":
2497 self._item = screen._createpoly()
2498 elif self._type == "image":
2499 self._item = screen._createimage(screen._shapes["blank"]._data)
2500 elif self._type == "compound":
2501 self._item = [screen._createpoly() for item in
2502 screen._shapes[shapeIndex]._data]
2503
2504
2505class RawTurtle(TPen, TNavigator):
2506 """Animation part of the RawTurtle.
2507 Puts RawTurtle upon a TurtleScreen and provides tools for
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002508 its animation.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002509 """
2510 screens = []
2511
2512 def __init__(self, canvas=None,
2513 shape=_CFG["shape"],
2514 undobuffersize=_CFG["undobuffersize"],
2515 visible=_CFG["visible"]):
Martin v. Löwis601149b2008-09-29 22:19:08 +00002516 if isinstance(canvas, _Screen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002517 self.screen = canvas
2518 elif isinstance(canvas, TurtleScreen):
2519 if canvas not in RawTurtle.screens:
2520 RawTurtle.screens.append(canvas)
2521 self.screen = canvas
2522 elif isinstance(canvas, (ScrolledCanvas, Canvas)):
2523 for screen in RawTurtle.screens:
2524 if screen.cv == canvas:
2525 self.screen = screen
2526 break
2527 else:
2528 self.screen = TurtleScreen(canvas)
2529 RawTurtle.screens.append(self.screen)
2530 else:
2531 raise TurtleGraphicsError("bad cavas argument %s" % canvas)
2532
2533 screen = self.screen
2534 TNavigator.__init__(self, screen.mode())
2535 TPen.__init__(self)
2536 screen._turtles.append(self)
2537 self.drawingLineItem = screen._createline()
2538 self.turtle = _TurtleImage(screen, shape)
2539 self._poly = None
2540 self._creatingPoly = False
2541 self._fillitem = self._fillpath = None
2542 self._shown = visible
2543 self._hidden_from_screen = False
2544 self.currentLineItem = screen._createline()
2545 self.currentLine = [self._position]
2546 self.items = [self.currentLineItem]
2547 self.stampItems = []
2548 self._undobuffersize = undobuffersize
2549 self.undobuffer = Tbuffer(undobuffersize)
2550 self._update()
2551
2552 def reset(self):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00002553 """Delete the turtle's drawings and restore its default values.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002554
2555 No argument.
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002556
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002557 Delete the turtle's drawings from the screen, re-center the turtle
2558 and set variables to the default values.
2559
2560 Example (for a Turtle instance named turtle):
2561 >>> turtle.position()
2562 (0.00,-22.00)
2563 >>> turtle.heading()
2564 100.0
2565 >>> turtle.reset()
2566 >>> turtle.position()
2567 (0.00,0.00)
2568 >>> turtle.heading()
2569 0.0
2570 """
2571 TNavigator.reset(self)
2572 TPen._reset(self)
2573 self._clear()
2574 self._drawturtle()
2575 self._update()
2576
2577 def setundobuffer(self, size):
2578 """Set or disable undobuffer.
2579
2580 Argument:
2581 size -- an integer or None
2582
2583 If size is an integer an empty undobuffer of given size is installed.
2584 Size gives the maximum number of turtle-actions that can be undone
2585 by the undo() function.
2586 If size is None, no undobuffer is present.
2587
2588 Example (for a Turtle instance named turtle):
2589 >>> turtle.setundobuffer(42)
2590 """
2591 if size is None:
2592 self.undobuffer = None
2593 else:
2594 self.undobuffer = Tbuffer(size)
2595
2596 def undobufferentries(self):
2597 """Return count of entries in the undobuffer.
2598
2599 No argument.
2600
2601 Example (for a Turtle instance named turtle):
2602 >>> while undobufferentries():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002603 ... undo()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002604 """
2605 if self.undobuffer is None:
2606 return 0
2607 return self.undobuffer.nr_of_items()
2608
2609 def _clear(self):
2610 """Delete all of pen's drawings"""
2611 self._fillitem = self._fillpath = None
2612 for item in self.items:
2613 self.screen._delete(item)
2614 self.currentLineItem = self.screen._createline()
2615 self.currentLine = []
2616 if self._drawing:
2617 self.currentLine.append(self._position)
2618 self.items = [self.currentLineItem]
2619 self.clearstamps()
2620 self.setundobuffer(self._undobuffersize)
2621
2622
2623 def clear(self):
2624 """Delete the turtle's drawings from the screen. Do not move turtle.
2625
2626 No arguments.
2627
2628 Delete the turtle's drawings from the screen. Do not move turtle.
2629 State and position of the turtle as well as drawings of other
2630 turtles are not affected.
2631
2632 Examples (for a Turtle instance named turtle):
2633 >>> turtle.clear()
2634 """
2635 self._clear()
2636 self._update()
2637
2638 def _update_data(self):
2639 self.screen._incrementudc()
2640 if self.screen._updatecounter != 0:
2641 return
2642 if len(self.currentLine)>1:
2643 self.screen._drawline(self.currentLineItem, self.currentLine,
2644 self._pencolor, self._pensize)
2645
2646 def _update(self):
2647 """Perform a Turtle-data update.
2648 """
2649 screen = self.screen
2650 if screen._tracing == 0:
2651 return
2652 elif screen._tracing == 1:
2653 self._update_data()
2654 self._drawturtle()
2655 screen._update() # TurtleScreenBase
2656 screen._delay(screen._delayvalue) # TurtleScreenBase
2657 else:
2658 self._update_data()
2659 if screen._updatecounter == 0:
2660 for t in screen.turtles():
2661 t._drawturtle()
2662 screen._update()
2663
2664 def _tracer(self, flag=None, delay=None):
2665 """Turns turtle animation on/off and set delay for update drawings.
2666
2667 Optional arguments:
2668 n -- nonnegative integer
2669 delay -- nonnegative integer
2670
2671 If n is given, only each n-th regular screen update is really performed.
2672 (Can be used to accelerate the drawing of complex graphics.)
2673 Second arguments sets delay value (see RawTurtle.delay())
2674
2675 Example (for a Turtle instance named turtle):
2676 >>> turtle.tracer(8, 25)
2677 >>> dist = 2
2678 >>> for i in range(200):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002679 ... turtle.fd(dist)
2680 ... turtle.rt(90)
2681 ... dist += 2
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002682 """
2683 return self.screen.tracer(flag, delay)
2684
2685 def _color(self, args):
2686 return self.screen._color(args)
2687
2688 def _colorstr(self, args):
2689 return self.screen._colorstr(args)
2690
2691 def _cc(self, args):
2692 """Convert colortriples to hexstrings.
2693 """
2694 if isinstance(args, str):
2695 return args
2696 try:
2697 r, g, b = args
2698 except:
2699 raise TurtleGraphicsError("bad color arguments: %s" % str(args))
2700 if self.screen._colormode == 1.0:
2701 r, g, b = [round(255.0*x) for x in (r, g, b)]
2702 if not ((0 <= r <= 255) and (0 <= g <= 255) and (0 <= b <= 255)):
2703 raise TurtleGraphicsError("bad color sequence: %s" % str(args))
2704 return "#%02x%02x%02x" % (r, g, b)
2705
2706 def clone(self):
2707 """Create and return a clone of the turtle.
2708
2709 No argument.
2710
2711 Create and return a clone of the turtle with same position, heading
2712 and turtle properties.
2713
2714 Example (for a Turtle instance named mick):
2715 mick = Turtle()
2716 joe = mick.clone()
2717 """
2718 screen = self.screen
2719 self._newLine(self._drawing)
2720
2721 turtle = self.turtle
2722 self.screen = None
2723 self.turtle = None # too make self deepcopy-able
2724
2725 q = deepcopy(self)
2726
2727 self.screen = screen
2728 self.turtle = turtle
2729
2730 q.screen = screen
2731 q.turtle = _TurtleImage(screen, self.turtle.shapeIndex)
2732
2733 screen._turtles.append(q)
2734 ttype = screen._shapes[self.turtle.shapeIndex]._type
2735 if ttype == "polygon":
2736 q.turtle._item = screen._createpoly()
2737 elif ttype == "image":
2738 q.turtle._item = screen._createimage(screen._shapes["blank"]._data)
2739 elif ttype == "compound":
2740 q.turtle._item = [screen._createpoly() for item in
2741 screen._shapes[self.turtle.shapeIndex]._data]
2742 q.currentLineItem = screen._createline()
2743 q._update()
2744 return q
2745
2746 def shape(self, name=None):
2747 """Set turtle shape to shape with given name / return current shapename.
2748
2749 Optional argument:
2750 name -- a string, which is a valid shapename
2751
2752 Set turtle shape to shape with given name or, if name is not given,
2753 return name of current shape.
2754 Shape with name must exist in the TurtleScreen's shape dictionary.
2755 Initially there are the following polygon shapes:
2756 'arrow', 'turtle', 'circle', 'square', 'triangle', 'classic'.
2757 To learn about how to deal with shapes see Screen-method register_shape.
2758
2759 Example (for a Turtle instance named turtle):
2760 >>> turtle.shape()
2761 'arrow'
2762 >>> turtle.shape("turtle")
2763 >>> turtle.shape()
2764 'turtle'
2765 """
2766 if name is None:
2767 return self.turtle.shapeIndex
2768 if not name in self.screen.getshapes():
2769 raise TurtleGraphicsError("There is no shape named %s" % name)
2770 self.turtle._setshape(name)
2771 self._update()
2772
2773 def shapesize(self, stretch_wid=None, stretch_len=None, outline=None):
2774 """Set/return turtle's stretchfactors/outline. Set resizemode to "user".
2775
2776 Optinonal arguments:
2777 stretch_wid : positive number
2778 stretch_len : positive number
2779 outline : positive number
2780
2781 Return or set the pen's attributes x/y-stretchfactors and/or outline.
2782 Set resizemode to "user".
2783 If and only if resizemode is set to "user", the turtle will be displayed
2784 stretched according to its stretchfactors:
2785 stretch_wid is stretchfactor perpendicular to orientation
2786 stretch_len is stretchfactor in direction of turtles orientation.
2787 outline determines the width of the shapes's outline.
2788
2789 Examples (for a Turtle instance named turtle):
2790 >>> turtle.resizemode("user")
2791 >>> turtle.shapesize(5, 5, 12)
2792 >>> turtle.shapesize(outline=8)
2793 """
Florent Xiclunafd1b0932010-03-28 00:25:02 +00002794 if stretch_wid is stretch_len is outline is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002795 stretch_wid, stretch_len = self._stretchfactor
2796 return stretch_wid, stretch_len, self._outlinewidth
Georg Brandleaa84ef2009-05-05 08:14:33 +00002797 if stretch_wid == 0 or stretch_len == 0:
2798 raise TurtleGraphicsError("stretch_wid/stretch_len must not be zero")
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002799 if stretch_wid is not None:
2800 if stretch_len is None:
2801 stretchfactor = stretch_wid, stretch_wid
2802 else:
2803 stretchfactor = stretch_wid, stretch_len
2804 elif stretch_len is not None:
2805 stretchfactor = self._stretchfactor[0], stretch_len
2806 else:
2807 stretchfactor = self._stretchfactor
2808 if outline is None:
2809 outline = self._outlinewidth
2810 self.pen(resizemode="user",
2811 stretchfactor=stretchfactor, outline=outline)
2812
Georg Brandleaa84ef2009-05-05 08:14:33 +00002813 def shearfactor(self, shear=None):
2814 """Set or return the current shearfactor.
2815
2816 Optional argument: shear -- number, tangent of the shear angle
2817
2818 Shear the turtleshape according to the given shearfactor shear,
2819 which is the tangent of the shear angle. DO NOT change the
2820 turtle's heading (direction of movement).
2821 If shear is not given: return the current shearfactor, i. e. the
2822 tangent of the shear angle, by which lines parallel to the
2823 heading of the turtle are sheared.
2824
2825 Examples (for a Turtle instance named turtle):
2826 >>> turtle.shape("circle")
2827 >>> turtle.shapesize(5,2)
2828 >>> turtle.shearfactor(0.5)
2829 >>> turtle.shearfactor()
2830 >>> 0.5
2831 """
2832 if shear is None:
2833 return self._shearfactor
2834 self.pen(resizemode="user", shearfactor=shear)
2835
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002836 def settiltangle(self, angle):
2837 """Rotate the turtleshape to point in the specified direction
2838
Georg Brandleaa84ef2009-05-05 08:14:33 +00002839 Argument: angle -- number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002840
2841 Rotate the turtleshape to point in the direction specified by angle,
2842 regardless of its current tilt-angle. DO NOT change the turtle's
2843 heading (direction of movement).
2844
2845
2846 Examples (for a Turtle instance named turtle):
2847 >>> turtle.shape("circle")
2848 >>> turtle.shapesize(5,2)
2849 >>> turtle.settiltangle(45)
2850 >>> stamp()
2851 >>> turtle.fd(50)
2852 >>> turtle.settiltangle(-45)
2853 >>> stamp()
2854 >>> turtle.fd(50)
2855 """
2856 tilt = -angle * self._degreesPerAU * self._angleOrient
2857 tilt = (tilt * math.pi / 180.0) % (2*math.pi)
2858 self.pen(resizemode="user", tilt=tilt)
2859
Georg Brandleaa84ef2009-05-05 08:14:33 +00002860 def tiltangle(self, angle=None):
2861 """Set or return the current tilt-angle.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002862
Georg Brandleaa84ef2009-05-05 08:14:33 +00002863 Optional argument: angle -- number
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002864
Georg Brandleaa84ef2009-05-05 08:14:33 +00002865 Rotate the turtleshape to point in the direction specified by angle,
2866 regardless of its current tilt-angle. DO NOT change the turtle's
2867 heading (direction of movement).
2868 If angle is not given: return the current tilt-angle, i. e. the angle
2869 between the orientation of the turtleshape and the heading of the
2870 turtle (its direction of movement).
2871
2872 Deprecated since Python 3.1
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002873
2874 Examples (for a Turtle instance named turtle):
2875 >>> turtle.shape("circle")
2876 >>> turtle.shapesize(5,2)
2877 >>> turtle.tilt(45)
2878 >>> turtle.tiltangle()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002879 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00002880 if angle is None:
2881 tilt = -self._tilt * (180.0/math.pi) * self._angleOrient
2882 return (tilt / self._degreesPerAU) % self._fullcircle
2883 else:
2884 self.settiltangle(angle)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002885
2886 def tilt(self, angle):
2887 """Rotate the turtleshape by angle.
2888
2889 Argument:
2890 angle - a number
2891
2892 Rotate the turtleshape by angle from its current tilt-angle,
2893 but do NOT change the turtle's heading (direction of movement).
2894
2895 Examples (for a Turtle instance named turtle):
2896 >>> turtle.shape("circle")
2897 >>> turtle.shapesize(5,2)
2898 >>> turtle.tilt(30)
2899 >>> turtle.fd(50)
2900 >>> turtle.tilt(30)
2901 >>> turtle.fd(50)
2902 """
2903 self.settiltangle(angle + self.tiltangle())
2904
Georg Brandleaa84ef2009-05-05 08:14:33 +00002905 def shapetransform(self, t11=None, t12=None, t21=None, t22=None):
2906 """Set or return the current transformation matrix of the turtle shape.
2907
2908 Optional arguments: t11, t12, t21, t22 -- numbers.
2909
2910 If none of the matrix elements are given, return the transformation
2911 matrix.
2912 Otherwise set the given elements and transform the turtleshape
2913 according to the matrix consisting of first row t11, t12 and
2914 second row t21, 22.
2915 Modify stretchfactor, shearfactor and tiltangle according to the
2916 given matrix.
2917
2918 Examples (for a Turtle instance named turtle):
2919 >>> turtle.shape("square")
2920 >>> turtle.shapesize(4,2)
2921 >>> turtle.shearfactor(-0.5)
2922 >>> turtle.shapetransform()
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02002923 (4.0, -1.0, -0.0, 2.0)
Georg Brandleaa84ef2009-05-05 08:14:33 +00002924 """
2925 if t11 is t12 is t21 is t22 is None:
2926 return self._shapetrafo
2927 m11, m12, m21, m22 = self._shapetrafo
2928 if t11 is not None: m11 = t11
2929 if t12 is not None: m12 = t12
2930 if t21 is not None: m21 = t21
2931 if t22 is not None: m22 = t22
2932 if t11 * t22 - t12 * t21 == 0:
2933 raise TurtleGraphicsError("Bad shape transform matrix: must not be singular")
2934 self._shapetrafo = (m11, m12, m21, m22)
2935 alfa = math.atan2(-m21, m11) % (2 * math.pi)
2936 sa, ca = math.sin(alfa), math.cos(alfa)
2937 a11, a12, a21, a22 = (ca*m11 - sa*m21, ca*m12 - sa*m22,
2938 sa*m11 + ca*m21, sa*m12 + ca*m22)
2939 self._stretchfactor = a11, a22
2940 self._shearfactor = a12/a22
2941 self._tilt = alfa
2942 self._update()
2943
2944
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002945 def _polytrafo(self, poly):
2946 """Computes transformed polygon shapes from a shape
2947 according to current position and heading.
2948 """
2949 screen = self.screen
2950 p0, p1 = self._position
2951 e0, e1 = self._orient
2952 e = Vec2D(e0, e1 * screen.yscale / screen.xscale)
2953 e0, e1 = (1.0 / abs(e)) * e
2954 return [(p0+(e1*x+e0*y)/screen.xscale, p1+(-e0*x+e1*y)/screen.yscale)
2955 for (x, y) in poly]
2956
Georg Brandleaa84ef2009-05-05 08:14:33 +00002957 def get_shapepoly(self):
2958 """Return the current shape polygon as tuple of coordinate pairs.
2959
2960 No argument.
2961
2962 Examples (for a Turtle instance named turtle):
2963 >>> turtle.shape("square")
2964 >>> turtle.shapetransform(4, -1, 0, 2)
2965 >>> turtle.get_shapepoly()
2966 ((50, -20), (30, 20), (-50, 20), (-30, -20))
2967
2968 """
2969 shape = self.screen._shapes[self.turtle.shapeIndex]
2970 if shape._type == "polygon":
2971 return self._getshapepoly(shape._data, shape._type == "compound")
2972 # else return None
2973
2974 def _getshapepoly(self, polygon, compound=False):
2975 """Calculate transformed shape polygon according to resizemode
2976 and shapetransform.
2977 """
2978 if self._resizemode == "user" or compound:
2979 t11, t12, t21, t22 = self._shapetrafo
2980 elif self._resizemode == "auto":
2981 l = max(1, self._pensize/5.0)
2982 t11, t12, t21, t22 = l, 0, 0, l
2983 elif self._resizemode == "noresize":
2984 return polygon
2985 return tuple([(t11*x + t12*y, t21*x + t22*y) for (x, y) in polygon])
2986
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002987 def _drawturtle(self):
2988 """Manages the correct rendering of the turtle with respect to
Mark Dickinson934896d2009-02-21 20:59:32 +00002989 its shape, resizemode, stretch and tilt etc."""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00002990 screen = self.screen
2991 shape = screen._shapes[self.turtle.shapeIndex]
2992 ttype = shape._type
2993 titem = self.turtle._item
2994 if self._shown and screen._updatecounter == 0 and screen._tracing > 0:
2995 self._hidden_from_screen = False
2996 tshape = shape._data
2997 if ttype == "polygon":
Georg Brandleaa84ef2009-05-05 08:14:33 +00002998 if self._resizemode == "noresize": w = 1
2999 elif self._resizemode == "auto": w = self._pensize
3000 else: w =self._outlinewidth
3001 shape = self._polytrafo(self._getshapepoly(tshape))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003002 fc, oc = self._fillcolor, self._pencolor
3003 screen._drawpoly(titem, shape, fill=fc, outline=oc,
3004 width=w, top=True)
3005 elif ttype == "image":
3006 screen._drawimage(titem, self._position, tshape)
3007 elif ttype == "compound":
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003008 for item, (poly, fc, oc) in zip(titem, tshape):
Georg Brandleaa84ef2009-05-05 08:14:33 +00003009 poly = self._polytrafo(self._getshapepoly(poly, True))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003010 screen._drawpoly(item, poly, fill=self._cc(fc),
Georg Brandleaa84ef2009-05-05 08:14:33 +00003011 outline=self._cc(oc), width=self._outlinewidth, top=True)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003012 else:
3013 if self._hidden_from_screen:
3014 return
3015 if ttype == "polygon":
3016 screen._drawpoly(titem, ((0, 0), (0, 0), (0, 0)), "", "")
3017 elif ttype == "image":
3018 screen._drawimage(titem, self._position,
3019 screen._shapes["blank"]._data)
3020 elif ttype == "compound":
3021 for item in titem:
3022 screen._drawpoly(item, ((0, 0), (0, 0), (0, 0)), "", "")
3023 self._hidden_from_screen = True
3024
3025############################## stamp stuff ###############################
3026
3027 def stamp(self):
Mark Dickinsonf8798f52009-02-20 20:53:56 +00003028 """Stamp a copy of the turtleshape onto the canvas and return its id.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003029
3030 No argument.
3031
3032 Stamp a copy of the turtle shape onto the canvas at the current
3033 turtle position. Return a stamp_id for that stamp, which can be
3034 used to delete it by calling clearstamp(stamp_id).
3035
3036 Example (for a Turtle instance named turtle):
3037 >>> turtle.color("blue")
3038 >>> turtle.stamp()
3039 13
3040 >>> turtle.fd(50)
3041 """
3042 screen = self.screen
3043 shape = screen._shapes[self.turtle.shapeIndex]
3044 ttype = shape._type
3045 tshape = shape._data
3046 if ttype == "polygon":
3047 stitem = screen._createpoly()
Georg Brandleaa84ef2009-05-05 08:14:33 +00003048 if self._resizemode == "noresize": w = 1
3049 elif self._resizemode == "auto": w = self._pensize
3050 else: w =self._outlinewidth
3051 shape = self._polytrafo(self._getshapepoly(tshape))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003052 fc, oc = self._fillcolor, self._pencolor
3053 screen._drawpoly(stitem, shape, fill=fc, outline=oc,
3054 width=w, top=True)
3055 elif ttype == "image":
3056 stitem = screen._createimage("")
3057 screen._drawimage(stitem, self._position, tshape)
3058 elif ttype == "compound":
3059 stitem = []
3060 for element in tshape:
3061 item = screen._createpoly()
3062 stitem.append(item)
3063 stitem = tuple(stitem)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003064 for item, (poly, fc, oc) in zip(stitem, tshape):
Georg Brandleaa84ef2009-05-05 08:14:33 +00003065 poly = self._polytrafo(self._getshapepoly(poly, True))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003066 screen._drawpoly(item, poly, fill=self._cc(fc),
Georg Brandleaa84ef2009-05-05 08:14:33 +00003067 outline=self._cc(oc), width=self._outlinewidth, top=True)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003068 self.stampItems.append(stitem)
3069 self.undobuffer.push(("stamp", stitem))
3070 return stitem
3071
3072 def _clearstamp(self, stampid):
3073 """does the work for clearstamp() and clearstamps()
3074 """
3075 if stampid in self.stampItems:
3076 if isinstance(stampid, tuple):
3077 for subitem in stampid:
3078 self.screen._delete(subitem)
3079 else:
3080 self.screen._delete(stampid)
3081 self.stampItems.remove(stampid)
3082 # Delete stampitem from undobuffer if necessary
3083 # if clearstamp is called directly.
3084 item = ("stamp", stampid)
3085 buf = self.undobuffer
3086 if item not in buf.buffer:
3087 return
3088 index = buf.buffer.index(item)
3089 buf.buffer.remove(item)
3090 if index <= buf.ptr:
3091 buf.ptr = (buf.ptr - 1) % buf.bufsize
3092 buf.buffer.insert((buf.ptr+1)%buf.bufsize, [None])
3093
3094 def clearstamp(self, stampid):
3095 """Delete stamp with given stampid
3096
3097 Argument:
3098 stampid - an integer, must be return value of previous stamp() call.
3099
3100 Example (for a Turtle instance named turtle):
3101 >>> turtle.color("blue")
3102 >>> astamp = turtle.stamp()
3103 >>> turtle.fd(50)
3104 >>> turtle.clearstamp(astamp)
3105 """
3106 self._clearstamp(stampid)
3107 self._update()
3108
3109 def clearstamps(self, n=None):
3110 """Delete all or first/last n of turtle's stamps.
3111
3112 Optional argument:
3113 n -- an integer
3114
3115 If n is None, delete all of pen's stamps,
3116 else if n > 0 delete first n stamps
3117 else if n < 0 delete last n stamps.
3118
3119 Example (for a Turtle instance named turtle):
3120 >>> for i in range(8):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003121 ... turtle.stamp(); turtle.fd(30)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003122 ...
3123 >>> turtle.clearstamps(2)
3124 >>> turtle.clearstamps(-2)
3125 >>> turtle.clearstamps()
3126 """
3127 if n is None:
3128 toDelete = self.stampItems[:]
3129 elif n >= 0:
3130 toDelete = self.stampItems[:n]
3131 else:
3132 toDelete = self.stampItems[n:]
3133 for item in toDelete:
3134 self._clearstamp(item)
3135 self._update()
3136
3137 def _goto(self, end):
3138 """Move the pen to the point end, thereby drawing a line
3139 if pen is down. All other methodes for turtle movement depend
3140 on this one.
3141 """
Alexander Belopolsky1842d0c2010-10-28 20:13:52 +00003142 ## Version with undo-stuff
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003143 go_modes = ( self._drawing,
3144 self._pencolor,
3145 self._pensize,
3146 isinstance(self._fillpath, list))
3147 screen = self.screen
3148 undo_entry = ("go", self._position, end, go_modes,
3149 (self.currentLineItem,
3150 self.currentLine[:],
3151 screen._pointlist(self.currentLineItem),
3152 self.items[:])
3153 )
3154 if self.undobuffer:
3155 self.undobuffer.push(undo_entry)
3156 start = self._position
3157 if self._speed and screen._tracing == 1:
3158 diff = (end-start)
3159 diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3160 nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3161 delta = diff * (1.0/nhops)
3162 for n in range(1, nhops):
3163 if n == 1:
3164 top = True
3165 else:
3166 top = False
3167 self._position = start + delta * n
3168 if self._drawing:
3169 screen._drawline(self.drawingLineItem,
3170 (start, self._position),
3171 self._pencolor, self._pensize, top)
3172 self._update()
3173 if self._drawing:
3174 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3175 fill="", width=self._pensize)
3176 # Turtle now at end,
3177 if self._drawing: # now update currentLine
3178 self.currentLine.append(end)
3179 if isinstance(self._fillpath, list):
3180 self._fillpath.append(end)
3181 ###### vererbung!!!!!!!!!!!!!!!!!!!!!!
3182 self._position = end
3183 if self._creatingPoly:
3184 self._poly.append(end)
3185 if len(self.currentLine) > 42: # 42! answer to the ultimate question
3186 # of life, the universe and everything
3187 self._newLine()
3188 self._update() #count=True)
3189
3190 def _undogoto(self, entry):
3191 """Reverse a _goto. Used for undo()
3192 """
3193 old, new, go_modes, coodata = entry
3194 drawing, pc, ps, filling = go_modes
3195 cLI, cL, pl, items = coodata
3196 screen = self.screen
3197 if abs(self._position - new) > 0.5:
3198 print ("undogoto: HALLO-DA-STIMMT-WAS-NICHT!")
3199 # restore former situation
3200 self.currentLineItem = cLI
3201 self.currentLine = cL
3202
3203 if pl == [(0, 0), (0, 0)]:
3204 usepc = ""
3205 else:
3206 usepc = pc
3207 screen._drawline(cLI, pl, fill=usepc, width=ps)
3208
3209 todelete = [i for i in self.items if (i not in items) and
3210 (screen._type(i) == "line")]
3211 for i in todelete:
3212 screen._delete(i)
3213 self.items.remove(i)
3214
3215 start = old
3216 if self._speed and screen._tracing == 1:
3217 diff = old - new
3218 diffsq = (diff[0]*screen.xscale)**2 + (diff[1]*screen.yscale)**2
3219 nhops = 1+int((diffsq**0.5)/(3*(1.1**self._speed)*self._speed))
3220 delta = diff * (1.0/nhops)
3221 for n in range(1, nhops):
3222 if n == 1:
3223 top = True
3224 else:
3225 top = False
3226 self._position = new + delta * n
3227 if drawing:
3228 screen._drawline(self.drawingLineItem,
3229 (start, self._position),
3230 pc, ps, top)
3231 self._update()
3232 if drawing:
3233 screen._drawline(self.drawingLineItem, ((0, 0), (0, 0)),
3234 fill="", width=ps)
3235 # Turtle now at position old,
3236 self._position = old
Ezio Melotti13925002011-03-16 11:05:33 +02003237 ## if undo is done during creating a polygon, the last vertex
3238 ## will be deleted. if the polygon is entirely deleted,
3239 ## creatingPoly will be set to False.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003240 ## Polygons created before the last one will not be affected by undo()
3241 if self._creatingPoly:
3242 if len(self._poly) > 0:
3243 self._poly.pop()
3244 if self._poly == []:
3245 self._creatingPoly = False
3246 self._poly = None
3247 if filling:
3248 if self._fillpath == []:
3249 self._fillpath = None
3250 print("Unwahrscheinlich in _undogoto!")
3251 elif self._fillpath is not None:
3252 self._fillpath.pop()
3253 self._update() #count=True)
3254
3255 def _rotate(self, angle):
3256 """Turns pen clockwise by angle.
3257 """
3258 if self.undobuffer:
3259 self.undobuffer.push(("rot", angle, self._degreesPerAU))
3260 angle *= self._degreesPerAU
3261 neworient = self._orient.rotate(angle)
3262 tracing = self.screen._tracing
3263 if tracing == 1 and self._speed > 0:
3264 anglevel = 3.0 * self._speed
3265 steps = 1 + int(abs(angle)/anglevel)
3266 delta = 1.0*angle/steps
3267 for _ in range(steps):
3268 self._orient = self._orient.rotate(delta)
3269 self._update()
3270 self._orient = neworient
3271 self._update()
3272
3273 def _newLine(self, usePos=True):
3274 """Closes current line item and starts a new one.
3275 Remark: if current line became too long, animation
3276 performance (via _drawline) slowed down considerably.
3277 """
3278 if len(self.currentLine) > 1:
3279 self.screen._drawline(self.currentLineItem, self.currentLine,
3280 self._pencolor, self._pensize)
3281 self.currentLineItem = self.screen._createline()
3282 self.items.append(self.currentLineItem)
3283 else:
3284 self.screen._drawline(self.currentLineItem, top=True)
3285 self.currentLine = []
3286 if usePos:
3287 self.currentLine = [self._position]
3288
3289 def filling(self):
3290 """Return fillstate (True if filling, False else).
3291
3292 No argument.
3293
3294 Example (for a Turtle instance named turtle):
3295 >>> turtle.begin_fill()
3296 >>> if turtle.filling():
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003297 ... turtle.pensize(5)
3298 ... else:
3299 ... turtle.pensize(3)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003300 """
3301 return isinstance(self._fillpath, list)
3302
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003303 def begin_fill(self):
3304 """Called just before drawing a shape to be filled.
3305
3306 No argument.
3307
3308 Example (for a Turtle instance named turtle):
3309 >>> turtle.color("black", "red")
3310 >>> turtle.begin_fill()
3311 >>> turtle.circle(60)
3312 >>> turtle.end_fill()
3313 """
3314 if not self.filling():
3315 self._fillitem = self.screen._createpoly()
3316 self.items.append(self._fillitem)
3317 self._fillpath = [self._position]
3318 self._newLine()
3319 if self.undobuffer:
3320 self.undobuffer.push(("beginfill", self._fillitem))
3321 self._update()
3322
3323
3324 def end_fill(self):
3325 """Fill the shape drawn after the call begin_fill().
3326
3327 No argument.
3328
3329 Example (for a Turtle instance named turtle):
3330 >>> turtle.color("black", "red")
3331 >>> turtle.begin_fill()
3332 >>> turtle.circle(60)
3333 >>> turtle.end_fill()
3334 """
3335 if self.filling():
3336 if len(self._fillpath) > 2:
3337 self.screen._drawpoly(self._fillitem, self._fillpath,
3338 fill=self._fillcolor)
3339 if self.undobuffer:
3340 self.undobuffer.push(("dofill", self._fillitem))
3341 self._fillitem = self._fillpath = None
3342 self._update()
3343
3344 def dot(self, size=None, *color):
3345 """Draw a dot with diameter size, using color.
3346
Ezio Melotti42da6632011-03-15 05:18:48 +02003347 Optional arguments:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003348 size -- an integer >= 1 (if given)
3349 color -- a colorstring or a numeric color tuple
3350
3351 Draw a circular dot with diameter size, using color.
3352 If size is not given, the maximum of pensize+4 and 2*pensize is used.
3353
3354 Example (for a Turtle instance named turtle):
3355 >>> turtle.dot()
3356 >>> turtle.fd(50); turtle.dot(20, "blue"); turtle.fd(50)
3357 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003358 if not color:
3359 if isinstance(size, (str, tuple)):
3360 color = self._colorstr(size)
3361 size = self._pensize + max(self._pensize, 4)
3362 else:
3363 color = self._pencolor
3364 if not size:
3365 size = self._pensize + max(self._pensize, 4)
3366 else:
3367 if size is None:
3368 size = self._pensize + max(self._pensize, 4)
3369 color = self._colorstr(color)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003370 if hasattr(self.screen, "_dot"):
3371 item = self.screen._dot(self._position, size, color)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003372 self.items.append(item)
3373 if self.undobuffer:
3374 self.undobuffer.push(("dot", item))
3375 else:
3376 pen = self.pen()
3377 if self.undobuffer:
3378 self.undobuffer.push(["seq"])
3379 self.undobuffer.cumulate = True
3380 try:
3381 if self.resizemode() == 'auto':
3382 self.ht()
3383 self.pendown()
3384 self.pensize(size)
3385 self.pencolor(color)
3386 self.forward(0)
3387 finally:
3388 self.pen(pen)
3389 if self.undobuffer:
3390 self.undobuffer.cumulate = False
3391
3392 def _write(self, txt, align, font):
3393 """Performs the writing for write()
3394 """
3395 item, end = self.screen._write(self._position, txt, align, font,
3396 self._pencolor)
3397 self.items.append(item)
3398 if self.undobuffer:
3399 self.undobuffer.push(("wri", item))
3400 return end
3401
3402 def write(self, arg, move=False, align="left", font=("Arial", 8, "normal")):
3403 """Write text at the current turtle position.
3404
3405 Arguments:
3406 arg -- info, which is to be written to the TurtleScreen
3407 move (optional) -- True/False
3408 align (optional) -- one of the strings "left", "center" or right"
3409 font (optional) -- a triple (fontname, fontsize, fonttype)
3410
3411 Write text - the string representation of arg - at the current
3412 turtle position according to align ("left", "center" or right")
3413 and with the given font.
3414 If move is True, the pen is moved to the bottom-right corner
3415 of the text. By default, move is False.
3416
3417 Example (for a Turtle instance named turtle):
3418 >>> turtle.write('Home = ', True, align="center")
3419 >>> turtle.write((0,0), True)
3420 """
3421 if self.undobuffer:
3422 self.undobuffer.push(["seq"])
3423 self.undobuffer.cumulate = True
3424 end = self._write(str(arg), align.lower(), font)
3425 if move:
3426 x, y = self.pos()
3427 self.setpos(end, y)
3428 if self.undobuffer:
3429 self.undobuffer.cumulate = False
3430
3431 def begin_poly(self):
3432 """Start recording the vertices of a polygon.
3433
3434 No argument.
3435
3436 Start recording the vertices of a polygon. Current turtle position
3437 is first point of polygon.
3438
3439 Example (for a Turtle instance named turtle):
3440 >>> turtle.begin_poly()
3441 """
3442 self._poly = [self._position]
3443 self._creatingPoly = True
3444
3445 def end_poly(self):
3446 """Stop recording the vertices of a polygon.
3447
3448 No argument.
3449
3450 Stop recording the vertices of a polygon. Current turtle position is
3451 last point of polygon. This will be connected with the first point.
3452
3453 Example (for a Turtle instance named turtle):
3454 >>> turtle.end_poly()
3455 """
3456 self._creatingPoly = False
3457
3458 def get_poly(self):
3459 """Return the lastly recorded polygon.
3460
3461 No argument.
3462
3463 Example (for a Turtle instance named turtle):
3464 >>> p = turtle.get_poly()
3465 >>> turtle.register_shape("myFavouriteShape", p)
3466 """
Georg Brandleaa84ef2009-05-05 08:14:33 +00003467 ## check if there is any poly?
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003468 if self._poly is not None:
3469 return tuple(self._poly)
3470
3471 def getscreen(self):
3472 """Return the TurtleScreen object, the turtle is drawing on.
3473
3474 No argument.
3475
3476 Return the TurtleScreen object, the turtle is drawing on.
3477 So TurtleScreen-methods can be called for that object.
3478
3479 Example (for a Turtle instance named turtle):
3480 >>> ts = turtle.getscreen()
3481 >>> ts
3482 <turtle.TurtleScreen object at 0x0106B770>
3483 >>> ts.bgcolor("pink")
3484 """
3485 return self.screen
3486
3487 def getturtle(self):
3488 """Return the Turtleobject itself.
3489
3490 No argument.
3491
3492 Only reasonable use: as a function to return the 'anonymous turtle':
3493
3494 Example:
3495 >>> pet = getturtle()
3496 >>> pet.fd(50)
3497 >>> pet
3498 <turtle.Turtle object at 0x0187D810>
3499 >>> turtles()
3500 [<turtle.Turtle object at 0x0187D810>]
3501 """
3502 return self
3503
3504 getpen = getturtle
3505
3506
3507 ################################################################
3508 ### screen oriented methods recurring to methods of TurtleScreen
3509 ################################################################
3510
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003511 def _delay(self, delay=None):
3512 """Set delay value which determines speed of turtle animation.
3513 """
3514 return self.screen.delay(delay)
3515
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003516 def onclick(self, fun, btn=1, add=None):
3517 """Bind fun to mouse-click event on this turtle on canvas.
3518
3519 Arguments:
3520 fun -- a function with two arguments, to which will be assigned
3521 the coordinates of the clicked point on the canvas.
3522 num -- number of the mouse-button defaults to 1 (left mouse button).
3523 add -- True or False. If True, new binding will be added, otherwise
3524 it will replace a former binding.
3525
3526 Example for the anonymous turtle, i. e. the procedural way:
3527
3528 >>> def turn(x, y):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003529 ... left(360)
3530 ...
3531 >>> onclick(turn) # Now clicking into the turtle will turn it.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003532 >>> onclick(None) # event-binding will be removed
3533 """
3534 self.screen._onclick(self.turtle._item, fun, btn, add)
3535 self._update()
3536
3537 def onrelease(self, fun, btn=1, add=None):
3538 """Bind fun to mouse-button-release event on this turtle on canvas.
3539
3540 Arguments:
3541 fun -- a function with two arguments, to which will be assigned
3542 the coordinates of the clicked point on the canvas.
3543 num -- number of the mouse-button defaults to 1 (left mouse button).
3544
3545 Example (for a MyTurtle instance named joe):
3546 >>> class MyTurtle(Turtle):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003547 ... def glow(self,x,y):
3548 ... self.fillcolor("red")
3549 ... def unglow(self,x,y):
3550 ... self.fillcolor("")
3551 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003552 >>> joe = MyTurtle()
3553 >>> joe.onclick(joe.glow)
3554 >>> joe.onrelease(joe.unglow)
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003555
3556 Clicking on joe turns fillcolor red, unclicking turns it to
3557 transparent.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003558 """
3559 self.screen._onrelease(self.turtle._item, fun, btn, add)
3560 self._update()
3561
3562 def ondrag(self, fun, btn=1, add=None):
3563 """Bind fun to mouse-move event on this turtle on canvas.
3564
3565 Arguments:
3566 fun -- a function with two arguments, to which will be assigned
3567 the coordinates of the clicked point on the canvas.
3568 num -- number of the mouse-button defaults to 1 (left mouse button).
3569
3570 Every sequence of mouse-move-events on a turtle is preceded by a
3571 mouse-click event on that turtle.
3572
3573 Example (for a Turtle instance named turtle):
3574 >>> turtle.ondrag(turtle.goto)
3575
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003576 Subsequently clicking and dragging a Turtle will move it
3577 across the screen thereby producing handdrawings (if pen is
3578 down).
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003579 """
3580 self.screen._ondrag(self.turtle._item, fun, btn, add)
3581
3582
3583 def _undo(self, action, data):
3584 """Does the main part of the work for undo()
3585 """
3586 if self.undobuffer is None:
3587 return
3588 if action == "rot":
3589 angle, degPAU = data
3590 self._rotate(-angle*degPAU/self._degreesPerAU)
3591 dummy = self.undobuffer.pop()
3592 elif action == "stamp":
3593 stitem = data[0]
3594 self.clearstamp(stitem)
3595 elif action == "go":
3596 self._undogoto(data)
3597 elif action in ["wri", "dot"]:
3598 item = data[0]
3599 self.screen._delete(item)
3600 self.items.remove(item)
3601 elif action == "dofill":
3602 item = data[0]
3603 self.screen._drawpoly(item, ((0, 0),(0, 0),(0, 0)),
3604 fill="", outline="")
3605 elif action == "beginfill":
3606 item = data[0]
3607 self._fillitem = self._fillpath = None
3608 if item in self.items:
3609 self.screen._delete(item)
3610 self.items.remove(item)
3611 elif action == "pen":
3612 TPen.pen(self, data[0])
3613 self.undobuffer.pop()
3614
3615 def undo(self):
3616 """undo (repeatedly) the last turtle action.
3617
3618 No argument.
3619
3620 undo (repeatedly) the last turtle action.
3621 Number of available undo actions is determined by the size of
3622 the undobuffer.
3623
3624 Example (for a Turtle instance named turtle):
3625 >>> for i in range(4):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003626 ... turtle.fd(50); turtle.lt(80)
3627 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003628 >>> for i in range(8):
Petri Lehtinen9aa20af2011-12-02 21:24:14 +02003629 ... turtle.undo()
3630 ...
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003631 """
3632 if self.undobuffer is None:
3633 return
3634 item = self.undobuffer.pop()
3635 action = item[0]
3636 data = item[1:]
3637 if action == "seq":
3638 while data:
3639 item = data.pop()
3640 self._undo(item[0], item[1:])
3641 else:
3642 self._undo(action, data)
3643
3644 turtlesize = shapesize
3645
3646RawPen = RawTurtle
3647
Martin v. Löwis601149b2008-09-29 22:19:08 +00003648### Screen - Singleton ########################
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003649
Martin v. Löwis601149b2008-09-29 22:19:08 +00003650def Screen():
3651 """Return the singleton screen object.
3652 If none exists at the moment, create a new one and return it,
3653 else return the existing one."""
3654 if Turtle._screen is None:
3655 Turtle._screen = _Screen()
3656 return Turtle._screen
3657
3658class _Screen(TurtleScreen):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003659
3660 _root = None
3661 _canvas = None
3662 _title = _CFG["title"]
3663
Guido van Rossumb241b671998-12-04 16:42:46 +00003664 def __init__(self):
Martin v. Löwis601149b2008-09-29 22:19:08 +00003665 # XXX there is no need for this code to be conditional,
3666 # as there will be only a single _Screen instance, anyway
3667 # XXX actually, the turtle demo is injecting root window,
3668 # so perhaps the conditional creation of a root should be
3669 # preserved (perhaps by passing it as an optional parameter)
3670 if _Screen._root is None:
3671 _Screen._root = self._root = _Root()
3672 self._root.title(_Screen._title)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003673 self._root.ondestroy(self._destroy)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003674 if _Screen._canvas is None:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003675 width = _CFG["width"]
3676 height = _CFG["height"]
3677 canvwidth = _CFG["canvwidth"]
3678 canvheight = _CFG["canvheight"]
3679 leftright = _CFG["leftright"]
3680 topbottom = _CFG["topbottom"]
3681 self._root.setupcanvas(width, height, canvwidth, canvheight)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003682 _Screen._canvas = self._root._getcanvas()
Martin v. Löwis601149b2008-09-29 22:19:08 +00003683 TurtleScreen.__init__(self, _Screen._canvas)
Georg Brandleaa84ef2009-05-05 08:14:33 +00003684 self.setup(width, height, leftright, topbottom)
Thomas Wouters477c8d52006-05-27 19:21:47 +00003685
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003686 def setup(self, width=_CFG["width"], height=_CFG["height"],
3687 startx=_CFG["leftright"], starty=_CFG["topbottom"]):
3688 """ Set the size and position of the main window.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003689
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003690 Arguments:
3691 width: as integer a size in pixels, as float a fraction of the screen.
3692 Default is 50% of screen.
3693 height: as integer the height in pixels, as float a fraction of the
3694 screen. Default is 75% of screen.
3695 startx: if positive, starting position in pixels from the left
3696 edge of the screen, if negative from the right edge
3697 Default, startx=None is to center window horizontally.
3698 starty: if positive, starting position in pixels from the top
3699 edge of the screen, if negative from the bottom edge
3700 Default, starty=None is to center window vertically.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003701
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003702 Examples (for a Screen instance named screen):
3703 >>> screen.setup (width=200, height=200, startx=0, starty=0)
3704
3705 sets window to 200x200 pixels, in upper left of screen
3706
3707 >>> screen.setup(width=.75, height=0.5, startx=None, starty=None)
3708
3709 sets window to 75% of screen by 50% of screen and centers
3710 """
3711 if not hasattr(self._root, "set_geometry"):
3712 return
3713 sw = self._root.win_width()
3714 sh = self._root.win_height()
3715 if isinstance(width, float) and 0 <= width <= 1:
3716 width = sw*width
3717 if startx is None:
3718 startx = (sw - width) / 2
3719 if isinstance(height, float) and 0 <= height <= 1:
3720 height = sh*height
3721 if starty is None:
3722 starty = (sh - height) / 2
3723 self._root.set_geometry(width, height, startx, starty)
Georg Brandleaa84ef2009-05-05 08:14:33 +00003724 self.update()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003725
3726 def title(self, titlestring):
3727 """Set title of turtle-window
3728
3729 Argument:
3730 titlestring -- a string, to appear in the titlebar of the
3731 turtle graphics window.
3732
3733 This is a method of Screen-class. Not available for TurtleScreen-
3734 objects.
3735
3736 Example (for a Screen instance named screen):
3737 >>> screen.title("Welcome to the turtle-zoo!")
3738 """
Martin v. Löwis601149b2008-09-29 22:19:08 +00003739 if _Screen._root is not None:
3740 _Screen._root.title(titlestring)
3741 _Screen._title = titlestring
Guido van Rossumb241b671998-12-04 16:42:46 +00003742
3743 def _destroy(self):
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003744 root = self._root
Martin v. Löwis601149b2008-09-29 22:19:08 +00003745 if root is _Screen._root:
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003746 Turtle._pen = None
3747 Turtle._screen = None
Martin v. Löwis601149b2008-09-29 22:19:08 +00003748 _Screen._root = None
3749 _Screen._canvas = None
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003750 TurtleScreen._RUNNING = True
Guido van Rossumb241b671998-12-04 16:42:46 +00003751 root.destroy()
Fred Draked038ca82000-10-23 18:31:14 +00003752
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003753 def bye(self):
3754 """Shut the turtlegraphics window.
3755
3756 Example (for a TurtleScreen instance named screen):
3757 >>> screen.bye()
3758 """
3759 self._destroy()
3760
3761 def exitonclick(self):
3762 """Go into mainloop until the mouse is clicked.
3763
3764 No arguments.
3765
3766 Bind bye() method to mouseclick on TurtleScreen.
3767 If "using_IDLE" - value in configuration dictionary is False
3768 (default value), enter mainloop.
3769 If IDLE with -n switch (no subprocess) is used, this value should be
3770 set to True in turtle.cfg. In this case IDLE's mainloop
3771 is active also for the client script.
3772
3773 This is a method of the Screen-class and not available for
3774 TurtleScreen instances.
3775
3776 Example (for a Screen instance named screen):
3777 >>> screen.exitonclick()
3778
3779 """
3780 def exitGracefully(x, y):
3781 """Screen.bye() with two dummy-parameters"""
3782 self.bye()
3783 self.onclick(exitGracefully)
3784 if _CFG["using_IDLE"]:
3785 return
3786 try:
3787 mainloop()
3788 except AttributeError:
3789 exit(0)
3790
3791
3792class Turtle(RawTurtle):
Ezio Melotti13925002011-03-16 11:05:33 +02003793 """RawTurtle auto-creating (scrolled) canvas.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003794
3795 When a Turtle object is created or a function derived from some
3796 Turtle method is called a TurtleScreen object is automatically created.
3797 """
3798 _pen = None
3799 _screen = None
3800
3801 def __init__(self,
3802 shape=_CFG["shape"],
3803 undobuffersize=_CFG["undobuffersize"],
3804 visible=_CFG["visible"]):
3805 if Turtle._screen is None:
3806 Turtle._screen = Screen()
3807 RawTurtle.__init__(self, Turtle._screen,
3808 shape=shape,
3809 undobuffersize=undobuffersize,
3810 visible=visible)
3811
3812Pen = Turtle
3813
Guido van Rossumb241b671998-12-04 16:42:46 +00003814def _getpen():
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003815 """Create the 'anonymous' turtle if not already present."""
3816 if Turtle._pen is None:
3817 Turtle._pen = Turtle()
3818 return Turtle._pen
Thomas Wouters477c8d52006-05-27 19:21:47 +00003819
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003820def _getscreen():
3821 """Create a TurtleScreen if not already present."""
3822 if Turtle._screen is None:
3823 Turtle._screen = Screen()
3824 return Turtle._screen
Thomas Wouters477c8d52006-05-27 19:21:47 +00003825
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003826def write_docstringdict(filename="turtle_docstringdict"):
3827 """Create and write docstring-dictionary to file.
Guido van Rossumb241b671998-12-04 16:42:46 +00003828
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003829 Optional argument:
3830 filename -- a string, used as filename
3831 default value is turtle_docstringdict
Thomas Wouters477c8d52006-05-27 19:21:47 +00003832
Ezio Melotti13925002011-03-16 11:05:33 +02003833 Has to be called explicitly, (not used by the turtle-graphics classes)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003834 The docstring dictionary will be written to the Python script <filname>.py
3835 It is intended to serve as a template for translation of the docstrings
3836 into different languages.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003837 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003838 docsdict = {}
Thomas Wouters477c8d52006-05-27 19:21:47 +00003839
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003840 for methodname in _tg_screen_functions:
Martin v. Löwis601149b2008-09-29 22:19:08 +00003841 key = "_Screen."+methodname
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003842 docsdict[key] = eval(key).__doc__
3843 for methodname in _tg_turtle_functions:
3844 key = "Turtle."+methodname
3845 docsdict[key] = eval(key).__doc__
Thomas Wouters477c8d52006-05-27 19:21:47 +00003846
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003847 f = open("%s.py" % filename,"w")
3848 keys = sorted([x for x in docsdict.keys()
3849 if x.split('.')[1] not in _alias_list])
3850 f.write('docsdict = {\n\n')
3851 for key in keys[:-1]:
3852 f.write('%s :\n' % repr(key))
3853 f.write(' """%s\n""",\n\n' % docsdict[key])
3854 key = keys[-1]
3855 f.write('%s :\n' % repr(key))
3856 f.write(' """%s\n"""\n\n' % docsdict[key])
3857 f.write("}\n")
3858 f.close()
Thomas Wouters477c8d52006-05-27 19:21:47 +00003859
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003860def read_docstrings(lang):
3861 """Read in docstrings from lang-specific docstring dictionary.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003862
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003863 Transfer docstrings, translated to lang, from a dictionary-file
3864 to the methods of classes Screen and Turtle and - in revised form -
3865 to the corresponding functions.
Thomas Wouters477c8d52006-05-27 19:21:47 +00003866 """
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003867 modname = "turtle_docstringdict_%(language)s" % {'language':lang.lower()}
3868 module = __import__(modname)
3869 docsdict = module.docsdict
3870 for key in docsdict:
3871 try:
3872# eval(key).im_func.__doc__ = docsdict[key]
3873 eval(key).__doc__ = docsdict[key]
3874 except:
3875 print("Bad docstring-entry: %s" % key)
Thomas Wouters477c8d52006-05-27 19:21:47 +00003876
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003877_LANGUAGE = _CFG["language"]
Guido van Rossumb241b671998-12-04 16:42:46 +00003878
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003879try:
3880 if _LANGUAGE != "english":
3881 read_docstrings(_LANGUAGE)
3882except ImportError:
3883 print("Cannot find docsdict for", _LANGUAGE)
3884except:
3885 print ("Unknown Error when trying to import %s-docstring-dictionary" %
3886 _LANGUAGE)
3887
3888
3889def getmethparlist(ob):
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003890 """Get strings describing the arguments for the given object
3891
3892 Returns a pair of strings representing function parameter lists
3893 including parenthesis. The first string is suitable for use in
3894 function definition and the second is suitable for use in function
3895 call. The "self" parameter is not included.
3896 """
3897 defText = callText = ""
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003898 # bit of a hack for methods - turn it into a function
3899 # but we drop the "self" param.
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003900 # Try and build one for Python defined functions
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003901 args, varargs, varkw = inspect.getargs(ob.__code__)
3902 items2 = args[1:]
3903 realArgs = args[1:]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003904 defaults = ob.__defaults__ or []
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003905 defaults = ["=%r" % (value,) for value in defaults]
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003906 defaults = [""] * (len(realArgs)-len(defaults)) + defaults
Alexander Belopolskyc1a68362010-10-27 13:25:45 +00003907 items1 = [arg + dflt for arg, dflt in zip(realArgs, defaults)]
3908 if varargs is not None:
3909 items1.append("*" + varargs)
3910 items2.append("*" + varargs)
3911 if varkw is not None:
3912 items1.append("**" + varkw)
3913 items2.append("**" + varkw)
3914 defText = ", ".join(items1)
3915 defText = "(%s)" % defText
3916 callText = ", ".join(items2)
3917 callText = "(%s)" % callText
3918 return defText, callText
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003919
3920def _turtle_docrevise(docstr):
3921 """To reduce docstrings from RawTurtle class for functions
3922 """
3923 import re
3924 if docstr is None:
3925 return None
3926 turtlename = _CFG["exampleturtle"]
3927 newdocstr = docstr.replace("%s." % turtlename,"")
3928 parexp = re.compile(r' \(.+ %s\):' % turtlename)
3929 newdocstr = parexp.sub(":", newdocstr)
3930 return newdocstr
3931
3932def _screen_docrevise(docstr):
3933 """To reduce docstrings from TurtleScreen class for functions
3934 """
3935 import re
3936 if docstr is None:
3937 return None
3938 screenname = _CFG["examplescreen"]
3939 newdocstr = docstr.replace("%s." % screenname,"")
3940 parexp = re.compile(r' \(.+ %s\):' % screenname)
3941 newdocstr = parexp.sub(":", newdocstr)
3942 return newdocstr
3943
3944## The following mechanism makes all methods of RawTurtle and Turtle available
3945## as functions. So we can enhance, change, add, delete methods to these
3946## classes and do not need to change anything here.
3947
3948
3949for methodname in _tg_screen_functions:
Martin v. Löwis601149b2008-09-29 22:19:08 +00003950 pl1, pl2 = getmethparlist(eval('_Screen.' + methodname))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003951 if pl1 == "":
3952 print(">>>>>>", pl1, pl2)
3953 continue
3954 defstr = ("def %(key)s%(pl1)s: return _getscreen().%(key)s%(pl2)s" %
3955 {'key':methodname, 'pl1':pl1, 'pl2':pl2})
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003956 exec(defstr)
Martin v. Löwis601149b2008-09-29 22:19:08 +00003957 eval(methodname).__doc__ = _screen_docrevise(eval('_Screen.'+methodname).__doc__)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003958
3959for methodname in _tg_turtle_functions:
3960 pl1, pl2 = getmethparlist(eval('Turtle.' + methodname))
3961 if pl1 == "":
3962 print(">>>>>>", pl1, pl2)
3963 continue
3964 defstr = ("def %(key)s%(pl1)s: return _getpen().%(key)s%(pl2)s" %
3965 {'key':methodname, 'pl1':pl1, 'pl2':pl2})
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003966 exec(defstr)
3967 eval(methodname).__doc__ = _turtle_docrevise(eval('Turtle.'+methodname).__doc__)
3968
3969
Georg Brandleaa84ef2009-05-05 08:14:33 +00003970done = mainloop
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00003971
3972if __name__ == "__main__":
3973 def switchpen():
3974 if isdown():
3975 pu()
3976 else:
3977 pd()
3978
3979 def demo1():
3980 """Demo of old turtle.py - module"""
3981 reset()
3982 tracer(True)
3983 up()
3984 backward(100)
3985 down()
3986 # draw 3 squares; the last filled
3987 width(3)
3988 for i in range(3):
3989 if i == 2:
3990 begin_fill()
3991 for _ in range(4):
3992 forward(20)
3993 left(90)
3994 if i == 2:
3995 color("maroon")
3996 end_fill()
3997 up()
3998 forward(30)
3999 down()
4000 width(1)
4001 color("black")
4002 # move out of the way
4003 tracer(False)
4004 up()
4005 right(90)
4006 forward(100)
4007 right(90)
4008 forward(100)
4009 right(180)
4010 down()
4011 # some text
4012 write("startstart", 1)
4013 write("start", 1)
4014 color("red")
4015 # staircase
4016 for i in range(5):
Guido van Rossumb241b671998-12-04 16:42:46 +00004017 forward(20)
4018 left(90)
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004019 forward(20)
4020 right(90)
4021 # filled staircase
4022 tracer(True)
4023 begin_fill()
4024 for i in range(5):
4025 forward(20)
4026 left(90)
4027 forward(20)
4028 right(90)
4029 end_fill()
4030 # more text
Thomas Wouters477c8d52006-05-27 19:21:47 +00004031
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004032 def demo2():
4033 """Demo of some new features."""
4034 speed(1)
4035 st()
4036 pensize(3)
4037 setheading(towards(0, 0))
4038 radius = distance(0, 0)/2.0
4039 rt(90)
4040 for _ in range(18):
4041 switchpen()
4042 circle(radius, 10)
4043 write("wait a moment...")
4044 while undobufferentries():
4045 undo()
4046 reset()
4047 lt(90)
4048 colormode(255)
4049 laenge = 10
4050 pencolor("green")
4051 pensize(3)
4052 lt(180)
4053 for i in range(-2, 16):
4054 if i > 0:
4055 begin_fill()
4056 fillcolor(255-15*i, 0, 15*i)
4057 for _ in range(3):
4058 fd(laenge)
4059 lt(120)
4060 end_fill()
4061 laenge += 10
4062 lt(15)
4063 speed((speed()+1)%12)
4064 #end_fill()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004065
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004066 lt(120)
4067 pu()
4068 fd(70)
4069 rt(30)
4070 pd()
4071 color("red","yellow")
4072 speed(0)
4073 begin_fill()
4074 for _ in range(4):
4075 circle(50, 90)
4076 rt(90)
4077 fd(30)
4078 rt(90)
4079 end_fill()
4080 lt(90)
4081 pu()
4082 fd(30)
4083 pd()
4084 shape("turtle")
Thomas Wouters477c8d52006-05-27 19:21:47 +00004085
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004086 tri = getturtle()
4087 tri.resizemode("auto")
4088 turtle = Turtle()
4089 turtle.resizemode("auto")
4090 turtle.shape("turtle")
4091 turtle.reset()
4092 turtle.left(90)
4093 turtle.speed(0)
4094 turtle.up()
4095 turtle.goto(280, 40)
4096 turtle.lt(30)
4097 turtle.down()
4098 turtle.speed(6)
4099 turtle.color("blue","orange")
4100 turtle.pensize(2)
4101 tri.speed(6)
Thomas Wouters477c8d52006-05-27 19:21:47 +00004102 setheading(towards(turtle))
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004103 count = 1
4104 while tri.distance(turtle) > 4:
4105 turtle.fd(3.5)
4106 turtle.lt(0.6)
4107 tri.setheading(tri.towards(turtle))
4108 tri.fd(4)
4109 if count % 20 == 0:
4110 turtle.stamp()
4111 tri.stamp()
4112 switchpen()
4113 count += 1
4114 tri.write("CAUGHT! ", font=("Arial", 16, "bold"), align="right")
4115 tri.pencolor("black")
4116 tri.pencolor("red")
Thomas Wouters477c8d52006-05-27 19:21:47 +00004117
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004118 def baba(xdummy, ydummy):
4119 clearscreen()
4120 bye()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004121
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004122 time.sleep(2)
Guido van Rossumb241b671998-12-04 16:42:46 +00004123
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004124 while undobufferentries():
4125 tri.undo()
4126 turtle.undo()
4127 tri.fd(50)
4128 tri.write(" Click me!", font = ("Courier", 12, "bold") )
4129 tri.onclick(baba, 1)
4130
4131 demo1()
Thomas Wouters477c8d52006-05-27 19:21:47 +00004132 demo2()
Martin v. Löwis97cf99f2008-06-10 04:44:07 +00004133 exitonclick()