ae36ccba86c30179f7a6b34975a0e33832cd39e9
[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/stop_signal.h>
22 #include <gtkmm2ext/choice.h>
23 #include <gtkmm2ext/doi.h>
24 #include <gtkmm2ext/bindable_button.h>
25 #include <gtkmm2ext/barcontroller.h>
26 #include <gtkmm2ext/gtk_ui.h>
27
28 #include "ardour/route_group.h"
29 #include "ardour/dB.h"
30 #include "pbd/memento_command.h"
31 #include "pbd/stacktrace.h"
32 #include "pbd/controllable.h"
33 #include "pbd/enumwriter.h"
34
35 #include "ardour_ui.h"
36 #include "editor.h"
37 #include "route_ui.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
48 #include "ardour/route.h"
49 #include "ardour/event_type_map.h"
50 #include "ardour/session.h"
51 #include "ardour/audioengine.h"
52 #include "ardour/audio_track.h"
53 #include "ardour/midi_track.h"
54 #include "ardour/template_utils.h"
55 #include "ardour/filename_extensions.h"
56 #include "ardour/directory_names.h"
57 #include "ardour/profile.h"
58
59 #include "i18n.h"
60 using namespace Gtk;
61 using namespace Gtkmm2ext;
62 using namespace ARDOUR;
63 using namespace PBD;
64
65 RouteUI::RouteUI (ARDOUR::Session* sess)
66         : AxisView(sess)
67 {
68         init ();
69 }
70
71 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session* sess)
72         : AxisView(sess)
73 {
74         init ();
75         set_route (rt);
76 }
77
78 RouteUI::~RouteUI()
79 {
80         _route.reset (); /* drop reference to route, so that it can be cleaned up */
81         route_connections.drop_connections ();
82
83         delete solo_menu;
84         delete mute_menu;
85         delete sends_menu;
86 }
87
88 void
89 RouteUI::init ()
90 {
91         self_destruct = true;
92         xml_node = 0;
93         mute_menu = 0;
94         solo_menu = 0;
95         sends_menu = 0;
96         pre_fader_mute_check = 0;
97         post_fader_mute_check = 0;
98         listen_mute_check = 0;
99         main_mute_check = 0;
100         solo_safe_check = 0;
101         solo_isolated_check = 0;
102         ignore_toggle = false;
103         _solo_release = 0;
104         _mute_release = 0;
105         route_active_menu_item = 0;
106         denormal_menu_item = 0;
107         multiple_mute_change = false;
108         multiple_solo_change = false;
109
110         invert_button = manage (new BindableToggleButton ());
111         // mute_button->set_self_managed (true);
112         invert_button->set_name ("InvertButton");
113         invert_button->add (invert_button_label);
114         invert_button_label.show ();
115         UI::instance()->set_tip (invert_button, _("Invert (Phase reverse) this track"), "");
116
117         mute_button = manage (new BindableToggleButton ());
118         // mute_button->set_self_managed (true);
119         mute_button->set_name ("MuteButton");
120         mute_button->add (mute_button_label);
121         mute_button_label.show ();
122         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
123
124         solo_button = manage (new BindableToggleButton ());
125         // solo_button->set_self_managed (true);
126         solo_button->set_name ("SoloButton");
127         solo_button->add (solo_button_label);
128         solo_button_label.show ();
129         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
130         solo_button->set_no_show_all (true);
131
132         rec_enable_button = manage (new BindableToggleButton ());
133         rec_enable_button->set_name ("RecordEnableButton");
134         // rec_enable_button->set_self_managed (true);
135         rec_enable_button->add (rec_enable_button_label);
136         rec_enable_button_label.show ();
137         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
138
139         show_sends_button = manage (new BindableToggleButton (""));
140         show_sends_button->set_name ("SendAlert");
141         // show_sends_button->set_self_managed (true);
142         UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
143
144         _session->SoloChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::solo_changed_so_update_mute, this), gui_context());
145         _session->TransportStateChange.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::check_rec_enable_sensitivity, this), gui_context());
146         _session->RecordStateChanged.connect (_session_connections, invalidator (*this), boost::bind (&RouteUI::session_rec_enable_changed, this), gui_context());
147
148         Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&RouteUI::parameter_changed, this, _1), gui_context());
149
150         rec_enable_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_press), false);
151         rec_enable_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::rec_enable_release), false);
152
153         show_sends_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_press), false);
154         show_sends_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::show_sends_release));
155
156         solo_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::solo_press), false);
157         solo_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::solo_release), false);
158         mute_button->signal_button_press_event().connect (sigc::mem_fun(*this, &RouteUI::mute_press), false);
159         mute_button->signal_button_release_event().connect (sigc::mem_fun(*this, &RouteUI::mute_release), false);
160         invert_button->signal_toggled().connect (sigc::mem_fun(*this, &RouteUI::invert_toggled), false);
161
162 }
163
164 void
165 RouteUI::reset ()
166 {
167         route_connections.drop_connections ();
168
169         delete solo_menu;
170         solo_menu = 0;
171
172         delete mute_menu;
173         mute_menu = 0;
174
175         if (xml_node) {
176                 /* do not delete the node - its owned by the route */
177                 xml_node = 0;
178         }
179
180         route_active_menu_item = 0;
181         denormal_menu_item = 0;
182 }
183
184 void
185 RouteUI::self_delete ()
186 {
187         /* This may be called from a non-GUI thread. Keep it safe */
188
189         delete_when_idle (this);
190 }
191
192 void
193 RouteUI::set_route (boost::shared_ptr<Route> rp)
194 {
195         reset ();
196
197         _route = rp;
198
199         if (set_color_from_route()) {
200                 set_color (unique_random_color());
201         }
202
203         if (self_destruct) {
204                 rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
205         }
206         
207         mute_button->set_controllable (_route->mute_control());
208         solo_button->set_controllable (_route->solo_control());
209
210         _route->active_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_active_changed, this), gui_context());
211         _route->mute_changed.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::mute_changed, this, _1), gui_context());
212
213         _route->solo_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
214         _route->solo_safe_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
215         _route->listen_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
216         _route->solo_isolated_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::update_solo_display, this), gui_context());
217
218         _route->phase_invert_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::polarity_changed, this), gui_context());
219         _route->PropertyChanged.connect (route_connections, invalidator (*this), ui_bind (&RouteUI::property_changed, this, _1), gui_context());
220
221         if (_session->writable() && is_track()) {
222                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
223
224                 t->RecordEnableChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::route_rec_enable_changed, this), gui_context());
225
226                 rec_enable_button->show();
227                 rec_enable_button->set_controllable (t->rec_enable_control());
228
229                 update_rec_display ();
230         }
231
232         mute_button->unset_flags (Gtk::CAN_FOCUS);
233         solo_button->unset_flags (Gtk::CAN_FOCUS);
234
235         mute_button->show();
236         invert_button->show ();
237
238         if (_route->is_monitor()) {
239                 solo_button->hide ();
240         } else {
241                 solo_button->show();
242         }
243
244         map_frozen ();
245 }
246
247 void
248 RouteUI::invert_toggled ()
249 {
250         cerr << this << " button state = " << invert_button->get_active() << " PI = " << _route->phase_invert() << endl;
251         _route->set_phase_invert (invert_button->get_active());
252 }
253
254 void
255 RouteUI::polarity_changed ()
256 {
257         if (!_route) {
258                 return;
259         }
260         
261         if (_route->phase_invert()) {
262                 invert_button->set_active (true);
263         } else {
264                 invert_button->set_active (false);
265         }
266 }
267
268 bool
269 RouteUI::mute_press (GdkEventButton* ev)
270 {
271         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
272                 return true;
273         }
274
275         multiple_mute_change = false;
276
277         if (!ignore_toggle) {
278
279                 if (Keyboard::is_context_menu_event (ev)) {
280
281                         if (mute_menu == 0){
282                                 build_mute_menu();
283                         }
284
285                         mute_menu->popup(0,ev->time);
286
287                 } else {
288
289                         if (Keyboard::is_button2_event (ev)) {
290                                 // Primary-button2 click is the midi binding click
291                                 // button2-click is "momentary"
292
293
294                                 if (mute_button->on_button_press_event (ev)) {
295                                         return true;
296                                 }
297
298                                 _mute_release = new SoloMuteRelease (_route->self_muted ());
299                         }
300
301                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
302
303                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
304
305                                         if (_mute_release) {
306                                                 _mute_release->routes = _session->get_routes ();
307                                         }
308
309                                         _session->set_mute (_session->get_routes(), !_route->self_muted());
310
311                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
312
313                                         /* Primary-button1 applies change to the mix group even if it is not active
314                                            NOTE: Primary-button2 is MIDI learn.
315                                         */
316
317                                         if (ev->button == 1 && _route->route_group()) {
318                                                 if (_mute_release) {
319                                                         _mute_release->routes = _session->get_routes ();
320                                                 }
321                                                                 
322                                                 _session->set_mute (_session->get_routes(), !_route->self_muted(), Session::rt_cleanup, true);
323                                         }
324
325                                 } else {
326
327                                         /* plain click applies change to this route */
328                                         
329                                         boost::shared_ptr<RouteList> rl (new RouteList);
330                                         rl->push_back (_route);
331
332                                         if (_mute_release) {
333                                                 _mute_release->routes = rl;
334                                         }
335
336                                         _session->set_mute (rl, !_route->self_muted());
337
338                                 }
339                         }
340                 }
341
342         }
343
344         return true;
345 }
346
347 bool
348 RouteUI::mute_release (GdkEventButton*)
349 {
350         if (!ignore_toggle) {
351                 if (_mute_release){
352                         _session->set_mute (_mute_release->routes, _mute_release->active, Session::rt_cleanup, true);
353                         delete _mute_release;
354                         _mute_release = 0;
355                 }
356         }
357
358         return true;
359 }
360
361 bool
362 RouteUI::solo_press(GdkEventButton* ev)
363 {
364         /* ignore double/triple clicks */
365
366         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
367                 return true;
368         }
369         
370         multiple_solo_change = false;
371
372         if (!ignore_toggle) {
373                 
374                 if (Keyboard::is_context_menu_event (ev)) {
375                         
376                         if (solo_menu == 0) {
377                                 build_solo_menu ();
378                         }
379                         
380                         solo_menu->popup (1, ev->time);
381                         
382                 } else {
383                         
384                         if (Keyboard::is_button2_event (ev)) {
385                                 
386                                 // Primary-button2 click is the midi binding click
387                                 // button2-click is "momentary"
388                                 
389                                 if (solo_button->on_button_press_event (ev)) {
390                                         return true;
391                                 }
392
393                                 _solo_release = new SoloMuteRelease (_route->self_soloed());
394                         }
395                         
396                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
397                                 
398                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
399                                         
400                                         /* Primary-Tertiary-click applies change to all routes */
401
402                                         if (_solo_release) {
403                                                 _solo_release->routes = _session->get_routes ();
404                                         }
405                                         
406                                         if (Config->get_solo_control_is_listen_control()) {
407                                                 _session->set_listen (_session->get_routes(), !_route->listening(),  Session::rt_cleanup, true);
408                                         } else {
409                                                 _session->set_solo (_session->get_routes(), !_route->self_soloed(),  Session::rt_cleanup, true);
410                                         }
411                                         
412                                 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
413                                         
414                                         // Primary-Secondary-click: exclusively solo this track
415
416                                         if (_solo_release) {
417                                                 _solo_release->exclusive = true;
418
419                                                 boost::shared_ptr<RouteList> routes = _session->get_routes();
420
421                                                 for (RouteList::iterator i = routes->begin(); i != routes->end(); ++i) {
422                                                         if ((*i)->soloed ()) {
423                                                                 _solo_release->routes_on->push_back (*i);
424                                                         } else {
425                                                                 _solo_release->routes_off->push_back (*i);
426                                                         }
427                                                 }
428                                         }
429                                         
430                                         if (Config->get_solo_control_is_listen_control()) {
431                                                 /* ??? we need a just_one_listen() method */
432                                         } else {
433                                                 _session->set_just_one_solo (_route, true);
434                                         }
435
436                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
437                                         
438                                         // shift-click: toggle solo isolated status
439                                         
440                                         _route->set_solo_isolated (!_route->solo_isolated(), this);
441                                         delete _solo_release;
442                                         _solo_release = 0;
443                                         
444                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
445                                         
446                                         /* Primary-button1: solo mix group.
447                                            NOTE: Primary-button2 is MIDI learn.
448                                         */
449                                         
450                                         if (ev->button == 1 && _route->route_group()) {
451
452                                                 if (_solo_release) {
453                                                         _solo_release->routes = _route->route_group()->route_list();
454                                                 }
455                                         
456                                                 if (Config->get_solo_control_is_listen_control()) {
457                                                         _session->set_listen (_route->route_group()->route_list(), !_route->listening(),  Session::rt_cleanup, true);
458                                                 } else {
459                                                         _session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(),  Session::rt_cleanup, true);
460                                                 }
461                                         }
462                                         
463                                 } else {
464                                         
465                                         /* click: solo this route */
466                                         
467                                         boost::shared_ptr<RouteList> rl (new RouteList);
468                                         rl->push_back (route());
469
470                                         if (_solo_release) {
471                                                 _solo_release->routes = rl;
472                                         }
473
474                                         if (Config->get_solo_control_is_listen_control()) {
475                                                 _session->set_listen (rl, !_route->listening());
476                                         } else {
477                                                 _session->set_solo (rl, !_route->self_soloed());
478                                         }
479                                 }
480                         }
481                 }
482         }
483
484         return true;
485 }
486
487 bool
488 RouteUI::solo_release (GdkEventButton*)
489 {
490         if (!ignore_toggle) {
491                 
492                 if (_solo_release) {
493
494                         if (_solo_release->exclusive) {
495
496                         } else {
497                                 if (Config->get_solo_control_is_listen_control()) {
498                                         _session->set_listen (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
499                                 } else {
500                                         _session->set_solo (_solo_release->routes, _solo_release->active, Session::rt_cleanup, true);
501                                 }
502                         }
503
504                         delete _solo_release;
505                         _solo_release = 0;
506                 }
507         }
508
509         return true;
510 }
511
512 bool
513 RouteUI::rec_enable_press(GdkEventButton* ev)
514 {
515         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
516                 return true;
517         }
518
519         if (!_session->engine().connected()) {
520                 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
521                 msg.run ();
522                 return true;
523         }
524
525         if (!ignore_toggle && is_track() && rec_enable_button) {
526
527                 if (Keyboard::is_button2_event (ev)) {
528
529                         // do nothing on midi sigc::bind event
530                         return rec_enable_button->on_button_press_event (ev);
531
532                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
533
534                         _session->set_record_enable (_session->get_routes(), !rec_enable_button->get_active());
535
536                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
537
538                         /* Primary-button1 applies change to the route group (even if it is not active)
539                            NOTE: Primary-button2 is MIDI learn.
540                         */
541                         if (ev->button == 1 && _route->route_group()) {
542                                 _session->set_record_enable (_route->route_group()->route_list(), !rec_enable_button->get_active(), Session::rt_cleanup, true);
543                         }
544
545                 } else if (Keyboard::is_context_menu_event (ev)) {
546
547                         /* do this on release */
548
549                 } else {
550
551                         boost::shared_ptr<RouteList> rl (new RouteList);
552                         rl->push_back (route());
553                         _session->set_record_enable (rl, !rec_enable_button->get_active());
554                 }
555         }
556
557         return true;
558 }
559
560 bool
561 RouteUI::rec_enable_release (GdkEventButton*)
562 {
563         return true;
564 }
565
566 void
567 RouteUI::build_sends_menu ()
568 {
569         using namespace Menu_Helpers;
570
571         sends_menu = new Menu;
572         sends_menu->set_name ("ArdourContextMenu");
573         MenuList& items = sends_menu->items();
574
575         items.push_back (MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader)));
576         items.push_back (MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader)));
577         items.push_back (MenuElem(_("Assign selected tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader)));
578         items.push_back (MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader)));
579         items.push_back (MenuElem(_("Copy track gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
580         items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
581         items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
582
583 }
584
585 void
586 RouteUI::create_sends (Placement p)
587 {
588         _session->globally_add_internal_sends (_route, p);
589 }
590
591 void
592 RouteUI::create_selected_sends (Placement p)
593 {
594         boost::shared_ptr<RouteList> rlist (new RouteList);
595         TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
596
597         for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
598                 RouteTimeAxisView* rtv;
599                 RouteUI* rui;
600                 if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
601                         if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
602                                 if (boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
603                                         rlist->push_back (rui->route());
604                                 }
605                         }
606                 }
607         }
608         
609         _session->add_internal_sends (_route, p, rlist);
610 }
611
612 void
613 RouteUI::set_sends_gain_from_track ()
614 {
615         _session->globally_set_send_gains_from_track (_route);
616 }
617
618 void
619 RouteUI::set_sends_gain_to_zero ()
620 {
621         _session->globally_set_send_gains_to_zero (_route);
622 }
623
624 void
625 RouteUI::set_sends_gain_to_unity ()
626 {
627         _session->globally_set_send_gains_to_unity (_route);
628 }
629
630 bool
631 RouteUI::show_sends_press(GdkEventButton* ev)
632 {
633         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
634                 return true;
635         }
636
637         if (!ignore_toggle && !is_track() && show_sends_button) {
638
639                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
640
641                         // do nothing on midi sigc::bind event
642                         return false;
643
644                 } else if (Keyboard::is_context_menu_event (ev)) {
645
646                         if (sends_menu == 0) {
647                                 build_sends_menu ();
648                         }
649
650                         sends_menu->popup (0, ev->time);
651
652                 } else {
653
654                         /* change button state */
655
656                         show_sends_button->set_active (!show_sends_button->get_active());
657
658                         /* start blinking */
659
660                         if (show_sends_button->get_active()) {
661                                 /* show sends to this bus */
662                                 MixerStrip::SwitchIO (_route);
663                                 send_blink_connection = ARDOUR_UI::instance()->Blink.connect (sigc::mem_fun(*this, &RouteUI::send_blink));
664                         } else {
665                                 /* everybody back to normal */
666                                 send_blink_connection.disconnect ();
667                                 MixerStrip::SwitchIO (boost::shared_ptr<Route>());
668                         }
669
670                 }
671         }
672
673         return true;
674 }
675
676 bool
677 RouteUI::show_sends_release (GdkEventButton*)
678 {
679         return true;
680 }
681
682 void
683 RouteUI::send_blink (bool onoff)
684 {
685         if (!show_sends_button) {
686                 return;
687         }
688
689         if (onoff) {
690                 show_sends_button->set_state (STATE_ACTIVE);
691         } else {
692                 show_sends_button->set_state (STATE_NORMAL);
693         }
694 }
695
696 int
697 RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
698 {
699         if (r->is_master() || r->is_monitor()) {
700                 return 0;
701         }
702         
703         if (Config->get_solo_control_is_listen_control()) {
704
705                 if (r->listening()) {
706                         return 1;
707                 } else {
708                         return 0;
709                 }
710
711         } 
712         
713         if (r->soloed()) {
714                 return 1;
715         } else {
716                 return 0;
717         }
718 }
719
720 int
721 RouteUI::solo_visual_state_with_isolate (boost::shared_ptr<Route> r)
722 {
723         if (r->is_master() || r->is_monitor()) {
724                 return 0;
725         }
726         
727         if (Config->get_solo_control_is_listen_control()) {
728
729                 if (r->listening()) {
730                         return 1;
731                 } else {
732                         return 0;
733                 }
734
735         } 
736         
737         if (r->solo_isolated()) {
738                 return 2;
739         } else if (r->soloed()) {
740                 if (!r->self_soloed()) {
741                         return 3;
742                 } else {
743                         return 1;
744                 }
745         } else {
746                 return 0;
747         }
748 }
749
750 int
751 RouteUI::solo_isolate_visual_state (boost::shared_ptr<Route> r)
752 {
753         if (r->is_master() || r->is_monitor()) {
754                 return 0;
755         }
756         
757         if (r->solo_isolated()) {
758                 return 1;
759         } else {
760                 return 0;
761         }
762 }
763
764 int
765 RouteUI::solo_safe_visual_state (boost::shared_ptr<Route> r)
766 {
767         if (r->is_master() || r->is_monitor()) {
768                 return 0;
769         }
770         
771         if (r->solo_safe()) {
772                 return 1;
773         } else {
774                 return 0;
775         }
776 }
777
778 void
779 RouteUI::update_solo_display ()
780 {
781         bool x;
782
783         if (Config->get_solo_control_is_listen_control()) {
784
785                 if (solo_button->get_active() != (x = _route->listening())) {
786                         ignore_toggle = true;
787                         solo_button->set_active(x);
788                         ignore_toggle = false;
789                 }
790
791         } else {
792
793                 if (solo_button->get_active() != (x = _route->soloed())) {
794                         ignore_toggle = true;
795                         solo_button->set_active (x);
796                         ignore_toggle = false;
797                 }
798
799         }
800
801         bool yn = _route->solo_safe ();
802
803         if (solo_safe_check && solo_safe_check->get_active() != yn) {
804                 solo_safe_check->set_active (yn);
805         }
806
807         yn = _route->solo_isolated ();
808
809         if (solo_isolated_check && solo_isolated_check->get_active() != yn) {
810                 solo_isolated_check->set_active (yn);
811         }
812
813         set_button_names ();
814
815         solo_button->set_visual_state (solo_visual_state_with_isolate (_route));
816 }
817
818 void
819 RouteUI::solo_changed_so_update_mute ()
820 {
821         update_mute_display ();
822 }
823
824 void
825 RouteUI::mute_changed(void* /*src*/)
826 {
827         update_mute_display ();
828 }
829
830 int
831 RouteUI::mute_visual_state (Session* s, boost::shared_ptr<Route> r)
832 {
833         if (r->is_master() || r->is_monitor()) {
834                 return 0;
835         }
836         
837         if (Config->get_show_solo_mutes()) {
838                 
839                 if (r->self_muted ()) {
840                         /* full mute */
841                         return 2;
842                 } else if (r->muted_by_others()) {
843                         return 1;
844                 } else {
845                         /* no mute at all */
846                         return 0;
847                 }
848
849         } else {
850
851                 if (r->self_muted()) {
852                         /* full mute */
853                         return 2;
854                 } else {
855                         /* no mute at all */
856                         return 0;
857                 }
858         }
859
860         return 0;
861 }
862
863 void
864 RouteUI::update_mute_display ()
865 {
866         if (!_route) {
867                 return;
868         }
869
870         bool model = _route->muted();
871         bool view = mute_button->get_active();
872
873         /* first make sure the button's "depressed" visual
874            is correct.
875         */
876
877         if (model != view) {
878                 ignore_toggle = true;
879                 mute_button->set_active (model);
880                 ignore_toggle = false;
881         }
882
883         mute_button->set_visual_state (mute_visual_state (_session, _route));
884 }
885
886 void
887 RouteUI::route_rec_enable_changed ()
888 {
889         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&RouteUI::update_rec_display, this));
890 }
891
892 void
893 RouteUI::session_rec_enable_changed ()
894 {
895         update_rec_display ();
896 }
897
898 void
899 RouteUI::update_rec_display ()
900 {
901         if (!rec_enable_button || !_route) {
902                 return;
903         }
904                         
905         bool model = _route->record_enabled();
906         bool view = rec_enable_button->get_active();
907
908         /* first make sure the button's "depressed" visual
909            is correct.
910         */
911
912         if (model != view) {
913                 ignore_toggle = true;
914                 rec_enable_button->set_active (model);
915                 ignore_toggle = false;
916         }
917
918         /* now make sure its color state is correct */
919
920         if (model) {
921
922                 switch (_session->record_status ()) {
923                 case Session::Recording:
924                         rec_enable_button->set_visual_state (1);
925                         break;
926
927                 case Session::Disabled:
928                 case Session::Enabled:
929                         rec_enable_button->set_visual_state (2);
930                         break;
931
932                 }
933
934         } else {
935                 rec_enable_button->set_visual_state (0);
936         }
937
938         check_rec_enable_sensitivity ();
939 }
940
941 void
942 RouteUI::build_solo_menu (void)
943 {
944         using namespace Menu_Helpers;
945
946         solo_menu = new Menu;
947         solo_menu->set_name ("ArdourContextMenu");
948         MenuList& items = solo_menu->items();
949         CheckMenuItem* check;
950
951         check = new CheckMenuItem(_("Solo Isolate"));
952         check->set_active (_route->solo_isolated());
953         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
954         items.push_back (CheckMenuElem(*check));
955         solo_isolated_check = dynamic_cast<CheckMenuItem*>(&items.back());
956         check->show_all();
957
958         check = new CheckMenuItem(_("Solo Safe"));
959         check->set_active (_route->solo_safe());
960         check->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_solo_safe), check));
961         items.push_back (CheckMenuElem(*check));
962         solo_safe_check = dynamic_cast<CheckMenuItem*>(&items.back());
963         check->show_all();
964
965         //items.push_back (SeparatorElem());
966         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
967
968 }
969
970 void
971 RouteUI::build_mute_menu(void)
972 {
973         using namespace Menu_Helpers;
974
975         mute_menu = new Menu;
976         mute_menu->set_name ("ArdourContextMenu");
977
978         MenuList& items = mute_menu->items();
979
980         pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
981         init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
982         pre_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
983         items.push_back (CheckMenuElem(*pre_fader_mute_check));
984         pre_fader_mute_check->show_all();
985
986         post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
987         init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
988         post_fader_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
989         items.push_back (CheckMenuElem(*post_fader_mute_check));
990         post_fader_mute_check->show_all();
991
992         listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
993         init_mute_menu(MuteMaster::Listen, listen_mute_check);
994         listen_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
995         items.push_back (CheckMenuElem(*listen_mute_check));
996         listen_mute_check->show_all();
997
998         main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
999         init_mute_menu(MuteMaster::Main, main_mute_check);
1000         main_mute_check->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
1001         items.push_back (CheckMenuElem(*main_mute_check));
1002         main_mute_check->show_all();
1003
1004         //items.push_back (SeparatorElem());
1005         // items.push_back (MenuElem (_("MIDI Bind"), sigc::mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
1006
1007         _route->mute_points_changed.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::muting_change, this), gui_context());
1008 }
1009
1010 void
1011 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
1012 {
1013         check->set_active (_route->mute_points() & mp);
1014 }
1015
1016 void
1017 RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
1018 {
1019         if (check->get_active()) {
1020                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
1021         } else {
1022                 _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
1023         }
1024 }
1025
1026 void
1027 RouteUI::muting_change ()
1028 {
1029         ENSURE_GUI_THREAD (*this, &RouteUI::muting_change)
1030
1031         bool yn;
1032         MuteMaster::MutePoint current = _route->mute_points ();
1033
1034         yn = (current & MuteMaster::PreFader);
1035
1036         if (pre_fader_mute_check->get_active() != yn) {
1037                 pre_fader_mute_check->set_active (yn);
1038         }
1039
1040         yn = (current & MuteMaster::PostFader);
1041
1042         if (post_fader_mute_check->get_active() != yn) {
1043                 post_fader_mute_check->set_active (yn);
1044         }
1045
1046         yn = (current & MuteMaster::Listen);
1047
1048         if (listen_mute_check->get_active() != yn) {
1049                 listen_mute_check->set_active (yn);
1050         }
1051
1052         yn = (current & MuteMaster::Main);
1053
1054         if (main_mute_check->get_active() != yn) {
1055                 main_mute_check->set_active (yn);
1056         }
1057 }
1058
1059 void
1060 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
1061 {
1062         _route->set_solo_isolated (check->get_active(), this);
1063 }
1064
1065 void
1066 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
1067 {
1068         _route->set_solo_safe (check->get_active(), this);
1069 }
1070
1071 bool
1072 RouteUI::choose_color()
1073 {
1074         bool picked;
1075         Gdk::Color color;
1076
1077         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
1078
1079         if (picked) {
1080                 set_color (color);
1081         }
1082
1083         return picked;
1084 }
1085
1086 void
1087 RouteUI::set_color (const Gdk::Color & c)
1088 {
1089         char buf[64];
1090
1091         _color = c;
1092
1093         ensure_xml_node ();
1094         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
1095         xml_node->add_property ("color", buf);
1096
1097         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
1098 }
1099
1100
1101 void
1102 RouteUI::ensure_xml_node ()
1103 {
1104         if (xml_node == 0) {
1105                 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
1106                         xml_node = new XMLNode ("GUI");
1107                         _route->add_extra_xml (*xml_node);
1108                 }
1109         }
1110 }
1111
1112 XMLNode*
1113 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
1114 {
1115         ensure_xml_node ();
1116
1117         XMLNodeList kids = xml_node->children();
1118         XMLNodeConstIterator iter;
1119
1120         const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
1121
1122         for (iter = kids.begin(); iter != kids.end(); ++iter) {
1123                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
1124                         XMLProperty* type = (*iter)->property("automation-id");
1125                         if (type && type->value() == sym)
1126                                 return *iter;
1127                 }
1128         }
1129
1130         // Didn't find it, make a new one
1131         XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
1132         child->add_property("automation-id", sym);
1133         xml_node->add_child_nocopy (*child);
1134
1135         return child;
1136 }
1137
1138 int
1139 RouteUI::set_color_from_route ()
1140 {
1141         XMLProperty *prop;
1142
1143         RouteUI::ensure_xml_node ();
1144
1145         if ((prop = xml_node->property ("color")) != 0) {
1146                 int r, g, b;
1147                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1148                 _color.set_red(r);
1149                 _color.set_green(g);
1150                 _color.set_blue(b);
1151                 return 0;
1152         }
1153         return 1;
1154 }
1155
1156 void
1157 RouteUI::remove_this_route ()
1158 {
1159         vector<string> choices;
1160         string prompt;
1161
1162         if (is_track()) {
1163                 prompt  = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n(this cannot be undone)"), _route->name());
1164         } else {
1165                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(this cannot be undone)"), _route->name());
1166         }
1167
1168         choices.push_back (_("No, do nothing."));
1169         choices.push_back (_("Yes, remove it."));
1170
1171         string title;
1172         if (is_track()) {
1173                 title = _("Remove track");
1174         } else {
1175                 title = _("Remove bus");
1176         }
1177
1178         Choice prompter (title, prompt, choices);
1179
1180         if (prompter.run () == 1) {
1181                 Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1182         }
1183 }
1184
1185 gint
1186 RouteUI::idle_remove_this_route (RouteUI *rui)
1187 {
1188         rui->_session->remove_route (rui->_route);
1189         return false;
1190 }
1191
1192 void
1193 RouteUI::route_rename ()
1194 {
1195         ArdourPrompter name_prompter (true);
1196         string result;
1197         name_prompter.set_prompt (_("New Name: "));
1198         name_prompter.set_initial_text (_route->name());
1199         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1200         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1201         name_prompter.show_all ();
1202
1203         switch (name_prompter.run ()) {
1204
1205         case Gtk::RESPONSE_ACCEPT:
1206         name_prompter.get_result (result);
1207         if (result.length()) {
1208                         _route->set_name (result);
1209                 }
1210                 break;
1211         }
1212
1213         return;
1214
1215 }
1216
1217 void
1218 RouteUI::property_changed (const PropertyChange& what_changed)
1219 {
1220         if (what_changed.contains (ARDOUR::Properties::name)) {
1221                 name_label.set_text (_route->name());
1222         }
1223 }
1224
1225 void
1226 RouteUI::toggle_route_active ()
1227 {
1228         bool yn;
1229
1230         if (route_active_menu_item) {
1231                 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1232                         _route->set_active (!yn);
1233                 }
1234         }
1235 }
1236
1237 void
1238 RouteUI::route_active_changed ()
1239 {
1240         if (route_active_menu_item) {
1241                 Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&CheckMenuItem::set_active, route_active_menu_item, _route->active()));
1242         }
1243 }
1244
1245
1246 void
1247 RouteUI::toggle_denormal_protection ()
1248 {
1249         if (denormal_menu_item) {
1250
1251                 bool x;
1252
1253                 ENSURE_GUI_THREAD (*this, &RouteUI::toggle_denormal_protection)
1254
1255                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1256                         _route->set_denormal_protection (x);
1257                 }
1258         }
1259 }
1260
1261 void
1262 RouteUI::denormal_protection_changed ()
1263 {
1264         if (denormal_menu_item) {
1265                 denormal_menu_item->set_active (_route->denormal_protection());
1266         }
1267 }
1268
1269 void
1270 RouteUI::disconnect_input ()
1271 {
1272         _route->input()->disconnect (this);
1273 }
1274
1275 void
1276 RouteUI::disconnect_output ()
1277 {
1278         _route->output()->disconnect (this);
1279 }
1280
1281 bool
1282 RouteUI::is_track () const
1283 {
1284         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1285 }
1286
1287 boost::shared_ptr<Track>
1288 RouteUI::track() const
1289 {
1290         return boost::dynamic_pointer_cast<Track>(_route);
1291 }
1292
1293 bool
1294 RouteUI::is_audio_track () const
1295 {
1296         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1297 }
1298
1299 boost::shared_ptr<AudioTrack>
1300 RouteUI::audio_track() const
1301 {
1302         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1303 }
1304
1305 bool
1306 RouteUI::is_midi_track () const
1307 {
1308         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1309 }
1310
1311 boost::shared_ptr<MidiTrack>
1312 RouteUI::midi_track() const
1313 {
1314         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1315 }
1316
1317 string
1318 RouteUI::name() const
1319 {
1320         return _route->name();
1321 }
1322
1323 void
1324 RouteUI::map_frozen ()
1325 {
1326         ENSURE_GUI_THREAD (*this, &RouteUI::map_frozen)
1327
1328         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1329
1330         if (at) {
1331                 switch (at->freeze_state()) {
1332                 case AudioTrack::Frozen:
1333                         rec_enable_button->set_sensitive (false);
1334                         break;
1335                 default:
1336                         rec_enable_button->set_sensitive (true);
1337                         break;
1338                 }
1339         }
1340 }
1341
1342 void
1343 RouteUI::adjust_latency ()
1344 {
1345         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session->frame_rate(), _session->engine().frames_per_cycle());
1346 }
1347
1348 void
1349 RouteUI::save_as_template ()
1350 {
1351         sys::path path;
1352         Glib::ustring safe_name;
1353         string name;
1354
1355         path = ARDOUR::user_route_template_directory ();
1356
1357         if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1358                 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1359                 return;
1360         }
1361
1362         Prompter p (true); // modal
1363
1364         p.set_prompt (_("Template name:"));
1365         switch (p.run()) {
1366         case RESPONSE_ACCEPT:
1367                 break;
1368         default:
1369                 return;
1370         }
1371
1372         p.hide ();
1373         p.get_result (name, true);
1374
1375         safe_name = legalize_for_path (name);
1376         safe_name += template_suffix;
1377
1378         path /= safe_name;
1379
1380         _route->save_as_template (path.to_string(), name);
1381 }
1382
1383 void
1384 RouteUI::check_rec_enable_sensitivity ()
1385 {
1386         if (_session->transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1387                 rec_enable_button->set_sensitive (false);
1388         } else {
1389                 rec_enable_button->set_sensitive (true);
1390         }
1391 }
1392
1393 void
1394 RouteUI::parameter_changed (string const & p)
1395 {
1396         if (p == "disable-disarm-during-roll") {
1397                 check_rec_enable_sensitivity ();
1398         } else if (p == "solo-control-is-listen-control") {
1399                 set_button_names ();
1400         } else if (p == "listen-position") {
1401                 set_button_names ();
1402         }
1403 }
1404
1405 void
1406 RouteUI::step_gain_up ()
1407 {
1408         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1409 }
1410
1411 void
1412 RouteUI::page_gain_up ()
1413 {
1414         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1415 }
1416
1417 void
1418 RouteUI::step_gain_down ()
1419 {
1420         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1421 }
1422
1423 void
1424 RouteUI::page_gain_down ()
1425 {
1426         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1427 }
1428
1429 void
1430 RouteUI::open_remote_control_id_dialog ()
1431 {
1432         ArdourDialog dialog (_("Remote Control ID"));
1433
1434         uint32_t const limit = _session->ntracks() + _session->nbusses () + 4;
1435
1436         HBox* hbox = manage (new HBox);
1437         hbox->set_spacing (6);
1438         hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1439         SpinButton* spin = manage (new SpinButton);
1440         spin->set_digits (0);
1441         spin->set_increments (1, 10);
1442         spin->set_range (0, limit);
1443         spin->set_value (_route->remote_control_id());
1444         hbox->pack_start (*spin);
1445         dialog.get_vbox()->pack_start (*hbox);
1446
1447         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1448         dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1449
1450         dialog.show_all ();
1451         int const r = dialog.run ();
1452
1453         if (r == RESPONSE_ACCEPT) {
1454                 _route->set_remote_control_id (spin->get_value_as_int ());
1455         }
1456 }