merge 3.0 from 2.0-ongoing@3243
[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
27 #include <ardour/route_group.h>
28 #include <pbd/memento_command.h>
29 #include <pbd/stacktrace.h>
30 #include <pbd/shiva.h>
31 #include <pbd/controllable.h>
32
33 #include "route_ui.h"
34 #include "keyboard.h"
35 #include "utils.h"
36 #include "prompter.h"
37 #include "gui_thread.h"
38 #include "ardour_dialog.h"
39 #include "latency_gui.h"
40 #include "automation_time_axis.h"
41
42 #include <ardour/route.h>
43 #include <ardour/session.h>
44 #include <ardour/audioengine.h>
45 #include <ardour/audio_track.h>
46 #include <ardour/audio_diskstream.h>
47 #include <ardour/midi_track.h>
48 #include <ardour/midi_diskstream.h>
49
50 #include "i18n.h"
51 using namespace sigc;
52 using namespace Gtk;
53 using namespace Gtkmm2ext;
54 using namespace ARDOUR;
55 using namespace PBD;
56
57 RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session& sess, const char* m_name,
58                   const char* s_name, const char* r_name)
59         : AxisView(sess),
60           _route(rt),
61           mute_button(0),
62           solo_button(0),
63           rec_enable_button(0)
64 {
65         xml_node = 0;
66         mute_menu = 0;
67         solo_menu = 0;
68         remote_control_menu = 0;
69         ignore_toggle = false;
70         wait_for_release = false;
71         route_active_menu_item = 0;
72         was_solo_safe = false;
73         polarity_menu_item = 0;
74         denormal_menu_item = 0;
75
76         if (set_color_from_route()) {
77                 set_color (unique_random_color());
78         }
79
80         new PairedShiva<Route,RouteUI> (*_route, *this);
81
82         _route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed));
83
84         mute_button = manage (new BindableToggleButton (*_route->mute_control().get(), m_name ));
85         mute_button->set_self_managed (true);
86
87         solo_button = manage (new BindableToggleButton (*_route->solo_control().get(), s_name ));
88         solo_button->set_self_managed (true);
89
90         mute_button->set_name ("MuteButton");
91         solo_button->set_name ("SoloButton");
92
93         _route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed));
94         _route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
95         _route->solo_safe_changed.connect (mem_fun(*this, &RouteUI::solo_changed));
96
97         /* when solo changes, update mute state too, in case the user wants us to display it */
98
99         _session.SoloChanged.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute));
100         
101         if (is_track()) {
102                 boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
103
104                 t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed));
105
106                 _session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed));
107
108                 rec_enable_button = manage (new BindableToggleButton (*t->rec_enable_control().get(), r_name ));
109                 rec_enable_button->set_name ("RecordEnableButton");
110                 rec_enable_button->set_self_managed (true);
111                 
112                 rec_enable_button->show();
113                 update_rec_display ();
114         } 
115
116         mute_button->unset_flags (Gtk::CAN_FOCUS);
117         solo_button->unset_flags (Gtk::CAN_FOCUS);
118         
119         mute_button->show();
120         solo_button->show();
121
122         _route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu));
123
124         /* map the current state */
125
126         map_frozen ();
127 }
128
129 RouteUI::~RouteUI()
130 {
131         GoingAway (); /* EMIT SIGNAL */
132         delete mute_menu;
133 }
134
135 bool
136 RouteUI::mute_press(GdkEventButton* ev)
137 {
138         if (ev->type == GDK_2BUTTON_PRESS) {
139                 return true;
140         }
141
142         if (!ignore_toggle) {
143
144                 if (Keyboard::is_context_menu_event (ev)) {
145
146                         if (mute_menu == 0){
147                                 build_mute_menu();
148                         }
149
150                         mute_menu->popup(0,ev->time);
151
152                 } else {
153
154                         if (ev->button == 2) {
155                                 // Primary-button2 click is the midi binding click
156                                 // button2-click is "momentary"
157                                 
158                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
159                                         wait_for_release = true;
160                                 } else {
161                                         return false;
162                                 }
163                         }
164
165                         if (ev->button == 1 || ev->button == 2) {
166
167                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
168
169                                         /* Primary-Tertiary-click applies change to all routes */
170
171                                         _session.begin_reversible_command (_("mute change"));
172                                         Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
173                                         _session.set_all_mute (!_route->muted());
174                                         cmd->mark();
175                                         _session.add_command(cmd);
176                                         _session.commit_reversible_command ();
177
178                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
179
180                                         /* Primary-button1 applies change to the mix group.
181                                            NOTE: Primary-button2 is MIDI learn.
182                                         */
183
184                                         if (ev->button == 1) {
185                                                 set_mix_group_mute (_route, !_route->muted());
186                                         }
187                                         
188                                 } else {
189
190                                         /* plain click applies change to this route */
191
192                                         reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
193                                 }
194                         }
195                 }
196
197         }
198
199         return true;
200 }
201
202 bool
203 RouteUI::mute_release(GdkEventButton* ev)
204 {
205         if (!ignore_toggle) {
206                 if (wait_for_release){
207                         wait_for_release = false;
208                         // undo the last op
209                         // because the press was the last undoable thing we did
210                         _session.undo (1U);
211                 }
212         }
213         return true;
214 }
215
216 bool
217 RouteUI::solo_press(GdkEventButton* ev)
218 {
219         /* ignore double clicks */
220
221         if (ev->type == GDK_2BUTTON_PRESS) {
222                 return true;
223         }
224
225         if (!ignore_toggle) {
226
227                 if (Keyboard::is_context_menu_event (ev)) {
228                         
229                         if (solo_menu == 0) {
230                                 build_solo_menu ();
231                         }
232
233                         solo_menu->popup (1, ev->time);
234
235                 } else {
236
237                         if (ev->button == 2) {
238
239                                 // Primary-button2 click is the midi binding click
240                                 // button2-click is "momentary"
241                                 
242                                 if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
243                                         wait_for_release = true;
244                                 } else {
245                                         return false;
246                                 }
247                         }
248
249                         if (ev->button == 1 || ev->button == 2) {
250
251                                 if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
252
253                                         /* Primary-Tertiary-click applies change to all routes */
254
255                                         _session.begin_reversible_command (_("solo change"));
256                                         Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
257                                         _session.set_all_solo (!_route->soloed());
258                                         cmd->mark();
259                                         _session.add_command (cmd);
260                                         _session.commit_reversible_command ();
261                                         
262                                 } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
263
264                                         // Primary-Secondary-click: exclusively solo this track, not a toggle */
265
266                                         _session.begin_reversible_command (_("solo change"));
267                                         Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
268                                         _session.set_all_solo (false);
269                                         _route->set_solo (true, this);
270                                         cmd->mark();
271                                         _session.add_command(cmd);
272                                         _session.commit_reversible_command ();
273
274                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
275
276                                         // shift-click: set this route to solo safe
277
278                                         _route->set_solo_safe (!_route->solo_safe(), this);
279                                         wait_for_release = false;
280
281                                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
282
283                                         /* Primary-button1: solo mix group.
284                                            NOTE: Primary-button2 is MIDI learn.
285                                         */
286
287                                         if (ev->button == 1) {
288                                                 set_mix_group_solo (_route, !_route->soloed());
289                                         }
290
291                                 } else {
292
293                                         /* click: solo this route */
294                                         reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
295                                 }
296                         }
297                 }
298         }
299
300         return true;
301 }
302
303 bool
304 RouteUI::solo_release(GdkEventButton* ev)
305 {
306         if (!ignore_toggle) {
307                 if (wait_for_release) {
308                         wait_for_release = false;
309                         // undo the last op
310                         // because the press was the last undoable thing we did
311
312                         _session.undo (1U);
313                 }
314         }
315
316         return true;
317 }
318
319 bool
320 RouteUI::rec_enable_press(GdkEventButton* ev)
321 {
322         if (ev->type == GDK_2BUTTON_PRESS) {
323                 return true;
324         }
325
326         if (!_session.engine().connected()) {
327                 MessageDialog msg (_("Not connected to JACK - cannot engage record"));
328                 msg.run ();
329                 return true;
330         }
331
332         if (!ignore_toggle && is_track() && rec_enable_button) {
333
334                 if (ev->button == 2 && Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
335
336                         // do nothing on midi bind event
337                         return false;
338
339                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
340
341                         _session.begin_reversible_command (_("rec-enable change"));
342                         Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
343
344                         if (rec_enable_button->get_active()) {
345                                 _session.record_disenable_all ();
346                         } else {
347                                 _session.record_enable_all ();
348                         }
349
350                         cmd->mark();
351                         _session.add_command(cmd);
352                         _session.commit_reversible_command ();
353
354                 } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
355
356                         /* Primary-button1 applies change to the mix group.
357                            NOTE: Primary-button2 is MIDI learn.
358                         */
359
360                         set_mix_group_rec_enable (_route, !_route->record_enabled());
361
362                 } else {
363
364                         reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
365                 }
366         }
367
368         return true;
369 }
370
371 bool
372 RouteUI::rec_enable_release (GdkEventButton* ev)
373 {
374         return true;
375 }
376
377 void
378 RouteUI::solo_changed(void* src)
379 {
380         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
381 }
382
383 void
384 RouteUI::update_solo_display ()
385 {
386         bool x;
387         vector<Gdk::Color> fg_colors;
388         Gdk::Color c;
389         
390         if (solo_button->get_active() != (x = _route->soloed())){
391                 ignore_toggle = true;
392                 solo_button->set_active(x);
393                 ignore_toggle = false;
394         } 
395         
396         if (_route->solo_safe()) {
397                 solo_button->set_visual_state (2);
398         } else if (_route->soloed()) {
399                 solo_button->set_visual_state (1);
400         } else {
401                 solo_button->set_visual_state (0);
402         }
403 }
404
405 void
406 RouteUI::solo_changed_so_update_mute ()
407 {
408         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
409 }
410
411 void
412 RouteUI::mute_changed(void* src)
413 {
414         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
415 }
416
417 void
418 RouteUI::update_mute_display ()
419 {
420         bool model = _route->muted();
421         bool view = mute_button->get_active();
422
423         /* first make sure the button's "depressed" visual
424            is correct.
425         */
426
427         if (model != view) {
428                 ignore_toggle = true;
429                 mute_button->set_active (model);
430                 ignore_toggle = false;
431         }
432
433         /* now attend to visual state */
434         
435         if (Config->get_show_solo_mutes()) {
436                 if (_route->muted()) {
437                         mute_button->set_visual_state (2);
438                 } else if (!_route->soloed() && _route->solo_muted()) {
439                         
440                         mute_button->set_visual_state (1);
441                 } else {
442                         mute_button->set_visual_state (0);
443                 }
444         } else {
445                 if (_route->muted()) {
446                         mute_button->set_visual_state (2);
447                 } else {
448                         mute_button->set_visual_state (0);
449                 }
450         }
451
452 }
453
454 void
455 RouteUI::route_rec_enable_changed ()
456 {
457         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
458 }
459
460 void
461 RouteUI::session_rec_enable_changed ()
462 {
463         Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display));
464 }
465
466 void
467 RouteUI::update_rec_display ()
468 {
469         bool model = _route->record_enabled();
470         bool view = rec_enable_button->get_active();
471
472         /* first make sure the button's "depressed" visual
473            is correct.
474         */
475
476         if (model != view) {
477                 ignore_toggle = true;
478                 rec_enable_button->set_active (model);
479                 ignore_toggle = false;
480         }
481         
482         /* now make sure its color state is correct */
483
484         if (model) {
485
486                 switch (_session.record_status ()) {
487                 case Session::Recording:
488                         rec_enable_button->set_visual_state (1);
489                         break;
490
491                 case Session::Disabled:
492                 case Session::Enabled:
493                         rec_enable_button->set_visual_state (2);
494                         break;
495
496                 }
497
498         } else {
499                 rec_enable_button->set_visual_state (0);
500         }
501 }
502
503 void
504 RouteUI::build_remote_control_menu ()
505 {
506         remote_control_menu = manage (new Menu);
507         refresh_remote_control_menu ();
508 }
509
510 void
511 RouteUI::refresh_remote_control_menu ()
512 {
513         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
514
515         // only refresh the menu if it has been instantiated
516
517         if (remote_control_menu == 0) {
518                 return;
519         }
520
521         using namespace Menu_Helpers;
522
523         RadioMenuItem::Group rc_group;
524         CheckMenuItem* rc_active;
525         uint32_t limit = _session.ntracks() + _session.nbusses();
526         char buf[32];
527
528         MenuList& rc_items = remote_control_menu->items();
529         rc_items.clear ();
530
531         /* note that this menu list starts at zero, not 1, because zero
532            is a valid, if useless, ID.
533         */
534
535         limit += 4; /* leave some breathing room */
536         
537         rc_items.push_back (RadioMenuElem (rc_group, _("None")));
538         if (_route->remote_control_id() == 0) {
539                 rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
540                 rc_active->set_active ();
541         }
542                 
543         for (uint32_t i = 1; i < limit; ++i) {
544                 snprintf (buf, sizeof (buf), "%u", i);
545                 rc_items.push_back (RadioMenuElem (rc_group, buf));
546                 rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
547                 if (_route->remote_control_id() == i) {
548                         rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
549                         rc_active->set_active ();
550                 }
551                 rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
552         }
553 }
554
555 void
556 RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
557 {
558         /* this is called when the radio menu item is toggled, and so 
559            is actually invoked twice per menu selection. we only
560            care about the invocation for the item that was being
561            marked active.
562         */
563
564         if (item->get_active()) {
565                 _route->set_remote_control_id (id);
566         }
567 }
568
569 void
570 RouteUI::build_solo_menu (void)
571 {
572         using namespace Menu_Helpers;
573         
574         solo_menu = new Menu;
575         solo_menu->set_name ("ArdourContextMenu");
576         MenuList& items = solo_menu->items();
577         CheckMenuItem* check;
578
579         check = new CheckMenuItem(_("Solo-safe"));
580         check->set_active (_route->solo_safe());
581         check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
582         _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
583         items.push_back (CheckMenuElem(*check));
584         check->show_all();
585
586         //items.push_back (SeparatorElem());
587         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
588         
589 }
590
591 void
592 RouteUI::build_mute_menu(void)
593 {
594         using namespace Menu_Helpers;
595         
596         mute_menu = new Menu;
597         mute_menu->set_name ("ArdourContextMenu");
598         MenuList& items = mute_menu->items();
599         CheckMenuItem* check;
600         
601         check = new CheckMenuItem(_("Pre Fader"));
602         init_mute_menu(PRE_FADER, check);
603         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
604         _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
605         items.push_back (CheckMenuElem(*check));
606         check->show_all();
607
608         check = new CheckMenuItem(_("Post Fader"));
609         init_mute_menu(POST_FADER, check);
610         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
611         _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
612         items.push_back (CheckMenuElem(*check));
613         check->show_all();
614         
615         check = new CheckMenuItem(_("Control Outs"));
616         init_mute_menu(CONTROL_OUTS, check);
617         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
618         _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
619         items.push_back (CheckMenuElem(*check));
620         check->show_all();
621
622         check = new CheckMenuItem(_("Main Outs"));
623         init_mute_menu(MAIN_OUTS, check);
624         check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
625         _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
626         items.push_back (CheckMenuElem(*check));
627         check->show_all();
628
629         //items.push_back (SeparatorElem());
630         // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
631 }
632
633 void
634 RouteUI::init_mute_menu(mute_type type, CheckMenuItem* check)
635 {
636         if (_route->get_mute_config (type)) {
637                 check->set_active (true);
638         }
639 }
640
641 void
642 RouteUI::toggle_mute_menu(mute_type type, Gtk::CheckMenuItem* check)
643 {
644         _route->set_mute_config(type, check->get_active(), this);
645 }
646
647 void
648 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
649 {
650         _route->set_solo_safe (check->get_active(), this);
651 }
652
653 void
654 RouteUI::set_mix_group_solo(boost::shared_ptr<Route> route, bool yn)
655 {
656         RouteGroup* mix_group;
657
658         if((mix_group = route->mix_group()) != 0){
659                 _session.begin_reversible_command (_("mix group solo  change"));
660                 Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
661                 mix_group->apply(&Route::set_solo, yn, this);
662                 cmd->mark();
663                 _session.add_command (cmd);
664                 _session.commit_reversible_command ();
665         } else {
666                 reversibly_apply_route_boolean ("solo change", &Route::set_solo, !route->soloed(), this);
667         }
668 }
669
670 void
671 RouteUI::reversibly_apply_route_boolean (string name, void (Route::*func)(bool, void *), bool yn, void *arg)
672 {
673         _session.begin_reversible_command (name);
674         XMLNode &before = _route->get_state();
675         bind(mem_fun(*_route, func), yn, arg)();
676         XMLNode &after = _route->get_state();
677         _session.add_command (new MementoCommand<Route>(*_route, &before, &after));
678         _session.commit_reversible_command ();
679 }
680
681 void
682 RouteUI::reversibly_apply_track_boolean (string name, void (Track::*func)(bool, void *), bool yn, void *arg)
683 {
684         _session.begin_reversible_command (name);
685         XMLNode &before = track()->get_state();
686         bind (mem_fun (*track(), func), yn, arg)();
687         XMLNode &after = track()->get_state();
688         _session.add_command (new MementoCommand<Track>(*track(), &before, &after));
689         _session.commit_reversible_command ();
690 }
691
692 void
693 RouteUI::set_mix_group_mute(boost::shared_ptr<Route> route, bool yn)
694 {
695         RouteGroup* mix_group;
696
697         if((mix_group = route->mix_group()) != 0){
698                 _session.begin_reversible_command (_("mix group mute change"));
699                 Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand (_session, this);
700                 mix_group->apply(&Route::set_mute, yn, this);
701                 cmd->mark();
702                 _session.add_command(cmd);
703                 _session.commit_reversible_command ();
704         } else {
705                 reversibly_apply_route_boolean ("mute change", &Route::set_mute, !route->muted(), this);
706         }
707 }
708
709 void
710 RouteUI::set_mix_group_rec_enable(boost::shared_ptr<Route> route, bool yn)
711 {
712         RouteGroup* mix_group;
713
714         if((mix_group = route->mix_group()) != 0){
715                 _session.begin_reversible_command (_("mix group rec-enable change"));
716                 Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
717                 mix_group->apply (&Route::set_record_enable, yn, this);
718                 cmd->mark();
719                 _session.add_command(cmd);
720                 _session.commit_reversible_command ();
721         } else {
722                 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable, !_route->record_enabled(), this);
723         }
724 }
725
726
727 bool
728 RouteUI::choose_color()
729 {
730         bool picked;
731         Gdk::Color color;
732
733         color = Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked, &_color);
734
735         if (picked) {
736                 set_color (color);
737         }
738
739         return picked;
740 }
741
742 void
743 RouteUI::set_color (const Gdk::Color & c)
744 {
745         char buf[64];
746         
747         _color = c;
748         
749         ensure_xml_node ();
750         snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
751         xml_node->add_property ("color", buf);
752
753         _route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
754 }
755
756
757 void
758 RouteUI::ensure_xml_node ()
759 {
760         if (xml_node == 0) {
761                 if ((xml_node = _route->extra_xml ("GUI")) == 0) {
762                         xml_node = new XMLNode ("GUI");
763                         _route->add_extra_xml (*xml_node);
764                 }
765         }
766 }
767
768 XMLNode*
769 RouteUI::get_automation_child_xml_node (Parameter param)
770 {
771         ensure_xml_node ();
772         
773         XMLNodeList kids = xml_node->children();
774         XMLNodeConstIterator iter;
775
776         for (iter = kids.begin(); iter != kids.end(); ++iter) {
777                 if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
778                         XMLProperty* type = (*iter)->property("automation-id");
779                         if (type && type->value() == param.to_string())
780                                 return *iter;
781                 }
782         }
783
784         // Didn't find it, make a new one
785         XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
786         child->add_property("automation-id", param.to_string());
787         xml_node->add_child_nocopy (*child);
788
789         return child;
790 }
791
792 int
793 RouteUI::set_color_from_route ()
794 {
795         XMLProperty *prop;
796         
797         RouteUI::ensure_xml_node ();
798
799         if ((prop = xml_node->property ("color")) != 0) {
800                 int r, g, b;
801                 sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
802                 _color.set_red(r);
803                 _color.set_green(g);
804                 _color.set_blue(b);
805                 return 0;
806         } 
807         return 1;
808 }
809
810 void
811 RouteUI::remove_this_route ()
812 {
813         vector<string> choices;
814         string prompt;
815
816         if (is_track()) {
817                 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());
818         } else {
819                 prompt  = string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route->name());
820         }
821
822         choices.push_back (_("No, do nothing."));
823         choices.push_back (_("Yes, remove it."));
824
825         Choice prompter (prompt, choices);
826
827         if (prompter.run () == 1) {
828                 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
829         }
830 }
831
832 gint
833 RouteUI::idle_remove_this_route (RouteUI *rui)
834 {
835         rui->_session.remove_route (rui->_route);
836         return FALSE;
837 }
838
839 void
840 RouteUI::route_rename ()
841 {
842         ArdourPrompter name_prompter (true);
843         string result;
844         name_prompter.set_prompt (_("New Name: "));
845         name_prompter.set_initial_text (_route->name());
846         name_prompter.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT);
847         name_prompter.set_response_sensitive (Gtk::RESPONSE_ACCEPT, false);
848         name_prompter.show_all ();
849
850         switch (name_prompter.run ()) {
851
852         case Gtk::RESPONSE_ACCEPT:
853         name_prompter.get_result (result);
854         if (result.length()) {
855                         _route->set_name (result);
856                 }       
857                 break;
858         }
859
860         return;
861   
862 }
863
864 void
865 RouteUI::name_changed ()
866 {
867         ENSURE_GUI_THREAD(sigc::mem_fun(*this, &RouteUI::name_changed));
868
869         name_label.set_text (_route->name());
870 }
871
872 void
873 RouteUI::toggle_route_active ()
874 {
875         bool yn;
876
877         if (route_active_menu_item) {
878                 if (route_active_menu_item->get_active() != (yn = _route->active())) {
879                         _route->set_active (!yn);
880                 }
881         }
882 }
883
884 void
885 RouteUI::route_active_changed ()
886 {
887         if (route_active_menu_item) {
888                 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item, &CheckMenuItem::set_active), _route->active()));
889         }
890 }
891
892 void
893 RouteUI::toggle_polarity ()
894 {
895         if (polarity_menu_item) {
896
897                 bool x;
898
899                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
900                 
901                 if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
902                         _route->set_phase_invert (x, this);
903                         if (x) {
904                                 name_label.set_text (X_("Ø ") + name_label.get_text());
905                         } else {
906                                 name_label.set_text (_route->name());
907                         }
908                 }
909         }
910 }
911
912 void
913 RouteUI::polarity_changed ()
914 {
915         /* no signal for this yet */
916 }
917
918 void
919 RouteUI::toggle_denormal_protection ()
920 {
921         if (denormal_menu_item) {
922
923                 bool x;
924
925                 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
926                 
927                 if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
928                         _route->set_denormal_protection (x, this);
929                 }
930         }
931 }
932
933 void
934 RouteUI::denormal_protection_changed ()
935 {
936         /* no signal for this yet */
937 }
938
939
940 void
941 RouteUI::solo_safe_toggle(void* src, Gtk::CheckMenuItem* check)
942 {
943         bool yn = _route->solo_safe ();
944
945         if (check->get_active() != yn) {
946                 check->set_active (yn);
947         }
948 }
949 void
950 RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
951 {
952         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
953         
954         bool yn = _route->get_mute_config(PRE_FADER);
955         if (check->get_active() != yn) {
956                 check->set_active (yn);
957         }
958 }
959
960 void
961 RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
962 {
963         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
964         
965         bool yn = _route->get_mute_config(POST_FADER);
966         if (check->get_active() != yn) {
967                 check->set_active (yn);
968         }
969 }
970
971 void
972 RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
973 {
974         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
975         
976         bool yn = _route->get_mute_config(CONTROL_OUTS);
977         if (check->get_active() != yn) {
978                 check->set_active (yn);
979         }
980 }
981
982 void
983 RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
984 {
985         ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
986         
987         bool yn = _route->get_mute_config(MAIN_OUTS);
988         if (check->get_active() != yn) {
989                 check->set_active (yn);
990         }
991 }
992
993 void
994 RouteUI::disconnect_input ()
995 {
996         _route->disconnect_inputs (this);
997 }
998
999 void
1000 RouteUI::disconnect_output ()
1001 {
1002         _route->disconnect_outputs (this);
1003 }
1004
1005 bool
1006 RouteUI::is_track () const
1007 {
1008         return boost::dynamic_pointer_cast<Track>(_route) != 0;
1009 }
1010
1011 boost::shared_ptr<Track>
1012 RouteUI::track() const
1013 {
1014         return boost::dynamic_pointer_cast<Track>(_route);
1015 }
1016
1017 bool
1018 RouteUI::is_audio_track () const
1019 {
1020         return boost::dynamic_pointer_cast<AudioTrack>(_route) != 0;
1021 }
1022
1023 boost::shared_ptr<AudioTrack>
1024 RouteUI::audio_track() const
1025 {
1026         return boost::dynamic_pointer_cast<AudioTrack>(_route);
1027 }
1028
1029 bool
1030 RouteUI::is_midi_track () const
1031 {
1032         return boost::dynamic_pointer_cast<MidiTrack>(_route) != 0;
1033 }
1034
1035 boost::shared_ptr<MidiTrack>
1036 RouteUI::midi_track() const
1037 {
1038         return boost::dynamic_pointer_cast<MidiTrack>(_route);
1039 }
1040
1041 boost::shared_ptr<Diskstream>
1042 RouteUI::get_diskstream () const
1043 {
1044         boost::shared_ptr<Track> t;
1045
1046         if ((t = boost::dynamic_pointer_cast<Track>(_route)) != 0) {
1047                 return t->diskstream();
1048         } else {
1049                 return boost::shared_ptr<Diskstream> ((Diskstream*) 0);
1050         }
1051 }
1052
1053 string
1054 RouteUI::name() const
1055 {
1056         return _route->name();
1057 }
1058
1059 void
1060 RouteUI::map_frozen ()
1061 {
1062         ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen));
1063
1064         AudioTrack* at = dynamic_cast<AudioTrack*>(_route.get());
1065
1066         if (at) {
1067                 switch (at->freeze_state()) {
1068                 case AudioTrack::Frozen:
1069                         rec_enable_button->set_sensitive (false);
1070                         break;
1071                 default:
1072                         rec_enable_button->set_sensitive (true);
1073                         break;
1074                 }
1075         }
1076 }
1077
1078 void
1079 RouteUI::adjust_latency ()
1080 {
1081         LatencyDialog dialog (_route->name() + _("latency"), *(_route.get()), _session.frame_rate(), _session.engine().frames_per_cycle());
1082 }