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