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