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