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