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