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