Various UI tweaks.
[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 <gtkmm2ext/gtk_ui.h>
21 #include <gtkmm2ext/choice.h>
22 #include <gtkmm2ext/doi.h>
23 #include <gtkmm2ext/bindable_button.h>
24 #include <gtkmm2ext/barcontroller.h>
25 #include <gtkmm2ext/gtk_ui.h>
26
27 #include "ardour/route_group.h"
28 #include "ardour/dB.h"
29 #include "pbd/memento_command.h"
30 #include "pbd/stacktrace.h"
31 #include "pbd/controllable.h"
32 #include "pbd/enumwriter.h"
33
34 #include "ardour_ui.h"
35 #include "editor.h"
36 #include "route_ui.h"
37 #include "ardour_button.h"
38 #include "keyboard.h"
39 #include "utils.h"
40 #include "prompter.h"
41 #include "gui_thread.h"
42 #include "ardour_dialog.h"
43 #include "latency_gui.h"
44 #include "mixer_strip.h"
45 #include "automation_time_axis.h"
46 #include "route_time_axis.h"
47 #include "group_tabs.h"
48
49 #include "ardour/audio_track.h"
50 #include "ardour/audioengine.h"
51 #include "ardour/filename_extensions.h"
52 #include "ardour/midi_track.h"
53 #include "ardour/route.h"
54 #include "ardour/session.h"
55 #include "ardour/template_utils.h"
56
57 #include "i18n.h"
58 using namespace Gtk;
59 using namespace Gtkmm2ext;
60 using namespace ARDOUR;
61 using namespace ARDOUR_UI_UTILS;
62 using namespace PBD;
63
64 uint32_t RouteUI::_max_invert_buttons = 3;
65 PBD::Signal1<void, boost::shared_ptr<Route> > RouteUI::BusSendDisplayChanged;
66 boost::weak_ptr<Route> RouteUI::_showing_sends_to;
67
68 RouteUI::RouteUI (ARDOUR::Session* sess)
69         : AxisView(sess)
70         , mute_menu(0)
71         , solo_menu(0)
72         , sends_menu(0)
73         , record_menu(0)
74         , comment_window(0)
75         , _invert_menu(0)
76 {
77         if (sess) init ();
78 }
79
80 RouteUI::~RouteUI()
81 {
82         _route.reset (); /* drop reference to route, so that it can be cleaned up */
83         route_connections.drop_connections ();
84
85         delete solo_menu;
86         delete mute_menu;
87         delete sends_menu;
88         delete record_menu;
89         delete _invert_menu;
90         delete comment_window;
91 }
92
93 void
94 RouteUI::init ()
95 {
96         self_destruct = true;
97         mute_menu = 0;
98         solo_menu = 0;
99         sends_menu = 0;
100         record_menu = 0;
101         _invert_menu = 0;
102         pre_fader_mute_check = 0;
103         post_fader_mute_check = 0;
104         listen_mute_check = 0;
105         main_mute_check = 0;
106         solo_safe_check = 0;
107         solo_isolated_check = 0;
108         solo_isolated_led = 0;
109         solo_safe_led = 0;
110         _solo_release = 0;
111         _mute_release = 0;
112         denormal_menu_item = 0;
113         step_edit_item = 0;
114         multiple_mute_change = false;
115         multiple_solo_change = false;
116         _i_am_the_modifier = 0;
117
118         setup_invert_buttons ();
119
120         mute_button = manage (new ArdourButton);
121         mute_button->set_name ("mute button");
122         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
123
124         solo_button = manage (new ArdourButton);
125         solo_button->set_name ("solo button");
126         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
127         solo_button->set_no_show_all (true);
128
129         rec_enable_button = manage (new ArdourButton);
130         rec_enable_button->set_name ("record enable button");
131 //      rec_enable_button->set_tweaks (ArdourButton::ImplicitUsesSolidColor);
132         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
133
134         show_sends_button = manage (new ArdourButton);
135         show_sends_button->set_name ("send alert button");
136         UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
137
138         monitor_input_button = manage (new ArdourButton (ArdourButton::default_elements));
139         monitor_input_button->set_name ("monitor button");
140         monitor_input_button->set_text (_("In"));
141         UI::instance()->set_tip (monitor_input_button, _("Monitor input"), "");
142         monitor_input_button->set_no_show_all (true);
143         
144         monitor_disk_button = manage (new ArdourButton (ArdourButton::default_elements));
145         monitor_disk_button->set_name ("monitor button");
146         monitor_disk_button->set_text (_("Disk"));
147         UI::instance()->set_tip (monitor_disk_button, _("Monitor playback"), "");
148         monitor_disk_button->set_no_show_all (true);
149
150         _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
151         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
152         _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
153
154         _session->config.ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
155         Config->ParameterChanged.connect (*this, invalidator (*this), boost::bind (&RouteUI::parameter_changed, this, _1), gui_context());
156
157         rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
158         rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
159
160         show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
161         show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
162
163         solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
164         solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
165         mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
166         mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
167         
168         monitor_input_button->set_distinct_led_click (false);
169         monitor_disk_button->set_distinct_led_click (false);
170
171         monitor_input_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_press));
172         monitor_input_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_input_release));
173
174         monitor_disk_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_press));
175         monitor_disk_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::monitor_disk_release));
176
177         BusSendDisplayChanged.connect_same_thread (*this, boost::bind(&RouteUI::bus_send_display_changed, this, _1));
178 }
179
180 void
181 RouteUI::reset ()
182 {
183         route_connections.drop_connections ();
184
185         delete solo_menu;
186         solo_menu = 0;
187
188         delete mute_menu;
189         mute_menu = 0;
190
191         denormal_menu_item = 0;
192 }
193
194 void
195 RouteUI::self_delete ()
196 {
197         delete this;
198 }
199
200 void
201 RouteUI::set_route (boost::shared_ptr<Route> rp)
202 {
203         reset ();
204
205         _route = rp;
206
207         if (set_color_from_route()) {
208                 set_color (unique_random_color());
209         }
210
211         if (self_destruct) {
212                 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
213         }
214
215         mute_button->set_controllable (_route->mute_control());
216         solo_button->set_controllable (_route->solo_control());
217
218         _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
219         _route->mute_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::mute_changed, this, _1), gui_context());
220
221         _route->comment_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::comment_changed, this, _1), gui_context());
222
223         _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
224         _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
225         _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
226         _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
227
228         _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
229         _route->PropertyChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::property_changed, this, _1), gui_context());
230
231         _route->io_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::setup_invert_buttons, this), gui_context ());
232         _route->gui_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_gui_changed, this, _1), gui_context ());
233
234         if (_session->writable() && is_track()) {
235                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
236
237                 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
238                 
239                 rec_enable_button->show();
240                 rec_enable_button->set_controllable (t->rec_enable_control());
241
242                 if (is_midi_track()) {
243                         midi_track()->StepEditStatusChange.connect (route_connections, invalidator (*this),
244                                                                     boost::bind (&RouteUI::step_edit_changed, this, _1), gui_context());
245                 }
246
247         } 
248
249         /* this will work for busses and tracks, and needs to be called to
250            set up the name entry/name label display.
251         */
252
253         update_rec_display ();
254
255         if (is_track()) {
256                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
257                 t->MonitoringChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::monitoring_changed, this), gui_context());
258
259                 update_monitoring_display ();
260         }
261
262         mute_button->unset_flags (Gtk::CAN_FOCUS);
263         solo_button->unset_flags (Gtk::CAN_FOCUS);
264
265         mute_button->show();
266
267         if (_route->is_monitor() || _route->is_master()) {
268                 solo_button->hide ();
269         } else {
270                 solo_button->show();
271         }
272
273         map_frozen ();
274
275         setup_invert_buttons ();
276         set_invert_button_state ();
277
278         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
279         bus_send_display_changed (s);
280
281         update_mute_display ();
282         update_solo_display ();
283 }
284
285 void
286 RouteUI::polarity_changed ()
287 {
288         if (!_route) {
289                 return;
290         }
291
292         set_invert_button_state ();
293 }
294
295 bool
296 RouteUI::mute_press (GdkEventButton* ev)
297 {
298         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
299                 return true;
300         }
301
302         multiple_mute_change = false;
303
304         if (Keyboard::is_context_menu_event (ev)) {
305
306                 if (mute_menu == 0){
307                         build_mute_menu();
308                 }
309
310                 mute_menu->popup(0,ev->time);
311
312         } else {
313
314                 if (Keyboard::is_button2_event (ev)) {
315                         // Primary-button2 click is the midi binding click
316                         // button2-click is "momentary"
317
318
319                         if (mute_button->on_button_press_event (ev)) {
320                                 return true;
321                         }
322
323                         _mute_release = new SoloMuteRelease (_route->muted ());
324                 }
325
326                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
327
328                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
329
330                                 /* toggle mute on everything (but
331                                  * exclude the master and monitor)
332                                  *
333                                  * because we are going to erase
334                                  * elements of the list we need to work
335                                  * on a copy.
336                                  */
337                                         
338                                 boost::shared_ptr<RouteList> copy (new RouteList);
339
340                                 *copy = *_session->get_routes ();
341
342                                 for (RouteList::iterator i = copy->begin(); i != copy->end(); ) {
343                                         if ((*i)->is_master() || (*i)->is_monitor()) {
344                                                 i = copy->erase (i);
345                                         } else {
346                                                 ++i;
347                                         }
348                                 }
349
350                                 if (_mute_release) {
351                                         _mute_release->routes = copy;
352                                 }
353
354                                 DisplaySuspender ds;
355                                 _session->set_mute (copy, !_route->muted());
356
357                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
358
359                                 /* Primary-button1 applies change to the mix group even if it is not active
360                                    NOTE: Primary-button2 is MIDI learn.
361                                 */
362
363                                 boost::shared_ptr<RouteList> rl;
364
365                                 if (ev->button == 1) { 
366
367                                         if (_route->route_group()) {
368                                                         
369                                                 rl = _route->route_group()->route_list();
370                                                         
371                                                 if (_mute_release) {
372                                                         _mute_release->routes = rl;
373                                                 }
374                                         } else {
375                                                 rl.reset (new RouteList);
376                                                 rl->push_back (_route);
377                                         }
378
379                                         DisplaySuspender ds;
380                                         _session->set_mute (rl, !_route->muted(), Session::rt_cleanup, true);
381                                 }
382
383                         } else {
384
385                                 /* plain click applies change to this route */
386
387                                 boost::shared_ptr<RouteList> rl (new RouteList);
388                                 rl->push_back (_route);
389                                         
390                                 if (_mute_release) {
391                                         _mute_release->routes = rl;
392                                 }
393
394                                 _session->set_mute (rl, !_route->muted());
395
396                         }
397                 }
398         }
399
400         return true;
401 }
402
403 bool
404 RouteUI::mute_release (GdkEventButton*)
405 {
406         if (_mute_release){
407                 DisplaySuspender ds;
408                 _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
409                 delete _mute_release;
410                 _mute_release = 0;
411         }
412
413         return true;
414 }
415
416 bool
417 RouteUI::solo_press(GdkEventButton* ev)
418 {
419         /* ignore double/triple clicks */
420
421         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
422                 return true;
423         }
424
425         multiple_solo_change = false;
426
427         if (Keyboard::is_context_menu_event (ev)) {
428
429                 if (! (solo_isolated_led && solo_isolated_led->is_visible()) ||
430                     ! (solo_safe_led && solo_safe_led->is_visible())) {
431
432                         if (solo_menu == 0) {
433                                 build_solo_menu ();
434                         }
435
436                         solo_menu->popup (1, ev->time);
437                 }
438
439         } else {
440
441                 if (Keyboard::is_button2_event (ev)) {
442
443                         // Primary-button2 click is the midi binding click
444                         // button2-click is "momentary"
445
446                         if (solo_button->on_button_press_event (ev)) {
447                                 return true;
448                         }
449
450                         _solo_release = new SoloMuteRelease (_route->self_soloed());
451                 }
452
453                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
454
455                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
456
457                                 /* Primary-Tertiary-click applies change to all routes */
458
459                                 if (_solo_release) {
460                                         _solo_release->routes = _session->get_routes ();
461                                 }
462
463                                 DisplaySuspender ds;
464                                 if (Config->get_solo_control_is_listen_control()) {
465                                         _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(),  Session::rt_cleanup, true);
466                                 } else {
467                                         _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, true);
468                                 }
469
470                         } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
471
472                                 // Primary-Secondary-click: exclusively solo this track
473
474                                 if (_solo_release) {
475                                         _solo_release->exclusive = true;
476
477                                         boost::shared_ptr<RouteList> routes = _session->get_routes();
478
479                                         for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
480                                                 if ((*i)->soloed ()) {
481                                                         _solo_release->routes_on->push_back (*i);
482                                                 } else {
483                                                         _solo_release->routes_off->push_back (*i);
484                                                 }
485                                         }
486                                 }
487
488                                 if (Config->get_solo_control_is_listen_control()) {
489                                         /* ??? we need a just_one_listen() method */
490                                 } else {
491                                         DisplaySuspender ds;
492                                         _session->set_just_one_solo (_route, true);
493                                 }
494
495                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
496
497                                 // shift-click: toggle solo isolated status
498
499                                 _route->set_solo_isolated (!_route->solo_isolated(), this);
500                                 delete _solo_release;
501                                 _solo_release = 0;
502
503                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
504
505                                 /* Primary-button1: solo mix group.
506                                    NOTE: Primary-button2 is MIDI learn.
507                                 */
508
509                                 /* Primary-button1 applies change to the mix group even if it is not active
510                                    NOTE: Primary-button2 is MIDI learn.
511                                 */
512
513                                 boost::shared_ptr<RouteList> rl;
514
515                                 if (ev->button == 1) { 
516
517                                         if (_route->route_group()) {
518                                                         
519                                                 rl = _route->route_group()->route_list();
520                                                         
521                                                 if (_solo_release) {
522                                                         _solo_release->routes = rl;
523                                                 }
524                                         } else {
525                                                 rl.reset (new RouteList);
526                                                 rl->push_back (_route);
527                                         }
528
529                                         DisplaySuspender ds;
530                                         if (Config->get_solo_control_is_listen_control()) {
531                                                 _session->set_listen (rl, !_route->listening_via_monitor(),  Session::rt_cleanup, true);
532                                         } else {
533                                                 _session->set_solo (rl, !_route->self_soloed(),  Session::rt_cleanup, true);
534                                         }
535                                 }
536
537                         } else {
538
539                                 /* click: solo this route */
540
541                                 boost::shared_ptr<RouteList> rl (new RouteList);
542                                 rl->push_back (route());
543
544                                 if (_solo_release) {
545                                         _solo_release->routes = rl;
546                                 }
547
548                                 DisplaySuspender ds;
549                                 if (Config->get_solo_control_is_listen_control()) {
550                                         _session->set_listen (rl, !_route->listening_via_monitor());
551                                 } else {
552                                         _session->set_solo (rl, !_route->self_soloed());
553                                 }
554                         }
555                 }
556         }
557
558         return true;
559 }
560
561 bool
562 RouteUI::solo_release (GdkEventButton*)
563 {
564         if (_solo_release) {
565
566                 if (_solo_release->exclusive) {
567
568                 } else {
569                         DisplaySuspender ds;
570                         if (Config->get_solo_control_is_listen_control()) {
571                                 _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
572                         } else {
573                                 _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
574                         }
575                 }
576
577                 delete _solo_release;
578                 _solo_release = 0;
579         }
580
581         return true;
582 }
583
584 bool
585 RouteUI::rec_enable_press(GdkEventButton* ev)
586 {
587         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
588                 return true;
589         }
590
591         if (!_session->engine().connected()) {
592                 MessageDialog msg (_("Not connected to AudioEngine - cannot engage record"));
593                 msg.run ();
594                 return true;
595         }
596
597         if (is_midi_track()) {
598
599                 /* rec-enable button exits from step editing */
600
601                 if (midi_track()->step_editing()) {
602                         midi_track()->set_step_editing (false);
603                         return true;
604                 }
605         }
606
607         if (is_track() && rec_enable_button) {
608
609                 if (Keyboard::is_button2_event (ev)) {
610
611                         // do nothing on midi sigc::bind event
612                         return rec_enable_button->on_button_press_event (ev);
613
614                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
615
616                         DisplaySuspender ds;
617                         _session->set_record_enabled (_session->get_routes(), !rec_enable_button->active_state());
618
619                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
620
621                         /* Primary-button1 applies change to the route group (even if it is not active)
622                            NOTE: Primary-button2 is MIDI learn.
623                         */
624
625                         if (ev->button == 1) {
626
627                                 boost::shared_ptr<RouteList> rl;
628                                 
629                                 if (_route->route_group()) {
630                                         
631                                         rl = _route->route_group()->route_list();
632                                         
633                                 } else {
634                                         rl.reset (new RouteList);
635                                         rl->push_back (_route);
636                                 }
637
638                                 DisplaySuspender ds;
639                                 _session->set_record_enabled (rl, !rec_enable_button->active_state(), Session::rt_cleanup, true);
640                         }
641
642                 } else if (Keyboard::is_context_menu_event (ev)) {
643
644                         /* do this on release */
645
646                 } else {
647
648                         boost::shared_ptr<RouteList> rl (new RouteList);
649                         rl->push_back (route());
650                         DisplaySuspender ds;
651                         _session->set_record_enabled (rl, !rec_enable_button->active_state());
652                 }
653         }
654
655         return true;
656 }
657
658 void
659 RouteUI::monitoring_changed ()
660 {
661         update_monitoring_display ();
662 }
663
664 void
665 RouteUI::update_monitoring_display ()
666 {
667         if (!_route) {
668                 return;
669         }
670
671         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
672
673         if (!t) {
674                 return;
675         }
676
677         MonitorState ms = t->monitoring_state();
678
679         if (t->monitoring_choice() & MonitorInput) {
680                 monitor_input_button->set_active_state (Gtkmm2ext::ExplicitActive);
681         } else {
682                 if (ms & MonitoringInput) {
683                         monitor_input_button->set_active_state (Gtkmm2ext::ImplicitActive);
684                 } else {
685                         monitor_input_button->unset_active_state ();
686                 }
687         }
688
689         if (t->monitoring_choice() & MonitorDisk) {
690                 monitor_disk_button->set_active_state (Gtkmm2ext::ExplicitActive);
691         } else {
692                 if (ms & MonitoringDisk) {
693                         monitor_disk_button->set_active_state (Gtkmm2ext::ImplicitActive);
694                 } else {
695                         monitor_disk_button->unset_active_state ();
696                 }
697         }
698 }
699
700 bool
701 RouteUI::monitor_input_press(GdkEventButton*)
702 {
703         return true;
704 }
705
706 bool
707 RouteUI::monitor_input_release(GdkEventButton* ev)
708 {
709         return monitor_release (ev, MonitorInput);
710 }
711
712 bool
713 RouteUI::monitor_disk_press (GdkEventButton*)
714 {
715         return true;
716 }
717
718 bool
719 RouteUI::monitor_disk_release (GdkEventButton* ev)
720 {
721         return monitor_release (ev, MonitorDisk);
722 }
723
724 bool
725 RouteUI::monitor_release (GdkEventButton* ev, MonitorChoice monitor_choice)
726 {       
727         if (ev->button != 1) {
728                 return false;
729         }
730
731         boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
732
733         if (!t) {
734                 return true;
735         }
736
737         MonitorChoice mc;
738         boost::shared_ptr<RouteList> rl;
739         
740         /* XXX for now, monitoring choices are orthogonal. cue monitoring 
741            will follow in 3.X but requires mixing the input and playback (disk)
742            signal together, which requires yet more buffers.
743         */
744
745         if (t->monitoring_choice() & monitor_choice) {
746                 mc = MonitorChoice (t->monitoring_choice() & ~monitor_choice);
747         } else {
748                 /* this line will change when the options are non-orthogonal */
749                 // mc = MonitorChoice (t->monitoring_choice() | monitor_choice);
750                 mc = monitor_choice;
751         }
752
753         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {       
754                 rl = _session->get_routes ();
755
756         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
757                 if (_route->route_group() && _route->route_group()->is_monitoring()) {
758                         rl = _route->route_group()->route_list();
759                 } else {
760                         rl.reset (new RouteList);
761                         rl->push_back (route());
762                 }
763         } else {
764                 rl.reset (new RouteList);
765                 rl->push_back (route());
766         }
767
768         DisplaySuspender ds;
769         _session->set_monitoring (rl, mc, Session::rt_cleanup, true);           
770
771         return true;
772 }
773
774 void
775 RouteUI::build_record_menu ()
776 {
777         if (record_menu) {
778                 return;
779         }
780
781         /* no rec-button context menu for non-MIDI tracks
782          */
783
784         if (is_midi_track()) {
785                 record_menu = new Menu;
786                 record_menu->set_name ("ArdourContextMenu");
787
788                 using namespace Menu_Helpers;
789                 MenuList& items = record_menu->items();
790
791                 items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
792                 step_edit_item = dynamic_cast<Gtk::CheckMenuItem*> (&items.back());
793
794                 if (_route->record_enabled()) {
795                         step_edit_item->set_sensitive (false);
796                 }
797
798                 step_edit_item->set_active (midi_track()->step_editing());
799         }
800 }
801
802 void
803 RouteUI::toggle_step_edit ()
804 {
805         if (!is_midi_track() || _route->record_enabled()) {
806                 return;
807         }
808
809         midi_track()->set_step_editing (step_edit_item->get_active());
810 }
811
812 void
813 RouteUI::step_edit_changed (bool yn)
814 {
815         if (yn) {
816                 if (rec_enable_button) {
817                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
818                 }
819
820                 start_step_editing ();
821
822                 if (step_edit_item) {
823                         step_edit_item->set_active (true);
824                 }
825
826         } else {
827
828                 if (rec_enable_button) {
829                         rec_enable_button->unset_active_state ();
830                 }
831
832                 stop_step_editing ();
833
834                 if (step_edit_item) {
835                         step_edit_item->set_active (false);
836                 }
837         }
838 }
839
840 bool
841 RouteUI::rec_enable_release (GdkEventButton* ev)
842 {
843         if (Keyboard::is_context_menu_event (ev)) {
844                 build_record_menu ();
845                 if (record_menu) {
846                         record_menu->popup (1, ev->time);
847                 }
848                 return true;
849         }
850
851         return true;
852 }
853
854 void
855 RouteUI::build_sends_menu ()
856 {
857         using namespace Menu_Helpers;
858
859         sends_menu = new Menu;
860         sends_menu->set_name ("ArdourContextMenu");
861         MenuList& items = sends_menu->items();
862
863         items.push_back (
864                 MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
865                 );
866
867         items.push_back (
868                 MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
869                 );
870
871         items.push_back (
872                 MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
873                 );
874
875         items.push_back (
876                 MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
877                 );
878
879         items.push_back (
880                 MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, false))
881                 );
882
883         items.push_back (
884                 MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
885
886         items.push_back (
887                 MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
888                 );
889
890         items.push_back (
891                 MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
892                 );
893
894         items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
895         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
896         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
897
898 }
899
900 void
901 RouteUI::create_sends (Placement p, bool include_buses)
902 {
903         _session->globally_add_internal_sends (_route, p, include_buses);
904 }
905
906 void
907 RouteUI::create_selected_sends (Placement p, bool include_buses)
908 {
909         boost::shared_ptr<RouteList> rlist (new RouteList);
910         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
911
912         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
913                 RouteTimeAxisView* rtv;
914                 RouteUI* rui;
915                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
916                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
917                                 if (include_buses || boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
918                                         rlist->push_back (rui->route());
919                                 }
920                         }
921                 }
922         }
923
924         _session->add_internal_sends (_route, p, rlist);
925 }
926
927 void
928 RouteUI::set_sends_gain_from_track ()
929 {
930         _session->globally_set_send_gains_from_track (_route);
931 }
932
933 void
934 RouteUI::set_sends_gain_to_zero ()
935 {
936         _session->globally_set_send_gains_to_zero (_route);
937 }
938
939 void
940 RouteUI::set_sends_gain_to_unity ()
941 {
942         _session->globally_set_send_gains_to_unity (_route);
943 }
944
945 bool
946 RouteUI::show_sends_press(GdkEventButton* ev)
947 {
948         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
949                 return true;
950         }
951
952         if (!is_track() && show_sends_button) {
953
954                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
955
956                         // do nothing on midi sigc::bind event
957                         return false;
958
959                 } else if (Keyboard::is_context_menu_event (ev)) {
960
961                         if (sends_menu == 0) {
962                                 build_sends_menu ();
963                         }
964
965                         sends_menu->popup (0, ev->time);
966
967                 } else {
968
969                         boost::shared_ptr<Route> s = _showing_sends_to.lock ();
970
971                         if (s == _route) {
972                                 set_showing_sends_to (boost::shared_ptr<Route> ());
973                         } else {
974                                 set_showing_sends_to (_route);
975                         }
976                 }
977         }
978
979         return true;
980 }
981
982 bool
983 RouteUI::show_sends_release (GdkEventButton*)
984 {
985         return true;
986 }
987
988 void
989 RouteUI::send_blink (bool onoff)
990 {
991         if (!show_sends_button) {
992                 return;
993         }
994
995         if (onoff) {
996                 show_sends_button->set_active_state (Gtkmm2ext::ExplicitActive);
997         } else {
998                 show_sends_button->unset_active_state ();
999         }
1000 }
1001
1002 Gtkmm2ext::ActiveState
1003 RouteUI::solo_active_state (boost::shared_ptr<Route> r)
1004 {
1005         if (r->is_master() || r->is_monitor()) {
1006                 return Gtkmm2ext::Off;
1007         }
1008
1009         if (Config->get_solo_control_is_listen_control()) {
1010
1011                 if (r->listening_via_monitor()) {
1012                         return Gtkmm2ext::ExplicitActive;
1013                 } else {
1014                         return Gtkmm2ext::Off;
1015                 }
1016
1017         }
1018
1019         if (r->soloed()) {
1020                 if (!r->self_soloed()) {
1021                         return Gtkmm2ext::ImplicitActive;
1022                 } else {
1023                         return Gtkmm2ext::ExplicitActive;
1024                 }
1025         } else {
1026                 return Gtkmm2ext::Off;
1027         }
1028 }
1029
1030 Gtkmm2ext::ActiveState
1031 RouteUI::solo_isolate_active_state (boost::shared_ptr<Route> r)
1032 {
1033         if (r->is_master() || r->is_monitor()) {
1034                 return Gtkmm2ext::Off;
1035         }
1036
1037         if (r->solo_isolated()) {
1038                 return Gtkmm2ext::ExplicitActive;
1039         } else {
1040                 return Gtkmm2ext::Off;
1041         }
1042 }
1043
1044 Gtkmm2ext::ActiveState
1045 RouteUI::solo_safe_active_state (boost::shared_ptr<Route> r)
1046 {
1047         if (r->is_master() || r->is_monitor()) {
1048                 return Gtkmm2ext::Off;
1049         }
1050
1051         if (r->solo_safe()) {
1052                 return Gtkmm2ext::ExplicitActive;
1053         } else {
1054                 return Gtkmm2ext::Off;
1055         }
1056 }
1057
1058 void
1059 RouteUI::update_solo_display ()
1060 {
1061         bool yn = _route->solo_safe ();
1062
1063         if (solo_safe_check && solo_safe_check->get_active() != yn) {
1064                 solo_safe_check->set_active (yn);
1065         }
1066
1067         yn = _route->solo_isolated ();
1068
1069         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
1070                 solo_isolated_check->set_active (yn);
1071         }
1072
1073         set_button_names ();
1074
1075         if (solo_isolated_led) {
1076                 if (_route->solo_isolated()) {
1077                         solo_isolated_led->set_active_state (Gtkmm2ext::ExplicitActive);
1078                 } else {
1079                         solo_isolated_led->unset_active_state ();
1080                 }
1081         }
1082
1083         if (solo_safe_led) {
1084                 if (_route->solo_safe()) {
1085                         solo_safe_led->set_active_state (Gtkmm2ext::ExplicitActive);
1086                 } else {
1087                         solo_safe_led->unset_active_state ();
1088                 }
1089         }
1090
1091         solo_button->set_active_state (solo_active_state (_route));
1092
1093         /* some changes to solo status can affect mute display, so catch up
1094          */
1095
1096         update_mute_display ();
1097 }
1098
1099 void
1100 RouteUI::solo_changed_so_update_mute ()
1101 {
1102         update_mute_display ();
1103 }
1104
1105 void
1106 RouteUI::mute_changed(void* /*src*/)
1107 {
1108         update_mute_display ();
1109 }
1110
1111 ActiveState
1112 RouteUI::mute_active_state (Session* s, boost::shared_ptr<Route> r)
1113 {
1114         if (r->is_monitor()) {
1115                 return ActiveState(0);
1116         }
1117
1118
1119         if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
1120
1121                 if (r->muted ()) {
1122                         /* full mute */
1123                         return Gtkmm2ext::ExplicitActive;
1124                 } else if (!r->is_master() && s->soloing() && !r->soloed() && !r->solo_isolated()) {
1125                         /* master is NEVER muted by others */
1126                         return Gtkmm2ext::ImplicitActive;
1127                 } else {
1128                         /* no mute at all */
1129                         return Gtkmm2ext::Off;
1130                 }
1131
1132         } else {
1133
1134                 if (r->muted()) {
1135                         /* full mute */
1136                         return Gtkmm2ext::ExplicitActive;
1137                 } else {
1138                         /* no mute at all */
1139                         return Gtkmm2ext::Off;
1140                 }
1141         }
1142
1143         return ActiveState(0);
1144 }
1145
1146 void
1147 RouteUI::update_mute_display ()
1148 {
1149         if (!_route) {
1150                 return;
1151         }
1152
1153         mute_button->set_active_state (mute_active_state (_session, _route));
1154 }
1155
1156 void
1157 RouteUI::route_rec_enable_changed ()
1158 {
1159         update_rec_display ();
1160         update_monitoring_display ();
1161 }
1162
1163 void
1164 RouteUI::session_rec_enable_changed ()
1165 {
1166         update_rec_display ();
1167         update_monitoring_display ();
1168 }
1169
1170 void
1171 RouteUI::update_rec_display ()
1172 {
1173         if (!rec_enable_button || !_route) {
1174                 return;
1175         }
1176
1177         if (_route->record_enabled()) {
1178                 switch (_session->record_status ()) {
1179                 case Session::Recording:
1180                         rec_enable_button->set_active_state (Gtkmm2ext::ExplicitActive);
1181                         break;
1182
1183                 case Session::Disabled:
1184                 case Session::Enabled:
1185                         rec_enable_button->set_active_state (Gtkmm2ext::ImplicitActive);
1186                         break;
1187
1188                 }
1189
1190                 if (step_edit_item) {
1191                         step_edit_item->set_sensitive (false);
1192                 }
1193
1194         } else {
1195                 rec_enable_button->unset_active_state ();
1196
1197                 if (step_edit_item) {
1198                         step_edit_item->set_sensitive (true);
1199                 }
1200         }
1201
1202
1203         check_rec_enable_sensitivity ();
1204 }
1205
1206 void
1207 RouteUI::build_solo_menu (void)
1208 {
1209         using namespace Menu_Helpers;
1210
1211         solo_menu = new Menu;
1212         solo_menu->set_name ("ArdourContextMenu");
1213         MenuList& items = solo_menu->items();
1214         Gtk::CheckMenuItem* check;
1215
1216         check = new Gtk::CheckMenuItem(_("Solo Isolate"));
1217         check->set_active (_route->solo_isolated());
1218         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
1219         items.push_back (CheckMenuElem(*check));
1220         solo_isolated_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1221         check->show_all();
1222
1223         check = new Gtk::CheckMenuItem(_("Solo Safe"));
1224         check->set_active (_route->solo_safe());
1225         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
1226         items.push_back (CheckMenuElem(*check));
1227         solo_safe_check = dynamic_cast<Gtk::CheckMenuItem*>(&items.back());
1228         check->show_all();
1229
1230         //items.push_back (SeparatorElem());
1231         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1232
1233 }
1234
1235 void
1236 RouteUI::build_mute_menu(void)
1237 {
1238         using namespace Menu_Helpers;
1239
1240         mute_menu = new Menu;
1241         mute_menu->set_name ("ArdourContextMenu");
1242
1243         MenuList& items = mute_menu->items();
1244
1245         pre_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Pre Fader Sends")));
1246         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
1247         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
1248         items.push_back (CheckMenuElem(*pre_fader_mute_check));
1249         pre_fader_mute_check->show_all();
1250
1251         post_fader_mute_check = manage (new Gtk::CheckMenuItem(_("Post Fader Sends")));
1252         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
1253         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
1254         items.push_back (CheckMenuElem(*post_fader_mute_check));
1255         post_fader_mute_check->show_all();
1256
1257         listen_mute_check = manage (new Gtk::CheckMenuItem(_("Control Outs")));
1258         init_mute_menu(MuteMaster::Listen, listen_mute_check);
1259         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
1260         items.push_back (CheckMenuElem(*listen_mute_check));
1261         listen_mute_check->show_all();
1262
1263         main_mute_check = manage (new Gtk::CheckMenuItem(_("Main Outs")));
1264         init_mute_menu(MuteMaster::Main, main_mute_check);
1265         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1266         items.push_back (CheckMenuElem(*main_mute_check));
1267         main_mute_check->show_all();
1268
1269         //items.push_back (SeparatorElem());
1270         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1271
1272         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1273 }
1274
1275 void
1276 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1277 {
1278         check->set_active (_route->mute_points() & mp);
1279 }
1280
1281 void
1282 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1283 {
1284         if (check->get_active()) {
1285                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1286         } else {
1287                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1288         }
1289 }
1290
1291 void
1292 RouteUI::muting_change ()
1293 {
1294         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1295
1296         bool yn;
1297         MuteMaster::MutePoint current = _route->mute_points ();
1298
1299         yn = (current & MuteMaster::PreFader);
1300
1301         if (pre_fader_mute_check->get_active() != yn) {
1302                 pre_fader_mute_check->set_active (yn);
1303         }
1304
1305         yn = (current & MuteMaster::PostFader);
1306
1307         if (post_fader_mute_check->get_active() != yn) {
1308                 post_fader_mute_check->set_active (yn);
1309         }
1310
1311         yn = (current & MuteMaster::Listen);
1312
1313         if (listen_mute_check->get_active() != yn) {
1314                 listen_mute_check->set_active (yn);
1315         }
1316
1317         yn = (current & MuteMaster::Main);
1318
1319         if (main_mute_check->get_active() != yn) {
1320                 main_mute_check->set_active (yn);
1321         }
1322 }
1323
1324 bool
1325 RouteUI::solo_isolate_button_release (GdkEventButton* ev)
1326 {
1327         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS) {
1328                 return true;
1329         }
1330
1331         bool view = solo_isolated_led->active_state();
1332         bool model = _route->solo_isolated();
1333
1334         /* called BEFORE the view has changed */
1335
1336         if (ev->button == 1) {
1337                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
1338
1339                         if (model) {
1340                                 /* disable isolate for all routes */
1341                                 DisplaySuspender ds;
1342                                 _session->set_solo_isolated (_session->get_routes(), false, Session::rt_cleanup, true);
1343                         }
1344
1345                 } else {
1346                         if (model == view) {
1347
1348                                 /* flip just this route */
1349
1350                                 boost::shared_ptr<RouteList> rl (new RouteList);
1351                                 rl->push_back (_route);
1352                                 DisplaySuspender ds;
1353                                 _session->set_solo_isolated (rl, !view, Session::rt_cleanup, true);
1354                         }
1355                 }
1356         }
1357
1358         return true;
1359 }
1360
1361 bool
1362 RouteUI::solo_safe_button_release (GdkEventButton* ev)
1363 {
1364         if (ev->button == 1) {
1365                 _route->set_solo_safe (!solo_safe_led->active_state(), this);
1366                 return true;
1367         }
1368         return false;
1369 }
1370
1371 void
1372 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1373 {
1374         bool view = check->get_active();
1375         bool model = _route->solo_isolated();
1376
1377         /* called AFTER the view has changed */
1378
1379         if (model != view) {
1380                 _route->set_solo_isolated (view, this);
1381         }
1382 }
1383
1384 void
1385 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1386 {
1387         _route->set_solo_safe (check->get_active(), this);
1388 }
1389
1390 /** Ask the user to choose a colour, and then apply that color to my route
1391  */
1392 void
1393 RouteUI::choose_color ()
1394 {
1395         bool picked;
1396         Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
1397
1398         if (picked) {
1399                 set_color(color);
1400         }
1401 }
1402
1403 /** Set the route's own color.  This may not be used for display if
1404  *  the route is in a group which shares its color with its routes.
1405  */
1406 void
1407 RouteUI::set_color (const Gdk::Color & c)
1408 {
1409         /* leave _color alone in the group case so that tracks can retain their
1410          * own pre-group colors.
1411          */
1412
1413         char buf[64];
1414         _color = c;
1415         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1416         
1417         /* note: we use the route state ID here so that color is the same for both
1418            the time axis view and the mixer strip
1419         */
1420         
1421         gui_object_state().set_property<string> (route_state_id(), X_("color"), buf);
1422         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1423 }
1424
1425 /** @return GUI state ID for things that are common to the route in all its representations */
1426 string
1427 RouteUI::route_state_id () const
1428 {
1429         return string_compose (X_("route %1"), _route->id().to_s());
1430 }
1431
1432 int
1433 RouteUI::set_color_from_route ()
1434 {
1435         const string str = gui_object_state().get_string (route_state_id(), X_("color"));
1436
1437         if (str.empty()) {
1438                 return 1;
1439         }
1440
1441         int r, g, b;
1442
1443         sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
1444
1445         _color.set_red (r);
1446         _color.set_green (g);
1447         _color.set_blue (b);
1448
1449         return 0;
1450 }
1451
1452 void
1453 RouteUI::remove_this_route (bool apply_to_selection)
1454 {
1455         if (apply_to_selection) {
1456                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
1457         } else {
1458                 if ((route()->is_master() || route()->is_monitor()) &&
1459                     !Config->get_allow_special_bus_removal()) {
1460                         MessageDialog msg (_("That would be bad news ...."),
1461                                            false,
1462                                            Gtk::MESSAGE_INFO,
1463                                    Gtk::BUTTONS_OK);
1464                         msg.set_secondary_text (string_compose (_(
1465 "Removing the master or monitor bus is such a bad idea\n\
1466 that %1 is not going to allow it.\n\
1467 \n\
1468 If you really want to do this sort of thing\n\
1469 edit your ardour.rc file to set the\n\
1470 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
1471
1472                         msg.present ();
1473                         msg.run ();
1474                         return;
1475                 }
1476
1477                 vector<string> choices;
1478                 string prompt;
1479
1480                 if (is_track()) {
1481                         prompt  = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1482                 } else {
1483                         prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
1484                 }
1485
1486                 choices.push_back (_("No, do nothing."));
1487                 choices.push_back (_("Yes, remove it."));
1488
1489                 string title;
1490                 if (is_track()) {
1491                         title = _("Remove track");
1492                 } else {
1493                         title = _("Remove bus");
1494                 }
1495
1496                 Choice prompter (title, prompt, choices);
1497
1498                 if (prompter.run () == 1) {
1499                         Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1500                 }
1501         }
1502 }
1503
1504 gint
1505 RouteUI::idle_remove_this_route (RouteUI *rui)
1506 {
1507         rui->_session->remove_route (rui->route());
1508         return false;
1509 }
1510
1511 /** @return true if this name should be used for the route, otherwise false */
1512 bool
1513 RouteUI::verify_new_route_name (const std::string& name)
1514 {
1515         if (name.find (':') == string::npos) {
1516                 return true;
1517         }
1518         
1519         MessageDialog colon_msg (
1520                 _("The use of colons (':') is discouraged in track and bus names.\nDo you want to use this new name?"),
1521                 false, MESSAGE_QUESTION, BUTTONS_NONE
1522                 );
1523         
1524         colon_msg.add_button (_("Use the new name"), Gtk::RESPONSE_ACCEPT);
1525         colon_msg.add_button (_("Re-edit the name"), Gtk::RESPONSE_CANCEL);
1526
1527         return (colon_msg.run () == Gtk::RESPONSE_ACCEPT);
1528 }
1529
1530 void
1531 RouteUI::route_rename ()
1532 {
1533         ArdourPrompter name_prompter (true);
1534         string result;
1535         bool done = false;
1536
1537         if (is_track()) {
1538                 name_prompter.set_title (_("Rename Track"));
1539         } else {
1540                 name_prompter.set_title (_("Rename Bus"));
1541         }
1542         name_prompter.set_prompt (_("New name:"));
1543         name_prompter.set_initial_text (_route->name());
1544         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1545         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1546         name_prompter.show_all ();
1547
1548         while (!done) {
1549                 switch (name_prompter.run ()) {
1550                 case Gtk::RESPONSE_ACCEPT:
1551                         name_prompter.get_result (result);
1552                         name_prompter.hide ();
1553                         if (result.length()) {
1554                                 if (verify_new_route_name (result)) {
1555                                         _route->set_name (result);
1556                                         done = true;
1557                                 } else {
1558                                         /* back to name prompter */
1559                                 }
1560
1561                         } else {
1562                                 /* nothing entered, just get out of here */
1563                                 done = true;
1564                         }
1565                         break;
1566                 default:
1567                         done = true;
1568                         break;
1569                 }
1570         }
1571
1572         return;
1573
1574 }
1575
1576 void
1577 RouteUI::property_changed (const PropertyChange& what_changed)
1578 {
1579         if (what_changed.contains (ARDOUR::Properties::name)) {
1580                 name_label.set_text (_route->name());
1581         }
1582 }
1583
1584 void
1585 RouteUI::toggle_comment_editor ()
1586 {
1587 //      if (ignore_toggle) {
1588 //              return;
1589 //      }
1590
1591         if (comment_window && comment_window->is_visible ()) {
1592                 comment_window->hide ();
1593         } else {
1594                 open_comment_editor ();
1595         }
1596 }
1597
1598
1599 void
1600 RouteUI::open_comment_editor ()
1601 {
1602         if (comment_window == 0) {
1603                 setup_comment_editor ();
1604         }
1605
1606         string title;
1607         title = _route->name();
1608         title += _(": comment editor");
1609
1610         comment_window->set_title (title);
1611         comment_window->present();
1612 }
1613
1614 void
1615 RouteUI::setup_comment_editor ()
1616 {
1617         comment_window = new ArdourWindow (""); // title will be reset to show route
1618         comment_window->set_skip_taskbar_hint (true);
1619         comment_window->signal_hide().connect (sigc::mem_fun(*this, &MixerStrip::comment_editor_done_editing));
1620         comment_window->set_default_size (400, 200);
1621
1622         comment_area = manage (new TextView());
1623         comment_area->set_name ("MixerTrackCommentArea");
1624         comment_area->set_wrap_mode (WRAP_WORD);
1625         comment_area->set_editable (true);
1626         comment_area->get_buffer()->set_text (_route->comment());
1627         comment_area->show ();
1628
1629         comment_window->add (*comment_area);
1630 }
1631
1632 void
1633 RouteUI::comment_changed (void *src)
1634 {
1635         ENSURE_GUI_THREAD (*this, &MixerStrip::comment_changed, src)
1636
1637         if (src != this) {
1638                 ignore_comment_edit = true;
1639                 if (comment_area) {
1640                         comment_area->get_buffer()->set_text (_route->comment());
1641                 }
1642                 ignore_comment_edit = false;
1643         }
1644 }
1645
1646 void
1647 RouteUI::comment_editor_done_editing ()
1648 {
1649         string const str = comment_area->get_buffer()->get_text();
1650         if (str == _route->comment ()) {
1651                 return;
1652         }
1653
1654         _route->set_comment (str, this);
1655 }
1656
1657 void
1658 RouteUI::set_route_active (bool a, bool apply_to_selection)
1659 {
1660         if (apply_to_selection) {
1661                 ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
1662         } else {
1663                 _route->set_active (a, this);
1664         }
1665 }
1666
1667 void
1668 RouteUI::toggle_denormal_protection ()
1669 {
1670         if (denormal_menu_item) {
1671
1672                 bool x;
1673
1674                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1675
1676                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1677                         _route->set_denormal_protection (x);
1678                 }
1679         }
1680 }
1681
1682 void
1683 RouteUI::denormal_protection_changed ()
1684 {
1685         if (denormal_menu_item) {
1686                 denormal_menu_item->set_active (_route->denormal_protection());
1687         }
1688 }
1689
1690 void
1691 RouteUI::disconnect_input ()
1692 {
1693         _route->input()->disconnect (this);
1694 }
1695
1696 void
1697 RouteUI::disconnect_output ()
1698 {
1699         _route->output()->disconnect (this);
1700 }
1701
1702 bool
1703 RouteUI::is_track () const
1704 {
1705         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1706 }
1707
1708 boost::shared_ptr<Track>
1709 RouteUI::track() const
1710 {
1711         return boost::dynamic_pointer_cast<Track>(_route);
1712 }
1713
1714 bool
1715 RouteUI::is_audio_track () const
1716 {
1717         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1718 }
1719
1720 boost::shared_ptr<AudioTrack>
1721 RouteUI::audio_track() const
1722 {
1723         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1724 }
1725
1726 bool
1727 RouteUI::is_midi_track () const
1728 {
1729         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1730 }
1731
1732 boost::shared_ptr<MidiTrack>
1733 RouteUI::midi_track() const
1734 {
1735         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1736 }
1737
1738 bool
1739 RouteUI::has_audio_outputs () const
1740 {
1741         return (_route->n_outputs().n_audio() > 0);
1742 }
1743
1744 string
1745 RouteUI::name() const
1746 {
1747         return _route->name();
1748 }
1749
1750 void
1751 RouteUI::map_frozen ()
1752 {
1753         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1754
1755         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1756
1757         if (at) {
1758                 switch (at->freeze_state()) {
1759                 case AudioTrack::Frozen:
1760                         rec_enable_button->set_sensitive (false);
1761                         break;
1762                 default:
1763                         rec_enable_button->set_sensitive (true);
1764                         break;
1765                 }
1766         }
1767 }
1768
1769 void
1770 RouteUI::adjust_latency ()
1771 {
1772         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), AudioEngine::instance()->samples_per_cycle());
1773 }
1774
1775 void
1776 RouteUI::save_as_template ()
1777 {
1778         std::string path;
1779         std::string safe_name;
1780         string name;
1781
1782         path = ARDOUR::user_route_template_directory ();
1783
1784         if (g_mkdir_with_parents (path.c_str(), 0755)) {
1785                 error << string_compose (_("Cannot create route template directory %1"), path) << endmsg;
1786                 return;
1787         }
1788
1789         Prompter p (true); // modal
1790
1791         p.set_title (_("Save As Template"));
1792         p.set_prompt (_("Template name:"));
1793         p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
1794         switch (p.run()) {
1795         case RESPONSE_ACCEPT:
1796                 break;
1797         default:
1798                 return;
1799         }
1800
1801         p.hide ();
1802         p.get_result (name, true);
1803
1804         safe_name = legalize_for_path (name);
1805         safe_name += template_suffix;
1806
1807         path = Glib::build_filename (path, safe_name);
1808
1809         _route->save_as_template (path, name);
1810 }
1811
1812 void
1813 RouteUI::check_rec_enable_sensitivity ()
1814 {
1815         if (_session->transport_rolling() && rec_enable_button->active_state() && Config->get_disable_disarm_during_roll()) {
1816                 rec_enable_button->set_sensitive (false);
1817         } else {
1818                 rec_enable_button->set_sensitive (true);
1819         }
1820
1821         update_monitoring_display ();
1822 }
1823
1824 void
1825 RouteUI::parameter_changed (string const & p)
1826 {
1827         /* this handles RC and per-session parameter changes */
1828
1829         if (p == "disable-disarm-during-roll") {
1830                 check_rec_enable_sensitivity ();
1831         } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
1832                 set_button_names ();
1833         } else if (p == "auto-input") {
1834                 update_monitoring_display ();
1835         }
1836 }
1837
1838 void
1839 RouteUI::step_gain_up ()
1840 {
1841         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1842 }
1843
1844 void
1845 RouteUI::page_gain_up ()
1846 {
1847         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1848 }
1849
1850 void
1851 RouteUI::step_gain_down ()
1852 {
1853         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1854 }
1855
1856 void
1857 RouteUI::page_gain_down ()
1858 {
1859         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1860 }
1861
1862 void
1863 RouteUI::open_remote_control_id_dialog ()
1864 {
1865         ArdourDialog dialog (_("Remote Control ID"));
1866         SpinButton* spin = 0;
1867
1868         dialog.get_vbox()->set_border_width (18);
1869
1870         if (Config->get_remote_model() == UserOrdered) {
1871                 uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1872                 
1873                 HBox* hbox = manage (new HBox);
1874                 hbox->set_spacing (6);
1875                 hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1876                 spin = manage (new SpinButton);
1877                 spin->set_digits (0);
1878                 spin->set_increments (1, 10);
1879                 spin->set_range (0, limit);
1880                 spin->set_value (_route->remote_control_id());
1881                 hbox->pack_start (*spin);
1882                 dialog.get_vbox()->pack_start (*hbox);
1883                 
1884                 dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1885                 dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1886         } else {
1887                 Label* l = manage (new Label());
1888                 if (_route->is_master() || _route->is_monitor()) {
1889                         l->set_markup (string_compose (_("The remote control ID of %1 is: %2\n\n\n"
1890                                                          "The remote control ID of %3 cannot be changed."),
1891                                                        Glib::Markup::escape_text (_route->name()),
1892                                                        _route->remote_control_id(),
1893                                                        (_route->is_master() ? _("the master bus") : _("the monitor bus"))));
1894                 } else {
1895                         l->set_markup (string_compose (_("The remote control ID of %5 is: %2\n\n\n"
1896                                                          "Remote Control IDs are currently determined by track/bus ordering in %6.\n\n"
1897                                                          "%3Use the User Interaction tab of the Preferences window if you want to change this%4"),
1898                                                        (is_track() ? _("track") : _("bus")),
1899                                                        _route->remote_control_id(),
1900                                                        "<span size=\"small\" style=\"italic\">",
1901                                                        "</span>",
1902                                                        Glib::Markup::escape_text (_route->name()),
1903                                                        PROGRAM_NAME));
1904                 }
1905                 dialog.get_vbox()->pack_start (*l);
1906                 dialog.add_button (Stock::OK, RESPONSE_CANCEL);
1907         }
1908
1909         dialog.show_all ();
1910         int const r = dialog.run ();
1911
1912         if (r == RESPONSE_ACCEPT && spin) {
1913                 _route->set_remote_control_id (spin->get_value_as_int ());
1914         }
1915 }
1916
1917 void
1918 RouteUI::setup_invert_buttons ()
1919 {
1920         /* remove old invert buttons */
1921         for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i) {
1922                 _invert_button_box.remove (**i);
1923         }
1924
1925         _invert_buttons.clear ();
1926
1927         if (!_route || !_route->input()) {
1928                 return;
1929         }
1930
1931         uint32_t const N = _route->input()->n_ports().n_audio ();
1932
1933         uint32_t const to_add = (N <= _max_invert_buttons) ? N : 1;
1934
1935         for (uint32_t i = 0; i < to_add; ++i) {
1936                 ArdourButton* b = manage (new ArdourButton);
1937                 b->set_size_request(20,20);
1938                 b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
1939                 b->signal_button_release_event().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_release), i));
1940
1941                 b->set_name (X_("invert button"));
1942                 if (to_add == 1) {
1943                         if (N > 1) {
1944                                 b->set_text (string_compose (X_("Ø (%1)"), N));
1945                         } else {
1946                                 b->set_text (X_("Ø"));
1947                         }
1948                 } else {
1949                         b->set_text (string_compose (X_("Ø%1"), i + 1));
1950                 }
1951
1952                 if (N <= _max_invert_buttons) {
1953                         UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) channel %1 of this track.  Right-click to show menu."), i + 1));
1954                 } else {
1955                         UI::instance()->set_tip (*b, _("Click to show a menu of channels for inversion (phase reverse)"));
1956                 }
1957
1958                 _invert_buttons.push_back (b);
1959                 _invert_button_box.pack_start (*b);
1960         }
1961
1962         _invert_button_box.set_spacing (1);
1963         _invert_button_box.show_all ();
1964 }
1965
1966 void
1967 RouteUI::set_invert_button_state ()
1968 {
1969         uint32_t const N = _route->input()->n_ports().n_audio();
1970         if (N > _max_invert_buttons) {
1971
1972                 /* One button for many channels; explicit active if all channels are inverted,
1973                    implicit active if some are, off if none are.
1974                 */
1975
1976                 ArdourButton* b = _invert_buttons.front ();
1977                 
1978                 if (_route->phase_invert().count() == _route->phase_invert().size()) {
1979                         b->set_active_state (Gtkmm2ext::ExplicitActive);
1980                 } else if (_route->phase_invert().any()) {
1981                         b->set_active_state (Gtkmm2ext::ImplicitActive);
1982                 } else {
1983                         b->set_active_state (Gtkmm2ext::Off);
1984                 }
1985
1986         } else {
1987
1988                 /* One button per channel; just set active */
1989
1990                 int j = 0;
1991                 for (vector<ArdourButton*>::iterator i = _invert_buttons.begin(); i != _invert_buttons.end(); ++i, ++j) {
1992                         (*i)->set_active (_route->phase_invert (j));
1993                 }
1994                 
1995         }
1996 }
1997
1998 bool
1999 RouteUI::invert_release (GdkEventButton* ev, uint32_t i)
2000 {
2001         if (ev->button == 1 && i < _invert_buttons.size()) {
2002                 uint32_t const N = _route->input()->n_ports().n_audio ();
2003                 if (N <= _max_invert_buttons) {
2004                         /* left-click inverts phase so long as we have a button per channel */
2005                         _route->set_phase_invert (i, !_invert_buttons[i]->get_active());
2006                         return true;
2007                 }
2008         }
2009         return false;
2010 }
2011
2012
2013 bool
2014 RouteUI::invert_press (GdkEventButton* ev)
2015 {
2016         using namespace Menu_Helpers;
2017
2018         uint32_t const N = _route->input()->n_ports().n_audio();
2019         if (N <= _max_invert_buttons && ev->button != 3) {
2020                 /* If we have an invert button per channel, we only pop
2021                    up a menu on right-click; left click is handled
2022                    on release.
2023                 */
2024                 return true;
2025         }
2026         
2027         delete _invert_menu;
2028         _invert_menu = new Menu;
2029         _invert_menu->set_name ("ArdourContextMenu");
2030         MenuList& items = _invert_menu->items ();
2031
2032         for (uint32_t i = 0; i < N; ++i) {
2033                 items.push_back (CheckMenuElem (string_compose (X_("Ø%1"), i + 1), sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_menu_toggled), i)));
2034                 Gtk::CheckMenuItem* e = dynamic_cast<Gtk::CheckMenuItem*> (&items.back ());
2035                 ++_i_am_the_modifier;
2036                 e->set_active (_route->phase_invert (i));
2037                 --_i_am_the_modifier;
2038         }
2039
2040         _invert_menu->popup (0, ev->time);
2041
2042         return false;
2043 }
2044
2045 void
2046 RouteUI::invert_menu_toggled (uint32_t c)
2047 {
2048         if (_i_am_the_modifier) {
2049                 return;
2050         }
2051
2052         _route->set_phase_invert (c, !_route->phase_invert (c));
2053 }
2054
2055 void
2056 RouteUI::set_invert_sensitive (bool yn)
2057 {
2058         for (vector<ArdourButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
2059                 (*b)->set_sensitive (yn);
2060         }
2061 }
2062
2063 void
2064 RouteUI::request_redraw ()
2065 {
2066         if (_route) {
2067                 _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
2068         }
2069 }
2070
2071 /** The Route's gui_changed signal has been emitted */
2072 void
2073 RouteUI::route_gui_changed (string what_changed)
2074 {
2075         if (what_changed == "color") {
2076                 if (set_color_from_route () == 0) {
2077                         route_color_changed ();
2078                 }
2079         }
2080 }
2081
2082 /** @return the color that this route should use; it maybe its own,
2083     or it maybe that of its route group.
2084 */
2085 Gdk::Color
2086 RouteUI::color () const
2087 {
2088         RouteGroup* g = _route->route_group ();
2089         
2090         if (g && g->is_color()) {
2091                 Gdk::Color c;
2092                 set_color_from_rgba (c, GroupTabs::group_color (g));
2093                 return c;
2094         }
2095
2096         return _color;
2097 }
2098
2099 void
2100 RouteUI::set_showing_sends_to (boost::shared_ptr<Route> send_to)
2101 {
2102         _showing_sends_to = send_to;
2103         BusSendDisplayChanged (send_to); /* EMIT SIGNAL */
2104 }
2105
2106 void
2107 RouteUI::bus_send_display_changed (boost::shared_ptr<Route> send_to)
2108 {
2109         if (_route == send_to) {
2110                 show_sends_button->set_active (true);
2111                 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun (*this, &RouteUI::send_blink));
2112         } else {
2113                 show_sends_button->set_active (false);
2114                 send_blink_connection.disconnect ();
2115         }
2116 }
2117
2118 RouteGroup*
2119 RouteUI::route_group() const
2120 {
2121         return _route->route_group();
2122 }