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