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