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