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