#Copyright (c) 2008, Media Modifications Ltd.

#Permission is hereby granted, free of charge, to any person obtaining a copy
#of this software and associated documentation files (the "Software"), to deal
#in the Software without restriction, including without limitation the rights
#to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
#copies of the Software, and to permit persons to whom the Software is
#furnished to do so, subject to the following conditions:

#The above copyright notice and this permission notice shall be included in
#all copies or substantial portions of the Software.

#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
#IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
#FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
#AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
#LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
#OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
#THE SOFTWARE.

import gtk
from gtk import gdk
import gobject
import cairo
import math

#Sometimes a gtk.Image is a useful alternative to a drawing area. You can put a gtk.gdk.Pixmap in the gtk.Image and draw to the gtk.gdk.Pixmap, calling the gtk.Widget.queue_draw() method on the gtk.Image when you want to refresh to the screen.

class P5(gtk.DrawingArea):
    def __init__(self):
        super(P5, self).__init__()

        # gtk.Widget signals
        self.connect("expose_event", self.expose)
        self.connect("button_press_event", self.button_press)
        self.connect("button_release_event", self.button_release)
        self.connect("motion_notify_event", self.motion_notify)

        # ok, we have to listen to mouse events here too
        self.add_events(gdk.BUTTON_PRESS_MASK | gdk.BUTTON_RELEASE_MASK | gdk.POINTER_MOTION_MASK)
        self._dragging = False
        self._mouseX = 0
        self._mouseY = 0

        self._w = -1
        self._h = -1


        #ok, this calls an initial painting & setting of painterly variables
        #e.g. time for the clock widget
        #(but not through to redraw_canvas when called here first time)
        self._msecUpdate = 100
        self._looping = False
        self.noloop()


    def loop(self):
        if (self._looping):
            return
        else:
            self._looping = True
            # this is our maybe-threaded refresh (in millisecs)
            gobject.timeout_add( self._msecUpdate, self.update )


    def noloop(self):
        self._looping = False
        self.redraw()


    def redraw(self):
        self.update()


    def expose(self, widget, event):
        ctx = widget.window.cairo_create()

        # set a clip region for the expose event
        ctx.rectangle(event.area.x, event.area.y, event.area.width, event.area.height)
        ctx.clip()

        rect = widget.allocation
        #self.draw(ctx, event.area.width, event.area.height)
        self.draw( ctx, rect.width, rect.height )


    def button_press(self, widget, event):
        self._mouseX = event.x
        self._mouseY = event.y
        self._dragging = True


    def button_release(self, widget, event):
        if self._dragging:
            self._dragging = False


    def motion_notify(self, widget, event):
        self._mouseX = event.x
        self._mouseY = event.y


    def draw(self, ctx, w, h):
        ctx.set_antialias( cairo.ANTIALIAS_NONE )
        ctx.set_line_width( 1 )
        ctx.identity_matrix( )
        if ((w != self._w) or (h != self._h)):
            self._w = w
            self._h = h
            self.doResize( )


    def doResize(self):
        pass


    #called from update
    def redraw_canvas(self):
        if self.window:
            alloc = self.get_allocation()
            #this is odd behavior, but once we add this widget to a parent (vbox)
            #it requires setting the q_d_a x,y to 0, 0
            #self.queue_draw_area(alloc.x, alloc.y, alloc.width, alloc.height)
            self.queue_draw_area(0, 0, alloc.width, alloc.height)
            self.window.process_updates(True)


    def update(self):
        #paint thread -- call redraw_canvas, which calls expose  
        self.redraw_canvas()
        if (self._looping):
            return True # keep running this event
        else:
            return False


    def drawShape( self, ctx, poly, col ):
        self.setColor( ctx, col )

        for i in range ( 0, len(poly._xs) ):
            ctx.line_to ( poly._xs[i], poly._ys[i] )
        ctx.close_path()
        ctx.set_line_width(1)
        ctx.stroke()


    def fillShape( self, ctx, poly, col ):
        self.setColor( ctx, col )
        for i in range ( 0, len(poly._xs) ):
            ctx.line_to (poly._xs[i], poly._ys[i])
        ctx.close_path()

        ctx.fill()


    def background( self, ctx, col, w, h ):
        self.setColor( ctx, col )

        ctx.line_to(0, 0)
        ctx.line_to(w, 0)
        ctx.line_to(w, h)
        ctx.line_to(0, h)
        ctx.close_path()

        ctx.fill()


    def rect( self, ctx, x, y, w, h ):
        ctx.line_to(x, y)
        ctx.line_to(x+w, y)
        ctx.line_to(x+w, y+h)
        ctx.line_to(x, y+h)
        ctx.close_path()


    def setColor( self, ctx, col ):
        if (not col._opaque):
            ctx.set_source_rgba( col._r, col._g, col._b, col._a )
        else:
            ctx.set_source_rgb( col._r, col._g, col._b )


    def line( self, ctx, x1, y1, x2, y2 ):
        ctx.move_to (x1, y1)
        ctx.line_to (x2, y2)
        ctx.stroke()


    def point( self, ctx, x1, y1 ):
        self.line( ctx, x1, y1, x1+1, y1 )