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