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