home *** CD-ROM | disk | FTP | other *** search
/ PC World 2005 June / PCWorld_2005-06_cd.bin / software / vyzkuste / firewally / firewally.exe / framework-2.3.exe / turtle.py < prev    next >
Text File  |  2003-12-30  |  13KB  |  427 lines

  1. # LogoMation-like turtle graphics
  2.  
  3. from math import * # Also for export
  4. import Tkinter
  5.  
  6. class Error(Exception):
  7.     pass
  8.  
  9. class RawPen:
  10.  
  11.     def __init__(self, canvas):
  12.         self._canvas = canvas
  13.         self._items = []
  14.         self._tracing = 1
  15.         self._arrow = 0
  16.         self.degrees()
  17.         self.reset()
  18.  
  19.     def degrees(self, fullcircle=360.0):
  20.         self._fullcircle = fullcircle
  21.         self._invradian = pi / (fullcircle * 0.5)
  22.  
  23.     def radians(self):
  24.         self.degrees(2.0*pi)
  25.  
  26.     def reset(self):
  27.         canvas = self._canvas
  28.         self._canvas.update()
  29.         width = canvas.winfo_width()
  30.         height = canvas.winfo_height()
  31.         if width <= 1:
  32.             width = canvas['width']
  33.         if height <= 1:
  34.             height = canvas['height']
  35.         self._origin = float(width)/2.0, float(height)/2.0
  36.         self._position = self._origin
  37.         self._angle = 0.0
  38.         self._drawing = 1
  39.         self._width = 1
  40.         self._color = "black"
  41.         self._filling = 0
  42.         self._path = []
  43.         self._tofill = []
  44.         self.clear()
  45.         canvas._root().tkraise()
  46.  
  47.     def clear(self):
  48.         self.fill(0)
  49.         canvas = self._canvas
  50.         items = self._items
  51.         self._items = []
  52.         for item in items:
  53.             canvas.delete(item)
  54.         self._delete_turtle()
  55.         self._draw_turtle()
  56.  
  57.     def tracer(self, flag):
  58.         self._tracing = flag
  59.         if not self._tracing:
  60.             self._delete_turtle()
  61.         self._draw_turtle()
  62.  
  63.     def forward(self, distance):
  64.         x0, y0 = start = self._position
  65.         x1 = x0 + distance * cos(self._angle*self._invradian)
  66.         y1 = y0 - distance * sin(self._angle*self._invradian)
  67.         self._goto(x1, y1)
  68.  
  69.     def backward(self, distance):
  70.         self.forward(-distance)
  71.  
  72.     def left(self, angle):
  73.         self._angle = (self._angle + angle) % self._fullcircle
  74.         self._draw_turtle()
  75.  
  76.     def right(self, angle):
  77.         self.left(-angle)
  78.  
  79.     def up(self):
  80.         self._drawing = 0
  81.  
  82.     def down(self):
  83.         self._drawing = 1
  84.  
  85.     def width(self, width):
  86.         self._width = float(width)
  87.  
  88.     def color(self, *args):
  89.         if not args:
  90.             raise Error, "no color arguments"
  91.         if len(args) == 1:
  92.             color = args[0]
  93.             if type(color) == type(""):
  94.                 # Test the color first
  95.                 try:
  96.                     id = self._canvas.create_line(0, 0, 0, 0, fill=color)
  97.                 except Tkinter.TclError:
  98.                     raise Error, "bad color string: %s" % `color`
  99.                 self._set_color(color)
  100.                 return
  101.             try:
  102.                 r, g, b = color
  103.             except:
  104.                 raise Error, "bad color sequence: %s" % `color`
  105.         else:
  106.             try:
  107.                 r, g, b = args
  108.             except:
  109.                 raise Error, "bad color arguments: %s" % `args`
  110.         assert 0 <= r <= 1
  111.         assert 0 <= g <= 1
  112.         assert 0 <= b <= 1
  113.         x = 255.0
  114.         y = 0.5
  115.         self._set_color("#%02x%02x%02x" % (int(r*x+y), int(g*x+y), int(b*x+y)))
  116.  
  117.     def _set_color(self,color):
  118.         self._color = color
  119.         self._draw_turtle()
  120.  
  121.     def write(self, arg, move=0):
  122.         x, y = start = self._position
  123.         x = x-1 # correction -- calibrated for Windows
  124.         item = self._canvas.create_text(x, y,
  125.                                         text=str(arg), anchor="sw",
  126.                                         fill=self._color)
  127.         self._items.append(item)
  128.         if move:
  129.             x0, y0, x1, y1 = self._canvas.bbox(item)
  130.             self._goto(x1, y1)
  131.         self._draw_turtle()
  132.  
  133.     def fill(self, flag):
  134.         if self._filling:
  135.             path = tuple(self._path)
  136.             smooth = self._filling < 0
  137.             if len(path) > 2:
  138.                 item = self._canvas._create('polygon', path,
  139.                                             {'fill': self._color,
  140.                                              'smooth': smooth})
  141.                 self._items.append(item)
  142.                 self._canvas.lower(item)
  143.                 if self._tofill:
  144.                     for item in self._tofill:
  145.                         self._canvas.itemconfigure(item, fill=self._color)
  146.                         self._items.append(item)
  147.         self._path = []
  148.         self._tofill = []
  149.         self._filling = flag
  150.         if flag:
  151.             self._path.append(self._position)
  152.         self.forward(0)
  153.  
  154.     def circle(self, radius, extent=None):
  155.         if extent is None:
  156.             extent = self._fullcircle
  157.         x0, y0 = self._position
  158.         xc = x0 - radius * sin(self._angle * self._invradian)
  159.         yc = y0 - radius * cos(self._angle * self._invradian)
  160.         if radius >= 0.0:
  161.             start = self._angle - 90.0
  162.         else:
  163.             start = self._angle + 90.0
  164.             extent = -extent
  165.         if self._filling:
  166.             if abs(extent) >= self._fullcircle:
  167.                 item = self._canvas.create_oval(xc-radius, yc-radius,
  168.                                                 xc+radius, yc+radius,
  169.                                                 width=self._width,
  170.                                                 outline="")
  171.                 self._tofill.append(item)
  172.             item = self._canvas.create_arc(xc-radius, yc-radius,
  173.                                            xc+radius, yc+radius,
  174.                                            style="chord",
  175.                                            start=start,
  176.                                            extent=extent,
  177.                                            width=self._width,
  178.                                            outline="")
  179.             self._tofill.append(item)
  180.         if self._drawing:
  181.             if abs(extent) >= self._fullcircle:
  182.                 item = self._canvas.create_oval(xc-radius, yc-radius,
  183.                                                 xc+radius, yc+radius,
  184.                                                 width=self._width,
  185.                                                 outline=self._color)
  186.                 self._items.append(item)
  187.             item = self._canvas.create_arc(xc-radius, yc-radius,
  188.                                            xc+radius, yc+radius,
  189.                                            style="arc",
  190.                                            start=start,
  191.                                            extent=extent,
  192.                                            width=self._width,
  193.                                            outline=self._color)
  194.             self._items.append(item)
  195.         angle = start + extent
  196.         x1 = xc + abs(radius) * cos(angle * self._invradian)
  197.         y1 = yc - abs(radius) * sin(angle * self._invradian)
  198.         self._angle = (self._angle + extent) % self._fullcircle
  199.         self._position = x1, y1
  200.         if self._filling:
  201.             self._path.append(self._position)
  202.         self._draw_turtle()
  203.  
  204.     def heading(self):
  205.         return self._angle
  206.  
  207.     def setheading(self, angle):
  208.         self._angle = angle
  209.         self._draw_turtle()
  210.  
  211.     def window_width(self):
  212.         width = self._canvas.winfo_width()
  213.         if width <= 1:  # the window isn't managed by a geometry manager
  214.             width = self._canvas['width']
  215.         return width
  216.  
  217.     def window_height(self):
  218.         height = self._canvas.winfo_height()
  219.         if height <= 1: # the window isn't managed by a geometry manager
  220.             height = self._canvas['height']
  221.         return height
  222.  
  223.     def position(self):
  224.         x0, y0 = self._origin
  225.         x1, y1 = self._position
  226.         return [x1-x0, -y1+y0]
  227.  
  228.     def setx(self, xpos):
  229.         x0, y0 = self._origin
  230.         x1, y1 = self._position
  231.         self._goto(x0+xpos, y1)
  232.  
  233.     def sety(self, ypos):
  234.         x0, y0 = self._origin
  235.         x1, y1 = self._position
  236.         self._goto(x1, y0-ypos)
  237.  
  238.     def goto(self, *args):
  239.         if len(args) == 1:
  240.             try:
  241.                 x, y = args[0]
  242.             except:
  243.                 raise Error, "bad point argument: %s" % `args[0]`
  244.         else:
  245.             try:
  246.                 x, y = args
  247.             except:
  248.                 raise Error, "bad coordinates: %s" % `args[0]`
  249.         x0, y0 = self._origin
  250.         self._goto(x0+x, y0-y)
  251.  
  252.     def _goto(self, x1, y1):
  253.         x0, y0 = start = self._position
  254.         self._position = map(float, (x1, y1))
  255.         if self._filling:
  256.             self._path.append(self._position)
  257.         if self._drawing:
  258.             if self._tracing:
  259.                 dx = float(x1 - x0)
  260.                 dy = float(y1 - y0)
  261.                 distance = hypot(dx, dy)
  262.                 nhops = int(distance)
  263.                 item = self._canvas.create_line(x0, y0, x0, y0,
  264.                                                 width=self._width,
  265.                                                 capstyle="round",
  266.                                                 fill=self._color)
  267.                 try:
  268.                     for i in range(1, 1+nhops):
  269.                         x, y = x0 + dx*i/nhops, y0 + dy*i/nhops
  270.                         self._canvas.coords(item, x0, y0, x, y)
  271.                         self._draw_turtle((x,y))
  272.                         self._canvas.update()
  273.                         self._canvas.after(10)
  274.                     # in case nhops==0
  275.                     self._canvas.coords(item, x0, y0, x1, y1)
  276.                     self._canvas.itemconfigure(item, arrow="none")
  277.                 except Tkinter.TclError:
  278.                     # Probably the window was closed!
  279.                     return
  280.             else:
  281.                 item = self._canvas.create_line(x0, y0, x1, y1,
  282.                                                 width=self._width,
  283.                                                 capstyle="round",
  284.                                                 fill=self._color)
  285.             self._items.append(item)
  286.         self._draw_turtle()
  287.  
  288.     def _draw_turtle(self,position=[]):
  289.         if not self._tracing:
  290.             return
  291.         if position == []:
  292.             position = self._position
  293.         x,y = position
  294.         distance = 8
  295.         dx = distance * cos(self._angle*self._invradian)
  296.         dy = distance * sin(self._angle*self._invradian)
  297.         self._delete_turtle()
  298.         self._arrow = self._canvas.create_line(x-dx,y+dy,x,y,
  299.                                           width=self._width,
  300.                                           arrow="last",
  301.                                           capstyle="round",
  302.                                           fill=self._color)
  303.         self._canvas.update()
  304.  
  305.     def _delete_turtle(self):
  306.         if self._arrow != 0:
  307.             self._canvas.delete(self._arrow)
  308.         self._arrow = 0
  309.  
  310.  
  311.  
  312. _root = None
  313. _canvas = None
  314. _pen = None
  315.  
  316. class Pen(RawPen):
  317.  
  318.     def __init__(self):
  319.         global _root, _canvas
  320.         if _root is None:
  321.             _root = Tkinter.Tk()
  322.             _root.wm_protocol("WM_DELETE_WINDOW", self._destroy)
  323.         if _canvas is None:
  324.             # XXX Should have scroll bars
  325.             _canvas = Tkinter.Canvas(_root, background="white")
  326.             _canvas.pack(expand=1, fill="both")
  327.         RawPen.__init__(self, _canvas)
  328.  
  329.     def _destroy(self):
  330.         global _root, _canvas, _pen
  331.         root = self._canvas._root()
  332.         if root is _root:
  333.             _pen = None
  334.             _root = None
  335.             _canvas = None
  336.         root.destroy()
  337.  
  338.  
  339. def _getpen():
  340.     global _pen
  341.     pen = _pen
  342.     if not pen:
  343.         _pen = pen = Pen()
  344.     return pen
  345.  
  346. def degrees(): _getpen().degrees()
  347. def radians(): _getpen().radians()
  348. def reset(): _getpen().reset()
  349. def clear(): _getpen().clear()
  350. def tracer(flag): _getpen().tracer(flag)
  351. def forward(distance): _getpen().forward(distance)
  352. def backward(distance): _getpen().backward(distance)
  353. def left(angle): _getpen().left(angle)
  354. def right(angle): _getpen().right(angle)
  355. def up(): _getpen().up()
  356. def down(): _getpen().down()
  357. def width(width): _getpen().width(width)
  358. def color(*args): _getpen().color(*args)
  359. def write(arg, move=0): _getpen().write(arg, move)
  360. def fill(flag): _getpen().fill(flag)
  361. def circle(radius, extent=None): _getpen().circle(radius, extent)
  362. def goto(*args): _getpen().goto(*args)
  363. def heading(): return _getpen().heading()
  364. def setheading(angle): _getpen().setheading(angle)
  365. def position(): return _getpen().position()
  366. def window_width(): return _getpen().window_width()
  367. def window_height(): return _getpen().window_height()
  368. def setx(xpos): _getpen().setx(xpos)
  369. def sety(ypos): _getpen().sety(ypos)
  370.  
  371. def demo():
  372.     reset()
  373.     tracer(1)
  374.     up()
  375.     backward(100)
  376.     down()
  377.     # draw 3 squares; the last filled
  378.     width(3)
  379.     for i in range(3):
  380.         if i == 2:
  381.             fill(1)
  382.         for j in range(4):
  383.             forward(20)
  384.             left(90)
  385.         if i == 2:
  386.             color("maroon")
  387.             fill(0)
  388.         up()
  389.         forward(30)
  390.         down()
  391.     width(1)
  392.     color("black")
  393.     # move out of the way
  394.     tracer(0)
  395.     up()
  396.     right(90)
  397.     forward(100)
  398.     right(90)
  399.     forward(100)
  400.     right(180)
  401.     down()
  402.     # some text
  403.     write("startstart", 1)
  404.     write("start", 1)
  405.     color("red")
  406.     # staircase
  407.     for i in range(5):
  408.         forward(20)
  409.         left(90)
  410.         forward(20)
  411.         right(90)
  412.     # filled staircase
  413.     fill(1)
  414.     for i in range(5):
  415.         forward(20)
  416.         left(90)
  417.         forward(20)
  418.         right(90)
  419.     fill(0)
  420.     # more text
  421.     write("end")
  422.     if __name__ == '__main__':
  423.         _root.mainloop()
  424.  
  425. if __name__ == '__main__':
  426.     demo()
  427.