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