Fix border case where bank select controlers are last in midnam file.
[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                                         if (n_items == 0) {
843                                                 /* Create a new submenu */
844                                                 ctl_menu = manage (new Menu);
845                                         }
846                                 
847                                         MenuList& ctl_items (ctl_menu->items());
848                                         if (chn_cnt > 1) {
849                                                 add_multi_channel_controller_item(ctl_items, ctl, c->second->name());
850                                         } else {
851                                                 add_single_channel_controller_item(ctl_items, ctl, c->second->name());
852                                         }
853                                 }
854
855                                 ++c;
856                                 if (ctl_menu && (++n_items == 16 || c == name_list->controls().end())) {
857                                         /* Submenu has 16 items or we're done, add it to controller menu and reset */
858                                         items.push_back(
859                                                 MenuElem(string_compose(_("Controllers %1-%2"),
860                                                                         (16 * n_groups), (16 * n_groups) + n_items - 1),
861                                                          *ctl_menu));
862                                         ctl_menu = NULL;
863                                         n_items  = 0;
864                                         ++n_groups;
865                                 }
866                         }
867                 }
868         } else {
869                 /* No controllers names, generate generic numeric menu */
870                 for (int i = 0; i < 127; i += 16) {
871                         Menu*     ctl_menu = manage (new Menu);
872                         MenuList& ctl_items (ctl_menu->items());
873
874                         for (int ctl = i; ctl < i+16; ++ctl) {
875                                 if (ctl == MIDI_CTL_MSB_BANK || ctl == MIDI_CTL_LSB_BANK) {
876                                         /* Skip bank select controllers since they're handled specially */
877                                         continue;
878                                 }
879
880                                 if (chn_cnt > 1) {
881                                         add_multi_channel_controller_item(
882                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
883                                 } else {
884                                         add_single_channel_controller_item(
885                                                 ctl_items, ctl, string_compose(_("Controller %1"), ctl));
886                                 }
887                         }
888
889                         /* Add submenu for this block of controllers to controller menu */
890                         items.push_back (
891                                 MenuElem (string_compose (_("Controllers %1-%2"), i, i + 15),
892                                           *ctl_menu));
893                 }
894         }
895 }
896
897 Gtk::Menu*
898 MidiTimeAxisView::build_note_mode_menu()
899 {
900         using namespace Menu_Helpers;
901
902         Menu* mode_menu = manage (new Menu);
903         MenuList& items = mode_menu->items();
904         mode_menu->set_name ("ArdourContextMenu");
905
906         RadioMenuItem::Group mode_group;
907         items.push_back (
908                 RadioMenuElem (mode_group,_("Sustained"),
909                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
910                                            Sustained, true)));
911         _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
912         _note_mode_item->set_active(_note_mode == Sustained);
913
914         items.push_back (
915                 RadioMenuElem (mode_group, _("Percussive"),
916                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_mode),
917                                            Percussive, true)));
918         _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
919         _percussion_mode_item->set_active(_note_mode == Percussive);
920
921         return mode_menu;
922 }
923
924 Gtk::Menu*
925 MidiTimeAxisView::build_color_mode_menu()
926 {
927         using namespace Menu_Helpers;
928
929         Menu* mode_menu = manage (new Menu);
930         MenuList& items = mode_menu->items();
931         mode_menu->set_name ("ArdourContextMenu");
932
933         RadioMenuItem::Group mode_group;
934         items.push_back (
935                 RadioMenuElem (mode_group, _("Meter Colors"),
936                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
937                                            MeterColors, false, true, true)));
938         _meter_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
939         _meter_color_mode_item->set_active(_color_mode == MeterColors);
940
941         items.push_back (
942                 RadioMenuElem (mode_group, _("Channel Colors"),
943                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
944                                            ChannelColors, false, true, true)));
945         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
946         _channel_color_mode_item->set_active(_color_mode == ChannelColors);
947
948         items.push_back (
949                 RadioMenuElem (mode_group, _("Track Color"),
950                                sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_color_mode),
951                                            TrackColor, false, true, true)));
952         _channel_color_mode_item = dynamic_cast<RadioMenuItem*>(&items.back());
953         _channel_color_mode_item->set_active(_color_mode == TrackColor);
954
955         return mode_menu;
956 }
957
958 void
959 MidiTimeAxisView::set_note_mode(NoteMode mode, bool apply_to_selection)
960 {
961         if (apply_to_selection) {
962                 _editor.get_selection().tracks.foreach_midi_time_axis (
963                         boost::bind (&MidiTimeAxisView::set_note_mode, _1, mode, false));
964         } else {
965                 if (_note_mode != mode || midi_track()->note_mode() != mode) {
966                         _note_mode = mode;
967                         midi_track()->set_note_mode(mode);
968                         set_gui_property ("note-mode", enum_2_string(_note_mode));
969                         _view->redisplay_track();
970                 }
971         }
972 }
973
974 void
975 MidiTimeAxisView::set_color_mode (ColorMode mode, bool force, bool redisplay, bool apply_to_selection)
976 {
977         if (apply_to_selection) {
978                 _editor.get_selection().tracks.foreach_midi_time_axis (
979                         boost::bind (&MidiTimeAxisView::set_color_mode, _1, mode, force, redisplay, false));
980         } else {
981                 if (_color_mode == mode && !force) {
982                         return;
983                 }
984                 
985                 if (mode == ChannelColors) {
986                         _channel_selector.set_channel_colors(CanvasNoteEvent::midi_channel_colors);
987                 } else {
988                         _channel_selector.set_default_channel_color();
989                 }
990                 
991                 _color_mode = mode;
992                 set_gui_property ("color-mode", enum_2_string(_color_mode));
993                 if (redisplay) {
994                         _view->redisplay_track();
995                 }
996         }
997 }
998
999 void
1000 MidiTimeAxisView::set_note_range (MidiStreamView::VisibleNoteRange range, bool apply_to_selection)
1001 {
1002         if (apply_to_selection) {
1003                 _editor.get_selection().tracks.foreach_midi_time_axis (
1004                         boost::bind (&MidiTimeAxisView::set_note_range, _1, range, false));
1005         } else {
1006                 if (!_ignore_signals) {
1007                         midi_view()->set_note_range(range);
1008                 }
1009         }
1010 }
1011
1012 void
1013 MidiTimeAxisView::update_range()
1014 {
1015         MidiGhostRegion* mgr;
1016
1017         for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
1018                 if ((mgr = dynamic_cast<MidiGhostRegion*>(*i)) != 0) {
1019                         mgr->update_range();
1020                 }
1021         }
1022 }
1023
1024 void
1025 MidiTimeAxisView::show_all_automation (bool apply_to_selection)
1026 {
1027         if (apply_to_selection) {
1028                 _editor.get_selection().tracks.foreach_midi_time_axis (
1029                         boost::bind (&MidiTimeAxisView::show_all_automation, _1, false));
1030         } else {
1031                 if (midi_track()) {
1032                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1033
1034                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1035                                 create_automation_child(*i, true);
1036                         }
1037                 }
1038
1039                 RouteTimeAxisView::show_all_automation ();
1040         }
1041 }
1042
1043 void
1044 MidiTimeAxisView::show_existing_automation (bool apply_to_selection)
1045 {
1046         if (apply_to_selection) {
1047                 _editor.get_selection().tracks.foreach_midi_time_axis (
1048                         boost::bind (&MidiTimeAxisView::show_existing_automation, _1, false));
1049         } else {
1050                 if (midi_track()) {
1051                         const set<Evoral::Parameter> params = midi_track()->midi_playlist()->contained_automation();
1052
1053                         for (set<Evoral::Parameter>::const_iterator i = params.begin(); i != params.end(); ++i) {
1054                                 create_automation_child (*i, true);
1055                         }
1056                 }
1057
1058                 RouteTimeAxisView::show_existing_automation ();
1059         }
1060 }
1061
1062 /** Create an automation track for the given parameter (pitch bend, channel pressure).
1063  */
1064 void
1065 MidiTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
1066 {
1067         if (param.type() == NullAutomation) {
1068                 return;
1069         }
1070
1071         AutomationTracks::iterator existing = _automation_tracks.find (param);
1072
1073         if (existing != _automation_tracks.end()) {
1074
1075                 /* automation track created because we had existing data for
1076                  * the processor, but visibility may need to be controlled
1077                  * since it will have been set visible by default.
1078                  */
1079
1080                 if (existing->second->set_marked_for_display (show) && !no_redraw) {
1081                         request_redraw ();
1082                 }
1083
1084                 return;
1085         }
1086
1087         boost::shared_ptr<AutomationTimeAxisView> track;
1088
1089         switch (param.type()) {
1090
1091         case GainAutomation:
1092                 create_gain_automation_child (param, show);
1093                 break;
1094
1095         case PluginAutomation:
1096                 /* handled elsewhere */
1097                 break;
1098
1099         case MidiCCAutomation:
1100         case MidiPgmChangeAutomation:
1101         case MidiPitchBenderAutomation:
1102         case MidiChannelPressureAutomation:
1103         case MidiSystemExclusiveAutomation:
1104                 /* These controllers are region "automation" - they are owned
1105                  * by regions (and their MidiModels), not by the track. As a
1106                  * result we do not create an AutomationList/Line for the track
1107                  * ... except here we are doing something!! XXX 
1108                  */
1109
1110                 track.reset (new AutomationTimeAxisView (
1111                                      _session,
1112                                      _route,
1113                                      boost::shared_ptr<Automatable> (),
1114                                      boost::shared_ptr<AutomationControl> (),
1115                                      param,
1116                                      _editor,
1117                                      *this,
1118                                      true,
1119                                      parent_canvas,
1120                                      _route->describe_parameter(param)));
1121
1122                 if (_view) {
1123                         _view->foreach_regionview (
1124                                 sigc::mem_fun (*track.get(), &TimeAxisView::add_ghost));
1125                 }
1126
1127                 add_automation_child (param, track, show);
1128                 break;
1129
1130         default:
1131                 error << "MidiTimeAxisView: unknown automation child "
1132                       << EventTypeMap::instance().to_symbol(param) << endmsg;
1133         }
1134 }
1135
1136 void
1137 MidiTimeAxisView::route_active_changed ()
1138 {
1139         RouteUI::route_active_changed ();
1140
1141         if (is_track()) {
1142                 if (_route->active()) {
1143                         controls_ebox.set_name ("MidiTrackControlsBaseUnselected");
1144                         controls_base_selected_name = "MidiTrackControlsBaseSelected";
1145                         controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
1146                 } else {
1147                         controls_ebox.set_name ("MidiTrackControlsBaseInactiveUnselected");
1148                         controls_base_selected_name = "MidiTrackControlsBaseInactiveSelected";
1149                         controls_base_unselected_name = "MidiTrackControlsBaseInactiveUnselected";
1150                 }
1151         } else {
1152                 if (_route->active()) {
1153                         controls_ebox.set_name ("BusControlsBaseUnselected");
1154                         controls_base_selected_name = "BusControlsBaseSelected";
1155                         controls_base_unselected_name = "BusControlsBaseUnselected";
1156                 } else {
1157                         controls_ebox.set_name ("BusControlsBaseInactiveUnselected");
1158                         controls_base_selected_name = "BusControlsBaseInactiveSelected";
1159                         controls_base_unselected_name = "BusControlsBaseInactiveUnselected";
1160                 }
1161         }
1162 }
1163
1164 void
1165 MidiTimeAxisView::set_note_selection (uint8_t note)
1166 {
1167         if (!_editor.internal_editing()) {
1168                 return;
1169         }
1170
1171         uint16_t chn_mask = _channel_selector.get_selected_channels();
1172
1173         if (_view->num_selected_regionviews() == 0) {
1174                 _view->foreach_regionview (
1175                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1176                                     note, chn_mask));
1177         } else {
1178                 _view->foreach_selected_regionview (
1179                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::set_note_selection_region_view),
1180                                     note, chn_mask));
1181         }
1182 }
1183
1184 void
1185 MidiTimeAxisView::add_note_selection (uint8_t note)
1186 {
1187         if (!_editor.internal_editing()) {
1188                 return;
1189         }
1190
1191         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1192
1193         if (_view->num_selected_regionviews() == 0) {
1194                 _view->foreach_regionview (
1195                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1196                                     note, chn_mask));
1197         } else {
1198                 _view->foreach_selected_regionview (
1199                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::add_note_selection_region_view),
1200                                     note, chn_mask));
1201         }
1202 }
1203
1204 void
1205 MidiTimeAxisView::extend_note_selection (uint8_t note)
1206 {
1207         if (!_editor.internal_editing()) {
1208                 return;
1209         }
1210
1211         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1212
1213         if (_view->num_selected_regionviews() == 0) {
1214                 _view->foreach_regionview (
1215                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1216                                     note, chn_mask));
1217         } else {
1218                 _view->foreach_selected_regionview (
1219                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::extend_note_selection_region_view),
1220                                     note, chn_mask));
1221         }
1222 }
1223
1224 void
1225 MidiTimeAxisView::toggle_note_selection (uint8_t note)
1226 {
1227         if (!_editor.internal_editing()) {
1228                 return;
1229         }
1230
1231         const uint16_t chn_mask = _channel_selector.get_selected_channels();
1232
1233         if (_view->num_selected_regionviews() == 0) {
1234                 _view->foreach_regionview (
1235                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1236                                     note, chn_mask));
1237         } else {
1238                 _view->foreach_selected_regionview (
1239                         sigc::bind (sigc::mem_fun (*this, &MidiTimeAxisView::toggle_note_selection_region_view),
1240                                     note, chn_mask));
1241         }
1242 }
1243
1244 void
1245 MidiTimeAxisView::set_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1246 {
1247         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, false, false);
1248 }
1249
1250 void
1251 MidiTimeAxisView::add_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1252 {
1253         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, false);
1254 }
1255
1256 void
1257 MidiTimeAxisView::extend_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1258 {
1259         dynamic_cast<MidiRegionView*>(rv)->select_matching_notes (note, chn_mask, true, true);
1260 }
1261
1262 void
1263 MidiTimeAxisView::toggle_note_selection_region_view (RegionView* rv, uint8_t note, uint16_t chn_mask)
1264 {
1265         dynamic_cast<MidiRegionView*>(rv)->toggle_matching_notes (note, chn_mask);
1266 }
1267
1268 void
1269 MidiTimeAxisView::set_channel_mode (ChannelMode, uint16_t)
1270 {
1271         /* hide all automation tracks that use the wrong channel(s) and show all those that use
1272            the right ones.
1273         */
1274
1275         const uint16_t selected_channels = _channel_selector.get_selected_channels();
1276         bool changed = false;
1277
1278         no_redraw = true;
1279
1280         for (uint32_t ctl = 0; ctl < 127; ++ctl) {
1281
1282                 for (uint32_t chn = 0; chn < 16; ++chn) {
1283                         Evoral::Parameter fully_qualified_param (MidiCCAutomation, chn, ctl);
1284                         boost::shared_ptr<AutomationTimeAxisView> track = automation_child (fully_qualified_param);
1285
1286                         if (!track) {
1287                                 continue;
1288                         }
1289
1290                         if ((selected_channels & (0x0001 << chn)) == 0) {
1291                                 /* channel not in use. hiding it will trigger RouteTimeAxisView::automation_track_hidden()
1292                                    which will cause a redraw. We don't want one per channel, so block that with no_redraw.
1293                                 */
1294                                 changed = track->set_marked_for_display (false) || changed;
1295                         } else {
1296                                 changed = track->set_marked_for_display (true) || changed;
1297                         }
1298                 }
1299         }
1300
1301         no_redraw = false;
1302
1303         /* TODO: Bender, Pressure */
1304
1305         /* invalidate the controller menu, so that we rebuild it next time */
1306         _controller_menu_map.clear ();
1307         delete controller_menu;
1308         controller_menu = 0;
1309
1310         if (changed) {
1311                 request_redraw ();
1312         }
1313 }
1314
1315 Gtk::CheckMenuItem*
1316 MidiTimeAxisView::automation_child_menu_item (Evoral::Parameter param)
1317 {
1318         Gtk::CheckMenuItem* m = RouteTimeAxisView::automation_child_menu_item (param);
1319         if (m) {
1320                 return m;
1321         }
1322
1323         ParameterMenuMap::iterator i = _controller_menu_map.find (param);
1324         if (i != _controller_menu_map.end()) {
1325                 return i->second;
1326         }
1327
1328         i = _channel_command_menu_map.find (param);
1329         if (i != _channel_command_menu_map.end()) {
1330                 return i->second;
1331         }
1332
1333         return 0;
1334 }
1335
1336 boost::shared_ptr<MidiRegion>
1337 MidiTimeAxisView::add_region (framepos_t pos, framecnt_t length, bool commit)
1338 {
1339         Editor* real_editor = dynamic_cast<Editor*> (&_editor);
1340
1341         real_editor->begin_reversible_command (Operations::create_region);
1342         playlist()->clear_changes ();
1343
1344         real_editor->snap_to (pos, 0);
1345
1346         boost::shared_ptr<Source> src = _session->create_midi_source_for_session (
1347                 view()->trackview().track().get(), view()->trackview().track()->name());
1348         PropertyList plist;
1349
1350         plist.add (ARDOUR::Properties::start, 0);
1351         plist.add (ARDOUR::Properties::length, length);
1352         plist.add (ARDOUR::Properties::name, PBD::basename_nosuffix(src->name()));
1353
1354         boost::shared_ptr<Region> region = (RegionFactory::create (src, plist));
1355
1356         playlist()->add_region (region, pos);
1357         _session->add_command (new StatefulDiffCommand (playlist()));
1358
1359         if (commit) {
1360                 real_editor->commit_reversible_command ();
1361         }
1362
1363         return boost::dynamic_pointer_cast<MidiRegion>(region);
1364 }
1365
1366 void
1367 MidiTimeAxisView::ensure_step_editor ()
1368 {
1369         if (!_step_editor) {
1370                 _step_editor = new StepEditor (_editor, midi_track(), *this);
1371         }
1372 }
1373
1374 void
1375 MidiTimeAxisView::start_step_editing ()
1376 {
1377         ensure_step_editor ();
1378         _step_editor->start_step_editing ();
1379
1380 }
1381 void
1382 MidiTimeAxisView::stop_step_editing ()
1383 {
1384         if (_step_editor) {
1385                 _step_editor->stop_step_editing ();
1386         }
1387 }
1388
1389 /** @return channel (counted from 0) to add an event to, based on the current setting
1390  *  of the channel selector.
1391  */
1392 uint8_t
1393 MidiTimeAxisView::get_channel_for_add () const
1394 {
1395         uint16_t const chn_mask = _channel_selector.get_selected_channels ();
1396         int chn_cnt = 0;
1397         uint8_t channel = 0;
1398
1399         /* pick the highest selected channel, unless all channels are selected,
1400            which is interpreted to mean channel 1 (zero)
1401         */
1402
1403         for (uint16_t i = 0; i < 16; ++i) {
1404                 if (chn_mask & (1<<i)) {
1405                         channel = i;
1406                         chn_cnt++;
1407                 }
1408         }
1409
1410         if (chn_cnt == 16) {
1411                 channel = 0;
1412         }
1413
1414         return channel;
1415 }
1416
1417 void
1418 MidiTimeAxisView::note_range_changed ()
1419 {
1420         set_gui_property ("note-range-min", (int) midi_view()->lowest_note ());
1421         set_gui_property ("note-range-max", (int) midi_view()->highest_note ());
1422 }
1423
1424 void
1425 MidiTimeAxisView::contents_height_changed ()
1426 {
1427         _range_scroomer->set_size_request (-1, _view->child_height ());
1428 }