use route automation control Changed() signals for solo/mute in GUI
[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
267         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this), gui_context());
268
269         _route->mute_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_mute_display, this), gui_context());
270         _route->solo_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
271         _route->solo_safe_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
272         _route->solo_isolate_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
273
274         if (_route->phase_control()) {
275                 _route->phase_control()->Changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
276         }
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->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
294                 t->RecordSafeChanged.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->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, 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->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_mute (copy, !_route->muted());
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_mute (rl, !_route->muted(), Session::rt_cleanup, 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_mute (rl, !_route->muted());
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_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, 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                                 if (Config->get_solo_control_is_listen_control()) {
576                                         _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::UseGroup);
577                                 } else {
578                                         _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, Controllable::UseGroup);
579                                 }
580
581                         } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
582
583                                 // Primary-Secondary-click: exclusively solo this track
584
585                                 if (_solo_release) {
586                                         _solo_release->exclusive = true;
587
588                                         boost::shared_ptr<RouteList> routes = _session->get_routes();
589
590                                         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
591                                                 if ((*i)->soloed ()) {
592                                                         _solo_release->routes_on->push_back (*i);
593                                                 } else {
594                                                         _solo_release->routes_off->push_back (*i);
595                                                 }
596                                         }
597                                 }
598
599                                 if (Config->get_solo_control_is_listen_control()) {
600                                         /* ??? we need a just_one_listen() method */
601                                 } else {
602                                         DisplaySuspender ds;
603                                         _session->set_just_one_solo (_route, true);
604                                 }
605
606                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
607
608                                 // shift-click: toggle solo isolated status
609
610                                 _route->set_solo_isolated (!_route->solo_isolated(), Controllable::UseGroup);
611                                 delete _solo_release;
612                                 _solo_release = 0;
613
614                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
615
616                                 /* Primary-button1: solo mix group.
617                                    NOTE: Primary-button2 is MIDI learn.
618                                 */
619
620                                 /* Primary-button1 applies change to the mix group even if it is not active
621                                    NOTE: Primary-button2 is MIDI learn.
622                                 */
623
624                                 boost::shared_ptr<RouteList> rl;
625
626                                 if (ev->button == 1) {
627
628                                         /* Primary-button1 inverts the implication of
629                                            the group being active. If the group is
630                                            active (for solo), then this modifier means
631                                            "do not apply to solo". If the group is
632                                            inactive (for mute), then this modifier
633                                            means "apply to route". This is all
634                                            accomplished by passing just the actual
635                                            route, along with the InverseGroup group
636                                            control disposition.
637
638                                            NOTE: Primary-button2 is MIDI learn.
639                                         */
640
641                                         rl.reset (new RouteList);
642                                         rl->push_back (_route);
643
644                                         if (_solo_release) {
645                                                 _solo_release->routes = rl;
646                                         }
647
648                                         DisplaySuspender ds;
649
650                                         if (Config->get_solo_control_is_listen_control()) {
651                                                 _session->set_listen (rl, !_route->listening_via_monitor(),  Session::rt_cleanup, Controllable::InverseGroup);
652                                         } else {
653                                                 _session->set_solo (rl, !_route->self_soloed(),  Session::rt_cleanup, Controllable::InverseGroup);
654                                         }
655                                 }
656
657                                 delete _solo_release;
658                                 _solo_release = 0;
659
660                         } else {
661
662                                 /* click: solo this route */
663
664                                 boost::shared_ptr<RouteList> rl (new RouteList);
665                                 rl->push_back (route());
666
667                                 if (_solo_release) {
668                                         _solo_release->routes = rl;
669                                 }
670
671                                 DisplaySuspender ds;
672                                 if (Config->get_solo_control_is_listen_control()) {
673                                         _session->set_listen (rl, !_route->listening_via_monitor());
674                                 } else {
675                                         _session->set_solo (rl, !_route->self_soloed());
676                                 }
677                         }
678                 }
679         }
680
681         return false;
682 }
683
684 bool
685 RouteUI::solo_release (GdkEventButton* /*ev*/)
686 {
687         if (_solo_release) {
688
689                 if (_solo_release->exclusive) {
690
691                 } else {
692                         DisplaySuspender ds;
693                         if (Config->get_solo_control_is_listen_control()) {
694                                 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
695                         } else {
696                                 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, Controllable::UseGroup);
697                         }
698                 }
699
700                 delete _solo_release;
701                 _solo_release = 0;
702         }
703
704         return false;
705 }
706
707 bool
708 RouteUI::rec_enable_press(GdkEventButton* ev)
709 {
710         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
711                 return true;
712         }
713
714         //if this is a binding action, let the ArdourButton handle it
715         if ( BindingProxy::is_bind_action(ev) )
716                 return false;
717
718         if (!_session->engine().connected()) {
719                 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
720                 msg.run ();
721                 return false;
722         }
723
724         if (is_midi_track()) {
725
726                 /* rec-enable button exits from step editing */
727
728                 if (midi_track()->step_editing()) {
729                         midi_track()->set_step_editing (false);
730                         return false;
731                 }
732         }
733
734         if (is_track() && rec_enable_button) {
735
736                 if (Keyboard::is_button2_event (ev)) {
737
738                         //rec arm does not have a momentary mode
739                         return false;
740
741                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
742
743                         DisplaySuspender ds;
744                         _session->set_record_enabled (_session->get_routes(), !_route->record_enabled());
745
746                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
747
748                         /* Primary-button1 applies change to the route group (even if it is not active)
749                            NOTE: Primary-button2 is MIDI learn.
750                         */
751
752                         if (ev->button == 1) {
753
754                                 boost::shared_ptr<RouteList> rl;
755
756                                 rl.reset (new RouteList);
757                                 rl->push_back (_route);
758
759                                 DisplaySuspender ds;
760                                 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
761                         }
762
763                 } else if (Keyboard::is_context_menu_event (ev)) {
764
765                         /* do this on release */
766
767                 } else {
768
769                         boost::shared_ptr<RouteList> rl (new RouteList);
770                         rl->push_back (route());
771                         DisplaySuspender ds;
772                         _session->set_record_enabled (rl, !_route->record_enabled());
773                 }
774         }
775
776         return false;
777 }
778
779 void
780 RouteUI::monitoring_changed ()
781 {
782         update_monitoring_display ();
783 }
784
785 void
786 RouteUI::update_monitoring_display ()
787 {
788         if (!_route) {
789                 return;
790         }
791
792         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
793
794         if (!t) {
795                 return;
796         }
797
798         MonitorState ms = t->monitoring_state();
799
800         if (t->monitoring_choice() & MonitorInput) {
801                 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
802         } else {
803                 if (ms & MonitoringInput) {
804                         monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
805                 } else {
806                         monitor_input_button->unset_active_state ();
807                 }
808         }
809
810         if (t->monitoring_choice() & MonitorDisk) {
811                 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
812         } else {
813                 if (ms & MonitoringDisk) {
814                         monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
815                 } else {
816                         monitor_disk_button->unset_active_state ();
817                 }
818         }
819 }
820
821 bool
822 RouteUI::monitor_input_press(GdkEventButton*)
823 {
824         return false;
825 }
826
827 bool
828 RouteUI::monitor_input_release(GdkEventButton* ev)
829 {
830         return monitor_release (ev, MonitorInput);
831 }
832
833 bool
834 RouteUI::monitor_disk_press (GdkEventButton*)
835 {
836         return false;
837 }
838
839 bool
840 RouteUI::monitor_disk_release (GdkEventButton* ev)
841 {
842         return monitor_release (ev, MonitorDisk);
843 }
844
845 bool
846 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
847 {
848         if (ev->button != 1) {
849                 return false;
850         }
851
852         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
853
854         if (!t) {
855                 return true;
856         }
857
858         MonitorChoice mc;
859         boost::shared_ptr<RouteList> rl;
860
861         /* XXX for now, monitoring choices are orthogonal. cue monitoring
862            will follow in 3.X but requires mixing the input and playback (disk)
863            signal together, which requires yet more buffers.
864         */
865
866         if (t->monitoring_choice() & monitor_choice) {
867                 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
868         } else {
869                 /* this line will change when the options are non-orthogonal */
870                 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
871                 mc = monitor_choice;
872         }
873
874         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
875                 rl = _session->get_routes ();
876
877         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
878                 if (_route->route_group() && _route->route_group()->is_monitoring()) {
879                         rl = _route->route_group()->route_list();
880                 } else {
881                         rl.reset (new RouteList);
882                         rl->push_back (route());
883                 }
884         } else {
885                 rl.reset (new RouteList);
886                 rl->push_back (route());
887         }
888
889         DisplaySuspender ds;
890         _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
891
892         return false;
893 }
894
895 void
896 RouteUI::build_record_menu ()
897 {
898         if (!record_menu) {
899                 record_menu = new Menu;
900                 record_menu->set_name ("ArdourContextMenu");
901                 using namespace Menu_Helpers;
902                 MenuList& items = record_menu->items();
903
904                 items.push_back (CheckMenuElem (_("Rec-Safe"), sigc::mem_fun (*this, &RouteUI::toggle_rec_safe)));
905                 rec_safe_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
906
907                 if (is_midi_track()) {
908                         items.push_back (SeparatorElem());
909                         items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
910                         step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
911                 }
912         }
913
914         if (step_edit_item) {
915                 step_edit_item->set_sensitive (!_route->record_enabled());
916                 step_edit_item->set_active (midi_track()->step_editing());
917         }
918         if (rec_safe_item) {
919                 rec_safe_item->set_sensitive (!_route->record_enabled());
920                 rec_safe_item->set_active (_route->record_safe());
921         }
922 }
923
924 void
925 RouteUI::toggle_step_edit ()
926 {
927         if (!is_midi_track() || _route->record_enabled()) {
928                 return;
929         }
930
931         midi_track()->set_step_editing (step_edit_item->get_active());
932 }
933
934 void
935 RouteUI::toggle_rec_safe ()
936 {
937         if (_route->record_enabled()) {
938                 return;
939         }
940         DisplaySuspender ds;
941         boost::shared_ptr<RouteList> rl (new RouteList);
942         rl->push_back (_route);
943         _session->set_record_safe (rl, rec_safe_item->get_active (), Session::rt_cleanup);
944 }
945
946 void
947 RouteUI::step_edit_changed (bool yn)
948 {
949         if (yn) {
950                 if (rec_enable_button) {
951                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
952                 }
953
954                 start_step_editing ();
955
956                 if (step_edit_item) {
957                         step_edit_item->set_active (true);
958                 }
959
960         } else {
961
962                 if (rec_enable_button) {
963                         rec_enable_button->unset_active_state ();
964                 }
965
966                 stop_step_editing ();
967
968                 if (step_edit_item) {
969                         step_edit_item->set_active (false);
970                 }
971         }
972 }
973
974 bool
975 RouteUI::rec_enable_release (GdkEventButton* ev)
976 {
977         if (Keyboard::is_context_menu_event (ev)) {
978                 build_record_menu ();
979                 if (record_menu) {
980                         record_menu->popup (1, ev->time);
981                 }
982                 return false;
983         }
984
985         return false;
986 }
987
988 void
989 RouteUI::build_sends_menu ()
990 {
991         using namespace Menu_Helpers;
992
993         sends_menu = new Menu;
994         sends_menu->set_name ("ArdourContextMenu");
995         MenuList& items = sends_menu->items();
996
997         items.push_back (
998                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
999                 );
1000
1001         items.push_back (
1002                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
1003                 );
1004
1005         items.push_back (
1006                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
1007                 );
1008
1009         items.push_back (
1010                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
1011                 );
1012
1013         items.push_back (
1014                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1015                 );
1016
1017         items.push_back (
1018                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1019
1020         items.push_back (
1021                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1022                 );
1023
1024         items.push_back (
1025                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1026                 );
1027
1028         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1029         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1030         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1031
1032 }
1033
1034 void
1035 RouteUI::create_sends (Placement p, bool include_buses)
1036 {
1037         _session->globally_add_internal_sends (_route, p, include_buses);
1038 }
1039
1040 void
1041 RouteUI::create_selected_sends (Placement p, bool include_buses)
1042 {
1043         boost::shared_ptr<RouteList> rlist (new RouteList);
1044         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1045
1046         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1047                 RouteTimeAxisView* rtv;
1048                 RouteUI* rui;
1049                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1050                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1051                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1052                                         rlist->push_back (rui->route());
1053                                 }
1054                         }
1055                 }
1056         }
1057
1058         _session->add_internal_sends (_route, p, rlist);
1059 }
1060
1061 void
1062 RouteUI::set_sends_gain_from_track ()
1063 {
1064         _session->globally_set_send_gains_from_track (_route);
1065 }
1066
1067 void
1068 RouteUI::set_sends_gain_to_zero ()
1069 {
1070         _session->globally_set_send_gains_to_zero (_route);
1071 }
1072
1073 void
1074 RouteUI::set_sends_gain_to_unity ()
1075 {
1076         _session->globally_set_send_gains_to_unity (_route);
1077 }
1078
1079 bool
1080 RouteUI::show_sends_press(GdkEventButton* ev)
1081 {
1082         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1083                 return true;
1084         }
1085
1086         if (!is_track() && show_sends_button) {
1087
1088                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1089
1090                         // do nothing on midi sigc::bind event
1091                         return false;
1092
1093                 } else if (Keyboard::is_context_menu_event (ev)) {
1094
1095                         if (sends_menu == 0) {
1096                                 build_sends_menu ();
1097                         }
1098
1099                         sends_menu->popup (0, ev->time);
1100
1101                 } else {
1102
1103                         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1104
1105                         if (s == _route) {
1106                                 set_showing_sends_to (boost::shared_ptr<Route> ());
1107                         } else {
1108                                 set_showing_sends_to (_route);
1109                         }
1110                 }
1111         }
1112
1113         return true;
1114 }
1115
1116 bool
1117 RouteUI::show_sends_release (GdkEventButton*)
1118 {
1119         return true;
1120 }
1121
1122 void
1123 RouteUI::send_blink (bool onoff)
1124 {
1125         if (!show_sends_button) {
1126                 return;
1127         }
1128
1129         if (onoff) {
1130                 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1131         } else {
1132                 show_sends_button->unset_active_state ();
1133         }
1134 }
1135
1136 Gtkmm2ext::ActiveState
1137 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1138 {
1139         if (r->is_master() || r->is_monitor()) {
1140                 return Gtkmm2ext::Off;
1141         }
1142
1143         if (Config->get_solo_control_is_listen_control()) {
1144
1145                 if (r->listening_via_monitor()) {
1146                         return Gtkmm2ext::ExplicitActive;
1147                 } else {
1148                         return Gtkmm2ext::Off;
1149                 }
1150
1151         }
1152
1153         if (r->soloed()) {
1154                 if (!r->self_soloed()) {
1155                         return Gtkmm2ext::ImplicitActive;
1156                 } else {
1157                         return Gtkmm2ext::ExplicitActive;
1158                 }
1159         } else {
1160                 return Gtkmm2ext::Off;
1161         }
1162 }
1163
1164 Gtkmm2ext::ActiveState
1165 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1166 {
1167         if (r->is_master() || r->is_monitor()) {
1168                 return Gtkmm2ext::Off;
1169         }
1170
1171         if (r->solo_isolated()) {
1172                 return Gtkmm2ext::ExplicitActive;
1173         } else {
1174                 return Gtkmm2ext::Off;
1175         }
1176 }
1177
1178 Gtkmm2ext::ActiveState
1179 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1180 {
1181         if (r->is_master() || r->is_monitor()) {
1182                 return Gtkmm2ext::Off;
1183         }
1184
1185         if (r->solo_safe()) {
1186                 return Gtkmm2ext::ExplicitActive;
1187         } else {
1188                 return Gtkmm2ext::Off;
1189         }
1190 }
1191
1192 void
1193 RouteUI::update_solo_display ()
1194 {
1195         bool yn = _route->solo_safe ();
1196
1197         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1198                 solo_safe_check->set_active (yn);
1199         }
1200
1201         yn = _route->solo_isolated ();
1202
1203         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1204                 solo_isolated_check->set_active (yn);
1205         }
1206
1207         set_button_names ();
1208
1209         if (solo_isolated_led) {
1210                 if (_route->solo_isolated()) {
1211                         solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1212                 } else {
1213                         solo_isolated_led->unset_active_state ();
1214                 }
1215         }
1216
1217         if (solo_safe_led) {
1218                 if (_route->solo_safe()) {
1219                         solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1220                 } else {
1221                         solo_safe_led->unset_active_state ();
1222                 }
1223         }
1224
1225         solo_button->set_active_state (solo_active_state (_route));
1226
1227         /* some changes to solo status can affect mute display, so catch up
1228          */
1229
1230         update_mute_display ();
1231 }
1232
1233 void
1234 RouteUI::solo_changed_so_update_mute ()
1235 {
1236         update_mute_display ();
1237 }
1238
1239 ActiveState
1240 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1241 {
1242         if (r->is_monitor()) {
1243                 return ActiveState(0);
1244         }
1245
1246
1247         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1248
1249                 if (r->muted ()) {
1250                         /* full mute */
1251                         return Gtkmm2ext::ExplicitActive;
1252                 } else if (r->muted_by_others()) {
1253                         return Gtkmm2ext::ImplicitActive;
1254                 } else {
1255                         /* no mute at all */
1256                         return Gtkmm2ext::Off;
1257                 }
1258
1259         } else {
1260
1261                 if (r->muted()) {
1262                         /* full mute */
1263                         return Gtkmm2ext::ExplicitActive;
1264                 } else {
1265                         /* no mute at all */
1266                         return Gtkmm2ext::Off;
1267                 }
1268         }
1269
1270         return ActiveState(0);
1271 }
1272
1273 void
1274 RouteUI::update_mute_display ()
1275 {
1276         if (!_route) {
1277                 return;
1278         }
1279
1280         mute_button->set_active_state (mute_active_state (_session, _route));
1281 }
1282
1283 void
1284 RouteUI::update_vca_display ()
1285 {
1286         if (!vca_button) {
1287                 return;
1288         }
1289
1290         VCAList vcas (_session->vca_manager().vcas());
1291         string label;
1292
1293         for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1294                 if (_route->slaved_to (*v)) {
1295                         if (!label.empty()) {
1296                                 label += ' ';
1297                         }
1298                         label += PBD::to_string ((*v)->number(), std::dec);
1299                 }
1300         }
1301
1302         if (label.empty()) {
1303                 label = _("-vca-");
1304                 vca_button->set_active_state (Gtkmm2ext::Off);
1305         } else {
1306                 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1307         }
1308
1309         vca_button->set_text (label);
1310 }
1311
1312 void
1313 RouteUI::route_rec_enable_changed ()
1314 {
1315         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1316         update_monitoring_display ();
1317 }
1318
1319 void
1320 RouteUI::session_rec_enable_changed ()
1321 {
1322         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1323         update_monitoring_display ();
1324 }
1325
1326 void
1327 RouteUI::blink_rec_display (bool blinkOn)
1328 {
1329         if (!rec_enable_button || !_route) {
1330                 return;
1331         }
1332         if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1333                 return;
1334         }
1335
1336         if (_route->record_enabled()) {
1337                 switch (_session->record_status ()) {
1338                 case Session::Recording:
1339                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1340                         break;
1341
1342                 case Session::Disabled:
1343                 case Session::Enabled:
1344                         if ( UIConfiguration::instance().get_blink_rec_arm() )
1345                                                         rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1346                                                 else
1347                                                         rec_enable_button->set_active_state ( ImplicitActive );
1348                         break;
1349
1350                 }
1351
1352                 if (step_edit_item) {
1353                         step_edit_item->set_sensitive (false);
1354                 }
1355
1356         } else {
1357                 rec_enable_button->unset_active_state ();
1358
1359                 if (step_edit_item) {
1360                         step_edit_item->set_sensitive (true);
1361                 }
1362         }
1363
1364         check_rec_enable_sensitivity ();
1365 }
1366
1367 void
1368 RouteUI::build_solo_menu (void)
1369 {
1370         using namespace Menu_Helpers;
1371
1372         solo_menu = new Menu;
1373         solo_menu->set_name ("ArdourContextMenu");
1374         MenuList& items = solo_menu->items();
1375         Gtk::CheckMenuItem* check;
1376
1377         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1378         check->set_active (_route->solo_isolated());
1379         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1380         items.push_back (CheckMenuElem(*check));
1381         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1382         check->show_all();
1383
1384         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1385         check->set_active (_route->solo_safe());
1386         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1387         items.push_back (CheckMenuElem(*check));
1388         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1389         check->show_all();
1390
1391         //items.push_back (SeparatorElem());
1392         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1393
1394 }
1395
1396 void
1397 RouteUI::build_mute_menu(void)
1398 {
1399         using namespace Menu_Helpers;
1400
1401         mute_menu = new Menu;
1402         mute_menu->set_name ("ArdourContextMenu");
1403
1404         MenuList& items = mute_menu->items();
1405
1406         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1407         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1408         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1409         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1410         pre_fader_mute_check->show_all();
1411
1412         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1413         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1414         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1415         items.push_back (CheckMenuElem(*post_fader_mute_check));
1416         post_fader_mute_check->show_all();
1417
1418         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1419         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1420         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1421         items.push_back (CheckMenuElem(*listen_mute_check));
1422         listen_mute_check->show_all();
1423
1424         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1425         init_mute_menu(MuteMaster::Main, main_mute_check);
1426         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1427         items.push_back (CheckMenuElem(*main_mute_check));
1428         main_mute_check->show_all();
1429
1430         //items.push_back (SeparatorElem());
1431         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1432
1433         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1434 }
1435
1436 void
1437 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1438 {
1439         check->set_active (_route->mute_points() & mp);
1440 }
1441
1442 void
1443 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1444 {
1445         if (check->get_active()) {
1446                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1447         } else {
1448                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1449         }
1450 }
1451
1452 void
1453 RouteUI::muting_change ()
1454 {
1455         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1456
1457         bool yn;
1458         MuteMaster::MutePoint current = _route->mute_points ();
1459
1460         yn = (current & MuteMaster::PreFader);
1461
1462         if (pre_fader_mute_check->get_active() != yn) {
1463                 pre_fader_mute_check->set_active (yn);
1464         }
1465
1466         yn = (current & MuteMaster::PostFader);
1467
1468         if (post_fader_mute_check->get_active() != yn) {
1469                 post_fader_mute_check->set_active (yn);
1470         }
1471
1472         yn = (current & MuteMaster::Listen);
1473
1474         if (listen_mute_check->get_active() != yn) {
1475                 listen_mute_check->set_active (yn);
1476         }
1477
1478         yn = (current & MuteMaster::Main);
1479
1480         if (main_mute_check->get_active() != yn) {
1481                 main_mute_check->set_active (yn);
1482         }
1483 }
1484
1485 bool
1486 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1487 {
1488         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1489                 return true;
1490         }
1491
1492         bool view = solo_isolated_led->active_state();
1493         bool model = _route->solo_isolated();
1494
1495         /* called BEFORE the view has changed */
1496
1497         if (ev->button == 1) {
1498                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1499
1500                         if (model) {
1501                                 /* disable isolate for all routes */
1502                                 DisplaySuspender ds;
1503                                 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1504                         } else {
1505                                 /* enable isolate for all routes */
1506                                 DisplaySuspender ds;
1507                                 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1508                         }
1509
1510                 } else {
1511
1512                         if (model == view) {
1513
1514                                 /* flip just this route */
1515
1516                                 boost::shared_ptr<RouteList> rl (new RouteList);
1517                                 rl->push_back (_route);
1518                                 DisplaySuspender ds;
1519                                 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1520                         }
1521                 }
1522         }
1523
1524         return false;
1525 }
1526
1527 bool
1528 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1529 {
1530         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1531                 return true;
1532         }
1533
1534         bool view = solo_safe_led->active_state();
1535         bool model = _route->solo_safe();
1536
1537         if (ev->button == 1) {
1538                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1539                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1540                         if (model) {
1541                                 /* disable solo safe for all routes */
1542                                 DisplaySuspender ds;
1543                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1544                                         (*i)->set_solo_safe (false, Controllable::NoGroup);
1545                                 }
1546                         } else {
1547                                 /* enable solo safe for all routes */
1548                                 DisplaySuspender ds;
1549                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1550                                         (*i)->set_solo_safe (true, Controllable::NoGroup);
1551                                 }
1552                         }
1553                 }
1554                 else {
1555                         if (model == view) {
1556                                 /* flip just this route */
1557                                 _route->set_solo_safe (!view, Controllable::NoGroup);
1558                         }
1559                 }
1560         }
1561
1562         return false;
1563 }
1564
1565 void
1566 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1567 {
1568         bool view = check->get_active();
1569         bool model = _route->solo_isolated();
1570
1571         /* called AFTER the view has changed */
1572
1573         if (model != view) {
1574                 _route->set_solo_isolated (view, Controllable::UseGroup);
1575         }
1576 }
1577
1578 void
1579 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1580 {
1581         _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1582 }
1583
1584 /** Ask the user to choose a colour, and then apply that color to my route
1585  */
1586 void
1587 RouteUI::choose_color ()
1588 {
1589         bool picked;
1590         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1591
1592         if (picked) {
1593                 set_color(color);
1594         }
1595 }
1596
1597 /** Set the route's own color.  This may not be used for display if
1598  *  the route is in a group which shares its color with its routes.
1599  */
1600 void
1601 RouteUI::set_color (const Gdk::Color & c)
1602 {
1603         /* leave _color alone in the group case so that tracks can retain their
1604          * own pre-group colors.
1605          */
1606
1607         char buf[64];
1608         _color = c;
1609         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1610
1611         /* note: we use the route state ID here so that color is the same for both
1612            the time axis view and the mixer strip
1613         */
1614
1615         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1616         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1617 }
1618
1619 /** @return GUI state ID for things that are common to the route in all its representations */
1620 string
1621 RouteUI::route_state_id () const
1622 {
1623         return string_compose (X_("route %1"), _route->id().to_s());
1624 }
1625
1626 int
1627 RouteUI::set_color_from_route ()
1628 {
1629         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1630
1631         if (str.empty()) {
1632                 return 1;
1633         }
1634
1635         int r, g, b;
1636
1637         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1638
1639         _color.set_red (r);
1640         _color.set_green (g);
1641         _color.set_blue (b);
1642
1643         return 0;
1644 }
1645
1646 /** @return true if this name should be used for the route, otherwise false */
1647 bool
1648 RouteUI::verify_new_route_name (const std::string& name)
1649 {
1650         if (name.find (':') == string::npos) {
1651                 return true;
1652         }
1653
1654         MessageDialog colon_msg (
1655                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1656                 false, MESSAGE_QUESTION, BUTTONS_NONE
1657                 );
1658
1659         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1660         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1661
1662         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1663 }
1664
1665 void
1666 RouteUI::route_rename ()
1667 {
1668         ArdourPrompter name_prompter (true);
1669         string result;
1670         bool done = false;
1671
1672         if (is_track()) {
1673                 name_prompter.set_title (_("Rename Track"));
1674         } else {
1675                 name_prompter.set_title (_("Rename Bus"));
1676         }
1677         name_prompter.set_prompt (_("New name:"));
1678         name_prompter.set_initial_text (_route->name());
1679         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1680         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1681         name_prompter.show_all ();
1682
1683         while (!done) {
1684                 switch (name_prompter.run ()) {
1685                 case Gtk::RESPONSE_ACCEPT:
1686                         name_prompter.get_result (result);
1687                         name_prompter.hide ();
1688                         if (result.length()) {
1689                                 if (verify_new_route_name (result)) {
1690                                         _route->set_name (result);
1691                                         done = true;
1692                                 } else {
1693                                         /* back to name prompter */
1694                                 }
1695
1696                         } else {
1697                                 /* nothing entered, just get out of here */
1698                                 done = true;
1699                         }
1700                         break;
1701                 default:
1702                         done = true;
1703                         break;
1704                 }
1705         }
1706
1707         return;
1708
1709 }
1710
1711 void
1712 RouteUI::property_changed (const PropertyChange& what_changed)
1713 {
1714         if (what_changed.contains (ARDOUR::Properties::name)) {
1715                 name_label.set_text (_route->name());
1716         }
1717 }
1718
1719 void
1720 RouteUI::toggle_comment_editor ()
1721 {
1722 //      if (ignore_toggle) {
1723 //              return;
1724 //      }
1725
1726         if (comment_window && comment_window->is_visible ()) {
1727                 comment_window->hide ();
1728         } else {
1729                 open_comment_editor ();
1730         }
1731 }
1732
1733
1734 void
1735 RouteUI::open_comment_editor ()
1736 {
1737         if (comment_window == 0) {
1738                 setup_comment_editor ();
1739         }
1740
1741         string title;
1742         title = _route->name();
1743         title += _(": comment editor");
1744
1745         comment_window->set_title (title);
1746         comment_window->present();
1747 }
1748
1749 void
1750 RouteUI::setup_comment_editor ()
1751 {
1752         comment_window = new ArdourWindow (""); // title will be reset to show route
1753         comment_window->set_skip_taskbar_hint (true);
1754         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1755         comment_window->set_default_size (400, 200);
1756
1757         comment_area = manage (new TextView());
1758         comment_area->set_name ("MixerTrackCommentArea");
1759         comment_area->set_wrap_mode (WRAP_WORD);
1760         comment_area->set_editable (true);
1761         comment_area->get_buffer()->set_text (_route->comment());
1762         comment_area->show ();
1763
1764         comment_window->add (*comment_area);
1765 }
1766
1767 void
1768 RouteUI::comment_changed ()
1769 {
1770         ignore_comment_edit = true;
1771         if (comment_area) {
1772                 comment_area->get_buffer()->set_text (_route->comment());
1773         }
1774         ignore_comment_edit = false;
1775 }
1776
1777 void
1778 RouteUI::comment_editor_done_editing ()
1779 {
1780         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1781
1782         string const str = comment_area->get_buffer()->get_text();
1783         if (str == _route->comment ()) {
1784                 return;
1785         }
1786
1787         _route->set_comment (str, this);
1788 }
1789
1790 void
1791 RouteUI::set_route_active (bool a, bool apply_to_selection)
1792 {
1793         if (apply_to_selection) {
1794                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1795         } else {
1796                 _route->set_active (a, this);
1797         }
1798 }
1799
1800 void
1801 RouteUI::duplicate_selected_routes ()
1802 {
1803         ARDOUR_UI::instance()->start_duplicate_routes();
1804 }
1805
1806 void
1807 RouteUI::toggle_denormal_protection ()
1808 {
1809         if (denormal_menu_item) {
1810
1811                 bool x;
1812
1813                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1814
1815                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1816                         _route->set_denormal_protection (x);
1817                 }
1818         }
1819 }
1820
1821 void
1822 RouteUI::denormal_protection_changed ()
1823 {
1824         if (denormal_menu_item) {
1825                 denormal_menu_item->set_active (_route->denormal_protection());
1826         }
1827 }
1828
1829 void
1830 RouteUI::disconnect_input ()
1831 {
1832         _route->input()->disconnect (this);
1833 }
1834
1835 void
1836 RouteUI::disconnect_output ()
1837 {
1838         _route->output()->disconnect (this);
1839 }
1840
1841 bool
1842 RouteUI::is_track () const
1843 {
1844         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1845 }
1846
1847 boost::shared_ptr<Track>
1848 RouteUI::track() const
1849 {
1850         return boost::dynamic_pointer_cast<Track>(_route);
1851 }
1852
1853 bool
1854 RouteUI::is_audio_track () const
1855 {
1856         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1857 }
1858
1859 boost::shared_ptr<AudioTrack>
1860 RouteUI::audio_track() const
1861 {
1862         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1863 }
1864
1865 bool
1866 RouteUI::is_midi_track () const
1867 {
1868         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1869 }
1870
1871 boost::shared_ptr<MidiTrack>
1872 RouteUI::midi_track() const
1873 {
1874         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1875 }
1876
1877 bool
1878 RouteUI::has_audio_outputs () const
1879 {
1880         return (_route->n_outputs().n_audio() > 0);
1881 }
1882
1883 string
1884 RouteUI::name() const
1885 {
1886         return _route->name();
1887 }
1888
1889 void
1890 RouteUI::map_frozen ()
1891 {
1892         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1893
1894         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1895
1896         if (at) {
1897                 check_rec_enable_sensitivity ();
1898         }
1899 }
1900
1901 void
1902 RouteUI::adjust_latency ()
1903 {
1904         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1905 }
1906
1907 bool
1908 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1909 {
1910         std::string path;
1911         std::string safe_name;
1912         std::string name;
1913
1914         prompter.get_result (name, true);
1915
1916         safe_name = legalize_for_path (name);
1917         safe_name += template_suffix;
1918
1919         path = Glib::build_filename (dir, safe_name);
1920
1921         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1922                 bool overwrite = overwrite_file_dialog (prompter,
1923                                                         _("Confirm Template Overwrite"),
1924                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1925
1926                 if (!overwrite) {
1927                         return false;
1928                 }
1929         }
1930
1931         _route->save_as_template (path, name);
1932
1933         return true;
1934 }
1935
1936 void
1937 RouteUI::save_as_template ()
1938 {
1939         std::string dir;
1940
1941         dir = ARDOUR::user_route_template_directory ();
1942
1943         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1944                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1945                 return;
1946         }
1947
1948         ArdourPrompter prompter (true); // modal
1949
1950         prompter.set_title (_("Save As Template"));
1951         prompter.set_prompt (_("Template name:"));
1952         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1953
1954         bool finished = false;
1955         while (!finished) {
1956                 switch (prompter.run()) {
1957                 case RESPONSE_ACCEPT:
1958                         finished = process_save_template_prompter (prompter, dir);
1959                         break;
1960                 default:
1961                         finished = true;
1962                         break;
1963                 }
1964         }
1965 }
1966
1967 void
1968 RouteUI::check_rec_enable_sensitivity ()
1969 {
1970         if (!rec_enable_button) {
1971                 assert (0); // This should not happen
1972                 return;
1973         }
1974         if (!_session->writable()) {
1975                 rec_enable_button->set_sensitive (false);
1976                 return;
1977         }
1978
1979         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1980                 rec_enable_button->set_sensitive (false);
1981         } else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1982                 rec_enable_button->set_sensitive (false);
1983         } else {
1984                 rec_enable_button->set_sensitive (true);
1985         }
1986         if (_route && _route->record_safe ()) {
1987                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1988         } else {
1989                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1990         }
1991         update_monitoring_display ();
1992 }
1993
1994 void
1995 RouteUI::parameter_changed (string const & p)
1996 {
1997         /* this handles RC and per-session parameter changes */
1998
1999         if (p == "disable-disarm-during-roll") {
2000                 check_rec_enable_sensitivity ();
2001         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2002                 set_button_names ();
2003         } else if (p == "auto-input") {
2004                 update_monitoring_display ();
2005         } else if (p == "blink-rec-arm") {
2006                 if (UIConfiguration::instance().get_blink_rec_arm()) {
2007                         rec_blink_connection.disconnect ();
2008                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2009                 } else {
2010                         rec_blink_connection.disconnect ();
2011                         RouteUI::blink_rec_display(false);
2012                 }
2013         }
2014 }
2015
2016 void
2017 RouteUI::step_gain_up ()
2018 {
2019         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2020 }
2021
2022 void
2023 RouteUI::page_gain_up ()
2024 {
2025         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2026 }
2027
2028 void
2029 RouteUI::step_gain_down ()
2030 {
2031         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2032 }
2033
2034 void
2035 RouteUI::page_gain_down ()
2036 {
2037         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2038 }
2039
2040 void
2041 RouteUI::open_remote_control_id_dialog ()
2042 {
2043         ArdourDialog dialog (_("Remote Control ID"));
2044         SpinButton* spin = 0;
2045
2046         dialog.get_vbox()->set_border_width (18);
2047
2048         if (Config->get_remote_model() == UserOrdered) {
2049                 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2050
2051                 HBox* hbox = manage (new HBox);
2052                 hbox->set_spacing (6);
2053                 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2054                 spin = manage (new SpinButton);
2055                 spin->set_digits (0);
2056                 spin->set_increments (1, 10);
2057                 spin->set_range (0, limit);
2058                 spin->set_value (_route->remote_control_id());
2059                 hbox->pack_start (*spin);
2060                 dialog.get_vbox()->pack_start (*hbox);
2061
2062                 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2063                 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2064         } else {
2065                 Label* l = manage (new Label());
2066                 if (_route->is_master() || _route->is_monitor()) {
2067                         l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2068                                                          "The remote control ID of %3 cannot be changed."),
2069                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2070                                                        _route->remote_control_id(),
2071                                                        (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2072                 } else {
2073                         l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2074                                                          "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2075                                                          "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2076                                                        (is_track() ? _("track") : _("bus")),
2077                                                        _route->remote_control_id(),
2078                                                        "<span size=\"small\" style=\"italic\">",
2079                                                        "</span>",
2080                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2081                                                        PROGRAM_NAME));
2082                 }
2083                 dialog.get_vbox()->pack_start (*l);
2084                 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2085         }
2086
2087         dialog.show_all ();
2088         int const r = dialog.run ();
2089
2090         if (r == RESPONSE_ACCEPT && spin) {
2091                 _route->set_remote_control_id (spin->get_value_as_int ());
2092         }
2093 }
2094
2095 void
2096 RouteUI::setup_invert_buttons ()
2097 {
2098         /* remove old invert buttons */
2099         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2100                 _invert_button_box.remove (**i);
2101         }
2102
2103         _invert_buttons.clear ();
2104
2105         if (!_route || !_route->input()) {
2106                 return;
2107         }
2108
2109         uint32_t const N = _route->input()->n_ports().n_audio ();
2110
2111         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2112
2113         for (uint32_t i = 0; i < to_add; ++i) {
2114                 ArdourButton* b = manage (new ArdourButton);
2115                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2116                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2117
2118                 b->set_name (X_("invert button"));
2119                 if (to_add == 1) {
2120                         if (N > 1) {
2121                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2122                         } else {
2123                                 b->set_text (X_("Ø"));
2124                         }
2125                 } else {
2126                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2127                 }
2128
2129                 if (N <= _max_invert_buttons) {
2130                         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));
2131                 } else {
2132                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2133                 }
2134
2135                 _invert_buttons.push_back (b);
2136                 _invert_button_box.pack_start (*b);
2137         }
2138
2139         _invert_button_box.set_spacing (1);
2140         _invert_button_box.show_all ();
2141 }
2142
2143 void
2144 RouteUI::set_invert_button_state ()
2145 {
2146         uint32_t const N = _route->input()->n_ports().n_audio();
2147         if (N > _max_invert_buttons) {
2148
2149                 /* One button for many channels; explicit active if all channels are inverted,
2150                    implicit active if some are, off if none are.
2151                 */
2152
2153                 ArdourButton* b = _invert_buttons.front ();
2154
2155                 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2156                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2157                 } else if (_route->phase_invert().any()) {
2158                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2159                 } else {
2160                         b->set_active_state (Gtkmm2ext::Off);
2161                 }
2162
2163         } else {
2164
2165                 /* One button per channel; just set active */
2166
2167                 int j = 0;
2168                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2169                         (*i)->set_active (_route->phase_invert (j));
2170                 }
2171
2172         }
2173 }
2174
2175 bool
2176 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2177 {
2178         if (ev->button == 1 && i < _invert_buttons.size()) {
2179                 uint32_t const N = _route->input()->n_ports().n_audio ();
2180                 if (N <= _max_invert_buttons) {
2181                         /* left-click inverts phase so long as we have a button per channel */
2182                         _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2183                         return false;
2184                 }
2185         }
2186         return false;
2187 }
2188
2189
2190 bool
2191 RouteUI::invert_press (GdkEventButton* ev)
2192 {
2193         using namespace Menu_Helpers;
2194
2195         uint32_t const N = _route->input()->n_ports().n_audio();
2196         if (N <= _max_invert_buttons && ev->button != 3) {
2197                 /* If we have an invert button per channel, we only pop
2198                    up a menu on right-click; left click is handled
2199                    on release.
2200                 */
2201                 return false;
2202         }
2203
2204         delete _invert_menu;
2205         _invert_menu = new Menu;
2206         _invert_menu->set_name ("ArdourContextMenu");
2207         MenuList& items = _invert_menu->items ();
2208
2209         for (uint32_t i = 0; i < N; ++i) {
2210                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2211                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2212                 ++_i_am_the_modifier;
2213                 e->set_active (_route->phase_invert (i));
2214                 --_i_am_the_modifier;
2215         }
2216
2217         _invert_menu->popup (0, ev->time);
2218
2219         return true;
2220 }
2221
2222 void
2223 RouteUI::invert_menu_toggled (uint32_t c)
2224 {
2225         if (_i_am_the_modifier) {
2226                 return;
2227         }
2228
2229         _route->set_phase_invert (c, !_route->phase_invert (c));
2230 }
2231
2232 void
2233 RouteUI::set_invert_sensitive (bool yn)
2234 {
2235         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2236                 (*b)->set_sensitive (yn);
2237         }
2238 }
2239
2240 void
2241 RouteUI::request_redraw ()
2242 {
2243         if (_route) {
2244                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2245         }
2246 }
2247
2248 /** The Route's gui_changed signal has been emitted */
2249 void
2250 RouteUI::route_gui_changed (string what_changed)
2251 {
2252         if (what_changed == "color") {
2253                 if (set_color_from_route () == 0) {
2254                         route_color_changed ();
2255                 }
2256         }
2257 }
2258
2259 void
2260 RouteUI::track_mode_changed (void)
2261 {
2262         assert(is_track());
2263         switch (track()->mode()) {
2264                 case ARDOUR::NonLayered:
2265                 case ARDOUR::Normal:
2266                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2267                         break;
2268                 case ARDOUR::Destructive:
2269                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2270                         break;
2271         }
2272         rec_enable_button->queue_draw();
2273 }
2274
2275 /** @return the color that this route should use; it maybe its own,
2276     or it maybe that of its route group.
2277 */
2278 Gdk::Color
2279 RouteUI::color () const
2280 {
2281         RouteGroup* g = _route->route_group ();
2282
2283         if (g && g->is_color()) {
2284                 Gdk::Color c;
2285                 set_color_from_rgba (c, GroupTabs::group_color (g));
2286                 return c;
2287         }
2288
2289         return _color;
2290 }
2291
2292 void
2293 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2294 {
2295         _showing_sends_to = send_to;
2296         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2297 }
2298
2299 void
2300 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2301 {
2302         if (_route == send_to) {
2303                 show_sends_button->set_active (true);
2304                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2305         } else {
2306                 show_sends_button->set_active (false);
2307                 send_blink_connection.disconnect ();
2308         }
2309 }
2310
2311 RouteGroup*
2312 RouteUI::route_group() const
2313 {
2314         return _route->route_group();
2315 }
2316
2317
2318 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2319         : WM::ProxyBase (name, string())
2320         , _route (boost::weak_ptr<Route> (route))
2321 {
2322         route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2323 }
2324
2325 RoutePinWindowProxy::~RoutePinWindowProxy()
2326 {
2327         _window = 0;
2328 }
2329
2330 ARDOUR::SessionHandlePtr*
2331 RoutePinWindowProxy::session_handle ()
2332 {
2333         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2334         if (aw) { return aw; }
2335         return 0;
2336 }
2337
2338 Gtk::Window*
2339 RoutePinWindowProxy::get (bool create)
2340 {
2341         boost::shared_ptr<Route> r = _route.lock ();
2342         if (!r) {
2343                 return 0;
2344         }
2345
2346         if (!_window) {
2347                 if (!create) {
2348                         return 0;
2349                 }
2350                 _window = new PluginPinDialog (r);
2351                 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2352                 if (aw) {
2353                         aw->set_session (_session);
2354                 }
2355                 _window->show_all ();
2356         }
2357         return _window;
2358 }
2359
2360 void
2361 RoutePinWindowProxy::route_going_away ()
2362 {
2363         delete _window;
2364         _window = 0;
2365         WM::Manager::instance().remove (this);
2366         going_away_connection.disconnect();
2367 }
2368
2369 void
2370 RouteUI::maybe_add_route_print_mgr ()
2371 {
2372         if (_route->pinmgr_proxy ()) {
2373                 return;
2374         }
2375         RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2376                         string_compose ("RPM-%1", _route->id()), _route);
2377         wp->set_session (_session);
2378
2379         const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2380         if (ui_xml) {
2381                 wp->set_state (*ui_xml, 0);
2382         }
2383
2384 #if 0
2385         void* existing_ui = _route->pinmgr_proxy ();
2386         if (existing_ui) {
2387                 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2388         }
2389 #endif
2390         _route->set_pingmgr_proxy (wp);
2391
2392         WM::Manager::instance().register_window (wp);
2393 }
2394
2395 void
2396 RouteUI::manage_pins ()
2397 {
2398         RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2399         if (proxy) {
2400                 proxy->get (true);
2401                 proxy->present();
2402         }
2403 }