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