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