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