#!/usr/bin/env python
# -*- coding: utf-8 -*-
# ------------------------------------------------------------------------------
# Copyright (c) 2009 Nicolas Rougier, Matthieu Kluj, Jessy Cyganczuk
# All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions 
# are met:
#
#    * Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#    * Redistributions in binary form must reproduce the above copyright 
#    notice, this list of conditions and the following disclaimer in
#    the documentation and/or other materials provided with the
#    distribution.
#    * Neither the name of pyglet nor the names of its
#    contributors may be used to endorse or promote products
#    derived from this software without specific prior written
#    permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------
import pyglet
from pyglet.gl import *
from shape import Rectangle, Ellipse, Cross, Star, Triangle
from widget import Widget

from decimal import *

# ----------------------------------------------------------------------- Slider
class Slider(Widget):
    ''' Slider widget
    
    Basic slider
    '''
    # _________________________________________________________________ __init__
    def __init__(self, x=0, y=0, z=0, width=200, height=60,
                 font_size=10, anchor_x='left', anchor_y='bottom',
                 value=0.50, minimum=0.0, maximum=1.0, step=0.01, label=True, ticks=[]):

        Widget.__init__(self, x, y, z, width, height, anchor_x, anchor_y)
        # colors
        fg = (1, 1, 1, 1)
        bg = (1, 1, 1, .5)
        self.panning = 6
        # step and precision
        getcontext().prec = 10
        self.precision = abs(Decimal("%.7f"%step).normalize().adjusted())
        self.step = step
        self.value = 0
        # widget elements
        self._elements['frame'] = Rectangle (x=0, y=height/2, z=z,
                                            width=width, height=height/2, radius=(height/2 - 1) / 2,
                                            foreground=fg, background=bg,
                                            anchor_x=anchor_x, anchor_y='bottom')
        self._elements['cursor'] = Ellipse (x=0, y= -.5 + height/2 , z=z,
                                            width=height/2 - 1, height=height/2 - 1,
                                            foreground=fg, background=fg,
                                            anchor_x='center', anchor_y='center')
        if len(ticks)>0:
            self._elements['ticks'] =  pyglet.text.Label(' 1 2 3 4 5', font_name='consolas',
                                                        font_size=height/4- self.panning,  x=0, y=2*height/4,
                                                        anchor_x='left', anchor_y='bottom')
            self.ticks = [ str(i) for i in ticks ]
            self.e =  float(self._elements['ticks'].content_width) / 10.0
        if label:
            self._elements['label'] = pyglet.text.Label('0', font_name='consolas',
                                                        font_size=height/4- self.panning, x=0, y=0,
                                                        anchor_x='center', anchor_y='bottom')
        # first time init : MUST give minimum and maximum
        self.set_cursor(value, minimum, maximum)
        # setup correct dimensions
        self.update_height()
        self._is_dragging = False
        
    # ____________________________________________________________________ update_width
    def update_width(self):
        self._elements['frame'].width = self.width
        if self._elements.has_key('ticks'):
            s = ''
            w = int(round(self.width / ( self.e * float( len(self.ticks) -1) )))
            for i in range(1, len(self.ticks)+1):
                if i==1:
                    s+= self.ticks[i-1].ljust(1+int(w/2))
                elif i==len(self.ticks):
                    s+= self.ticks[i-1].rjust(int(w/2))
                else:
                    s += self.ticks[i-1].center( w +(i%2*len(self.ticks[i])%2))
            self._elements['ticks'].text = s
        self.set_cursor(self.value)

    # ____________________________________________________________________ update_height
    def update_height(self):
        # The frame takes 1/2 of the height, and the rest is shared by ticks and label
        self._elements['frame'].height = self.height/2 - 2*self.panning
        self._elements['frame'].radius = (self._elements['frame'].height - 1) / 2
        self._elements['frame'].y = (self.height/4 - 1) + self.panning
        self._elements['cursor'].height = self._elements['frame'].height - 1
        self._elements['cursor'].width = self._elements['cursor'].height
        self._elements['cursor'].y = self._elements['frame'].y + self._elements['cursor'].height / 2 + 0.5
        if self._elements.has_key('ticks'):
            self._elements['ticks'] = pyglet.text.Label(' 1 2 3 4 5',  font_name='consolas',
                                                        font_size= int((self.height/4 - self.panning)/2.0) * 2, 
                                                        x=0, y=self._elements['frame'].y + self._elements['frame'].height + self.panning,
                                                        anchor_x='left', anchor_y='bottom')
            self.e =  float(self._elements['ticks'].content_width) / 10.0
        if self._elements.has_key('label'):
            self._elements['label'] = pyglet.text.Label(' ',  font_name='consolas',
                                                        font_size= int((self.height/4 - self.panning)/2.0) * 2, x=0, y=0,
                                                        anchor_x='center', anchor_y='bottom')
        # because we have changed font size, we must adjust the width
        self.update_width()
        
    # ____________________________________________________________________ set_cursor
    def set_cursor(self, v, minimum=None, maximum=None):
        ''' Sets the cursor position
        
        :Parameters:
            `v` : float
                New position of the cursor.
            `minimum` : float
                left bound of the cursor.
            `maximum` : float
                right bound of the cursor.
        '''
        if minimum is not None:
            self.minimum = minimum
        if maximum is not None:
            self.maximum = maximum
        if v != self.value or minimum is not None or maximum is not None:
            self.value = max(self.minimum, min(self.maximum, float(v)))
            self.value = round(self.value / self.step) * self.step
            # inform about the change of value
            self.dispatch_event('on_value_change', self.value)
        # convert value in proportions of width [0 1] for display
        p = (self.value - self.minimum) / (self.maximum - self.minimum)
        self._elements['cursor'].x = self._elements['frame'].radius +  int( float(self._elements['frame'].width - self._elements['cursor'].width) * p)
        if self._elements.has_key('label'): 
            self._elements['label'].text = str('{0:.%df}'%self.precision).format(self.value)
            self._elements['label'].x = self._elements['cursor'].x

    # ____________________________________________________________________ on_mouse_press
    def on_mouse_press(self, x, y, button, modifiers):
        if button == pyglet.window.mouse.LEFT:
            if self._elements['frame'].hit_test(x - self.x, y - self.y):
                self._is_dragging = True
                self._elements['cursor'].background = (0.4, 0.4, 0.4, 1)
                v = float(x -4 -self._elements['frame'].x -self._elements['frame'].radius) / float(self._elements['frame'].width - self._elements['cursor'].width)
                self.set_cursor(v * (self.maximum - self.minimum) + self.minimum)
                return pyglet.event.EVENT_HANDLED
        
        return pyglet.event.EVENT_UNHANDLED

    # ____________________________________________________________________ on_mouse_drag
    def on_mouse_drag(self, x, y, dx, dy, button, modifiers):
        if self._is_dragging and button == pyglet.window.mouse.LEFT:
            v = float(x + dx -4 -self._elements['frame'].x -self._elements['frame'].radius) / float(self._elements['frame'].width - self._elements['cursor'].width)
            self.set_cursor(v * (self.maximum - self.minimum) + self.minimum)
            return pyglet.event.EVENT_HANDLED
        
        return pyglet.event.EVENT_UNHANDLED

    # ____________________________________________________________________ on_mouse_release
    def on_mouse_release(self, x, y, button, modifiers):
        if button == pyglet.window.mouse.LEFT and self._is_dragging:
            self._is_dragging = False
            self._elements['cursor'].background = (1, 1, 1, 1)
        return pyglet.event.EVENT_UNHANDLED

Slider.register_event_type('on_value_change')

# ------------------------------------------------------------------------------
if __name__ == '__main__':
    window = pyglet.window.Window(resizable=True)
    slider = Slider(x=50, y=50)
    window.push_handlers(slider)

    @window.event
    def on_draw():
        window.clear()
        slider.on_draw()

    @slider.event
    def on_value_change(v):
        print v

    pyglet.app.run()
