show VCA master mute state in RouteUI, even if Config->get_show_solo_mutes() is false...
[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         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1247
1248                 if (r->muted ()) {
1249                         /* full mute */
1250                         return Gtkmm2ext::ExplicitActive;
1251                 } else if (r->muted_by_others ()) {
1252                         /* this will reflect both solo mutes AND master mutes */
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 if (r->mute_master()->muted_by_others()) {
1265                         /* note the direct use of MuteMaster API here. We are
1266                            not interested in showing
1267                            others-soloed-so-this-muted status in this branch.
1268                         */
1269                         return Gtkmm2ext::ImplicitActive;
1270                 } else {
1271                         /* no mute at all */
1272                         return Gtkmm2ext::Off;
1273                 }
1274         }
1275
1276         return ActiveState(0);
1277 }
1278
1279 void
1280 RouteUI::update_mute_display ()
1281 {
1282         if (!_route) {
1283                 return;
1284         }
1285
1286         mute_button->set_active_state (mute_active_state (_session, _route));
1287 }
1288
1289 void
1290 RouteUI::update_vca_display ()
1291 {
1292         if (!vca_button) {
1293                 return;
1294         }
1295
1296         VCAList vcas (_session->vca_manager().vcas());
1297         string label;
1298
1299         for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1300                 if (_route->slaved_to (*v)) {
1301                         if (!label.empty()) {
1302                                 label += ' ';
1303                         }
1304                         label += PBD::to_string ((*v)->number(), std::dec);
1305                 }
1306         }
1307
1308         if (label.empty()) {
1309                 label = _("-vca-");
1310                 vca_button->set_active_state (Gtkmm2ext::Off);
1311         } else {
1312                 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1313         }
1314
1315         vca_button->set_text (label);
1316 }
1317
1318 void
1319 RouteUI::route_rec_enable_changed ()
1320 {
1321         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1322         update_monitoring_display ();
1323 }
1324
1325 void
1326 RouteUI::session_rec_enable_changed ()
1327 {
1328         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1329         update_monitoring_display ();
1330 }
1331
1332 void
1333 RouteUI::blink_rec_display (bool blinkOn)
1334 {
1335         if (!rec_enable_button || !_route) {
1336                 return;
1337         }
1338         if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1339                 return;
1340         }
1341
1342         if (_route->record_enabled()) {
1343                 switch (_session->record_status ()) {
1344                 case Session::Recording:
1345                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1346                         break;
1347
1348                 case Session::Disabled:
1349                 case Session::Enabled:
1350                         if ( UIConfiguration::instance().get_blink_rec_arm() )
1351                                                         rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1352                                                 else
1353                                                         rec_enable_button->set_active_state ( ImplicitActive );
1354                         break;
1355
1356                 }
1357
1358                 if (step_edit_item) {
1359                         step_edit_item->set_sensitive (false);
1360                 }
1361
1362         } else {
1363                 rec_enable_button->unset_active_state ();
1364
1365                 if (step_edit_item) {
1366                         step_edit_item->set_sensitive (true);
1367                 }
1368         }
1369
1370         check_rec_enable_sensitivity ();
1371 }
1372
1373 void
1374 RouteUI::build_solo_menu (void)
1375 {
1376         using namespace Menu_Helpers;
1377
1378         solo_menu = new Menu;
1379         solo_menu->set_name ("ArdourContextMenu");
1380         MenuList& items = solo_menu->items();
1381         Gtk::CheckMenuItem* check;
1382
1383         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1384         check->set_active (_route->solo_isolated());
1385         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1386         items.push_back (CheckMenuElem(*check));
1387         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1388         check->show_all();
1389
1390         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1391         check->set_active (_route->solo_safe());
1392         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1393         items.push_back (CheckMenuElem(*check));
1394         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1395         check->show_all();
1396
1397         //items.push_back (SeparatorElem());
1398         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1399
1400 }
1401
1402 void
1403 RouteUI::build_mute_menu(void)
1404 {
1405         using namespace Menu_Helpers;
1406
1407         mute_menu = new Menu;
1408         mute_menu->set_name ("ArdourContextMenu");
1409
1410         MenuList& items = mute_menu->items();
1411
1412         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1413         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1414         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1415         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1416         pre_fader_mute_check->show_all();
1417
1418         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1419         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1420         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1421         items.push_back (CheckMenuElem(*post_fader_mute_check));
1422         post_fader_mute_check->show_all();
1423
1424         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1425         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1426         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1427         items.push_back (CheckMenuElem(*listen_mute_check));
1428         listen_mute_check->show_all();
1429
1430         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1431         init_mute_menu(MuteMaster::Main, main_mute_check);
1432         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1433         items.push_back (CheckMenuElem(*main_mute_check));
1434         main_mute_check->show_all();
1435
1436         //items.push_back (SeparatorElem());
1437         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1438
1439         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1440 }
1441
1442 void
1443 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1444 {
1445         check->set_active (_route->mute_points() & mp);
1446 }
1447
1448 void
1449 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1450 {
1451         if (check->get_active()) {
1452                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1453         } else {
1454                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1455         }
1456 }
1457
1458 void
1459 RouteUI::muting_change ()
1460 {
1461         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1462
1463         bool yn;
1464         MuteMaster::MutePoint current = _route->mute_points ();
1465
1466         yn = (current & MuteMaster::PreFader);
1467
1468         if (pre_fader_mute_check->get_active() != yn) {
1469                 pre_fader_mute_check->set_active (yn);
1470         }
1471
1472         yn = (current & MuteMaster::PostFader);
1473
1474         if (post_fader_mute_check->get_active() != yn) {
1475                 post_fader_mute_check->set_active (yn);
1476         }
1477
1478         yn = (current & MuteMaster::Listen);
1479
1480         if (listen_mute_check->get_active() != yn) {
1481                 listen_mute_check->set_active (yn);
1482         }
1483
1484         yn = (current & MuteMaster::Main);
1485
1486         if (main_mute_check->get_active() != yn) {
1487                 main_mute_check->set_active (yn);
1488         }
1489 }
1490
1491 bool
1492 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1493 {
1494         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1495                 return true;
1496         }
1497
1498         bool view = solo_isolated_led->active_state();
1499         bool model = _route->solo_isolated();
1500
1501         /* called BEFORE the view has changed */
1502
1503         if (ev->button == 1) {
1504                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1505
1506                         if (model) {
1507                                 /* disable isolate for all routes */
1508                                 DisplaySuspender ds;
1509                                 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1510                         } else {
1511                                 /* enable isolate for all routes */
1512                                 DisplaySuspender ds;
1513                                 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1514                         }
1515
1516                 } else {
1517
1518                         if (model == view) {
1519
1520                                 /* flip just this route */
1521
1522                                 boost::shared_ptr<RouteList> rl (new RouteList);
1523                                 rl->push_back (_route);
1524                                 DisplaySuspender ds;
1525                                 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1526                         }
1527                 }
1528         }
1529
1530         return false;
1531 }
1532
1533 bool
1534 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1535 {
1536         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1537                 return true;
1538         }
1539
1540         bool view = solo_safe_led->active_state();
1541         bool model = _route->solo_safe();
1542
1543         if (ev->button == 1) {
1544                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1545                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1546                         if (model) {
1547                                 /* disable solo safe for all routes */
1548                                 DisplaySuspender ds;
1549                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1550                                         (*i)->set_solo_safe (false, Controllable::NoGroup);
1551                                 }
1552                         } else {
1553                                 /* enable solo safe for all routes */
1554                                 DisplaySuspender ds;
1555                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1556                                         (*i)->set_solo_safe (true, Controllable::NoGroup);
1557                                 }
1558                         }
1559                 }
1560                 else {
1561                         if (model == view) {
1562                                 /* flip just this route */
1563                                 _route->set_solo_safe (!view, Controllable::NoGroup);
1564                         }
1565                 }
1566         }
1567
1568         return false;
1569 }
1570
1571 void
1572 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1573 {
1574         bool view = check->get_active();
1575         bool model = _route->solo_isolated();
1576
1577         /* called AFTER the view has changed */
1578
1579         if (model != view) {
1580                 _route->set_solo_isolated (view, Controllable::UseGroup);
1581         }
1582 }
1583
1584 void
1585 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1586 {
1587         _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1588 }
1589
1590 /** Ask the user to choose a colour, and then apply that color to my route
1591  */
1592 void
1593 RouteUI::choose_color ()
1594 {
1595         bool picked;
1596         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1597
1598         if (picked) {
1599                 set_color(color);
1600         }
1601 }
1602
1603 /** Set the route's own color.  This may not be used for display if
1604  *  the route is in a group which shares its color with its routes.
1605  */
1606 void
1607 RouteUI::set_color (const Gdk::Color & c)
1608 {
1609         /* leave _color alone in the group case so that tracks can retain their
1610          * own pre-group colors.
1611          */
1612
1613         char buf[64];
1614         _color = c;
1615         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1616
1617         /* note: we use the route state ID here so that color is the same for both
1618            the time axis view and the mixer strip
1619         */
1620
1621         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1622         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1623 }
1624
1625 /** @return GUI state ID for things that are common to the route in all its representations */
1626 string
1627 RouteUI::route_state_id () const
1628 {
1629         return string_compose (X_("route %1"), _route->id().to_s());
1630 }
1631
1632 int
1633 RouteUI::set_color_from_route ()
1634 {
1635         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1636
1637         if (str.empty()) {
1638                 return 1;
1639         }
1640
1641         int r, g, b;
1642
1643         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1644
1645         _color.set_red (r);
1646         _color.set_green (g);
1647         _color.set_blue (b);
1648
1649         return 0;
1650 }
1651
1652 /** @return true if this name should be used for the route, otherwise false */
1653 bool
1654 RouteUI::verify_new_route_name (const std::string& name)
1655 {
1656         if (name.find (':') == string::npos) {
1657                 return true;
1658         }
1659
1660         MessageDialog colon_msg (
1661                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1662                 false, MESSAGE_QUESTION, BUTTONS_NONE
1663                 );
1664
1665         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1666         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1667
1668         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1669 }
1670
1671 void
1672 RouteUI::route_rename ()
1673 {
1674         ArdourPrompter name_prompter (true);
1675         string result;
1676         bool done = false;
1677
1678         if (is_track()) {
1679                 name_prompter.set_title (_("Rename Track"));
1680         } else {
1681                 name_prompter.set_title (_("Rename Bus"));
1682         }
1683         name_prompter.set_prompt (_("New name:"));
1684         name_prompter.set_initial_text (_route->name());
1685         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1686         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1687         name_prompter.show_all ();
1688
1689         while (!done) {
1690                 switch (name_prompter.run ()) {
1691                 case Gtk::RESPONSE_ACCEPT:
1692                         name_prompter.get_result (result);
1693                         name_prompter.hide ();
1694                         if (result.length()) {
1695                                 if (verify_new_route_name (result)) {
1696                                         _route->set_name (result);
1697                                         done = true;
1698                                 } else {
1699                                         /* back to name prompter */
1700                                 }
1701
1702                         } else {
1703                                 /* nothing entered, just get out of here */
1704                                 done = true;
1705                         }
1706                         break;
1707                 default:
1708                         done = true;
1709                         break;
1710                 }
1711         }
1712
1713         return;
1714
1715 }
1716
1717 void
1718 RouteUI::property_changed (const PropertyChange& what_changed)
1719 {
1720         if (what_changed.contains (ARDOUR::Properties::name)) {
1721                 name_label.set_text (_route->name());
1722         }
1723 }
1724
1725 void
1726 RouteUI::toggle_comment_editor ()
1727 {
1728 //      if (ignore_toggle) {
1729 //              return;
1730 //      }
1731
1732         if (comment_window && comment_window->is_visible ()) {
1733                 comment_window->hide ();
1734         } else {
1735                 open_comment_editor ();
1736         }
1737 }
1738
1739
1740 void
1741 RouteUI::open_comment_editor ()
1742 {
1743         if (comment_window == 0) {
1744                 setup_comment_editor ();
1745         }
1746
1747         string title;
1748         title = _route->name();
1749         title += _(": comment editor");
1750
1751         comment_window->set_title (title);
1752         comment_window->present();
1753 }
1754
1755 void
1756 RouteUI::setup_comment_editor ()
1757 {
1758         comment_window = new ArdourWindow (""); // title will be reset to show route
1759         comment_window->set_skip_taskbar_hint (true);
1760         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1761         comment_window->set_default_size (400, 200);
1762
1763         comment_area = manage (new TextView());
1764         comment_area->set_name ("MixerTrackCommentArea");
1765         comment_area->set_wrap_mode (WRAP_WORD);
1766         comment_area->set_editable (true);
1767         comment_area->get_buffer()->set_text (_route->comment());
1768         comment_area->show ();
1769
1770         comment_window->add (*comment_area);
1771 }
1772
1773 void
1774 RouteUI::comment_changed ()
1775 {
1776         ignore_comment_edit = true;
1777         if (comment_area) {
1778                 comment_area->get_buffer()->set_text (_route->comment());
1779         }
1780         ignore_comment_edit = false;
1781 }
1782
1783 void
1784 RouteUI::comment_editor_done_editing ()
1785 {
1786         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1787
1788         string const str = comment_area->get_buffer()->get_text();
1789         if (str == _route->comment ()) {
1790                 return;
1791         }
1792
1793         _route->set_comment (str, this);
1794 }
1795
1796 void
1797 RouteUI::set_route_active (bool a, bool apply_to_selection)
1798 {
1799         if (apply_to_selection) {
1800                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1801         } else {
1802                 _route->set_active (a, this);
1803         }
1804 }
1805
1806 void
1807 RouteUI::duplicate_selected_routes ()
1808 {
1809         ARDOUR_UI::instance()->start_duplicate_routes();
1810 }
1811
1812 void
1813 RouteUI::toggle_denormal_protection ()
1814 {
1815         if (denormal_menu_item) {
1816
1817                 bool x;
1818
1819                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1820
1821                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1822                         _route->set_denormal_protection (x);
1823                 }
1824         }
1825 }
1826
1827 void
1828 RouteUI::denormal_protection_changed ()
1829 {
1830         if (denormal_menu_item) {
1831                 denormal_menu_item->set_active (_route->denormal_protection());
1832         }
1833 }
1834
1835 void
1836 RouteUI::disconnect_input ()
1837 {
1838         _route->input()->disconnect (this);
1839 }
1840
1841 void
1842 RouteUI::disconnect_output ()
1843 {
1844         _route->output()->disconnect (this);
1845 }
1846
1847 bool
1848 RouteUI::is_track () const
1849 {
1850         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1851 }
1852
1853 boost::shared_ptr<Track>
1854 RouteUI::track() const
1855 {
1856         return boost::dynamic_pointer_cast<Track>(_route);
1857 }
1858
1859 bool
1860 RouteUI::is_audio_track () const
1861 {
1862         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1863 }
1864
1865 boost::shared_ptr<AudioTrack>
1866 RouteUI::audio_track() const
1867 {
1868         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1869 }
1870
1871 bool
1872 RouteUI::is_midi_track () const
1873 {
1874         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1875 }
1876
1877 boost::shared_ptr<MidiTrack>
1878 RouteUI::midi_track() const
1879 {
1880         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1881 }
1882
1883 bool
1884 RouteUI::has_audio_outputs () const
1885 {
1886         return (_route->n_outputs().n_audio() > 0);
1887 }
1888
1889 string
1890 RouteUI::name() const
1891 {
1892         return _route->name();
1893 }
1894
1895 void
1896 RouteUI::map_frozen ()
1897 {
1898         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1899
1900         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1901
1902         if (at) {
1903                 check_rec_enable_sensitivity ();
1904         }
1905 }
1906
1907 void
1908 RouteUI::adjust_latency ()
1909 {
1910         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1911 }
1912
1913 bool
1914 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1915 {
1916         std::string path;
1917         std::string safe_name;
1918         std::string name;
1919
1920         prompter.get_result (name, true);
1921
1922         safe_name = legalize_for_path (name);
1923         safe_name += template_suffix;
1924
1925         path = Glib::build_filename (dir, safe_name);
1926
1927         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1928                 bool overwrite = overwrite_file_dialog (prompter,
1929                                                         _("Confirm Template Overwrite"),
1930                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1931
1932                 if (!overwrite) {
1933                         return false;
1934                 }
1935         }
1936
1937         _route->save_as_template (path, name);
1938
1939         return true;
1940 }
1941
1942 void
1943 RouteUI::save_as_template ()
1944 {
1945         std::string dir;
1946
1947         dir = ARDOUR::user_route_template_directory ();
1948
1949         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1950                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1951                 return;
1952         }
1953
1954         ArdourPrompter prompter (true); // modal
1955
1956         prompter.set_title (_("Save As Template"));
1957         prompter.set_prompt (_("Template name:"));
1958         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1959
1960         bool finished = false;
1961         while (!finished) {
1962                 switch (prompter.run()) {
1963                 case RESPONSE_ACCEPT:
1964                         finished = process_save_template_prompter (prompter, dir);
1965                         break;
1966                 default:
1967                         finished = true;
1968                         break;
1969                 }
1970         }
1971 }
1972
1973 void
1974 RouteUI::check_rec_enable_sensitivity ()
1975 {
1976         if (!rec_enable_button) {
1977                 assert (0); // This should not happen
1978                 return;
1979         }
1980         if (!_session->writable()) {
1981                 rec_enable_button->set_sensitive (false);
1982                 return;
1983         }
1984
1985         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1986                 rec_enable_button->set_sensitive (false);
1987         } else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1988                 rec_enable_button->set_sensitive (false);
1989         } else {
1990                 rec_enable_button->set_sensitive (true);
1991         }
1992         if (_route && _route->record_safe ()) {
1993                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1994         } else {
1995                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1996         }
1997         update_monitoring_display ();
1998 }
1999
2000 void
2001 RouteUI::parameter_changed (string const & p)
2002 {
2003         /* this handles RC and per-session parameter changes */
2004
2005         if (p == "disable-disarm-during-roll") {
2006                 check_rec_enable_sensitivity ();
2007         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2008                 set_button_names ();
2009         } else if (p == "auto-input") {
2010                 update_monitoring_display ();
2011         } else if (p == "blink-rec-arm") {
2012                 if (UIConfiguration::instance().get_blink_rec_arm()) {
2013                         rec_blink_connection.disconnect ();
2014                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2015                 } else {
2016                         rec_blink_connection.disconnect ();
2017                         RouteUI::blink_rec_display(false);
2018                 }
2019         }
2020 }
2021
2022 void
2023 RouteUI::step_gain_up ()
2024 {
2025         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2026 }
2027
2028 void
2029 RouteUI::page_gain_up ()
2030 {
2031         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2032 }
2033
2034 void
2035 RouteUI::step_gain_down ()
2036 {
2037         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2038 }
2039
2040 void
2041 RouteUI::page_gain_down ()
2042 {
2043         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2044 }
2045
2046 void
2047 RouteUI::open_remote_control_id_dialog ()
2048 {
2049         ArdourDialog dialog (_("Remote Control ID"));
2050         SpinButton* spin = 0;
2051
2052         dialog.get_vbox()->set_border_width (18);
2053
2054         if (Config->get_remote_model() == UserOrdered) {
2055                 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
2056
2057                 HBox* hbox = manage (new HBox);
2058                 hbox->set_spacing (6);
2059                 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
2060                 spin = manage (new SpinButton);
2061                 spin->set_digits (0);
2062                 spin->set_increments (1, 10);
2063                 spin->set_range (0, limit);
2064                 spin->set_value (_route->remote_control_id());
2065                 hbox->pack_start (*spin);
2066                 dialog.get_vbox()->pack_start (*hbox);
2067
2068                 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2069                 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2070         } else {
2071                 Label* l = manage (new Label());
2072                 if (_route->is_master() || _route->is_monitor()) {
2073                         l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2074                                                          "The remote control ID of %3 cannot be changed."),
2075                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2076                                                        _route->remote_control_id(),
2077                                                        (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2078                 } else {
2079                         l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2080                                                          "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2081                                                          "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2082                                                        (is_track() ? _("track") : _("bus")),
2083                                                        _route->remote_control_id(),
2084                                                        "<span size=\"small\" style=\"italic\">",
2085                                                        "</span>",
2086                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2087                                                        PROGRAM_NAME));
2088                 }
2089                 dialog.get_vbox()->pack_start (*l);
2090                 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2091         }
2092
2093         dialog.show_all ();
2094         int const r = dialog.run ();
2095
2096         if (r == RESPONSE_ACCEPT && spin) {
2097                 _route->set_remote_control_id (spin->get_value_as_int ());
2098         }
2099 }
2100
2101 void
2102 RouteUI::setup_invert_buttons ()
2103 {
2104         /* remove old invert buttons */
2105         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2106                 _invert_button_box.remove (**i);
2107         }
2108
2109         _invert_buttons.clear ();
2110
2111         if (!_route || !_route->input()) {
2112                 return;
2113         }
2114
2115         uint32_t const N = _route->input()->n_ports().n_audio ();
2116
2117         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2118
2119         for (uint32_t i = 0; i < to_add; ++i) {
2120                 ArdourButton* b = manage (new ArdourButton);
2121                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2122                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2123
2124                 b->set_name (X_("invert button"));
2125                 if (to_add == 1) {
2126                         if (N > 1) {
2127                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2128                         } else {
2129                                 b->set_text (X_("Ø"));
2130                         }
2131                 } else {
2132                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2133                 }
2134
2135                 if (N <= _max_invert_buttons) {
2136                         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));
2137                 } else {
2138                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2139                 }
2140
2141                 _invert_buttons.push_back (b);
2142                 _invert_button_box.pack_start (*b);
2143         }
2144
2145         _invert_button_box.set_spacing (1);
2146         _invert_button_box.show_all ();
2147 }
2148
2149 void
2150 RouteUI::set_invert_button_state ()
2151 {
2152         uint32_t const N = _route->input()->n_ports().n_audio();
2153         if (N > _max_invert_buttons) {
2154
2155                 /* One button for many channels; explicit active if all channels are inverted,
2156                    implicit active if some are, off if none are.
2157                 */
2158
2159                 ArdourButton* b = _invert_buttons.front ();
2160
2161                 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2162                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2163                 } else if (_route->phase_invert().any()) {
2164                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2165                 } else {
2166                         b->set_active_state (Gtkmm2ext::Off);
2167                 }
2168
2169         } else {
2170
2171                 /* One button per channel; just set active */
2172
2173                 int j = 0;
2174                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2175                         (*i)->set_active (_route->phase_invert (j));
2176                 }
2177
2178         }
2179 }
2180
2181 bool
2182 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2183 {
2184         if (ev->button == 1 && i < _invert_buttons.size()) {
2185                 uint32_t const N = _route->input()->n_ports().n_audio ();
2186                 if (N <= _max_invert_buttons) {
2187                         /* left-click inverts phase so long as we have a button per channel */
2188                         _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2189                         return false;
2190                 }
2191         }
2192         return false;
2193 }
2194
2195
2196 bool
2197 RouteUI::invert_press (GdkEventButton* ev)
2198 {
2199         using namespace Menu_Helpers;
2200
2201         uint32_t const N = _route->input()->n_ports().n_audio();
2202         if (N <= _max_invert_buttons && ev->button != 3) {
2203                 /* If we have an invert button per channel, we only pop
2204                    up a menu on right-click; left click is handled
2205                    on release.
2206                 */
2207                 return false;
2208         }
2209
2210         delete _invert_menu;
2211         _invert_menu = new Menu;
2212         _invert_menu->set_name ("ArdourContextMenu");
2213         MenuList& items = _invert_menu->items ();
2214
2215         for (uint32_t i = 0; i < N; ++i) {
2216                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2217                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2218                 ++_i_am_the_modifier;
2219                 e->set_active (_route->phase_invert (i));
2220                 --_i_am_the_modifier;
2221         }
2222
2223         _invert_menu->popup (0, ev->time);
2224
2225         return true;
2226 }
2227
2228 void
2229 RouteUI::invert_menu_toggled (uint32_t c)
2230 {
2231         if (_i_am_the_modifier) {
2232                 return;
2233         }
2234
2235         _route->set_phase_invert (c, !_route->phase_invert (c));
2236 }
2237
2238 void
2239 RouteUI::set_invert_sensitive (bool yn)
2240 {
2241         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2242                 (*b)->set_sensitive (yn);
2243         }
2244 }
2245
2246 void
2247 RouteUI::request_redraw ()
2248 {
2249         if (_route) {
2250                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2251         }
2252 }
2253
2254 /** The Route's gui_changed signal has been emitted */
2255 void
2256 RouteUI::route_gui_changed (string what_changed)
2257 {
2258         if (what_changed == "color") {
2259                 if (set_color_from_route () == 0) {
2260                         route_color_changed ();
2261                 }
2262         }
2263 }
2264
2265 void
2266 RouteUI::track_mode_changed (void)
2267 {
2268         assert(is_track());
2269         switch (track()->mode()) {
2270                 case ARDOUR::NonLayered:
2271                 case ARDOUR::Normal:
2272                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2273                         break;
2274                 case ARDOUR::Destructive:
2275                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2276                         break;
2277         }
2278         rec_enable_button->queue_draw();
2279 }
2280
2281 /** @return the color that this route should use; it maybe its own,
2282     or it maybe that of its route group.
2283 */
2284 Gdk::Color
2285 RouteUI::color () const
2286 {
2287         RouteGroup* g = _route->route_group ();
2288
2289         if (g && g->is_color()) {
2290                 Gdk::Color c;
2291                 set_color_from_rgba (c, GroupTabs::group_color (g));
2292                 return c;
2293         }
2294
2295         return _color;
2296 }
2297
2298 void
2299 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2300 {
2301         _showing_sends_to = send_to;
2302         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2303 }
2304
2305 void
2306 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2307 {
2308         if (_route == send_to) {
2309                 show_sends_button->set_active (true);
2310                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2311         } else {
2312                 show_sends_button->set_active (false);
2313                 send_blink_connection.disconnect ();
2314         }
2315 }
2316
2317 RouteGroup*
2318 RouteUI::route_group() const
2319 {
2320         return _route->route_group();
2321 }
2322
2323
2324 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2325         : WM::ProxyBase (name, string())
2326         , _route (boost::weak_ptr<Route> (route))
2327 {
2328         route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2329 }
2330
2331 RoutePinWindowProxy::~RoutePinWindowProxy()
2332 {
2333         _window = 0;
2334 }
2335
2336 ARDOUR::SessionHandlePtr*
2337 RoutePinWindowProxy::session_handle ()
2338 {
2339         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2340         if (aw) { return aw; }
2341         return 0;
2342 }
2343
2344 Gtk::Window*
2345 RoutePinWindowProxy::get (bool create)
2346 {
2347         boost::shared_ptr<Route> r = _route.lock ();
2348         if (!r) {
2349                 return 0;
2350         }
2351
2352         if (!_window) {
2353                 if (!create) {
2354                         return 0;
2355                 }
2356                 _window = new PluginPinDialog (r);
2357                 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2358                 if (aw) {
2359                         aw->set_session (_session);
2360                 }
2361                 _window->show_all ();
2362         }
2363         return _window;
2364 }
2365
2366 void
2367 RoutePinWindowProxy::route_going_away ()
2368 {
2369         delete _window;
2370         _window = 0;
2371         WM::Manager::instance().remove (this);
2372         going_away_connection.disconnect();
2373 }
2374
2375 void
2376 RouteUI::maybe_add_route_print_mgr ()
2377 {
2378         if (_route->pinmgr_proxy ()) {
2379                 return;
2380         }
2381         RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2382                         string_compose ("RPM-%1", _route->id()), _route);
2383         wp->set_session (_session);
2384
2385         const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2386         if (ui_xml) {
2387                 wp->set_state (*ui_xml, 0);
2388         }
2389
2390 #if 0
2391         void* existing_ui = _route->pinmgr_proxy ();
2392         if (existing_ui) {
2393                 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2394         }
2395 #endif
2396         _route->set_pingmgr_proxy (wp);
2397
2398         WM::Manager::instance().register_window (wp);
2399 }
2400
2401 void
2402 RouteUI::manage_pins ()
2403 {
2404         RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2405         if (proxy) {
2406                 proxy->get (true);
2407                 proxy->present();
2408         }
2409 }