#
# turtle.py: a Tkinter based turtle graphics module for Python
# Version 1.0.1 - 24. 9. 2009
#
# Copyright (C) 2006 - 2010 Gregor Lingl
# email: glingl@aon.at
#
# This software is provided 'as-is', without any express or implied
# warranty. In no event will the authors be held liable for any damages
# arising from the use of this software.
#
# Permission is granted to anyone to use this software for any purpose,
# including commercial applications, and to alter it and redistribute it
# freely, subject to the following restrictions:
#
# 1. The origin of this software must not be misrepresented; you must not
# claim that you wrote the original software. If you use this software
# in a product, an acknowledgment in the product documentation would be
# appreciated but is not required.
# 2. Altered source versions must be plainly marked as such, and must not be
# misrepresented as being the original software.
# 3. This notice may not be removed or altered from any source distribution.
"""
Turtle graphics is a popular way for introducing programming to
kids. It was part of the original Logo programming language developed
by Wally Feurzig and Seymour Papert in 1966.
Imagine a robotic turtle starting at (0, 0) in the x-y plane. After an ``import turtle``, give it
the command turtle.forward(15), and it moves (on-screen!) 15 pixels in
the direction it is facing, drawing a line as it moves. Give it the
command turtle.right(25), and it rotates in-place 25 degrees clockwise.
By combining together these and similar commands, intricate shapes and
pictures can easily be drawn.
----- turtle.py
This module is an extended reimplementation of turtle.py from the
Python standard distribution up to Python 2.5. (See: http://www.python.org)
It tries to keep the merits of turtle.py and to be (nearly) 100%
compatible with it. This means in the first place to enable the
learning programmer to use all the commands, classes and methods
interactively when using the module from within IDLE run with
the -n switch.
Roughly it has the following features added:
- Better animation of the turtle movements, especially of turning the
turtle. So the turtles can more easily be used as a visual feedback
instrument by the (beginning) programmer.
- Different turtle shapes, gif-images as turtle shapes, user defined
and user controllable turtle shapes, among them compound
(multicolored) shapes. Turtle shapes can be stretched and tilted, which
makes turtles very versatile geometrical objects.
- Fine control over turtle movement and screen updates via delay(),
and enhanced tracer() and speed() methods.
- Aliases for the most commonly used commands, like fd for forward etc.,
following the early Logo traditions. This reduces the boring work of
typing long sequences of commands, which often occur in a natural way
when kids try to program fancy pictures on their first encounter with
turtle graphics.
- Turtles now have an undo()-method with configurable undo-buffer.
- Some simple commands/methods for creating event driven programs
(mouse-, key-, timer-events). Especially useful for programming games.
- A scrollable Canvas class. The default scrollable Canvas can be
extended interactively as needed while playing around with the turtle(s).
- A TurtleScreen class with methods controlling background color or
background image, window and canvas size and other properties of the
TurtleScreen.
- There is a method, setworldcoordinates(), to install a user defined
coordinate-system for the TurtleScreen.
- The implementation uses a 2-vector class named Vec2D, derived from tuple.
This class is public, so it can be imported by the application programmer,
which makes certain types of computations very natural and compact.
- Appearance of the TurtleScreen and the Turtles at startup/import can be
configured by means of a turtle.cfg configuration file.
The default configuration mimics the appearance of the old turtle module.
- If configured appropriately the module reads in docstrings from a docstring
dictionary in some different language, supplied separately and replaces
the English ones by those read in. There is a utility function
write_docstringdict() to write a dictionary with the original (English)
docstrings to disc, so it can serve as a template for translations.
Behind the scenes there are some features included with possible
extensions in mind. These will be commented and documented elsewhere.
"""_ver="turtle 1.0b1 - for Python 2.6 - 30. 5. 2008, 18:08"#print _ver
importTkinterasTKimporttypesimportmathimporttimeimportosfromos.pathimportisfile,split,joinfromcopyimportdeepcopyfrommathimport*## for compatibility with old turtle module
_tg_classes=['ScrolledCanvas','TurtleScreen','Screen','RawTurtle','Turtle','RawPen','Pen','Shape','Vec2D']_tg_screen_functions=['addshape','bgcolor','bgpic','bye','clearscreen','colormode','delay','exitonclick','getcanvas','getshapes','listen','mode','onkey','onscreenclick','ontimer','register_shape','resetscreen','screensize','setup','setworldcoordinates','title','tracer','turtles','update','window_height','window_width']_tg_turtle_functions=['back','backward','begin_fill','begin_poly','bk','circle','clear','clearstamp','clearstamps','clone','color','degrees','distance','dot','down','end_fill','end_poly','fd','fill','fillcolor','forward','get_poly','getpen','getscreen','getturtle','goto','heading','hideturtle','home','ht','isdown','isvisible','left','lt','onclick','ondrag','onrelease','pd','pen','pencolor','pendown','pensize','penup','pos','position','pu','radians','right','reset','resizemode','rt','seth','setheading','setpos','setposition','settiltangle','setundobuffer','setx','sety','shape','shapesize','showturtle','speed','st','stamp','tilt','tiltangle','towards','tracer','turtlesize','undo','undobufferentries','up','width','window_height','window_width','write','xcor','ycor']_tg_utilities=['write_docstringdict','done','mainloop']_math_functions=['acos','asin','atan','atan2','ceil','cos','cosh','e','exp','fabs','floor','fmod','frexp','hypot','ldexp','log','log10','modf','pi','pow','sin','sinh','sqrt','tan','tanh']__all__=(_tg_classes+_tg_screen_functions+_tg_turtle_functions+_tg_utilities+['Terminator']+_math_functions)_alias_list=['addshape','backward','bk','fd','ht','lt','pd','pos','pu','rt','seth','setpos','setposition','st','turtlesize','up','width']_CFG={"width":0.5,# Screen
"height":0.75,"canvwidth":400,"canvheight":300,"leftright":None,"topbottom":None,"mode":"standard",# TurtleScreen
"colormode":1.0,"delay":10,"undobuffersize":1000,# RawTurtle
"shape":"classic","pencolor":"black","fillcolor":"black","resizemode":"noresize","visible":True,"language":"english",# docstrings
"exampleturtle":"turtle","examplescreen":"screen","title":"Python Turtle Graphics","using_IDLE":False}##print "cwd:", os.getcwd()
##print "__file__:", __file__
##
##def show(dictionary):
## print "=========================="
## for key in sorted(dictionary.keys()):
## print key, ":", dictionary[key]
## print "=========================="
## print
defconfig_dict(filename):"""Convert content of config-file into dictionary."""f=open(filename,"r")cfglines=f.readlines()f.close()cfgdict={}forlineincfglines:line=line.strip()ifnotlineorline.startswith("#"):continuetry:key,value=line.split("=")exceptValueError:print"Bad line in config-file %s:\n%s"%(filename,line)continuekey=key.strip()value=value.strip()ifvaluein["True","False","None","''",'""']:value=eval(value)else:try:if"."invalue:value=float(value)else:value=int(value)exceptValueError:pass# value need not be converted
cfgdict[key]=valuereturncfgdictdefreadconfig(cfgdict):"""Read config-files, change configuration-dict accordingly.
If there is a turtle.cfg file in the current working directory,
read it from there. If this contains an importconfig-value,
say 'myway', construct filename turtle_mayway.cfg else use
turtle.cfg and read it from the import-directory, where
turtle.py is located.
Update configuration dictionary first according to config-file,
in the import directory, then according to config-file in the
current working directory.
If no config-file is found, the default configuration is used.
"""default_cfg="turtle.cfg"cfgdict1={}cfgdict2={}ifisfile(default_cfg):cfgdict1=config_dict(default_cfg)#print "1. Loading config-file %s from: %s" % (default_cfg, os.getcwd())
if"importconfig"incfgdict1:default_cfg="turtle_%s.cfg"%cfgdict1["importconfig"]try:head,tail=split(__file__)cfg_file2=join(head,default_cfg)exceptBaseException:cfg_file2=""ifisfile(cfg_file2):#print "2. Loading config-file %s:" % cfg_file2
cfgdict2=config_dict(cfg_file2)## show(_CFG)
## show(cfgdict2)
_CFG.update(cfgdict2)## show(_CFG)
## show(cfgdict1)
_CFG.update(cfgdict1)## show(_CFG)
try:readconfig(_CFG)exceptBaseException:print"No configfile read, reason unknown"classVec2D(tuple):"""A 2 dimensional vector class, used as a helper class
for implementing turtle graphics.
May be useful for turtle graphics programs also.
Derived from tuple, so a vector is a tuple!
Provides (for a, b vectors, k number):
a+b vector addition
a-b vector subtraction
a*b inner product
k*a and a*k multiplication with scalar
|a| absolute value of a
a.rotate(angle) rotation
"""def__new__(cls,x,y):returntuple.__new__(cls,(x,y))def__add__(self,other):returnVec2D(self[0]+other[0],self[1]+other[1])def__mul__(self,other):ifisinstance(other,Vec2D):returnself[0]*other[0]+self[1]*other[1]returnVec2D(self[0]*other,self[1]*other)def__rmul__(self,other):ifisinstance(other,(int,long,float)):returnVec2D(self[0]*other,self[1]*other)def__sub__(self,other):returnVec2D(self[0]-other[0],self[1]-other[1])def__neg__(self):returnVec2D(-self[0],-self[1])def__abs__(self):return (self[0]**2+self[1]**2)**0.5defrotate(self,angle):"""rotate self counterclockwise by angle
"""perp=Vec2D(-self[1],self[0])angle=angle*math.pi/180.0c,s=math.cos(angle),math.sin(angle)returnVec2D(self[0]*c+perp[0]*s,self[1]*c+perp[1]*s)def__getnewargs__(self):return (self[0],self[1])def__repr__(self):return"(%.2f,%.2f)"%self##############################################################################
### From here up to line : Tkinter - Interface for turtle.py ###
### May be replaced by an interface to some different graphics toolkit ###
##############################################################################
## helper functions for Scrolled Canvas, to forward Canvas-methods
## to ScrolledCanvas class
def__methodDict(cls,_dict):"""helper function for Scrolled Canvas"""baseList=list(cls.__bases__)baseList.reverse()for_superinbaseList:__methodDict(_super,_dict)forkey,valueincls.__dict__.items():iftype(value)==types.FunctionType:_dict[key]=valuedef__methods(cls):"""helper function for Scrolled Canvas"""_dict={}__methodDict(cls,_dict)return_dict.keys()__stringBody=('def %(method)s(self, *args, **kw): return '+'self.%(attribute)s.%(method)s(*args, **kw)')def__forwardmethods(fromClass,toClass,toPart,exclude=()):"""Helper functions for Scrolled Canvas, used to forward
ScrolledCanvas-methods to Tkinter.Canvas class.
"""_dict={}__methodDict(toClass,_dict)forexin_dict.keys():ifex[:1]=='_'orex[-1:]=='_':del_dict[ex]forexinexclude:ifexin_dict:del_dict[ex]forexin__methods(fromClass):ifexin_dict:del_dict[ex]formethod,funcin_dict.items():d={'method':method,'func':func}iftype(toPart)==types.StringType:execString= \
__stringBody%{'method':method,'attribute':toPart}execexecStringindfromClass.__dict__[method]=d[method]classScrolledCanvas(TK.Frame):"""Modeled after the scrolled canvas class from Grayons's Tkinter book.
Used as the default canvas, which pops up automatically when
using turtle graphics functions or the Turtle class.
"""def__init__(self,master,width=500,height=350,canvwidth=600,canvheight=500):TK.Frame.__init__(self,master,width=width,height=height)self._rootwindow=self.winfo_toplevel()self.width,self.height=width,heightself.canvwidth,self.canvheight=canvwidth,canvheightself.bg="white"self._canvas=TK.Canvas(master,width=width,height=height,bg=self.bg,relief=TK.SUNKEN,borderwidth=2)self.hscroll=TK.Scrollbar(master,command=self._canvas.xview,orient=TK.HORIZONTAL)self.vscroll=TK.Scrollbar(master,command=self._canvas.yview)self._canvas.configure(xscrollcommand=self.hscroll.set,yscrollcommand=self.vscroll.set)self.rowconfigure(0,weight=1,minsize=0)self.columnconfigure(0,weight=1,minsize=0)self._canvas.grid(padx=1,in_=self,pady=1,row=0,column=0,rowspan=1,columnspan=1,sticky='news')self.vscroll.grid(padx=1,in_=self,pady=1,row=0,column=1,rowspan=1,columnspan=1,sticky='news')self.hscroll.grid(padx=1,in_=self,pady=1,row=1,column=0,rowspan=1,columnspan=1,sticky='news')self.reset()self._rootwindow.bind('<Configure>',self.onResize)defreset(self,canvwidth=None,canvheight=None,bg=None):"""Adjust canvas and scrollbars according to given canvas size."""ifcanvwidth:self.canvwidth=canvwidthifcanvheight:self.canvheight=canvheightifbg:self.bg=bgself._canvas.config(bg=bg,scrollregion=(-self.canvwidth//2,-self.canvheight//2,self.canvwidth//2,self.canvheight//2))self._canvas.xview_moveto(0.5*(self.canvwidth-self.width+30)/self.canvwidth)self._canvas.yview_moveto(0.5*(self.canvheight-self.height+30)/self.canvheight)self.adjustScrolls()defadjustScrolls(self):""" Adjust scrollbars according to window- and canvas-size.
"""cwidth=self._canvas.winfo_width()cheight=self._canvas.winfo_height()self._canvas.xview_moveto(0.5*(self.canvwidth-cwidth)/self.canvwidth)self._canvas.yview_moveto(0.5*(self.canvheight-cheight)/self.canvheight)ifcwidth<self.canvwidthorcheight<self.canvheight:self.hscroll.grid(padx=1,in_=self,pady=1,row=1,column=0,rowspan=1,columnspan=1,sticky='news')self.vscroll.grid(padx=1,in_=self,pady=1,row=0,column=1,rowspan=1,columnspan=1,sticky='news')else:self.hscroll.grid_forget()self.vscroll.grid_forget()defonResize(self,event):"""self-explanatory"""self.adjustScrolls()defbbox(self,*args):"""'forward' method, which canvas itself has inherited...
"""returnself._canvas.bbox(*args)defcget(self,*args,**kwargs):"""'forward' method, which canvas itself has inherited...
"""returnself._canvas.cget(*args,**kwargs)defconfig(self,*args,**kwargs):"""'forward' method, which canvas itself has inherited...
"""self._canvas.config(*args,**kwargs)defbind(self,*args,**kwargs):"""'forward' method, which canvas itself has inherited...
"""self._canvas.bind(*args,**kwargs)defunbind(self,*args,**kwargs):"""'forward' method, which canvas itself has inherited...
"""self._canvas.unbind(*args,**kwargs)deffocus_force(self):"""'forward' method, which canvas itself has inherited...
"""self._canvas.focus_force()__forwardmethods(ScrolledCanvas,TK.Canvas,'_canvas')class_Root(TK.Tk):"""Root class for Screen based on Tkinter."""def__init__(self):TK.Tk.__init__(self)defsetupcanvas(self,width,height,cwidth,cheight):self._canvas=ScrolledCanvas(self,width,height,cwidth,cheight)self._canvas.pack(expand=1,fill="both")def_getcanvas(self):returnself._canvasdefset_geometry(self,width,height,startx,starty):self.geometry("%dx%d%+d%+d"%(width,height,startx,starty))defondestroy(self,destroy):self.wm_protocol("WM_DELETE_WINDOW",destroy)defwin_width(self):returnself.winfo_screenwidth()defwin_height(self):returnself.winfo_screenheight()Canvas=TK.CanvasclassTurtleScreenBase(object):"""Provide the basic graphics functionality.
Interface between Tkinter and turtle.py.
To port turtle.py to some different graphics toolkit
a corresponding TurtleScreenBase class has to be implemented.
"""@staticmethoddef_blankimage():"""return a blank image object
"""img=TK.PhotoImage(width=1,height=1)img.blank()returnimg@staticmethoddef_image(filename):"""return an image object containing the
imagedata from a gif-file named filename.
"""returnTK.PhotoImage(file=filename)def__init__(self,cv):self.cv=cvifisinstance(cv,ScrolledCanvas):w=self.cv.canvwidthh=self.cv.canvheightelse:# expected: ordinary TK.Canvas
w=int(self.cv.cget("width"))h=int(self.cv.cget("height"))self.cv.config(scrollregion=(-w//2,-h//2,w//2,h//2))self.canvwidth=wself.canvheight=hself.xscale=self.yscale=1.0def_createpoly(self):"""Create an invisible polygon item on canvas self.cv)
"""returnself.cv.create_polygon((0,0,0,0,0,0),fill="",outline="")def_drawpoly(self,polyitem,coordlist,fill=None,outline=None,width=None,top=False):"""Configure polygonitem polyitem according to provided
arguments:
coordlist is sequence of coordinates
fill is filling color
outline is outline color
top is a boolean value, which specifies if polyitem
will be put on top of the canvas' displaylist so it
will not be covered by other items.
"""cl=[]forx,yincoordlist:cl.append(x*self.xscale)cl.append(-y*self.yscale)self.cv.coords(polyitem,*cl)iffillisnotNone:self.cv.itemconfigure(polyitem,fill=fill)ifoutlineisnotNone:self.cv.itemconfigure(polyitem,outline=outline)ifwidthisnotNone:self.cv.itemconfigure(polyitem,width=width)iftop:self.cv.tag_raise(polyitem)def_createline(self):"""Create an invisible line item on canvas self.cv)
"""returnself.cv.create_line(0,0,0,0,fill="",width=2,capstyle=TK.ROUND)def_drawline(self,lineitem,coordlist=None,fill=None,width=None,top=False):"""Configure lineitem according to provided arguments:
coordlist is sequence of coordinates
fill is drawing color
width is width of drawn line.
top is a boolean value, which specifies if polyitem
will be put on top of the canvas' displaylist so it
will not be covered by other items.
"""ifcoordlistisnotNone:cl=[]forx,yincoordlist:cl.append(x*self.xscale)cl.append(-y*self.yscale)self.cv.coords(lineitem,*cl)iffillisnotNone:self.cv.itemconfigure(lineitem,fill=fill)ifwidthisnotNone:self.cv.itemconfigure(lineitem,width=width)iftop:self.cv.tag_raise(lineitem)def_delete(self,item):"""Delete graphics item from canvas.
If item is"all" delete all graphics items.
"""self.cv.delete(item)def_update(self):"""Redraw graphics items on canvas
"""self.cv.update()def_delay(self,delay):"""Delay subsequent canvas actions for delay ms."""self.cv.after(delay)def_iscolorstring(self,color):"""Check if the string color is a legal Tkinter color string.
"""try:rgb=self.cv.winfo_rgb(color)ok=TrueexceptTK.TclError:ok=Falsereturnokdef_bgcolor(self,color=None):"""Set canvas' backgroundcolor if color is not None,
else return backgroundcolor."""ifcolorisnotNone:self.cv.config(bg=color)self._update()else:returnself.cv.cget("bg")def_write(self,pos,txt,align,font,pencolor):"""Write txt at pos in canvas with specified font
and color.
Return text item and x-coord of right bottom corner
of text's bounding box."""x,y=posx=x*self.xscaley=y*self.yscaleanchor={"left":"sw","center":"s","right":"se"}item=self.cv.create_text(x-1,-y,text=txt,anchor=anchor[align],fill=pencolor,font=font)x0,y0,x1,y1=self.cv.bbox(item)self.cv.update()returnitem,x1-1## def _dot(self, pos, size, color):
## """may be implemented for some other graphics toolkit"""
def_onclick(self,item,fun,num=1,add=None):"""Bind fun to mouse-click event on turtle.
fun must be a function with two arguments, the coordinates
of the clicked point on the canvas.
num, the number of the mouse-button defaults to 1
"""iffunisNone:self.cv.tag_unbind(item,"<Button-%s>"%num)else:defeventfun(event):x,y=(self.cv.canvasx(event.x)/self.xscale,-self.cv.canvasy(event.y)/self.yscale)fun(x,y)self.cv.tag_bind(item,"<Button-%s>"%num,eventfun,add)def_onrelease(self,item,fun,num=1,add=None):"""Bind fun to mouse-button-release event on turtle.
fun must be a function with two arguments, the coordinates
of the point on the canvas where mouse button is released.
num, the number of the mouse-button defaults to 1
If a turtle is clicked, first _onclick-event will be performed,
then _onscreensclick-event.
"""iffunisNone:self.cv.tag_unbind(item,"<Button%s-ButtonRelease>"%num)else:defeventfun(event):x,y=(self.cv.canvasx(event.x)/self.xscale,-self.cv.canvasy(event.y)/self.yscale)fun(x,y)self.cv.tag_bind(item,"<Button%s-ButtonRelease>"%num,eventfun,add)def_ondrag(self,item,fun,num=1,add=None):"""Bind fun to mouse-move-event (with pressed mouse button) on turtle.
fun must be a function with two arguments, the coordinates of the
actual mouse position on the canvas.
num, the number of the mouse-button defaults to 1
Every sequence of mouse-move-events on a turtle is preceded by a
mouse-click event on that turtle.
"""iffunisNone:self.cv.tag_unbind(item,"<Button%s-Motion>"%num)else:defeventfun(event):try:x,y=(self.cv.canvasx(event.x)/self.xscale,-self.cv.canvasy(event.y)/self.yscale)fun(x,y)exceptBaseException:passself.cv.tag_bind(item,"<Button%s-Motion>"%num,eventfun,add)def_onscreenclick(self,fun,num=1,add=None):"""Bind fun to mouse-click event on canvas.
fun must be a function with two arguments, the coordinates
of the clicked point on the canvas.
num, the number of the mouse-button defaults to 1
If a turtle is clicked, first _onclick-event will be performed,
then _onscreensclick-event.
"""iffunisNone:self.cv.unbind("<Button-%s>"%num)else:defeventfun(event):x,y=(self.cv.canvasx(event.x)/self.xscale,-self.cv.canvasy(event.y)/self.yscale)fun(x,y)self.cv.bind("<Button-%s>"%num,eventfun,add)def_onkey(self,fun,key):"""Bind fun to key-release event of key.
Canvas must have focus. See method listen
"""iffunisNone:self.cv.unbind("<KeyRelease-%s>"%key,None)else:defeventfun(event):fun()self.cv.bind("<KeyRelease-%s>"%key,eventfun)def_listen(self):"""Set focus on canvas (in order to collect key-events)
"""self.cv.focus_force()def_ontimer(self,fun,t):"""Install a timer, which calls fun after t milliseconds.
"""ift==0:self.cv.after_idle(fun)else:self.cv.after(t,fun)def_createimage(self,image):"""Create and return image item on canvas.
"""returnself.cv.create_image(0,0,image=image)def_drawimage(self,item,pos,image):"""Configure image item as to draw image object
at position (x,y) on canvas)
"""x,y=posself.cv.coords(item,(x*self.xscale,-y*self.yscale))self.cv.itemconfig(item,image=image)def_setbgpic(self,item,image):"""Configure image item as to draw image object
at center of canvas. Set item to the first item
in the displaylist, so it will be drawn below
any other item ."""self.cv.itemconfig(item,image=image)self.cv.tag_lower(item)def_type(self,item):"""Return 'line' or 'polygon' or 'image' depending on
type of item.
"""returnself.cv.type(item)def_pointlist(self,item):"""returns list of coordinate-pairs of points of item
Example (for insiders):
>>>fromturtleimport* >>>getscreen()._pointlist(getturtle().turtle._item) [(0.0, 9.9999999999999982), (0.0, -9.9999999999999982),
(9.9999999999999982, 0.0)]
>>>"""cl=self.cv.coords(item)pl=[(cl[i],-cl[i+1])foriinrange(0,len(cl),2)]returnpldef_setscrollregion(self,srx1,sry1,srx2,sry2):self.cv.config(scrollregion=(srx1,sry1,srx2,sry2))def_rescale(self,xscalefactor,yscalefactor):items=self.cv.find_all()foriteminitems:coordinates=self.cv.coords(item)newcoordlist=[]whilecoordinates:x,y=coordinates[:2]newcoordlist.append(x*xscalefactor)newcoordlist.append(y*yscalefactor)coordinates=coordinates[2:]self.cv.coords(item,*newcoordlist)def_resize(self,canvwidth=None,canvheight=None,bg=None):"""Resize the canvas the turtles are drawing on. Does
not alter the drawing window.
"""# needs amendment
ifnotisinstance(self.cv,ScrolledCanvas):returnself.canvwidth,self.canvheightifcanvwidthiscanvheightisbgisNone:returnself.cv.canvwidth,self.cv.canvheightifcanvwidthisnotNone:self.canvwidth=canvwidthifcanvheightisnotNone:self.canvheight=canvheightself.cv.reset(canvwidth,canvheight,bg)def_window_size(self):""" Return the width and height of the turtle window.
"""width=self.cv.winfo_width()ifwidth<=1:# the window isn't managed by a geometry manager
width=self.cv['width']height=self.cv.winfo_height()ifheight<=1:# the window isn't managed by a geometry manager
height=self.cv['height']returnwidth,height##############################################################################
### End of Tkinter - interface ###
##############################################################################
classTerminator(Exception):"""Will be raised in TurtleScreen.update, if _RUNNING becomes False.
This stops execution of a turtle graphics script.
Main purpose: use in the Demo-Viewer turtle.Demo.py.
"""passclassTurtleGraphicsError(Exception):"""Some TurtleGraphics Error
"""classShape(object):"""Data structure modeling shapes.
attribute _type is one of "polygon", "image", "compound"
attribute _data is - depending on _type a poygon-tuple,
an image or a list constructed using the addcomponent method.
"""def__init__(self,type_,data=None):self._type=type_iftype_=="polygon":ifisinstance(data,list):data=tuple(data)eliftype_=="image":ifisinstance(data,basestring):ifdata.lower().endswith(".gif")andisfile(data):data=TurtleScreen._image(data)# else data assumed to be Photoimage
eliftype_=="compound":data=[]else:raiseTurtleGraphicsError("There is no shape type %s"%type_)self._data=datadefaddcomponent(self,poly,fill,outline=None):"""Add component to a shape of type compound.
Arguments: poly is a polygon, i. e. a tuple of number pairs.
fill is the fillcolor of the component,
outline is the outline color of the component.
call (for a Shapeobject namend s):
-- s.addcomponent(((0,0), (10,10), (-10,10)), "red", "blue")
Example:
>>>poly=((0,0),(10,-5),(0,10),(-10,-5)) >>>s=Shape("compound") >>>s.addcomponent(poly,"red","blue") >>># .. add more components and then use register_shape()
"""ifself._type!="compound":raiseTurtleGraphicsError("Cannot add component to %s Shape"%self._type)ifoutlineisNone:outline=fillself._data.append([poly,fill,outline])classTbuffer(object):"""Ring buffer used as undobuffer for RawTurtle objects."""def__init__(self,bufsize=10):self.bufsize=bufsizeself.buffer=[[None]]*bufsizeself.ptr=-1self.cumulate=Falsedefreset(self,bufsize=None):ifbufsizeisNone:foriinrange(self.bufsize):self.buffer[i]=[None]else:self.bufsize=bufsizeself.buffer=[[None]]*bufsizeself.ptr=-1defpush(self,item):ifself.bufsize>0:ifnotself.cumulate:self.ptr=(self.ptr+1)%self.bufsizeself.buffer[self.ptr]=itemelse:self.buffer[self.ptr].append(item)defpop(self):ifself.bufsize>0:item=self.buffer[self.ptr]ifitemisNone:returnNoneelse:self.buffer[self.ptr]=[None]self.ptr=(self.ptr-1)%self.bufsizereturn (item)defnr_of_items(self):returnself.bufsize-self.buffer.count([None])def__repr__(self):returnstr(self.buffer)+""+str(self.ptr)classTurtleScreen(TurtleScreenBase):"""Provides screen oriented methods like setbg etc.
Only relies upon the methods of TurtleScreenBase and NOT
upon components of the underlying graphics toolkit -
which is Tkinter in this case.
"""# _STANDARD_DELAY = 5
_RUNNING=Truedef__init__(self,cv,mode=_CFG["mode"],colormode=_CFG["colormode"],delay=_CFG["delay"]):self._shapes={"arrow":Shape("polygon",((-10,0),(10,0),(0,10))),"turtle":Shape("polygon",((0,16),(-2,14),(-1,10),(-4,7),(-7,9),(-9,8),(-6,5),(-7,1),(-5,-3),(-8,-6),(-6,-8),(-4,-5),(0,-7),(4,-5),(6,-8),(8,-6),(5,-3),(7,1),(6,5),(9,8),(7,9),(4,7),(1,10),(2,14))),"circle":Shape("polygon",((10,0),(9.51,3.09),(8.09,5.88),(5.88,8.09),(3.09,9.51),(0,10),(-3.09,9.51),(-5.88,8.09),(-8.09,5.88),(-9.51,3.09),(-10,0),(-9.51,-3.09),(-8.09,-5.88),(-5.88,-8.09),(-3.09,-9.51),(-0.00,-10.00),(3.09,-9.51),(5.88,-8.09),(8.09,-5.88),(9.51,-3.09))),"square":Shape("polygon",((10,-10),(10,10),(-10,10),(-10,-10))),"triangle":Shape("polygon",((10,-5.77),(0,11.55),(-10,-5.77))),"classic":Shape("polygon",((0,0),(-5,-9),(0,-7),(5,-9))),"blank":Shape("image",self._blankimage())}self._bgpics={"nopic":""}TurtleScreenBase.__init__(self,cv)self._mode=modeself._delayvalue=delayself._colormode=_CFG["colormode"]self._keys=[]self.clear()defclear(self):"""Delete all drawings and all turtles from the TurtleScreen.
Reset empty TurtleScreen to its initial state: white background,
no backgroundimage, no eventbindings and tracing on.
No argument.
Example (for a TurtleScreen instance named screen):
>>>screen.clear()
Note: this method is not available as function.
"""self._delayvalue=_CFG["delay"]self._colormode=_CFG["colormode"]self._delete("all")self._bgpic=self._createimage("")self._bgpicname="nopic"self._tracing=1self._updatecounter=0self._turtles=[]self.bgcolor("white")forbtnin1,2,3:self.onclick(None,btn)forkeyinself._keys[:]:self.onkey(None,key)Turtle._pen=Nonedefmode(self,mode=None):"""Set turtle-mode ('standard', 'logo' or 'world') and perform reset.
Optional argument:
mode -- one of the strings 'standard', 'logo' or 'world'
Mode 'standard' is compatible with turtle.py.
Mode 'logo' is compatible with most Logo-Turtle-Graphics.
Mode 'world' uses userdefined 'worldcoordinates'. *Attention*: in
this mode angles appear distorted if x/y unit-ratio doesn't equal 1.
If mode is not given, return the current mode.
Mode Initial turtle heading positive angles
------------|-------------------------|-------------------
'standard' to the right (east) counterclockwise
'logo' upward (north) clockwise
Examples:
>>>mode('logo')# resets turtle heading to north
>>>mode()'logo'"""ifmodeisNone:returnself._modemode=mode.lower()ifmodenotin["standard","logo","world"]:raiseTurtleGraphicsError("No turtle-graphics-mode %s"%mode)self._mode=modeifmodein["standard","logo"]:self._setscrollregion(-self.canvwidth//2,-self.canvheight//2,self.canvwidth//2,self.canvheight//2)self.xscale=self.yscale=1.0self.reset()defsetworldcoordinates(self,llx,lly,urx,ury):"""Set up a user defined coordinate-system.
Arguments:
llx -- a number, x-coordinate of lower left corner of canvas
lly -- a number, y-coordinate of lower left corner of canvas
urx -- a number, x-coordinate of upper right corner of canvas
ury -- a number, y-coordinate of upper right corner of canvas
Set up user coodinat-system and switch to mode 'world' if necessary.
This performs a screen.reset. If mode 'world' is already active,
all drawings are redrawn according to the new coordinates.
But ATTENTION: in user-defined coordinatesystems angles may appear
distorted. (see Screen.mode())
Example (for a TurtleScreen instance named screen):
>>>screen.setworldcoordinates(-10,-0.5,50,1.5) >>>for_inrange(36): ...left(10) ...forward(0.5)"""ifself.mode()!="world":self.mode("world")xspan=float(urx-llx)yspan=float(ury-lly)wx,wy=self._window_size()self.screensize(wx-20,wy-20)oldxscale,oldyscale=self.xscale,self.yscaleself.xscale=self.canvwidth/xspanself.yscale=self.canvheight/yspansrx1=llx*self.xscalesry1=-ury*self.yscalesrx2=self.canvwidth+srx1sry2=self.canvheight+sry1self._setscrollregion(srx1,sry1,srx2,sry2)self._rescale(self.xscale/oldxscale,self.yscale/oldyscale)self.update()defregister_shape(self,name,shape=None):"""Adds a turtle shape to TurtleScreen's shapelist.
Arguments:
(1) name is the name of a gif-file and shape is None.
Installs the corresponding image shape.
!! Image-shapes DO NOT rotate when turning the turtle,
!! so they do not display the heading of the turtle!
(2) name is an arbitrary string and shape is a tuple
of pairs of coordinates. Installs the corresponding
polygon shape
(3) name is an arbitrary string and shape is a
(compound) Shape object. Installs the corresponding
compound shape.
To use a shape, you have to issue the command shape(shapename).
call: register_shape("turtle.gif")
--or: register_shape("tri", ((0,0), (10,10), (-10,10)))
Example (for a TurtleScreen instance named screen):
>>>screen.register_shape("triangle",((5,-3),(0,5),(-5,-3)))"""ifshapeisNone:# image
ifname.lower().endswith(".gif"):shape=Shape("image",self._image(name))else:raiseTurtleGraphicsError("Bad arguments for register_shape.\n"+"Use help(register_shape)")elifisinstance(shape,tuple):shape=Shape("polygon",shape)## else shape assumed to be Shape-instance
self._shapes[name]=shape# print "shape added:" , self._shapes
def_colorstr(self,color):"""Return color string corresponding to args.
Argument may be a string or a tuple of three
numbers corresponding to actual colormode,
i.e. in the range 0<=n<=colormode.
If the argument doesn't represent a color,
an error is raised.
"""iflen(color)==1:color=color[0]ifisinstance(color,basestring):ifself._iscolorstring(color)orcolor=="":returncolor
During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:
Ensure the proper functioning of the site (essential cookies); and
Track your browsing to send you personalized communications if you have created a professional account on the site and can be contacted (audience measurement cookies).
With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.