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