2 Copyright (C) 2002-2006 Paul Davis
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.
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.
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.
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 #include <gtkmm2ext/prompter.h>
28 #include <ardour/route_group.h>
29 #include <pbd/memento_command.h>
30 #include <pbd/stacktrace.h>
31 #include <pbd/shiva.h>
37 #include "gui_thread.h"
39 #include <ardour/route.h>
40 #include <ardour/session.h>
41 #include <ardour/audioengine.h>
42 #include <ardour/audio_track.h>
43 #include <ardour/audio_diskstream.h>
44 #include <ardour/profile.h>
45 #include <ardour/utils.h>
50 using namespace Gtkmm2ext
;
51 using namespace ARDOUR
;
54 RouteUI::RouteUI (ARDOUR::Session
& sess
, const char* mute_name
, const char* solo_name
, const char* rec_name
)
58 set_button_names (mute_name
, solo_name
, rec_name
);
61 RouteUI::RouteUI (boost::shared_ptr
<ARDOUR::Route
> rt
,
62 ARDOUR::Session
& sess
, const char* mute_name
, const char* solo_name
, const char* rec_name
)
66 set_button_names (mute_name
, solo_name
, rec_name
);
77 remote_control_menu
= 0;
78 ignore_toggle
= false;
79 wait_for_release
= false;
80 route_active_menu_item
= 0;
81 was_solo_safe
= false;
82 polarity_menu_item
= 0;
83 denormal_menu_item
= 0;
84 multiple_mute_change
= false;
85 multiple_solo_change
= false;
87 mute_button
= manage (new BindableToggleButton (0, ""));
88 mute_button
->set_self_managed (true);
89 mute_button
->set_name ("MuteButton");
90 UI::instance()->set_tip (mute_button
, _("Mute this track"), "");
92 solo_button
= manage (new BindableToggleButton (0, ""));
93 solo_button
->set_self_managed (true);
94 solo_button
->set_name ("SoloButton");
95 UI::instance()->set_tip (solo_button
, _("Mute other (non-soloed) tracks"), "");
97 rec_enable_button
= manage (new BindableToggleButton (0, ""));
98 rec_enable_button
->set_name ("RecordEnableButton");
99 rec_enable_button
->set_self_managed (true);
100 UI::instance()->set_tip (rec_enable_button
, _("Enable recording on this track"), "");
102 _session
.SoloChanged
.connect (mem_fun(*this, &RouteUI::solo_changed_so_update_mute
));
108 connections
.clear ();
121 /* do not delete the node - its owned by the route */
125 route_active_menu_item
= 0;
126 polarity_menu_item
= 0;
127 denormal_menu_item
= 0;
131 RouteUI::set_button_names (const char* mute
, const char* solo
, const char* rec
)
139 RouteUI::set_route (boost::shared_ptr
<Route
> rp
)
145 if (set_color_from_route()) {
146 set_color (unique_random_color());
149 /* no, there is no memory leak here. This object cleans itself (and other stuff)
150 up when the route is destroyed.
154 new PairedShiva
<Route
,RouteUI
> (*_route
, *this);
157 mute_button
->set_controllable (&_route
->mute_control());
158 mute_button
->set_label (m_name
);
160 solo_button
->set_controllable (&_route
->solo_control());
161 solo_button
->set_label (s_name
);
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
)));
168 /* when solo changes, update mute state too, in case the user wants us to display it */
170 update_solo_display ();
171 update_mute_display ();
173 if (_session
.writable() && is_track()) {
174 boost::shared_ptr
<Track
> t
= boost::dynamic_pointer_cast
<Track
>(_route
);
176 connections
.push_back (t
->diskstream()->RecordEnableChanged
.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed
)));
178 connections
.push_back (_session
.RecordStateChanged
.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed
)));
180 rec_enable_button
->set_controllable (&t
->rec_enable_control());
181 rec_enable_button
->set_label (r_name
);
183 update_rec_display ();
186 connections
.push_back (_route
->RemoteControlIDChanged
.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu
)));
188 /* map the current state */
195 /* derived classes should emit GoingAway so that they receive the signal
196 when the object is still a legal derived instance.
207 /* Note: the remote control menu is constructed
208 by derived classes (e.g. MixerStrip or RouteTimeAxis) and
209 is always attached to a context menu. It then becomes
210 owned by that menu, and will deleted along with it. We
211 do not need to take care of it here.
216 RouteUI::mute_press(GdkEventButton
* ev
)
218 if (ev
->type
== GDK_2BUTTON_PRESS
|| ev
->type
== GDK_3BUTTON_PRESS
) {
221 multiple_mute_change
= false;
222 if (!ignore_toggle
) {
224 if (Keyboard::is_context_menu_event (ev
)) {
230 mute_menu
->popup(0,ev
->time
);
234 if (Keyboard::is_button2_event (ev
)) {
236 if (mute_button
->on_button_press_event (ev
)) {
239 // button2-click is "momentary"
240 wait_for_release
= true;
244 if (ev
->button
== 1 || Keyboard::is_button2_event (ev
)) {
246 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::ModifierMask (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
))) {
248 /* Primary-Tertiary-click applies change to all routes */
250 _session
.begin_reversible_command (_("mute change"));
251 Session::GlobalMuteStateCommand
*cmd
= new Session::GlobalMuteStateCommand(_session
, this);
252 _session
.set_all_mute (!_route
->muted());
254 _session
.add_command(cmd
);
255 _session
.commit_reversible_command ();
256 multiple_mute_change
= true;
258 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
260 /* Primary-button1 applies change to the mix group.
261 NOTE: Primary-button2 is MIDI learn.
264 if (ev
->button
== 1) {
265 set_mix_group_mute (_route
, !_route
->muted());
270 /* plain click applies change to this route */
271 if (wait_for_release
) {
272 _route
->set_mute (!_route
->muted(), this);
274 reversibly_apply_route_boolean ("mute change", &Route::set_mute
, !_route
->muted(), this);
286 RouteUI::mute_release(GdkEventButton
* ev
)
288 if (!ignore_toggle
) {
289 if (wait_for_release
){
290 wait_for_release
= false;
291 if (multiple_mute_change
) {
292 multiple_mute_change
= false;
294 // because the press was the last undoable thing we did
297 _route
->set_mute (!_route
->muted(), this);
305 RouteUI::solo_press(GdkEventButton
* ev
)
307 /* ignore double/triple clicks */
309 if (ev
->type
== GDK_2BUTTON_PRESS
|| ev
->type
== GDK_3BUTTON_PRESS
) {
312 multiple_solo_change
= false;
313 if (!ignore_toggle
) {
315 if (Keyboard::is_context_menu_event (ev
)) {
317 if (solo_menu
== 0) {
321 solo_menu
->popup (1, ev
->time
);
325 if (Keyboard::is_button2_event (ev
)) {
327 if (solo_button
->on_button_press_event (ev
)) {
330 // button2-click is "momentary"
331 wait_for_release
= true;
335 if (ev
->button
== 1 || Keyboard::is_button2_event (ev
)) {
337 if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::ModifierMask (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
))) {
339 /* Primary-Tertiary-click applies change to all routes */
340 bool was_not_latched
= false;
341 if (!Config
->get_solo_latched ()) {
342 was_not_latched
= true;
344 XXX it makes no sense to solo all tracks if we're
345 not in latched mode, but doing nothing feels like a bug,
348 Config
->set_solo_latched (true);
350 _session
.begin_reversible_command (_("solo change"));
351 Session::GlobalSoloStateCommand
*cmd
= new Session::GlobalSoloStateCommand(_session
, this);
352 _session
.set_all_solo (!_route
->soloed());
354 _session
.add_command (cmd
);
355 _session
.commit_reversible_command ();
356 multiple_solo_change
= true;
357 if (was_not_latched
) {
358 Config
->set_solo_latched (false);
361 } else if (Keyboard::modifier_state_contains (ev
->state
, Keyboard::ModifierMask (Keyboard::PrimaryModifier
|Keyboard::SecondaryModifier
))) {
363 // Primary-Secondary-click: exclusively solo this track, not a toggle */
365 _session
.begin_reversible_command (_("solo change"));
366 Session::GlobalSoloStateCommand
*cmd
= new Session::GlobalSoloStateCommand (_session
, this);
367 _session
.set_all_solo (false);
368 _route
->set_solo (true, this);
370 _session
.add_command(cmd
);
371 _session
.commit_reversible_command ();
373 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::TertiaryModifier
)) {
375 // shift-click: set this route to solo safe
377 if (Profile
->get_sae() && ev
->button
== 1) {
378 // button 1 and shift-click: disables solo_latched for this click
379 if (!Config
->get_solo_latched ()) {
380 Config
->set_solo_latched (true);
381 reversibly_apply_route_boolean ("solo change", &Route::set_solo
, !_route
->soloed(), this);
382 Config
->set_solo_latched (false);
385 _route
->set_solo_safe (!_route
->solo_safe(), this);
386 wait_for_release
= false;
389 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
391 /* Primary-button1: solo mix group.
392 NOTE: Primary-button2 is MIDI learn.
395 if (ev
->button
== 1) {
396 set_mix_group_solo (_route
, !_route
->soloed());
401 /* click: solo this route */
402 if (wait_for_release
) {
403 _route
->set_solo (!_route
->soloed(), this);
405 reversibly_apply_route_boolean ("solo change", &Route::set_solo
, !_route
->soloed(), this);
416 RouteUI::solo_release(GdkEventButton
* ev
)
418 if (!ignore_toggle
) {
419 if (wait_for_release
) {
420 wait_for_release
= false;
421 if (multiple_solo_change
) {
422 multiple_solo_change
= false;
424 // because the press was the last undoable thing we did
427 // we don't use "undo the last op"
428 // here because its expensive for the GUI
429 _route
->set_solo (!_route
->soloed(), this);
438 RouteUI::rec_enable_press(GdkEventButton
* ev
)
440 if (ev
->type
== GDK_2BUTTON_PRESS
|| ev
->type
== GDK_3BUTTON_PRESS
) {
444 if (!_session
.engine().connected()) {
445 MessageDialog
msg (_("Not connected to JACK - cannot engage record"));
450 if (!ignore_toggle
&& is_track() && rec_enable_button
) {
452 if (Keyboard::is_button2_event (ev
)) {
454 return rec_enable_button
->on_button_press_event (ev
);
456 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::ModifierMask (Keyboard::PrimaryModifier
|Keyboard::TertiaryModifier
))) {
458 _session
.begin_reversible_command (_("rec-enable change"));
459 Session::GlobalRecordEnableStateCommand
*cmd
= new Session::GlobalRecordEnableStateCommand(_session
, this);
461 if (rec_enable_button
->get_active()) {
462 _session
.record_disenable_all ();
464 _session
.record_enable_all ();
468 _session
.add_command(cmd
);
469 _session
.commit_reversible_command ();
471 } else if (Keyboard::modifier_state_equals (ev
->state
, Keyboard::PrimaryModifier
)) {
473 /* Primary-button1 applies change to the mix group.
474 NOTE: Primary-button2 is MIDI learn.
477 set_mix_group_rec_enable (_route
, !_route
->record_enabled());
481 reversibly_apply_audio_track_boolean ("rec-enable change", &AudioTrack::set_record_enable
, !audio_track()->record_enabled(), this);
489 RouteUI::rec_enable_release (GdkEventButton
* ev
)
495 RouteUI::solo_changed(void* src
)
498 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display
));
502 RouteUI::update_solo_display ()
505 vector
<Gdk::Color
> fg_colors
;
508 if (solo_button
->get_active() != (x
= _route
->soloed())){
509 ignore_toggle
= true;
510 solo_button
->set_active(x
);
511 ignore_toggle
= false;
514 if (_route
->solo_safe()) {
515 solo_button
->set_visual_state (2);
516 } else if (_route
->soloed()) {
517 solo_button
->set_visual_state (1);
519 solo_button
->set_visual_state (0);
524 RouteUI::solo_changed_so_update_mute ()
526 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display
));
530 RouteUI::mute_changed(void* src
)
532 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display
));
536 RouteUI::update_mute_display ()
538 bool model
= _route
->muted();
539 bool view
= mute_button
->get_active();
541 /* first make sure the button's "depressed" visual
546 ignore_toggle
= true;
547 mute_button
->set_active (model
);
548 ignore_toggle
= false;
551 /* now attend to visual state */
553 if (Config
->get_show_solo_mutes()) {
554 if (_route
->muted()) {
555 mute_button
->set_visual_state (2);
556 } else if (!_route
->soloed() && _route
->solo_muted()) {
558 mute_button
->set_visual_state (1);
560 mute_button
->set_visual_state (0);
563 if (_route
->muted()) {
564 mute_button
->set_visual_state (2);
566 mute_button
->set_visual_state (0);
573 RouteUI::route_rec_enable_changed ()
575 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display
));
579 RouteUI::session_rec_enable_changed ()
581 Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_rec_display
));
585 RouteUI::update_rec_display ()
587 bool model
= _route
->record_enabled();
588 bool view
= rec_enable_button
->get_active();
590 /* first make sure the button's "depressed" visual
595 ignore_toggle
= true;
596 rec_enable_button
->set_active (model
);
597 ignore_toggle
= false;
600 /* now make sure its color state is correct */
604 switch (_session
.record_status ()) {
605 case Session::Recording
:
606 rec_enable_button
->set_visual_state (1);
609 case Session::Disabled
:
610 case Session::Enabled
:
611 rec_enable_button
->set_visual_state (2);
617 rec_enable_button
->set_visual_state (0);
622 RouteUI::build_remote_control_menu ()
624 remote_control_menu
= new Menu
;
625 refresh_remote_control_menu ();
629 RouteUI::refresh_remote_control_menu ()
631 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu
));
633 // only refresh the menu if it has been instantiated
635 if (remote_control_menu
== 0) {
639 using namespace Menu_Helpers
;
641 RadioMenuItem::Group rc_group
;
642 CheckMenuItem
* rc_active
;
643 uint32_t limit
= _session
.ntracks() + _session
.nbusses();
646 MenuList
& rc_items
= remote_control_menu
->items();
649 /* note that this menu list starts at zero, not 1, because zero
650 is a valid, if useless, ID.
653 limit
+= 4; /* leave some breathing room */
655 rc_items
.push_back (RadioMenuElem (rc_group
, _("None")));
656 if (_route
->remote_control_id() == 0) {
657 rc_active
= dynamic_cast<CheckMenuItem
*> (&rc_items
.back());
658 rc_active
->set_active ();
661 for (uint32_t i
= 1; i
< limit
; ++i
) {
662 snprintf (buf
, sizeof (buf
), "%u", i
);
663 rc_items
.push_back (RadioMenuElem (rc_group
, buf
));
664 rc_active
= dynamic_cast<RadioMenuItem
*>(&rc_items
.back());
665 if (_route
->remote_control_id() == i
) {
666 rc_active
= dynamic_cast<CheckMenuItem
*> (&rc_items
.back());
667 rc_active
->set_active ();
669 rc_active
->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id
), i
, rc_active
));
674 RouteUI::set_remote_control_id (uint32_t id
, CheckMenuItem
* item
)
676 /* this is called when the radio menu item is toggled, and so
677 is actually invoked twice per menu selection. we only
678 care about the invocation for the item that was being
682 if (item
->get_active()) {
683 _route
->set_remote_control_id (id
);
688 RouteUI::build_solo_menu (void)
690 using namespace Menu_Helpers
;
692 solo_menu
= new Menu
;
693 solo_menu
->set_name ("ArdourContextMenu");
694 MenuList
& items
= solo_menu
->items();
695 CheckMenuItem
* check
;
697 check
= new CheckMenuItem(_("Solo Lock"));
698 check
->set_active (_route
->solo_safe());
699 check
->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe
), check
));
700 _route
->solo_safe_changed
.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle
), check
));
701 items
.push_back (CheckMenuElem(*check
));
704 //items.push_back (SeparatorElem());
705 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
710 RouteUI::build_mute_menu(void)
712 using namespace Menu_Helpers
;
714 mute_menu
= new Menu
;
715 mute_menu
->set_name ("ArdourContextMenu");
716 MenuList
& items
= mute_menu
->items();
717 CheckMenuItem
* check
;
719 check
= new CheckMenuItem(_("Pre Fader"));
720 init_mute_menu(PRE_FADER
, check
);
721 check
->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu
), PRE_FADER
, check
));
722 _route
->pre_fader_changed
.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle
), check
));
723 items
.push_back (CheckMenuElem(*check
));
726 check
= new CheckMenuItem(_("Post Fader"));
727 init_mute_menu(POST_FADER
, check
);
728 check
->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu
), POST_FADER
, check
));
729 _route
->post_fader_changed
.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle
), check
));
730 items
.push_back (CheckMenuElem(*check
));
733 check
= new CheckMenuItem(_("Control Outs"));
734 init_mute_menu(CONTROL_OUTS
, check
);
735 check
->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu
), CONTROL_OUTS
, check
));
736 _route
->control_outs_changed
.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle
), check
));
737 items
.push_back (CheckMenuElem(*check
));
740 check
= new CheckMenuItem(_("Main Outs"));
741 init_mute_menu(MAIN_OUTS
, check
);
742 check
->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu
), MAIN_OUTS
, check
));
743 _route
->main_outs_changed
.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle
), check
));
744 items
.push_back (CheckMenuElem(*check
));
747 //items.push_back (SeparatorElem());
748 // items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
752 RouteUI::init_mute_menu(mute_type type
, CheckMenuItem
* check
)
754 if (_route
->get_mute_config (type
)) {
755 check
->set_active (true);
760 RouteUI::toggle_mute_menu(mute_type type
, Gtk::CheckMenuItem
* check
)
762 _route
->set_mute_config(type
, check
->get_active(), this);
766 RouteUI::toggle_solo_safe (Gtk::CheckMenuItem
* check
)
768 _route
->set_solo_safe (check
->get_active(), this);
772 RouteUI::set_mix_group_solo(boost::shared_ptr
<Route
> route
, bool yn
)
774 RouteGroup
* mix_group
;
776 if((mix_group
= route
->mix_group()) != 0){
777 _session
.begin_reversible_command (_("mix group solo change"));
778 Session::GlobalSoloStateCommand
*cmd
= new Session::GlobalSoloStateCommand(_session
, this);
779 mix_group
->apply(&Route::set_solo
, yn
, this);
781 _session
.add_command (cmd
);
782 _session
.commit_reversible_command ();
784 reversibly_apply_route_boolean ("solo change", &Route::set_solo
, !route
->soloed(), this);
789 RouteUI::reversibly_apply_route_boolean (string name
, void (Route::*func
)(bool, void *), bool yn
, void *arg
)
791 _session
.begin_reversible_command (name
);
792 XMLNode
&before
= _route
->get_state();
793 bind(mem_fun(*_route
, func
), yn
, arg
)();
794 XMLNode
&after
= _route
->get_state();
795 _session
.add_command (new MementoCommand
<Route
>(*_route
, &before
, &after
));
796 _session
.commit_reversible_command ();
800 RouteUI::reversibly_apply_audio_track_boolean (string name
, void (AudioTrack::*func
)(bool, void *), bool yn
, void *arg
)
802 _session
.begin_reversible_command (name
);
803 XMLNode
&before
= audio_track()->get_state();
804 bind (mem_fun (*audio_track(), func
), yn
, arg
)();
805 XMLNode
&after
= audio_track()->get_state();
806 _session
.add_command (new MementoCommand
<AudioTrack
>(*audio_track(), &before
, &after
));
807 _session
.commit_reversible_command ();
811 RouteUI::set_mix_group_mute(boost::shared_ptr
<Route
> route
, bool yn
)
813 RouteGroup
* mix_group
;
815 if((mix_group
= route
->mix_group()) != 0){
816 _session
.begin_reversible_command (_("mix group mute change"));
817 Session::GlobalMuteStateCommand
*cmd
= new Session::GlobalMuteStateCommand (_session
, this);
818 mix_group
->apply(&Route::set_mute
, yn
, this);
820 _session
.add_command(cmd
);
821 _session
.commit_reversible_command ();
823 reversibly_apply_route_boolean ("mute change", &Route::set_mute
, !route
->muted(), this);
828 RouteUI::set_mix_group_rec_enable(boost::shared_ptr
<Route
> route
, bool yn
)
830 RouteGroup
* mix_group
;
832 if((mix_group
= route
->mix_group()) != 0){
833 _session
.begin_reversible_command (_("mix group rec-enable change"));
834 Session::GlobalRecordEnableStateCommand
*cmd
= new Session::GlobalRecordEnableStateCommand(_session
, this);
835 mix_group
->apply (&Route::set_record_enable
, yn
, this);
837 _session
.add_command(cmd
);
838 _session
.commit_reversible_command ();
840 reversibly_apply_route_boolean ("rec-enable change", &Route::set_record_enable
, !_route
->record_enabled(), this);
846 RouteUI::choose_color()
851 color
= Gtkmm2ext::UI::instance()->get_color (_("ardour: color selection"), picked
, &_color
);
861 RouteUI::set_color (const Gdk::Color
& c
)
868 snprintf (buf
, sizeof (buf
), "%d:%d:%d", c
.get_red(), c
.get_green(), c
.get_blue());
869 xml_node
->add_property ("color", buf
);
871 _route
->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
876 RouteUI::ensure_xml_node ()
879 if ((xml_node
= _route
->extra_xml ("GUI")) == 0) {
880 xml_node
= new XMLNode ("GUI");
881 _route
->add_extra_xml (*xml_node
);
887 RouteUI::get_child_xml_node (const string
& childname
)
894 if ((child
= find_named_node (*xml_node
, childname
)) == 0) {
895 child
= new XMLNode (childname
);
896 xml_node
->add_child_nocopy (*child
);
903 RouteUI::set_color_from_route ()
907 RouteUI::ensure_xml_node ();
909 if ((prop
= xml_node
->property ("color")) != 0) {
911 sscanf (prop
->value().c_str(), "%d:%d:%d", &r
, &g
, &b
);
921 RouteUI::remove_this_route ()
923 vector
<string
> choices
;
927 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());
929 prompt
= string_compose (_("Do you really want to remove bus \"%1\" ?\n(cannot be undone)"), _route
->name());
932 choices
.push_back (_("No, do nothing."));
933 choices
.push_back (_("Yes, remove it."));
935 Choice
prompter (prompt
, choices
);
937 if (prompter
.run () == 1) {
938 Glib::signal_idle().connect (bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route
), this));
943 RouteUI::idle_remove_this_route (RouteUI
*rui
)
945 rui
->_session
.remove_route (rui
->_route
);
950 RouteUI::route_rename ()
952 ArdourPrompter
name_prompter (true);
954 name_prompter
.set_prompt (_("New Name: "));
955 name_prompter
.set_initial_text (_route
->name());
956 name_prompter
.add_button (_("Rename"), Gtk::RESPONSE_ACCEPT
);
957 name_prompter
.set_response_sensitive (Gtk::RESPONSE_ACCEPT
, false);
958 name_prompter
.show_all ();
960 switch (name_prompter
.run ()) {
962 case Gtk::RESPONSE_ACCEPT
:
963 name_prompter
.get_result (result
);
964 if (result
.length()) {
965 _route
->set_name (result
, this);
975 RouteUI::name_changed (void *src
)
977 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::name_changed
), src
));
979 name_label
.set_text (_route
->name());
983 RouteUI::toggle_route_active ()
987 if (route_active_menu_item
) {
988 if (route_active_menu_item
->get_active() != (yn
= _route
->active())) {
989 _route
->set_active (!yn
);
995 RouteUI::route_active_changed ()
997 if (route_active_menu_item
) {
998 Gtkmm2ext::UI::instance()->call_slot (bind (mem_fun (*route_active_menu_item
, &CheckMenuItem::set_active
), _route
->active()));
1003 RouteUI::toggle_polarity ()
1005 if (polarity_menu_item
) {
1009 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity
));
1011 if ((x
= polarity_menu_item
->get_active()) != _route
->phase_invert()) {
1012 _route
->set_phase_invert (x
, this);
1014 name_label
.set_text (X_("Ø ") + name_label
.get_text());
1016 name_label
.set_text (_route
->name());
1023 RouteUI::polarity_changed ()
1025 /* no signal for this yet */
1029 RouteUI::toggle_denormal_protection ()
1031 if (denormal_menu_item
) {
1035 ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection
));
1037 if ((x
= denormal_menu_item
->get_active()) != _route
->denormal_protection()) {
1038 _route
->set_denormal_protection (x
, this);
1044 RouteUI::denormal_protection_changed ()
1046 /* no signal for this yet */
1051 RouteUI::solo_safe_toggle(void* src
, Gtk::CheckMenuItem
* check
)
1053 bool yn
= _route
->solo_safe ();
1055 if (check
->get_active() != yn
) {
1056 check
->set_active (yn
);
1060 RouteUI::pre_fader_toggle(void* src
, Gtk::CheckMenuItem
* check
)
1062 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle
), src
, check
));
1064 bool yn
= _route
->get_mute_config(PRE_FADER
);
1065 if (check
->get_active() != yn
) {
1066 check
->set_active (yn
);
1071 RouteUI::post_fader_toggle(void* src
, Gtk::CheckMenuItem
* check
)
1073 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle
), src
, check
));
1075 bool yn
= _route
->get_mute_config(POST_FADER
);
1076 if (check
->get_active() != yn
) {
1077 check
->set_active (yn
);
1082 RouteUI::control_outs_toggle(void* src
, Gtk::CheckMenuItem
* check
)
1084 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle
), src
, check
));
1086 bool yn
= _route
->get_mute_config(CONTROL_OUTS
);
1087 if (check
->get_active() != yn
) {
1088 check
->set_active (yn
);
1093 RouteUI::main_outs_toggle(void* src
, Gtk::CheckMenuItem
* check
)
1095 ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle
), src
, check
));
1097 bool yn
= _route
->get_mute_config(MAIN_OUTS
);
1098 if (check
->get_active() != yn
) {
1099 check
->set_active (yn
);
1104 RouteUI::disconnect_input ()
1106 _route
->disconnect_inputs (this);
1110 RouteUI::disconnect_output ()
1112 _route
->disconnect_outputs (this);
1116 RouteUI::is_track () const
1118 return boost::dynamic_pointer_cast
<Track
>(_route
) != 0;
1121 boost::shared_ptr
<Track
>
1122 RouteUI::track() const
1124 return boost::dynamic_pointer_cast
<Track
>(_route
);
1128 RouteUI::is_audio_track () const
1130 return boost::dynamic_pointer_cast
<AudioTrack
>(_route
) != 0;
1133 boost::shared_ptr
<AudioTrack
>
1134 RouteUI::audio_track() const
1136 return boost::dynamic_pointer_cast
<AudioTrack
>(_route
);
1139 boost::shared_ptr
<Diskstream
>
1140 RouteUI::get_diskstream () const
1142 boost::shared_ptr
<Track
> t
;
1144 if ((t
= boost::dynamic_pointer_cast
<Track
>(_route
)) != 0) {
1145 return t
->diskstream();
1147 return boost::shared_ptr
<Diskstream
> ((Diskstream
*) 0);
1152 RouteUI::name() const
1154 return _route
->name();
1158 RouteUI::map_frozen ()
1160 ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::map_frozen
));
1162 AudioTrack
* at
= dynamic_cast<AudioTrack
*>(_route
.get());
1165 switch (at
->freeze_state()) {
1166 case AudioTrack::Frozen
:
1167 rec_enable_button
->set_sensitive (false);
1170 rec_enable_button
->set_sensitive (true);
1177 RouteUI::save_as_template ()
1180 Glib::ustring safe_name
;
1183 path
= Session::route_template_dir();
1185 if (g_mkdir_with_parents (path
.c_str(), 0755)) {
1186 error
<< string_compose (_("Cannot create route template directory %1"), path
) << endmsg
;
1190 Prompter
p (true); // modal
1192 p
.set_prompt (_("Template name:"));
1194 case RESPONSE_ACCEPT
:
1201 p
.get_result (name
, true);
1203 safe_name
= legalize_for_path (name
);
1204 safe_name
+= Session::template_suffix ();
1206 path
= Glib::build_filename (path
, safe_name
);
1208 _route
->save_as_template (path
, name
);