#!/usr/bin/env python
import cairo
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GLib, GObject
import threading
import time
import _thread
from random import random,randint
from math import pi

width,height = 1024,768
win = Gtk.Window()
drawingarea = Gtk.DrawingArea()
win.add(drawingarea)
brush = 1
da = 1
delaytime = 500
eehandler = 0

### Thread control
syn = threading.Event()   # throttles mainloop
syn2 = threading.Event()  # throttles user thread
syn.clear()  # .set allows to go through, .clear blocks
syn2.clear()  # block
stopall = False           # for cleanup

# old code, Thread permits a while loop inside mydraw
class MyThread ( threading.Thread ):
    def __init__(self,d,b):
        global brush,da
        threading.Thread.__init__(self)
        self.da = d
        self.br = b
        brush = b
        da = d
    def run ( self ):
        global mydraw
        mydraw()
#class MyThread

# animation refresh control loop:
def mainloop(da1, brush1):
    global da,brush
#    da = da1
    brush = brush1
#    print("mainloop")	
    if not stopall:
        syn.wait()  # wait for permission to refresh screen
        syn.clear() # reset for next round
        brush.stroke() 
        syn2.set()   # informs user thread to goto next iteration
        win.queue_draw_area(0,0,width-1,height-1)
        return False
# end mainloop

def area_expose_cb(daa, bbrush):	
    global brush, da, eehandler,mainloop
    brush = bbrush
    my = MyThread(daa,bbrush)
    my.start()
    drawingarea.handler_block(eehandler)
    eeh = drawingarea.connect('draw', mainloop)  # reconnect
    #win.queue_draw()
    mainloop(daa,bbrush)  # sxxtart main animation refresh cycle
    return True

win.connect('destroy', lambda w: Gtk.main_quit())
win.set_default_size(width,height)
eehandler = drawingarea.connect('draw', area_expose_cb)
win.show_all()


def updateDisplay():
    syn.set()         # release mainloop to refresh screen
    syn2.wait()       # synch with mainloop before looping again
    syn2.clear()      # reset for next round
# end updateDisplay

def cleanup():
    global stopall
    stopall = True
    syn.set()
    syn2.set()
# end cleanup

### some common colors as RGB triples:
black = (0,0,0)
white=(1,1,1)
red = (1,0,0)
green = (0,1,0)
blue=(0,0,1)
yellow = (1,1,0)
aqua=(0,1,1)
magenta=(1,0,1)
gray=(.5,.5,.5)
purple=(.5,0,0.5)

COLORS = [black,white,red,green,blue,yellow,aqua,magenta,gray,purple]

##########################################################################
############################# STUDENT CODE ###############################
##########################################################################



## To affect animation, entire image must be redrawn with each updateDisplay
## Animate one moving circle, defined by x,y,r,dx,dy,c for color

def mydraw():
    # sets attributes of circle
    r = randint(8,64)  # radius of circle
    x,y = width//2, height//2   # start at middle
    dx,dy = randint(-10,10), randint(-6,6)
    CLS = [white,red,green,blue,yellow,aqua,magenta,gray,purple]    
    color = CLS[ randint(1,len(CLS)-1) ]
    while True:
        brush.set_source_rgb(*black)  # * needed to unravel tuple
        brush.paint()  # paints over background to draw new frame
        # draw circle
        brush.set_source_rgb(*color)
        brush.new_sub_path()    # avoids extra line in arc
        brush.arc(x,y,r,0,2*pi)   # circle
        brush.fill()  # solid circle

        x += dx  # change position by movement vector
        y += dy
        if (x<=r or x>=width-r): dx = -1 *dx
        if (y<=r or y>=height-r): dy *= -1 # same as dy = dy* -1
        
        updateDisplay()   # draw frame
        time.sleep(0.1)  # animation delay
    return False
#mydraw




#### The following must be the last line of the program: don't move
Gtk.main()
