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