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