# GNU Solfege - eartraining for GNOME
# Copyright (C) 2000, 2001, 2002  Tom Cato Amundsen
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

import gtk, gnome
import GDK
import mpd, gu, cfg
import types
from i18n import _

class SimplestNotenameSpinButton(gtk.GtkHBox):
    """
    The simplest notename spin button. The widget don't have any
    limits to what values are allowed. It won't change its own value,
    but call the callback function with the requested new value as value.

    This class is not usable on it's own, it has to be subclassed or
    used with NotenameSpinButtonController.
    """
    def __init__(self, value):
        assert type(value) == types.StringType
        gtk.GtkHBox.__init__(self)
        self.g_entry = gtk.GtkEntry()
        self.g_entry.set_text(value)
        self.pack_start(self.g_entry, gtk.FALSE, gtk.FALSE)
        self.g_entry.set_usize(40, -1)
        self.g_entry.set_editable(gtk.FALSE)

        box = gtk.GtkVBox()
        self.pack_start(box, gtk.FALSE, gtk.FALSE)
        eb = gtk.GtkEventBox()
        eb.connect('button_press_event', self.on_arrowclick, 1)
        self.g_up = gtk.GtkArrow(gtk.ARROW_UP, gtk.SHADOW_OUT)
        eb.add(self.g_up)
        box.pack_start(eb)
        eb = gtk.GtkEventBox()
        eb.connect('button_press_event', self.on_arrowclick, -1)
        self.g_down = gtk.GtkArrow(gtk.ARROW_DOWN, gtk.SHADOW_OUT)
        eb.add(self.g_down)
        box.pack_start(eb)
        self.g_entry.connect('event', self.on_entry_event)
    def connect_request_change(self, callback):
        self.m_callback = callback
    def on_entry_event(self, entry, event):
        if event.type == GDK.KEY_PRESS:
            if event.keyval == GDK.Page_Up:
                self.change_value(12)
                return 1
            elif event.keyval == GDK.Page_Down:
                self.change_value(-12)
                return 1
            elif event.keyval == GDK.Up:
                self.change_value(1)
                return 1
            elif event.keyval == GDK.Down:
                self.change_value(-1)
                return 1
    def on_arrowclick(self, _o, event, v):
        if event.type == GDK.BUTTON_PRESS:
            assert v in (-1, 1)
            if event.button == 1:
                self.change_value(v)
            elif event.button == 3: # right button
                self.change_value(v*12)
            elif event.button == 2: # middle button
                if v == 1:
                    self.change_value(1000)
                else:
                    self.change_value(-1000)
    def get_value(self):
        return self.g_entry.get_text()
    def change_value(self, v):
        self.m_callback(self, mpd.int_to_notename(mpd.notename_to_int(self.get_value()) + v))
    def set_value(self, n):
        assert type(n) == types.StringType
        # only change the entry if the value has actually changed, to
        # avoid unnecessary 'changed' signals emitted.
        if self.g_entry.get_text() != n:
            self.g_entry.set_text(n)

class NotenameRangeController:
    def __init__(self, spin_low, spin_high, lowest_value, highest_value):
        self.g_spin_low = spin_low
        self.g_spin_low.connect_request_change(self.on_low_changed)
        self.g_spin_high = spin_high
        self.g_spin_high.connect_request_change(self.on_high_changed)
        self.m_lowest_value = lowest_value
        self.m_highest_value = highest_value
    def on_low_changed(self, widget, value):
        """
        value: the new notename STRING
        """
        if mpd.compare_notenames(value, self.g_spin_high.get_value()) > 0:
            self.g_spin_low.set_value(self.g_spin_high.get_value())
        elif mpd.compare_notenames(value, self.m_lowest_value) < 0:
            self.g_spin_low.set_value(self.m_lowest_value)
        else:
            self.g_spin_low.set_value(value)
    def on_high_changed(self, widget, value):
        if mpd.compare_notenames(value, self.g_spin_low.get_value()) < 0:
            self.g_spin_high.set_value(self.g_spin_low.get_value())
        elif mpd.compare_notenames(value, self.m_highest_value) > 0:
            self.g_spin_high.set_value(self.m_highest_value)
        else:
            self.g_spin_high.set_value(value)

class nNotenameRangeController(NotenameRangeController, cfg.ConfigUtils):
    def __init__(self, spin_low, spin_high, lowest_value, highest_value,
                 exname, name_low, name_high):
        NotenameRangeController.__init__(self, spin_low, spin_high,
                lowest_value, highest_value)
        cfg.ConfigUtils.__init__(self, exname)
        self.m_name_low = name_low
        self.m_name_high = name_high
        #self.g_spin_low.set_value(self.get_string(self.m_name_low))
        #self.g_spin_high.set_value(self.get_string(self.m_name_high))
    def set_range(self, lowest_value, highest_value):
        """
        make a separate function for NotenameRangeController if we need it.
        """
        assert mpd.compare_notenames(lowest_value, highest_value) <= 0
        self.m_lowest_value = lowest_value
        self.m_highest_value = highest_value
        if mpd.compare_notenames(lowest_value, self.g_spin_low.get_value()) > 0:
            self.set_string(self.m_name_low, lowest_value)
            self.g_spin_low.set_value(lowest_value)
        if mpd.compare_notenames(highest_value,
                                 self.g_spin_high.get_value()) < 0:
            self.set_string(self.m_name_high, highest_value)
            self.g_spin_high.set_value(highest_value)
