class TurtleWidget(CanvasWidget): def newTKWidget(self, parent, hOptions): return super().newTKWidget(parent, hOptions) def initialize(self, hOptions): self.screen = TurtleScreen(self.tkWidget) self.tkTurtle = RawTurtle(self.screen) self.screen.mode('world') self.tkTurtle.setheading(90) if 'speed' in hOptions: self.curSpeed = int(hOptions['speed']) else: self.curSpeed = 1 self.lSaveStack = [] # stack to save/restore state on def setBounds(self, xmin, ymin, xmax, ymax, padding=15): width = xmax - xmin height = ymax - ymin if (width > height): halfdiff = (width - height) / 2 ymin -= halfdiff ymax += halfdiff else: halfdiff = (height - width) / 2 xmin -= halfdiff xmax += halfdiff self.screen.setworldcoordinates( xmin - padding, ymin - padding, xmax + padding, ymax + padding, ) def reset(self): self.screen.reset() def move(self, n): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) tkTurtle.speed(self.curSpeed) tkTurtle.forward(n) def turn(self, d): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) tkTurtle.speed(self.curSpeed) tkTurtle.right(d) # --- Turtle state includes these fields: # xpos, ypos, heading, isvisible, isdown def saveState(self): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) self.lSaveStack.append([ tkTurtle.xcor(), tkTurtle.ycor(), tkTurtle.heading(), tkTurtle.isvisible(), tkTurtle.isdown(), ]) def restoreState(self): tkTurtle = self.tkTurtle assert isinstance(tkTurtle, RawTurtle) if len(self.lSaveStack) == 0: raise Exception("restoreState(): No saved state to restore") lState = self.lSaveStack.pop() saved_x = lState[0] saved_y = lState[1] cur_x = tkTurtle.xcor() cur_y = tkTurtle.ycor() # --- determine whether we need to hide the turtle if tkTurtle.isvisible(): dist = hypot(saved_x - cur_x, saved_y - cur_y) mustHide = (dist > 1) else: mustHide = False if mustHide: tkTurtle.hideturtle() tkTurtle.penup() tkTurtle.setposition(saved_x, saved_y) tkTurtle.setheading(lState[2]) if lState[3] and mustHide: tkTurtle.showturtle() if lState[4]: tkTurtle.pendown() def moveTo(self, x, y): tkTurtle = self.tkTurtle tkTurtle.penup() tkTurtle.hideturtle() tkTurtle.setposition(x, y) tkTurtle.setheading(90) tkTurtle.pendown() tkTurtle.showturtle() def drawAt(self, x, y, func): # --- Must not draw or show movement tkTurtle = self.tkTurtle self.saveState() self.moveTo(x, y) func(self) self.restoreState()