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