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