from Gui import *

class Item:
    """an Item object represents a canvas item.

    When you create a canvas item, Tkinter returns an integer 'tag'
    that identifies the new item.  To perform an operation on the
    item, you invoke a method on the canvas and pass the tag as
    a parameter.

    The Item class makes this interface more object-oriented:
    each Item object contains a canvas and a tag.  When you
    invoke methods on the Item, it invokes methods on its canvas.
    """
    def __init__(self, canvas, tag):
        self.canvas = canvas
        self.tag = tag
        self.bind('<Button-1>', self.select)
        self.bind('<B1-Motion>', self.drag)
        self.bind('<ButtonRelease-1>', self.release)

    def __str__(self):
        return 'Item' + str(self.tag)
        
    # the following are wrappers for canvas methods
    
    def bind(self, event, callback):
        """this method applies bindings to canvas items (not
        the whole canvas)"""
        self.canvas.tag_bind(self.tag, event, callback)

    def config(self, **options):
        """reconfigure this item with the given options"""
        self.canvas.itemconfig(self.tag, **options)

    def coords(self, *args):
        """get or set the canvas coordinates for this item"""
        return self.canvas.coords(self.tag, *args)

    def move(self, dx, dy):
        """move this item by (dx, dy) in PIXEL coordinates"""
        self.canvas.move(self.tag, dx, dy)

    def move_coord(self, i, dx, dy):
        """move the ith coordinate by (dx, dy) in canvas coordinates """
        coords = self.coords()
        coords[i][0] += dx
        coords[i][1] += dy
        self.coords(coords)

    def replace_coord(self, i, coord):
        """replace the ith coordinate with the given canvas coordinate"""
        coords = self.coords()
        coords[i] = coord
        self.coords(coords)

    # the following event handlers take an event object as a parameter

    def select(self, event):
        print 'Item.select', self
        self.config(fill='red')
        self.set_drag(event)
        
    def drag(self, event):
        """move this item using the pixel
        coordinates in the event object."""

        # see how far we have moved
        dx, dy = self.sub_drag(event, self.drag)
        
        # save the current drag coordinates
        self.set_drag(event)

        # move the item
        # NOTE: the reason we have to negate dy is to translate
        # from pixel coordinates to canvas coordinates,
        # but this is a terrible hack, because it assumes that
        # the only transform in effect is a CanvasTransform.
        self.move(dx, -dy)
        return dx, dy

    def release(self, event):
        print 'Item.release', self
        self.config(fill='blue')


    # the following methods are for dealing with events and drag
    # coordinates
        
    def get_drag(self, event):
        """get the drag coordinates from this event and translate
        them into canvas coordinates"""
        x, y = self.canvas.trans([event.x, event.y])
        return x, y

    def set_drag(self, event):
        """store the current drag coordinates"""
        self.drag = self.get_drag(event)

    def sub_drag(self, event, d2):
        """subtract d2 from the drag coordinates in event"""
        d1 = self.get_drag(event)
        return d1[0] - d2[0], d1[1] - d2[1]
        

class Hello(Gui):
    def __init__(self):
        Gui.__init__(self)
        self.ca_width = 400
        self.ca_height = 400
        self.setup()

    def setup(self):
        
        # frame 1
        self.fr(TOP)
        self.canvas = self.ca(width=self.ca_width, height=self.ca_height,
                              bg='white')
        self.canvas.bind('<Button-1>', self.click)
        self.endfr()

        # frame 2
        self.fr(TOP, fill=BOTH, expand=1)

        self.fr()
        self.bu(LEFT, text='Hello', command=self.hello)
        self.bu(LEFT, text='Circle', command=self.circle)
        self.bu(LEFT, text='Quit', command=self.quit)
        self.endfr()

        self.endfr()

    def hello(self):
        font = ('Helvetica', 36)
        tag = self.canvas.text([0, 0], 'Hello', font=font, fill='blue')
        item = Item(self.canvas, tag)

    def circle(self):
        tag = self.canvas.circle(0, 0, 100, 'blue')
        item = Item(self.canvas, tag)

    def click(self, event):
        """this event handler gets invoked when the user clicks
        on the canvas."""
        print 'Hello.click', event.type, event.num, event.x, event.y


if __name__ == '__main__':
    h = Hello()
    h.mainloop()
