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