# -*- mode: python; coding: utf-8 -*-
#
# Pigment Python tools
#
# Copyright © 2006, 2007, 2008 Fluendo Embedded S.L.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.

from pgm.graph.group import Group
from pgm.graph.image import Image
from pgm.timing import implicit
from pgm.widgets import const
import pgm, gobject

class Scrollbar(Group):

    __gsignals__ = { 
        'index-changed' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE,
                           (gobject.TYPE_INT,))
        }


    def __init__(self, orientation=const.VERTICAL, items_number=0,
                 thickness=0.1,
                 cursor=None, background=None, spacing=None
                 ):
        """
        @keyword orientation:  bar orientation, const.VERTICAL by default
        @type orientation:     int
        @keyword items_number: how many cursors the bar can scroll
        @type items_number:    int
        @keyword cursor_color: color of the bar cursor, white by default
        @type cursor_color:    4-int tuple
        @keyword bg_color:     color of the bar background, black by default
        @type bg_color:        4-int tuple
        """
        Group.__init__(self)
        self._items_number = items_number
        self._current_index = 0
        self._cur_size = None
        self._cur_pos = None
        self._orientation = orientation
        self._thickness = thickness
        self._background = None
        self._cursor = None
        self._animated_cursor = None

        if spacing is None:
            spacing = 0
            
        self._spacing = spacing
        
        if not cursor:
            # cursor, white by default
            cursor_color = (255,255,255,255)
            cursor = Image()
            cursor.bg_color= cursor_color
            
        if not background:
            # background of the bar, black by default
            bg_color = (0,0,0,255)
            background = Image()
            background.bg_color = bg_color

        self.background = background        
        self.cursor = cursor
        self.visible = True

        # animation support
        self._animated = implicit.AnimatedObject(self)
        self._animated.setup_next_animations(duration=500, resolution=5,
                                             transformation=implicit.DECELERATE)
        self._animated.mode = implicit.REPLACE


    def background__set(self, background):
        if self._background:
            self.remove(self._background)
            
        self._background = background
        self._background.visible = True
        self.add(self._background)
        self._background.size = self.size

        self._background.connect("scrolled", self._scrolled)
        
        self._update_cursor_size()
        self._update_cursor_position()
        
    def background__get(self):
        return self._background

    def cursor__set(self, cursor):
        if self._cursor:
            self.remove(self._cursor)

        self._cursor = cursor
        self._cursor.visible = True
        self.add(self._cursor)
        self._cursor.connect("drag-begin", self._drag_begin)
        self._cursor.connect("drag-motion", self._drag_motion)
        self._cursor.connect("drag-end", self._drag_end)
        self._cursor.connect("pressed", self._drag_pressed)
        
        self._update_cursor_size()
        self._update_cursor_position()

        attrs = ('cursor_index','position')
        self._animated_cursor = implicit.AnimatedObject(self._cursor, attrs)
        settings = {'duration': 300,
                    'transformation': implicit.LINEAR,
                    'resolution': 5}
        self._animated_cursor.setup_next_animations(**settings)
        self._animated_cursor.mode = implicit.REPLACE
        
    def cursor__get(self):
        return self._cursor

    def thickness__get(self):
        return self._thickness

    def thickness__set(self, thickness):
        self._thickness = thickness
        self.size = self.size

    def orientation__set(self, orientation):
        self._orientation = orientation
        self._update_cursor_size()
        self._update_cursor_position()

    def orientation__get(self):
        return self._orientation
        
    def size__set(self, size):
        size = self._apply_thickness(size)
        Group.size__set(self, size)
        self.background.size = size

        self._update_cursor_size()
        self._update_cursor_position()

    def items_number__set(self, nb):
        if nb <= 0:
            nb = 1
            
        self._items_number = nb

        if self._current_index > (nb-1):
            self._current_index = nb - 1
        
        self._update_cursor_size()
        self._update_cursor_position()

    def items_number__get(self):
        return self._items_number

    def cursor_index__set(self, position):
        """
        Set the position of the cursor. The bar is automatically new painted
        @param position: the position to set to
        @type position: something to do mathematic stuff
        """
        if position >= 0 and position < self._items_number:
            changed = position != self._current_index
            self._current_index = position
            self._update_cursor_position()
            if changed:
                self.emit('index-changed', position)
                
    def cursor_index__get(self):
        """
        returns the position of the cursor
        @return : the position of the cursor
        """
        return int(self._current_index)

    def next_item(self):
        """
        go to the next item.  The bar is automatically new painted
        """
        self.cursor_index += 1

    def previous_item(self):
        """
        go to the previous item.  The bar is automatically new painted
        """
        self.cursor_index -= 1

    def _apply_thickness(self, size):
        width, height = size
        if self._orientation == const.HORIZONTAL:
            height = self._thickness
        else:
            width = self._thickness

        size = (width, height)
        return size

    def _update_cursor_size(self):
        if self._items_number > 0:
            spacing = (self._spacing * 2)
            if self._orientation == const.VERTICAL:
                width = self.width - spacing
                height = float(self.height / self._items_number)
                if self._items_number == 1:
                    height -= spacing
            else:
                width = float(self.width / self._items_number)
                height = self.height - spacing
                if self._items_number == 1:
                    width -= spacing
                    
            size = (width, height)
        else:
            size = self.size

        self._cur_size = size
        if self._animated_cursor:
            self._animated_cursor.size = self._cur_size
        elif self._cursor:
            self._cursor.size = self._cur_size
            
    def _update_cursor_position(self):
        if self._background:
            if self._current_index == 0:
                spacing = self._spacing
            elif self._current_index == self._items_number-1:
                spacing = - self._spacing
            else:
                spacing = 0

            w, h = self._cur_size
            if self._orientation == const.VERTICAL:
                y = self.background.y + spacing + (h * self._current_index)
                x = self.background.x + self._spacing
            else:
                x = self.background.x + spacing + (w * self._current_index)
                y = self.background.y + self._spacing

            self._cur_pos = (x, y, self.z)
            if self._animated_cursor:
                self._animated_cursor.position = self._cur_pos
            elif self._cursor:
                self._cursor.position = self._cur_pos

    def _scrolled(self, widget, x, y, z, direction, time):
        if direction == pgm.SCROLL_UP:
            self.previous_item()
        else:
            self.next_item()

    def _drag_begin(self, widget, x, y, z, button, time, pressure):
        self._original_position = (x, y, z)
        #print widget
        #self._animated.stop_animations()
        
    def _drag_motion(self, widget, x, y, z, button, time, pressure):
        if self._orientation == const.VERTICAL:
            offset = y - self._original_position[1]
        else:
            offset = x - self._original_position[0]
        #print offset
        new_index = self._current_index + (offset / self._items_number)
        if new_index >= 0 and new_index < self._items_number-1:
            #self._current_index = new_index
            self.cursor_index = new_index
        self._original_position = (x, y, z)
        self._update_cursor_position()
        
    def _drag_end(self, widget, x, y, z, button, time):
        self._original_position = None
        self._current_index = round(self._current_index)
        self._update_cursor_position()
        
    def _drag_pressed(self, widget, x, y, z, button, time, pressure):
        self._drag_begin(widget, x, y, z, button, time, pressure)
        self._drag_end(widget, x, y, z, button, time, pressure)

            
if __name__ == "__main__":
    from pgm.graph.image import Image
    from pgm.graph.text import Text
    import pgm
    import os, gobject, sys
    from sliced_image import SlicedImage

    def update_bars(bars, function):
        for b in bars:
            function(b)

    def on_key_pressed(port, event, bars, loop):
        if event.keyval in (pgm.keysyms.Escape, pgm.keysyms.q):
            loop.quit()
        if event.keyval == pgm.keysyms.Up:
            update_bars(bars, lambda b: b.previous_item())
        elif event.keyval == pgm.keysyms.Down:
            update_bars(bars, lambda b: b.next_item())
        elif event.keyval == pgm.keysyms.a:
            update_bars(bars, lambda b: setattr(b, 'items_number',
                                                getattr(b, 'items_number') + 1))
        elif event.keyval == pgm.keysyms.r:
            update_bars(bars, lambda b: setattr(b, 'items_number',
                                                getattr(b, 'items_number') - 1))

    factory = pgm.ViewportFactory('opengl')
    gl = factory.create()
    gl.title = 'bar widget'

    canvas = pgm.Canvas()
    gl.set_canvas(canvas)
    gl.show()

    bar = Scrollbar(canvas, pgm.DRAWABLE_MIDDLE, items_number=12,
                    spacing=0.01)
    bar.canvas = canvas
    bar.background.bg_color = 38, 139, 200, 255
    bar.cursor.bg_color = 200, 239, 250, 155
    bar.position = (canvas.width * 0.05, canvas.height * 0.1, 0)
    bar.height = canvas.height * 0.8

    pictos = ("elisa_mockups/export/list_mode/selector/selector-left.png",
              "elisa_mockups/export/list_mode/selector/selector-right.png",
              "elisa_mockups/export/list_mode/selector/selector-body.png")
    cursor = SlicedImage(orientation=const.HORIZONTAL, *pictos)
                         
    bar2 = Scrollbar(items_number=12, orientation=const.HORIZONTAL,
                     cursor=cursor, thickness=0.5)
    bar2.canvas = canvas
    bar2.cursor.z += 1
    bar2.position = (0.5, 1, 0)
    bar2.width = canvas.width * 0.8

    pictos = ("elisa_mockups/export/list_mode/scrollbar/scrollbar-top.png",
              "elisa_mockups/export/list_mode/scrollbar/scrollbar-bottom.png",
              "elisa_mockups/export/list_mode/scrollbar/scrollbar-body.png")
    frame = SlicedImage(*pictos)
    pictos = ("elisa_mockups/export/list_mode/scrollbar/cursor-top.png",
              "elisa_mockups/export/list_mode/scrollbar/cursor-bottom.png",
              "elisa_mockups/export/list_mode/scrollbar/cursor-body.png")
    cursor = SlicedImage(*pictos)
    
    bar3 = Scrollbar(items_number=12,
                     background=frame,
                     #thickness=0.08,
                     cursor=cursor, spacing=0.01
                     )
    bar3.canvas = canvas
    bar3.position = (0.35, canvas.height * 0.1, 0)
    bar3.height = canvas.height * 0.8


    bars = [bar, bar2, bar3,]
    
    loop = gobject.MainLoop()
    gl.connect('key-press-event', on_key_pressed, bars, loop)
    loop.run()
