initial implementation of VCA time axis views
[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 <boost/algorithm/string.hpp>
21
22 #include <gtkmm2ext/gtk_ui.h>
23 #include <gtkmm2ext/choice.h>
24 #include <gtkmm2ext/doi.h>
25 #include <gtkmm2ext/bindable_button.h>
26 #include <gtkmm2ext/barcontroller.h>
27 #include <gtkmm2ext/gtk_ui.h>
28 #include <gtkmm2ext/utils.h>
29
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
34
35 #include "ardour/dB.h"
36 #include "ardour/route_group.h"
37 #include "ardour/solo_isolate_control.h"
38 #include "ardour/vca.h"
39 #include "ardour/vca_manager.h"
40 #include "ardour/audio_track.h"
41 #include "ardour/audioengine.h"
42 #include "ardour/filename_extensions.h"
43 #include "ardour/midi_track.h"
44 #include "ardour/monitor_control.h"
45 #include "ardour/internal_send.h"
46 #include "ardour/profile.h"
47 #include "ardour/phase_control.h"
48 #include "ardour/send.h"
49 #include "ardour/route.h"
50 #include "ardour/session.h"
51 #include "ardour/template_utils.h"
52
53 #include "ardour_ui.h"
54 #include "editor.h"
55 #include "route_ui.h"
56 #include "ardour_button.h"
57 #include "keyboard.h"
58 #include "utils.h"
59 #include "plugin_pin_dialog.h"
60 #include "prompter.h"
61 #include "gui_thread.h"
62 #include "ardour_dialog.h"
63 #include "latency_gui.h"
64 #include "mixer_strip.h"
65 #include "automation_time_axis.h"
66 #include "route_time_axis.h"
67 #include "group_tabs.h"
68 #include "timers.h"
69 #include "ui_config.h"
70
71
72 #include "i18n.h"
73 using namespace Gtk;
74 using namespace Gtkmm2ext;
75 using namespace ARDOUR;
76 using namespace ARDOUR_UI_UTILS;
77 using namespace PBD;
78 using namespace std;
79
80 uint32_t RouteUI::_max_invert_buttons = 3;
81 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
82 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
83 std::string RouteUI::program_port_prefix;
84
85 RouteUI::RouteUI (ARDOUR::Session* sess)
86         : AxisView(sess)
87         , mute_menu(0)
88         , solo_menu(0)
89         , sends_menu(0)
90         , record_menu(0)
91         , comment_window(0)
92         , comment_area(0)
93         , input_selector (0)
94         , output_selector (0)
95         , _invert_menu(0)
96 {
97         if (program_port_prefix.empty()) {
98                 // compare to gtk2_ardour/port_group.cc
99                 string lpn (PROGRAM_NAME);
100                 boost::to_lower (lpn);
101                 program_port_prefix = lpn + ":"; // e.g. "ardour:"
102         }
103         if (sess) init ();
104 }
105
106 RouteUI::~RouteUI()
107 {
108         if (_route) {
109                 gui_object_state().remove_node (route_state_id());
110         }
111
112         _route.reset (); /* drop reference to route, so that it can be cleaned up */
113         route_connections.drop_connections ();
114
115         delete solo_menu;
116         delete mute_menu;
117         delete sends_menu;
118         delete record_menu;
119         delete comment_window;
120         delete input_selector;
121         delete output_selector;
122         delete _invert_menu;
123
124         send_blink_connection.disconnect ();
125         rec_blink_connection.disconnect ();
126 }
127
128 void
129 RouteUI::init ()
130 {
131         self_destruct = true;
132         mute_menu = 0;
133         solo_menu = 0;
134         sends_menu = 0;
135         record_menu = 0;
136         _invert_menu = 0;
137         pre_fader_mute_check = 0;
138         post_fader_mute_check = 0;
139         listen_mute_check = 0;
140         main_mute_check = 0;
141         solo_safe_check = 0;
142         solo_isolated_check = 0;
143         solo_isolated_led = 0;
144         solo_safe_led = 0;
145         _solo_release = 0;
146         _mute_release = 0;
147         denormal_menu_item = 0;
148         step_edit_item = 0;
149         rec_safe_item = 0;
150         multiple_mute_change = false;
151         multiple_solo_change = false;
152         _i_am_the_modifier = 0;
153         vca_button = 0;
154
155         input_selector = 0;
156         output_selector = 0;
157
158         setup_invert_buttons ();
159
160         mute_button = manage (new ArdourButton);
161         mute_button->set_name ("mute button");
162         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
163
164         solo_button = manage (new ArdourButton);
165         solo_button->set_name ("solo button");
166         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
167         solo_button->set_no_show_all (true);
168
169         rec_enable_button = manage (new ArdourButton);
170         rec_enable_button->set_name ("record enable button");
171         rec_enable_button->set_icon (ArdourIcon::RecButton);
172         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
173
174         if (UIConfiguration::instance().get_blink_rec_arm()) {
175                 rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
176         }
177
178         show_sends_button = manage (new ArdourButton);
179         show_sends_button->set_name ("send alert button");
180         UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
181
182         monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
183         monitor_input_button->set_name ("monitor button");
184         monitor_input_button->set_text (_("In"));
185         UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
186         monitor_input_button->set_no_show_all (true);
187
188         monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
189         monitor_disk_button->set_name ("monitor button");
190         monitor_disk_button->set_text (_("Disk"));
191         UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
192         monitor_disk_button->set_no_show_all (true);
193
194         _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
195         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
196         _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
197
198         _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
199         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
200
201         rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
202         rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
203
204         show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
205         show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release), false);
206
207         solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
208         solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
209         mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
210         mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
211
212         monitor_input_button->set_distinct_led_click (false);
213         monitor_disk_button->set_distinct_led_click (false);
214
215         monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press), false);
216         monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release), false);
217
218         monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press), false);
219         monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release), false);
220
221         BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
222 }
223
224 void
225 RouteUI::reset ()
226 {
227         route_connections.drop_connections ();
228
229         delete solo_menu;
230         solo_menu = 0;
231
232         delete mute_menu;
233         mute_menu = 0;
234
235         denormal_menu_item = 0;
236 }
237
238 void
239 RouteUI::self_delete ()
240 {
241         delete this;
242 }
243
244 void
245 RouteUI::set_route (boost::shared_ptr<Route> rp)
246 {
247         reset ();
248
249         _route = rp;
250
251         if (set_color_from_route()) {
252                 set_color (unique_random_color());
253         }
254
255         if (self_destruct) {
256                 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
257         }
258
259         delete input_selector;
260         input_selector = 0;
261
262         delete output_selector;
263         output_selector = 0;
264
265         mute_button->set_controllable (_route->mute_control());
266         solo_button->set_controllable (_route->solo_control());
267
268         _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
269
270         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
271
272         _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
273         _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
274         _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
275         _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
276         _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
277
278         if (is_track()) {
279                 track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteUI::map_frozen, this), gui_context());
280                 track()->TrackModeChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::track_mode_changed, this), gui_context());
281                 track_mode_changed();
282         }
283
284
285         _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
286
287         _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
288         _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
289
290         if (_session->writable() && is_track()) {
291                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
292
293                 t->rec_enable_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
294                 t->rec_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
295
296                 rec_enable_button->show();
297                 rec_enable_button->set_controllable (t->rec_enable_control());
298
299                 if (is_midi_track()) {
300                         midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
301                                                                     boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
302                 }
303
304         }
305
306         /* this will work for busses and tracks, and needs to be called to
307            set up the name entry/name label display.
308         */
309
310         if (is_track()) {
311                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
312                 t->monitoring_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_monitoring_display, this), gui_context());
313
314                 update_monitoring_display ();
315         }
316
317         mute_button->unset_flags (Gtk::CAN_FOCUS);
318         solo_button->unset_flags (Gtk::CAN_FOCUS);
319
320         mute_button->show();
321
322         if (_route->is_monitor() || _route->is_master()) {
323                 solo_button->hide ();
324         } else {
325                 solo_button->show();
326         }
327
328         map_frozen ();
329
330         setup_invert_buttons ();
331         set_invert_button_state ();
332
333         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
334         bus_send_display_changed (s);
335
336         update_mute_display ();
337         update_solo_display ();
338
339         if (!UIConfiguration::instance().get_blink_rec_arm()) {
340                 blink_rec_display(true); // set initial rec-en button state
341         }
342
343         check_rec_enable_sensitivity ();
344         maybe_add_route_print_mgr ();
345         route_color_changed();
346 }
347
348 void
349 RouteUI::polarity_changed ()
350 {
351         if (!_route) {
352                 return;
353         }
354
355         set_invert_button_state ();
356 }
357
358 bool
359 RouteUI::mute_press (GdkEventButton* ev)
360 {
361         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
362                 return true;
363         }
364
365         //if this is a binding action, let the ArdourButton handle it
366         if ( BindingProxy::is_bind_action(ev) )
367                 return false;
368
369         multiple_mute_change = false;
370
371         if (Keyboard::is_context_menu_event (ev)) {
372
373                 if (mute_menu == 0){
374                         build_mute_menu();
375                 }
376
377                 mute_menu->popup(0,ev->time);
378
379                 return true;
380
381         } else {
382
383                 if (Keyboard::is_button2_event (ev)) {
384                         // button2-click is "momentary"
385
386                         _mute_release = new SoloMuteRelease (_route->mute_control()->muted ());
387                 }
388
389                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
390
391                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
392
393                                 /* toggle mute on everything (but
394                                  * exclude the master and monitor)
395                                  *
396                                  * because we are going to erase
397                                  * elements of the list we need to work
398                                  * on a copy.
399                                  */
400
401                                 boost::shared_ptr<RouteList> copy (new RouteList);
402
403                                 *copy = *_session->get_routes ();
404
405                                 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
406                                         if ((*i)->is_master() || (*i)->is_monitor()) {
407                                                 i = copy->erase (i);
408                                         } else {
409                                                 ++i;
410                                         }
411                                 }
412
413                                 if (_mute_release) {
414                                         _mute_release->routes = copy;
415                                 }
416
417                                 DisplaySuspender ds;
418                                 _session->set_controls (route_list_to_control_list (copy, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
419
420                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
421
422                                 /* Primary-button1 inverts the implication of
423                                    the group being active. If the group is
424                                    active (for mute), then this modifier means
425                                    "do not apply to mute". If the group is
426                                    inactive (for mute), then this modifier
427                                    means "apply to route". This is all
428                                    accomplished by passing just the actual
429                                    route, along with the InverseGroup group
430                                    control disposition.
431
432                                    NOTE: Primary-button2 is MIDI learn.
433                                 */
434
435                                 boost::shared_ptr<RouteList> rl;
436
437                                 if (ev->button == 1) {
438
439                                         rl.reset (new RouteList);
440                                         rl->push_back (_route);
441
442                                         if (_mute_release) {
443                                                 _mute_release->routes = rl;
444                                         }
445
446                                         DisplaySuspender ds;
447                                         _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), _route->muted_by_self() ? 0.0 : 1.0, Controllable::InverseGroup);
448                                 }
449
450                         } else {
451
452                                 /* plain click applies change to this route */
453
454                                 boost::shared_ptr<RouteList> rl (new RouteList);
455                                 rl->push_back (_route);
456
457                                 if (_mute_release) {
458                                         _mute_release->routes = rl;
459                                 }
460
461                                 _session->set_control (_route->mute_control(), _route->muted_by_self() ? 0.0 : 1.0, Controllable::UseGroup);
462
463                         }
464                 }
465         }
466
467         return false;
468 }
469
470 bool
471 RouteUI::mute_release (GdkEventButton* /*ev*/)
472 {
473         if (_mute_release){
474                 DisplaySuspender ds;
475                 _session->set_controls (route_list_to_control_list (_mute_release->routes, &Route::mute_control), _mute_release->active, Controllable::UseGroup);
476                 delete _mute_release;
477                 _mute_release = 0;
478         }
479
480         return false;
481 }
482
483 void
484 RouteUI::edit_output_configuration ()
485 {
486         if (output_selector == 0) {
487
488                 boost::shared_ptr<Send> send;
489                 boost::shared_ptr<IO> output;
490
491                 if ((send = boost::dynamic_pointer_cast<Send>(_current_delivery)) != 0) {
492                         if (!boost::dynamic_pointer_cast<InternalSend>(send)) {
493                                 output = send->output();
494                         } else {
495                                 output = _route->output ();
496                         }
497                 } else {
498                         output = _route->output ();
499                 }
500
501                 output_selector = new IOSelectorWindow (_session, output);
502         }
503
504         if (output_selector->is_visible()) {
505                 output_selector->get_toplevel()->get_window()->raise();
506         } else {
507                 output_selector->present ();
508         }
509
510         //output_selector->set_keep_above (true);
511 }
512
513 void
514 RouteUI::edit_input_configuration ()
515 {
516         if (input_selector == 0) {
517                 input_selector = new IOSelectorWindow (_session, _route->input());
518         }
519
520         if (input_selector->is_visible()) {
521                 input_selector->get_toplevel()->get_window()->raise();
522         } else {
523                 input_selector->present ();
524         }
525
526         //input_selector->set_keep_above (true);
527 }
528
529 bool
530 RouteUI::solo_press(GdkEventButton* ev)
531 {
532         /* ignore double/triple clicks */
533
534         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
535                 return true;
536         }
537
538         //if this is a binding action, let the ArdourButton handle it
539         if ( BindingProxy::is_bind_action(ev) )
540                 return false;
541
542         multiple_solo_change = false;
543
544         if (Keyboard::is_context_menu_event (ev)) {
545
546                 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
547                     ! (solo_safe_led && solo_safe_led->is_visible())) {
548
549                         if (solo_menu == 0) {
550                                 build_solo_menu ();
551                         }
552
553                         solo_menu->popup (1, ev->time);
554                 }
555
556         } else {
557
558                 if (Keyboard::is_button2_event (ev)) {
559
560                         // button2-click is "momentary"
561                         _solo_release = new SoloMuteRelease (_route->self_soloed());
562                 }
563
564                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
565
566                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
567
568                                 /* Primary-Tertiary-click applies change to all routes */
569
570                                 if (_solo_release) {
571                                         _solo_release->routes = _session->get_routes ();
572                                 }
573
574                                 DisplaySuspender ds;
575                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_control), !_route->solo_control()->get_value(), Controllable::UseGroup);
576
577                         } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
578
579                                 // Primary-Secondary-click: exclusively solo this track
580
581                                 if (_solo_release) {
582                                         _solo_release->exclusive = true;
583
584                                         boost::shared_ptr<RouteList> routes = _session->get_routes();
585
586                                         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
587                                                 if ((*i)->soloed ()) {
588                                                         _solo_release->routes_on->push_back (*i);
589                                                 } else {
590                                                         _solo_release->routes_off->push_back (*i);
591                                                 }
592                                         }
593                                 }
594
595                                 if (Config->get_solo_control_is_listen_control()) {
596                                         /* ??? we need a just_one_listen() method */
597                                 } else {
598                                         DisplaySuspender ds;
599                                         boost::shared_ptr<ControlList> cl (new ControlList);
600                                         cl->push_back (_route->solo_control());
601                                         _session->set_controls (cl, 1.0, Controllable::NoGroup);
602                                 }
603
604                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
605
606                                 // shift-click: toggle solo isolated status
607
608                                 _route->solo_isolate_control()->set_value (_route->solo_isolate_control()->get_value() ? 0.0 : 1.0, Controllable::UseGroup);
609                                 delete _solo_release;
610                                 _solo_release = 0;
611
612                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
613
614                                 /* Primary-button1: solo mix group.
615                                    NOTE: Primary-button2 is MIDI learn.
616                                 */
617
618                                 /* Primary-button1 applies change to the mix group even if it is not active
619                                    NOTE: Primary-button2 is MIDI learn.
620                                 */
621
622                                 boost::shared_ptr<RouteList> rl;
623
624                                 if (ev->button == 1) {
625
626                                         /* Primary-button1 inverts the implication of
627                                            the group being active. If the group is
628                                            active (for solo), then this modifier means
629                                            "do not apply to solo". If the group is
630                                            inactive (for mute), then this modifier
631                                            means "apply to route". This is all
632                                            accomplished by passing just the actual
633                                            route, along with the InverseGroup group
634                                            control disposition.
635
636                                            NOTE: Primary-button2 is MIDI learn.
637                                         */
638
639                                         rl.reset (new RouteList);
640                                         rl->push_back (_route);
641
642                                         if (_solo_release) {
643                                                 _solo_release->routes = rl;
644                                         }
645
646                                         DisplaySuspender ds;
647
648                                         _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::InverseGroup);
649                                 }
650
651                                 delete _solo_release;
652                                 _solo_release = 0;
653
654                         } else {
655
656                                 /* click: solo this route */
657
658                                 boost::shared_ptr<RouteList> rl (new RouteList);
659                                 rl->push_back (route());
660
661                                 if (_solo_release) {
662                                         _solo_release->routes = rl;
663                                 }
664
665                                 DisplaySuspender ds;
666                                 _session->set_controls (route_list_to_control_list (rl, &Route::solo_control), !_route->self_soloed(), Controllable::UseGroup);
667                         }
668                 }
669         }
670
671         return false;
672 }
673
674 bool
675 RouteUI::solo_release (GdkEventButton* /*ev*/)
676 {
677         if (_solo_release) {
678
679                 if (_solo_release->exclusive) {
680
681                 } else {
682                         DisplaySuspender ds;
683                         _session->set_controls (route_list_to_control_list (_solo_release->routes, &Route::solo_control), _solo_release->active ? 1.0 : 0.0, Controllable::UseGroup);
684                 }
685
686                 delete _solo_release;
687                 _solo_release = 0;
688         }
689
690         return false;
691 }
692
693 bool
694 RouteUI::rec_enable_press(GdkEventButton* ev)
695 {
696         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
697                 return true;
698         }
699
700         //if this is a binding action, let the ArdourButton handle it
701         if ( BindingProxy::is_bind_action(ev) )
702                 return false;
703
704         if (!_session->engine().connected()) {
705                 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
706                 msg.run ();
707                 return false;
708         }
709
710         if (is_midi_track()) {
711
712                 /* rec-enable button exits from step editing */
713
714                 if (midi_track()->step_editing()) {
715                         midi_track()->set_step_editing (false);
716                         return false;
717                 }
718         }
719
720         if (is_track() && rec_enable_button) {
721
722                 if (Keyboard::is_button2_event (ev)) {
723
724                         //rec arm does not have a momentary mode
725                         return false;
726
727                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
728
729                         DisplaySuspender ds;
730                         _session->set_controls (route_list_to_control_list (_session->get_routes(), &Track::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::NoGroup);
731
732                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
733
734                         /* Primary-button1 applies change to the route group (even if it is not active)
735                            NOTE: Primary-button2 is MIDI learn.
736                         */
737
738                         if (ev->button == 1) {
739
740                                 boost::shared_ptr<RouteList> rl;
741
742                                 rl.reset (new RouteList);
743                                 rl->push_back (_route);
744
745                                 DisplaySuspender ds;
746                                 _session->set_controls (route_list_to_control_list (rl, &Track::rec_enable_control), !track()->rec_enable_control()->get_value(), Controllable::InverseGroup);
747                         }
748
749                 } else if (Keyboard::is_context_menu_event (ev)) {
750
751                         /* do this on release */
752
753                 } else {
754
755                         boost::shared_ptr<Track> trk = track();
756                         _session->set_control (trk->rec_enable_control(), !trk->rec_enable_control()->get_value(), Controllable::UseGroup);
757                 }
758         }
759
760         return false;
761 }
762
763 void
764 RouteUI::update_monitoring_display ()
765 {
766         if (!_route) {
767                 return;
768         }
769
770         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
771
772         if (!t) {
773                 return;
774         }
775
776         MonitorState ms = t->monitoring_state();
777
778         if (t->monitoring_control()->monitoring_choice() & MonitorInput) {
779                 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
780         } else {
781                 if (ms & MonitoringInput) {
782                         monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
783                 } else {
784                         monitor_input_button->unset_active_state ();
785                 }
786         }
787
788         if (t->monitoring_control()->monitoring_choice() & MonitorDisk) {
789                 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
790         } else {
791                 if (ms & MonitoringDisk) {
792                         monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
793                 } else {
794                         monitor_disk_button->unset_active_state ();
795                 }
796         }
797 }
798
799 bool
800 RouteUI::monitor_input_press(GdkEventButton*)
801 {
802         return false;
803 }
804
805 bool
806 RouteUI::monitor_input_release(GdkEventButton* ev)
807 {
808         return monitor_release (ev, MonitorInput);
809 }
810
811 bool
812 RouteUI::monitor_disk_press (GdkEventButton*)
813 {
814         return false;
815 }
816
817 bool
818 RouteUI::monitor_disk_release (GdkEventButton* ev)
819 {
820         return monitor_release (ev, MonitorDisk);
821 }
822
823 bool
824 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
825 {
826         if (ev->button != 1) {
827                 return false;
828         }
829
830         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
831
832         if (!t) {
833                 return true;
834         }
835
836         MonitorChoice mc;
837         boost::shared_ptr<RouteList> rl;
838
839         /* XXX for now, monitoring choices are orthogonal. cue monitoring
840            will follow in 3.X but requires mixing the input and playback (disk)
841            signal together, which requires yet more buffers.
842         */
843
844         if (t->monitoring_control()->monitoring_choice() & monitor_choice) {
845                 mc = MonitorChoice (t->monitoring_control()->monitoring_choice() & ~monitor_choice);
846         } else {
847                 /* this line will change when the options are non-orthogonal */
848                 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
849                 mc = monitor_choice;
850         }
851
852         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
853                 rl = _session->get_routes ();
854
855         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
856                 if (_route->route_group() && _route->route_group()->is_monitoring()) {
857                         rl = _route->route_group()->route_list();
858                 } else {
859                         rl.reset (new RouteList);
860                         rl->push_back (route());
861                 }
862         } else {
863                 rl.reset (new RouteList);
864                 rl->push_back (route());
865         }
866
867         DisplaySuspender ds;
868         _session->set_controls (route_list_to_control_list (rl, &Route::monitoring_control), (double) mc, Controllable::UseGroup);
869
870         return false;
871 }
872
873 void
874 RouteUI::build_record_menu ()
875 {
876         if (!record_menu) {
877                 record_menu = new Menu;
878                 record_menu->set_name ("ArdourContextMenu");
879                 using namespace Menu_Helpers;
880                 MenuList& items = record_menu->items();
881
882                 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
883                 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
884
885                 if (is_midi_track()) {
886                         items.push_back (SeparatorElem());
887                         items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
888                         step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
889                 }
890         }
891
892         if (step_edit_item) {
893                 if (track()->rec_enable_control()->get_value()) {
894                         step_edit_item->set_sensitive (false);
895                 }
896                 step_edit_item->set_active (midi_track()->step_editing());
897         }
898         if (rec_safe_item) {
899                 rec_safe_item->set_sensitive (!_route->record_enabled());
900                 rec_safe_item->set_active (_route->record_safe());
901         }
902 }
903
904 void
905 RouteUI::toggle_step_edit ()
906 {
907         if (!is_midi_track() || track()->rec_enable_control()->get_value()) {
908                 return;
909         }
910
911         midi_track()->set_step_editing (step_edit_item->get_active());
912 }
913
914 void
915 RouteUI::toggle_rec_safe ()
916 {
917         if (_route->record_enabled()) {
918                 return;
919         }
920         DisplaySuspender ds;
921         boost::shared_ptr<RouteList> rl (new RouteList);
922         rl->push_back (_route);
923         _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
924 }
925
926 void
927 RouteUI::step_edit_changed (bool yn)
928 {
929         if (yn) {
930                 if (rec_enable_button) {
931                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
932                 }
933
934                 start_step_editing ();
935
936                 if (step_edit_item) {
937                         step_edit_item->set_active (true);
938                 }
939
940         } else {
941
942                 if (rec_enable_button) {
943                         rec_enable_button->unset_active_state ();
944                 }
945
946                 stop_step_editing ();
947
948                 if (step_edit_item) {
949                         step_edit_item->set_active (false);
950                 }
951         }
952 }
953
954 bool
955 RouteUI::rec_enable_release (GdkEventButton* ev)
956 {
957         if (Keyboard::is_context_menu_event (ev)) {
958                 build_record_menu ();
959                 if (record_menu) {
960                         record_menu->popup (1, ev->time);
961                 }
962                 return false;
963         }
964
965         return false;
966 }
967
968 void
969 RouteUI::build_sends_menu ()
970 {
971         using namespace Menu_Helpers;
972
973         sends_menu = new Menu;
974         sends_menu->set_name ("ArdourContextMenu");
975         MenuList& items = sends_menu->items();
976
977         items.push_back (
978                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
979                 );
980
981         items.push_back (
982                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
983                 );
984
985         items.push_back (
986                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
987                 );
988
989         items.push_back (
990                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
991                 );
992
993         items.push_back (
994                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
995                 );
996
997         items.push_back (
998                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
999
1000         items.push_back (
1001                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1002                 );
1003
1004         items.push_back (
1005                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1006                 );
1007
1008         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1009         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1010         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1011
1012 }
1013
1014 void
1015 RouteUI::create_sends (Placement p, bool include_buses)
1016 {
1017         _session->globally_add_internal_sends (_route, p, include_buses);
1018 }
1019
1020 void
1021 RouteUI::create_selected_sends (Placement p, bool include_buses)
1022 {
1023         boost::shared_ptr<RouteList> rlist (new RouteList);
1024         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1025
1026         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1027                 RouteTimeAxisView* rtv;
1028                 RouteUI* rui;
1029                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1030                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1031                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1032                                         rlist->push_back (rui->route());
1033                                 }
1034                         }
1035                 }
1036         }
1037
1038         _session->add_internal_sends (_route, p, rlist);
1039 }
1040
1041 void
1042 RouteUI::set_sends_gain_from_track ()
1043 {
1044         _session->globally_set_send_gains_from_track (_route);
1045 }
1046
1047 void
1048 RouteUI::set_sends_gain_to_zero ()
1049 {
1050         _session->globally_set_send_gains_to_zero (_route);
1051 }
1052
1053 void
1054 RouteUI::set_sends_gain_to_unity ()
1055 {
1056         _session->globally_set_send_gains_to_unity (_route);
1057 }
1058
1059 bool
1060 RouteUI::show_sends_press(GdkEventButton* ev)
1061 {
1062         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1063                 return true;
1064         }
1065
1066         if (!is_track() && show_sends_button) {
1067
1068                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1069
1070                         // do nothing on midi sigc::bind event
1071                         return false;
1072
1073                 } else if (Keyboard::is_context_menu_event (ev)) {
1074
1075                         if (sends_menu == 0) {
1076                                 build_sends_menu ();
1077                         }
1078
1079                         sends_menu->popup (0, ev->time);
1080
1081                 } else {
1082
1083                         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1084
1085                         if (s == _route) {
1086                                 set_showing_sends_to (boost::shared_ptr<Route> ());
1087                         } else {
1088                                 set_showing_sends_to (_route);
1089                         }
1090                 }
1091         }
1092
1093         return true;
1094 }
1095
1096 bool
1097 RouteUI::show_sends_release (GdkEventButton*)
1098 {
1099         return true;
1100 }
1101
1102 void
1103 RouteUI::send_blink (bool onoff)
1104 {
1105         if (!show_sends_button) {
1106                 return;
1107         }
1108
1109         if (onoff) {
1110                 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1111         } else {
1112                 show_sends_button->unset_active_state ();
1113         }
1114 }
1115
1116 Gtkmm2ext::ActiveState
1117 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1118 {
1119         boost::shared_ptr<SoloControl> sc = s->solo_control();
1120
1121         if (!sc) {
1122                 return Gtkmm2ext::Off;
1123         }
1124
1125         if (!sc->can_solo()) {
1126                 return Gtkmm2ext::Off;
1127         }
1128
1129
1130         if (sc->self_soloed()) {
1131                 return Gtkmm2ext::ExplicitActive;
1132         } else if (sc->soloed_by_others()) {
1133                 return Gtkmm2ext::ImplicitActive;
1134         } else {
1135                 return Gtkmm2ext::Off;
1136         }
1137 }
1138
1139 Gtkmm2ext::ActiveState
1140 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1141 {
1142         boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1143
1144         if (!sc) {
1145                 return Gtkmm2ext::Off;
1146         }
1147
1148         if (s->is_master() || s->is_monitor()) {
1149                 return Gtkmm2ext::Off;
1150         }
1151
1152         if (sc->solo_isolated()) {
1153                 return Gtkmm2ext::ExplicitActive;
1154         } else {
1155                 return Gtkmm2ext::Off;
1156         }
1157 }
1158
1159 Gtkmm2ext::ActiveState
1160 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1161 {
1162         boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1163
1164         if (!sc) {
1165                 return Gtkmm2ext::Off;
1166         }
1167
1168         if (s->is_master() || s->is_monitor()) {
1169                 return Gtkmm2ext::Off;
1170         }
1171
1172         if (sc->solo_safe()) {
1173                 return Gtkmm2ext::ExplicitActive;
1174         } else {
1175                 return Gtkmm2ext::Off;
1176         }
1177 }
1178
1179 void
1180 RouteUI::update_solo_display ()
1181 {
1182         bool yn = _route->solo_safe_control()->solo_safe ();
1183
1184         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1185                 solo_safe_check->set_active (yn);
1186         }
1187
1188         yn = _route->solo_isolate_control()->solo_isolated ();
1189
1190         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1191                 solo_isolated_check->set_active (yn);
1192         }
1193
1194         set_button_names ();
1195
1196         if (solo_isolated_led) {
1197                 if (_route->solo_isolate_control()->solo_isolated()) {
1198                         solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1199                 } else {
1200                         solo_isolated_led->unset_active_state ();
1201                 }
1202         }
1203
1204         if (solo_safe_led) {
1205                 if (_route->solo_safe_control()->solo_safe()) {
1206                         solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1207                 } else {
1208                         solo_safe_led->unset_active_state ();
1209                 }
1210         }
1211
1212         solo_button->set_active_state (solo_active_state (_route));
1213
1214         /* some changes to solo status can affect mute display, so catch up
1215          */
1216
1217         update_mute_display ();
1218 }
1219
1220 void
1221 RouteUI::solo_changed_so_update_mute ()
1222 {
1223         update_mute_display ();
1224 }
1225
1226 ActiveState
1227 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1228 {
1229         boost::shared_ptr<MuteControl> mc = s->mute_control();
1230
1231         if (s->is_monitor()) {
1232                 return Gtkmm2ext::Off;
1233         }
1234
1235         if (!mc) {
1236                 return Gtkmm2ext::Off;
1237         }
1238
1239         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1240
1241                 if (mc->muted_by_self ()) {
1242                         /* full mute */
1243                         return Gtkmm2ext::ExplicitActive;
1244                 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1245                         /* this will reflect both solo mutes AND master mutes */
1246                         return Gtkmm2ext::ImplicitActive;
1247                 } else {
1248                         /* no mute at all */
1249                         return Gtkmm2ext::Off;
1250                 }
1251
1252         } else {
1253
1254                 if (mc->muted_by_self()) {
1255                         /* full mute */
1256                         return Gtkmm2ext::ExplicitActive;
1257                 } else if (mc->muted_by_masters ()) {
1258                         /* this shows only master mutes, not mute-by-others-soloing */
1259                         return Gtkmm2ext::ImplicitActive;
1260                 } else {
1261                         /* no mute at all */
1262                         return Gtkmm2ext::Off;
1263                 }
1264         }
1265
1266         return ActiveState(0);
1267 }
1268
1269 void
1270 RouteUI::update_mute_display ()
1271 {
1272         if (!_route) {
1273                 return;
1274         }
1275
1276         mute_button->set_active_state (mute_active_state (_session, _route));
1277 }
1278
1279 void
1280 RouteUI::update_vca_display ()
1281 {
1282         if (!vca_button) {
1283                 return;
1284         }
1285
1286         VCAList vcas (_session->vca_manager().vcas());
1287         string label;
1288
1289         for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1290                 if (_route->slaved_to (*v)) {
1291                         if (!label.empty()) {
1292                                 label += ' ';
1293                         }
1294                         label += PBD::to_string ((*v)->number(), std::dec);
1295                 }
1296         }
1297
1298         if (label.empty()) {
1299                 label = _("-vca-");
1300                 vca_button->set_active_state (Gtkmm2ext::Off);
1301         } else {
1302                 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1303         }
1304
1305         vca_button->set_text (label);
1306 }
1307
1308 void
1309 RouteUI::route_rec_enable_changed ()
1310 {
1311         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1312         update_monitoring_display ();
1313 }
1314
1315 void
1316 RouteUI::session_rec_enable_changed ()
1317 {
1318         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1319         update_monitoring_display ();
1320 }
1321
1322 void
1323 RouteUI::blink_rec_display (bool blinkOn)
1324 {
1325         if (!rec_enable_button || !_route) {
1326                 return;
1327         }
1328
1329         if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1330                 return;
1331         }
1332
1333         if (!is_track()) {
1334                 return;
1335         }
1336
1337         if (track()->rec_enable_control()->get_value()) {
1338                 switch (_session->record_status ()) {
1339                 case Session::Recording:
1340                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1341                         break;
1342
1343                 case Session::Disabled:
1344                 case Session::Enabled:
1345                         if (UIConfiguration::instance().get_blink_rec_arm()) {
1346                                 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1347                         } else {
1348                                 rec_enable_button->set_active_state ( ImplicitActive );
1349                         }
1350                         break;
1351                 }
1352
1353                 if (step_edit_item) {
1354                         step_edit_item->set_sensitive (false);
1355                 }
1356
1357         } else {
1358                 rec_enable_button->unset_active_state ();
1359
1360                 if (step_edit_item) {
1361                         step_edit_item->set_sensitive (true);
1362                 }
1363         }
1364
1365         check_rec_enable_sensitivity ();
1366 }
1367
1368 void
1369 RouteUI::build_solo_menu (void)
1370 {
1371         using namespace Menu_Helpers;
1372
1373         solo_menu = new Menu;
1374         solo_menu->set_name ("ArdourContextMenu");
1375         MenuList& items = solo_menu->items();
1376         Gtk::CheckMenuItem* check;
1377
1378         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1379         check->set_active (_route->solo_isolate_control()->solo_isolated());
1380         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1381         items.push_back (CheckMenuElem(*check));
1382         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1383         check->show_all();
1384
1385         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1386         check->set_active (_route->solo_safe_control()->solo_safe());
1387         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1388         items.push_back (CheckMenuElem(*check));
1389         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1390         check->show_all();
1391
1392         //items.push_back (SeparatorElem());
1393         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1394
1395 }
1396
1397 void
1398 RouteUI::build_mute_menu(void)
1399 {
1400         using namespace Menu_Helpers;
1401
1402         mute_menu = new Menu;
1403         mute_menu->set_name ("ArdourContextMenu");
1404
1405         MenuList& items = mute_menu->items();
1406
1407         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1408         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1409         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1410         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1411         pre_fader_mute_check->show_all();
1412
1413         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1414         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1415         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1416         items.push_back (CheckMenuElem(*post_fader_mute_check));
1417         post_fader_mute_check->show_all();
1418
1419         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1420         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1421         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1422         items.push_back (CheckMenuElem(*listen_mute_check));
1423         listen_mute_check->show_all();
1424
1425         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1426         init_mute_menu(MuteMaster::Main, main_mute_check);
1427         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1428         items.push_back (CheckMenuElem(*main_mute_check));
1429         main_mute_check->show_all();
1430
1431         //items.push_back (SeparatorElem());
1432         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1433
1434         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1435 }
1436
1437 void
1438 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1439 {
1440         check->set_active (_route->mute_control()->mute_points() & mp);
1441 }
1442
1443 void
1444 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1445 {
1446         if (check->get_active()) {
1447                 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1448         } else {
1449                 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1450         }
1451 }
1452
1453 void
1454 RouteUI::muting_change ()
1455 {
1456         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1457
1458         bool yn;
1459         MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1460
1461         yn = (current & MuteMaster::PreFader);
1462
1463         if (pre_fader_mute_check->get_active() != yn) {
1464                 pre_fader_mute_check->set_active (yn);
1465         }
1466
1467         yn = (current & MuteMaster::PostFader);
1468
1469         if (post_fader_mute_check->get_active() != yn) {
1470                 post_fader_mute_check->set_active (yn);
1471         }
1472
1473         yn = (current & MuteMaster::Listen);
1474
1475         if (listen_mute_check->get_active() != yn) {
1476                 listen_mute_check->set_active (yn);
1477         }
1478
1479         yn = (current & MuteMaster::Main);
1480
1481         if (main_mute_check->get_active() != yn) {
1482                 main_mute_check->set_active (yn);
1483         }
1484 }
1485
1486 bool
1487 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1488 {
1489         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1490                 return true;
1491         }
1492
1493         bool view = solo_isolated_led->active_state();
1494         bool model = _route->solo_isolate_control()->solo_isolated();
1495
1496         /* called BEFORE the view has changed */
1497
1498         if (ev->button == 1) {
1499                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1500
1501                         if (model) {
1502                                 /* disable isolate for all routes */
1503                                 DisplaySuspender ds;
1504                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 0.0, Controllable::NoGroup);
1505                         } else {
1506                                 /* enable isolate for all routes */
1507                                 DisplaySuspender ds;
1508                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Route::solo_isolate_control), 1.0, Controllable::NoGroup);
1509                         }
1510
1511                 } else {
1512
1513                         if (model == view) {
1514
1515                                 /* flip just this route */
1516
1517                                 boost::shared_ptr<RouteList> rl (new RouteList);
1518                                 rl->push_back (_route);
1519                                 DisplaySuspender ds;
1520                                 _session->set_controls (route_list_to_control_list (rl, &Route::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1521                         }
1522                 }
1523         }
1524
1525         return false;
1526 }
1527
1528 bool
1529 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1530 {
1531         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1532                 return true;
1533         }
1534
1535         bool view = solo_safe_led->active_state();
1536         bool model = _route->solo_safe_control()->solo_safe();
1537
1538         if (ev->button == 1) {
1539                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1540                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1541                         if (model) {
1542                                 /* disable solo safe for all routes */
1543                                 DisplaySuspender ds;
1544                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1545                                         (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1546                                 }
1547                         } else {
1548                                 /* enable solo safe for all routes */
1549                                 DisplaySuspender ds;
1550                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1551                                         (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1552                                 }
1553                         }
1554                 }
1555                 else {
1556                         if (model == view) {
1557                                 /* flip just this route */
1558                                 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1559                         }
1560                 }
1561         }
1562
1563         return false;
1564 }
1565
1566 void
1567 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1568 {
1569         bool view = check->get_active();
1570         bool model = _route->solo_isolate_control()->solo_isolated();
1571
1572         /* called AFTER the view has changed */
1573
1574         if (model != view) {
1575                 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1576         }
1577 }
1578
1579 void
1580 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1581 {
1582         _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1583 }
1584
1585 /** Ask the user to choose a colour, and then apply that color to my route
1586  */
1587 void
1588 RouteUI::choose_color ()
1589 {
1590         bool picked;
1591         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1592
1593         if (picked) {
1594                 set_color(color);
1595         }
1596 }
1597
1598 /** Set the route's own color.  This may not be used for display if
1599  *  the route is in a group which shares its color with its routes.
1600  */
1601 void
1602 RouteUI::set_color (const Gdk::Color & c)
1603 {
1604         /* leave _color alone in the group case so that tracks can retain their
1605          * own pre-group colors.
1606          */
1607
1608         char buf[64];
1609         _color = c;
1610         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1611
1612         /* note: we use the route state ID here so that color is the same for both
1613            the time axis view and the mixer strip
1614         */
1615
1616         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1617         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1618 }
1619
1620 /** @return GUI state ID for things that are common to the route in all its representations */
1621 string
1622 RouteUI::route_state_id () const
1623 {
1624         return string_compose (X_("route %1"), _route->id().to_s());
1625 }
1626
1627 int
1628 RouteUI::set_color_from_route ()
1629 {
1630         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1631
1632         if (str.empty()) {
1633                 return 1;
1634         }
1635
1636         int r, g, b;
1637
1638         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1639
1640         _color.set_red (r);
1641         _color.set_green (g);
1642         _color.set_blue (b);
1643
1644         return 0;
1645 }
1646
1647 /** @return true if this name should be used for the route, otherwise false */
1648 bool
1649 RouteUI::verify_new_route_name (const std::string& name)
1650 {
1651         if (name.find (':') == string::npos) {
1652                 return true;
1653         }
1654
1655         MessageDialog colon_msg (
1656                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1657                 false, MESSAGE_QUESTION, BUTTONS_NONE
1658                 );
1659
1660         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1661         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1662
1663         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1664 }
1665
1666 void
1667 RouteUI::route_rename ()
1668 {
1669         ArdourPrompter name_prompter (true);
1670         string result;
1671         bool done = false;
1672
1673         if (is_track()) {
1674                 name_prompter.set_title (_("Rename Track"));
1675         } else {
1676                 name_prompter.set_title (_("Rename Bus"));
1677         }
1678         name_prompter.set_prompt (_("New name:"));
1679         name_prompter.set_initial_text (_route->name());
1680         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1681         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1682         name_prompter.show_all ();
1683
1684         while (!done) {
1685                 switch (name_prompter.run ()) {
1686                 case Gtk::RESPONSE_ACCEPT:
1687                         name_prompter.get_result (result);
1688                         name_prompter.hide ();
1689                         if (result.length()) {
1690                                 if (verify_new_route_name (result)) {
1691                                         _route->set_name (result);
1692                                         done = true;
1693                                 } else {
1694                                         /* back to name prompter */
1695                                 }
1696
1697                         } else {
1698                                 /* nothing entered, just get out of here */
1699                                 done = true;
1700                         }
1701                         break;
1702                 default:
1703                         done = true;
1704                         break;
1705                 }
1706         }
1707
1708         return;
1709
1710 }
1711
1712 void
1713 RouteUI::property_changed (const PropertyChange& what_changed)
1714 {
1715         if (what_changed.contains (ARDOUR::Properties::name)) {
1716                 name_label.set_text (_route->name());
1717         }
1718 }
1719
1720 void
1721 RouteUI::toggle_comment_editor ()
1722 {
1723 //      if (ignore_toggle) {
1724 //              return;
1725 //      }
1726
1727         if (comment_window && comment_window->is_visible ()) {
1728                 comment_window->hide ();
1729         } else {
1730                 open_comment_editor ();
1731         }
1732 }
1733
1734
1735 void
1736 RouteUI::open_comment_editor ()
1737 {
1738         if (comment_window == 0) {
1739                 setup_comment_editor ();
1740         }
1741
1742         string title;
1743         title = _route->name();
1744         title += _(": comment editor");
1745
1746         comment_window->set_title (title);
1747         comment_window->present();
1748 }
1749
1750 void
1751 RouteUI::setup_comment_editor ()
1752 {
1753         comment_window = new ArdourWindow (""); // title will be reset to show route
1754         comment_window->set_skip_taskbar_hint (true);
1755         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1756         comment_window->set_default_size (400, 200);
1757
1758         comment_area = manage (new TextView());
1759         comment_area->set_name ("MixerTrackCommentArea");
1760         comment_area->set_wrap_mode (WRAP_WORD);
1761         comment_area->set_editable (true);
1762         comment_area->get_buffer()->set_text (_route->comment());
1763         comment_area->show ();
1764
1765         comment_window->add (*comment_area);
1766 }
1767
1768 void
1769 RouteUI::comment_changed ()
1770 {
1771         ignore_comment_edit = true;
1772         if (comment_area) {
1773                 comment_area->get_buffer()->set_text (_route->comment());
1774         }
1775         ignore_comment_edit = false;
1776 }
1777
1778 void
1779 RouteUI::comment_editor_done_editing ()
1780 {
1781         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1782
1783         string const str = comment_area->get_buffer()->get_text();
1784         if (str == _route->comment ()) {
1785                 return;
1786         }
1787
1788         _route->set_comment (str, this);
1789 }
1790
1791 void
1792 RouteUI::set_route_active (bool a, bool apply_to_selection)
1793 {
1794         if (apply_to_selection) {
1795                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1796         } else {
1797                 _route->set_active (a, this);
1798         }
1799 }
1800
1801 void
1802 RouteUI::duplicate_selected_routes ()
1803 {
1804         ARDOUR_UI::instance()->start_duplicate_routes();
1805 }
1806
1807 void
1808 RouteUI::toggle_denormal_protection ()
1809 {
1810         if (denormal_menu_item) {
1811
1812                 bool x;
1813
1814                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1815
1816                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1817                         _route->set_denormal_protection (x);
1818                 }
1819         }
1820 }
1821
1822 void
1823 RouteUI::denormal_protection_changed ()
1824 {
1825         if (denormal_menu_item) {
1826                 denormal_menu_item->set_active (_route->denormal_protection());
1827         }
1828 }
1829
1830 void
1831 RouteUI::disconnect_input ()
1832 {
1833         _route->input()->disconnect (this);
1834 }
1835
1836 void
1837 RouteUI::disconnect_output ()
1838 {
1839         _route->output()->disconnect (this);
1840 }
1841
1842 bool
1843 RouteUI::is_track () const
1844 {
1845         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1846 }
1847
1848 boost::shared_ptr<Track>
1849 RouteUI::track() const
1850 {
1851         return boost::dynamic_pointer_cast<Track>(_route);
1852 }
1853
1854 bool
1855 RouteUI::is_audio_track () const
1856 {
1857         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1858 }
1859
1860 boost::shared_ptr<AudioTrack>
1861 RouteUI::audio_track() const
1862 {
1863         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1864 }
1865
1866 bool
1867 RouteUI::is_midi_track () const
1868 {
1869         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1870 }
1871
1872 boost::shared_ptr<MidiTrack>
1873 RouteUI::midi_track() const
1874 {
1875         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1876 }
1877
1878 bool
1879 RouteUI::has_audio_outputs () const
1880 {
1881         return (_route->n_outputs().n_audio() > 0);
1882 }
1883
1884 string
1885 RouteUI::name() const
1886 {
1887         return _route->name();
1888 }
1889
1890 void
1891 RouteUI::map_frozen ()
1892 {
1893         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1894
1895         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1896
1897         if (at) {
1898                 check_rec_enable_sensitivity ();
1899         }
1900 }
1901
1902 void
1903 RouteUI::adjust_latency ()
1904 {
1905         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1906 }
1907
1908 bool
1909 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1910 {
1911         std::string path;
1912         std::string safe_name;
1913         std::string name;
1914
1915         prompter.get_result (name, true);
1916
1917         safe_name = legalize_for_path (name);
1918         safe_name += template_suffix;
1919
1920         path = Glib::build_filename (dir, safe_name);
1921
1922         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1923                 bool overwrite = overwrite_file_dialog (prompter,
1924                                                         _("Confirm Template Overwrite"),
1925                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1926
1927                 if (!overwrite) {
1928                         return false;
1929                 }
1930         }
1931
1932         _route->save_as_template (path, name);
1933
1934         return true;
1935 }
1936
1937 void
1938 RouteUI::save_as_template ()
1939 {
1940         std::string dir;
1941
1942         dir = ARDOUR::user_route_template_directory ();
1943
1944         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1945                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1946                 return;
1947         }
1948
1949         ArdourPrompter prompter (true); // modal
1950
1951         prompter.set_title (_("Save As Template"));
1952         prompter.set_prompt (_("Template name:"));
1953         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1954
1955         bool finished = false;
1956         while (!finished) {
1957                 switch (prompter.run()) {
1958                 case RESPONSE_ACCEPT:
1959                         finished = process_save_template_prompter (prompter, dir);
1960                         break;
1961                 default:
1962                         finished = true;
1963                         break;
1964                 }
1965         }
1966 }
1967
1968 void
1969 RouteUI::check_rec_enable_sensitivity ()
1970 {
1971         if (!rec_enable_button) {
1972                 assert (0); // This should not happen
1973                 return;
1974         }
1975         if (!_session->writable()) {
1976                 rec_enable_button->set_sensitive (false);
1977                 return;
1978         }
1979
1980         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1981                 rec_enable_button->set_sensitive (false);
1982         } else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1983                 rec_enable_button->set_sensitive (false);
1984         } else {
1985                 rec_enable_button->set_sensitive (true);
1986         }
1987         if (_route && _route->record_safe ()) {
1988                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1989         } else {
1990                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1991         }
1992         update_monitoring_display ();
1993 }
1994
1995 void
1996 RouteUI::parameter_changed (string const & p)
1997 {
1998         /* this handles RC and per-session parameter changes */
1999
2000         if (p == "disable-disarm-during-roll") {
2001                 check_rec_enable_sensitivity ();
2002         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2003                 set_button_names ();
2004         } else if (p == "auto-input") {
2005                 update_monitoring_display ();
2006         } else if (p == "blink-rec-arm") {
2007                 if (UIConfiguration::instance().get_blink_rec_arm()) {
2008                         rec_blink_connection.disconnect ();
2009                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2010                 } else {
2011                         rec_blink_connection.disconnect ();
2012                         RouteUI::blink_rec_display(false);
2013                 }
2014         }
2015 }
2016
2017 void
2018 RouteUI::step_gain_up ()
2019 {
2020         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2021 }
2022
2023 void
2024 RouteUI::page_gain_up ()
2025 {
2026         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2027 }
2028
2029 void
2030 RouteUI::step_gain_down ()
2031 {
2032         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2033 }
2034
2035 void
2036 RouteUI::page_gain_down ()
2037 {
2038         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2039 }
2040
2041 void
2042 RouteUI::open_remote_control_id_dialog ()
2043 {
2044         ArdourDialog dialog (_("Remote Control ID"));
2045         SpinButton* spin = 0;
2046
2047         dialog.get_vbox()->set_border_width (18);
2048
2049         if (Config->get_remote_model() == UserOrdered) {
2050                 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2051
2052                 HBox* hbox = manage (new HBox);
2053                 hbox->set_spacing (6);
2054                 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2055                 spin = manage (new SpinButton);
2056                 spin->set_digits (0);
2057                 spin->set_increments (1, 10);
2058                 spin->set_range (0, limit);
2059                 spin->set_value (_route->presentation_info().group_order());
2060                 hbox->pack_start (*spin);
2061                 dialog.get_vbox()->pack_start (*hbox);
2062
2063                 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2064                 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2065         } else {
2066                 Label* l = manage (new Label());
2067                 if (_route->is_master() || _route->is_monitor()) {
2068                         l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2069                                                          "The remote control ID of %3 cannot be changed."),
2070                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2071                                                        _route->presentation_info().group_order(),
2072                                                        (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2073                 } else {
2074                         l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2075                                                          "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2076                                                          "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2077                                                        (is_track() ? _("track") : _("bus")),
2078                                                        _route->presentation_info().group_order(),
2079                                                        "<span size=\"small\" style=\"italic\">",
2080                                                        "</span>",
2081                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2082                                                        PROGRAM_NAME));
2083                 }
2084                 dialog.get_vbox()->pack_start (*l);
2085                 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2086         }
2087
2088         dialog.show_all ();
2089         int const r = dialog.run ();
2090
2091         if (r == RESPONSE_ACCEPT && spin) {
2092                 _route->set_presentation_group_order_explicit (spin->get_value_as_int ());
2093         }
2094 }
2095
2096 void
2097 RouteUI::setup_invert_buttons ()
2098 {
2099         /* remove old invert buttons */
2100         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2101                 _invert_button_box.remove (**i);
2102         }
2103
2104         _invert_buttons.clear ();
2105
2106         if (!_route || !_route->input()) {
2107                 return;
2108         }
2109
2110         uint32_t const N = _route->input()->n_ports().n_audio ();
2111
2112         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2113
2114         for (uint32_t i = 0; i < to_add; ++i) {
2115                 ArdourButton* b = manage (new ArdourButton);
2116                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2117                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2118
2119                 b->set_name (X_("invert button"));
2120                 if (to_add == 1) {
2121                         if (N > 1) {
2122                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2123                         } else {
2124                                 b->set_text (X_("Ø"));
2125                         }
2126                 } else {
2127                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2128                 }
2129
2130                 if (N <= _max_invert_buttons) {
2131                         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));
2132                 } else {
2133                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2134                 }
2135
2136                 _invert_buttons.push_back (b);
2137                 _invert_button_box.pack_start (*b);
2138         }
2139
2140         _invert_button_box.set_spacing (1);
2141         _invert_button_box.show_all ();
2142 }
2143
2144 void
2145 RouteUI::set_invert_button_state ()
2146 {
2147         uint32_t const N = _route->input()->n_ports().n_audio();
2148         if (N > _max_invert_buttons) {
2149
2150                 /* One button for many channels; explicit active if all channels are inverted,
2151                    implicit active if some are, off if none are.
2152                 */
2153
2154                 ArdourButton* b = _invert_buttons.front ();
2155
2156                 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2157                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2158                 } else if (_route->phase_control()->any()) {
2159                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2160                 } else {
2161                         b->set_active_state (Gtkmm2ext::Off);
2162                 }
2163
2164         } else {
2165
2166                 /* One button per channel; just set active */
2167
2168                 int j = 0;
2169                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2170                         (*i)->set_active (_route->phase_control()->inverted (j));
2171                 }
2172
2173         }
2174 }
2175
2176 bool
2177 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2178 {
2179         if (ev->button == 1 && i < _invert_buttons.size()) {
2180                 uint32_t const N = _route->input()->n_ports().n_audio ();
2181                 if (N <= _max_invert_buttons) {
2182                         /* left-click inverts phase so long as we have a button per channel */
2183                         _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2184                         return false;
2185                 }
2186         }
2187         return false;
2188 }
2189
2190
2191 bool
2192 RouteUI::invert_press (GdkEventButton* ev)
2193 {
2194         using namespace Menu_Helpers;
2195
2196         uint32_t const N = _route->input()->n_ports().n_audio();
2197         if (N <= _max_invert_buttons && ev->button != 3) {
2198                 /* If we have an invert button per channel, we only pop
2199                    up a menu on right-click; left click is handled
2200                    on release.
2201                 */
2202                 return false;
2203         }
2204
2205         delete _invert_menu;
2206         _invert_menu = new Menu;
2207         _invert_menu->set_name ("ArdourContextMenu");
2208         MenuList& items = _invert_menu->items ();
2209
2210         for (uint32_t i = 0; i < N; ++i) {
2211                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2212                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2213                 ++_i_am_the_modifier;
2214                 e->set_active (_route->phase_control()->inverted (i));
2215                 --_i_am_the_modifier;
2216         }
2217
2218         _invert_menu->popup (0, ev->time);
2219
2220         return true;
2221 }
2222
2223 void
2224 RouteUI::invert_menu_toggled (uint32_t c)
2225 {
2226         if (_i_am_the_modifier) {
2227                 return;
2228         }
2229
2230
2231         _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2232 }
2233
2234 void
2235 RouteUI::set_invert_sensitive (bool yn)
2236 {
2237         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2238                 (*b)->set_sensitive (yn);
2239         }
2240 }
2241
2242 void
2243 RouteUI::request_redraw ()
2244 {
2245         if (_route) {
2246                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2247         }
2248 }
2249
2250 /** The Route's gui_changed signal has been emitted */
2251 void
2252 RouteUI::route_gui_changed (string what_changed)
2253 {
2254         if (what_changed == "color") {
2255                 if (set_color_from_route () == 0) {
2256                         route_color_changed ();
2257                 }
2258         }
2259 }
2260
2261 void
2262 RouteUI::track_mode_changed (void)
2263 {
2264         assert(is_track());
2265         switch (track()->mode()) {
2266                 case ARDOUR::NonLayered:
2267                 case ARDOUR::Normal:
2268                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2269                         break;
2270                 case ARDOUR::Destructive:
2271                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2272                         break;
2273         }
2274         rec_enable_button->queue_draw();
2275 }
2276
2277 /** @return the color that this route should use; it maybe its own,
2278     or it maybe that of its route group.
2279 */
2280 Gdk::Color
2281 RouteUI::color () const
2282 {
2283         RouteGroup* g = _route->route_group ();
2284
2285         if (g && g->is_color()) {
2286                 Gdk::Color c;
2287                 set_color_from_rgba (c, GroupTabs::group_color (g));
2288                 return c;
2289         }
2290
2291         return _color;
2292 }
2293
2294 void
2295 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2296 {
2297         _showing_sends_to = send_to;
2298         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2299 }
2300
2301 void
2302 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2303 {
2304         if (_route == send_to) {
2305                 show_sends_button->set_active (true);
2306                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2307         } else {
2308                 show_sends_button->set_active (false);
2309                 send_blink_connection.disconnect ();
2310         }
2311 }
2312
2313 RouteGroup*
2314 RouteUI::route_group() const
2315 {
2316         return _route->route_group();
2317 }
2318
2319
2320 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2321         : WM::ProxyBase (name, string())
2322         , _route (boost::weak_ptr<Route> (route))
2323 {
2324         route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2325 }
2326
2327 RoutePinWindowProxy::~RoutePinWindowProxy()
2328 {
2329         _window = 0;
2330 }
2331
2332 ARDOUR::SessionHandlePtr*
2333 RoutePinWindowProxy::session_handle ()
2334 {
2335         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2336         if (aw) { return aw; }
2337         return 0;
2338 }
2339
2340 Gtk::Window*
2341 RoutePinWindowProxy::get (bool create)
2342 {
2343         boost::shared_ptr<Route> r = _route.lock ();
2344         if (!r) {
2345                 return 0;
2346         }
2347
2348         if (!_window) {
2349                 if (!create) {
2350                         return 0;
2351                 }
2352                 _window = new PluginPinDialog (r);
2353                 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2354                 if (aw) {
2355                         aw->set_session (_session);
2356                 }
2357                 _window->show_all ();
2358         }
2359         return _window;
2360 }
2361
2362 void
2363 RoutePinWindowProxy::route_going_away ()
2364 {
2365         delete _window;
2366         _window = 0;
2367         WM::Manager::instance().remove (this);
2368         going_away_connection.disconnect();
2369 }
2370
2371 void
2372 RouteUI::maybe_add_route_print_mgr ()
2373 {
2374         if (_route->pinmgr_proxy ()) {
2375                 return;
2376         }
2377         RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2378                         string_compose ("RPM-%1", _route->id()), _route);
2379         wp->set_session (_session);
2380
2381         const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2382         if (ui_xml) {
2383                 wp->set_state (*ui_xml, 0);
2384         }
2385
2386 #if 0
2387         void* existing_ui = _route->pinmgr_proxy ();
2388         if (existing_ui) {
2389                 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2390         }
2391 #endif
2392         _route->set_pingmgr_proxy (wp);
2393
2394         WM::Manager::instance().register_window (wp);
2395 }
2396
2397 void
2398 RouteUI::manage_pins ()
2399 {
2400         RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2401         if (proxy) {
2402                 proxy->get (true);
2403                 proxy->present();
2404         }
2405 }