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