# -*- 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>
#

from elisa.plugins.pigment.graph.image import Image
from elisa.plugins.pigment.widgets.const import *
from elisa.plugins.pigment.widgets.widget import Widget
from elisa.plugins.pigment.widgets.theme import Theme

import pgm


class Button(Widget):
    """
    3 states button widget starring a background and an overlaid glyph.
    A different couple (background, glyph) is displayed for each state among:

     - STATE_NORMAL
     - STATE_SELECTED
     - STATE_PRESSED

    Button is by default in STATE_NORMAL. When hovering it it goes to
    STATE_SELECTED. When pressed it then goes to STATE_PRESSED.

    @ivar sticky: if True the button will stay in STATE_SELECTED state after the
                  mouse stopped hovering it, otherwise it will go to STATE_NORMAL
    @type sticky: bool
    @ivar alignment: alignement of the background images
    @type alignment: L{pgm.IMAGE_ALIGNMENT}
    """

    def __init__(self):
        # the widget is not ready yet to react on external events
        self._initialized = False

        super(Button, self).__init__()

        # invisible drawable used to receive mouse clicks
        self._mouse_area = Image()
        self.add(self._mouse_area)
        self._mouse_area.bg_color = (0, 0, 0, 0)
        self._mouse_area.position = (0.0, 0.0, 0.0)
        self._mouse_area.size = (1.0, 1.0)
        self._mouse_area.visible = True

        # connect to mouse relevant mouse signals
        self._mouse_signal_ids = []
        id = self._mouse_area.connect('entered', self._entered)
        self._mouse_signal_ids.append(id)
        id = self._mouse_area.connect('left', self._left)
        self._mouse_signal_ids.append(id)

        # alignment of the background images
        self._alignment = pgm.IMAGE_CENTER

        # dictionary of background images
        # key:   state
        # value: Image drawable
        self._backgrounds = {}
        self._add_background(STATE_NORMAL)
        self._add_background(STATE_SELECTED)
        self._add_background(STATE_PRESSED)

        # dictionary of glyph images
        # key:   state
        # value: Image drawable
        self._glyphs = {}
        self._add_glyph(STATE_NORMAL)
        self._add_glyph(STATE_SELECTED)
        self._add_glyph(STATE_PRESSED)

        # sticky mode: the button will stay selected when the mouse stops
        # hovering it
        self.sticky = False

        # the widget is ready to react on external events
        self._initialized = True

        # force a state update now that _backgrounds and _glyphs are ready
        self.do_state_changed(STATE_NORMAL)

    def clean(self):
        super(Button, self).clean()
        for id in self._mouse_signal_ids:
            self._mouse_area.disconnect(id)

    def _set_alignment(self, value):
        for background in self._backgrounds.values():
            background.alignment = value
        for glyph in self._glyphs.values():
            glyph.alignment = value
        self._alignment = value

    def _get_alignment(self):
        return self._alignment

    alignment = property(_get_alignment, _set_alignment)

    def _add_background(self, state):
        """
        Add a background Image drawable for L{state}.
        """
        image = Image()
        image.bg_a = 0
        self.add(image, forward_signals=False)
        image.position = (0.0, 0.0, 0.0)
        image.size = (1.0, 1.0)
        image.alignment = self._alignment
        self._backgrounds[state] = image

    def _add_glyph(self, state):
        """
        Add a glyph Image drawable for L{state}.
        """
        image = Image()
        image.bg_a = 0
        self.add(image, forward_signals=False)
        image.position = (0.0, 0.0, 0.0)
        image.size = (1.0, 1.0)
        image.alignment = self._alignment
        self._glyphs[state] = image

    def set_glyphs(self, normal, selected, active):
        """
        Load the resources L{normal}, L{selected} and L{active} into their
        corresponding glyph drawables.

        @param normal:   image resource to be used for STATE_NORMAL state
        @type normal:    str
        @param selected: image resource to be used for STATE_SELECTED state
        @type selected:  str
        @param active:   image resource to be used for STATE_PRESSED state
        @type active:    str
        """
        theme = Theme.get_default()

        normal_path = theme.get_resource(normal)
        self._glyphs[STATE_NORMAL].set_from_file(normal_path)

        selected_path = theme.get_resource(selected)
        self._glyphs[STATE_SELECTED].set_from_file(selected_path)

        active_path = theme.get_resource(active)
        self._glyphs[STATE_PRESSED].set_from_file(active_path)

    def set_backgrounds(self, normal, selected, active):
        """
        Load the resources L{normal}, L{selected} and L{active} into their
        corresponding background drawables.

        @param normal:   image resource to be used for STATE_NORMAL state
        @type normal:    str
        @param selected: image resource to be used for STATE_SELECTED state
        @type selected:  str
        @param active:   image resource to be used for STATE_PRESSED state
        @type active:    str
        """
        theme = Theme.get_default()

        normal_path = theme.get_resource(normal)
        self._backgrounds[STATE_NORMAL].set_from_file(normal_path)

        selected_path = theme.get_resource(selected)
        self._backgrounds[STATE_SELECTED].set_from_file(selected_path)

        active_path = theme.get_resource(active)
        self._backgrounds[STATE_PRESSED].set_from_file(active_path)

    def do_state_changed(self, previous_state):
        # the state is changed once before the widget is fully initialised
        if not self._initialized:
            return

        # hide drawables corresponding to previous state
        if previous_state != None:
            self._glyphs[previous_state].visible = False
            self._backgrounds[previous_state].visible = False

        # show drawables corresponding to new state
        self._glyphs[self.state].visible = True
        self._backgrounds[self.state].visible = True

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

    def do_clicked(self, x, y, z, button, time, pressure):
        return True

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

    def _entered(self, mouse_area, x, y, z, time):
        self.state = STATE_SELECTED
        return True

    def _left(self, mouse_area, x, y, z, time):
        if not self.sticky:
            self.state = STATE_NORMAL
        return True

    @classmethod
    def _demo_widget(cls, *args, **kwargs):
        theme = Theme.load_from_module("elisa.plugins.poblesec")
        Theme.set_default(theme)

        widget = cls()
        widget.set_glyphs("elisa.plugins.poblesec.player.glyphs.play_normal",
                          "elisa.plugins.poblesec.player.glyphs.play_selected",
                          "elisa.plugins.poblesec.player.glyphs.play_active")
        widget.set_backgrounds(
              "elisa.plugins.poblesec.player.ribbon.button_background_normal",
              "elisa.plugins.poblesec.player.ribbon.button_background_selected",
              "elisa.plugins.poblesec.player.ribbon.button_background_active")

        widget.size = (0.4, 0.4)
        widget.visible = True
        return widget


if __name__ == '__main__':
    import logging
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)

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