# GNU Solfege - free ear training software # Copyright (C) 2000, 2001, 2002, 2003, 2004, 2007 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., 51 Franklin ST, Fifth Floor, Boston, MA 02110-1301 USA import gtk import gobject import gu import const import cfg class IntervalCheckBox(gtk.HBox): """ Emit 'value-changed' if the state of an interval has changed. """ max_interval = 16 # Major decim def __init__(self): gtk.HBox.__init__(self) self.checkbox_dict = {} for x in range(1, self.max_interval): self.checkbox_dict[x] = c \ = gtk.ToggleButton(const.short_interval_name[x]) c.set_data('interval', x) c.connect('toggled', self.on_toggle) c.show() self.pack_start(c) def on_toggle(self, _o): self.emit('value-changed', self.get_value()) def get_value(self): """ Return a list with the integer value for the intervals that are active. """ return [x for x in self.checkbox_dict.keys() \ if self.checkbox_dict[x].get_active()] def set_value(self, v): """ Set the state of the intervals. v is a list of integers representing the intervals that are active. """ for key, btn in self.checkbox_dict.items(): self.checkbox_dict[key].set_active(key in v) return class nIntervalCheckBox(IntervalCheckBox, cfg.ConfigUtils): def __init__(self, exname, varname): IntervalCheckBox.__init__(self) cfg.ConfigUtils.__init__(self, exname) self.m_varname = varname intervals = self.get_list(self.m_varname) if not intervals: intervals = range(1, 17) self.set_list(varname, intervals) self.set_value(intervals) self.add_watch(self.m_varname, self._watch_cb) def _watch_cb(self, name): self.set_value(self.get_list(self.m_varname)) def on_toggle(self, _o): IntervalCheckBox.on_toggle(self, _o) self.set_list(self.m_varname, self.get_value()) class MultipleIntervalConfigWidget(gtk.VBox, cfg.ConfigUtils): """ This class gives you some spin buttons and two rows of buttons where you select what intervals to use for exercises where you select one or more intervals. """ def __init__(self, exname): gtk.VBox.__init__(self) cfg.ConfigUtils.__init__(self, exname) self.MAX_INT = self.get_int('maximum_number_of_intervals') if self.MAX_INT == 0: self.MAX_INT = 10 self._watched_interval_id = None self._watched_interval = None self.m_ignore_iclick = 0 box = gu.bHBox(self, expand=False) box.set_spacing(gu.PAD_SMALL) box.pack_start(gtk.Label(_("Number of intervals:")), False) self.g_num_int_spin = gu.nSpinButton(self.m_exname, 'number_of_intervals', gtk.Adjustment(1, 1, self.MAX_INT, 1, 10)) self.add_watch('number_of_intervals', self.on_num_int_spin) box.pack_start(self.g_num_int_spin, False) self.g_all_int_button = gu.bButton(box, _("Configure all intervals in this exercise like this"), self.configure_all_like_active_interval, expand=False) self.add_watch('number_of_intervals', lambda n, self=self: \ self.g_all_int_button.set_sensitive(self.get_int(n)!=1)) box = gu.bHBox(self, expand=False) box.set_spacing(gu.PAD_SMALL) box.pack_start(gtk.Label( _("Togglebuttons are for interval number:")), False) self.m_int_sel_adjustment \ = gtk.Adjustment(1, 1, self.get_int('number_of_intervals'), 1) self.g_int_sel_spin = gu.nSpinButton(self.m_exname, 'cur_edit_interval', self.m_int_sel_adjustment, digits=0) self.g_int_sel_spin.connect('changed', self.on_int_sel_spin) box.pack_start(self.g_int_sel_spin, False) table = gtk.Table() self.pack_start(table, False) label = gtk.Label(_("Up:")) label.set_alignment(1.0, 0.5) table.attach(label, 0, 1, 0, 1, xpadding=gu.PAD_SMALL) self.g_interval_chk = {} V = self.get_list("ask_for_intervals_%i" % (self.g_int_sel_spin.get_value_as_int()-1)) for x in range(1, 17): self.g_interval_chk[x] = c = gtk.ToggleButton(const.short_interval_name[x]) c.set_data('interval', x) if x in V: c.set_active(True) c.show() c.connect('clicked', self.on_interval_chk_clicked) table.attach(c, x, x+1, 0, 1) box = gu.bHBox(self, expand=False) label = gtk.Label(_("Down:")) label.set_alignment(1.0, 0.5) table.attach(label, 0, 1, 1, 2, xpadding=gu.PAD_SMALL) v = range(-16, 0) v.reverse() for x in v: self.g_interval_chk[x] = c = gtk.ToggleButton(const.short_interval_name[-x]) c.set_data('interval', x) if x in V: c.set_active(True) c.show() c.connect('clicked', self.on_interval_chk_clicked) table.attach(c, -x, -x+1, 1, 2) table.show_all() if self.g_num_int_spin.get_value_as_int() == 1: self.g_all_int_button.set_sensitive(False) gu.bButton(self, _("Reset to default values"), self.reset_to_default, False, False) self._watch_interval(self.get_int('cur_edit_interval')-1) def reset_to_default(self, _o): self.set_int('cur_edit_interval', 1) self.set_int('number_of_intervals', 1) self.set_list('ask_for_intervals_0', range(-12, 0)+range(1, 13)) def configure_all_like_active_interval(self, _o): v = self.get_list('ask_for_intervals_%i' \ % (self.g_int_sel_spin.get_value_as_int()-1)) for i in range(self.get_int('number_of_intervals')): self.set_string('ask_for_intervals_%i' % i, str(v)) def on_interval_chk_clicked(self, _o): if self.m_ignore_iclick: return i = self.g_int_sel_spin.get_value_as_int() - 1 v = self.get_list('ask_for_intervals_%i' % i) if _o.get_active(): if not _o.get_data('interval') in v: v.append(_o.get_data('interval')) else: if _o.get_data('interval') in v: del v[v.index(_o.get_data('interval'))] self.set_list('ask_for_intervals_%i' % i, v) def on_num_int_spin(self, _o): adj = gtk.Adjustment(self.get_int('cur_edit_interval'), 1, self.get_int('number_of_intervals'), 1, 10, 10) self.g_int_sel_spin.set_adjustment(adj) self.g_int_sel_spin.update() def on_int_sel_spin(self, spin): self._watch_interval(spin.get_value_as_int()-1) self.update_togglebuttons(spin.get_value_as_int()-1) def update_togglebuttons(self, i): self.m_ignore_iclick = 1 v = self.get_list('ask_for_intervals_%i' % i) for i in range(-16, 0)+range(1, 17): self.g_interval_chk[i].set_active(i in v) self.m_ignore_iclick = 0 def _watch_interval(self, i): """ Add a watch for the correct ask_for_intervals_%i variable. Remove old watches. Do nothing if we are already watching the correct data. """ if self._watched_interval == i: return if self._watched_interval is not None: self.remove_watch('ask_for_intervals_%i' % self._watched_interval, self._watched_interval_id) self._watched_interval = i self._watched_interval_id = self.add_watch('ask_for_intervals_%i' % i, self._interval_watch_cb) def _interval_watch_cb(self, name): self.update_togglebuttons(self._watched_interval)