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