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