
import math

import cairo
import gobject
import gtk
import gtk.gdk

import glitch, glitch.gtk
from glitch.cairo import CairoTexture
from glitch.limbo.spread import Spread

class Slide(CairoTexture):
    def __init__(self, text, **kw):
        CairoTexture.__init__(self, 800, 600, **kw)
        self.text = text

    def draw_cairo(self, cr):
        cr.set_source_rgba(1, 1, 1, 0.95)
        cr.paint()
        cr.set_source_rgba(0, 0, 0, 0.95)
        cr.move_to(0, 100)
        cr.set_font_size(64)
        cr.select_font_face(
            "Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
        cr.show_text(self.text)

def sigmoid(t):
    return 1 / (1 + math.exp(-t))

class Animation(object):
    def __init__(self, duration, steps, apply):
        self.duration = duration
        self.steps = steps
        self.apply = apply
        self.done = lambda: None
        self.time  = 0
        self.timeout_id = None

    def start(self):
        if self.timeout_id is not None:
            raise RuntimeError

        interval = int(self.duration / float(self.steps) * 100)
        self.timeout_id = gobject.timeout_add(interval, self.tick)

    def tick(self):
        self.apply(self.time / float(self.steps))
        self.time += 1

        if self.time == self.steps:
            self.timeout_id = None
            self.done()
            return False
        else:
            return True

def animate_move_x(obj, destination):
    source = obj.x

    def apply(time):
        obj.x = source + sigmoid(10 * (time - 0.5)) * (destination - source)

    return Animation(0.6, 12, apply)

def key_press(w, ev):
    global current_slide
    name = gtk.gdk.keyval_name(ev.keyval)
    new_slide = current_slide

    if name == 'Left':
        new_slide = max(0, current_slide - 1)
    elif name == 'Right':
        new_slide = min(len(slides.children) - 1, current_slide + 1)

    if new_slide != current_slide and not animations:
        current_slide = new_slide
        a = animate_move_x(translate, -slides.x * current_slide)
        old_apply = a.apply

        def apply_and_refresh(time):
            old_apply(time)
            camera.refresh()

        def done():
            animations.remove(a)

        a.apply = apply_and_refresh
        a.done = done
        animations.append(a)
        a.start()

if __name__ == '__main__':
    current_slide = 0
    animations = []
    slides = Spread(x=1.3, children=[
        glitch.ApplyTexture(Slide(text='EENIE'),
            children=[glitch.TexturedRectangle()]),
        glitch.ApplyTexture(Slide(text='MEANIE'),
            children=[glitch.TexturedRectangle()]),
        glitch.ApplyTexture(Slide(text='MYNIE'),
            children=[glitch.TexturedRectangle()]),
        glitch.ApplyTexture(Slide(text='MOE'),
            children=[glitch.TexturedRectangle()])])
    translate = glitch.Translate(children=[slides])
    camera = glitch.gtk.GtkCamera(eye=[0.5, 0.5, 0.7], ref=[0.5, 0.5, 0],
        zNear=0.1, zFar=10, children=[translate])

    w = gtk.Window()
    w.connect('destroy', lambda w: gtk.main_quit())
    w.connect('key-press-event', key_press)
    w.add(camera)
    w.show_all()

    gtk.main()
