# -*- coding: utf-8 -*-
# Moovida - Home multimedia server
# Copyright (C) 2006-2009 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 Moovida with Fluendo's plugins.
#
# The GPL part of Moovida is also available under a commercial licensing
# agreement from Fluendo.
# See "LICENSE.Moovida" in the root directory of this distribution package
# for details on that license.
#
# Author: Florian Boucault <florian@fluendo.com>
#

import gobject

from elisa.core.input_event import EventValue

from elisa.plugins.pigment.widgets.widget import Widget
from elisa.plugins.pigment.widgets.const import STATE_NORMAL, \
                                                STATE_PRESSED, \
                                                STATE_SELECTED, \
                                                STATE_DISABLED

from elisa.plugins.pigment.graph.image import Image
from elisa.plugins.pigment.graph.text import Text


class AbstractButton(Widget):
    """
    Abstract base class of button widgets, providing functionality common to
    buttons.

    This class implements an abstract button. Subclasses of this class handle
    user actions, and specify how the button is drawn.

    Emits signals:
        - 'clicked': when the  DOCME
        - 'pressed': when the position  DOCME
        - 'released': when the position  DOCME
        - 'entered': DOCME
        - 'left': DOCME
        - 'activated': when the button is activated, i.e. clicked with a mouse,
                       ENTER'ed with a keyboard or OK'ed with a remote control.
    """

    __gsignals__ = {
        'entered':  (gobject.SIGNAL_RUN_LAST, gobject.TYPE_BOOLEAN,
                    (gobject.TYPE_FLOAT, gobject.TYPE_FLOAT, gobject.TYPE_FLOAT,
                     gobject.TYPE_UINT)),
        'left':     (gobject.SIGNAL_RUN_LAST, gobject.TYPE_BOOLEAN,
                    (gobject.TYPE_FLOAT, gobject.TYPE_FLOAT, gobject.TYPE_FLOAT,
                     gobject.TYPE_UINT)),
        'activated': (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, ()),
    }


    def __init__(self):
        super(AbstractButton, self).__init__()
        self._pressed = False
        self._entered = False

    def _connect_mouse_events(self, mouse_drawable):
        # drawable used to receive mouse events (hover, clicks, etc.)
        self._mouse_drawable = mouse_drawable

        # connect to drawable's mouse related signals and automatically forward
        # to self
        for signal in ('entered', 'left', 'pressed', 'clicked', 'released'):
            self._mouse_drawable.connect(signal, self._proxy_signal, signal)

    def clean(self):
        super(AbstractButton, self).__init__()
        self._mouse_drawable.disconnect_by_func(self._proxy_signal)
        self._mouse_drawable = None

    def _proxy_signal(self, drawable, *args):
        if self.state == STATE_DISABLED:
            return True
        other_args, signal = args[:-1], args[-1]
        return self.emit(signal, *other_args)

    def handle_input(self, manager, event):
        if event.value == EventValue.KEY_OK:
            self.emit('activated')
            return True

        return super(AbstractButton, self).handle_input(manager, event)

    def do_clicked(self, *args):
        self.emit('activated')
        return True

    # default signal handlers managing internal state changes

    def do_pressed(self, x, y, z, button, time, pressure):
        if self.state == STATE_DISABLED:
            return True

        self._pressed = True
        self.state = STATE_PRESSED
        return True

    def do_released(self, x, y, z, button, time):
        if self.state == STATE_DISABLED:
            return True

        self._pressed = False

        if self._entered:
            self.state = STATE_SELECTED
        else:
            self.state = STATE_NORMAL

        return True

    def do_entered(self, x, y, z, time):
        if self.state == STATE_DISABLED:
            return True

        self._entered = True

        if self._pressed:
            self.state = STATE_PRESSED
        else:
            self.state = STATE_SELECTED

        return True

    def do_left(self, x, y, z, time):
        if self.state == STATE_DISABLED:
            return True

        self._entered = False
        self.state = STATE_NORMAL
        return True

class Button(AbstractButton):
    """
    The Button widget, is perhaps the most commonly used widget in any GUI.

    Click a button to command the computer to perform some action, or to answer
    a question. Typical buttons are OK, Apply, Cancel, Close, Yes, No and Help.

    A button is rectangular and typically displays a text label describing its
    action.

    Buttons display a textual label, and optionally a small icon.

    A push button emits the signal 'activated' when it is activated by the mouse,
    the keyboard or calling its 'activate()' method. Connect to this signal to
    perform the button's action.

    @ivar text:      DOCME
    @type text:      DOCME
    @ivar icon:       DOCME
    @type icon:       DOCME
    @ivar background:       DOCME
    @type background:       DOCME
    """

    def __init__(self):
        super(Button, self).__init__()
        self._create_widgets()
        self.update_style_properties(self.style.get_items())

    def clean(self):
        self._icon = None
        self._text = None
        return super(Button, self).clean()

    def _create_widgets(self):
        self.background = self._create_background()
        self._connect_mouse_events(self.background)

    def _create_icon(self):
        icon = Image()
        icon.bg_a = 0
        self.add(icon, forward_signals=False)
        icon.visible = True
        return icon

    def _create_text(self):
        text = Text()
        text.bg_a = 0
        self.add(text, forward_signals=False)
        text.visible = True
        return text

    def _create_background(self):
        background = Image()
        background.bg_a = 0
        self.add(background, forward_signals=False)
        background.visible = True
        return background

    def icon__get(self):
        try:
            return self._icon
        except AttributeError:
            self._icon = self._create_icon()
            return self._icon

    icon = property(fget=icon__get)

    def text__get(self):
        try:
            return self._text
        except AttributeError:
            self._text = self._create_text()
            return self._text

    text = property(fget=text__get)


    @classmethod
    def _demo_widget(cls, *args, **kwargs):
        from pkg_resources import resource_filename
        import pgm

        widget = cls()
        widget.set_name("test_button")
        widget.size = (150.0, 40.0)
        glyph = resource_filename('elisa.plugins.pigment.widgets',
                                  'data/star.png')

        def on_pressed(widget, *args):
            print "Pressed", args

        def on_released(widget, *args):
            print "Released", args

        def on_clicked(widget, *args):
            print "Clicked", args

        def on_entered(widget, *args):
            print "Entered", args

        def on_left(widget, *args):
            print "Left", args

        def on_activate(widget):
            print 'Activated'

        widget.connect("pressed", on_pressed)
        widget.connect("released", on_released)
        widget.connect("clicked", on_clicked)
        widget.connect("entered", on_entered)
        widget.connect("left", on_left)
        widget.connect('activated', on_activate)

        print "Press the 'g' key to load a glyph"
        print "Press the 'd' key to enable/disable the button"
        def key_press_event_cb(self, viewport, event, grid):
            if event.keyval == pgm.keysyms.g:
                widget.icon.set_from_file(glyph)
            elif event.keyval == pgm.keysyms.d:
                if widget.state != STATE_DISABLED:
                    widget.state = STATE_DISABLED
                else:
                    widget.state = STATE_NORMAL

        widget.connect('key-press-event', key_press_event_cb)
        return widget


if __name__ == '__main__':
    import pgm
    # absolute import required in order to make styling work
    from elisa.plugins.pigment.widgets.button import Button

    button = Button.demo()
    try:
        __IPYTHON__
    except NameError:
        pgm.main()
