start of tracking monitor state correctly
[ardour.git] / gtk2_ardour / route_ui.cc
1 /*
2     Copyright (C) 2002-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/choice.h>
22 #include <gtkmm2ext/doi.h>
23 #include <gtkmm2ext/bindable_button.h>
24 #include <gtkmm2ext/barcontroller.h>
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "ardour/route_group.h"
28 #include "ardour/dB.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/controllable.h"
32 #include "pbd/enumwriter.h"
33
34 #include "ardour_ui.h"
35 #include "editor.h"
36 #include "route_ui.h"
37 #include "led.h"
38 #include "keyboard.h"
39 #include "utils.h"
40 #include "prompter.h"
41 #include "gui_thread.h"
42 #include "ardour_dialog.h"
43 #include "latency_gui.h"
44 #include "mixer_strip.h"
45 #include "automation_time_axis.h"
46 #include "route_time_axis.h"
47 #include "group_tabs.h"
48
49 #include "ardour/route.h"
50 #include "ardour/event_type_map.h"
51 #include "ardour/session.h"
52 #include "ardour/audioengine.h"
53 #include "ardour/audio_track.h"
54 #include "ardour/midi_track.h"
55 #include "ardour/template_utils.h"
56 #include "ardour/filename_extensions.h"
57 #include "ardour/directory_names.h"
58 #include "ardour/profile.h"
59
60 #include "i18n.h"
61 using namespace Gtk;
62 using namespace Gtkmm2ext;
63 using namespace ARDOUR;
64 using namespace PBD;
65
66 uint32_t RouteUI::_max_invert_buttons = 3;
67
68 RouteUI::RouteUI (ARDOUR::Session* sess)
69         : AxisView(sess)
70 {
71         init ();
72 }
73
74 RouteUI::~RouteUI()
75 {
76         _route.reset (); /* drop reference to route, so that it can be cleaned up */
77         route_connections.drop_connections ();
78
79         delete solo_menu;
80         delete mute_menu;
81         delete sends_menu;
82         delete record_menu;
83         delete _invert_menu;
84 }
85
86 void
87 RouteUI::init ()
88 {
89         self_destruct = true;
90         mute_menu = 0;
91         solo_menu = 0;
92         sends_menu = 0;
93         record_menu = 0;
94         _invert_menu = 0;
95         pre_fader_mute_check = 0;
96         post_fader_mute_check = 0;
97         listen_mute_check = 0;
98         main_mute_check = 0;
99         solo_safe_check = 0;
100         solo_isolated_check = 0;
101         solo_isolated_led = 0;
102         solo_safe_led = 0;
103         _solo_release = 0;
104         _mute_release = 0;
105         denormal_menu_item = 0;
106         step_edit_item = 0;
107         multiple_mute_change = false;
108         multiple_solo_change = false;
109         _i_am_the_modifier = 0;
110
111         setup_invert_buttons ();
112
113         mute_button = manage (new BindableToggleButton ());
114         // mute_button->set_self_managed (true);
115         mute_button->set_name ("MuteButton");
116         mute_button->add (mute_button_label);
117         mute_button_label.show ();
118         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
119
120         solo_button = manage (new BindableToggleButton ());
121         // solo_button->set_self_managed (true);
122         solo_button->set_name ("SoloButton");
123         solo_button->add (solo_button_label);
124         solo_button_label.show ();
125         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
126         solo_button->set_no_show_all (true);
127
128         rec_enable_button = manage (new BindableToggleButton ());
129         rec_enable_button->set_name ("RecordEnableButton");
130         // rec_enable_button->set_self_managed (true);
131         rec_enable_button->add (rec_enable_button_label);
132         rec_enable_button_label.show ();
133         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
134
135         show_sends_button = manage (new BindableToggleButton (""));
136         show_sends_button->set_name ("SendAlert");
137         // show_sends_button->set_self_managed (true);
138         UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
139
140         monitor_input_button = manage (new BindableToggleButton ());
141         // monitor_input_button->set_self_managed (true);
142         monitor_input_button->set_name ("MonitorInputButton");
143         monitor_input_button->add (monitor_input_button_label);
144         monitor_input_button_label.show ();
145         UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
146         monitor_input_button->set_no_show_all (true);
147
148         monitor_disk_button = manage (new BindableToggleButton ());
149         // monitor_disk_button->set_self_managed (true);
150         monitor_disk_button->set_name ("MonitorDiskButton");
151         monitor_disk_button->add (monitor_disk_button_label);
152         monitor_disk_button_label.show ();
153         UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
154         monitor_disk_button->set_no_show_all (true);
155
156         _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
157         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
158         _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
159
160         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
161
162         rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
163         rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
164
165         show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
166         show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
167
168         solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
169         solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
170         mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
171         mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
172
173         monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
174         monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
175
176         monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
177         monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
178 }
179
180 void
181 RouteUI::reset ()
182 {
183         route_connections.drop_connections ();
184
185         delete solo_menu;
186         solo_menu = 0;
187
188         delete mute_menu;
189         mute_menu = 0;
190
191         denormal_menu_item = 0;
192 }
193
194 void
195 RouteUI::self_delete ()
196 {
197         delete this;
198 }
199
200 void
201 RouteUI::set_route (boost::shared_ptr<Route> rp)
202 {
203         reset ();
204
205         _route = rp;
206
207         if (set_color_from_route()) {
208                 set_color (unique_random_color());
209         }
210
211         if (self_destruct) {
212                 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
213         }
214
215         mute_button->set_controllable (_route->mute_control());
216         solo_button->set_controllable (_route->solo_control());
217
218         _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
219         _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
220
221         _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
222         _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
223         _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
224         _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
225
226         _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
227         _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
228
229         _route->io_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::setup_invert_buttons, this), gui_context ());
230         _route->gui_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
231
232         if (_session->writable() && is_track()) {
233                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
234
235                 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
236                 
237                 rec_enable_button->show();
238                 rec_enable_button->set_controllable (t->rec_enable_control());
239
240                 update_rec_display ();
241
242                 if (is_midi_track()) {
243                         midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
244                                                                     ui_bind (&RouteUI::step_edit_changed, this, _1), gui_context());
245                 }
246
247         }
248
249         if (is_track()) {
250                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
251                 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
252
253                 update_monitoring_display ();
254         }
255
256         mute_button->unset_flags (Gtk::CAN_FOCUS);
257         solo_button->unset_flags (Gtk::CAN_FOCUS);
258
259         mute_button->show();
260
261         if (_route->is_monitor()) {
262                 solo_button->hide ();
263         } else {
264                 solo_button->show();
265         }
266
267         map_frozen ();
268
269         setup_invert_buttons ();
270         set_invert_button_state ();
271 }
272
273 void
274 RouteUI::polarity_changed ()
275 {
276         if (!_route) {
277                 return;
278         }
279
280         set_invert_button_state ();
281 }
282
283 bool
284 RouteUI::mute_press (GdkEventButton* ev)
285 {
286         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
287                 return true;
288         }
289
290         multiple_mute_change = false;
291
292         if (!_i_am_the_modifier) {
293
294                 if (Keyboard::is_context_menu_event (ev)) {
295
296                         if (mute_menu == 0){
297                                 build_mute_menu();
298                         }
299
300                         mute_menu->popup(0,ev->time);
301
302                 } else {
303
304                         if (Keyboard::is_button2_event (ev)) {
305                                 // Primary-button2 click is the midi binding click
306                                 // button2-click is "momentary"
307
308
309                                 if (mute_button->on_button_press_event (ev)) {
310                                         return true;
311                                 }
312
313                                 _mute_release = new SoloMuteRelease (_route->muted ());
314                         }
315
316                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
317
318                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
319
320                                         if (_mute_release) {
321                                                 _mute_release->routes = _session->get_routes ();
322                                         }
323
324                                         _session->set_mute (_session->get_routes(), !_route->muted());
325
326                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
327
328                                         /* Primary-button1 applies change to the mix group even if it is not active
329                                            NOTE: Primary-button2 is MIDI learn.
330                                         */
331
332                                         if (ev->button == 1 && _route->route_group()) {
333                                                 if (_mute_release) {
334                                                         _mute_release->routes = _session->get_routes ();
335                                                 }
336
337                                                 _session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
338                                         }
339
340                                 } else {
341
342                                         /* plain click applies change to this route */
343
344                                         boost::shared_ptr<RouteList> rl (new RouteList);
345                                         rl->push_back (_route);
346
347                                         if (_mute_release) {
348                                                 _mute_release->routes = rl;
349                                         }
350
351                                         _session->set_mute (rl, !_route->muted());
352
353                                 }
354                         }
355                 }
356
357         }
358
359         return true;
360 }
361
362 bool
363 RouteUI::mute_release (GdkEventButton*)
364 {
365         if (!_i_am_the_modifier) {
366                 if (_mute_release){
367                         _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
368                         delete _mute_release;
369                         _mute_release = 0;
370                 }
371         }
372
373         return true;
374 }
375
376 bool
377 RouteUI::solo_press(GdkEventButton* ev)
378 {
379         /* ignore double/triple clicks */
380
381         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
382                 return true;
383         }
384
385         multiple_solo_change = false;
386
387         if (!_i_am_the_modifier) {
388
389                 if (Keyboard::is_context_menu_event (ev)) {
390
391                         if (!solo_isolated_led) {
392
393                                 if (solo_menu == 0) {
394                                         build_solo_menu ();
395                                 }
396
397                                 solo_menu->popup (1, ev->time);
398                         }
399
400                 } else {
401
402                         if (Keyboard::is_button2_event (ev)) {
403
404                                 // Primary-button2 click is the midi binding click
405                                 // button2-click is "momentary"
406
407                                 if (solo_button->on_button_press_event (ev)) {
408                                         return true;
409                                 }
410
411                                 _solo_release = new SoloMuteRelease (_route->self_soloed());
412                         }
413
414                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
415
416                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
417
418                                         /* Primary-Tertiary-click applies change to all routes */
419
420                                         if (_solo_release) {
421                                                 _solo_release->routes = _session->get_routes ();
422                                         }
423
424                                         if (Config->get_solo_control_is_listen_control()) {
425                                                 _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, true);
426                                         } else {
427                                                 _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, true);
428                                         }
429
430                                 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
431
432                                         // Primary-Secondary-click: exclusively solo this track
433
434                                         if (_solo_release) {
435                                                 _solo_release->exclusive = true;
436
437                                                 boost::shared_ptr<RouteList> routes = _session->get_routes();
438
439                                                 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
440                                                         if ((*i)->soloed ()) {
441                                                                 _solo_release->routes_on->push_back (*i);
442                                                         } else {
443                                                                 _solo_release->routes_off->push_back (*i);
444                                                         }
445                                                 }
446                                         }
447
448                                         if (Config->get_solo_control_is_listen_control()) {
449                                                 /* ??? we need a just_one_listen() method */
450                                         } else {
451                                                 _session->set_just_one_solo (_route, true);
452                                         }
453
454                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
455
456                                         // shift-click: toggle solo isolated status
457
458                                         _route->set_solo_isolated (!_route->solo_isolated(), this);
459                                         delete _solo_release;
460                                         _solo_release = 0;
461
462                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
463
464                                         /* Primary-button1: solo mix group.
465                                            NOTE: Primary-button2 is MIDI learn.
466                                         */
467
468                                         if (ev->button == 1 && _route->route_group()) {
469
470                                                 if (_solo_release) {
471                                                         _solo_release->routes = _route->route_group()->route_list();
472                                                 }
473
474                                                 if (Config->get_solo_control_is_listen_control()) {
475                                                         _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(),  Session::rt_cleanup, true);
476                                                 } else {
477                                                         _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(),  Session::rt_cleanup, true);
478                                                 }
479                                         }
480
481                                 } else {
482
483                                         /* click: solo this route */
484
485                                         boost::shared_ptr<RouteList> rl (new RouteList);
486                                         rl->push_back (route());
487
488                                         if (_solo_release) {
489                                                 _solo_release->routes = rl;
490                                         }
491
492                                         if (Config->get_solo_control_is_listen_control()) {
493                                                 _session->set_listen (rl, !_route->listening_via_monitor());
494                                         } else {
495                                                 _session->set_solo (rl, !_route->self_soloed());
496                                         }
497                                 }
498                         }
499                 }
500         }
501
502         return true;
503 }
504
505 bool
506 RouteUI::solo_release (GdkEventButton*)
507 {
508         if (!_i_am_the_modifier) {
509
510                 if (_solo_release) {
511
512                         if (_solo_release->exclusive) {
513
514                         } else {
515                                 if (Config->get_solo_control_is_listen_control()) {
516                                         _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
517                                 } else {
518                                         _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
519                                 }
520                         }
521
522                         delete _solo_release;
523                         _solo_release = 0;
524                 }
525         }
526
527         return true;
528 }
529
530 bool
531 RouteUI::rec_enable_press(GdkEventButton* ev)
532 {
533         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
534                 return true;
535         }
536
537         if (!_session->engine().connected()) {
538                 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
539                 msg.run ();
540                 return true;
541         }
542
543         if (is_midi_track()) {
544
545                 /* cannot rec-enable while step-editing */
546
547                 if (midi_track()->step_editing()) {
548                         return true;
549                 }
550         }
551
552         if (!_i_am_the_modifier && is_track() && rec_enable_button) {
553
554                 if (Keyboard::is_button2_event (ev)) {
555
556                         // do nothing on midi sigc::bind event
557                         return rec_enable_button->on_button_press_event (ev);
558
559                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
560
561                         _session->set_record_enabled (_session->get_routes(), !rec_enable_button->get_active());
562
563                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
564
565                         /* Primary-button1 applies change to the route group (even if it is not active)
566                            NOTE: Primary-button2 is MIDI learn.
567                         */
568                         if (ev->button == 1 && _route->route_group()) {
569                                 _session->set_record_enabled (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
570                         }
571
572                 } else if (Keyboard::is_context_menu_event (ev)) {
573
574                         /* do this on release */
575
576                 } else {
577
578                         boost::shared_ptr<RouteList> rl (new RouteList);
579                         rl->push_back (route());
580                         _session->set_record_enabled (rl, !rec_enable_button->get_active());
581                 }
582         }
583
584         return true;
585 }
586
587 void
588 RouteUI::monitoring_changed ()
589 {
590         update_monitoring_display ();
591 }
592
593 void
594 RouteUI::update_monitoring_display ()
595 {
596         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
597
598         if (!t) {
599                 return;
600         }
601
602         MonitorChoice mc = t->monitoring();
603
604         if (mc & MonitorInput) {
605                 monitor_input_button->set_visual_state (1);
606         } else {
607                 monitor_input_button->set_visual_state (0);
608         }
609
610         if (mc & MonitorDisk) {
611                 monitor_disk_button->set_visual_state (1);
612         } else {
613                 monitor_disk_button->set_visual_state (0);
614         }
615 }
616
617 bool
618 RouteUI::monitor_input_press(GdkEventButton* ev)
619 {
620         return true;
621 }
622
623 bool
624 RouteUI::monitor_input_release(GdkEventButton* ev)
625 {
626         return monitor_release (ev, MonitorInput);
627 }
628
629 bool
630 RouteUI::monitor_disk_press (GdkEventButton* ev)
631 {
632         return true;
633 }
634
635 bool
636 RouteUI::monitor_disk_release (GdkEventButton* ev)
637 {
638         return monitor_release (ev, MonitorDisk);
639 }
640
641 bool
642 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
643 {       
644         if (ev->button != 1) {
645                 return false;
646         }
647
648         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
649
650         if (!t) {
651                 return true;
652         }
653
654         MonitorChoice mc;
655         boost::shared_ptr<RouteList> rl;
656         
657         /* XXX for now, monitoring choices are orthogonal. cue monitoring 
658            will follow in 3.X but requires mixing the input and playback (disk)
659            signal together, which requires yet more buffers.
660         */
661
662         if (t->monitoring() & monitor_choice) {
663                 mc = MonitorChoice (t->monitoring() & ~monitor_choice);
664         } else {
665                 /* this line will change when the options are non-orthogonal */
666                 // mc = MonitorChoice (t->monitoring() | monitor_choice);
667                 mc = monitor_choice;
668         }
669
670         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {       
671                 rl = _session->get_routes ();
672
673         } else {
674                 rl.reset (new RouteList);
675                 rl->push_back (route());
676         }
677
678         _session->set_monitoring (rl, mc, Session::rt_cleanup, true);           
679
680         return true;
681 }
682
683 void
684 RouteUI::build_record_menu ()
685 {
686         if (record_menu) {
687                 return;
688         }
689
690         /* no rec-button context menu for non-MIDI tracks
691          */
692
693         if (is_midi_track()) {
694                 record_menu = new Menu;
695                 record_menu->set_name ("ArdourContextMenu");
696
697                 using namespace Menu_Helpers;
698                 MenuList& items = record_menu->items();
699
700                 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
701                 step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
702
703                 if (_route->record_enabled()) {
704                         step_edit_item->set_sensitive (false);
705                 }
706
707                 step_edit_item->set_active (midi_track()->step_editing());
708         }
709 }
710
711 void
712 RouteUI::toggle_step_edit ()
713 {
714         if (!is_midi_track() || _route->record_enabled()) {
715                 return;
716         }
717
718         midi_track()->set_step_editing (step_edit_item->get_active());
719 }
720
721 void
722 RouteUI::step_edit_changed (bool yn)
723 {
724         if (yn) {
725                 if (rec_enable_button) {
726                         rec_enable_button->set_visual_state (3);
727                 }
728
729                 start_step_editing ();
730
731                 if (step_edit_item) {
732                         step_edit_item->set_active (true);
733                 }
734
735         } else {
736
737                 if (rec_enable_button) {
738                         rec_enable_button->set_visual_state (0);
739                 }
740
741                 stop_step_editing ();
742
743                 if (step_edit_item) {
744                         step_edit_item->set_active (false);
745                 }
746         }
747 }
748
749 bool
750 RouteUI::rec_enable_release (GdkEventButton* ev)
751 {
752         if (Keyboard::is_context_menu_event (ev)) {
753                 build_record_menu ();
754                 if (record_menu) {
755                         record_menu->popup (1, ev->time);
756                 }
757                 return true;
758         }
759
760         return true;
761 }
762
763 void
764 RouteUI::build_sends_menu ()
765 {
766         using namespace Menu_Helpers;
767
768         sends_menu = new Menu;
769         sends_menu->set_name ("ArdourContextMenu");
770         MenuList& items = sends_menu->items();
771
772         items.push_back (
773                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
774                 );
775
776         items.push_back (
777                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
778                 );
779
780         items.push_back (
781                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
782                 );
783
784         items.push_back (
785                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
786                 );
787
788         items.push_back (
789                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
790                 );
791
792         items.push_back (
793                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
794
795         items.push_back (
796                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
797                 );
798
799         items.push_back (
800                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
801                 );
802
803         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
804         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
805         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
806
807 }
808
809 void
810 RouteUI::create_sends (Placement p, bool include_buses)
811 {
812         _session->globally_add_internal_sends (_route, p, include_buses);
813 }
814
815 void
816 RouteUI::create_selected_sends (Placement p, bool include_buses)
817 {
818         boost::shared_ptr<RouteList> rlist (new RouteList);
819         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
820
821         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
822                 RouteTimeAxisView* rtv;
823                 RouteUI* rui;
824                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
825                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
826                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
827                                         rlist->push_back (rui->route());
828                                 }
829                         }
830                 }
831         }
832
833         _session->add_internal_sends (_route, p, rlist);
834 }
835
836 void
837 RouteUI::set_sends_gain_from_track ()
838 {
839         _session->globally_set_send_gains_from_track (_route);
840 }
841
842 void
843 RouteUI::set_sends_gain_to_zero ()
844 {
845         _session->globally_set_send_gains_to_zero (_route);
846 }
847
848 void
849 RouteUI::set_sends_gain_to_unity ()
850 {
851         _session->globally_set_send_gains_to_unity (_route);
852 }
853
854 bool
855 RouteUI::show_sends_press(GdkEventButton* ev)
856 {
857         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
858                 return true;
859         }
860
861         if (!_i_am_the_modifier && !is_track() && show_sends_button) {
862
863                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
864
865                         // do nothing on midi sigc::bind event
866                         return false;
867
868                 } else if (Keyboard::is_context_menu_event (ev)) {
869
870                         if (sends_menu == 0) {
871                                 build_sends_menu ();
872                         }
873
874                         sends_menu->popup (0, ev->time);
875
876                 } else {
877
878                         /* change button state */
879
880                         show_sends_button->set_active (!show_sends_button->get_active());
881
882                         /* start blinking */
883
884                         if (show_sends_button->get_active()) {
885                                 /* show sends to this bus */
886                                 MixerStrip::SwitchIO (_route);
887                                 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun(*this, &RouteUI::send_blink));
888                         } else {
889                                 /* everybody back to normal */
890                                 send_blink_connection.disconnect ();
891                                 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
892                         }
893
894                 }
895         }
896
897         return true;
898 }
899
900 bool
901 RouteUI::show_sends_release (GdkEventButton*)
902 {
903         return true;
904 }
905
906 void
907 RouteUI::send_blink (bool onoff)
908 {
909         if (!show_sends_button) {
910                 return;
911         }
912
913         if (onoff) {
914                 show_sends_button->set_state (STATE_ACTIVE);
915         } else {
916                 show_sends_button->set_state (STATE_NORMAL);
917         }
918 }
919
920 int
921 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
922 {
923         if (r->is_master() || r->is_monitor()) {
924                 return 0;
925         }
926
927         if (Config->get_solo_control_is_listen_control()) {
928
929                 if (r->listening_via_monitor()) {
930                         return 1;
931                 } else {
932                         return 0;
933                 }
934
935         }
936
937         if (r->soloed()) {
938                 if (!r->self_soloed()) {
939                         return 3;
940                 } else {
941                         return 1;
942                 }
943         } else {
944                 return 0;
945         }
946 }
947
948 int
949 RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
950 {
951         if (r->is_master() || r->is_monitor()) {
952                 return 0;
953         }
954
955         if (Config->get_solo_control_is_listen_control()) {
956
957                 if (r->listening_via_monitor()) {
958                         return 1;
959                 } else {
960                         return 0;
961                 }
962
963         }
964
965         if (r->solo_isolated()) {
966                 return 2;
967         } else if (r->soloed()) {
968                 if (!r->self_soloed()) {
969                         return 3;
970                 } else {
971                         return 1;
972                 }
973         } else {
974                 return 0;
975         }
976 }
977
978 int
979 RouteUI::solo_isolate_visual_state (boost::shared_ptr<Route> r)
980 {
981         if (r->is_master() || r->is_monitor()) {
982                 return 0;
983         }
984
985         if (r->solo_isolated()) {
986                 return 1;
987         } else {
988                 return 0;
989         }
990 }
991
992 int
993 RouteUI::solo_safe_visual_state (boost::shared_ptr<Route> r)
994 {
995         if (r->is_master() || r->is_monitor()) {
996                 return 0;
997         }
998
999         if (r->solo_safe()) {
1000                 return 1;
1001         } else {
1002                 return 0;
1003         }
1004 }
1005
1006 void
1007 RouteUI::update_solo_display ()
1008 {
1009         bool x;
1010
1011         if (Config->get_solo_control_is_listen_control()) {
1012
1013                 if (solo_button->get_active() != (x = _route->listening_via_monitor())) {
1014                         ++_i_am_the_modifier;
1015                         solo_button->set_active(x);
1016                         --_i_am_the_modifier;
1017                 }
1018
1019         } else {
1020
1021                 if (solo_button->get_active() != (x = _route->soloed())) {
1022                         ++_i_am_the_modifier;
1023                         solo_button->set_active (x);
1024                         --_i_am_the_modifier;
1025                 }
1026
1027         }
1028
1029         bool yn = _route->solo_safe ();
1030
1031         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1032                 solo_safe_check->set_active (yn);
1033         }
1034
1035         yn = _route->solo_isolated ();
1036
1037         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1038                 solo_isolated_check->set_active (yn);
1039         }
1040
1041         set_button_names ();
1042
1043         if (solo_isolated_led) {
1044                 solo_isolated_led->set_visual_state (_route->solo_isolated() ? 1 : 0);
1045         }
1046
1047         if (solo_safe_led) {
1048                 solo_safe_led->set_visual_state (_route->solo_safe() ? 1 : 0);
1049         }
1050
1051         solo_button->set_visual_state (solo_visual_state (_route));
1052
1053         /* some changes to solo status can affect mute display, so catch up
1054          */
1055
1056         update_mute_display ();
1057 }
1058
1059 void
1060 RouteUI::solo_changed_so_update_mute ()
1061 {
1062         update_mute_display ();
1063 }
1064
1065 void
1066 RouteUI::mute_changed(void* /*src*/)
1067 {
1068         update_mute_display ();
1069 }
1070
1071 int
1072 RouteUI::mute_visual_state (Session* s, boost::shared_ptr<Route> r)
1073 {
1074         if (r->is_master() || r->is_monitor()) {
1075                 return 0;
1076         }
1077
1078
1079         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1080
1081                 if (r->muted ()) {
1082                         /* full mute */
1083                         return 2;
1084                 } else if (s->soloing() && !r->soloed() && !r->solo_isolated()) {
1085                         return 1;
1086                 } else {
1087                         /* no mute at all */
1088                         return 0;
1089                 }
1090
1091         } else {
1092
1093                 if (r->muted()) {
1094                         /* full mute */
1095                         return 2;
1096                 } else {
1097                         /* no mute at all */
1098                         return 0;
1099                 }
1100         }
1101
1102         return 0;
1103 }
1104
1105 void
1106 RouteUI::update_mute_display ()
1107 {
1108         if (!_route) {
1109                 return;
1110         }
1111
1112         bool model = _route->muted();
1113         bool view = mute_button->get_active();
1114
1115         /* first make sure the button's "depressed" visual
1116            is correct.
1117         */
1118
1119         if (model != view) {
1120                 ++_i_am_the_modifier;
1121                 mute_button->set_active (model);
1122                 --_i_am_the_modifier;
1123         }
1124
1125         mute_button->set_visual_state (mute_visual_state (_session, _route));
1126 }
1127
1128 void
1129 RouteUI::route_rec_enable_changed ()
1130 {
1131         update_rec_display ();
1132 }
1133
1134 void
1135 RouteUI::session_rec_enable_changed ()
1136 {
1137         update_rec_display ();
1138 }
1139
1140 void
1141 RouteUI::update_rec_display ()
1142 {
1143         if (!rec_enable_button || !_route) {
1144                 return;
1145         }
1146
1147         bool model = _route->record_enabled();
1148         bool view = rec_enable_button->get_active();
1149
1150         /* first make sure the button's "depressed" visual
1151            is correct.
1152         */
1153
1154         if (model != view) {
1155                 ++_i_am_the_modifier;
1156                 rec_enable_button->set_active (model);
1157                 --_i_am_the_modifier;
1158         }
1159
1160         /* now make sure its color state is correct */
1161
1162         if (model) {
1163                 switch (_session->record_status ()) {
1164                 case Session::Recording:
1165                         rec_enable_button->set_visual_state (1);
1166                         break;
1167
1168                 case Session::Disabled:
1169                 case Session::Enabled:
1170                         rec_enable_button->set_visual_state (2);
1171                         break;
1172
1173                 }
1174
1175                 if (step_edit_item) {
1176                         step_edit_item->set_sensitive (false);
1177                 }
1178
1179         } else {
1180                 rec_enable_button->set_visual_state (0);
1181
1182                 if (step_edit_item) {
1183                         step_edit_item->set_sensitive (true);
1184                 }
1185         }
1186
1187
1188         check_rec_enable_sensitivity ();
1189 }
1190
1191 void
1192 RouteUI::build_solo_menu (void)
1193 {
1194         using namespace Menu_Helpers;
1195
1196         solo_menu = new Menu;
1197         solo_menu->set_name ("ArdourContextMenu");
1198         MenuList& items = solo_menu->items();
1199         CheckMenuItem* check;
1200
1201         check = new CheckMenuItem(_("Solo Isolate"));
1202         check->set_active (_route->solo_isolated());
1203         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1204         items.push_back (CheckMenuElem(*check));
1205         solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
1206         check->show_all();
1207
1208         check = new CheckMenuItem(_("Solo Safe"));
1209         check->set_active (_route->solo_safe());
1210         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1211         items.push_back (CheckMenuElem(*check));
1212         solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
1213         check->show_all();
1214
1215         //items.push_back (SeparatorElem());
1216         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1217
1218 }
1219
1220 void
1221 RouteUI::build_mute_menu(void)
1222 {
1223         using namespace Menu_Helpers;
1224
1225         mute_menu = new Menu;
1226         mute_menu->set_name ("ArdourContextMenu");
1227
1228         MenuList& items = mute_menu->items();
1229
1230         pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
1231         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1232         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1233         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1234         pre_fader_mute_check->show_all();
1235
1236         post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
1237         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1238         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1239         items.push_back (CheckMenuElem(*post_fader_mute_check));
1240         post_fader_mute_check->show_all();
1241
1242         listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
1243         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1244         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1245         items.push_back (CheckMenuElem(*listen_mute_check));
1246         listen_mute_check->show_all();
1247
1248         main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
1249         init_mute_menu(MuteMaster::Main, main_mute_check);
1250         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1251         items.push_back (CheckMenuElem(*main_mute_check));
1252         main_mute_check->show_all();
1253
1254         //items.push_back (SeparatorElem());
1255         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1256
1257         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1258 }
1259
1260 void
1261 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1262 {
1263         check->set_active (_route->mute_points() & mp);
1264 }
1265
1266 void
1267 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1268 {
1269         if (check->get_active()) {
1270                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1271         } else {
1272                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1273         }
1274 }
1275
1276 void
1277 RouteUI::muting_change ()
1278 {
1279         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1280
1281         bool yn;
1282         MuteMaster::MutePoint current = _route->mute_points ();
1283
1284         yn = (current & MuteMaster::PreFader);
1285
1286         if (pre_fader_mute_check->get_active() != yn) {
1287                 pre_fader_mute_check->set_active (yn);
1288         }
1289
1290         yn = (current & MuteMaster::PostFader);
1291
1292         if (post_fader_mute_check->get_active() != yn) {
1293                 post_fader_mute_check->set_active (yn);
1294         }
1295
1296         yn = (current & MuteMaster::Listen);
1297
1298         if (listen_mute_check->get_active() != yn) {
1299                 listen_mute_check->set_active (yn);
1300         }
1301
1302         yn = (current & MuteMaster::Main);
1303
1304         if (main_mute_check->get_active() != yn) {
1305                 main_mute_check->set_active (yn);
1306         }
1307 }
1308
1309 bool
1310 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1311 {
1312         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1313                 return true;
1314         }
1315
1316         bool view = (solo_isolated_led->visual_state() != 0);
1317         bool model = _route->solo_isolated();
1318
1319         /* called BEFORE the view has changed */
1320
1321         if (ev->button == 1) {
1322                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1323
1324                         if (model) {
1325                                 /* disable isolate for all routes */
1326                                 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1327                         }
1328
1329                 } else {
1330                         if (model == view) {
1331
1332                                 /* flip just this route */
1333
1334                                 boost::shared_ptr<RouteList> rl (new RouteList);
1335                                 rl->push_back (_route);
1336                                 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1337                         }
1338                 }
1339         }
1340
1341         return true;
1342 }
1343
1344 bool
1345 RouteUI::solo_safe_button_release (GdkEventButton*)
1346 {
1347         _route->set_solo_safe (!(solo_safe_led->visual_state() > 0), this);
1348         return true;
1349 }
1350
1351 void
1352 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1353 {
1354         bool view = check->get_active();
1355         bool model = _route->solo_isolated();
1356
1357         /* called AFTER the view has changed */
1358
1359         if (model != view) {
1360                 _route->set_solo_isolated (view, this);
1361         }
1362 }
1363
1364 void
1365 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1366 {
1367         _route->set_solo_safe (check->get_active(), this);
1368 }
1369
1370 /** Ask the user to choose a colour, and then set all selected tracks
1371  *  to that colour.
1372  */
1373 void
1374 RouteUI::choose_color ()
1375 {
1376         bool picked;
1377         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1378
1379         if (picked) {
1380                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
1381                         boost::bind (&RouteUI::set_color, _1, color)
1382                         );
1383         }
1384 }
1385
1386 /** Set the route's own color.  This may not be used for display if
1387  *  the route is in a group which shares its color with its routes.
1388  */
1389 void
1390 RouteUI::set_color (const Gdk::Color & c)
1391 {
1392         char buf[64];
1393
1394         _color = c;
1395
1396         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1397
1398         /* note: we use the route state ID here so that color is the same for both
1399            the time axis view and the mixer strip
1400         */
1401         
1402         gui_object_state().set<string> (route_state_id(), X_("color"), buf);
1403         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1404 }
1405
1406 /** @return GUI state ID for things that are common to the route in all its representations */
1407 string
1408 RouteUI::route_state_id () const
1409 {
1410         return string_compose (X_("route %1"), _route->id().to_s());
1411 }
1412
1413 int
1414 RouteUI::set_color_from_route ()
1415 {
1416         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1417
1418         if (str.empty()) {
1419                 return 1;
1420         }
1421
1422         int r, g, b;
1423
1424         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1425
1426         _color.set_red (r);
1427         _color.set_green (g);
1428         _color.set_blue (b);
1429
1430         return 0;
1431 }
1432
1433 void
1434 RouteUI::remove_this_route (bool apply_to_selection)
1435 {
1436         if (apply_to_selection) {
1437                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1438         } else {
1439                 if ((route()->is_master() || route()->is_monitor()) &&
1440                     !Config->get_allow_special_bus_removal()) {
1441                         MessageDialog msg (_("That would be bad news ...."),
1442                                            false,
1443                                            Gtk::MESSAGE_INFO,
1444                                    Gtk::BUTTONS_OK);
1445                         msg.set_secondary_text (string_compose (_(
1446 "Removing the master or monitor bus is such a bad idea\n\
1447 that %1 is not going to allow it.\n\
1448 \n\
1449 If you really want to do this sort of thing\n\
1450 edit your ardour.rc file to set the\n\
1451 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1452
1453                         msg.present ();
1454                         msg.run ();
1455                         return;
1456                 }
1457
1458                 vector<string> choices;
1459                 string prompt;
1460
1461                 if (is_track()) {
1462                         prompt  = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1463                 } else {
1464                         prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1465                 }
1466
1467                 choices.push_back (_("No, do nothing."));
1468                 choices.push_back (_("Yes, remove it."));
1469
1470                 string title;
1471                 if (is_track()) {
1472                         title = _("Remove track");
1473                 } else {
1474                         title = _("Remove bus");
1475                 }
1476
1477                 Choice prompter (title, prompt, choices);
1478
1479                 if (prompter.run () == 1) {
1480                         Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1481                 }
1482         }
1483 }
1484
1485 gint
1486 RouteUI::idle_remove_this_route (RouteUI *rui)
1487 {
1488         rui->_session->remove_route (rui->route());
1489         return false;
1490 }
1491
1492 /** @return true if this name should be used for the route, otherwise false */
1493 bool
1494 RouteUI::verify_new_route_name (const std::string& name)
1495 {
1496         if (name.find (':') == string::npos) {
1497                 return true;
1498         }
1499         
1500         MessageDialog colon_msg (
1501                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1502                 false, MESSAGE_QUESTION, BUTTONS_NONE
1503                 );
1504         
1505         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1506         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1507
1508         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1509 }
1510
1511 void
1512 RouteUI::route_rename ()
1513 {
1514         ArdourPrompter name_prompter (true);
1515         string result;
1516         bool done = false;
1517
1518         if (is_track()) {
1519                 name_prompter.set_title (_("Rename Track"));
1520         } else {
1521                 name_prompter.set_title (_("Rename Bus"));
1522         }
1523         name_prompter.set_prompt (_("New name:"));
1524         name_prompter.set_initial_text (_route->name());
1525         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1526         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1527         name_prompter.show_all ();
1528
1529         while (!done) {
1530                 switch (name_prompter.run ()) {
1531                 case Gtk::RESPONSE_ACCEPT:
1532                         name_prompter.get_result (result);
1533                         name_prompter.hide ();
1534                         if (result.length()) {
1535                                 if (verify_new_route_name (result)) {
1536                                         _route->set_name (result);
1537                                         done = true;
1538                                 } else {
1539                                         /* back to name prompter */
1540                                 }
1541
1542                         } else {
1543                                 /* nothing entered, just get out of here */
1544                                 done = true;
1545                         }
1546                         break;
1547                 }
1548         }
1549
1550         return;
1551
1552 }
1553
1554 void
1555 RouteUI::property_changed (const PropertyChange& what_changed)
1556 {
1557         if (what_changed.contains (ARDOUR::Properties::name)) {
1558                 name_label.set_text (_route->name());
1559         }
1560 }
1561
1562 void
1563 RouteUI::set_route_active (bool a, bool apply_to_selection)
1564 {
1565         if (apply_to_selection) {
1566                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1567         } else {
1568                 _route->set_active (a, this);
1569         }
1570 }
1571
1572 void
1573 RouteUI::toggle_denormal_protection ()
1574 {
1575         if (denormal_menu_item) {
1576
1577                 bool x;
1578
1579                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1580
1581                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1582                         _route->set_denormal_protection (x);
1583                 }
1584         }
1585 }
1586
1587 void
1588 RouteUI::denormal_protection_changed ()
1589 {
1590         if (denormal_menu_item) {
1591                 denormal_menu_item->set_active (_route->denormal_protection());
1592         }
1593 }
1594
1595 void
1596 RouteUI::disconnect_input ()
1597 {
1598         _route->input()->disconnect (this);
1599 }
1600
1601 void
1602 RouteUI::disconnect_output ()
1603 {
1604         _route->output()->disconnect (this);
1605 }
1606
1607 bool
1608 RouteUI::is_track () const
1609 {
1610         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1611 }
1612
1613 boost::shared_ptr<Track>
1614 RouteUI::track() const
1615 {
1616         return boost::dynamic_pointer_cast<Track>(_route);
1617 }
1618
1619 bool
1620 RouteUI::is_audio_track () const
1621 {
1622         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1623 }
1624
1625 boost::shared_ptr<AudioTrack>
1626 RouteUI::audio_track() const
1627 {
1628         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1629 }
1630
1631 bool
1632 RouteUI::is_midi_track () const
1633 {
1634         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1635 }
1636
1637 boost::shared_ptr<MidiTrack>
1638 RouteUI::midi_track() const
1639 {
1640         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1641 }
1642
1643 bool
1644 RouteUI::has_audio_outputs () const
1645 {
1646         return (_route->n_outputs().n_audio() > 0);
1647 }
1648
1649 string
1650 RouteUI::name() const
1651 {
1652         return _route->name();
1653 }
1654
1655 void
1656 RouteUI::map_frozen ()
1657 {
1658         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1659
1660         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1661
1662         if (at) {
1663                 switch (at->freeze_state()) {
1664                 case AudioTrack::Frozen:
1665                         rec_enable_button->set_sensitive (false);
1666                         break;
1667                 default:
1668                         rec_enable_button->set_sensitive (true);
1669                         break;
1670                 }
1671         }
1672 }
1673
1674 void
1675 RouteUI::adjust_latency ()
1676 {
1677         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1678 }
1679
1680 void
1681 RouteUI::save_as_template ()
1682 {
1683         sys::path path;
1684         std::string safe_name;
1685         string name;
1686
1687         path = ARDOUR::user_route_template_directory ();
1688
1689         if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1690                 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1691                 return;
1692         }
1693
1694         Prompter p (true); // modal
1695
1696         p.set_title (_("Save As Template"));
1697         p.set_prompt (_("Template name:"));
1698         p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1699         switch (p.run()) {
1700         case RESPONSE_ACCEPT:
1701                 break;
1702         default:
1703                 return;
1704         }
1705
1706         p.hide ();
1707         p.get_result (name, true);
1708
1709         safe_name = legalize_for_path (name);
1710         safe_name += template_suffix;
1711
1712         path /= safe_name;
1713
1714         _route->save_as_template (path.to_string(), name);
1715 }
1716
1717 void
1718 RouteUI::check_rec_enable_sensitivity ()
1719 {
1720         if (_session->transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1721                 rec_enable_button->set_sensitive (false);
1722         } else {
1723                 rec_enable_button->set_sensitive (true);
1724         }
1725 }
1726
1727 void
1728 RouteUI::parameter_changed (string const & p)
1729 {
1730         if (p == "disable-disarm-during-roll") {
1731                 check_rec_enable_sensitivity ();
1732         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1733                 set_button_names ();
1734         }
1735 }
1736
1737 void
1738 RouteUI::step_gain_up ()
1739 {
1740         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1741 }
1742
1743 void
1744 RouteUI::page_gain_up ()
1745 {
1746         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1747 }
1748
1749 void
1750 RouteUI::step_gain_down ()
1751 {
1752         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1753 }
1754
1755 void
1756 RouteUI::page_gain_down ()
1757 {
1758         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1759 }
1760
1761 void
1762 RouteUI::open_remote_control_id_dialog ()
1763 {
1764         ArdourDialog dialog (_("Remote Control ID"));
1765
1766         uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1767
1768         HBox* hbox = manage (new HBox);
1769         hbox->set_spacing (6);
1770         hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1771         SpinButton* spin = manage (new SpinButton);
1772         spin->set_digits (0);
1773         spin->set_increments (1, 10);
1774         spin->set_range (0, limit);
1775         spin->set_value (_route->remote_control_id());
1776         hbox->pack_start (*spin);
1777         dialog.get_vbox()->pack_start (*hbox);
1778
1779         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1780         dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1781
1782         dialog.show_all ();
1783         int const r = dialog.run ();
1784
1785         if (r == RESPONSE_ACCEPT) {
1786                 _route->set_remote_control_id (spin->get_value_as_int ());
1787         }
1788 }
1789
1790 void
1791 RouteUI::setup_invert_buttons ()
1792 {
1793         /* remove old invert buttons */
1794         for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1795                 _invert_button_box.remove (**i);
1796         }
1797
1798         _invert_buttons.clear ();
1799
1800         if (!_route || !_route->input()) {
1801                 return;
1802         }
1803
1804         uint32_t const N = _route->input()->n_ports().n_audio ();
1805
1806         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1807
1808         for (uint32_t i = 0; i < to_add; ++i) {
1809                 BindableToggleButton* b = manage (new BindableToggleButton);
1810                 b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
1811                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1812
1813                 b->set_name (X_("MixerInvertButton"));
1814                 if (to_add == 1) {
1815                         b->add (*manage (new Label (X_("Ø"))));
1816                 } else {
1817                         b->add (*manage (new Label (string_compose (X_("Ø%1"), i + 1))));
1818                 }
1819
1820                 if (N <= 4) {
1821                         UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track.  Right-click to show menu."), i + 1));
1822                 } else {
1823                         UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) all channels of this track.  Right-click to show menu."), i + 1));
1824                 }
1825
1826                 _invert_buttons.push_back (b);
1827                 _invert_button_box.pack_start (*b);
1828         }
1829
1830         _invert_button_box.show_all ();
1831 }
1832
1833 void
1834 RouteUI::set_invert_button_state ()
1835 {
1836         ++_i_am_the_modifier;
1837
1838         uint32_t const N = _route->input()->n_ports().n_audio();
1839         if (N > _max_invert_buttons) {
1840                 _invert_buttons.front()->set_active (_route->phase_invert().any());
1841                 --_i_am_the_modifier;
1842                 return;
1843         }
1844
1845         int j = 0;
1846         for (list<BindableToggleButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1847                 (*i)->set_active (_route->phase_invert (j));
1848         }
1849
1850         --_i_am_the_modifier;
1851 }
1852
1853 void
1854 RouteUI::invert_toggled (uint32_t i, BindableToggleButton* b)
1855 {
1856         if (_i_am_the_modifier) {
1857                 return;
1858         }
1859
1860         uint32_t const N = _route->input()->n_ports().n_audio();
1861         if (N <= _max_invert_buttons) {
1862                 _route->set_phase_invert (i, b->get_active ());
1863         } else {
1864                 boost::dynamic_bitset<> p (N);
1865                 if (b->get_active ()) {
1866                         p.set ();
1867                 }
1868                 _route->set_phase_invert (p);
1869         }
1870 }
1871
1872 bool
1873 RouteUI::invert_press (GdkEventButton* ev)
1874 {
1875         using namespace Menu_Helpers;
1876
1877         if (ev->button != 3) {
1878                 return true;
1879         }
1880
1881         delete _invert_menu;
1882         _invert_menu = new Menu;
1883         _invert_menu->set_name ("ArdourContextMenu");
1884         MenuList& items = _invert_menu->items ();
1885
1886         uint32_t const N = _route->input()->n_ports().n_audio();
1887         for (uint32_t i = 0; i < N; ++i) {
1888                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
1889                 CheckMenuItem* e = dynamic_cast<CheckMenuItem*> (&items.back ());
1890                 ++_i_am_the_modifier;
1891                 e->set_active (_route->phase_invert (i));
1892                 --_i_am_the_modifier;
1893         }
1894
1895         _invert_menu->popup (0, ev->time);
1896
1897         return false;
1898 }
1899
1900 void
1901 RouteUI::invert_menu_toggled (uint32_t c)
1902 {
1903         if (_i_am_the_modifier) {
1904                 return;
1905         }
1906
1907         _route->set_phase_invert (c, !_route->phase_invert (c));
1908 }
1909
1910 void
1911 RouteUI::set_invert_sensitive (bool yn)
1912 {
1913         for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
1914                 (*b)->set_sensitive (yn);
1915         }
1916 }
1917
1918 void
1919 RouteUI::request_redraw ()
1920 {
1921         if (_route) {
1922                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
1923         }
1924 }
1925
1926 /** The Route's gui_changed signal has been emitted */
1927 void
1928 RouteUI::route_gui_changed (string what_changed)
1929 {
1930         if (what_changed == "color") {
1931                 if (set_color_from_route () == 0) {
1932                         route_color_changed ();
1933                 }
1934         }
1935 }
1936
1937 /** @return the color that this route should use; it maybe its own,
1938     or it maybe that of its route group.
1939 */
1940 Gdk::Color
1941 RouteUI::color () const
1942 {
1943         RouteGroup* g = _route->route_group ();
1944         
1945         if (g && g->is_color()) {
1946                 return GroupTabs::group_color (g);
1947         }
1948
1949         return _color;
1950 }