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