# -*- coding: utf-8 -*-
# Elisa - Home multimedia server
# Copyright (C) 2006-2008 Fluendo Embedded S.L. (www.fluendo.com).
# All rights reserved.
#
# This file is available under one of two license agreements.
#
# This file is licensed under the GPL version 3.
# See "LICENSE.GPL" in the root of this distribution including a special
# exception to use Elisa with Fluendo's plugins.
#
# The GPL part of Elisa is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Elisa" in the root directory of this distribution package
# for details on that license.

import pgm
from pgm.timing import implicit
from pgm.graph.image import Image
from pgm.utils import image as image_utils

from pgm.widgets import list_ng, const
import scrolled_list


class ShadedScrolledList(scrolled_list.ScrolledList):
    
    def __init__(self, 
                 width=1.0, height=2.0, visible_range_size=7,
                 top_shade=None, bottom_shade=None,orientation=const.VERTICAL):
        self._bottom_shade = Image()
        self._bottom_shade.connect("pixbuf-loaded", self._bottom_shade_loaded)
        
        self._top_shade = Image()
        self._top_shade.connect("pixbuf-loaded", self._top_shade_loaded)

        settings = {'duration': 300,
                    'transformation': implicit.DECELERATE,
                    }
        self._animated_top_shade = implicit.AnimatedObject(self._top_shade,
                                                          ('opacity',))
        self._animated_bottom_shade = implicit.AnimatedObject(self._bottom_shade,
                                                              ('opacity',))
        self._animated_top_shade.setup_next_animations(**settings)
        self._animated_bottom_shade.setup_next_animations(**settings)


        super(ShadedScrolledList, self).__init__(width=width, height=height,
                                                 visible_range_size=visible_range_size,
                                                 orientation=orientation)
        self.add(self._bottom_shade)
        self.add(self._top_shade)
        self.top_shade = top_shade
        self.bottom_shade = bottom_shade

    def top_shade__set(self, top_shade):
        if top_shade:
            self._top_shade.set_from_file(top_shade)

    def top_shade__get(self):
        return self._top_shade

    def bottom_shade__set(self, bottom_shade):
        if bottom_shade:
            self._bottom_shade.set_from_file(bottom_shade)

    def bottom_shade__get(self):
        return self._bottom_shade
        
    def _top_shade_loaded(self, top):
        self._top_shade.bg_color = (0, 0, 0, 0)
        self._top_shade.visible = True
        self._layout_shades()
        self._hide_show_shades()
        
    def _bottom_shade_loaded(self, bottom):
        self._bottom_shade.bg_color = (0, 0, 0, 0)
        self._bottom_shade.visible = True
        self._layout_shades()
        self._hide_show_shades()

    def pop(self, index):
        widget = scrolled_list.ScrolledList.pop(self, index)
        self._hide_show_shades()
        return widget
        
    def insert(self, index, widget):
        scrolled_list.ScrolledList.insert(self, index, widget)
        self._hide_show_shades()

    def selected_item__set(self, index):
        scrolled_list.ScrolledList.selected_item__set(self, index)
        self._hide_show_shades()
            
    def size__set(self, size):
        scrolled_list.ScrolledList.size__set(self, size)
        self._layout_shades()
 
    def position__set(self, position):
        scrolled_list.ScrolledList.position__set(self, position)
        self._layout_shades()

    def _hide_show_shades(self):
        index = self.selected_item
        middle = self.visible_range_size / 2
        max_opacity = 255
        min_opacity = 1

        bar_visible = False
        if self._vbar or self._hbar:
            bar_visible = self._hbar and self._hbar.visible
            bar_visible = bar_visible or (self._vbar and self._vbar.visible)

        if bar_visible:
            self._top_shade.visible = True
            self._bottom_shade.visible = True
            if index > middle:
                self._animated_top_shade.opacity = max_opacity
            else:
                self._animated_top_shade.opacity = min_opacity

            if index < len(self.widgets)-middle-1:
                self._animated_bottom_shade.opacity = max_opacity
            else:
                self._animated_bottom_shade.opacity = min_opacity
        else:
            self._top_shade.visible = False
            self._bottom_shade.visible = False
            
    def _layout_shades(self):
        z = self.z + 1

        try:
            current_item = self[self.selected_item]
            item_size = current_item.size
        except IndexError:
            item_size = self.size
        
        if self._orientation == const.VERTICAL:
            self._top_shade.width = item_size[0]
            self._top_shade.height = image_utils.get_height_from_par(self._top_shade)
            
            top_y = -(self._top_shade.height / 1.8)

            if self._vbar:
                if self._vbar_pos == const.LEFT:
                    x = self._vbar_spacing * 1.5
                else:
                    x = self.width - self._vbar_spacing
            else:
                x = 0
            self._top_shade.position = (x, top_y, z)
            
            self._bottom_shade.width = item_size[0]
            height = image_utils.get_height_from_par(self._bottom_shade)
            self._bottom_shade.height = height

            bottom_y = self.height - (self._bottom_shade.height / 2.5)
            self._bottom_shade.position = (x, bottom_y, z)
            
        elif self._orientation == const.HORIZONTAL:
            self._top_shade.height = item_size[1]
            self._top_shade.width = image_utils.get_width_from_par(self._top_shade)

            top_x =  -(self._top_shade.width / 1.5)
            if self._hbar:
                if self._hbar_pos == const.TOP:
                    y = self._hbar_spacing
                else:
                    y = self.height - self._hbar_spacing
            else:
                y = 0
            self._top_shade.position = (top_x, y, z)

            self._bottom_shade.height = self.height
            bottom_width = image_utils.get_width_from_par(self._bottom_shade)
            self._bottom_shade.width = bottom_width

            bottom_x = self.width - (self._bottom_shade.width / 2.5)
            self._bottom_shade.position = (bottom_x, y, z)
            
            
if __name__ == "__main__":
    import pgm
    import gobject
    import operator
    from pgm.graph.group import Group
    from pgm.graph.image import Image
    from pgm.graph.text import Text
    from pgm.timing import implicit
    from pgm.widgets import sliced_image, scrollbar, const
    import selector


    class ListItem(Group):

        def __init__(self, thumbnail=None, description=None, arrow=None):
            Group.__init__(self)

            self.thumbnail = Image()
            #self.thumbnail.bg_color = (0, 255, 0, 255)
            self.thumbnail.bg_color = (0, 0, 0, 0)
            self.thumbnail.layout = pgm.IMAGE_SCALED
            self.thumbnail.visible = True

            self._description = self._create_text()
            self._description.bg_color = (255, 0, 0, 255)

            self.add(self.thumbnail)
            self.add(self._description)
            
            if thumbnail is not None:
                self.thumbnail.set_from_file(thumbnail)

            self.description = description

##             if self.canvas:
##                 self._layout()

            # Arrow support disabled until some decision is taken.
            """
            arrow_x = text_x + text_width
            arrow_y = 0.4
            arrow_width = 0.25
            arrow_height = 0.8

            self.arrow = Image()
            self.arrow.bg_color = (0, 0, 0, 0)
            #self.arrow.bg_color = (0, 0, 255, 255)
            self.arrow.layout = pgm.IMAGE_SCALED
            self.arrow.size = (arrow_width, arrow_height)
            self.add(self.arrow)
            self.arrow.position = (arrow_x, arrow_y, 0)

            if arrow:
                self.arrow.set_from_file(arrow)
            """

        def _layout(self):
            canvas = self.canvas
            vspacing = canvas.width / 35.

            thumbnail_width = canvas.width / 13.
            thumbnail_height = canvas.height / 8.
            thumbnail_x = canvas.width / 70.
            thumbnail_y = canvas.height / 60.

            self.thumbnail.position = (thumbnail_x, thumbnail_y, 0)
            self.thumbnail.size = (thumbnail_width, thumbnail_height)

            text_x = thumbnail_width + vspacing
            text_y = canvas.height / 45.
            text_width = canvas.width / 1.9
            text_height = self.height

            self._description.position = (text_x, text_y, 0)
            self._description.size = (text_width, text_height)

        def canvas__set(self, canvas):
            Group.canvas__set(self, canvas)
            if canvas is not None:
                self._layout()

        def _create_text(self):
            txt = Text()
            txt.font_family = "Nimbus Sans L"
            txt.bg_color = (0, 0, 0, 0)
            txt.alignment = pgm.TEXT_ALIGN_LEFT
            txt.ellipsize = pgm.TEXT_ELLIPSIZE_MIDDLE
            txt.opacity = 255
            return txt

        def description__set(self, text):
            self._description.markup = u'<b>%s</b>' % text
            self._description.visible = True
            # len(text) > 0

        def description__get(self):
            return self._description
    


    text_idx = 0

    def create_item(label):
        global text_idx
        text = "%s %s" % (label, text_idx)
        item = ListItem(description=text, arrow="theme/arrow.png")
        text_idx += 1
        return item

    def update_lists(lists, function):
        for list_widget in lists:
            try:
                function(list_widget)
            except Exception, exc:
                print exc

    def on_key_press(viewport, event, lists):
        # quit on q or ESC
        if event.keyval in (pgm.keysyms.q, pgm.keysyms.Escape):
            pgm.main_quit()

        if event.keyval in (pgm.keysyms.Down, pgm.keysyms.Right):
            prop = 'selected_item'
            update_lists(lists,
                         lambda w: setattr(w, prop, getattr(w, prop) + 1))
        elif event.keyval in (pgm.keysyms.Up, pgm.keysyms.Left):
            prop = 'selected_item'
            update_lists(lists,
                         lambda w: setattr(w, prop, getattr(w, prop) - 1))
        elif event.keyval == pgm.keysyms.a:
            update_lists(lists,
                         lambda w: w.append(create_item("pictures/fluendo.png")))
        elif event.keyval == pgm.keysyms.r:
            update_lists(lists,
                         lambda list_widget: list_widget.pop())
                
    def on_delete(viewport, event):
        pgm.main_quit()

    # OpenGL viewport creation
    factory = pgm.ViewportFactory('opengl')
    gl = factory.create()
    gl.title = 'TextList widget-test'

    # Canvas and image drawable creation
    canvas = pgm.Canvas()

    # Bind the canvas to the OpenGL viewport
    gl.set_canvas(canvas)
    gl.show()

    visible_items = 9
    items_nb = 20
    
##     canvas_bg = Image()
##     canvas_bg.size = canvas.size
##     canvas_bg.fg_color = (255, 0, 0, 0)
##     canvas_bg.visible = True
##     canvas.add(pgm.DRAWABLE_MIDDLE, canvas_bg)
##     canvas_bg.position = (0, 0, 0)

    top_left = ShadedScrolledList(3, 1, orientation=const.VERTICAL)
    top_left.top_shade = "theme/gradient-top.png"
    top_left.bottom_shade = "theme/gradient-bottom.png"
                            
    top_left.canvas = canvas    
    top_left.visible_range_size = visible_items
    top_left.position = (0.04, 0.65, 0)
    top_left.width = canvas.width * 0.55
    top_left.height = canvas.height * 0.72
    top_left.visible = True
    
    bg = sliced_image.SlicedImage(top_file="theme/scrollbar-top.png",
                                  bottom_file="theme/scrollbar-bottom.png",
                                  body_file="theme/scrollbar-body.png")

    cursor = sliced_image.SlicedImage(top_file="theme/cursor-top.png",
                                      bottom_file="theme/cursor-bottom.png",
                                      body_file="theme/cursor-body.png")

    bar = scrollbar.Scrollbar(items_number=visible_items,
                              background=bg, cursor=cursor,
                              spacing=0.01)
    #bar.visible = False
 
    bar.thickness=0.07
    
    top_left.set_vertical_scrollbar(bar, const.LEFT, spacing=0.02)

    pictos = ("theme/selector-left.png",
              "theme/selector-right.png",
              "theme/selector-body.png",
              "theme/back-selector-left.png",
              "theme/back-selector-right.png",
              "theme/back-selector-body.png",
              
              )
    
    list_selector = selector.Selector(orientation=const.HORIZONTAL, *pictos)
    #list_selector.opacity = 100
    top_left.set_selector(list_selector)

    lists = [ top_left,
             ]

    # very very very very
    label = "this is a long long text"
    update_lists(lists, lambda w: [ w.append(create_item(label))
                                    for i in xrange(items_nb) ])
    update_lists(lists, lambda w: setattr(w, 'selected_item', 0))


    # Let's start a mainloop
    gl.connect('key-press-event', on_key_press, lists)
    gl.connect('delete-event', on_delete)
    pgm.main()
