Fix named controls menu to display all controls (don't miss the last submenu).
[ardour.git] / gtk2_ardour / midi_time_axis.cc
1 /*
2     Copyright (C) 2000 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 #include <cstdlib>
20 #include <cmath>
21
22 #include <algorithm>
23 #include <string>
24 #include <vector>
25
26 #include <sigc++/bind.h>
27
28 #include "pbd/error.h"
29 #include "pbd/stl_delete.h"
30 #include "pbd/whitespace.h"
31 #include "pbd/basename.h"
32 #include "pbd/enumwriter.h"
33 #include "pbd/memento_command.h"
34 #include "pbd/stateful_diff_command.h"
35
36 #include "gtkmm2ext/gtk_ui.h"
37 #include "gtkmm2ext/selector.h"
38 #include "gtkmm2ext/bindable_button.h"
39 #include "gtkmm2ext/utils.h"
40
41 #include "ardour/event_type_map.h"
42 #include "ardour/midi_patch_manager.h"
43 #include "ardour/midi_playlist.h"
44 #include "ardour/midi_region.h"
45 #include "ardour/midi_source.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/operations.h"
48 #include "ardour/playlist.h"
49 #include "ardour/region.h"
50 #include "ardour/region_factory.h"
51 #include "ardour/route.h"
52 #include "ardour/session.h"
53 #include "ardour/session_object.h"
54 #include "ardour/source.h"
55 #include "ardour/track.h"
56 #include "ardour/types.h"
57
58 #include "ardour_ui.h"
59 #include "ardour_button.h"
60 #include "automation_line.h"
61 #include "automation_time_axis.h"
62 #include "canvas-note-event.h"
63 #include "canvas_impl.h"
64 #include "editor.h"
65 #include "enums.h"
66 #include "ghostregion.h"
67 #include "gui_thread.h"
68 #include "keyboard.h"
69 #include "midi_scroomer.h"
70 #include "midi_streamview.h"
71 #include "midi_region_view.h"
72 #include "midi_time_axis.h"
73 #include "piano_roll_header.h"
74 #include "playlist_selector.h"
75 #include "plugin_selector.h"
76 #include "plugin_ui.h"
77 #include "point_selection.h"
78 #include "prompter.h"
79 #include "region_view.h"
80 #include "rgb_macros.h"
81 #include "selection.h"
82 #include "step_editor.h"
83 #include "simplerect.h"
84 #include "utils.h"
85
86 #include "ardour/midi_track.h"
87
88 #include "i18n.h"
89
90 using namespace ARDOUR;
91 using namespace PBD;
92 using namespace Gtk;
93 using namespace Gtkmm2ext;
94 using namespace Editing;
95
96 // Minimum height at which a control is displayed
97 static const uint32_t MIDI_CONTROLS_BOX_MIN_HEIGHT = 162;
98 static const uint32_t KEYBOARD_MIN_HEIGHT = 140;
99
100 MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
101         : AxisView(sess) // virtually inherited
102         , RouteTimeAxisView(ed, sess, canvas)
103         , _ignore_signals(false)
104         , _range_scroomer(0)
105         , _piano_roll_header(0)
106         , _note_mode(Sustained)
107         , _note_mode_item(0)
108         , _percussion_mode_item(0)
109         , _color_mode(MeterColors)
110         , _meter_color_mode_item(0)
111         , _channel_color_mode_item(0)
112         , _track_color_mode_item(0)
113         , _step_edit_item (0)
114         , controller_menu (0)
115         , _step_editor (0)
116 {
117 }
118
119 void
120 MidiTimeAxisView::set_route (boost::shared_ptr<Route> rt)
121 {
122         _route = rt;
123         
124         _view = new MidiStreamView (*this);
125
126         if (is_track ()) {
127                 _piano_roll_header = new PianoRollHeader(*midi_view());
128                 _range_scroomer = new MidiScroomer(midi_view()->note_range_adjustment);
129                 _range_scroomer->DoubleClicked.connect (
130                         sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
131                                     MidiStreamView::ContentsRange, false));
132         }
133
134         /* This next call will result in our height being set up, so it must come after
135            the creation of the piano roll / range scroomer as their visibility is set up
136            when our height is.
137         */
138         RouteTimeAxisView::set_route (rt);
139
140         _view->apply_color (_color, StreamView::RegionColor);
141
142         subplugin_menu.set_name ("ArdourContextMenu");
143
144         if (!gui_property ("note-range-min").empty ()) {
145                 midi_view()->apply_note_range (atoi (gui_property ("note-range-min").c_str()),
146                                                atoi (gui_property ("note-range-max").c_str()),
147                                                true);
148         }
149
150         midi_view()->NoteRangeChanged.connect (
151                 sigc::mem_fun (*this, &MidiTimeAxisView::note_range_changed));
152         _view->ContentsHeightChanged.connect (
153                 sigc::mem_fun (*this, &MidiTimeAxisView::contents_height_changed));
154
155         ignore_toggle = false;
156
157         if (is_midi_track()) {
158                 controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected");
159                 _note_mode = midi_track()->note_mode();
160         } else { // MIDI bus (which doesn't exist yet..)
161                 controls_ebox.set_name ("MidiBusControlsBaseUnselected");
162         }
163
164         /* map current state of the route */
165
166         processors_changed (RouteProcessorChange ());
167
168         _route->processors_changed.connect (*this, invalidator (*this),
169                                             boost::bind (&MidiTimeAxisView::processors_changed, this, _1),
170                                             gui_context());
171
172         if (is_track()) {
173                 _piano_roll_header->SetNoteSelection.connect (
174                         sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection));
175                 _piano_roll_header->AddNoteSelection.connect (
176                         sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection));
177                 _piano_roll_header->ExtendNoteSelection.connect (
178                         sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection));
179                 _piano_roll_header->ToggleNoteSelection.connect (
180                         sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection));
181
182                 /* Suspend updates of the StreamView during scroomer drags to speed things up */
183                 _range_scroomer->DragStarting.connect (
184                         sigc::mem_fun (*midi_view(), &MidiStreamView::suspend_updates));
185                 _range_scroomer->DragFinishing.connect (
186                         sigc::mem_fun (*midi_view(), &MidiStreamView::resume_updates));
187
188                 /* Put the scroomer and the keyboard in a VBox with a padding
189                    label so that they can be reduced in height for stacked-view
190                    tracks.
191                 */
192                 VBox* v = manage (new VBox);
193                 HBox* h = manage (new HBox);
194                 h->pack_start (*_range_scroomer);
195                 h->pack_start (*_piano_roll_header);
196                 v->pack_start (*h, false, false);
197                 v->pack_start (*manage (new Label ("")), true, true);
198                 v->show ();
199                 h->show ();
200                 controls_hbox.pack_start(*v);
201
202                 controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
203                 controls_base_selected_name = "MidiTrackControlsBaseSelected";
204                 controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
205
206                 midi_view()->NoteRangeChanged.connect (
207                         sigc::mem_fun(*this, &MidiTimeAxisView::update_range));
208
209                 /* ask for notifications of any new RegionViews */
210                 _view->RegionViewAdded.connect (
211                         sigc::mem_fun(*this, &MidiTimeAxisView::region_view_added));
212
213                 if (!_editor.have_idled()) {
214                         /* first idle will do what we need */
215                 } else {
216                         first_idle ();
217                 }
218         }
219
220         MIDI::Name::MidiPatchManager& patch_manager = MIDI::Name::MidiPatchManager::instance();
221
222         MIDI::Name::MasterDeviceNames::Models::const_iterator m = patch_manager.all_models().begin();
223         for (; m != patch_manager.all_models().end(); ++m) {
224                 _midnam_model_selector.append_text(m->c_str());
225         }
226
227         if (gui_property (X_("midnam-model-name")).empty()) {
228                 set_gui_property (X_("midnam-model-name"), "Generic");
229         }
230
231         if (gui_property (X_("midnam-custom-device-mode")).empty()) {
232                 boost::shared_ptr<MIDI::Name::MasterDeviceNames> device_names = get_device_names();
233                 if (device_names) {
234                         set_gui_property (X_("midnam-custom-device-mode"),
235                                           *device_names->custom_device_mode_names().begin());
236                 }
237         }
238
239         _midnam_model_selector.set_active_text (gui_property (X_("midnam-model-name")));
240         _midnam_custom_device_mode_selector.set_active_text (gui_property (X_("midnam-custom-device-mode")));
241
242         ARDOUR_UI::instance()->set_tip (_midnam_model_selector, _("External MIDI Device"));
243         ARDOUR_UI::instance()->set_tip (_midnam_custom_device_mode_selector, _("External Device Mode"));
244
245         _midi_controls_box.set_homogeneous(false);
246         _midi_controls_box.set_border_width (10);
247
248         if (!patch_manager.all_models().empty()) {
249                 _channel_selector.set_border_width(2);
250                 _channel_selector.show_all ();
251
252                 _midi_controls_box.resize(3, 2);
253                 _midi_controls_box.attach(_channel_selector, 0, 2, 0, 1);
254                 
255                 _midi_controls_box.attach(*manage(new HSeparator()), 0, 2, 1, 2);
256
257                 _midnam_model_selector.set_size_request(22, 30);
258                 _midnam_model_selector.set_border_width(2);
259                 _midnam_model_selector.show ();
260                 _midi_controls_box.attach(_midnam_model_selector, 0, 1, 2, 3);
261
262                 _midnam_custom_device_mode_selector.set_size_request(10, 30);
263                 _midnam_custom_device_mode_selector.set_border_width(2);
264                 _midnam_custom_device_mode_selector.show ();
265
266                 _midi_controls_box.attach(_midnam_custom_device_mode_selector, 0, 1, 3, 4);
267         } else {
268                 _midi_controls_box.attach(_channel_selector, 0, 1, 0, 1);
269                 _channel_selector.show_all ();
270         }
271
272         model_changed();
273         custom_device_mode_changed();
274
275         _midnam_model_selector.signal_changed().connect(
276                 sigc::mem_fun(*this, &MidiTimeAxisView::model_changed));
277         _midnam_custom_device_mode_selector.signal_changed().connect(
278                 sigc::mem_fun(*this, &MidiTimeAxisView::custom_device_mode_changed));
279
280         controls_vbox.pack_start(_midi_controls_box, false, false);
281
282         // restore channel selector settings
283         _channel_selector.set_channel_mode(midi_track()->get_channel_mode(),
284                                            midi_track()->get_channel_mask());
285         _channel_selector.mode_changed.connect(
286                 sigc::mem_fun(*midi_track(), &MidiTrack::set_channel_mode));
287         _channel_selector.mode_changed.connect(
288                 sigc::mem_fun(*this, &MidiTimeAxisView::set_channel_mode));
289
290         const string color_mode = gui_property ("color-mode");
291         if (!color_mode.empty()) {
292                 _color_mode = ColorMode (string_2_enum(color_mode, _color_mode));
293                 if (_color_mode == ChannelColors) {
294                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
295                 }
296         }
297
298         set_color_mode (_color_mode, true, false);
299
300         const string note_mode = gui_property ("note-mode");
301         if (!note_mode.empty()) {
302                 _note_mode = NoteMode (string_2_enum (note_mode, _note_mode));
303                 if (_percussion_mode_item) {
304                         _percussion_mode_item->set_active (_note_mode == Percussive);
305                 }
306         }
307
308         /* Look for any GUI object state nodes that represent automation children
309          * that should exist, and create the children.
310          */
311
312         const list<string> gui_ids = gui_object_state().all_ids ();
313         for (list<string>::const_iterator i = gui_ids.begin(); i != gui_ids.end(); ++i) {
314                 PBD::ID route_id;
315                 bool has_parameter;
316                 Evoral::Parameter parameter (0, 0, 0);
317
318                 bool const p = AutomationTimeAxisView::parse_state_id (
319                         *i, route_id, has_parameter, parameter);
320                 if (p && route_id == _route->id () && has_parameter) {
321                         const std::string& visible = gui_object_state().get_string (*i, X_("visible"));
322                         create_automation_child (parameter, string_is_affirmative (visible));
323                 }
324         }
325 }
326
327 void
328 MidiTimeAxisView::first_idle ()
329 {
330         if (is_track ()) {
331                 _view->attach ();
332         }
333 }
334
335 MidiTimeAxisView::~MidiTimeAxisView ()
336 {
337         delete _piano_roll_header;
338         _piano_roll_header = 0;
339
340         delete _range_scroomer;
341         _range_scroomer = 0;
342
343         delete controller_menu;
344         delete _step_editor;
345 }
346
347 void
348 MidiTimeAxisView::enter_internal_edit_mode ()
349 {
350         if (midi_view()) {
351                 midi_view()->enter_internal_edit_mode ();
352         }
353 }
354
355 void
356 MidiTimeAxisView::leave_internal_edit_mode ()
357 {
358         if (midi_view()) {
359                 midi_view()->leave_internal_edit_mode ();
360         }
361 }
362
363 void
364 MidiTimeAxisView::check_step_edit ()
365 {
366         ensure_step_editor ();
367         _step_editor->check_step_edit ();
368 }
369
370 void
371 MidiTimeAxisView::model_changed()
372 {
373         const Glib::ustring model = _midnam_model_selector.get_active_text();
374         set_gui_property (X_("midnam-model-name"), model);
375
376         const std::list<std::string> device_modes = MIDI::Name::MidiPatchManager::instance()
377                 .custom_device_mode_names_by_model(model);
378
379         _midnam_custom_device_mode_selector.clear_items();
380
381         for (std::list<std::string>::const_iterator i = device_modes.begin();
382              i != device_modes.end(); ++i) {
383                 _midnam_custom_device_mode_selector.append_text(*i);
384         }
385
386         _midnam_custom_device_mode_selector.set_active(0);
387         
388         _route->instrument_info().set_external_instrument (
389                 _midnam_model_selector.get_active_text(),
390                 _midnam_custom_device_mode_selector.get_active_text());
391
392         // Rebuild controller menu
393         _controller_menu_map.clear ();
394         delete controller_menu;
395         controller_menu = 0;
396         build_automation_action_menu(false);
397 }
398
399 void
400 MidiTimeAxisView::custom_device_mode_changed()
401 {
402         const Glib::ustring mode = _midnam_custom_device_mode_selector.get_active_text();
403         set_gui_property (X_("midnam-custom-device-mode"), mode);
404         _route->instrument_info().set_external_instrument (
405                 _midnam_model_selector.get_active_text(), mode);
406 }
407
408 MidiStreamView*
409 MidiTimeAxisView::midi_view()
410 {
411         return dynamic_cast<MidiStreamView*>(_view);
412 }
413
414 void
415 MidiTimeAxisView::set_height (uint32_t h)
416 {
417         if (h >= MIDI_CONTROLS_BOX_MIN_HEIGHT) {
418                 _midi_controls_box.show ();
419         } else {
420                 _midi_controls_box.hide();
421         }
422         
423         if (h >= KEYBOARD_MIN_HEIGHT) {
424                 if (is_track() && _range_scroomer) {
425                         _range_scroomer->show();
426                 }
427                 if (is_track() && _piano_roll_header) {
428                         _piano_roll_header->show();
429                 }
430         } else {
431                 if (is_track() && _range_scroomer) {
432                         _range_scroomer->hide();
433                 }
434                 if (is_track() && _piano_roll_header) {
435                         _piano_roll_header->hide();
436                 }
437         }
438
439         /* We need to do this after changing visibility of our stuff, as it will
440            eventually trigger a call to Editor::reset_controls_layout_width(),
441            which needs to know if we have just shown or hidden a scroomer /
442            piano roll.
443         */
444         RouteTimeAxisView::set_height (h);
445 }
446
447 void
448 MidiTimeAxisView::append_extra_display_menu_items ()
449 {
450         using namespace Menu_Helpers;
451
452         MenuList& items = display_menu->items();
453
454         // Note range
455         Menu *range_menu = manage(new Menu);
456         MenuList& range_items = range_menu->items();
457         range_menu->set_name ("ArdourContextMenu");
458
459         range_items.push_back (
460                 MenuElem (_("Show Full Range"),
461                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range), 
462                                       MidiStreamView::FullRange, true)));
463
464         range_items.push_back (
465                 MenuElem (_("Fit Contents"),
466                           sigc::bind (sigc::mem_fun(*this, &MidiTimeAxisView::set_note_range),
467                                       MidiStreamView::ContentsRange, true)));
468
469         items.push_back (MenuElem (_("Note Range"), *range_menu));
470         items.push_back (MenuElem (_("Note Mode"), *build_note_mode_menu()));
471
472         items.push_back (SeparatorElem ());
473 }
474
475 void
476 MidiTimeAxisView::build_automation_action_menu (bool for_selection)
477 {
478         using namespace Menu_Helpers;
479
480         /* If we have a controller menu, we need to detach it before
481            RouteTimeAxis::build_automation_action_menu destroys the
482            menu it is attached to.  Otherwise GTK destroys
483            controller_menu's gobj, meaning that it can't be reattached
484            below.  See bug #3134.
485         */
486
487         if (controller_menu) {
488                 detach_menu (*controller_menu);
489         }
490
491         _channel_command_menu_map.clear ();
492         RouteTimeAxisView::build_automation_action_menu (for_selection);
493
494         MenuList& automation_items = automation_action_menu->items();
495
496         uint16_t selected_channels = _channel_selector.get_selected_channels();
497
498         if (selected_channels !=  0) {
499
500                 automation_items.push_back (SeparatorElem());
501
502                 /* these 2 MIDI "command" types are semantically more like automation
503                    than note data, but they are not MIDI controllers. We give them
504                    special status in this menu, since they will not show up in the
505                    controller list and anyone who actually knows something about MIDI
506                    (!) would not expect to find them there.
507                 */
508
509                 add_channel_command_menu_item (
510                         automation_items, _("Bender"), MidiPitchBenderAutomation, 0);
511                 automation_items.back().set_sensitive (
512                         !for_selection || _editor.get_selection().tracks.size() == 1);
513                 add_channel_command_menu_item (
514                         automation_items, _("Pressure"), MidiChannelPressureAutomation, 0);
515                 automation_items.back().set_sensitive (
516                         !for_selection || _editor.get_selection().tracks.size() == 1);
517
518                 /* now all MIDI controllers. Always offer the possibility that we will
519                    rebuild the controllers menu since it might need to be updated after
520                    a channel mode change or other change. Also detach it first in case
521                    it has been used anywhere else.
522                 */
523
524                 build_controller_menu ();
525
526                 automation_items.push_back (SeparatorElem());
527                 automation_items.push_back (MenuElem (_("Controllers"), *controller_menu));
528                 automation_items.back().set_sensitive (
529                         !for_selection || _editor.get_selection().tracks.size() == 1);
530         } else {
531                 automation_items.push_back (
532                         MenuElem (string_compose ("<i>%1</i>", _("No MIDI Channels selected"))));
533                 dynamic_cast<Label*> (automation_items.back().get_child())->set_use_markup (true);
534         }
535 }
536
537 void
538 MidiTimeAxisView::change_all_channel_tracks_visibility (bool yn, Evoral::Parameter param)
539 {
540         const uint16_t selected_channels = _channel_selector.get_selected_channels();
541
542         for (uint8_t chn = 0; chn < 16; chn++) {
543                 if (selected_channels & (0x0001 << chn)) {
544
545                         Evoral::Parameter fully_qualified_param (param.type(), chn, param.id());
546                         Gtk::CheckMenuItem* menu = automation_child_menu_item (fully_qualified_param);
547
548                         if (menu) {
549                                 menu->set_active (yn);
550                         }
551                 }
552         }
553 }
554
555 void
556 MidiTimeAxisView::add_channel_command_menu_item (Menu_Helpers::MenuList& items,
557                                                  const string&           label,
558                                                  AutomationType          auto_type,
559                                                  uint8_t                 cmd)
560 {
561         using namespace Menu_Helpers;
562
563         /* count the number of selected channels because we will build a different menu
564            structure if there is more than 1 selected.
565          */
566
567         const uint16_t selected_channels = _channel_selector.get_selected_channels();
568         int chn_cnt = 0;
569
570         for (uint8_t chn = 0; chn < 16; chn++) {
571                 if (selected_channels & (0x0001 << chn)) {
572                         if (++chn_cnt > 1) {
573                                 break;
574                         }
575                 }
576         }
577
578         if (chn_cnt > 1) {
579
580                 /* multiple channels - create a submenu, with 1 item per channel */
581
582                 Menu* chn_menu = manage (new Menu);
583                 MenuList& chn_items (chn_menu->items());
584                 Evoral::Parameter param_without_channel (auto_type, 0, cmd);
585
586                 /* add a couple of items to hide/show all of them */
587
588                 chn_items.push_back (
589                         MenuElem (_("Hide all channels"),
590                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
591                                               false, param_without_channel)));
592                 chn_items.push_back (
593                         MenuElem (_("Show all channels"),
594                                   sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
595                                               true, param_without_channel)));
596
597                 for (uint8_t chn = 0; chn < 16; chn++) {
598                         if (selected_channels & (0x0001 << chn)) {
599
600                                 /* for each selected channel, add a menu item for this controller */
601
602                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
603                                 chn_items.push_back (
604                                         CheckMenuElem (string_compose (_("Channel %1"), chn+1),
605                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
606                                                                    fully_qualified_param)));
607
608                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
609                                 bool visible = false;
610
611                                 if (track) {
612                                         if (track->marked_for_display()) {
613                                                 visible = true;
614                                         }
615                                 }
616
617                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
618                                 _channel_command_menu_map[fully_qualified_param] = cmi;
619                                 cmi->set_active (visible);
620                         }
621                 }
622
623                 /* now create an item in the parent menu that has the per-channel list as a submenu */
624
625                 items.push_back (MenuElem (label, *chn_menu));
626
627         } else {
628
629                 /* just one channel - create a single menu item for this command+channel combination*/
630
631                 for (uint8_t chn = 0; chn < 16; chn++) {
632                         if (selected_channels & (0x0001 << chn)) {
633
634                                 Evoral::Parameter fully_qualified_param (auto_type, chn, cmd);
635                                 items.push_back (
636                                         CheckMenuElem (label,
637                                                        sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
638                                                                    fully_qualified_param)));
639
640                                 boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
641                                 bool visible = false;
642
643                                 if (track) {
644                                         if (track->marked_for_display()) {
645                                                 visible = true;
646                                         }
647                                 }
648
649                                 CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&items.back());
650                                 _channel_command_menu_map[fully_qualified_param] = cmi;
651                                 cmi->set_active (visible);
652
653                                 /* one channel only */
654                                 break;
655                         }
656                 }
657         }
658 }
659
660 /** Add a single menu item for a controller on one channel. */
661 void
662 MidiTimeAxisView::add_single_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
663                                                      int                     ctl,
664                                                      const std::string&      name)
665 {
666         using namespace Menu_Helpers;
667
668         const uint16_t selected_channels = _channel_selector.get_selected_channels();
669         for (uint8_t chn = 0; chn < 16; chn++) {
670                 if (selected_channels & (0x0001 << chn)) {
671
672                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
673                         ctl_items.push_back (
674                                 CheckMenuElem (
675                                         string_compose ("<b>%1</b>: %2 [%3]", ctl, name, int (chn)),
676                                         sigc::bind (
677                                                 sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
678                                                 fully_qualified_param)));
679                         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
680
681                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
682                                 fully_qualified_param);
683
684                         bool visible = false;
685                         if (track) {
686                                 if (track->marked_for_display()) {
687                                         visible = true;
688                                 }
689                         }
690
691                         CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&ctl_items.back());
692                         _controller_menu_map[fully_qualified_param] = cmi;
693                         cmi->set_active (visible);
694
695                         /* one channel only */
696                         break;
697                 }
698         }
699 }
700
701 /** Add a submenu with 1 item per channel for a controller on many channels. */
702 void
703 MidiTimeAxisView::add_multi_channel_controller_item(Menu_Helpers::MenuList& ctl_items,
704                                                     int                     ctl,
705                                                     const std::string&      name)
706 {
707         using namespace Menu_Helpers;
708
709         const uint16_t selected_channels = _channel_selector.get_selected_channels();
710
711         Menu* chn_menu = manage (new Menu);
712         MenuList& chn_items (chn_menu->items());
713
714         /* add a couple of items to hide/show this controller on all channels */
715
716         Evoral::Parameter param_without_channel (MidiCCAutomation, 0, ctl);
717         chn_items.push_back (
718                 MenuElem (_("Hide all channels"),
719                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
720                                       false, param_without_channel)));
721         chn_items.push_back (
722                 MenuElem (_("Show all channels"),
723                           sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::change_all_channel_tracks_visibility),
724                                       true, param_without_channel)));
725
726         for (uint8_t chn = 0; chn < 16; chn++) {
727                 if (selected_channels & (0x0001 << chn)) {
728
729                         /* for each selected channel, add a menu item for this controller */
730
731                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
732                         chn_items.push_back (
733                                 CheckMenuElem (string_compose (_("Channel %1"), chn+1),
734                                                sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::toggle_automation_track),
735                                                            fully_qualified_param)));
736
737                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (
738                                 fully_qualified_param);
739                         bool visible = false;
740
741                         if (track) {
742                                 if (track->marked_for_display()) {
743                                         visible = true;
744                                 }
745                         }
746
747                         CheckMenuItem* cmi = static_cast<CheckMenuItem*>(&chn_items.back());
748                         _controller_menu_map[fully_qualified_param] = cmi;
749                         cmi->set_active (visible);
750                 }
751         }
752
753         /* add the per-channel menu to the list of controllers, with the name of the controller */
754         ctl_items.push_back (MenuElem (string_compose ("<b>%1</b>: %2", ctl, name),
755                                        *chn_menu));
756         dynamic_cast<Label*> (ctl_items.back().get_child())->set_use_markup (true);
757 }
758
759 boost::shared_ptr<MIDI::Name::CustomDeviceMode>
760 MidiTimeAxisView::get_device_mode()
761 {
762         using namespace MIDI::Name;
763
764         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
765         if (!device_names) {
766                 return boost::shared_ptr<MIDI::Name::CustomDeviceMode>();
767         }
768
769         return device_names->custom_device_mode_by_name(
770                 gui_property (X_("midnam-custom-device-mode")));
771 }
772
773 boost::shared_ptr<MIDI::Name::MasterDeviceNames>
774 MidiTimeAxisView::get_device_names()
775 {
776         using namespace MIDI::Name;
777
778         const std::string model = gui_property (X_("midnam-model-name"));
779
780         boost::shared_ptr<MIDINameDocument> midnam = MidiPatchManager::instance()
781                 .document_by_model(model);
782         if (midnam) {
783                 return midnam->master_device_names(model);
784         } else {
785                 return boost::shared_ptr<MasterDeviceNames>();
786         }
787 }
788
789 void
790 MidiTimeAxisView::build_controller_menu ()
791 {
792         using namespace Menu_Helpers;
793
794         if (controller_menu) {
795                 /* it exists and has not been invalidated by a channel mode change */
796                 return;
797         }
798
799         controller_menu = new Menu; // explicitly managed by us
800         MenuList& items (controller_menu->items());
801
802         /* create several "top level" menu items for sets of controllers (16 at a
803            time), and populate each one with a submenu for each controller+channel
804            combination covering the currently selected channels for this track
805         */
806
807         const uint16_t selected_channels = _channel_selector.get_selected_channels();
808
809         /* count the number of selected channels because we will build a different menu
810            structure if there is more than 1 selected.
811         */
812
813         int chn_cnt = 0;
814         for (uint8_t chn = 0; chn < 16; chn++) {
815                 if (selected_channels & (0x0001 << chn)) {
816                         if (++chn_cnt > 1) {
817                                 break;
818                         }
819                 }
820         }
821
822         using namespace MIDI::Name;
823         boost::shared_ptr<MasterDeviceNames> device_names = get_device_names();
824
825         if (device_names && !device_names->controls().empty()) {
826                 /* Controllers names available in midnam file, generate fancy menu */
827                 unsigned n_items  = 0;
828                 unsigned n_groups = 0;
829
830                 /* TODO: This is not correct, should look up the currently applicable ControlNameList
831                    and only build a menu for that one. */
832                 for (MasterDeviceNames::ControlNameLists::const_iterator l = device_names->controls().begin();
833                      l != device_names->controls().end(); ++l) {
834                         boost::shared_ptr<ControlNameList> name_list = l->second;
835                         Menu*                              ctl_menu  = NULL;
836                         
837                         for (ControlNameList::Controls::const_iterator c = name_list->controls().begin();
838                              c != name_list->controls().end();) {
839                                 const uint16_t ctl = c->second->number();
840                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
841                                         /* Skip bank select controllers since they're handled specially */
842                                         /* FIXME: If this is the last control, the last submenu might be lost */
843                                         continue;
844                                 }
845                                 
846                                 if (n_items == 0) {
847                                         /* Create a new submenu */
848                                         ctl_menu = manage (new Menu);
849                                 }
850                                 
851                                 MenuList& ctl_items (ctl_menu->items());
852                                 if (chn_cnt > 1) {
853                                         add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
854                                 } else {
855                                         add_single_channel_controller_item(ctl_items, ctl, c->second->name());
856                                 }
857
858                                 ++c;
859                                 if (++n_items == 16 || c == name_list->controls().end()) {
860                                         /* Submenu has 16 items, add it to controller menu and reset */
861                                         items.push_back(
862                                                 MenuElem(string_compose(_("Controllers %1-%2"),
863                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
864                                                          *ctl_menu));
865                                         ctl_menu = NULL;
866                                         n_items  = 0;
867                                         ++n_groups;
868                                 }
869                         }
870                 }
871         } else {
872                 /* No controllers names, generate generic numeric menu */
873                 for (int i = 0; i < 127; i += 16) {
874                         Menu*     ctl_menu = manage (new Menu);
875                         MenuList& ctl_items (ctl_menu->items());
876
877                         for (int ctl = i; ctl < i+16; ++ctl) {
878                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
879                                         /* Skip bank select controllers since they're handled specially */
880                                         continue;
881                                 }
882
883                                 if (chn_cnt > 1) {
884                                         add_multi_channel_controller_item(
885                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
886                                 } else {
887                                         add_single_channel_controller_item(
888                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
889                                 }
890                         }
891
892                         /* Add submenu for this block of controllers to controller menu */
893                         items.push_back (
894                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
895                                           *ctl_menu));
896                 }
897         }
898 }
899
900 Gtk::Menu*
901 MidiTimeAxisView::build_note_mode_menu()
902 {
903         using namespace Menu_Helpers;
904
905         Menu* mode_menu = manage (new Menu);
906         MenuList& items = mode_menu->items();
907         mode_menu->set_name ("ArdourContextMenu");
908
909         RadioMenuItem::Group mode_group;
910         items.push_back (
911                 RadioMenuElem (mode_group,_("Sustained"),
912                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
913                                            Sustained, true)));
914         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
915         _note_mode_item->set_active(_note_mode == Sustained);
916
917         items.push_back (
918                 RadioMenuElem (mode_group, _("Percussive"),
919                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
920                                            Percussive, true)));
921         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
922         _percussion_mode_item->set_active(_note_mode == Percussive);
923
924         return mode_menu;
925 }
926
927 Gtk::Menu*
928 MidiTimeAxisView::build_color_mode_menu()
929 {
930         using namespace Menu_Helpers;
931
932         Menu* mode_menu = manage (new Menu);
933         MenuList& items = mode_menu->items();
934         mode_menu->set_name ("ArdourContextMenu");
935
936         RadioMenuItem::Group mode_group;
937         items.push_back (
938                 RadioMenuElem (mode_group, _("Meter Colors"),
939                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
940                                            MeterColors, false, true, true)));
941         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
942         _meter_color_mode_item->set_active(_color_mode == MeterColors);
943
944         items.push_back (
945                 RadioMenuElem (mode_group, _("Channel Colors"),
946                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
947                                            ChannelColors, false, true, true)));
948         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
949         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
950
951         items.push_back (
952                 RadioMenuElem (mode_group, _("Track Color"),
953                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
954                                            TrackColor, false, true, true)));
955         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
956         _channel_color_mode_item->set_active(_color_mode == TrackColor);
957
958         return mode_menu;
959 }
960
961 void
962 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
963 {
964         if (apply_to_selection) {
965                 _editor.get_selection().tracks.foreach_midi_time_axis (
966                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
967         } else {
968                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
969                         _note_mode = mode;
970                         midi_track()->set_note_mode(mode);
971                         set_gui_property ("note-mode", enum_2_string(_note_mode));
972                         _view->redisplay_track();
973                 }
974         }
975 }
976
977 void
978 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
979 {
980         if (apply_to_selection) {
981                 _editor.get_selection().tracks.foreach_midi_time_axis (
982                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
983         } else {
984                 if (_color_mode == mode && !force) {
985                         return;
986                 }
987                 
988                 if (mode == ChannelColors) {
989                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
990                 } else {
991                         _channel_selector.set_default_channel_color();
992                 }
993                 
994                 _color_mode = mode;
995                 set_gui_property ("color-mode", enum_2_string(_color_mode));
996                 if (redisplay) {
997                         _view->redisplay_track();
998                 }
999         }
1000 }
1001
1002 void
1003 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1004 {
1005         if (apply_to_selection) {
1006                 _editor.get_selection().tracks.foreach_midi_time_axis (
1007                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1008         } else {
1009                 if (!_ignore_signals) {
1010                         midi_view()->set_note_range(range);
1011                 }
1012         }
1013 }
1014
1015 void
1016 MidiTimeAxisView::update_range()
1017 {
1018         MidiGhostRegion* mgr;
1019
1020         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1021                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1022                         mgr->update_range();
1023                 }
1024         }
1025 }
1026
1027 void
1028 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1029 {
1030         if (apply_to_selection) {
1031                 _editor.get_selection().tracks.foreach_midi_time_axis (
1032                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1033         } else {
1034                 if (midi_track()) {
1035                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1036
1037                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1038                                 create_automation_child(*i, true);
1039                         }
1040                 }
1041
1042                 RouteTimeAxisView::show_all_automation ();
1043         }
1044 }
1045
1046 void
1047 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1048 {
1049         if (apply_to_selection) {
1050                 _editor.get_selection().tracks.foreach_midi_time_axis (
1051                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1052         } else {
1053                 if (midi_track()) {
1054                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1055
1056                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1057                                 create_automation_child (*i, true);
1058                         }
1059                 }
1060
1061                 RouteTimeAxisView::show_existing_automation ();
1062         }
1063 }
1064
1065 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1066  */
1067 void
1068 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1069 {
1070         if (param.type() == NullAutomation) {
1071                 return;
1072         }
1073
1074         AutomationTracks::iterator existing = _automation_tracks.find (param);
1075
1076         if (existing != _automation_tracks.end()) {
1077
1078                 /* automation track created because we had existing data for
1079                  * the processor, but visibility may need to be controlled
1080                  * since it will have been set visible by default.
1081                  */
1082
1083                 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1084                         request_redraw ();
1085                 }
1086
1087                 return;
1088         }
1089
1090         boost::shared_ptr<AutomationTimeAxisView> track;
1091
1092         switch (param.type()) {
1093
1094         case GainAutomation:
1095                 create_gain_automation_child (param, show);
1096                 break;
1097
1098         case PluginAutomation:
1099                 /* handled elsewhere */
1100                 break;
1101
1102         case MidiCCAutomation:
1103         case MidiPgmChangeAutomation:
1104         case MidiPitchBenderAutomation:
1105         case MidiChannelPressureAutomation:
1106         case MidiSystemExclusiveAutomation:
1107                 /* These controllers are region "automation" - they are owned
1108                  * by regions (and their MidiModels), not by the track. As a
1109                  * result we do not create an AutomationList/Line for the track
1110                  * ... except here we are doing something!! XXX 
1111                  */
1112
1113                 track.reset (new AutomationTimeAxisView (
1114                                      _session,
1115                                      _route,
1116                                      boost::shared_ptr<Automatable> (),
1117                                      boost::shared_ptr<AutomationControl> (),
1118                                      param,
1119                                      _editor,
1120                                      *this,
1121                                      true,
1122                                      parent_canvas,
1123                                      _route->describe_parameter(param)));
1124
1125                 if (_view) {
1126                         _view->foreach_regionview (
1127                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1128                 }
1129
1130                 add_automation_child (param, track, show);
1131                 break;
1132
1133         default:
1134                 error << "MidiTimeAxisView: unknown automation child "
1135                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1136         }
1137 }
1138
1139 void
1140 MidiTimeAxisView::route_active_changed ()
1141 {
1142         RouteUI::route_active_changed ();
1143
1144         if (is_track()) {
1145                 if (_route->active()) {
1146                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1147                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1148                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1149                 } else {
1150                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1151                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1152                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1153                 }
1154         } else {
1155                 if (_route->active()) {
1156                         controls_ebox.set_name ("BusControlsBaseUnselected");
1157                         controls_base_selected_name = "BusControlsBaseSelected";
1158                         controls_base_unselected_name = "BusControlsBaseUnselected";
1159                 } else {
1160                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1161                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1162                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1163                 }
1164         }
1165 }
1166
1167 void
1168 MidiTimeAxisView::set_note_selection (uint8_t note)
1169 {
1170         if (!_editor.internal_editing()) {
1171                 return;
1172         }
1173
1174         uint16_t chn_mask = _channel_selector.get_selected_channels();
1175
1176         if (_view->num_selected_regionviews() == 0) {
1177                 _view->foreach_regionview (
1178                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1179                                     note, chn_mask));
1180         } else {
1181                 _view->foreach_selected_regionview (
1182                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1183                                     note, chn_mask));
1184         }
1185 }
1186
1187 void
1188 MidiTimeAxisView::add_note_selection (uint8_t note)
1189 {
1190         if (!_editor.internal_editing()) {
1191                 return;
1192         }
1193
1194         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1195
1196         if (_view->num_selected_regionviews() == 0) {
1197                 _view->foreach_regionview (
1198                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1199                                     note, chn_mask));
1200         } else {
1201                 _view->foreach_selected_regionview (
1202                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1203                                     note, chn_mask));
1204         }
1205 }
1206
1207 void
1208 MidiTimeAxisView::extend_note_selection (uint8_t note)
1209 {
1210         if (!_editor.internal_editing()) {
1211                 return;
1212         }
1213
1214         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1215
1216         if (_view->num_selected_regionviews() == 0) {
1217                 _view->foreach_regionview (
1218                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1219                                     note, chn_mask));
1220         } else {
1221                 _view->foreach_selected_regionview (
1222                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1223                                     note, chn_mask));
1224         }
1225 }
1226
1227 void
1228 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1229 {
1230         if (!_editor.internal_editing()) {
1231                 return;
1232         }
1233
1234         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1235
1236         if (_view->num_selected_regionviews() == 0) {
1237                 _view->foreach_regionview (
1238                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1239                                     note, chn_mask));
1240         } else {
1241                 _view->foreach_selected_regionview (
1242                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1243                                     note, chn_mask));
1244         }
1245 }
1246
1247 void
1248 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1249 {
1250         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1251 }
1252
1253 void
1254 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1255 {
1256         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1257 }
1258
1259 void
1260 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1261 {
1262         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1263 }
1264
1265 void
1266 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1267 {
1268         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1269 }
1270
1271 void
1272 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1273 {
1274         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1275            the right ones.
1276         */
1277
1278         const uint16_t selected_channels = _channel_selector.get_selected_channels();
1279         bool changed = false;
1280
1281         no_redraw = true;
1282
1283         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1284
1285                 for (uint32_t chn = 0; chn < 16; ++chn) {
1286                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1287                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1288
1289                         if (!track) {
1290                                 continue;
1291                         }
1292
1293                         if ((selected_channels & (0x0001 << chn)) == 0) {
1294                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1295                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1296                                 */
1297                                 changed = track->set_marked_for_display (false) || changed;
1298                         } else {
1299                                 changed = track->set_marked_for_display (true) || changed;
1300                         }
1301                 }
1302         }
1303
1304         no_redraw = false;
1305
1306         /* TODO: Bender, Pressure */
1307
1308         /* invalidate the controller menu, so that we rebuild it next time */
1309         _controller_menu_map.clear ();
1310         delete controller_menu;
1311         controller_menu = 0;
1312
1313         if (changed) {
1314                 request_redraw ();
1315         }
1316 }
1317
1318 Gtk::CheckMenuItem*
1319 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1320 {
1321         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1322         if (m) {
1323                 return m;
1324         }
1325
1326         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1327         if (i != _controller_menu_map.end()) {
1328                 return i->second;
1329         }
1330
1331         i = _channel_command_menu_map.find (param);
1332         if (i != _channel_command_menu_map.end()) {
1333                 return i->second;
1334         }
1335
1336         return 0;
1337 }
1338
1339 boost::shared_ptr<MidiRegion>
1340 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1341 {
1342         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1343
1344         real_editor->begin_reversible_command (Operations::create_region);
1345         playlist()->clear_changes ();
1346
1347         real_editor->snap_to (pos, 0);
1348
1349         boost::shared_ptr<Source> src = _session->create_midi_source_for_session (
1350                 view()->trackview().track().get(), view()->trackview().track()->name());
1351         PropertyList plist;
1352
1353         plist.add (ARDOUR::Properties::start, 0);
1354         plist.add (ARDOUR::Properties::length, length);
1355         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1356
1357         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1358
1359         playlist()->add_region (region, pos);
1360         _session->add_command (new StatefulDiffCommand (playlist()));
1361
1362         if (commit) {
1363                 real_editor->commit_reversible_command ();
1364         }
1365
1366         return boost::dynamic_pointer_cast<MidiRegion>(region);
1367 }
1368
1369 void
1370 MidiTimeAxisView::ensure_step_editor ()
1371 {
1372         if (!_step_editor) {
1373                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1374         }
1375 }
1376
1377 void
1378 MidiTimeAxisView::start_step_editing ()
1379 {
1380         ensure_step_editor ();
1381         _step_editor->start_step_editing ();
1382
1383 }
1384 void
1385 MidiTimeAxisView::stop_step_editing ()
1386 {
1387         if (_step_editor) {
1388                 _step_editor->stop_step_editing ();
1389         }
1390 }
1391
1392 /** @return channel (counted from 0) to add an event to, based on the current setting
1393  *  of the channel selector.
1394  */
1395 uint8_t
1396 MidiTimeAxisView::get_channel_for_add () const
1397 {
1398         uint16_t const chn_mask = _channel_selector.get_selected_channels ();
1399         int chn_cnt = 0;
1400         uint8_t channel = 0;
1401
1402         /* pick the highest selected channel, unless all channels are selected,
1403            which is interpreted to mean channel 1 (zero)
1404         */
1405
1406         for (uint16_t i = 0; i < 16; ++i) {
1407                 if (chn_mask & (1<<i)) {
1408                         channel = i;
1409                         chn_cnt++;
1410                 }
1411         }
1412
1413         if (chn_cnt == 16) {
1414                 channel = 0;
1415         }
1416
1417         return channel;
1418 }
1419
1420 void
1421 MidiTimeAxisView::note_range_changed ()
1422 {
1423         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1424         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1425 }
1426
1427 void
1428 MidiTimeAxisView::contents_height_changed ()
1429 {
1430         _range_scroomer->set_size_request (-1, _view->child_height ());
1431 }