when using InverseGroup for solo, do not collect group members and pass them to a...
[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::NoGroup);
563                                 } else {
564                                         _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, Controllable::NoGroup);
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                                 if (_route->route_group()) {
743
744                                         rl = _route->route_group()->route_list();
745
746                                 } else {
747                                         rl.reset (new RouteList);
748                                         rl->push_back (_route);
749                                 }
750
751                                 DisplaySuspender ds;
752                                 _session->set_record_enabled (rl, !_route->record_enabled(), Session::rt_cleanup, Controllable::InverseGroup);
753                         }
754
755                 } else if (Keyboard::is_context_menu_event (ev)) {
756
757                         /* do this on release */
758
759                 } else {
760
761                         boost::shared_ptr<RouteList> rl (new RouteList);
762                         rl->push_back (route());
763                         DisplaySuspender ds;
764                         _session->set_record_enabled (rl, !_route->record_enabled());
765                 }
766         }
767
768         return false;
769 }
770
771 void
772 RouteUI::monitoring_changed ()
773 {
774         update_monitoring_display ();
775 }
776
777 void
778 RouteUI::update_monitoring_display ()
779 {
780         if (!_route) {
781                 return;
782         }
783
784         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
785
786         if (!t) {
787                 return;
788         }
789
790         MonitorState ms = t->monitoring_state();
791
792         if (t->monitoring_choice() & MonitorInput) {
793                 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
794         } else {
795                 if (ms & MonitoringInput) {
796                         monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
797                 } else {
798                         monitor_input_button->unset_active_state ();
799                 }
800         }
801
802         if (t->monitoring_choice() & MonitorDisk) {
803                 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
804         } else {
805                 if (ms & MonitoringDisk) {
806                         monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
807                 } else {
808                         monitor_disk_button->unset_active_state ();
809                 }
810         }
811 }
812
813 bool
814 RouteUI::monitor_input_press(GdkEventButton*)
815 {
816         return false;
817 }
818
819 bool
820 RouteUI::monitor_input_release(GdkEventButton* ev)
821 {
822         return monitor_release (ev, MonitorInput);
823 }
824
825 bool
826 RouteUI::monitor_disk_press (GdkEventButton*)
827 {
828         return false;
829 }
830
831 bool
832 RouteUI::monitor_disk_release (GdkEventButton* ev)
833 {
834         return monitor_release (ev, MonitorDisk);
835 }
836
837 bool
838 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
839 {
840         if (ev->button != 1) {
841                 return false;
842         }
843
844         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
845
846         if (!t) {
847                 return true;
848         }
849
850         MonitorChoice mc;
851         boost::shared_ptr<RouteList> rl;
852
853         /* XXX for now, monitoring choices are orthogonal. cue monitoring
854            will follow in 3.X but requires mixing the input and playback (disk)
855            signal together, which requires yet more buffers.
856         */
857
858         if (t->monitoring_choice() & monitor_choice) {
859                 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
860         } else {
861                 /* this line will change when the options are non-orthogonal */
862                 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
863                 mc = monitor_choice;
864         }
865
866         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
867                 rl = _session->get_routes ();
868
869         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
870                 if (_route->route_group() && _route->route_group()->is_monitoring()) {
871                         rl = _route->route_group()->route_list();
872                 } else {
873                         rl.reset (new RouteList);
874                         rl->push_back (route());
875                 }
876         } else {
877                 rl.reset (new RouteList);
878                 rl->push_back (route());
879         }
880
881         DisplaySuspender ds;
882         _session->set_monitoring (rl, mc, Session::rt_cleanup, Controllable::UseGroup);
883
884         return false;
885 }
886
887 void
888 RouteUI::build_record_menu ()
889 {
890         if (record_menu) {
891                 return;
892         }
893
894         /* no rec-button context menu for non-MIDI tracks
895          */
896
897         if (is_midi_track()) {
898                 record_menu = new Menu;
899                 record_menu->set_name ("ArdourContextMenu");
900
901                 using namespace Menu_Helpers;
902                 MenuList& items = record_menu->items();
903
904                 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
905                 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
906
907                 if (_route->record_enabled()) {
908                         step_edit_item->set_sensitive (false);
909                 }
910
911                 step_edit_item->set_active (midi_track()->step_editing());
912         }
913 }
914
915 void
916 RouteUI::toggle_step_edit ()
917 {
918         if (!is_midi_track() || _route->record_enabled()) {
919                 return;
920         }
921
922         midi_track()->set_step_editing (step_edit_item->get_active());
923 }
924
925 void
926 RouteUI::step_edit_changed (bool yn)
927 {
928         if (yn) {
929                 if (rec_enable_button) {
930                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
931                 }
932
933                 start_step_editing ();
934
935                 if (step_edit_item) {
936                         step_edit_item->set_active (true);
937                 }
938
939         } else {
940
941                 if (rec_enable_button) {
942                         rec_enable_button->unset_active_state ();
943                 }
944
945                 stop_step_editing ();
946
947                 if (step_edit_item) {
948                         step_edit_item->set_active (false);
949                 }
950         }
951 }
952
953 bool
954 RouteUI::rec_enable_release (GdkEventButton* ev)
955 {
956         if (Keyboard::is_context_menu_event (ev)) {
957                 build_record_menu ();
958                 if (record_menu) {
959                         record_menu->popup (1, ev->time);
960                 }
961                 return false;
962         }
963
964         return false;
965 }
966
967 void
968 RouteUI::build_sends_menu ()
969 {
970         using namespace Menu_Helpers;
971
972         sends_menu = new Menu;
973         sends_menu->set_name ("ArdourContextMenu");
974         MenuList& items = sends_menu->items();
975
976         items.push_back (
977                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
978                 );
979
980         items.push_back (
981                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
982                 );
983
984         items.push_back (
985                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
986                 );
987
988         items.push_back (
989                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
990                 );
991
992         items.push_back (
993                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
994                 );
995
996         items.push_back (
997                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
998
999         items.push_back (
1000                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
1001                 );
1002
1003         items.push_back (
1004                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
1005                 );
1006
1007         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
1008         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
1009         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
1010
1011 }
1012
1013 void
1014 RouteUI::create_sends (Placement p, bool include_buses)
1015 {
1016         _session->globally_add_internal_sends (_route, p, include_buses);
1017 }
1018
1019 void
1020 RouteUI::create_selected_sends (Placement p, bool include_buses)
1021 {
1022         boost::shared_ptr<RouteList> rlist (new RouteList);
1023         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
1024
1025         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
1026                 RouteTimeAxisView* rtv;
1027                 RouteUI* rui;
1028                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
1029                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
1030                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
1031                                         rlist->push_back (rui->route());
1032                                 }
1033                         }
1034                 }
1035         }
1036
1037         _session->add_internal_sends (_route, p, rlist);
1038 }
1039
1040 void
1041 RouteUI::set_sends_gain_from_track ()
1042 {
1043         _session->globally_set_send_gains_from_track (_route);
1044 }
1045
1046 void
1047 RouteUI::set_sends_gain_to_zero ()
1048 {
1049         _session->globally_set_send_gains_to_zero (_route);
1050 }
1051
1052 void
1053 RouteUI::set_sends_gain_to_unity ()
1054 {
1055         _session->globally_set_send_gains_to_unity (_route);
1056 }
1057
1058 bool
1059 RouteUI::show_sends_press(GdkEventButton* ev)
1060 {
1061         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
1062                 return true;
1063         }
1064
1065         if (!is_track() && show_sends_button) {
1066
1067                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
1068
1069                         // do nothing on midi sigc::bind event
1070                         return false;
1071
1072                 } else if (Keyboard::is_context_menu_event (ev)) {
1073
1074                         if (sends_menu == 0) {
1075                                 build_sends_menu ();
1076                         }
1077
1078                         sends_menu->popup (0, ev->time);
1079
1080                 } else {
1081
1082                         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
1083
1084                         if (s == _route) {
1085                                 set_showing_sends_to (boost::shared_ptr<Route> ());
1086                         } else {
1087                                 set_showing_sends_to (_route);
1088                         }
1089                 }
1090         }
1091
1092         return true;
1093 }
1094
1095 bool
1096 RouteUI::show_sends_release (GdkEventButton*)
1097 {
1098         return true;
1099 }
1100
1101 void
1102 RouteUI::send_blink (bool onoff)
1103 {
1104         if (!show_sends_button) {
1105                 return;
1106         }
1107
1108         if (onoff) {
1109                 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
1110         } else {
1111                 show_sends_button->unset_active_state ();
1112         }
1113 }
1114
1115 Gtkmm2ext::ActiveState
1116 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1117 {
1118         if (r->is_master() || r->is_monitor()) {
1119                 return Gtkmm2ext::Off;
1120         }
1121
1122         if (Config->get_solo_control_is_listen_control()) {
1123
1124                 if (r->listening_via_monitor()) {
1125                         return Gtkmm2ext::ExplicitActive;
1126                 } else {
1127                         return Gtkmm2ext::Off;
1128                 }
1129
1130         }
1131
1132         if (r->soloed()) {
1133                 if (!r->self_soloed()) {
1134                         return Gtkmm2ext::ImplicitActive;
1135                 } else {
1136                         return Gtkmm2ext::ExplicitActive;
1137                 }
1138         } else {
1139                 return Gtkmm2ext::Off;
1140         }
1141 }
1142
1143 Gtkmm2ext::ActiveState
1144 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1145 {
1146         if (r->is_master() || r->is_monitor()) {
1147                 return Gtkmm2ext::Off;
1148         }
1149
1150         if (r->solo_isolated()) {
1151                 return Gtkmm2ext::ExplicitActive;
1152         } else {
1153                 return Gtkmm2ext::Off;
1154         }
1155 }
1156
1157 Gtkmm2ext::ActiveState
1158 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1159 {
1160         if (r->is_master() || r->is_monitor()) {
1161                 return Gtkmm2ext::Off;
1162         }
1163
1164         if (r->solo_safe()) {
1165                 return Gtkmm2ext::ExplicitActive;
1166         } else {
1167                 return Gtkmm2ext::Off;
1168         }
1169 }
1170
1171 void
1172 RouteUI::update_solo_display ()
1173 {
1174         bool yn = _route->solo_safe ();
1175
1176         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1177                 solo_safe_check->set_active (yn);
1178         }
1179
1180         yn = _route->solo_isolated ();
1181
1182         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1183                 solo_isolated_check->set_active (yn);
1184         }
1185
1186         set_button_names ();
1187
1188         if (solo_isolated_led) {
1189                 if (_route->solo_isolated()) {
1190                         solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1191                 } else {
1192                         solo_isolated_led->unset_active_state ();
1193                 }
1194         }
1195
1196         if (solo_safe_led) {
1197                 if (_route->solo_safe()) {
1198                         solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1199                 } else {
1200                         solo_safe_led->unset_active_state ();
1201                 }
1202         }
1203
1204         solo_button->set_active_state (solo_active_state (_route));
1205
1206         /* some changes to solo status can affect mute display, so catch up
1207          */
1208
1209         update_mute_display ();
1210 }
1211
1212 void
1213 RouteUI::solo_changed_so_update_mute ()
1214 {
1215         update_mute_display ();
1216 }
1217
1218 ActiveState
1219 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1220 {
1221         if (r->is_monitor()) {
1222                 return ActiveState(0);
1223         }
1224
1225
1226         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1227
1228                 if (r->muted ()) {
1229                         /* full mute */
1230                         return Gtkmm2ext::ExplicitActive;
1231                 } else if (r->muted_by_others()) {
1232                         return Gtkmm2ext::ImplicitActive;
1233                 } else {
1234                         /* no mute at all */
1235                         return Gtkmm2ext::Off;
1236                 }
1237
1238         } else {
1239
1240                 if (r->muted()) {
1241                         /* full mute */
1242                         return Gtkmm2ext::ExplicitActive;
1243                 } else {
1244                         /* no mute at all */
1245                         return Gtkmm2ext::Off;
1246                 }
1247         }
1248
1249         return ActiveState(0);
1250 }
1251
1252 void
1253 RouteUI::update_mute_display ()
1254 {
1255         if (!_route) {
1256                 return;
1257         }
1258
1259         mute_button->set_active_state (mute_active_state (_session, _route));
1260 }
1261
1262 void
1263 RouteUI::route_rec_enable_changed ()
1264 {
1265         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1266         update_monitoring_display ();
1267 }
1268
1269 void
1270 RouteUI::session_rec_enable_changed ()
1271 {
1272         blink_rec_display(true);  //this lets the button change "immediately" rather than wait for the next blink
1273         update_monitoring_display ();
1274 }
1275
1276 void
1277 RouteUI::blink_rec_display (bool blinkOn)
1278 {
1279         if (!rec_enable_button || !_route) {
1280                 return;
1281         }
1282         if (boost::dynamic_pointer_cast<Send>(_current_delivery)) {
1283                 return;
1284         }
1285
1286         if (_route->record_enabled()) {
1287                 switch (_session->record_status ()) {
1288                 case Session::Recording:
1289                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1290                         break;
1291
1292                 case Session::Disabled:
1293                 case Session::Enabled:
1294                         if ( UIConfiguration::instance().get_blink_rec_arm() )
1295                                                         rec_enable_button->set_active_state ( blinkOn ? Gtkmm2ext::ExplicitActive : Gtkmm2ext::Off );
1296                                                 else
1297                                                         rec_enable_button->set_active_state ( ImplicitActive );
1298                         break;
1299
1300                 }
1301
1302                 if (step_edit_item) {
1303                         step_edit_item->set_sensitive (false);
1304                 }
1305
1306         } else {
1307                 rec_enable_button->unset_active_state ();
1308
1309                 if (step_edit_item) {
1310                         step_edit_item->set_sensitive (true);
1311                 }
1312         }
1313
1314
1315         check_rec_enable_sensitivity ();
1316 }
1317
1318 void
1319 RouteUI::build_solo_menu (void)
1320 {
1321         using namespace Menu_Helpers;
1322
1323         solo_menu = new Menu;
1324         solo_menu->set_name ("ArdourContextMenu");
1325         MenuList& items = solo_menu->items();
1326         Gtk::CheckMenuItem* check;
1327
1328         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1329         check->set_active (_route->solo_isolated());
1330         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1331         items.push_back (CheckMenuElem(*check));
1332         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1333         check->show_all();
1334
1335         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1336         check->set_active (_route->solo_safe());
1337         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1338         items.push_back (CheckMenuElem(*check));
1339         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1340         check->show_all();
1341
1342         //items.push_back (SeparatorElem());
1343         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1344
1345 }
1346
1347 void
1348 RouteUI::build_mute_menu(void)
1349 {
1350         using namespace Menu_Helpers;
1351
1352         mute_menu = new Menu;
1353         mute_menu->set_name ("ArdourContextMenu");
1354
1355         MenuList& items = mute_menu->items();
1356
1357         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1358         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1359         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1360         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1361         pre_fader_mute_check->show_all();
1362
1363         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1364         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1365         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1366         items.push_back (CheckMenuElem(*post_fader_mute_check));
1367         post_fader_mute_check->show_all();
1368
1369         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1370         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1371         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1372         items.push_back (CheckMenuElem(*listen_mute_check));
1373         listen_mute_check->show_all();
1374
1375         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1376         init_mute_menu(MuteMaster::Main, main_mute_check);
1377         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1378         items.push_back (CheckMenuElem(*main_mute_check));
1379         main_mute_check->show_all();
1380
1381         //items.push_back (SeparatorElem());
1382         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1383
1384         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1385 }
1386
1387 void
1388 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1389 {
1390         check->set_active (_route->mute_points() & mp);
1391 }
1392
1393 void
1394 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1395 {
1396         if (check->get_active()) {
1397                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1398         } else {
1399                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1400         }
1401 }
1402
1403 void
1404 RouteUI::muting_change ()
1405 {
1406         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1407
1408         bool yn;
1409         MuteMaster::MutePoint current = _route->mute_points ();
1410
1411         yn = (current & MuteMaster::PreFader);
1412
1413         if (pre_fader_mute_check->get_active() != yn) {
1414                 pre_fader_mute_check->set_active (yn);
1415         }
1416
1417         yn = (current & MuteMaster::PostFader);
1418
1419         if (post_fader_mute_check->get_active() != yn) {
1420                 post_fader_mute_check->set_active (yn);
1421         }
1422
1423         yn = (current & MuteMaster::Listen);
1424
1425         if (listen_mute_check->get_active() != yn) {
1426                 listen_mute_check->set_active (yn);
1427         }
1428
1429         yn = (current & MuteMaster::Main);
1430
1431         if (main_mute_check->get_active() != yn) {
1432                 main_mute_check->set_active (yn);
1433         }
1434 }
1435
1436 bool
1437 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1438 {
1439         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1440                 return true;
1441         }
1442
1443         bool view = solo_isolated_led->active_state();
1444         bool model = _route->solo_isolated();
1445
1446         /* called BEFORE the view has changed */
1447
1448         if (ev->button == 1) {
1449                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1450
1451                         if (model) {
1452                                 /* disable isolate for all routes */
1453                                 DisplaySuspender ds;
1454                                 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, Controllable::NoGroup);
1455                         } else {
1456                                 /* enable isolate for all routes */
1457                                 DisplaySuspender ds;
1458                                 _session->set_solo_isolated (_session->get_routes(), true, Session::rt_cleanup, Controllable::NoGroup);
1459                         }
1460
1461                 } else {
1462
1463                         if (model == view) {
1464
1465                                 /* flip just this route */
1466
1467                                 boost::shared_ptr<RouteList> rl (new RouteList);
1468                                 rl->push_back (_route);
1469                                 DisplaySuspender ds;
1470                                 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, Controllable::NoGroup);
1471                         }
1472                 }
1473         }
1474
1475         return false;
1476 }
1477
1478 bool
1479 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1480 {
1481         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1482                 return true;
1483         }
1484
1485         bool view = solo_safe_led->active_state();
1486         bool model = _route->solo_safe();
1487
1488         if (ev->button == 1) {
1489                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1490                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1491                         if (model) {
1492                                 /* disable solo safe for all routes */
1493                                 DisplaySuspender ds;
1494                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1495                                         (*i)->set_solo_safe (false, Controllable::NoGroup);
1496                                 }
1497                         } else {
1498                                 /* enable solo safe for all routes */
1499                                 DisplaySuspender ds;
1500                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1501                                         (*i)->set_solo_safe (true, Controllable::NoGroup);
1502                                 }
1503                         }
1504                 }
1505                 else {
1506                         if (model == view) {
1507                                 /* flip just this route */
1508                                 _route->set_solo_safe (!view, Controllable::NoGroup);
1509                         }
1510                 }
1511         }
1512
1513         return false;
1514 }
1515
1516 void
1517 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1518 {
1519         bool view = check->get_active();
1520         bool model = _route->solo_isolated();
1521
1522         /* called AFTER the view has changed */
1523
1524         if (model != view) {
1525                 _route->set_solo_isolated (view, Controllable::UseGroup);
1526         }
1527 }
1528
1529 void
1530 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1531 {
1532         _route->set_solo_safe (check->get_active(), Controllable::UseGroup);
1533 }
1534
1535 /** Ask the user to choose a colour, and then apply that color to my route
1536  */
1537 void
1538 RouteUI::choose_color ()
1539 {
1540         bool picked;
1541         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1542
1543         if (picked) {
1544                 set_color(color);
1545         }
1546 }
1547
1548 /** Set the route's own color.  This may not be used for display if
1549  *  the route is in a group which shares its color with its routes.
1550  */
1551 void
1552 RouteUI::set_color (const Gdk::Color & c)
1553 {
1554         /* leave _color alone in the group case so that tracks can retain their
1555          * own pre-group colors.
1556          */
1557
1558         char buf[64];
1559         _color = c;
1560         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1561
1562         /* note: we use the route state ID here so that color is the same for both
1563            the time axis view and the mixer strip
1564         */
1565
1566         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1567         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1568 }
1569
1570 /** @return GUI state ID for things that are common to the route in all its representations */
1571 string
1572 RouteUI::route_state_id () const
1573 {
1574         return string_compose (X_("route %1"), _route->id().to_s());
1575 }
1576
1577 int
1578 RouteUI::set_color_from_route ()
1579 {
1580         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1581
1582         if (str.empty()) {
1583                 return 1;
1584         }
1585
1586         int r, g, b;
1587
1588         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1589
1590         _color.set_red (r);
1591         _color.set_green (g);
1592         _color.set_blue (b);
1593
1594         return 0;
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 ()
1720 {
1721         ignore_comment_edit = true;
1722         if (comment_area) {
1723                 comment_area->get_buffer()->set_text (_route->comment());
1724         }
1725         ignore_comment_edit = false;
1726 }
1727
1728 void
1729 RouteUI::comment_editor_done_editing ()
1730 {
1731         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1732
1733         string const str = comment_area->get_buffer()->get_text();
1734         if (str == _route->comment ()) {
1735                 return;
1736         }
1737
1738         _route->set_comment (str, this);
1739 }
1740
1741 void
1742 RouteUI::set_route_active (bool a, bool apply_to_selection)
1743 {
1744         if (apply_to_selection) {
1745                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1746         } else {
1747                 _route->set_active (a, this);
1748         }
1749 }
1750
1751 void
1752 RouteUI::duplicate_selected_routes ()
1753 {
1754         ARDOUR_UI::instance()->start_duplicate_routes();
1755 }
1756
1757 void
1758 RouteUI::toggle_denormal_protection ()
1759 {
1760         if (denormal_menu_item) {
1761
1762                 bool x;
1763
1764                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1765
1766                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1767                         _route->set_denormal_protection (x);
1768                 }
1769         }
1770 }
1771
1772 void
1773 RouteUI::denormal_protection_changed ()
1774 {
1775         if (denormal_menu_item) {
1776                 denormal_menu_item->set_active (_route->denormal_protection());
1777         }
1778 }
1779
1780 void
1781 RouteUI::disconnect_input ()
1782 {
1783         _route->input()->disconnect (this);
1784 }
1785
1786 void
1787 RouteUI::disconnect_output ()
1788 {
1789         _route->output()->disconnect (this);
1790 }
1791
1792 bool
1793 RouteUI::is_track () const
1794 {
1795         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1796 }
1797
1798 boost::shared_ptr<Track>
1799 RouteUI::track() const
1800 {
1801         return boost::dynamic_pointer_cast<Track>(_route);
1802 }
1803
1804 bool
1805 RouteUI::is_audio_track () const
1806 {
1807         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1808 }
1809
1810 boost::shared_ptr<AudioTrack>
1811 RouteUI::audio_track() const
1812 {
1813         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1814 }
1815
1816 bool
1817 RouteUI::is_midi_track () const
1818 {
1819         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1820 }
1821
1822 boost::shared_ptr<MidiTrack>
1823 RouteUI::midi_track() const
1824 {
1825         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1826 }
1827
1828 bool
1829 RouteUI::has_audio_outputs () const
1830 {
1831         return (_route->n_outputs().n_audio() > 0);
1832 }
1833
1834 string
1835 RouteUI::name() const
1836 {
1837         return _route->name();
1838 }
1839
1840 void
1841 RouteUI::map_frozen ()
1842 {
1843         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1844
1845         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1846
1847         if (at) {
1848                 switch (at->freeze_state()) {
1849                 case AudioTrack::Frozen:
1850                         rec_enable_button->set_sensitive (false);
1851                         break;
1852                 default:
1853                         rec_enable_button->set_sensitive (true);
1854                         break;
1855                 }
1856         }
1857 }
1858
1859 void
1860 RouteUI::adjust_latency ()
1861 {
1862         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1863 }
1864
1865 bool
1866 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1867 {
1868         std::string path;
1869         std::string safe_name;
1870         std::string name;
1871
1872         prompter.get_result (name, true);
1873
1874         safe_name = legalize_for_path (name);
1875         safe_name += template_suffix;
1876
1877         path = Glib::build_filename (dir, safe_name);
1878
1879         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1880                 bool overwrite = overwrite_file_dialog (prompter,
1881                                                         _("Confirm Template Overwrite"),
1882                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1883
1884                 if (!overwrite) {
1885                         return false;
1886                 }
1887         }
1888
1889         _route->save_as_template (path, name);
1890
1891         return true;
1892 }
1893
1894 void
1895 RouteUI::save_as_template ()
1896 {
1897         std::string dir;
1898
1899         dir = ARDOUR::user_route_template_directory ();
1900
1901         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1902                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1903                 return;
1904         }
1905
1906         ArdourPrompter prompter (true); // modal
1907
1908         prompter.set_title (_("Save As Template"));
1909         prompter.set_prompt (_("Template name:"));
1910         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1911
1912         bool finished = false;
1913         while (!finished) {
1914                 switch (prompter.run()) {
1915                 case RESPONSE_ACCEPT:
1916                         finished = process_save_template_prompter (prompter, dir);
1917                         break;
1918                 default:
1919                         finished = true;
1920                         break;
1921                 }
1922         }
1923 }
1924
1925 void
1926 RouteUI::check_rec_enable_sensitivity ()
1927 {
1928         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1929                 rec_enable_button->set_sensitive (false);
1930         } else {
1931                 rec_enable_button->set_sensitive (true);
1932         }
1933
1934         update_monitoring_display ();
1935 }
1936
1937 void
1938 RouteUI::parameter_changed (string const & p)
1939 {
1940         /* this handles RC and per-session parameter changes */
1941
1942         if (p == "disable-disarm-during-roll") {
1943                 check_rec_enable_sensitivity ();
1944         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1945                 set_button_names ();
1946         } else if (p == "auto-input") {
1947                 update_monitoring_display ();
1948         } else if (p == "blink-rec-arm") {
1949                 if (UIConfiguration::instance().get_blink_rec_arm()) {
1950                         rec_blink_connection.disconnect ();
1951                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
1952                 } else {
1953                         rec_blink_connection.disconnect ();
1954                         RouteUI::blink_rec_display(false);
1955                 }
1956         }
1957 }
1958
1959 void
1960 RouteUI::step_gain_up ()
1961 {
1962         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), Controllable::UseGroup);
1963 }
1964
1965 void
1966 RouteUI::page_gain_up ()
1967 {
1968         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), Controllable::UseGroup);
1969 }
1970
1971 void
1972 RouteUI::step_gain_down ()
1973 {
1974         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), Controllable::UseGroup);
1975 }
1976
1977 void
1978 RouteUI::page_gain_down ()
1979 {
1980         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), Controllable::UseGroup);
1981 }
1982
1983 void
1984 RouteUI::open_remote_control_id_dialog ()
1985 {
1986         ArdourDialog dialog (_("Remote Control ID"));
1987         SpinButton* spin = 0;
1988
1989         dialog.get_vbox()->set_border_width (18);
1990
1991         if (Config->get_remote_model() == UserOrdered) {
1992                 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1993
1994                 HBox* hbox = manage (new HBox);
1995                 hbox->set_spacing (6);
1996                 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1997                 spin = manage (new SpinButton);
1998                 spin->set_digits (0);
1999                 spin->set_increments (1, 10);
2000                 spin->set_range (0, limit);
2001                 spin->set_value (_route->remote_control_id());
2002                 hbox->pack_start (*spin);
2003                 dialog.get_vbox()->pack_start (*hbox);
2004
2005                 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
2006                 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
2007         } else {
2008                 Label* l = manage (new Label());
2009                 if (_route->is_master() || _route->is_monitor()) {
2010                         l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
2011                                                          "The remote control ID of %3 cannot be changed."),
2012                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2013                                                        _route->remote_control_id(),
2014                                                        (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
2015                 } else {
2016                         l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
2017                                                          "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
2018                                                          "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
2019                                                        (is_track() ? _("track") : _("bus")),
2020                                                        _route->remote_control_id(),
2021                                                        "<span size=\"small\" style=\"italic\">",
2022                                                        "</span>",
2023                                                        Gtkmm2ext::markup_escape_text (_route->name()),
2024                                                        PROGRAM_NAME));
2025                 }
2026                 dialog.get_vbox()->pack_start (*l);
2027                 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
2028         }
2029
2030         dialog.show_all ();
2031         int const r = dialog.run ();
2032
2033         if (r == RESPONSE_ACCEPT && spin) {
2034                 _route->set_remote_control_id (spin->get_value_as_int ());
2035         }
2036 }
2037
2038 void
2039 RouteUI::setup_invert_buttons ()
2040 {
2041         /* remove old invert buttons */
2042         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2043                 _invert_button_box.remove (**i);
2044         }
2045
2046         _invert_buttons.clear ();
2047
2048         if (!_route || !_route->input()) {
2049                 return;
2050         }
2051
2052         uint32_t const N = _route->input()->n_ports().n_audio ();
2053
2054         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2055
2056         for (uint32_t i = 0; i < to_add; ++i) {
2057                 ArdourButton* b = manage (new ArdourButton);
2058                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2059                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2060
2061                 b->set_name (X_("invert button"));
2062                 if (to_add == 1) {
2063                         if (N > 1) {
2064                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2065                         } else {
2066                                 b->set_text (X_("Ø"));
2067                         }
2068                 } else {
2069                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2070                 }
2071
2072                 if (N <= _max_invert_buttons) {
2073                         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));
2074                 } else {
2075                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
2076                 }
2077
2078                 _invert_buttons.push_back (b);
2079                 _invert_button_box.pack_start (*b);
2080         }
2081
2082         _invert_button_box.set_spacing (1);
2083         _invert_button_box.show_all ();
2084 }
2085
2086 void
2087 RouteUI::set_invert_button_state ()
2088 {
2089         uint32_t const N = _route->input()->n_ports().n_audio();
2090         if (N > _max_invert_buttons) {
2091
2092                 /* One button for many channels; explicit active if all channels are inverted,
2093                    implicit active if some are, off if none are.
2094                 */
2095
2096                 ArdourButton* b = _invert_buttons.front ();
2097
2098                 if (_route->phase_invert().count() == _route->phase_invert().size()) {
2099                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2100                 } else if (_route->phase_invert().any()) {
2101                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2102                 } else {
2103                         b->set_active_state (Gtkmm2ext::Off);
2104                 }
2105
2106         } else {
2107
2108                 /* One button per channel; just set active */
2109
2110                 int j = 0;
2111                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2112                         (*i)->set_active (_route->phase_invert (j));
2113                 }
2114
2115         }
2116 }
2117
2118 bool
2119 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2120 {
2121         if (ev->button == 1 && i < _invert_buttons.size()) {
2122                 uint32_t const N = _route->input()->n_ports().n_audio ();
2123                 if (N <= _max_invert_buttons) {
2124                         /* left-click inverts phase so long as we have a button per channel */
2125                         _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2126                         return false;
2127                 }
2128         }
2129         return false;
2130 }
2131
2132
2133 bool
2134 RouteUI::invert_press (GdkEventButton* ev)
2135 {
2136         using namespace Menu_Helpers;
2137
2138         uint32_t const N = _route->input()->n_ports().n_audio();
2139         if (N <= _max_invert_buttons && ev->button != 3) {
2140                 /* If we have an invert button per channel, we only pop
2141                    up a menu on right-click; left click is handled
2142                    on release.
2143                 */
2144                 return false;
2145         }
2146
2147         delete _invert_menu;
2148         _invert_menu = new Menu;
2149         _invert_menu->set_name ("ArdourContextMenu");
2150         MenuList& items = _invert_menu->items ();
2151
2152         for (uint32_t i = 0; i < N; ++i) {
2153                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2154                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2155                 ++_i_am_the_modifier;
2156                 e->set_active (_route->phase_invert (i));
2157                 --_i_am_the_modifier;
2158         }
2159
2160         _invert_menu->popup (0, ev->time);
2161
2162         return true;
2163 }
2164
2165 void
2166 RouteUI::invert_menu_toggled (uint32_t c)
2167 {
2168         if (_i_am_the_modifier) {
2169                 return;
2170         }
2171
2172         _route->set_phase_invert (c, !_route->phase_invert (c));
2173 }
2174
2175 void
2176 RouteUI::set_invert_sensitive (bool yn)
2177 {
2178         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2179                 (*b)->set_sensitive (yn);
2180         }
2181 }
2182
2183 void
2184 RouteUI::request_redraw ()
2185 {
2186         if (_route) {
2187                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2188         }
2189 }
2190
2191 /** The Route's gui_changed signal has been emitted */
2192 void
2193 RouteUI::route_gui_changed (string what_changed)
2194 {
2195         if (what_changed == "color") {
2196                 if (set_color_from_route () == 0) {
2197                         route_color_changed ();
2198                 }
2199         }
2200 }
2201
2202 void
2203 RouteUI::track_mode_changed (void)
2204 {
2205         assert(is_track());
2206         switch (track()->mode()) {
2207                 case ARDOUR::NonLayered:
2208                 case ARDOUR::Normal:
2209                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2210                         break;
2211                 case ARDOUR::Destructive:
2212                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2213                         break;
2214         }
2215         rec_enable_button->queue_draw();
2216 }
2217
2218 /** @return the color that this route should use; it maybe its own,
2219     or it maybe that of its route group.
2220 */
2221 Gdk::Color
2222 RouteUI::color () const
2223 {
2224         RouteGroup* g = _route->route_group ();
2225
2226         if (g && g->is_color()) {
2227                 Gdk::Color c;
2228                 set_color_from_rgba (c, GroupTabs::group_color (g));
2229                 return c;
2230         }
2231
2232         return _color;
2233 }
2234
2235 void
2236 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2237 {
2238         _showing_sends_to = send_to;
2239         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2240 }
2241
2242 void
2243 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2244 {
2245         if (_route == send_to) {
2246                 show_sends_button->set_active (true);
2247                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2248         } else {
2249                 show_sends_button->set_active (false);
2250                 send_blink_connection.disconnect ();
2251         }
2252 }
2253
2254 RouteGroup*
2255 RouteUI::route_group() const
2256 {
2257         return _route->route_group();
2258 }