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