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