1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
|
# GNU Solfege - free ear training software
# Copyright (C) 2000, 2001, 2002, 2003, 2004, 2007, 2008 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 3 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, see <http://www.gnu.org/licenses/>.
import sys
import gtk
import cfg
import gu
class AbstractQuestionNameTable(gtk.Table, cfg.ConfigUtils):
"""
Base class for QuestionNameButtonTable and QuestionNameCheckButtonTable.
"""
def __init__(self, exname):
gtk.Table.__init__(self)
cfg.ConfigUtils.__init__(self, exname)
self._ignore_watch = 0
self.add_watch('ask_for_names', self.ask_for_names_changed)
def ask_for_names_changed(self):
pass
def initialize(self, num, dir):
self.m_num = num
self.m_dir = dir
self.m_x = 0
self.m_y = 0
for X in self.get_children():
X.destroy()
self.m_button_dict = {}
self.m_name_list = []
def conditional_newline(self):
"""
Do newline if there are enough buttons on the line.
"""
if self.m_dir == 'vertic':
self.m_y = self.m_y + 1
if self.m_y == self.m_num:
self.m_y = 0
self.m_x = self.m_x + 1
else:
self.m_x = self.m_x + 1
if self.m_x == self.m_num:
self.m_x = 0
self.m_y = self.m_y + 1
def newline(self):
if self.m_dir == 'vertic':
self.m_y = 0
self.m_x = self.m_x + 1
else:
self.m_x = 0
self.m_y = self.m_y + 1
def grab_focus_first_button(self):
v = self.get_children()
v.reverse()
for c in v:
if c.get_property("sensitive"):
c.grab_focus()
return
class QuestionNameButtonTable(AbstractQuestionNameTable):
def __init__(self, exname):
AbstractQuestionNameTable.__init__(self, exname)
def ask_for_names_changed(self, *v):
"""
This method is called when the config variable 'ask_for_names' is
changed. The watching of the method is set up in
AbstractQuestionNameTable.__init__
"""
if self._ignore_watch > 0:
return
for n, button in self.m_button_dict.items():
button.set_sensitive(
self.m_name_list.index(n) in self.get_list('ask_for_names'))
def add(self, question, style, callback):
"""add a button and set up callback function.
there should not be created more than one button with the same
(c locale) name.
return the button created.
"""
if 'newline' in question and question.newline:
self.newline()
b = gtk.Button()
if question.name.cval in self.m_button_dict:
print >> sys.stderr, "Warning: The lessonfile contain several questions with the same name:", question.name.cval
print >> sys.stderr, " This is a bug in the lesson file."
self.m_button_dict[question.name.cval] = b
self.m_name_list.append(question.name.cval)
b.set_data('cname', question.name.cval)
b.set_sensitive(question.active)
if style == 'progression':
b.add(gu.HarmonicProgressionLabel(question.name, 'center'))
else:
b.add(gtk.Label(question.name))
b.show_all()
self.attach(b, self.m_x, self.m_x+1, self.m_y, self.m_y+1)
b.connect('clicked', callback)
b.connect('button_release_event', callback)
self.conditional_newline()
return b
class QuestionNameCheckButtonTable(AbstractQuestionNameTable):
def __init__(self, teacher):
AbstractQuestionNameTable.__init__(self, teacher.m_exname)
self.m_t = teacher
def ask_for_names_changed(self, *v):
self.m_t.m_P.m_random.reset()
if not self.m_name_list:
# If m_name_list is empty, it means that no lesson file is
# yet loaded. Just return.
return
if self._ignore_watch > 0:
return
for question in self.m_t.m_P.m_questions:
question.active = self.m_name_list.index(question.name.cval) in self.get_list('ask_for_names')
def add(self, question, labelformat):
"""add a button and set up callback function.
there should not be created more than one button with the same
(c locale) name.
return the button created.
"""
if 'newline' in question and question.newline:
self.newline()
b = gtk.CheckButton()
if question.name.cval in self.m_button_dict:
print >> sys.stderr, "Warning: The lessonfile contain several questions with the same name:", question.name.cval
print >> sys.stderr, " Things will not work as normal after this."
self.m_button_dict[question.name.cval] = b
self.m_name_list.append(question.name.cval)
b.set_active(question.active)
b.connect('toggled', self.on_checkbutton_toggled)
b.set_data('cname', question.name.cval)
if labelformat == 'progression':
b.add(gu.HarmonicProgressionLabel(question.name, 'center'))
elif labelformat == 'normal':
b.add(gtk.Label(question.name))
else:
print >> sys.stderr, "labelformat=%s is not valid" % labelformat
b.show_all()
self.attach(b, self.m_x, self.m_x+1, self.m_y, self.m_y+1)
self.conditional_newline()
return b
def on_checkbutton_toggled(self, button):
"""
Set the content of the 'ask_for_names' config variable based on
the active status of the check buttons.
"""
v= []
for i in range(len(self.m_name_list)):
if self.m_button_dict[self.m_name_list[i]].get_active():
v.append(i)
self.set_list('ask_for_names', v)
def select_all(self):
for button in self.m_button_dict.values():
button.set_active(True)
class RandomTransposeDialog(gtk.Dialog):
def __init__(self, initial_value, parent):
gtk.Dialog.__init__(self, _("Set transposition"), parent, 0,
(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL,
gtk.STOCK_OK, gtk.RESPONSE_OK,
))
dlg_vbox = gu.hig_dlg_vbox()
self.vbox.pack_start(dlg_vbox)
xbox, vbox = gu.hig_category_vbox(_("Select how to do random transposition"))
dlg_vbox.pack_start(xbox)
label = gtk.Label(_("""You can read about the different types of transposition in the lesson file documentation available on the Help menu."""))
label.set_line_wrap(True)
vbox.pack_start(label)
sizegroup = gtk.SizeGroup(gtk.SIZE_GROUP_HORIZONTAL)
self.m_buttons = {}
self.m_spins = {}
self.m_buttons['no'] = b1 = gtk.RadioButton(None, _("No"))
self.m_spins['no'] = []
vbox.pack_start(b1)
self.m_buttons['yes'] = b2 = gtk.RadioButton(b1, _("Yes"))
self.m_spins['yes'] = []
vbox.pack_start(b2)
self.m_buttons['accidentals'] = gtk.RadioButton(b1, "accidentals")
hbox = gu.bHBox(vbox)
hbox.pack_start(self.m_buttons['accidentals'])
self.m_spins['accidentals'] = [
gtk.SpinButton(gtk.Adjustment(0, -7, 7, 1, 1, 1), 0.0, 0),
gtk.SpinButton(gtk.Adjustment(0, -7, 7, 1, 1, 1), 0.0, 0)]
hbox.pack_start(self.m_spins['accidentals'][0])
hbox.pack_start(self.m_spins['accidentals'][1])
gu.SpinButtonRangeController(self.m_spins['accidentals'][0],
self.m_spins['accidentals'][1],
-7, 7)
self.m_buttons['key'] = gtk.RadioButton(b1, "key")
hbox = gu.bHBox(vbox)
hbox.pack_start(self.m_buttons['key'])
self.m_spins['key'] = [
gtk.SpinButton(gtk.Adjustment(0, -10, 10, 1, 1, 1), 0.0, 0),
gtk.SpinButton(gtk.Adjustment(0, -10, 10, 1, 1, 1), 0.0, 0)]
hbox.pack_start(self.m_spins['key'][0])
hbox.pack_start(self.m_spins['key'][1])
gu.SpinButtonRangeController(self.m_spins['key'][0],
self.m_spins['key'][1],
-10, 10)
self.m_buttons['semitones'] = gtk.RadioButton(b1, "semitones")
hbox = gu.bHBox(vbox)
hbox.pack_start(self.m_buttons['semitones'])
self.m_spins['semitones'] = [
gtk.SpinButton(gtk.Adjustment(0, -100, 100, 1, 1, 1), 0.0, 0),
gtk.SpinButton(gtk.Adjustment(0, -100, 100, 1, 1, 1), 0.0, 0)]
hbox.pack_start(self.m_spins['semitones'][0])
hbox.pack_start(self.m_spins['semitones'][1])
gu.SpinButtonRangeController(self.m_spins['semitones'][0],
self.m_spins['semitones'][1],
-100, 100)
for n, w in self.m_buttons.items():
sizegroup.add_widget(w)
for ww in self.m_spins[n]:
ww.set_sensitive(False)
w.connect('clicked', self.on_spins_clicked, n)
if initial_value == False:
k = 'no'
elif initial_value == True:
k = 'yes'
else:
k = initial_value[0]
self.m_buttons[k].set_active(True)
if k in ('accidentals', 'key', 'semitones'):
t, v1, v2 = initial_value
# FIXME Because of the RangeController, we have to do this
# twice to be sure both values are set properly.
self.m_spins[t][1].set_value(v2)
self.m_spins[t][0].set_value(v1)
self.m_spins[t][1].set_value(v2)
self.m_spins[t][0].set_value(v1)
self.show_all()
def on_spins_clicked(self, w, n):
for w in self.m_spins[n]:
w.set_sensitive(self.m_buttons[n].get_active())
def get_value(self):
for n, btn in self.m_buttons.items():
if btn.get_active():
s = n
if s == 'yes':
return True
elif s == 'no':
return False
return [s, self.m_spins[s][0].get_value_as_int(), self.m_spins[s][1].get_value_as_int()]
|