the OMG-make-radio-buttons-and-actions-work-properly commit for the step editor
[ardour.git] / gtk2_ardour / step_entry.cc
1 /*
2     Copyright (C) 2010 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <iostream>
21
22 #include "pbd/filesystem.h"
23 #include "pbd/file_utils.h"
24
25 #include "gtkmm2ext/keyboard.h"
26 #include "gtkmm2ext/actions.h"
27 #include "gtkmm2ext/bindings.h"
28
29 #include "ardour/filesystem_paths.h"
30
31 #include "ardour_ui.h"
32 #include "midi_channel_selector.h"
33 #include "midi_time_axis.h"
34 #include "step_entry.h"
35 #include "utils.h"
36
37 #include "i18n.h"
38
39 using namespace std;
40 using namespace Gtk;
41 using namespace Glib;
42 using namespace Gtkmm2ext;
43 using namespace PBD;
44 using namespace ARDOUR;
45
46 static void
47 _note_off_event_handler (GtkWidget* widget, int note, gpointer arg)
48 {
49         ((StepEntry*)arg)->note_off_event_handler (note);
50 }
51
52 static void
53 _rest_event_handler (GtkWidget* widget, gpointer arg)
54 {
55         ((StepEntry*)arg)->rest_event_handler ();
56 }
57
58 StepEntry::StepEntry (MidiTimeAxisView& mtv)
59         : ArdourDialog (string_compose (_("Step Entry: %1"), mtv.name()))
60         , _current_note_length (1.0)
61         , _current_note_velocity (64)
62         , triplet_button ("3")
63         , beat_resync_button (_(">beat"))
64         , bar_resync_button (_(">bar"))
65         , sustain_button (_("sustain"))
66         , rest_button (_("rest"))
67         , grid_rest_button (_("g-rest"))
68         , channel_adjustment (1, 1, 16, 1, 4) 
69         , channel_spinner (channel_adjustment)
70         , octave_adjustment (0, 1, 11, 1, 4)
71         , octave_spinner (octave_adjustment)
72         , length_divisor_adjustment (1.0, 1.0, 128, 1.0, 4.0)
73         , length_divisor_spinner (length_divisor_adjustment)
74         , velocity_adjustment (64.0, 0.0, 127.0, 1.0, 4.0)
75         , velocity_spinner (velocity_adjustment)
76         , _piano (0)
77         , piano (0)
78         , _mtv (&mtv)
79 {
80         register_actions ();
81         load_bindings ();
82
83         /* set channel selector to first selected channel. if none
84            are selected, it will remain at the value set in its
85            constructor, above (1)
86         */
87
88         uint16_t chn_mask = _mtv->channel_selector().get_selected_channels();
89         
90         for (uint32_t i = 0; i < 16; ++i) {
91                 if (chn_mask & (1<<i)) {
92                         channel_adjustment.set_value (i+1);
93                         break;
94                 }
95         }
96
97         RadioButtonGroup length_group = length_1_button.get_group();
98         length_2_button.set_group (length_group);
99         length_4_button.set_group (length_group);
100         length_8_button.set_group (length_group);
101         length_12_button.set_group (length_group);
102         length_16_button.set_group (length_group);
103         length_32_button.set_group (length_group);
104         length_64_button.set_group (length_group);
105
106         Widget* w;
107
108         w = manage (new Image (::get_icon (X_("wholenote"))));
109         w->show();
110         length_1_button.add (*w);
111         w = manage (new Image (::get_icon (X_("halfnote"))));
112         w->show();
113         length_2_button.add (*w);
114         w = manage (new Image (::get_icon (X_("quarternote"))));
115         w->show();
116         length_4_button.add (*w);
117         w = manage (new Image (::get_icon (X_("eighthnote"))));
118         w->show();
119         length_8_button.add (*w);
120         w = manage (new Image (::get_icon (X_("sixteenthnote"))));
121         w->show();
122         length_16_button.add (*w);
123         w = manage (new Image (::get_icon (X_("thirtysecondnote"))));
124         w->show();
125         length_32_button.add (*w);
126         w = manage (new Image (::get_icon (X_("sixtyfourthnote"))));
127         w->show();
128         length_64_button.add (*w);
129
130         RefPtr<Action> act;
131
132         act = myactions.find_action ("StepEditing/note-length-whole");
133         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_1_button.gobj()), act->gobj());
134         act = myactions.find_action ("StepEditing/note-length-half");
135         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_2_button.gobj()), act->gobj());
136         act = myactions.find_action ("StepEditing/note-length-quarter");
137         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_4_button.gobj()), act->gobj());
138         act = myactions.find_action ("StepEditing/note-length-eighth");
139         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_8_button.gobj()), act->gobj());
140         act = myactions.find_action ("StepEditing/note-length-sixteenth");
141         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_16_button.gobj()), act->gobj());
142         act = myactions.find_action ("StepEditing/note-length-thirtysecond");
143         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_32_button.gobj()), act->gobj());
144         act = myactions.find_action ("StepEditing/note-length-sixtyfourth");
145         gtk_activatable_set_related_action (GTK_ACTIVATABLE (length_64_button.gobj()), act->gobj());
146
147         length_1_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
148         length_1_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 1), false);
149         length_2_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
150         length_2_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 2), false);
151         length_4_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
152         length_4_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 4), false);
153         length_8_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
154         length_8_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 8), false);
155         length_16_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
156         length_16_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 16), false);
157         length_32_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
158         length_32_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 32), false);
159         length_64_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
160         length_64_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &length_1_button, 64), false);
161
162         length_1_button.property_draw_indicator() = false;
163         length_2_button.property_draw_indicator() = false;
164         length_4_button.property_draw_indicator() = false;
165         length_8_button.property_draw_indicator() = false;
166         length_16_button.property_draw_indicator() = false;
167         length_32_button.property_draw_indicator() = false;
168         length_64_button.property_draw_indicator() = false;
169
170         note_length_box.pack_start (length_1_button, false, false);
171         note_length_box.pack_start (length_2_button, false, false);
172         note_length_box.pack_start (length_4_button, false, false);
173         note_length_box.pack_start (length_8_button, false, false);
174         note_length_box.pack_start (length_16_button, false, false);
175         note_length_box.pack_start (length_32_button, false, false);
176         note_length_box.pack_start (length_64_button, false, false);
177
178         ARDOUR_UI::instance()->set_tip (&length_1_button, _("Set note length to a whole note"), "");
179         ARDOUR_UI::instance()->set_tip (&length_2_button, _("Set note length to a half note"), "");
180         ARDOUR_UI::instance()->set_tip (&length_4_button, _("Set note length to a quarter note"), "");
181         ARDOUR_UI::instance()->set_tip (&length_8_button, _("Set note length to a eighth note"), "");
182         ARDOUR_UI::instance()->set_tip (&length_16_button, _("Set note length to a sixteenth note"), "");
183         ARDOUR_UI::instance()->set_tip (&length_32_button, _("Set note length to a thirty-second note"), "");
184         ARDOUR_UI::instance()->set_tip (&length_64_button, _("Set note length to a sixty-fourth note"), "");
185
186         RadioButtonGroup velocity_group = velocity_ppp_button.get_group();
187         velocity_pp_button.set_group (velocity_group);
188         velocity_p_button.set_group (velocity_group);
189         velocity_mp_button.set_group (velocity_group);
190         velocity_mf_button.set_group (velocity_group);
191         velocity_f_button.set_group (velocity_group);
192         velocity_ff_button.set_group (velocity_group);
193         velocity_fff_button.set_group (velocity_group);
194
195         w = manage (new Image (::get_icon (X_("pianississimo"))));
196         w->show();
197         velocity_ppp_button.add (*w);
198         w = manage (new Image (::get_icon (X_("pianissimo"))));
199         w->show();
200         velocity_pp_button.add (*w);
201         w = manage (new Image (::get_icon (X_("piano"))));
202         w->show();
203         velocity_p_button.add (*w);
204         w = manage (new Image (::get_icon (X_("mezzopiano"))));
205         w->show();
206         velocity_mp_button.add (*w);
207         w = manage (new Image (::get_icon (X_("mezzoforte"))));
208         w->show();
209         velocity_mf_button.add (*w);
210         w = manage (new Image (::get_icon (X_("forte"))));
211         w->show();
212         velocity_f_button.add (*w);
213         w = manage (new Image (::get_icon (X_("fortissimo"))));
214         w->show();
215         velocity_ff_button.add (*w);
216         w = manage (new Image (::get_icon (X_("fortississimo"))));
217         w->show();
218         velocity_fff_button.add (*w);
219
220         act = myactions.find_action ("StepEditing/note-velocity-ppp");
221         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_ppp_button.gobj()), act->gobj());
222         act = myactions.find_action ("StepEditing/note-velocity-pp");
223         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_pp_button.gobj()), act->gobj());
224         act = myactions.find_action ("StepEditing/note-velocity-p");
225         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_p_button.gobj()), act->gobj());
226         act = myactions.find_action ("StepEditing/note-velocity-mp");
227         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_mp_button.gobj()), act->gobj());
228         act = myactions.find_action ("StepEditing/note-velocity-mf");
229         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_mf_button.gobj()), act->gobj());
230         act = myactions.find_action ("StepEditing/note-velocity-f");
231         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_f_button.gobj()), act->gobj());
232         act = myactions.find_action ("StepEditing/note-velocity-ff");
233         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_ff_button.gobj()), act->gobj());
234         act = myactions.find_action ("StepEditing/note-velocity-fff");
235         gtk_activatable_set_related_action (GTK_ACTIVATABLE (velocity_fff_button.gobj()), act->gobj());
236
237         velocity_ppp_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
238         velocity_ppp_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_ppp_button, 1), false);
239         velocity_pp_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
240         velocity_pp_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_pp_button, 16), false);
241         velocity_p_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
242         velocity_p_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_p_button, 32), false);
243         velocity_mp_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
244         velocity_mp_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_mp_button, 64), false);
245         velocity_mf_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
246         velocity_mf_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_mf_button, 80), false);
247         velocity_f_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
248         velocity_f_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_f_button, 96), false);
249         velocity_ff_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
250         velocity_ff_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_ff_button, 112), false);
251         velocity_fff_button.signal_button_press_event().connect (sigc::mem_fun (*this, &StepEntry::radio_button_press), false);
252         velocity_fff_button.signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &StepEntry::radio_button_release), &velocity_fff_button, 127), false);
253
254         velocity_ppp_button.property_draw_indicator() = false;
255         velocity_pp_button.property_draw_indicator() = false;
256         velocity_p_button.property_draw_indicator() = false;
257         velocity_mp_button.property_draw_indicator() = false;
258         velocity_mf_button.property_draw_indicator() = false;
259         velocity_f_button.property_draw_indicator() = false;
260         velocity_ff_button.property_draw_indicator() = false;
261         velocity_fff_button.property_draw_indicator() = false;
262
263         ARDOUR_UI::instance()->set_tip (&velocity_ppp_button, _("Set volume (velocity) to pianississimo"), "");
264         ARDOUR_UI::instance()->set_tip (&velocity_pp_button, _("Set volume (velocity) to pianissimo"), "");
265         ARDOUR_UI::instance()->set_tip (&velocity_p_button, _("Set volume (velocity) to piano"), "");
266         ARDOUR_UI::instance()->set_tip (&velocity_mp_button, _("Set volume (velocity) to mezzo-piano"), "");
267         ARDOUR_UI::instance()->set_tip (&velocity_mf_button, _("Set volume (velocity) to mezzo-forte"), "");
268         ARDOUR_UI::instance()->set_tip (&velocity_f_button, _("Set volume (velocity) to forte"), "");
269         ARDOUR_UI::instance()->set_tip (&velocity_ff_button, _("Set volume (velocity) to forteissimo"), "");
270         ARDOUR_UI::instance()->set_tip (&velocity_fff_button, _("Set volume (velocity) to forteississimo"), "");
271
272         note_velocity_box.pack_start (velocity_ppp_button, false, false);
273         note_velocity_box.pack_start (velocity_pp_button, false, false);
274         note_velocity_box.pack_start (velocity_p_button, false, false);
275         note_velocity_box.pack_start (velocity_mp_button, false, false);
276         note_velocity_box.pack_start (velocity_mf_button, false, false);
277         note_velocity_box.pack_start (velocity_f_button, false, false);
278         note_velocity_box.pack_start (velocity_ff_button, false, false);
279         note_velocity_box.pack_start (velocity_fff_button, false, false);
280
281         Label* l = manage (new Label);
282         l->set_markup ("<b><big>.</big></b>");
283         l->show ();
284         dot_button.add (*l);
285
286         w = manage (new Image (::get_icon (X_("chord"))));
287         w->show();
288         chord_button.add (*w);
289
290         rest_box.pack_start (rest_button, false, false);
291         rest_box.pack_start (grid_rest_button, false, false);
292
293         resync_box.pack_start (beat_resync_button, false, false);
294         resync_box.pack_start (bar_resync_button, false, false);
295
296         ARDOUR_UI::instance()->set_tip (&chord_button, _("Stack inserted notes to form a chord"), "");
297         ARDOUR_UI::instance()->set_tip (&sustain_button, _("Extend selected notes by note length"), "");
298         ARDOUR_UI::instance()->set_tip (&dot_button, _("Use dotted note lengths"), "");
299         ARDOUR_UI::instance()->set_tip (&rest_button, _("Insert a note-length's rest"), "");
300         ARDOUR_UI::instance()->set_tip (&grid_rest_button, _("Insert a grid-unit's rest"), "");
301         ARDOUR_UI::instance()->set_tip (&beat_resync_button, _("Insert a rest until the next beat"), "");
302         ARDOUR_UI::instance()->set_tip (&bar_resync_button, _("Insert a rest until the next bar"), "");
303
304         upper_box.set_spacing (6);
305         upper_box.pack_start (chord_button, false, false);
306         upper_box.pack_start (note_length_box, false, false, 12);
307         upper_box.pack_start (triplet_button, false, false);
308         upper_box.pack_start (dot_button, false, false);
309         upper_box.pack_start (sustain_button, false, false);
310         upper_box.pack_start (rest_box, false, false);
311         upper_box.pack_start (resync_box, false, false);
312         upper_box.pack_start (note_velocity_box, false, false, 12);
313
314         VBox* v = manage (new VBox);
315         l = manage (new Label (_("Channel")));
316         v->set_spacing (6);
317         v->pack_start (*l, false, false);
318         v->pack_start (channel_spinner, false, false);
319         upper_box.pack_start (*v, false, false);
320
321         upper_box.pack_start (length_divisor_spinner, false, false);
322         upper_box.pack_start (velocity_spinner, false, false);
323         upper_box.pack_start (octave_spinner, false, false);
324
325         velocity_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::velocity_value_change));
326         length_divisor_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::length_value_change));
327
328         _piano = (PianoKeyboard*) piano_keyboard_new ();
329         piano = wrap ((GtkWidget*) _piano);
330
331         piano->set_flags (Gtk::CAN_FOCUS);
332
333         g_signal_connect(G_OBJECT(_piano), "note-off", G_CALLBACK(_note_off_event_handler), this);
334         g_signal_connect(G_OBJECT(_piano), "rest", G_CALLBACK(_rest_event_handler), this);
335         
336         rest_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::rest_click));
337         grid_rest_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::grid_rest_click));
338         chord_button.signal_toggled().connect (sigc::mem_fun (*this, &StepEntry::chord_toggled));
339         triplet_button.signal_toggled().connect (sigc::mem_fun (*this, &StepEntry::triplet_toggled));
340         beat_resync_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::beat_resync_click));
341         bar_resync_button.signal_clicked().connect (sigc::mem_fun (*this, &StepEntry::bar_resync_click));
342
343         length_divisor_adjustment.signal_value_changed().connect (sigc::mem_fun (*this, &StepEntry::length_changed));
344
345         packer.set_spacing (6);
346         packer.pack_start (upper_box, false, false);
347         packer.pack_start (*piano, false, false);
348         packer.show_all ();
349
350         get_vbox()->add (packer);
351 }
352
353 StepEntry::~StepEntry()
354 {
355 }
356
357 void
358 StepEntry::length_changed ()
359 {
360         length_1_button.queue_draw ();
361         length_2_button.queue_draw ();
362         length_4_button.queue_draw ();
363         length_8_button.queue_draw ();
364         length_16_button.queue_draw ();
365         length_32_button.queue_draw ();
366         length_64_button.queue_draw ();
367 }
368
369 bool
370 StepEntry::on_key_press_event (GdkEventKey* ev)
371 {
372         /* focus widget gets first shot, then bindings, otherwise
373            forward to main window
374         */
375         
376         if (!gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
377                 KeyboardKey k (ev->state, ev->keyval);
378
379                 if (bindings.activate (k, KeyboardKey::Press)) {
380                         return true;
381                 }
382         }
383
384         return forward_key_press (ev);
385 }
386
387 bool
388 StepEntry::on_key_release_event (GdkEventKey* ev)
389 {
390         /* focus widget gets first shot, then bindings, otherwise
391            forward to main window
392         */
393
394         if (!gtk_window_propagate_key_event (GTK_WINDOW(gobj()), ev)) {
395                 KeyboardKey k (ev->state, ev->keyval);
396
397                 if (bindings.activate (k, KeyboardKey::Release)) {
398                         return true;
399                 }
400         }
401
402         return forward_key_press (ev);
403 }
404
405 void
406 StepEntry::rest_event_handler ()
407 {
408         _mtv->step_edit_rest (0.0);
409 }
410
411 Evoral::MusicalTime
412 StepEntry::note_length () const
413 {
414         return 1.0 / (Evoral::MusicalTime) length_divisor_adjustment.get_value();
415 }
416
417 uint8_t
418 StepEntry::note_velocity () const
419 {
420         return (Evoral::MusicalTime) velocity_adjustment.get_value();
421 }
422
423 uint8_t 
424 StepEntry::note_channel() const
425 {
426         return channel_adjustment.get_value() - 1;
427 }
428
429 void
430 StepEntry::note_off_event_handler (int note)
431 {
432         insert_note (note);
433 }
434
435 void
436 StepEntry::rest_click ()
437 {
438         insert_rest ();
439 }
440
441 void
442 StepEntry::grid_rest_click ()
443 {
444         insert_grid_rest ();
445 }
446
447 void
448 StepEntry::triplet_toggled ()
449 {
450         if (triplet_button.get_active () != _mtv->step_edit_within_triplet()) {
451                 _mtv->step_edit_toggle_triplet ();
452         }
453 }
454
455 void
456 StepEntry::chord_toggled ()
457 {
458         if (chord_button.get_active() != _mtv->step_edit_within_chord ()) {
459                 _mtv->step_edit_toggle_chord ();
460         }
461 }
462
463 void
464 StepEntry::on_show ()
465 {
466         ArdourDialog::on_show ();
467         piano->grab_focus ();
468 }
469
470 void
471 StepEntry::beat_resync_click ()
472 {
473         _mtv->step_edit_beat_sync ();
474 }
475
476 void
477 StepEntry::bar_resync_click ()
478 {
479         _mtv->step_edit_bar_sync ();
480 }
481
482 void
483 StepEntry::register_actions ()
484 {
485         /* add named actions for the editor */
486
487         myactions.register_action ("StepEditing", "insert-a", _("Insert Note A"), sigc::mem_fun (*this, &StepEntry::insert_a));
488         myactions.register_action ("StepEditing", "insert-bsharp", _("Insert Note A-sharp"), sigc::mem_fun (*this, &StepEntry::insert_asharp));
489         myactions.register_action ("StepEditing", "insert-b", _("Insert Note B"), sigc::mem_fun (*this, &StepEntry::insert_b));
490         myactions.register_action ("StepEditing", "insert-bsharp", _("Insert Note B-sharp"), sigc::mem_fun (*this, &StepEntry::insert_bsharp));
491         myactions.register_action ("StepEditing", "insert-c", _("Insert Note C"), sigc::mem_fun (*this, &StepEntry::insert_c));
492         myactions.register_action ("StepEditing", "insert-csharp", _("Insert Note C-sharp"), sigc::mem_fun (*this, &StepEntry::insert_csharp));
493         myactions.register_action ("StepEditing", "insert-d", _("Insert Note D"), sigc::mem_fun (*this, &StepEntry::insert_d));
494         myactions.register_action ("StepEditing", "insert-dsharp", _("Insert Note D-sharp"), sigc::mem_fun (*this, &StepEntry::insert_dsharp));
495         myactions.register_action ("StepEditing", "insert-e", _("Insert Note E"), sigc::mem_fun (*this, &StepEntry::insert_e));
496         myactions.register_action ("StepEditing", "insert-f", _("Insert Note F"), sigc::mem_fun (*this, &StepEntry::insert_f));
497         myactions.register_action ("StepEditing", "insert-fsharp", _("Insert Note F-sharp"), sigc::mem_fun (*this, &StepEntry::insert_fsharp));
498         myactions.register_action ("StepEditing", "insert-g", _("Insert Note G"), sigc::mem_fun (*this, &StepEntry::insert_g));
499         myactions.register_action ("StepEditing", "insert-gsharp", _("Insert Note G-sharp"), sigc::mem_fun (*this, &StepEntry::insert_gsharp));
500
501         RadioAction::Group note_length_group;
502
503         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-whole", 
504                                          _("Set Note Length to Whole"), sigc::mem_fun (*this, &StepEntry::note_length_change), 1);
505         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-half", 
506                                          _("Set Note Length to 1/2"), sigc::mem_fun (*this, &StepEntry::note_length_change), 2);
507         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-quarter",
508                                          _("Set Note Length to 1/4"), sigc::mem_fun (*this, &StepEntry::note_length_change), 4);
509         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-eighth",
510                                          _("Set Note Length to 1/8"), sigc::mem_fun (*this, &StepEntry::note_length_change), 8);
511         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-sixteenth",
512                                          _("Set Note Length to 1/16"), sigc::mem_fun (*this, &StepEntry::note_length_change), 16);
513         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-thirtysecond",
514                                          _("Set Note Length to 1/32"), sigc::mem_fun (*this, &StepEntry::note_length_change), 32);
515         myactions.register_radio_action ("StepEditing", note_length_group, "note-length-sixtyfourth",
516                                          _("Set Note Length to 1/64"), sigc::mem_fun (*this, &StepEntry::note_length_change), 64);
517
518         RadioAction::Group note_velocity_group;
519
520         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-ppp",
521                                          _("Set Note Velocity to Pianississimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 1);
522         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-pp",
523                                          _("Set Note Velocity to Pianissimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 16);
524         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-p",
525                                          _("Set Note Velocity to Piano"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 32);
526         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-mp",
527                                          _("Set Note Velocity to Mezzo-Piano"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 64);
528         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-mf",
529                                          _("Set Note Velocity to Mezzo-Forte"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 80);
530         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-f",
531                                          _("Set Note Velocity to Forte"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 96);
532         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-ff",
533                                          _("Set Note Velocity to Fortississimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 112);
534         myactions.register_radio_action ("StepEditing", note_velocity_group, "note-velocity-fff",
535                                          _("Set Note Velocity to Fortississimo"), sigc::mem_fun (*this, &StepEntry::note_velocity_change), 127);
536 }
537
538 void
539 StepEntry::load_bindings ()
540 {
541         bindings.set_action_map (myactions);
542
543         sys::path binding_file;
544         SearchPath spath = ardour_search_path() + user_config_directory() + system_config_search_path();
545
546         if (find_file_in_search_path (spath, "step_editing.bindings", binding_file)) {
547                 bindings.load (binding_file.to_string());
548         }
549 }
550
551 void
552 StepEntry::insert_rest ()
553 {
554         _mtv->step_edit_rest (note_length());
555 }
556
557 void
558 StepEntry::insert_grid_rest ()
559 {
560         _mtv->step_edit_rest (0.0);
561 }
562
563 void
564 StepEntry::insert_note (uint8_t note)
565 {
566         _mtv->step_add_note (note_channel(), note, note_velocity(), note_length());
567 }
568 void
569 StepEntry::insert_c ()
570 {
571         insert_note (0 + (current_octave() * 12));
572 }
573 void
574 StepEntry::insert_csharp ()
575 {
576         insert_note (1 + (current_octave() * 12));
577 }
578 void
579 StepEntry::insert_d ()
580 {
581         insert_note (2 + (current_octave() * 12));
582 }
583 void
584 StepEntry::insert_dsharp ()
585 {
586         insert_note (3 + (current_octave() * 12));
587 }
588 void
589 StepEntry::insert_e ()
590 {
591         insert_note (4 + (current_octave() * 12));
592 }
593 void
594 StepEntry::insert_f ()
595 {
596         insert_note (5 + (current_octave() * 12));
597 }
598 void
599 StepEntry::insert_fsharp ()
600 {
601         insert_note (6 + (current_octave() * 12));
602 }
603 void
604 StepEntry::insert_g ()
605 {
606         insert_note (7 + (current_octave() * 12));
607 }
608 void
609 StepEntry::insert_gsharp ()
610 {
611         insert_note (8 + (current_octave() * 12));
612 }
613
614 void
615 StepEntry::insert_a ()
616 {
617         insert_note (9 + (current_octave() * 12));
618 }
619
620 void
621 StepEntry::insert_asharp ()
622 {
623         insert_note (10 + (current_octave() * 12));
624 }
625 void
626 StepEntry::insert_b ()
627 {
628         insert_note (11 + (current_octave() * 12));
629 }
630
631 void
632 StepEntry::insert_bsharp ()
633 {
634         insert_note (12 + (current_octave() * 12));
635 }
636
637 void
638 StepEntry::note_length_change (GtkAction* act)
639 {
640         /* it doesn't matter which note length action we look up - we are interested
641            in the current_value which is global across the whole group of note length
642            actions. this method is called twice for every user operation,
643            once for the action that became "inactive" and once for the action that
644            becaome "active". so ... only bother to actually change the value when this
645            is called for the "active" action.
646         */
647         
648         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION(act))) {
649                 gint v = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (act));
650                 length_divisor_adjustment.set_value (v);
651         }
652 }
653
654 void
655 StepEntry::note_velocity_change (GtkAction* act)
656 {
657         /* it doesn't matter which note length action we look up - we are interested
658            in the current_value which is global across the whole group of note length
659            actions. this method is called twice for every user operation,
660            once for the action that became "inactive" and once for the action that
661            becaome "active". so ... only bother to actually change the value when this
662            is called for the "active" action.
663         */
664         
665         if (gtk_toggle_action_get_active (GTK_TOGGLE_ACTION(act))) {
666                 gint v = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (act));
667                 cerr << "Velocity reset to " << v << endl;
668                 velocity_adjustment.set_value (v);
669         }
670 }
671
672 void
673 StepEntry::velocity_value_change ()
674 {
675         RefPtr<Action> act;
676         RefPtr<RadioAction> ract;
677         double val = velocity_adjustment.get_value();
678         bool inconsistent = true;
679         vector<const char*> velocity_actions;
680
681         velocity_actions.push_back ("StepEditing/note-velocity-ppp");
682         velocity_actions.push_back ("StepEditing/note-velocity-pp");
683         velocity_actions.push_back ("StepEditing/note-velocity-p");
684         velocity_actions.push_back ("StepEditing/note-velocity-mp");
685         velocity_actions.push_back ("StepEditing/note-velocity-mf");
686         velocity_actions.push_back ("StepEditing/note-velocity-f");
687         velocity_actions.push_back ("StepEditing/note-velocity-ff");
688         velocity_actions.push_back ("StepEditing/note-velocity-fff");
689
690         for (vector<const char*>::iterator i = velocity_actions.begin(); i != velocity_actions.end(); ++i) {
691
692                 act = myactions.find_action (*i);
693                 
694                 if (act) {
695                         ract = RefPtr<RadioAction>::cast_dynamic (act);
696
697                         if (ract) { 
698                                 if (ract->property_value() == val) {
699                                         ract->set_active (true);
700                                         inconsistent = false;
701                                         break;
702                                 }
703                         }
704                 }
705         }
706
707         velocity_ppp_button.set_inconsistent (inconsistent);
708         velocity_pp_button.set_inconsistent (inconsistent);
709         velocity_p_button.set_inconsistent (inconsistent);
710         velocity_mp_button.set_inconsistent (inconsistent);
711         velocity_mf_button.set_inconsistent (inconsistent);
712         velocity_f_button.set_inconsistent (inconsistent);
713         velocity_ff_button.set_inconsistent (inconsistent);
714         velocity_fff_button.set_inconsistent (inconsistent);
715 }
716
717 void
718 StepEntry::length_value_change ()
719 {
720         RefPtr<Action> act;
721         RefPtr<RadioAction> ract;
722         double val = length_divisor_adjustment.get_value();
723         bool inconsistent = true;
724         vector<const char*> length_actions;
725
726         length_actions.push_back ("StepEditing/note-length-whole");
727         length_actions.push_back ("StepEditing/note-length-half");
728         length_actions.push_back ("StepEditing/note-length-quarter");
729         length_actions.push_back ("StepEditing/note-length-eighth");
730         length_actions.push_back ("StepEditing/note-length-sixteenth");
731         length_actions.push_back ("StepEditing/note-length-thirtysecond");
732         length_actions.push_back ("StepEditing/note-length-sixtyfourth");
733
734         for (vector<const char*>::iterator i = length_actions.begin(); i != length_actions.end(); ++i) {
735
736                 act = myactions.find_action (*i);
737                 
738                 if (act) {
739                         ract = RefPtr<RadioAction>::cast_dynamic (act);
740
741                         if (ract) { 
742                                 if (ract->property_value() == val) {
743                                         ract->set_active (true);
744                                         inconsistent = false;
745                                         break;
746                                 }
747                         }
748                 }
749         }
750
751         length_1_button.set_inconsistent (inconsistent);
752         length_2_button.set_inconsistent (inconsistent);
753         length_4_button.set_inconsistent (inconsistent);
754         length_8_button.set_inconsistent (inconsistent);
755         length_16_button.set_inconsistent (inconsistent);
756         length_32_button.set_inconsistent (inconsistent);
757         length_64_button.set_inconsistent (inconsistent);
758 }
759
760 bool
761 StepEntry::radio_button_press (GdkEventButton* ev)
762 {
763         if (ev->button == 1) {
764                 return true;
765         } 
766
767         return false;
768 }
769
770 bool
771 StepEntry::radio_button_release (GdkEventButton* ev, RadioButton* btn, int v)
772 {
773         if (ev->button == 1) {
774                 GtkAction* act = gtk_activatable_get_related_action (GTK_ACTIVATABLE (btn->gobj()));
775                 
776                 if (act) {
777                         gtk_radio_action_set_current_value (GTK_RADIO_ACTION(act), v);
778                 }
779                 
780                 return true;
781         } 
782
783         return false;
784 }