@@ -860,13 +860,26 @@ class TurtleGraphicsError(Exception):
860860 """Some TurtleGraphics Error
861861 """
862862
863+ class BaseShapeDrawer (object ):
864+ """Base class that allows for taking over controll of drawing process
865+ for custom turtle shapes
866+ """
867+ def __init__ (self , screen ):
868+ self .screen = screen
869+ def clone (self , * args , ** kwargs ):
870+ return self .__class__ (self .screen , * args , ** kwargs )
871+ def draw (self , position , orientation , pen_color , fill_color , transform , pen_size ):
872+ pass
873+ def delete (self ):
874+ pass
863875
864876class Shape (object ):
865877 """Data structure modeling shapes.
866878
867- attribute _type is one of "polygon", "image", "compound"
879+ attribute _type is one of "polygon", "image", "compound", "shape_drawer"
868880 attribute _data is - depending on _type a poygon-tuple,
869- an image or a list constructed using the addcomponent method.
881+ an image, a list constructed using the addcomponent method or a subclass of
882+ BaseShapeDrawer.
870883 """
871884 def __init__ (self , type_ , data = None ):
872885 self ._type = type_
@@ -875,6 +888,8 @@ def __init__(self, type_, data=None):
875888 data = tuple (data )
876889 elif type_ == "image" :
877890 assert (isinstance (data , TK .PhotoImage ))
891+ elif type_ == "shape_drawer" :
892+ assert (issubclass (data , BaseShapeDrawer ))
878893 elif type_ == "compound" :
879894 data = []
880895 else :
@@ -1111,8 +1126,8 @@ def register_shape(self, name, shape=None):
11111126 of pairs of coordinates. Installs the corresponding
11121127 polygon shape
11131128 (4) name is an arbitrary string and shape is a
1114- (compound) Shape object. Installs the corresponding
1115- compound shape.
1129+ (compound or shape_drawer ) Shape object. Installs the corresponding
1130+ shape.
11161131 To use a shape, you have to issue the command shape(shapename).
11171132
11181133 call: register_shape("turtle.gif")
@@ -2550,7 +2565,6 @@ def __init__(self, screen, shapeIndex):
25502565
25512566 def _setshape (self , shapeIndex ):
25522567 screen = self .screen
2553- self .shapeIndex = shapeIndex
25542568 if self ._type == "polygon" == screen ._shapes [shapeIndex ]._type :
25552569 return
25562570 if self ._type == "image" == screen ._shapes [shapeIndex ]._type :
@@ -2560,14 +2574,21 @@ def _setshape(self, shapeIndex):
25602574 elif self ._type == "compound" :
25612575 for item in self ._item :
25622576 screen ._delete (item )
2577+ elif self ._type == "shape_drawer" :
2578+ del self ._item
2579+
25632580 self ._type = screen ._shapes [shapeIndex ]._type
2581+ self .shapeIndex = shapeIndex
2582+
25642583 if self ._type == "polygon" :
25652584 self ._item = screen ._createpoly ()
25662585 elif self ._type == "image" :
25672586 self ._item = screen ._createimage (screen ._shapes ["blank" ]._data )
25682587 elif self ._type == "compound" :
25692588 self ._item = [screen ._createpoly () for item in
25702589 screen ._shapes [shapeIndex ]._data ]
2590+ elif self ._type == "shape_drawer" :
2591+ self ._item = screen ._shapes [self .shapeIndex ]._data (screen )
25712592
25722593
25732594class RawTurtle (TPen , TNavigator ):
@@ -2855,6 +2876,8 @@ def clone(self):
28552876 elif ttype == "compound" :
28562877 q .turtle ._item = [screen ._createpoly () for item in
28572878 screen ._shapes [self .turtle .shapeIndex ]._data ]
2879+ elif ttype == "shape_drawer" :
2880+ q .turtle ._item = screen ._shapes [self .turtle .shapeIndex ]._data (screen )
28582881 q .currentLineItem = screen ._createline ()
28592882 q ._update ()
28602883 return q
@@ -3111,6 +3134,10 @@ def _drawturtle(self):
31113134 poly = self ._polytrafo (self ._getshapepoly (poly , True ))
31123135 screen ._drawpoly (item , poly , fill = self ._cc (fc ),
31133136 outline = self ._cc (oc ), width = self ._outlinewidth , top = True )
3137+ elif ttype == "shape_drawer" :
3138+ titem .draw (self ._position , self ._orient , pen_color = self ._pencolor ,
3139+ fill_color = self ._fillcolor , transform = self ._shapetrafo ,
3140+ pen_size = self ._pensize )
31143141 else :
31153142 if self ._hidden_from_screen :
31163143 return
@@ -3167,6 +3194,11 @@ def stamp(self):
31673194 poly = self ._polytrafo (self ._getshapepoly (poly , True ))
31683195 screen ._drawpoly (item , poly , fill = self ._cc (fc ),
31693196 outline = self ._cc (oc ), width = self ._outlinewidth , top = True )
3197+ elif ttype == "shape_drawer" :
3198+ stitem = self .turtle ._item .clone ()
3199+ stitem .draw (self ._position , self ._orient , pen_color = self ._pencolor ,
3200+ fill_color = self ._fillcolor , transform = self ._shapetrafo ,
3201+ pen_size = self ._pensize )
31703202 self .stampItems .append (stitem )
31713203 self .undobuffer .push (("stamp" , stitem ))
31723204 return stitem
@@ -3178,20 +3210,22 @@ def _clearstamp(self, stampid):
31783210 if isinstance (stampid , tuple ):
31793211 for subitem in stampid :
31803212 self .screen ._delete (subitem )
3181- else :
3213+ elif not isinstance ( stampid , BaseShapeDrawer ) :
31823214 self .screen ._delete (stampid )
31833215 self .stampItems .remove (stampid )
3216+
31843217 # Delete stampitem from undobuffer if necessary
31853218 # if clearstamp is called directly.
31863219 item = ("stamp" , stampid )
31873220 buf = self .undobuffer
3188- if item not in buf .buffer :
3189- return
3190- index = buf .buffer .index (item )
3191- buf .buffer .remove (item )
3192- if index <= buf .ptr :
3193- buf .ptr = (buf .ptr - 1 ) % buf .bufsize
3194- buf .buffer .insert ((buf .ptr + 1 )% buf .bufsize , [None ])
3221+ if item in buf .buffer :
3222+ index = buf .buffer .index (item )
3223+ buf .buffer .remove (item )
3224+ if index <= buf .ptr :
3225+ buf .ptr = (buf .ptr - 1 ) % buf .bufsize
3226+ buf .buffer .insert ((buf .ptr + 1 )% buf .bufsize , [None ])
3227+ if isinstance (stampid , BaseShapeDrawer ):
3228+ stampid .delete ()
31953229
31963230 def clearstamp (self , stampid ):
31973231 """Delete stamp with given stampid
0 commit comments