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