Move Gtkmm2ext widgets into libwidget
[ardour.git] / gtk2_ardour / route_ui.cc
1 /*
2     Copyright (C) 2002-2006 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <map>
21 #include <boost/algorithm/string.hpp>
22
23 #include "gtkmm2ext/gtk_ui.h"
24 #include "gtkmm2ext/choice.h"
25 #include "gtkmm2ext/doi.h"
26 #include "gtkmm2ext/bindable_button.h"
27 #include "gtkmm2ext/gtk_ui.h"
28 #include "gtkmm2ext/utils.h"
29
30 #include "widgets/ardour_button.h"
31
32 #include "pbd/memento_command.h"
33 #include "pbd/stacktrace.h"
34 #include "pbd/controllable.h"
35 #include "pbd/enumwriter.h"
36
37 #include "ardour/dB.h"
38 #include "ardour/route_group.h"
39 #include "ardour/solo_isolate_control.h"
40 #include "ardour/vca.h"
41 #include "ardour/vca_manager.h"
42 #include "ardour/audio_track.h"
43 #include "ardour/audio_port.h"
44 #include "ardour/audioengine.h"
45 #include "ardour/filename_extensions.h"
46 #include "ardour/midi_track.h"
47 #include "ardour/monitor_control.h"
48 #include "ardour/internal_send.h"
49 #include "ardour/panner_shell.h"
50 #include "ardour/profile.h"
51 #include "ardour/phase_control.h"
52 #include "ardour/send.h"
53 #include "ardour/route.h"
54 #include "ardour/session.h"
55 #include "ardour/template_utils.h"
56
57
58 #include "ardour_dialog.h"
59 #include "ardour_ui.h"
60 #include "automation_time_axis.h"
61 #include "editor.h"
62 #include "group_tabs.h"
63 #include "gui_object.h"
64 #include "gui_thread.h"
65 #include "keyboard.h"
66 #include "latency_gui.h"
67 #include "mixer_strip.h"
68 #include "plugin_pin_dialog.h"
69 #include "prompter.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
78 #include "pbd/i18n.h"
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         //items.push_back (SeparatorElem());
1436         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1437
1438 }
1439
1440 void
1441 RouteUI::build_mute_menu(void)
1442 {
1443         using namespace Menu_Helpers;
1444
1445         mute_menu = new Menu;
1446         mute_menu->set_name ("ArdourContextMenu");
1447
1448         MenuList& items = mute_menu->items();
1449
1450         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1451         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1452         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1453         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1454         pre_fader_mute_check->show_all();
1455
1456         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1457         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1458         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1459         items.push_back (CheckMenuElem(*post_fader_mute_check));
1460         post_fader_mute_check->show_all();
1461
1462         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1463         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1464         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1465         items.push_back (CheckMenuElem(*listen_mute_check));
1466         listen_mute_check->show_all();
1467
1468         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1469         init_mute_menu(MuteMaster::Main, main_mute_check);
1470         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1471         items.push_back (CheckMenuElem(*main_mute_check));
1472         main_mute_check->show_all();
1473
1474         //items.push_back (SeparatorElem());
1475         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1476
1477         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1478 }
1479
1480 void
1481 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1482 {
1483         check->set_active (_route->mute_control()->mute_points() & mp);
1484 }
1485
1486 void
1487 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1488 {
1489         if (check->get_active()) {
1490                 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() | mp));
1491         } else {
1492                 _route->mute_control()->set_mute_points (MuteMaster::MutePoint (_route->mute_control()->mute_points() & ~mp));
1493         }
1494 }
1495
1496 void
1497 RouteUI::muting_change ()
1498 {
1499         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1500
1501         bool yn;
1502         MuteMaster::MutePoint current = _route->mute_control()->mute_points ();
1503
1504         yn = (current & MuteMaster::PreFader);
1505
1506         if (pre_fader_mute_check->get_active() != yn) {
1507                 pre_fader_mute_check->set_active (yn);
1508         }
1509
1510         yn = (current & MuteMaster::PostFader);
1511
1512         if (post_fader_mute_check->get_active() != yn) {
1513                 post_fader_mute_check->set_active (yn);
1514         }
1515
1516         yn = (current & MuteMaster::Listen);
1517
1518         if (listen_mute_check->get_active() != yn) {
1519                 listen_mute_check->set_active (yn);
1520         }
1521
1522         yn = (current & MuteMaster::Main);
1523
1524         if (main_mute_check->get_active() != yn) {
1525                 main_mute_check->set_active (yn);
1526         }
1527 }
1528
1529 bool
1530 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1531 {
1532         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1533                 return true;
1534         }
1535
1536         bool view = solo_isolated_led->active_state();
1537         bool model = _route->solo_isolate_control()->solo_isolated();
1538
1539         /* called BEFORE the view has changed */
1540
1541         if (ev->button == 1) {
1542                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1543
1544                         if (model) {
1545                                 /* disable isolate for all routes */
1546                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 0.0, Controllable::NoGroup);
1547                         } else {
1548                                 /* enable isolate for all routes */
1549                                 _session->set_controls (route_list_to_control_list (_session->get_routes(), &Stripable::solo_isolate_control), 1.0, Controllable::NoGroup);
1550                         }
1551
1552                 } else {
1553
1554                         if (model == view) {
1555
1556                                 /* flip just this route */
1557
1558                                 boost::shared_ptr<RouteList> rl (new RouteList);
1559                                 rl->push_back (_route);
1560                                 _session->set_controls (route_list_to_control_list (rl, &Stripable::solo_isolate_control), view ? 0.0 : 1.0, Controllable::NoGroup);
1561                         }
1562                 }
1563         }
1564
1565         return false;
1566 }
1567
1568 bool
1569 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1570 {
1571         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1572                 return true;
1573         }
1574
1575         bool view = solo_safe_led->active_state();
1576         bool model = _route->solo_safe_control()->solo_safe();
1577
1578         if (ev->button == 1) {
1579                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1580                         boost::shared_ptr<RouteList> rl (_session->get_routes());
1581                         if (model) {
1582                                 /* disable solo safe for all routes */
1583                                 DisplaySuspender ds;
1584                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1585                                         (*i)->solo_safe_control()->set_value (0.0, Controllable::NoGroup);
1586                                 }
1587                         } else {
1588                                 /* enable solo safe for all routes */
1589                                 DisplaySuspender ds;
1590                                 for (RouteList::iterator i = rl->begin(); i != rl->end(); ++i) {
1591                                         (*i)->solo_safe_control()->set_value (1.0, Controllable::NoGroup);
1592                                 }
1593                         }
1594                 }
1595                 else {
1596                         if (model == view) {
1597                                 /* flip just this route */
1598                                 _route->solo_safe_control()->set_value (view ? 0.0 : 1.0, Controllable::NoGroup);
1599                         }
1600                 }
1601         }
1602
1603         return false;
1604 }
1605
1606 void
1607 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1608 {
1609         bool view = check->get_active();
1610         bool model = _route->solo_isolate_control()->solo_isolated();
1611
1612         /* called AFTER the view has changed */
1613
1614         if (model != view) {
1615                 _route->solo_isolate_control()->set_value (view ? 1.0 : 0.0, Controllable::UseGroup);
1616         }
1617 }
1618
1619 void
1620 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1621 {
1622         _route->solo_safe_control()->set_value (check->get_active() ? 1.0 : 0.0, Controllable::UseGroup);
1623 }
1624
1625 /** Ask the user to choose a colour, and then apply that color to my route */
1626 void
1627 RouteUI::choose_color ()
1628 {
1629         _color_picker.popup (_route);
1630 }
1631
1632 /** Set the route's own color.  This may not be used for display if
1633  *  the route is in a group which shares its color with its routes.
1634  */
1635 void
1636 RouteUI::set_color (uint32_t c)
1637 {
1638         _route->presentation_info().set_color (c);
1639 }
1640
1641 /** @return GUI state ID for things that are common to the route in all its representations */
1642 string
1643 RouteUI::route_state_id () const
1644 {
1645         return string_compose (X_("route %1"), _route->id().to_s());
1646 }
1647
1648 int
1649 RouteUI::set_color_from_route ()
1650 {
1651         if (_route->presentation_info().color_set()) {
1652                 return 0; /* nothing to do */
1653         }
1654
1655         return 1; /* pick a color */
1656 }
1657
1658 /** @return true if this name should be used for the route, otherwise false */
1659 bool
1660 RouteUI::verify_new_route_name (const std::string& name)
1661 {
1662         if (name.find (':') == string::npos) {
1663                 return true;
1664         }
1665
1666         MessageDialog colon_msg (
1667                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1668                 false, MESSAGE_QUESTION, BUTTONS_NONE
1669                 );
1670
1671         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1672         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1673
1674         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1675 }
1676
1677 void
1678 RouteUI::route_rename ()
1679 {
1680         ArdourPrompter name_prompter (true);
1681         string result;
1682         bool done = false;
1683
1684         if (is_track()) {
1685                 name_prompter.set_title (_("Rename Track"));
1686         } else {
1687                 name_prompter.set_title (_("Rename Bus"));
1688         }
1689         name_prompter.set_prompt (_("New name:"));
1690         name_prompter.set_initial_text (_route->name());
1691         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1692         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1693         name_prompter.show_all ();
1694
1695         while (!done) {
1696                 switch (name_prompter.run ()) {
1697                 case Gtk::RESPONSE_ACCEPT:
1698                         name_prompter.get_result (result);
1699                         name_prompter.hide ();
1700                         if (result.length()) {
1701                                 if (verify_new_route_name (result)) {
1702                                         _route->set_name (result);
1703                                         done = true;
1704                                 } else {
1705                                         /* back to name prompter */
1706                                 }
1707
1708                         } else {
1709                                 /* nothing entered, just get out of here */
1710                                 done = true;
1711                         }
1712                         break;
1713                 default:
1714                         done = true;
1715                         break;
1716                 }
1717         }
1718
1719         return;
1720
1721 }
1722
1723 void
1724 RouteUI::toggle_comment_editor ()
1725 {
1726 //      if (ignore_toggle) {
1727 //              return;
1728 //      }
1729
1730         if (comment_window && comment_window->is_visible ()) {
1731                 comment_window->hide ();
1732         } else {
1733                 open_comment_editor ();
1734         }
1735 }
1736
1737
1738 void
1739 RouteUI::open_comment_editor ()
1740 {
1741         if (comment_window == 0) {
1742                 setup_comment_editor ();
1743         }
1744
1745         string title;
1746         title = _route->name();
1747         title += _(": comment editor");
1748
1749         comment_window->set_title (title);
1750         comment_window->present();
1751 }
1752
1753 void
1754 RouteUI::setup_comment_editor ()
1755 {
1756         comment_window = new ArdourWindow (""); // title will be reset to show route
1757         comment_window->set_skip_taskbar_hint (true);
1758         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1759         comment_window->set_default_size (400, 200);
1760
1761         comment_area = manage (new TextView());
1762         comment_area->set_name ("MixerTrackCommentArea");
1763         comment_area->set_wrap_mode (WRAP_WORD);
1764         comment_area->set_editable (true);
1765         comment_area->get_buffer()->set_text (_route->comment());
1766         comment_area->show ();
1767
1768         comment_window->add (*comment_area);
1769 }
1770
1771 void
1772 RouteUI::comment_changed ()
1773 {
1774         ignore_comment_edit = true;
1775         if (comment_area) {
1776                 comment_area->get_buffer()->set_text (_route->comment());
1777         }
1778         ignore_comment_edit = false;
1779 }
1780
1781 void
1782 RouteUI::comment_editor_done_editing ()
1783 {
1784         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_editor_done_editing, src)
1785
1786         string const str = comment_area->get_buffer()->get_text();
1787         if (str == _route->comment ()) {
1788                 return;
1789         }
1790
1791         _route->set_comment (str, this);
1792 }
1793
1794 void
1795 RouteUI::set_route_active (bool a, bool apply_to_selection)
1796 {
1797         if (apply_to_selection) {
1798                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1799         } else {
1800                 _route->set_active (a, this);
1801         }
1802 }
1803
1804 void
1805 RouteUI::duplicate_selected_routes ()
1806 {
1807         ARDOUR_UI::instance()->start_duplicate_routes();
1808 }
1809
1810 void
1811 RouteUI::toggle_denormal_protection ()
1812 {
1813         if (denormal_menu_item) {
1814
1815                 bool x;
1816
1817                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1818
1819                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1820                         _route->set_denormal_protection (x);
1821                 }
1822         }
1823 }
1824
1825 void
1826 RouteUI::denormal_protection_changed ()
1827 {
1828         if (denormal_menu_item) {
1829                 denormal_menu_item->set_active (_route->denormal_protection());
1830         }
1831 }
1832
1833 void
1834 RouteUI::disconnect_input ()
1835 {
1836         _route->input()->disconnect (this);
1837 }
1838
1839 void
1840 RouteUI::disconnect_output ()
1841 {
1842         _route->output()->disconnect (this);
1843 }
1844
1845 bool
1846 RouteUI::is_track () const
1847 {
1848         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1849 }
1850
1851 boost::shared_ptr<Track>
1852 RouteUI::track() const
1853 {
1854         return boost::dynamic_pointer_cast<Track>(_route);
1855 }
1856
1857 bool
1858 RouteUI::is_audio_track () const
1859 {
1860         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1861 }
1862
1863 boost::shared_ptr<AudioTrack>
1864 RouteUI::audio_track() const
1865 {
1866         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1867 }
1868
1869 bool
1870 RouteUI::is_midi_track () const
1871 {
1872         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1873 }
1874
1875 boost::shared_ptr<MidiTrack>
1876 RouteUI::midi_track() const
1877 {
1878         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1879 }
1880
1881 bool
1882 RouteUI::has_audio_outputs () const
1883 {
1884         return (_route->n_outputs().n_audio() > 0);
1885 }
1886
1887 void
1888 RouteUI::map_frozen ()
1889 {
1890         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1891
1892         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1893
1894         if (at) {
1895                 check_rec_enable_sensitivity ();
1896         }
1897 }
1898
1899 void
1900 RouteUI::adjust_latency ()
1901 {
1902         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1903 }
1904
1905 bool
1906 RouteUI::process_save_template_prompter (ArdourPrompter& prompter, const std::string& dir)
1907 {
1908         std::string path;
1909         std::string safe_name;
1910         std::string name;
1911
1912         prompter.get_result (name, true);
1913
1914         safe_name = legalize_for_path (name);
1915         safe_name += template_suffix;
1916
1917         path = Glib::build_filename (dir, safe_name);
1918
1919         if (Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
1920                 bool overwrite = overwrite_file_dialog (prompter,
1921                                                         _("Confirm Template Overwrite"),
1922                                                         _("A template already exists with that name. Do you want to overwrite it?"));
1923
1924                 if (!overwrite) {
1925                         return false;
1926                 }
1927         }
1928
1929         _route->save_as_template (path, name);
1930
1931         return true;
1932 }
1933
1934 void
1935 RouteUI::save_as_template ()
1936 {
1937         std::string dir;
1938
1939         dir = ARDOUR::user_route_template_directory ();
1940
1941         if (g_mkdir_with_parents (dir.c_str(), 0755)) {
1942                 error << string_compose (_("Cannot create route template directory %1"), dir) << endmsg;
1943                 return;
1944         }
1945
1946         ArdourPrompter prompter (true); // modal
1947
1948         prompter.set_title (_("Save As Template"));
1949         prompter.set_prompt (_("Template name:"));
1950         prompter.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1951
1952         bool finished = false;
1953         while (!finished) {
1954                 switch (prompter.run()) {
1955                 case RESPONSE_ACCEPT:
1956                         finished = process_save_template_prompter (prompter, dir);
1957                         break;
1958                 default:
1959                         finished = true;
1960                         break;
1961                 }
1962         }
1963 }
1964
1965 void
1966 RouteUI::check_rec_enable_sensitivity ()
1967 {
1968         if (!rec_enable_button) {
1969                 assert (0); // This should not happen
1970                 return;
1971         }
1972         if (!_session->writable()) {
1973                 rec_enable_button->set_sensitive (false);
1974                 return;
1975         }
1976
1977         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1978                 rec_enable_button->set_sensitive (false);
1979         } else if (is_audio_track ()  && track()->freeze_state() == AudioTrack::Frozen) {
1980                 rec_enable_button->set_sensitive (false);
1981         } else {
1982                 rec_enable_button->set_sensitive (true);
1983         }
1984         if (_route && _route->rec_safe_control () && _route->rec_safe_control()->get_value()) {
1985                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() | Gtkmm2ext::Insensitive));
1986         } else {
1987                 rec_enable_button->set_visual_state (Gtkmm2ext::VisualState (solo_button->visual_state() & ~Gtkmm2ext::Insensitive));
1988         }
1989         update_monitoring_display ();
1990 }
1991
1992 void
1993 RouteUI::parameter_changed (string const & p)
1994 {
1995         /* this handles RC and per-session parameter changes */
1996
1997         if (p == "disable-disarm-during-roll") {
1998                 check_rec_enable_sensitivity ();
1999         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
2000                 set_button_names ();
2001         } else if (p == "session-monitoring") {
2002                 update_monitoring_display ();
2003         } else if (p == "auto-input") {
2004                 update_monitoring_display ();
2005         } else if (p == "blink-rec-arm") {
2006                 if (UIConfiguration::instance().get_blink_rec_arm()) {
2007                         rec_blink_connection.disconnect ();
2008                         rec_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::blink_rec_display));
2009                 } else {
2010                         rec_blink_connection.disconnect ();
2011                         RouteUI::blink_rec_display(false);
2012                 }
2013         }
2014 }
2015
2016 void
2017 RouteUI::setup_invert_buttons ()
2018 {
2019         /* remove old invert buttons */
2020         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
2021                 _invert_button_box.remove (**i);
2022         }
2023
2024         _invert_buttons.clear ();
2025
2026         if (!_route || !_route->input()) {
2027                 return;
2028         }
2029
2030         uint32_t const N = _route->input()->n_ports().n_audio ();
2031
2032         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
2033
2034         for (uint32_t i = 0; i < to_add; ++i) {
2035                 ArdourButton* b = manage (new ArdourButton);
2036                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press), false);
2037                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i), false);
2038
2039                 b->set_name (X_("invert button"));
2040                 if (to_add == 1) {
2041                         if (N > 1) {
2042                                 b->set_text (string_compose (X_("Ø (%1)"), N));
2043                         } else {
2044                                 b->set_text (X_("Ø"));
2045                         }
2046                 } else {
2047                         b->set_text (string_compose (X_("Ø%1"), i + 1));
2048                 }
2049
2050                 if (N <= _max_invert_buttons) {
2051                         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));
2052                 } else {
2053                         UI::instance()->set_tip (*b, _("Click to show a menu of channels to invert polarity"));
2054                 }
2055
2056                 _invert_buttons.push_back (b);
2057                 _invert_button_box.pack_start (*b);
2058         }
2059
2060         _invert_button_box.set_spacing (1);
2061         _invert_button_box.show_all ();
2062 }
2063
2064 void
2065 RouteUI::set_invert_button_state ()
2066 {
2067         uint32_t const N = _route->input()->n_ports().n_audio();
2068         if (N > _max_invert_buttons) {
2069
2070                 /* One button for many channels; explicit active if all channels are inverted,
2071                    implicit active if some are, off if none are.
2072                 */
2073
2074                 ArdourButton* b = _invert_buttons.front ();
2075
2076                 if (_route->phase_control()->count() == _route->phase_control()->size()) {
2077                         b->set_active_state (Gtkmm2ext::ExplicitActive);
2078                 } else if (_route->phase_control()->any()) {
2079                         b->set_active_state (Gtkmm2ext::ImplicitActive);
2080                 } else {
2081                         b->set_active_state (Gtkmm2ext::Off);
2082                 }
2083
2084         } else {
2085
2086                 /* One button per channel; just set active */
2087
2088                 int j = 0;
2089                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
2090                         (*i)->set_active (_route->phase_control()->inverted (j));
2091                 }
2092
2093         }
2094 }
2095
2096 bool
2097 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2098 {
2099         if (ev->button == 1 && i < _invert_buttons.size()) {
2100                 uint32_t const N = _route->input()->n_ports().n_audio ();
2101                 if (N <= _max_invert_buttons) {
2102                         /* left-click inverts phase so long as we have a button per channel */
2103                         _route->phase_control()->set_phase_invert (i, !_invert_buttons[i]->get_active());
2104                         return false;
2105                 }
2106         }
2107         return false;
2108 }
2109
2110
2111 bool
2112 RouteUI::invert_press (GdkEventButton* ev)
2113 {
2114         using namespace Menu_Helpers;
2115
2116         uint32_t const N = _route->input()->n_ports().n_audio();
2117         if (N <= _max_invert_buttons && ev->button != 3) {
2118                 /* If we have an invert button per channel, we only pop
2119                    up a menu on right-click; left click is handled
2120                    on release.
2121                 */
2122                 return false;
2123         }
2124
2125         delete _invert_menu;
2126         _invert_menu = new Menu;
2127         _invert_menu->set_name ("ArdourContextMenu");
2128         MenuList& items = _invert_menu->items ();
2129
2130         for (uint32_t i = 0; i < N; ++i) {
2131                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2132                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2133                 ++_i_am_the_modifier;
2134                 e->set_active (_route->phase_control()->inverted (i));
2135                 --_i_am_the_modifier;
2136         }
2137
2138         _invert_menu->popup (0, ev->time);
2139
2140         return true;
2141 }
2142
2143 void
2144 RouteUI::invert_menu_toggled (uint32_t c)
2145 {
2146         if (_i_am_the_modifier) {
2147                 return;
2148         }
2149
2150
2151         _route->phase_control()->set_phase_invert (c, !_route->phase_control()->inverted (c));
2152 }
2153
2154 void
2155 RouteUI::set_invert_sensitive (bool yn)
2156 {
2157         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2158                 (*b)->set_sensitive (yn);
2159         }
2160 }
2161
2162 /** The Route's gui_changed signal has been emitted */
2163 void
2164 RouteUI::route_gui_changed (PropertyChange const& what_changed)
2165 {
2166         if (what_changed.contains (Properties::color)) {
2167                 if (set_color_from_route () == 0) {
2168                         route_color_changed ();
2169                 }
2170         }
2171 }
2172
2173 void
2174 RouteUI::track_mode_changed (void)
2175 {
2176         assert(is_track());
2177         switch (track()->mode()) {
2178                 case ARDOUR::NonLayered:
2179                 case ARDOUR::Normal:
2180                         rec_enable_button->set_icon (ArdourIcon::RecButton);
2181                         break;
2182                 case ARDOUR::Destructive:
2183                         rec_enable_button->set_icon (ArdourIcon::RecTapeMode);
2184                         break;
2185         }
2186         rec_enable_button->queue_draw();
2187 }
2188
2189 /** @return the color that this route should use; it maybe its own,
2190  *  or it maybe that of its route group.
2191  */
2192 Gdk::Color
2193 RouteUI::route_color () const
2194 {
2195         Gdk::Color c;
2196         RouteGroup* g = _route->route_group ();
2197         string p;
2198
2199         if (g && g->is_color()) {
2200                 set_color_from_rgba (c, GroupTabs::group_color (g));
2201         } else {
2202                 set_color_from_rgba (c, _route->presentation_info().color());
2203         }
2204
2205         return c;
2206 }
2207
2208 void
2209 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2210 {
2211         _showing_sends_to = send_to;
2212         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2213 }
2214
2215 void
2216 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2217 {
2218         if (_route == send_to) {
2219                 show_sends_button->set_active (true);
2220                 send_blink_connection = Timers::blink_connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2221         } else {
2222                 show_sends_button->set_active (false);
2223                 send_blink_connection.disconnect ();
2224         }
2225 }
2226
2227 RouteGroup*
2228 RouteUI::route_group() const
2229 {
2230         return _route->route_group();
2231 }
2232
2233
2234 RoutePinWindowProxy::RoutePinWindowProxy(std::string const &name, boost::shared_ptr<ARDOUR::Route> route)
2235         : WM::ProxyBase (name, string())
2236         , _route (boost::weak_ptr<Route> (route))
2237 {
2238         route->DropReferences.connect (going_away_connection, MISSING_INVALIDATOR, boost::bind (&RoutePinWindowProxy::route_going_away, this), gui_context());
2239 }
2240
2241 RoutePinWindowProxy::~RoutePinWindowProxy()
2242 {
2243         _window = 0;
2244 }
2245
2246 ARDOUR::SessionHandlePtr*
2247 RoutePinWindowProxy::session_handle ()
2248 {
2249         ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2250         if (aw) { return aw; }
2251         return 0;
2252 }
2253
2254 Gtk::Window*
2255 RoutePinWindowProxy::get (bool create)
2256 {
2257         boost::shared_ptr<Route> r = _route.lock ();
2258         if (!r) {
2259                 return 0;
2260         }
2261
2262         if (!_window) {
2263                 if (!create) {
2264                         return 0;
2265                 }
2266                 _window = new PluginPinDialog (r);
2267                 ArdourWindow* aw = dynamic_cast<ArdourWindow*> (_window);
2268                 if (aw) {
2269                         aw->set_session (_session);
2270                 }
2271                 _window->show_all ();
2272         }
2273         return _window;
2274 }
2275
2276 void
2277 RoutePinWindowProxy::route_going_away ()
2278 {
2279         delete _window;
2280         _window = 0;
2281         WM::Manager::instance().remove (this);
2282         going_away_connection.disconnect();
2283         delete this;
2284 }
2285
2286 void
2287 RouteUI::maybe_add_route_print_mgr ()
2288 {
2289         if (_route->pinmgr_proxy ()) {
2290                 return;
2291         }
2292         RoutePinWindowProxy* wp = new RoutePinWindowProxy (
2293                         string_compose ("RPM-%1", _route->id()), _route);
2294         wp->set_session (_session);
2295
2296         const XMLNode* ui_xml = _session->extra_xml (X_("UI"));
2297         if (ui_xml) {
2298                 wp->set_state (*ui_xml, 0);
2299         }
2300
2301 #if 0
2302         void* existing_ui = _route->pinmgr_proxy ();
2303         if (existing_ui) {
2304                 wp->use_window (*(reinterpret_cast<Gtk::Window*>(existing_ui)));
2305         }
2306 #endif
2307         _route->set_pingmgr_proxy (wp);
2308
2309         WM::Manager::instance().register_window (wp);
2310 }
2311
2312 void
2313 RouteUI::manage_pins ()
2314 {
2315         RoutePinWindowProxy* proxy = _route->pinmgr_proxy ();
2316         if (proxy) {
2317                 proxy->get (true);
2318                 proxy->present();
2319         }
2320 }
2321
2322 void
2323 RouteUI::fan_out (bool to_busses, bool group)
2324 {
2325         DisplaySuspender ds;
2326         boost::shared_ptr<ARDOUR::Route> route = _route;
2327         boost::shared_ptr<PluginInsert> pi = boost::dynamic_pointer_cast<PluginInsert> (route->the_instrument ());
2328         assert (pi);
2329
2330         const uint32_t n_outputs = pi->output_streams ().n_audio ();
2331         if (route->n_outputs ().n_audio () != n_outputs) {
2332                 MessageDialog msg (string_compose (
2333                                         _("The Plugin's number of audio outputs ports (%1) does not match the Tracks's number of audio outputs (%2). Cannot fan out."),
2334                                         n_outputs, route->n_outputs ().n_audio ()));
2335                 msg.run ();
2336                 return;
2337         }
2338
2339 #define BUSNAME  pd.group_name + "(" + route->name () + ")"
2340
2341         /* count busses and channels/bus */
2342         boost::shared_ptr<Plugin> plugin = pi->plugin ();
2343         std::map<std::string, uint32_t> busnames;
2344         for (uint32_t p = 0; p < n_outputs; ++p) {
2345                 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2346                 std::string bn = BUSNAME;
2347                 busnames[bn]++;
2348         }
2349
2350         if (busnames.size () < 2) {
2351                 MessageDialog msg (_("Instrument has only 1 output bus. Nothing to fan out."));
2352                 msg.run ();
2353                 return;
2354         }
2355
2356         uint32_t outputs = 2;
2357         if (_session->master_out ()) {
2358                 outputs = std::max (outputs, _session->master_out ()->n_inputs ().n_audio ());
2359         }
2360
2361         route->output ()->disconnect (this);
2362         route->panner_shell ()->set_bypassed (true);
2363
2364         RouteList to_group;
2365         for (uint32_t p = 0; p < n_outputs; ++p) {
2366                 const Plugin::IOPortDescription& pd (plugin->describe_io_port (DataType::AUDIO, false, p));
2367                 std::string bn = BUSNAME;
2368                 boost::shared_ptr<Route> r = _session->route_by_name (bn);
2369                 if (!r) {
2370                         if (to_busses) {
2371                                 RouteList rl = _session->new_audio_route (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::AudioBus, PresentationInfo::max_order);
2372                                 r = rl.front ();
2373                                 assert (r);
2374                         } else {
2375                                 list<boost::shared_ptr<AudioTrack> > tl =
2376                                         _session->new_audio_track (busnames[bn], outputs, NULL, 1, bn, PresentationInfo::max_order, Normal);
2377                                 r = tl.front ();
2378                                 assert (r);
2379
2380                                 boost::shared_ptr<ControlList> cl (new ControlList);
2381                                 cl->push_back (r->monitoring_control ());
2382                                 _session->set_controls (cl, (double) MonitorInput, Controllable::NoGroup);
2383                         }
2384                         r->input ()->disconnect (this);
2385                 }
2386                 to_group.push_back (r);
2387                 route->output ()->audio (p)->connect (r->input ()->audio (pd.group_channel).get());
2388         }
2389 #undef BUSNAME
2390
2391         if (group) {
2392                 RouteGroup* rg = NULL;
2393                 const std::list<RouteGroup*>& rgs (_session->route_groups ());
2394                 for (std::list<RouteGroup*>::const_iterator i = rgs.begin (); i != rgs.end (); ++i) {
2395                         if ((*i)->name () == pi->name ()) {
2396                                 rg = *i;
2397                                 break;
2398                         }
2399                 }
2400                 if (!rg) {
2401                         rg = new RouteGroup (*_session, pi->name ());
2402                         _session->add_route_group (rg);
2403                         rg->set_gain (false);
2404                 }
2405
2406                 GroupTabs::set_group_color (rg, route->presentation_info().color());
2407                 for (RouteList::const_iterator i = to_group.begin(); i != to_group.end(); ++i) {
2408                         rg->add (*i);
2409                 }
2410         }
2411 }
2412
2413 bool
2414 RouteUI::mark_hidden (bool yn)
2415 {
2416         if (yn != _route->presentation_info().hidden()) {
2417                 _route->presentation_info().set_hidden (yn);
2418                 return true; // things changed
2419         }
2420         return false;
2421 }
2422
2423 boost::shared_ptr<Stripable>
2424 RouteUI::stripable () const
2425 {
2426         return _route;
2427 }
2428