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