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