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