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