there is no explicit "Remote Control ID" control anymore - all done by ordering in...
[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, &Stripable::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, &Stripable::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, &Stripable::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(), &Stripable::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, &Stripable::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, &Stripable::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, &Stripable::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(), &Stripable::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, &Stripable::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, &Stripable::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->rec_enable_control()->get_value());
900                 rec_safe_item->set_active (_route->rec_safe_control()->get_value());
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         boost::shared_ptr<AutomationControl> rs = _route->rec_safe_control();
918
919         if (!rs) {
920                 return;
921         }
922
923         /* This check is made inside the control too, but dong it here can't
924          * hurt.
925          */
926
927         if (_route->rec_enable_control()->get_value()) {
928                 return;
929         }
930
931         rs->set_value (rec_safe_item->get_active (), Controllable::UseGroup);
932 }
933
934 void
935 RouteUI::step_edit_changed (bool yn)
936 {
937         if (yn) {
938                 if (rec_enable_button) {
939                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
940                 }
941
942                 start_step_editing ();
943
944                 if (step_edit_item) {
945                         step_edit_item->set_active (true);
946                 }
947
948         } else {
949
950                 if (rec_enable_button) {
951                         rec_enable_button->unset_active_state ();
952                 }
953
954                 stop_step_editing ();
955
956                 if (step_edit_item) {
957                         step_edit_item->set_active (false);
958                 }
959         }
960 }
961
962 bool
963 RouteUI::rec_enable_release (GdkEventButton* ev)
964 {
965         if (Keyboard::is_context_menu_event (ev)) {
966                 build_record_menu ();
967                 if (record_menu) {
968                         record_menu->popup (1, ev->time);
969                 }
970                 return false;
971         }
972
973         return false;
974 }
975
976 void
977 RouteUI::build_sends_menu ()
978 {
979         using namespace Menu_Helpers;
980
981         sends_menu = new Menu;
982         sends_menu->set_name ("ArdourContextMenu");
983         MenuList& items = sends_menu->items();
984
985         items.push_back (
986                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
987                 );
988
989         items.push_back (
990                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
991                 );
992
993         items.push_back (
994                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
995                 );
996
997         items.push_back (
998                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
999                 );
1000
1001         items.push_back (
1002                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
1003                 );
1004
1005         items.push_back (
1006                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
1007
1008         items.push_back (
1009                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1010                 );
1011
1012         items.push_back (
1013                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1014                 );
1015
1016         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1017         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1018         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1019
1020 }
1021
1022 void
1023 RouteUI::create_sends (Placement p, bool include_buses)
1024 {
1025         _session->globally_add_internal_sends (_route, p, include_buses);
1026 }
1027
1028 void
1029 RouteUI::create_selected_sends (Placement p, bool include_buses)
1030 {
1031         boost::shared_ptr<RouteList> rlist (new RouteList);
1032         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1033
1034         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1035                 RouteTimeAxisView* rtv;
1036                 RouteUI* rui;
1037                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1038                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1039                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1040                                         rlist->push_back (rui->route());
1041                                 }
1042                         }
1043                 }
1044         }
1045
1046         _session->add_internal_sends (_route, p, rlist);
1047 }
1048
1049 void
1050 RouteUI::set_sends_gain_from_track ()
1051 {
1052         _session->globally_set_send_gains_from_track (_route);
1053 }
1054
1055 void
1056 RouteUI::set_sends_gain_to_zero ()
1057 {
1058         _session->globally_set_send_gains_to_zero (_route);
1059 }
1060
1061 void
1062 RouteUI::set_sends_gain_to_unity ()
1063 {
1064         _session->globally_set_send_gains_to_unity (_route);
1065 }
1066
1067 bool
1068 RouteUI::show_sends_press(GdkEventButton* ev)
1069 {
1070         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1071                 return true;
1072         }
1073
1074         if (!is_track() && show_sends_button) {
1075
1076                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1077
1078                         // do nothing on midi sigc::bind event
1079                         return false;
1080
1081                 } else if (Keyboard::is_context_menu_event (ev)) {
1082
1083                         if (sends_menu == 0) {
1084                                 build_sends_menu ();
1085                         }
1086
1087                         sends_menu->popup (0, ev->time);
1088
1089                 } else {
1090
1091                         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1092
1093                         if (s == _route) {
1094                                 set_showing_sends_to (boost::shared_ptr<Route> ());
1095                         } else {
1096                                 set_showing_sends_to (_route);
1097                         }
1098                 }
1099         }
1100
1101         return true;
1102 }
1103
1104 bool
1105 RouteUI::show_sends_release (GdkEventButton*)
1106 {
1107         return true;
1108 }
1109
1110 void
1111 RouteUI::send_blink (bool onoff)
1112 {
1113         if (!show_sends_button) {
1114                 return;
1115         }
1116
1117         if (onoff) {
1118                 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1119         } else {
1120                 show_sends_button->unset_active_state ();
1121         }
1122 }
1123
1124 Gtkmm2ext::ActiveState
1125 RouteUI::solo_active_state (boost::shared_ptr<Stripable> s)
1126 {
1127         boost::shared_ptr<SoloControl> sc = s->solo_control();
1128
1129         if (!sc) {
1130                 return Gtkmm2ext::Off;
1131         }
1132
1133         if (!sc->can_solo()) {
1134                 return Gtkmm2ext::Off;
1135         }
1136
1137
1138         if (sc->self_soloed()) {
1139                 return Gtkmm2ext::ExplicitActive;
1140         } else if (sc->soloed_by_others()) {
1141                 return Gtkmm2ext::ImplicitActive;
1142         } else {
1143                 return Gtkmm2ext::Off;
1144         }
1145 }
1146
1147 Gtkmm2ext::ActiveState
1148 RouteUI::solo_isolate_active_state (boost::shared_ptr<Stripable> s)
1149 {
1150         boost::shared_ptr<SoloIsolateControl> sc = s->solo_isolate_control();
1151
1152         if (!sc) {
1153                 return Gtkmm2ext::Off;
1154         }
1155
1156         if (s->is_master() || s->is_monitor()) {
1157                 return Gtkmm2ext::Off;
1158         }
1159
1160         if (sc->solo_isolated()) {
1161                 return Gtkmm2ext::ExplicitActive;
1162         } else {
1163                 return Gtkmm2ext::Off;
1164         }
1165 }
1166
1167 Gtkmm2ext::ActiveState
1168 RouteUI::solo_safe_active_state (boost::shared_ptr<Stripable> s)
1169 {
1170         boost::shared_ptr<SoloSafeControl> sc = s->solo_safe_control();
1171
1172         if (!sc) {
1173                 return Gtkmm2ext::Off;
1174         }
1175
1176         if (s->is_master() || s->is_monitor()) {
1177                 return Gtkmm2ext::Off;
1178         }
1179
1180         if (sc->solo_safe()) {
1181                 return Gtkmm2ext::ExplicitActive;
1182         } else {
1183                 return Gtkmm2ext::Off;
1184         }
1185 }
1186
1187 void
1188 RouteUI::update_solo_display ()
1189 {
1190         bool yn = _route->solo_safe_control()->solo_safe ();
1191
1192         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1193                 solo_safe_check->set_active (yn);
1194         }
1195
1196         yn = _route->solo_isolate_control()->solo_isolated ();
1197
1198         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1199                 solo_isolated_check->set_active (yn);
1200         }
1201
1202         set_button_names ();
1203
1204         if (solo_isolated_led) {
1205                 if (_route->solo_isolate_control()->solo_isolated()) {
1206                         solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1207                 } else {
1208                         solo_isolated_led->unset_active_state ();
1209                 }
1210         }
1211
1212         if (solo_safe_led) {
1213                 if (_route->solo_safe_control()->solo_safe()) {
1214                         solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1215                 } else {
1216                         solo_safe_led->unset_active_state ();
1217                 }
1218         }
1219
1220         solo_button->set_active_state (solo_active_state (_route));
1221
1222         /* some changes to solo status can affect mute display, so catch up
1223          */
1224
1225         update_mute_display ();
1226 }
1227
1228 void
1229 RouteUI::solo_changed_so_update_mute ()
1230 {
1231         update_mute_display ();
1232 }
1233
1234 ActiveState
1235 RouteUI::mute_active_state (Session*, boost::shared_ptr<Stripable> s)
1236 {
1237         boost::shared_ptr<MuteControl> mc = s->mute_control();
1238
1239         if (s->is_monitor()) {
1240                 return Gtkmm2ext::Off;
1241         }
1242
1243         if (!mc) {
1244                 return Gtkmm2ext::Off;
1245         }
1246
1247         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1248
1249                 if (mc->muted_by_self ()) {
1250                         /* full mute */
1251                         return Gtkmm2ext::ExplicitActive;
1252                 } else if (mc->muted_by_others_soloing () || mc->muted_by_masters ()) {
1253                         /* this will reflect both solo mutes AND master mutes */
1254                         return Gtkmm2ext::ImplicitActive;
1255                 } else {
1256                         /* no mute at all */
1257                         return Gtkmm2ext::Off;
1258                 }
1259
1260         } else {
1261
1262                 if (mc->muted_by_self()) {
1263                         /* full mute */
1264                         return Gtkmm2ext::ExplicitActive;
1265                 } else if (mc->muted_by_masters ()) {
1266                         /* this shows only master mutes, not mute-by-others-soloing */
1267                         return Gtkmm2ext::ImplicitActive;
1268                 } else {
1269                         /* no mute at all */
1270                         return Gtkmm2ext::Off;
1271                 }
1272         }
1273
1274         return ActiveState(0);
1275 }
1276
1277 void
1278 RouteUI::update_mute_display ()
1279 {
1280         if (!_route) {
1281                 return;
1282         }
1283
1284         mute_button->set_active_state (mute_active_state (_session, _route));
1285 }
1286
1287 void
1288 RouteUI::update_vca_display ()
1289 {
1290         if (!vca_button) {
1291                 return;
1292         }
1293
1294         VCAList vcas (_session->vca_manager().vcas());
1295         string label;
1296
1297         for (VCAList::iterator v = vcas.begin(); v != vcas.end(); ++v) {
1298                 if (_route->slaved_to (*v)) {
1299                         if (!label.empty()) {
1300                                 label += ' ';
1301                         }
1302                         label += PBD::to_string ((*v)->number(), std::dec);
1303                 }
1304         }
1305
1306         if (label.empty()) {
1307                 label = _("-vca-");
1308                 vca_button->set_active_state (Gtkmm2ext::Off);
1309         } else {
1310                 vca_button->set_active_state (Gtkmm2ext::ExplicitActive);
1311         }
1312
1313         vca_button->set_text (label);
1314 }
1315
1316 void
1317 RouteUI::route_rec_enable_changed ()
1318 {
1319         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1320         update_monitoring_display ();
1321 }
1322
1323 void
1324 RouteUI::session_rec_enable_changed ()
1325 {
1326         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1327         update_monitoring_display ();
1328 }
1329
1330 void
1331 RouteUI::blink_rec_display (bool blinkOn)
1332 {
1333         if (!rec_enable_button || !_route) {
1334                 return;
1335         }
1336
1337         if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1338                 return;
1339         }
1340
1341         if (!is_track()) {
1342                 return;
1343         }
1344
1345         if (track()->rec_enable_control()->get_value()) {
1346                 switch (_session->record_status ()) {
1347                 case Session::Recording:
1348                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1349                         break;
1350
1351                 case Session::Disabled:
1352                 case Session::Enabled:
1353                         if (UIConfiguration::instance().get_blink_rec_arm()) {
1354                                 rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1355                         } else {
1356                                 rec_enable_button->set_active_state ( ImplicitActive );
1357                         }
1358                         break;
1359                 }
1360
1361                 if (step_edit_item) {
1362                         step_edit_item->set_sensitive (false);
1363                 }
1364
1365         } else {
1366                 rec_enable_button->unset_active_state ();
1367
1368                 if (step_edit_item) {
1369                         step_edit_item->set_sensitive (true);
1370                 }
1371         }
1372
1373         check_rec_enable_sensitivity ();
1374 }
1375
1376 void
1377 RouteUI::build_solo_menu (void)
1378 {
1379         using namespace Menu_Helpers;
1380
1381         solo_menu = new Menu;
1382         solo_menu->set_name ("ArdourContextMenu");
1383         MenuList& items = solo_menu->items();
1384         Gtk::CheckMenuItem* check;
1385
1386         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1387         check->set_active (_route->solo_isolate_control()->solo_isolated());
1388         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1389         items.push_back (CheckMenuElem(*check));
1390         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1391         check->show_all();
1392
1393         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1394         check->set_active (_route->solo_safe_control()->solo_safe());
1395         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1396         items.push_back (CheckMenuElem(*check));
1397         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1398         check->show_all();
1399
1400         //items.push_back (SeparatorElem());
1401         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1402
1403 }
1404
1405 void
1406 RouteUI::build_mute_menu(void)
1407 {
1408         using namespace Menu_Helpers;
1409
1410         mute_menu = new Menu;
1411         mute_menu->set_name ("ArdourContextMenu");
1412
1413         MenuList& items = mute_menu->items();
1414
1415         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1416         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1417         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1418         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1419         pre_fader_mute_check->show_all();
1420
1421         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1422         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1423         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1424         items.push_back (CheckMenuElem(*post_fader_mute_check));
1425         post_fader_mute_check->show_all();
1426
1427         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1428         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1429         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1430         items.push_back (CheckMenuElem(*listen_mute_check));
1431         listen_mute_check->show_all();
1432
1433         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1434         init_mute_menu(MuteMaster::Main, main_mute_check);
1435         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1436         items.push_back (CheckMenuElem(*main_mute_check));
1437         main_mute_check->show_all();
1438
1439         //items.push_back (SeparatorElem());
1440         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1441
1442         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1443 }
1444
1445 void
1446 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1447 {
1448         check->set_active (_route->mute_control()->mute_points() & mp);
1449 }
1450
1451 void
1452 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1453 {
1454         if (check->get_active()) {
1455                 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1456         } else {
1457                 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1458         }
1459 }
1460
1461 void
1462 RouteUI::muting_change ()
1463 {
1464         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1465
1466         bool yn;
1467         MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1468
1469         yn = (current & MuteMaster::PreFader);
1470
1471         if (pre_fader_mute_check->get_active() != yn) {
1472                 pre_fader_mute_check->set_active (yn);
1473         }
1474
1475         yn = (current & MuteMaster::PostFader);
1476
1477         if (post_fader_mute_check->get_active() != yn) {
1478                 post_fader_mute_check->set_active (yn);
1479         }
1480
1481         yn = (current & MuteMaster::Listen);
1482
1483         if (listen_mute_check->get_active() != yn) {
1484                 listen_mute_check->set_active (yn);
1485         }
1486
1487         yn = (current & MuteMaster::Main);
1488
1489         if (main_mute_check->get_active() != yn) {
1490                 main_mute_check->set_active (yn);
1491         }
1492 }
1493
1494 bool
1495 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1496 {
1497         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1498                 return true;
1499         }
1500
1501         bool view = solo_isolated_led->active_state();
1502         bool model = _route->solo_isolate_control()->solo_isolated();
1503
1504         /* called BEFORE the view has changed */
1505
1506         if (ev->button == 1) {
1507                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1508
1509                         if (model) {
1510                                 /* disable isolate for all routes */
1511                                 DisplaySuspender ds;
1512                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1513                         } else {
1514                                 /* enable isolate for all routes */
1515                                 DisplaySuspender ds;
1516                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1517                         }
1518
1519                 } else {
1520
1521                         if (model == view) {
1522
1523                                 /* flip just this route */
1524
1525                                 boost::shared_ptr<RouteList> rl (new RouteList);
1526                                 rl->push_back (_route);
1527                                 DisplaySuspender ds;
1528                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1529                         }
1530                 }
1531         }
1532
1533         return false;
1534 }
1535
1536 bool
1537 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1538 {
1539         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1540                 return true;
1541         }
1542
1543         bool view = solo_safe_led->active_state();
1544         bool model = _route->solo_safe_control()->solo_safe();
1545
1546         if (ev->button == 1) {
1547                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1548                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1549                         if (model) {
1550                                 /* disable solo safe for all routes */
1551                                 DisplaySuspender ds;
1552                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1553                                         (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1554                                 }
1555                         } else {
1556                                 /* enable solo safe for all routes */
1557                                 DisplaySuspender ds;
1558                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1559                                         (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1560                                 }
1561                         }
1562                 }
1563                 else {
1564                         if (model == view) {
1565                                 /* flip just this route */
1566                                 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1567                         }
1568                 }
1569         }
1570
1571         return false;
1572 }
1573
1574 void
1575 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1576 {
1577         bool view = check->get_active();
1578         bool model = _route->solo_isolate_control()->solo_isolated();
1579
1580         /* called AFTER the view has changed */
1581
1582         if (model != view) {
1583                 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1584         }
1585 }
1586
1587 void
1588 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1589 {
1590         _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1591 }
1592
1593 /** Ask the user to choose a colour, and then apply that color to my route
1594  */
1595 void
1596 RouteUI::choose_color ()
1597 {
1598         bool picked;
1599         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1600
1601         if (picked) {
1602                 set_color(color);
1603         }
1604 }
1605
1606 /** Set the route's own color.  This may not be used for display if
1607  *  the route is in a group which shares its color with its routes.
1608  */
1609 void
1610 RouteUI::set_color (const Gdk::Color & c)
1611 {
1612         /* leave _color alone in the group case so that tracks can retain their
1613          * own pre-group colors.
1614          */
1615
1616         char buf[64];
1617         _color = c;
1618         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1619
1620         /* note: we use the route state ID here so that color is the same for both
1621            the time axis view and the mixer strip
1622         */
1623
1624         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1625         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1626 }
1627
1628 /** @return GUI state ID for things that are common to the route in all its representations */
1629 string
1630 RouteUI::route_state_id () const
1631 {
1632         return string_compose (X_("route %1"), _route->id().to_s());
1633 }
1634
1635 int
1636 RouteUI::set_color_from_route ()
1637 {
1638         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1639
1640         if (str.empty()) {
1641                 return 1;
1642         }
1643
1644         int r, g, b;
1645
1646         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1647
1648         _color.set_red (r);
1649         _color.set_green (g);
1650         _color.set_blue (b);
1651
1652         return 0;
1653 }
1654
1655 /** @return true if this name should be used for the route, otherwise false */
1656 bool
1657 RouteUI::verify_new_route_name (const std::string& name)
1658 {
1659         if (name.find (':') == string::npos) {
1660                 return true;
1661         }
1662
1663         MessageDialog colon_msg (
1664                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1665                 false, MESSAGE_QUESTION, BUTTONS_NONE
1666                 );
1667
1668         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1669         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1670
1671         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1672 }
1673
1674 void
1675 RouteUI::route_rename ()
1676 {
1677         ArdourPrompter name_prompter (true);
1678         string result;
1679         bool done = false;
1680
1681         if (is_track()) {
1682                 name_prompter.set_title (_("Rename Track"));
1683         } else {
1684                 name_prompter.set_title (_("Rename Bus"));
1685         }
1686         name_prompter.set_prompt (_("New name:"));
1687         name_prompter.set_initial_text (_route->name());
1688         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1689         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1690         name_prompter.show_all ();
1691
1692         while (!done) {
1693                 switch (name_prompter.run ()) {
1694                 case Gtk::RESPONSE_ACCEPT:
1695                         name_prompter.get_result (result);
1696                         name_prompter.hide ();
1697                         if (result.length()) {
1698                                 if (verify_new_route_name (result)) {
1699                                         _route->set_name (result);
1700                                         done = true;
1701                                 } else {
1702                                         /* back to name prompter */
1703                                 }
1704
1705                         } else {
1706                                 /* nothing entered, just get out of here */
1707                                 done = true;
1708                         }
1709                         break;
1710                 default:
1711                         done = true;
1712                         break;
1713                 }
1714         }
1715
1716         return;
1717
1718 }
1719
1720 void
1721 RouteUI::property_changed (const PropertyChange& what_changed)
1722 {
1723         if (what_changed.contains (ARDOUR::Properties::name)) {
1724                 name_label.set_text (_route->name());
1725         }
1726 }
1727
1728 void
1729 RouteUI::toggle_comment_editor ()
1730 {
1731 //      if (ignore_toggle) {
1732 //              return;
1733 //      }
1734
1735         if (comment_window && comment_window->is_visible ()) {
1736                 comment_window->hide ();
1737         } else {
1738                 open_comment_editor ();
1739         }
1740 }
1741
1742
1743 void
1744 RouteUI::open_comment_editor ()
1745 {
1746         if (comment_window == 0) {
1747                 setup_comment_editor ();
1748         }
1749
1750         string title;
1751         title = _route->name();
1752         title += _(": comment editor");
1753
1754         comment_window->set_title (title);
1755         comment_window->present();
1756 }
1757
1758 void
1759 RouteUI::setup_comment_editor ()
1760 {
1761         comment_window = new ArdourWindow (""); // title will be reset to show route
1762         comment_window->set_skip_taskbar_hint (true);
1763         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1764         comment_window->set_default_size (400, 200);
1765
1766         comment_area = manage (new TextView());
1767         comment_area->set_name ("MixerTrackCommentArea");
1768         comment_area->set_wrap_mode (WRAP_WORD);
1769         comment_area->set_editable (true);
1770         comment_area->get_buffer()->set_text (_route->comment());
1771         comment_area->show ();
1772
1773         comment_window->add (*comment_area);
1774 }
1775
1776 void
1777 RouteUI::comment_changed ()
1778 {
1779         ignore_comment_edit = true;
1780         if (comment_area) {
1781                 comment_area->get_buffer()->set_text (_route->comment());
1782         }
1783         ignore_comment_edit = false;
1784 }
1785
1786 void
1787 RouteUI::comment_editor_done_editing ()
1788 {
1789         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1790
1791         string const str = comment_area->get_buffer()->get_text();
1792         if (str == _route->comment ()) {
1793                 return;
1794         }
1795
1796         _route->set_comment (str, this);
1797 }
1798
1799 void
1800 RouteUI::set_route_active (bool a, bool apply_to_selection)
1801 {
1802         if (apply_to_selection) {
1803                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1804         } else {
1805                 _route->set_active (a, this);
1806         }
1807 }
1808
1809 void
1810 RouteUI::duplicate_selected_routes ()
1811 {
1812         ARDOUR_UI::instance()->start_duplicate_routes();
1813 }
1814
1815 void
1816 RouteUI::toggle_denormal_protection ()
1817 {
1818         if (denormal_menu_item) {
1819
1820                 bool x;
1821
1822                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1823
1824                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1825                         _route->set_denormal_protection (x);
1826                 }
1827         }
1828 }
1829
1830 void
1831 RouteUI::denormal_protection_changed ()
1832 {
1833         if (denormal_menu_item) {
1834                 denormal_menu_item->set_active (_route->denormal_protection());
1835         }
1836 }
1837
1838 void
1839 RouteUI::disconnect_input ()
1840 {
1841         _route->input()->disconnect (this);
1842 }
1843
1844 void
1845 RouteUI::disconnect_output ()
1846 {
1847         _route->output()->disconnect (this);
1848 }
1849
1850 bool
1851 RouteUI::is_track () const
1852 {
1853         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1854 }
1855
1856 boost::shared_ptr<Track>
1857 RouteUI::track() const
1858 {
1859         return boost::dynamic_pointer_cast<Track>(_route);
1860 }
1861
1862 bool
1863 RouteUI::is_audio_track () const
1864 {
1865         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1866 }
1867
1868 boost::shared_ptr<AudioTrack>
1869 RouteUI::audio_track() const
1870 {
1871         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1872 }
1873
1874 bool
1875 RouteUI::is_midi_track () const
1876 {
1877         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1878 }
1879
1880 boost::shared_ptr<MidiTrack>
1881 RouteUI::midi_track() const
1882 {
1883         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1884 }
1885
1886 bool
1887 RouteUI::has_audio_outputs () const
1888 {
1889         return (_route->n_outputs().n_audio() > 0);
1890 }
1891
1892 string
1893 RouteUI::name() const
1894 {
1895         return _route->name();
1896 }
1897
1898 void
1899 RouteUI::map_frozen ()
1900 {
1901         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1902
1903         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1904
1905         if (at) {
1906                 check_rec_enable_sensitivity ();
1907         }
1908 }
1909
1910 void
1911 RouteUI::adjust_latency ()
1912 {
1913         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1914 }
1915
1916 bool
1917 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1918 {
1919         std::string path;
1920         std::string safe_name;
1921         std::string name;
1922
1923         prompter.get_result (name, true);
1924
1925         safe_name = legalize_for_path (name);
1926         safe_name += template_suffix;
1927
1928         path = Glib::build_filename (dir, safe_name);
1929
1930         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1931                 bool overwrite = overwrite_file_dialog (prompter,
1932                                                         _("Confirm Template Overwrite"),
1933                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1934
1935                 if (!overwrite) {
1936                         return false;
1937                 }
1938         }
1939
1940         _route->save_as_template (path, name);
1941
1942         return true;
1943 }
1944
1945 void
1946 RouteUI::save_as_template ()
1947 {
1948         std::string dir;
1949
1950         dir = ARDOUR::user_route_template_directory ();
1951
1952         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1953                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1954                 return;
1955         }
1956
1957         ArdourPrompter prompter (true); // modal
1958
1959         prompter.set_title (_("Save As Template"));
1960         prompter.set_prompt (_("Template name:"));
1961         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1962
1963         bool finished = false;
1964         while (!finished) {
1965                 switch (prompter.run()) {
1966                 case RESPONSE_ACCEPT:
1967                         finished = process_save_template_prompter (prompter, dir);
1968                         break;
1969                 default:
1970                         finished = true;
1971                         break;
1972                 }
1973         }
1974 }
1975
1976 void
1977 RouteUI::check_rec_enable_sensitivity ()
1978 {
1979         if (!rec_enable_button) {
1980                 assert (0); // This should not happen
1981                 return;
1982         }
1983         if (!_session->writable()) {
1984                 rec_enable_button->set_sensitive (false);
1985                 return;
1986         }
1987
1988         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1989                 rec_enable_button->set_sensitive (false);
1990         } else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1991                 rec_enable_button->set_sensitive (false);
1992         } else {
1993                 rec_enable_button->set_sensitive (true);
1994         }
1995         if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1996                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1997         } else {
1998                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1999         }
2000         update_monitoring_display ();
2001 }
2002
2003 void
2004 RouteUI::parameter_changed (string const & p)
2005 {
2006         /* this handles RC and per-session parameter changes */
2007
2008         if (p == "disable-disarm-during-roll") {
2009                 check_rec_enable_sensitivity ();
2010         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2011                 set_button_names ();
2012         } else if (p == "auto-input") {
2013                 update_monitoring_display ();
2014         } else if (p == "blink-rec-arm") {
2015                 if (UIConfiguration::instance().get_blink_rec_arm()) {
2016                         rec_blink_connection.disconnect ();
2017                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2018                 } else {
2019                         rec_blink_connection.disconnect ();
2020                         RouteUI::blink_rec_display(false);
2021                 }
2022         }
2023 }
2024
2025 void
2026 RouteUI::step_gain_up ()
2027 {
2028         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
2029 }
2030
2031 void
2032 RouteUI::page_gain_up ()
2033 {
2034         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
2035 }
2036
2037 void
2038 RouteUI::step_gain_down ()
2039 {
2040         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
2041 }
2042
2043 void
2044 RouteUI::page_gain_down ()
2045 {
2046         _route->gain_control()->set_value (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
2047 }
2048
2049 void
2050 RouteUI::setup_invert_buttons ()
2051 {
2052         /* remove old invert buttons */
2053         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2054                 _invert_button_box.remove (**i);
2055         }
2056
2057         _invert_buttons.clear ();
2058
2059         if (!_route || !_route->input()) {
2060                 return;
2061         }
2062
2063         uint32_t const N = _route->input()->n_ports().n_audio ();
2064
2065         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2066
2067         for (uint32_t i = 0; i < to_add; ++i) {
2068                 ArdourButton* b = manage (new ArdourButton);
2069                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2070                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2071
2072                 b->set_name (X_("invert button"));
2073                 if (to_add == 1) {
2074                         if (N > 1) {
2075                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2076                         } else {
2077                                 b->set_text (X_("Ø"));
2078                         }
2079                 } else {
2080                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2081                 }
2082
2083                 if (N <= _max_invert_buttons) {
2084                         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));
2085                 } else {
2086                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2087                 }
2088
2089                 _invert_buttons.push_back (b);
2090                 _invert_button_box.pack_start (*b);
2091         }
2092
2093         _invert_button_box.set_spacing (1);
2094         _invert_button_box.show_all ();
2095 }
2096
2097 void
2098 RouteUI::set_invert_button_state ()
2099 {
2100         uint32_t const N = _route->input()->n_ports().n_audio();
2101         if (N > _max_invert_buttons) {
2102
2103                 /* One button for many channels; explicit active if all channels are inverted,
2104                    implicit active if some are, off if none are.
2105                 */
2106
2107                 ArdourButton* b = _invert_buttons.front ();
2108
2109                 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2110                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2111                 } else if (_route->phase_control()->any()) {
2112                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2113                 } else {
2114                         b->set_active_state (Gtkmm2ext::Off);
2115                 }
2116
2117         } else {
2118
2119                 /* One button per channel; just set active */
2120
2121                 int j = 0;
2122                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2123                         (*i)->set_active (_route->phase_control()->inverted (j));
2124                 }
2125
2126         }
2127 }
2128
2129 bool
2130 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2131 {
2132         if (ev->button == 1 && i < _invert_buttons.size()) {
2133                 uint32_t const N = _route->input()->n_ports().n_audio ();
2134                 if (N <= _max_invert_buttons) {
2135                         /* left-click inverts phase so long as we have a button per channel */
2136                         _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2137                         return false;
2138                 }
2139         }
2140         return false;
2141 }
2142
2143
2144 bool
2145 RouteUI::invert_press (GdkEventButton* ev)
2146 {
2147         using namespace Menu_Helpers;
2148
2149         uint32_t const N = _route->input()->n_ports().n_audio();
2150         if (N <= _max_invert_buttons && ev->button != 3) {
2151                 /* If we have an invert button per channel, we only pop
2152                    up a menu on right-click; left click is handled
2153                    on release.
2154                 */
2155                 return false;
2156         }
2157
2158         delete _invert_menu;
2159         _invert_menu = new Menu;
2160         _invert_menu->set_name ("ArdourContextMenu");
2161         MenuList& items = _invert_menu->items ();
2162
2163         for (uint32_t i = 0; i < N; ++i) {
2164                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2165                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2166                 ++_i_am_the_modifier;
2167                 e->set_active (_route->phase_control()->inverted (i));
2168                 --_i_am_the_modifier;
2169         }
2170
2171         _invert_menu->popup (0, ev->time);
2172
2173         return true;
2174 }
2175
2176 void
2177 RouteUI::invert_menu_toggled (uint32_t c)
2178 {
2179         if (_i_am_the_modifier) {
2180                 return;
2181         }
2182
2183
2184         _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2185 }
2186
2187 void
2188 RouteUI::set_invert_sensitive (bool yn)
2189 {
2190         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2191                 (*b)->set_sensitive (yn);
2192         }
2193 }
2194
2195 void
2196 RouteUI::request_redraw ()
2197 {
2198         if (_route) {
2199                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2200         }
2201 }
2202
2203 /** The Route's gui_changed signal has been emitted */
2204 void
2205 RouteUI::route_gui_changed (string what_changed)
2206 {
2207         if (what_changed == "color") {
2208                 if (set_color_from_route () == 0) {
2209                         route_color_changed ();
2210                 }
2211         }
2212 }
2213
2214 void
2215 RouteUI::track_mode_changed (void)
2216 {
2217         assert(is_track());
2218         switch (track()->mode()) {
2219                 case ARDOUR::NonLayered:
2220                 case ARDOUR::Normal:
2221                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2222                         break;
2223                 case ARDOUR::Destructive:
2224                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2225                         break;
2226         }
2227         rec_enable_button->queue_draw();
2228 }
2229
2230 /** @return the color that this route should use; it maybe its own,
2231     or it maybe that of its route group.
2232 */
2233 Gdk::Color
2234 RouteUI::color () const
2235 {
2236         RouteGroup* g = _route->route_group ();
2237
2238         if (g && g->is_color()) {
2239                 Gdk::Color c;
2240                 set_color_from_rgba (c, GroupTabs::group_color (g));
2241                 return c;
2242         }
2243
2244         return _color;
2245 }
2246
2247 void
2248 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2249 {
2250         _showing_sends_to = send_to;
2251         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2252 }
2253
2254 void
2255 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2256 {
2257         if (_route == send_to) {
2258                 show_sends_button->set_active (true);
2259                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2260         } else {
2261                 show_sends_button->set_active (false);
2262                 send_blink_connection.disconnect ();
2263         }
2264 }
2265
2266 RouteGroup*
2267 RouteUI::route_group() const
2268 {
2269         return _route->route_group();
2270 }
2271
2272
2273 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2274         : WM::ProxyBase (name, string())
2275         , _route (boost::weak_ptr<Route> (route))
2276 {
2277         route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2278 }
2279
2280 RoutePinWindowProxy::~RoutePinWindowProxy()
2281 {
2282         _window = 0;
2283 }
2284
2285 ARDOUR::SessionHandlePtr*
2286 RoutePinWindowProxy::session_handle ()
2287 {
2288         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2289         if (aw) { return aw; }
2290         return 0;
2291 }
2292
2293 Gtk::Window*
2294 RoutePinWindowProxy::get (bool create)
2295 {
2296         boost::shared_ptr<Route> r = _route.lock ();
2297         if (!r) {
2298                 return 0;
2299         }
2300
2301         if (!_window) {
2302                 if (!create) {
2303                         return 0;
2304                 }
2305                 _window = new PluginPinDialog (r);
2306                 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2307                 if (aw) {
2308                         aw->set_session (_session);
2309                 }
2310                 _window->show_all ();
2311         }
2312         return _window;
2313 }
2314
2315 void
2316 RoutePinWindowProxy::route_going_away ()
2317 {
2318         delete _window;
2319         _window = 0;
2320         WM::Manager::instance().remove (this);
2321         going_away_connection.disconnect();
2322 }
2323
2324 void
2325 RouteUI::maybe_add_route_print_mgr ()
2326 {
2327         if (_route->pinmgr_proxy ()) {
2328                 return;
2329         }
2330         RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2331                         string_compose ("RPM-%1", _route->id()), _route);
2332         wp->set_session (_session);
2333
2334         const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2335         if (ui_xml) {
2336                 wp->set_state (*ui_xml, 0);
2337         }
2338
2339 #if 0
2340         void* existing_ui = _route->pinmgr_proxy ();
2341         if (existing_ui) {
2342                 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2343         }
2344 #endif
2345         _route->set_pingmgr_proxy (wp);
2346
2347         WM::Manager::instance().register_window (wp);
2348 }
2349
2350 void
2351 RouteUI::manage_pins ()
2352 {
2353         RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2354         if (proxy) {
2355                 proxy->get (true);
2356                 proxy->present();
2357         }
2358 }