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