ยปCore Development>Code coverage>Lib/turtle.py

Python code coverage for Lib/turtle.py

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