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