Fix warning.
[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 sends_menu;
88 }
89
90 void
91 RouteUI::init ()
92 {
93         self_destruct = true;
94         xml_node = 0;
95         mute_menu = 0;
96         solo_menu = 0;
97         sends_menu = 0;
98         ignore_toggle = false;
99         wait_for_release = false;
100         route_active_menu_item = 0;
101         polarity_menu_item = 0;
102         denormal_menu_item = 0;
103         multiple_mute_change = false;
104         multiple_solo_change = false;
105
106         mute_button = manage (new BindableToggleButton ());
107         mute_button->set_self_managed (true);
108         mute_button->set_name ("MuteButton");
109         mute_button->add (mute_button_label);
110         mute_button_label.show ();
111         UI::instance()->set_tip (mute_button, _("Mute this track"), "");
112
113         solo_button = manage (new BindableToggleButton ());
114         solo_button->set_self_managed (true);
115         solo_button->set_name ("SoloButton");
116         solo_button->add (solo_button_label);
117         solo_button_label.show ();
118         UI::instance()->set_tip (solo_button, _("Mute other (non-soloed) tracks"), "");
119         solo_button->set_no_show_all (true);
120
121         rec_enable_button = manage (new BindableToggleButton ());
122         rec_enable_button->set_name ("RecordEnableButton");
123         rec_enable_button->set_self_managed (true);
124         rec_enable_button->add (rec_enable_button_label);
125         rec_enable_button_label.show ();
126         UI::instance()->set_tip (rec_enable_button, _("Enable recording on this track"), "");
127
128         show_sends_button = manage (new BindableToggleButton (""));
129         show_sends_button->set_name ("SendAlert");
130         show_sends_button->set_self_managed (true);
131         UI::instance()->set_tip (show_sends_button, _("make mixer strips show sends to this bus"), "");
132
133         _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
134         _session.TransportStateChange.connect (mem_fun (*this, &RouteUI::check_rec_enable_sensitivity));
135
136         Config->ParameterChanged.connect (mem_fun (*this, &RouteUI::parameter_changed));
137 }
138
139 void
140 RouteUI::reset ()
141 {
142         //Remove route connections associated with us.
143         for (vector<sigc::connection>::iterator it = connections.begin(); it!=connections.end(); ++it) {
144             (*it).disconnect();
145         }
146
147         connections.clear ();
148
149         delete solo_menu;
150         solo_menu = 0;
151
152         delete mute_menu;
153         mute_menu = 0;
154         
155         if (xml_node) {
156                 /* do not delete the node - its owned by the route */
157                 xml_node = 0;
158         }
159
160         route_active_menu_item = 0;
161         polarity_menu_item = 0;
162         denormal_menu_item = 0;
163 }
164
165 void
166 RouteUI::set_route (boost::shared_ptr<Route> rp)
167 {
168         reset ();
169
170         _route = rp;
171
172         if (set_color_from_route()) {
173                 set_color (unique_random_color());
174         }
175
176         /* no, there is no memory leak here. This object cleans itself (and other stuff)
177            up when the route is destroyed.
178         */
179
180         if (self_destruct) {
181                 new PairedShiva<Route,RouteUI> (*_route, *this);
182         }
183
184         mute_button->set_controllable (_route->mute_control());
185         solo_button->set_controllable (_route->solo_control());
186   
187         connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
188         connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
189         connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
190         connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
191         connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
192   
193         if (is_track()) {
194                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
195
196                 connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
197                 connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
198
199                 rec_enable_button->show();
200                 rec_enable_button->set_controllable (t->rec_enable_control());
201
202                 update_rec_display ();
203         } 
204
205         mute_button->unset_flags (Gtk::CAN_FOCUS);
206         solo_button->unset_flags (Gtk::CAN_FOCUS);
207         
208         mute_button->show();
209
210         if (_route->is_control()) {
211                 solo_button->hide ();
212         } else {
213                 solo_button->show();
214         }
215
216         /* map the current state */
217
218         mute_changed (0);
219         solo_changed (0);
220
221         map_frozen ();
222 }
223
224 bool
225 RouteUI::mute_press(GdkEventButton* ev)
226 {
227         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
228                 return true;
229         }
230         multiple_mute_change = false;
231         if (!ignore_toggle) {
232
233                 if (Keyboard::is_context_menu_event (ev)) {
234
235                         if (mute_menu == 0){
236                                 build_mute_menu();
237                         }
238
239                         mute_menu->popup(0,ev->time);
240
241                 } else {
242
243                         if (Keyboard::is_button2_event (ev)) {
244                                 // Primary-button2 click is the midi binding click
245                                 // button2-click is "momentary"
246                                 
247                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
248                                         wait_for_release = true;
249                                 } else {
250                                         return false;
251                                 }
252                         }
253
254                         if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
255
256                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
257
258                                         /* Primary-Tertiary-click applies change to all routes */
259
260                                         _session.begin_reversible_command (_("mute change"));
261                                         Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
262                                         _session.set_all_mute (!_route->muted());
263                                         cmd->mark();
264                                         _session.add_command(cmd);
265                                         _session.commit_reversible_command ();
266                                         multiple_mute_change = true;
267
268                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
269
270                                         /* Primary-button1 applies change to the mix group.
271                                            NOTE: Primary-button2 is MIDI learn.
272                                         */
273
274                                         if (ev->button == 1) {
275                                                 set_route_group_mute (_route, !_route->muted());
276                                         }
277                                         
278                                 } else {
279
280                                         /* plain click applies change to this route */
281                                         if (wait_for_release) {
282                                                 _route->set_mute (!_route->muted(), this);
283                                         } else {
284                                                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
285                                         }
286                                 }
287                         }
288                 }
289
290         }
291
292         return true;
293 }
294
295 bool
296 RouteUI::mute_release(GdkEventButton*)
297 {
298         if (!ignore_toggle) {
299                 if (wait_for_release){
300                         wait_for_release = false;
301                         if (multiple_mute_change) {
302                                 multiple_mute_change = false;
303                                 // undo the last op
304                                 // because the press was the last undoable thing we did
305                                 _session.undo (1U);
306                         } else {
307                                 _route->set_mute (!_route->muted(), this);
308                         }
309                 }
310         }
311         return true;
312 }
313
314 bool
315 RouteUI::solo_press(GdkEventButton* ev)
316 {
317         /* ignore double/triple clicks */
318
319         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
320                 return true;
321         }
322
323         if (Config->get_solo_control_is_listen_control()) {
324
325                 _route->set_listen (!_route->listening(), this);
326
327         } else {
328
329                 multiple_solo_change = false;
330                 if (!ignore_toggle) {
331                         
332                         if (Keyboard::is_context_menu_event (ev)) {
333                                 
334                                 if (solo_menu == 0) {
335                                         build_solo_menu ();
336                                 }
337                                 
338                                 solo_menu->popup (1, ev->time);
339                                 
340                         } else {
341                                 
342                                 if (Keyboard::is_button2_event (ev)) {
343                                         
344                                         // Primary-button2 click is the midi binding click
345                                         // button2-click is "momentary"
346                                         
347                                         if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
348                                                 wait_for_release = true;
349                                         } else {
350                                                 return false;
351                                         }
352                                 }
353                                 
354                                 if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
355                                         
356                                         if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
357                                                 
358                                                 /* Primary-Tertiary-click applies change to all routes */
359                                                 bool was_not_latched = false;
360                                                 if (!Config->get_solo_latched ()) {
361                                                         was_not_latched = true;
362                                                         /*
363                                                           XXX it makes no sense to solo all tracks if we're 
364                                                           not in latched mode, but doing nothing feels like a bug, 
365                                                           so do it anyway 
366                                                         */
367                                                         Config->set_solo_latched (true);
368                                                 }
369                                                 _session.begin_reversible_command (_("solo change"));
370                                                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
371                                                 _session.set_all_solo (!_route->soloed());
372                                                 cmd->mark();
373                                                 _session.add_command (cmd);
374                                                 _session.commit_reversible_command ();
375                                                 multiple_solo_change = true;
376                                                 if (was_not_latched) {
377                                                         Config->set_solo_latched (false);
378                                                 }
379                                                 
380                                         } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
381                                                 
382                                                 // Primary-Secondary-click: exclusively solo this track, not a toggle */
383
384                                                 _session.begin_reversible_command (_("solo change"));
385                                                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
386                                                 _session.set_all_solo (false);
387                                                 _route->set_solo (true, this);
388                                                 cmd->mark();
389                                                 _session.add_command(cmd);
390                                                 _session.commit_reversible_command ();
391
392                                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
393
394                                                 // shift-click: set this route to solo safe
395
396                                                 if (Profile->get_sae() && ev->button == 1) {
397                                                         // button 1 and shift-click: disables solo_latched for this click
398                                                         if (!Config->get_solo_latched ()) {
399                                                                 Config->set_solo_latched (true);
400                                                                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
401                                                                 Config->set_solo_latched (false);
402                                                         }
403                                                 } else {
404                                                         _route->set_solo_isolated (!_route->solo_isolated(), this);
405                                                         wait_for_release = false;
406                                                 }
407
408                                         } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
409
410                                                 /* Primary-button1: solo mix group.
411                                                    NOTE: Primary-button2 is MIDI learn.
412                                                 */
413
414                                                 if (ev->button == 1) {
415                                                         set_route_group_solo (_route, !_route->soloed());
416                                                 }
417
418                                         } else {
419
420                                                 /* click: solo this route */
421                                                 if (wait_for_release) {
422                                                         _route->set_solo (!_route->soloed(), this);
423                                                 } else {
424                                                         reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
425                                                 }
426                                         }
427                                 }
428                         }
429                 }
430         }
431
432         return true;
433 }
434
435 bool
436 RouteUI::solo_release(GdkEventButton*)
437 {
438         if (!ignore_toggle) {
439                 if (wait_for_release) {
440                         wait_for_release = false;
441                         if (multiple_solo_change) {
442                                 multiple_solo_change = false;
443                                 // undo the last op
444                                 // because the press was the last undoable thing we did
445                                 _session.undo (1U);
446                         } else {
447                                 // we don't use "undo the last op"
448                                 // here because its expensive for the GUI
449                                 _route->set_solo (!_route->soloed(), this);
450                         }
451                 }
452         }
453
454         return true;
455 }
456
457 bool
458 RouteUI::rec_enable_press(GdkEventButton* ev)
459 {
460         if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
461                 return true;
462         }
463
464         if (!_session.engine().connected()) {
465                 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
466                 msg.run ();
467                 return true;
468         }
469
470         if (!ignore_toggle && is_track() && rec_enable_button) {
471
472                 if (Keyboard::is_button2_event (ev) && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
473
474                         // do nothing on midi bind event
475                         return false;
476
477                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
478
479                         _session.begin_reversible_command (_("rec-enable change"));
480                         Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
481
482                         if (rec_enable_button->get_active()) {
483                                 _session.record_disenable_all ();
484                         } else {
485                                 _session.record_enable_all ();
486                                 check_rec_enable_sensitivity ();
487                         }
488
489                         cmd->mark();
490                         _session.add_command(cmd);
491                         _session.commit_reversible_command ();
492
493                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
494
495                         /* Primary-button1 applies change to the mix group.
496                            NOTE: Primary-button2 is MIDI learn.
497                         */
498
499                         set_route_group_rec_enable (_route, !_route->record_enabled());
500
501                 } else if (Keyboard::is_context_menu_event (ev)) {
502                         
503                         /* do this on release */
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_solo_menu (void)
780 {
781         using namespace Menu_Helpers;
782         
783         solo_menu = new Menu;
784         solo_menu->set_name ("ArdourContextMenu");
785         MenuList& items = solo_menu->items();
786         CheckMenuItem* check;
787
788         check = new CheckMenuItem(_("Solo Isolate"));
789         check->set_active (_route->solo_isolated());
790         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_isolated), check));
791         _route->solo_isolated_changed.connect(bind (mem_fun (*this, &RouteUI::solo_isolated_toggle), check));
792         items.push_back (CheckMenuElem(*check));
793         check->show_all();
794
795         //items.push_back (SeparatorElem());
796         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
797         
798 }
799
800 void
801 RouteUI::build_mute_menu(void)
802 {
803         using namespace Menu_Helpers;
804         
805         mute_menu = new Menu;
806         mute_menu->set_name ("ArdourContextMenu");
807
808 #if FIX_ME_IN_3_0       
809         MenuList& items = mute_menu->items();
810         CheckMenuItem* check;
811
812         check = new CheckMenuItem(_("Pre Fader"));
813         init_mute_menu(PRE_FADER, check);
814         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
815         _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
816         items.push_back (CheckMenuElem(*check));
817         check->show_all();
818
819         check = new CheckMenuItem(_("Post Fader"));
820         init_mute_menu(POST_FADER, check);
821         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
822         _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
823         items.push_back (CheckMenuElem(*check));
824         check->show_all();
825         
826         check = new CheckMenuItem(_("Control Outs"));
827         init_mute_menu(CONTROL_OUTS, check);
828         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
829         _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
830         items.push_back (CheckMenuElem(*check));
831         check->show_all();
832
833         check = new CheckMenuItem(_("Main Outs"));
834         init_mute_menu(MAIN_OUTS, check);
835         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
836         _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
837         items.push_back (CheckMenuElem(*check));
838         check->show_all();
839 #endif
840         //items.push_back (SeparatorElem());
841         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
842 }
843
844 void
845 RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
846 {
847         check->set_active (_route->mute_master()->muted_at (mp));
848 }
849
850 void
851 RouteUI::toggle_mute_menu(MuteMaster::MutePoint /*mp*/, Gtk::CheckMenuItem* /*check*/)
852 {
853         // _route->set_mute_config(type, check->get_active(), this);
854 }
855
856 void
857 RouteUI::toggle_solo_isolated (Gtk::CheckMenuItem* check)
858 {
859         _route->set_solo_isolated (check->get_active(), this);
860 }
861
862 void
863 RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
864 {
865         RouteGroup* route_group;
866
867         if((route_group = route->route_group()) != 0){
868                 _session.begin_reversible_command (_("mix group solo  change"));
869                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
870                 route_group->apply(&Route::set_solo, yn, this);
871                 cmd->mark();
872                 _session.add_command (cmd);
873                 _session.commit_reversible_command ();
874         } else {
875                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
876         }
877 }
878
879 void
880 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
881 {
882         _session.begin_reversible_command (name);
883         XMLNode &before = _route->get_state();
884         bind(mem_fun(*_route, func), yn, arg)();
885         XMLNode &after = _route->get_state();
886         _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
887         _session.commit_reversible_command ();
888 }
889
890 void
891 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
892 {
893         _session.begin_reversible_command (name);
894         XMLNode &before = track()->get_state();
895         bind (mem_fun (*track(), func), yn, arg)();
896         XMLNode &after = track()->get_state();
897         _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
898         _session.commit_reversible_command ();
899 }
900
901 void
902 RouteUI::set_route_group_mute(boost::shared_ptr<Route> route, bool yn)
903 {
904         RouteGroup* route_group;
905
906         if((route_group = route->route_group()) != 0){
907                 _session.begin_reversible_command (_("mix group mute change"));
908                 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
909                 route_group->apply(&Route::set_mute, yn, this);
910                 cmd->mark();
911                 _session.add_command(cmd);
912                 _session.commit_reversible_command ();
913         } else {
914                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
915         }
916 }
917
918 void
919 RouteUI::set_route_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
920 {
921         RouteGroup* route_group;
922
923         if((route_group = route->route_group()) != 0){
924                 _session.begin_reversible_command (_("mix group rec-enable change"));
925                 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
926                 route_group->apply (&Route::set_record_enable, yn, this);
927                 cmd->mark();
928                 _session.add_command(cmd);
929                 _session.commit_reversible_command ();
930         } else {
931                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
932         }
933 }
934
935
936 bool
937 RouteUI::choose_color()
938 {
939         bool picked;
940         Gdk::Color color;
941
942         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
943
944         if (picked) {
945                 set_color (color);
946         }
947
948         return picked;
949 }
950
951 void
952 RouteUI::set_color (const Gdk::Color & c)
953 {
954         char buf[64];
955         
956         _color = c;
957         
958         ensure_xml_node ();
959         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
960         xml_node->add_property ("color", buf);
961
962         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
963 }
964
965
966 void
967 RouteUI::ensure_xml_node ()
968 {
969         if (xml_node == 0) {
970                 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
971                         xml_node = new XMLNode ("GUI");
972                         _route->add_extra_xml (*xml_node);
973                 }
974         }
975 }
976
977 XMLNode*
978 RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
979 {
980         ensure_xml_node ();
981         
982         XMLNodeList kids = xml_node->children();
983         XMLNodeConstIterator iter;
984
985         const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
986
987         for (iter = kids.begin(); iter != kids.end(); ++iter) {
988                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
989                         XMLProperty* type = (*iter)->property("automation-id");
990                         if (type && type->value() == sym)
991                                 return *iter;
992                 }
993         }
994
995         // Didn't find it, make a new one
996         XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
997         child->add_property("automation-id", sym);
998         xml_node->add_child_nocopy (*child);
999
1000         return child;
1001 }
1002
1003 int
1004 RouteUI::set_color_from_route ()
1005 {
1006         XMLProperty *prop;
1007         
1008         RouteUI::ensure_xml_node ();
1009
1010         if ((prop = xml_node->property ("color")) != 0) {
1011                 int r, g, b;
1012                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
1013                 _color.set_red(r);
1014                 _color.set_green(g);
1015                 _color.set_blue(b);
1016                 return 0;
1017         } 
1018         return 1;
1019 }
1020
1021 void
1022 RouteUI::remove_this_route ()
1023 {
1024         vector<string> choices;
1025         string prompt;
1026
1027         if (is_track()) {
1028                 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());
1029         } else {
1030                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
1031         }
1032
1033         choices.push_back (_("No, do nothing."));
1034         choices.push_back (_("Yes, remove it."));
1035
1036         Choice prompter (prompt, choices);
1037
1038         if (prompter.run () == 1) {
1039                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
1040         }
1041 }
1042
1043 gint
1044 RouteUI::idle_remove_this_route (RouteUI *rui)
1045 {
1046         rui->_session.remove_route (rui->_route);
1047         return false;
1048 }
1049
1050 void
1051 RouteUI::route_rename ()
1052 {
1053         ArdourPrompter name_prompter (true);
1054         string result;
1055         name_prompter.set_prompt (_("New Name: "));
1056         name_prompter.set_initial_text (_route->name());
1057         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
1058         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
1059         name_prompter.show_all ();
1060
1061         switch (name_prompter.run ()) {
1062
1063         case Gtk::RESPONSE_ACCEPT:
1064         name_prompter.get_result (result);
1065         if (result.length()) {
1066                         _route->set_name (result);
1067                 }       
1068                 break;
1069         }
1070
1071         return;
1072   
1073 }
1074
1075 void
1076 RouteUI::name_changed ()
1077 {
1078         ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
1079
1080         name_label.set_text (_route->name());
1081 }
1082
1083 void
1084 RouteUI::toggle_route_active ()
1085 {
1086         bool yn;
1087
1088         if (route_active_menu_item) {
1089                 if (route_active_menu_item->get_active() != (yn = _route->active())) {
1090                         _route->set_active (!yn);
1091                 }
1092         }
1093 }
1094
1095 void
1096 RouteUI::route_active_changed ()
1097 {
1098         if (route_active_menu_item) {
1099                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
1100         }
1101 }
1102
1103 void
1104 RouteUI::toggle_polarity ()
1105 {
1106         if (polarity_menu_item) {
1107
1108                 bool x;
1109
1110                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
1111                 
1112                 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
1113                         _route->set_phase_invert (x);
1114                         if (x) {
1115                                 name_label.set_text (X_("Ø ") + name_label.get_text());
1116                         } else {
1117                                 name_label.set_text (_route->name());
1118                         }
1119                 }
1120         }
1121 }
1122
1123 void
1124 RouteUI::polarity_changed ()
1125 {
1126         if (_route->phase_invert()) {
1127                 name_label.set_text (X_("Ø ") + name_label.get_text());
1128         } else {
1129                 name_label.set_text (_route->name());
1130         }
1131 }
1132
1133 void
1134 RouteUI::toggle_denormal_protection ()
1135 {
1136         if (denormal_menu_item) {
1137
1138                 bool x;
1139
1140                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
1141                 
1142                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
1143                         _route->set_denormal_protection (x);
1144                 }
1145         }
1146 }
1147
1148 void
1149 RouteUI::denormal_protection_changed ()
1150 {
1151         if (denormal_menu_item) {
1152                 denormal_menu_item->set_active (_route->denormal_protection());
1153         }
1154 }
1155
1156 void
1157 RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
1158 {
1159         bool yn = _route->solo_isolated ();
1160
1161         if (check->get_active() != yn) {
1162                 check->set_active (yn);
1163         }
1164 }
1165
1166 #ifdef FIX_THIS_FOR_3_0
1167 void
1168 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1169 {
1170         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
1171         
1172         bool yn = _route->get_mute_config(PRE_FADER);
1173         if (check->get_active() != yn) {
1174                 check->set_active (yn);
1175         }
1176 }
1177
1178 void
1179 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
1180 {
1181         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
1182         
1183         bool yn = _route->get_mute_config(POST_FADER);
1184         if (check->get_active() != yn) {
1185                 check->set_active (yn);
1186         }
1187 }
1188
1189 void
1190 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1191 {
1192         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
1193         
1194         bool yn = _route->get_mute_config(CONTROL_OUTS);
1195         if (check->get_active() != yn) {
1196                 check->set_active (yn);
1197         }
1198 }
1199
1200 void
1201 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
1202 {
1203         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
1204         
1205         bool yn = _route->get_mute_config(MAIN_OUTS);
1206         if (check->get_active() != yn) {
1207                 check->set_active (yn);
1208         }
1209 }
1210 #endif
1211
1212 void
1213 RouteUI::disconnect_input ()
1214 {
1215         _route->input()->disconnect (this);
1216 }
1217
1218 void
1219 RouteUI::disconnect_output ()
1220 {
1221         _route->output()->disconnect (this);
1222 }
1223
1224 bool
1225 RouteUI::is_track () const
1226 {
1227         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1228 }
1229
1230 boost::shared_ptr<Track>
1231 RouteUI::track() const
1232 {
1233         return boost::dynamic_pointer_cast<Track>(_route);
1234 }
1235
1236 bool
1237 RouteUI::is_audio_track () const
1238 {
1239         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1240 }
1241
1242 boost::shared_ptr<AudioTrack>
1243 RouteUI::audio_track() const
1244 {
1245         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1246 }
1247
1248 bool
1249 RouteUI::is_midi_track () const
1250 {
1251         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1252 }
1253
1254 boost::shared_ptr<MidiTrack>
1255 RouteUI::midi_track() const
1256 {
1257         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1258 }
1259
1260 boost::shared_ptr<Diskstream>
1261 RouteUI::get_diskstream () const
1262 {
1263         boost::shared_ptr<Track> t;
1264
1265         if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1266                 return t->diskstream();
1267         } else {
1268                 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1269         }
1270 }
1271
1272 string
1273 RouteUI::name() const
1274 {
1275         return _route->name();
1276 }
1277
1278 void
1279 RouteUI::map_frozen ()
1280 {
1281         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1282
1283         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1284
1285         if (at) {
1286                 switch (at->freeze_state()) {
1287                 case AudioTrack::Frozen:
1288                         rec_enable_button->set_sensitive (false);
1289                         break;
1290                 default:
1291                         rec_enable_button->set_sensitive (true);
1292                         break;
1293                 }
1294         }
1295 }
1296
1297 void
1298 RouteUI::adjust_latency ()
1299 {
1300         LatencyDialog dialog (_route->name() + _(" latency"), *(_route->output()), _session.frame_rate(), _session.engine().frames_per_cycle());
1301 }
1302
1303 void
1304 RouteUI::save_as_template ()
1305 {
1306         sys::path path;
1307         Glib::ustring safe_name;
1308         string name;
1309         
1310         path = ARDOUR::user_route_template_directory ();
1311         
1312         if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
1313                 error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
1314                 return;
1315         }
1316         
1317         Prompter p (true); // modal
1318         
1319         p.set_prompt (_("Template name:"));
1320         switch (p.run()) {
1321         case RESPONSE_ACCEPT:
1322                 break;
1323         default:
1324                 return;
1325         }
1326         
1327         p.hide ();
1328         p.get_result (name, true);
1329         
1330         safe_name = legalize_for_path (name);
1331         safe_name += template_suffix;
1332         
1333         path /= safe_name;
1334         
1335         _route->save_as_template (path.to_string(), name);
1336 }
1337
1338 void
1339 RouteUI::check_rec_enable_sensitivity ()
1340 {
1341         if (_session.transport_rolling() && rec_enable_button->get_active() && Config->get_disable_disarm_during_roll()) {
1342                 rec_enable_button->set_sensitive (false);
1343         } else {
1344                 rec_enable_button->set_sensitive (true);
1345         }
1346 }
1347
1348 void
1349 RouteUI::parameter_changed (string const & p)
1350 {
1351         ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
1352         
1353         if (p == "disable-disarm-during-roll") {
1354                 check_rec_enable_sensitivity ();
1355         } else if (p == "solo-control-is-listen-control") {
1356                 set_button_names ();
1357         } else if (p == "listen-position") {
1358                 set_button_names ();
1359         }
1360 }
1361
1362 void
1363 RouteUI::step_gain_up ()
1364 {
1365         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
1366 }
1367
1368 void
1369 RouteUI::page_gain_up ()
1370 {
1371         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
1372 }
1373
1374 void
1375 RouteUI::step_gain_down ()
1376 {
1377         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
1378 }
1379
1380 void
1381 RouteUI::page_gain_down ()
1382 {
1383         _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
1384 }
1385
1386 void
1387 RouteUI::open_remote_control_id_dialog ()
1388 {
1389         ArdourDialog dialog (_("Remote Control ID"));
1390
1391         uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
1392
1393         HBox* hbox = manage (new HBox);
1394         hbox->set_spacing (6);
1395         hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
1396         SpinButton* spin = manage (new SpinButton);
1397         spin->set_digits (0);
1398         spin->set_increments (1, 10);
1399         spin->set_range (0, limit);
1400         spin->set_value (_route->remote_control_id());
1401         hbox->pack_start (*spin);
1402         dialog.get_vbox()->pack_start (*hbox);
1403
1404         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
1405         dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
1406
1407         dialog.show_all ();
1408         int const r = dialog.run ();
1409
1410         if (r == RESPONSE_ACCEPT) {
1411                 _route->set_remote_control_id (spin->get_value_as_int ());
1412         }
1413 }