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