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