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