Skip to content

Commit 49f9bc6

Browse files
committed
Turtle custom ShapeDrawer mechanism added
1 parent 9f81f82 commit 49f9bc6

File tree

1 file changed

+47
-13
lines changed

1 file changed

+47
-13
lines changed

Lib/turtle.py

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -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

864876
class 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

25732594
class 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

Comments
 (0)