/*
- Copyright (C) 2002-2006 Paul Davis
+ Copyright (C) 2002-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <gtkmm2ext/gtk_ui.h>
#include "ardour/route_group.h"
+#include "ardour/dB.h"
#include "pbd/memento_command.h"
#include "pbd/stacktrace.h"
#include "pbd/shiva.h"
#include "pbd/controllable.h"
+#include "pbd/enumwriter.h"
#include "ardour_ui.h"
#include "editor.h"
#include "latency_gui.h"
#include "mixer_strip.h"
#include "automation_time_axis.h"
+#include "route_time_axis.h"
#include "ardour/route.h"
+#include "ardour/event_type_map.h"
#include "ardour/session.h"
#include "ardour/audioengine.h"
#include "ardour/audio_track.h"
/* derived classes should emit GoingAway so that they receive the signal
when the object is still a legal derived instance.
*/
-
+
delete solo_menu;
delete mute_menu;
- delete remote_control_menu;
delete sends_menu;
}
xml_node = 0;
mute_menu = 0;
solo_menu = 0;
- remote_control_menu = 0;
sends_menu = 0;
+ pre_fader_mute_check = 0;
+ post_fader_mute_check = 0;
+ listen_mute_check = 0;
+ main_mute_check = 0;
ignore_toggle = false;
wait_for_release = false;
route_active_menu_item = 0;
delete mute_menu;
mute_menu = 0;
-
+
if (xml_node) {
/* do not delete the node - its owned by the route */
xml_node = 0;
mute_button->set_controllable (_route->mute_control());
solo_button->set_controllable (_route->solo_control());
-
+
connections.push_back (_route->active_changed.connect (mem_fun (*this, &RouteUI::route_active_changed)));
connections.push_back (_route->mute_changed.connect (mem_fun(*this, &RouteUI::mute_changed)));
connections.push_back (_route->solo_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
+ connections.push_back (_route->listen_changed.connect (mem_fun(*this, &RouteUI::listen_changed)));
connections.push_back (_route->solo_isolated_changed.connect (mem_fun(*this, &RouteUI::solo_changed)));
-
- if (is_track()) {
+
+ if (_session.writable() && is_track()) {
boost::shared_ptr<Track> t = boost::dynamic_pointer_cast<Track>(_route);
connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (*this, &RouteUI::route_rec_enable_changed)));
- connections.push_back (t->diskstream()->RecordEnableChanged.connect (mem_fun (PublicEditor::instance(), &PublicEditor::update_rec_display)));
connections.push_back (_session.RecordStateChanged.connect (mem_fun (*this, &RouteUI::session_rec_enable_changed)));
rec_enable_button->show();
rec_enable_button->set_controllable (t->rec_enable_control());
update_rec_display ();
- }
+ }
mute_button->unset_flags (Gtk::CAN_FOCUS);
solo_button->unset_flags (Gtk::CAN_FOCUS);
-
+
mute_button->show();
- if (_route->is_master()) {
+ if (_route->is_control()) {
solo_button->hide ();
} else {
solo_button->show();
}
- connections.push_back (_route->RemoteControlIDChanged.connect (mem_fun(*this, &RouteUI::refresh_remote_control_menu)));
-
/* map the current state */
mute_changed (0);
if (Keyboard::is_button2_event (ev)) {
// Primary-button2 click is the midi binding click
// button2-click is "momentary"
-
+
if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
wait_for_release = true;
} else {
if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
+#if 0
/* Primary-Tertiary-click applies change to all routes */
_session.begin_reversible_command (_("mute change"));
Session::GlobalMuteStateCommand *cmd = new Session::GlobalMuteStateCommand(_session, this);
- _session.set_all_mute (!_route->muted());
+ _session.set_mute (!_route->muted());
cmd->mark();
_session.add_command(cmd);
_session.commit_reversible_command ();
multiple_mute_change = true;
+#endif
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+#if 0
/* Primary-button1 applies change to the mix group.
NOTE: Primary-button2 is MIDI learn.
*/
if (ev->button == 1) {
set_route_group_mute (_route, !_route->muted());
}
-
+#endif
+
} else {
+#if 0
/* plain click applies change to this route */
if (wait_for_release) {
_route->set_mute (!_route->muted(), this);
} else {
reversibly_apply_route_boolean ("mute change", &Route::set_mute, !_route->muted(), this);
}
+#endif
}
}
}
}
bool
-RouteUI::mute_release(GdkEventButton* ev)
+RouteUI::mute_release(GdkEventButton*)
{
if (!ignore_toggle) {
if (wait_for_release){
return true;
}
+void
+RouteUI::post_solo_cleanup (SessionEvent* ev, bool was_not_latched)
+{
+ ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_solo_cleanup), ev, was_not_latched));
+
+ delete ev;
+
+ if (was_not_latched) {
+ Config->set_solo_latched (false);
+ }
+}
+
bool
RouteUI::solo_press(GdkEventButton* ev)
{
if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
return true;
}
- multiple_solo_change = false;
- if (!ignore_toggle) {
- if (Keyboard::is_context_menu_event (ev)) {
+ if (Config->get_solo_control_is_listen_control()) {
- if (solo_menu == 0) {
- build_solo_menu ();
- }
+ _route->set_listen (!_route->listening(), this);
- solo_menu->popup (1, ev->time);
+ } else {
- } else {
+ multiple_solo_change = false;
+ if (!ignore_toggle) {
- if (Keyboard::is_button2_event (ev)) {
+ if (Keyboard::is_context_menu_event (ev)) {
- // Primary-button2 click is the midi binding click
- // button2-click is "momentary"
-
- if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
- wait_for_release = true;
- } else {
- return false;
+ if (solo_menu == 0) {
+ build_solo_menu ();
}
- }
- if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
+ solo_menu->popup (1, ev->time);
- if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
+ } else {
- /* Primary-Tertiary-click applies change to all routes */
- bool was_not_latched = false;
- if (!Config->get_solo_latched ()) {
- was_not_latched = true;
- /*
- XXX it makes no sense to solo all tracks if we're
- not in latched mode, but doing nothing feels like a bug,
- so do it anyway
- */
- Config->set_solo_latched (true);
- }
- _session.begin_reversible_command (_("solo change"));
- Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand(_session, this);
- _session.set_all_solo (!_route->soloed());
- cmd->mark();
- _session.add_command (cmd);
- _session.commit_reversible_command ();
- multiple_solo_change = true;
- if (was_not_latched) {
- Config->set_solo_latched (false);
- }
-
- } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
+ if (Keyboard::is_button2_event (ev)) {
- // Primary-Secondary-click: exclusively solo this track, not a toggle */
+ // Primary-button2 click is the midi binding click
+ // button2-click is "momentary"
- _session.begin_reversible_command (_("solo change"));
- Session::GlobalSoloStateCommand *cmd = new Session::GlobalSoloStateCommand (_session, this);
- _session.set_all_solo (false);
- _route->set_solo (true, this);
- cmd->mark();
- _session.add_command(cmd);
- _session.commit_reversible_command ();
+ if (!Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier))) {
+ wait_for_release = true;
+ } else {
+ return false;
+ }
+ }
+
+ if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
- } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
+ if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
- // shift-click: set this route to solo safe
+ /* Primary-Tertiary-click applies change to all routes */
+ bool was_not_latched = false;
- if (Profile->get_sae() && ev->button == 1) {
- // button 1 and shift-click: disables solo_latched for this click
if (!Config->get_solo_latched ()) {
+ was_not_latched = true;
+ /*
+ XXX it makes no sense to solo all tracks if we're
+ not in latched mode, but doing nothing feels like a bug,
+ so do it anyway
+ */
Config->set_solo_latched (true);
- reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
- Config->set_solo_latched (false);
}
- } else {
+
+ SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+ ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_solo), _session.get_routes(), !_route->soloed());
+ ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_solo_cleanup), was_not_latched);
+
+ _session.queue_event (ev);
+
+ } else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
+
+ // Primary-Secondary-click: exclusively solo this track, not a toggle */
+
+ //boost::shared_ptr<RouteList> rl (new RouteList);
+ //rl->push_back (route());
+
+ //SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+ // ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_just_one_solo), rl, true);
+ //ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
+
+ //_session.queue_event (ev);
+
+ } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
+
+ // shift-click: toggle solo isolated status
+
_route->set_solo_isolated (!_route->solo_isolated(), this);
wait_for_release = false;
- }
- } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
+ } else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- /* Primary-button1: solo mix group.
- NOTE: Primary-button2 is MIDI learn.
- */
+#if 0
+ /* Primary-button1: solo mix group.
+ NOTE: Primary-button2 is MIDI learn.
+ */
- if (ev->button == 1) {
- set_route_group_solo (_route, !_route->soloed());
- }
+ if (ev->button == 1) {
+ queue_route_group_op (RouteGroup::Solo, &Session::set_all_solo, !_route->soloed());
+ }
+#endif
- } else {
- /* click: solo this route */
- if (wait_for_release) {
- _route->set_solo (!_route->soloed(), this);
} else {
- reversibly_apply_route_boolean ("solo change", &Route::set_solo, !_route->soloed(), this);
+
+ /* click: solo this route */
+
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (route());
+
+ SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+ ev->rt_slot = bind (sigc::mem_fun (_session, &Session::set_solo), rl, !rec_enable_button->get_active());
+ ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
+
+ _session.queue_event (ev);
}
}
}
}
bool
-RouteUI::solo_release(GdkEventButton* ev)
+RouteUI::solo_release(GdkEventButton*)
{
if (!ignore_toggle) {
if (wait_for_release) {
return true;
}
+void
+RouteUI::post_rtop_cleanup (SessionEvent* ev)
+{
+ ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_rtop_cleanup), ev));
+ delete ev;
+}
+
+void
+RouteUI::post_group_rtop_cleanup (SessionEvent* ev, RouteGroup* rg, RouteGroup::Property prop)
+{
+ ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::post_group_rtop_cleanup), ev, rg, prop));
+ delete ev;
+ rg->set_property (prop, false);
+}
+
+void
+RouteUI::queue_route_group_op (RouteGroup::Property prop, void (Session::*session_method)(boost::shared_ptr<RouteList>, bool), bool yn)
+{
+ RouteGroup* rg = _route->route_group();
+ bool prop_was_active;
+
+ if (rg) {
+ prop_was_active = rg->active_property (prop);
+ rg->set_property (prop, true);
+ } else {
+ prop_was_active = false;
+ }
+
+ /* we will queue the op for just this route, but because its route group now has the relevant property marked active,
+ the operation will apply to the whole group (if there is a group)
+ */
+
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (route());
+
+ SessionEvent* ev = new SessionEvent (SessionEvent::RealTimeOperation, SessionEvent::Add, SessionEvent::Immediate, 0, 0.0);
+ ev->rt_slot = bind (sigc::mem_fun (_session, session_method), rl, yn);
+ if (rg && !prop_was_active) {
+ ev->rt_return = bind (sigc::mem_fun (*this, &RouteUI::post_group_rtop_cleanup), rg, prop);
+ } else {
+ ev->rt_return = sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup);
+ }
+
+ _session.queue_event (ev);
+}
+
bool
RouteUI::rec_enable_press(GdkEventButton* ev)
{
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
- _session.begin_reversible_command (_("rec-enable change"));
- Session::GlobalRecordEnableStateCommand *cmd = new Session::GlobalRecordEnableStateCommand(_session, this);
-
- if (rec_enable_button->get_active()) {
- _session.record_disenable_all ();
- } else {
- _session.record_enable_all ();
- check_rec_enable_sensitivity ();
- }
-
- cmd->mark();
- _session.add_command(cmd);
- _session.commit_reversible_command ();
+#if 0
+ _session.set_record_enable (_session.get_route(), !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
+#endif
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
- /* Primary-button1 applies change to the mix group.
+ /* Primary-button1 applies change to the route group (even if it is not active)
NOTE: Primary-button2 is MIDI learn.
*/
+#if 0
+ if (ev->button == 1 && _route->route_group()) {
+ _session.set_record_enable (_route->route_group(), !rec_enable_button->get_active(),
+ queue_route_group_op (RouteGroup::RecEnable, &Session::set_record_enable,
+ }
+#endif
- set_route_group_rec_enable (_route, !_route->record_enabled());
+ } else if (Keyboard::is_context_menu_event (ev)) {
+
+ /* do this on release */
} else {
- reversibly_apply_track_boolean ("rec-enable change", &Track::set_record_enable, !track()->record_enabled(), this);
- check_rec_enable_sensitivity ();
+
+#if 0
+ boost::shared_ptr<RouteList> rl (new RouteList);
+ rl->push_back (route());
+ _session.set_record_enable (rl, !rec_enable_button->get_active(), sigc::mem_fun (*this, &RouteUI::post_rtop_cleanup));
+#endif
}
}
}
bool
-RouteUI::rec_enable_release (GdkEventButton* ev)
+RouteUI::rec_enable_release (GdkEventButton*)
{
return true;
}
RouteUI::build_sends_menu ()
{
using namespace Menu_Helpers;
-
+
sends_menu = new Menu;
sends_menu->set_name ("ArdourContextMenu");
MenuList& items = sends_menu->items();
-
+
+ items.push_back (MenuElem(_("Assign all tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_sends), PreFader)));
+ items.push_back (MenuElem(_("Assign all tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_sends), PostFader)));
+ items.push_back (MenuElem(_("Assign selected tracks (prefader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PreFader)));
+ items.push_back (MenuElem(_("Assign selected tracks (postfader)"), bind (mem_fun (*this, &RouteUI::create_selected_sends), PostFader)));
items.push_back (MenuElem(_("Copy track gains to sends"), mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
items.push_back (MenuElem(_("Set sends gain to -inf"), mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
items.push_back (MenuElem(_("Set sends gain to 0dB"), mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
+
+}
+
+void
+RouteUI::create_sends (Placement p)
+{
+ _session.globally_add_internal_sends (_route, p);
+}
+
+void
+RouteUI::create_selected_sends (Placement p)
+{
+ boost::shared_ptr<RouteList> rlist (new RouteList);
+ TrackSelection& selected_tracks (ARDOUR_UI::instance()->the_editor().get_selection().tracks);
+
+ for (TrackSelection::iterator i = selected_tracks.begin(); i != selected_tracks.end(); ++i) {
+ RouteTimeAxisView* rtv;
+ RouteUI* rui;
+ if ((rtv = dynamic_cast<RouteTimeAxisView*>(*i)) != 0) {
+ if ((rui = dynamic_cast<RouteUI*>(rtv)) != 0) {
+ if (boost::dynamic_pointer_cast<AudioTrack>(rui->route())) {
+ rlist->push_back (rui->route());
+ }
+ }
+ }
+ }
+
+ _session.add_internal_sends (_route, p, rlist);
}
void
RouteUI::set_sends_gain_from_track ()
{
+ _session.globally_set_send_gains_from_track (_route);
}
void
RouteUI::set_sends_gain_to_zero ()
{
+ _session.globally_set_send_gains_to_zero (_route);
}
void
RouteUI::set_sends_gain_to_unity ()
{
+ _session.globally_set_send_gains_to_unity (_route);
}
bool
}
bool
-RouteUI::show_sends_release (GdkEventButton* ev)
+RouteUI::show_sends_release (GdkEventButton*)
{
return true;
}
if (!show_sends_button) {
return;
}
-
+
if (onoff) {
show_sends_button->set_state (STATE_ACTIVE);
} else {
}
void
-RouteUI::solo_changed(void* src)
+RouteUI::solo_changed(void* /*src*/)
{
+ Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
+}
+
+void
+RouteUI::listen_changed(void* /*src*/)
+{
Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_solo_display));
}
+int
+RouteUI::solo_visual_state (boost::shared_ptr<Route> r)
+{
+ if (Config->get_solo_control_is_listen_control()) {
+
+ if (r->listening()) {
+ return 1;
+ } else {
+ return 0;
+ }
+
+ } else {
+
+ if (r->solo_isolated()) {
+ return 2;
+ } else if (r->soloed()) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
void
RouteUI::update_solo_display ()
{
bool x;
- vector<Gdk::Color> fg_colors;
- Gdk::Color c;
-
- if (solo_button->get_active() != (x = _route->soloed())){
- ignore_toggle = true;
- solo_button->set_active(x);
- ignore_toggle = false;
- }
- if (_route->solo_isolated()) {
- solo_button->set_visual_state (2);
- } else if (_route->soloed()) {
- solo_button->set_visual_state (1);
+ if (Config->get_solo_control_is_listen_control()) {
+
+ if (solo_button->get_active() != (x = _route->listening())) {
+ ignore_toggle = true;
+ solo_button->set_active(x);
+ ignore_toggle = false;
+ }
+
} else {
- solo_button->set_visual_state (0);
+
+ if (solo_button->get_active() != (x = _route->soloed())) {
+ ignore_toggle = true;
+ solo_button->set_active (x);
+ ignore_toggle = false;
+ }
+
}
+
+ solo_button->set_visual_state (solo_visual_state (_route));
}
void
}
void
-RouteUI::mute_changed(void* src)
+RouteUI::mute_changed(void* /*src*/)
{
Gtkmm2ext::UI::instance()->call_slot (mem_fun (*this, &RouteUI::update_mute_display));
}
+int
+RouteUI::mute_visual_state (Session& s, boost::shared_ptr<Route> r)
+{
+ if (Config->get_show_solo_mutes()) {
+
+ if (r->muted ()) {
+ /* full mute */
+ return 2;
+ } else if (s.soloing() && !r->soloed() && !r->solo_isolated()) {
+ /* mute-because-not-soloed */
+ return 1;
+ } else {
+ /* no mute at all */
+ return 0;
+ }
+
+ } else {
+
+ if (r->muted()) {
+ /* full mute */
+ return 2;
+ } else {
+ /* no mute at all */
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
void
RouteUI::update_mute_display ()
{
ignore_toggle = false;
}
- /* now attend to visual state */
-
- if (Config->get_show_solo_mutes()) {
- if (_route->muted()) {
- mute_button->set_visual_state (2);
- } else if (!_route->soloed() && _session.soloing()) {
- mute_button->set_visual_state (1);
- } else {
- mute_button->set_visual_state (0);
- }
- } else {
- if (_route->muted()) {
- mute_button->set_visual_state (2);
- } else {
- mute_button->set_visual_state (0);
- }
- }
-
+ mute_button->set_visual_state (mute_visual_state (_session, _route));
}
void
rec_enable_button->set_active (model);
ignore_toggle = false;
}
- else {
- return;
- }
-
+
/* now make sure its color state is correct */
if (model) {
} else {
rec_enable_button->set_visual_state (0);
}
-}
-void
-RouteUI::build_remote_control_menu ()
-{
- remote_control_menu = new Menu;
- refresh_remote_control_menu ();
-}
-
-void
-RouteUI::refresh_remote_control_menu ()
-{
- ENSURE_GUI_THREAD (mem_fun (*this, &RouteUI::refresh_remote_control_menu));
-
- // only refresh the menu if it has been instantiated
-
- if (remote_control_menu == 0) {
- return;
- }
-
- using namespace Menu_Helpers;
-
- RadioMenuItem::Group rc_group;
- CheckMenuItem* rc_active;
- uint32_t limit = _session.ntracks() + _session.nbusses();
- char buf[32];
-
- MenuList& rc_items = remote_control_menu->items();
- rc_items.clear ();
-
- /* note that this menu list starts at zero, not 1, because zero
- is a valid, if useless, ID.
- */
-
- limit += 4; /* leave some breathing room */
-
- rc_items.push_back (RadioMenuElem (rc_group, _("None")));
- if (_route->remote_control_id() == 0) {
- rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
- rc_active->set_active ();
- }
-
- for (uint32_t i = 1; i < limit; ++i) {
- snprintf (buf, sizeof (buf), "%u", i);
- rc_items.push_back (RadioMenuElem (rc_group, buf));
- rc_active = dynamic_cast<RadioMenuItem*>(&rc_items.back());
- if (_route->remote_control_id() == i) {
- rc_active = dynamic_cast<CheckMenuItem*> (&rc_items.back());
- rc_active->set_active ();
- }
- rc_active->signal_activate().connect (bind (mem_fun (*this, &RouteUI::set_remote_control_id), i, rc_active));
- }
-}
-
-void
-RouteUI::set_remote_control_id (uint32_t id, CheckMenuItem* item)
-{
- /* this is called when the radio menu item is toggled, and so
- is actually invoked twice per menu selection. we only
- care about the invocation for the item that was being
- marked active.
- */
-
- if (item->get_active()) {
- _route->set_remote_control_id (id);
- }
+ check_rec_enable_sensitivity ();
}
void
RouteUI::build_solo_menu (void)
{
using namespace Menu_Helpers;
-
+
solo_menu = new Menu;
solo_menu->set_name ("ArdourContextMenu");
MenuList& items = solo_menu->items();
items.push_back (CheckMenuElem(*check));
check->show_all();
+ check = new CheckMenuItem(_("Solo Safe"));
+ check->set_active (_route->solo_safe());
+ check->signal_toggled().connect (bind (mem_fun (*this, &RouteUI::toggle_solo_safe), check));
+ _route->solo_safe_changed.connect(bind (mem_fun (*this, &RouteUI::solo_safe_toggle), check));
+ items.push_back (CheckMenuElem(*check));
+ check->show_all();
+
//items.push_back (SeparatorElem());
// items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
-
+
}
void
RouteUI::build_mute_menu(void)
{
using namespace Menu_Helpers;
-
+
mute_menu = new Menu;
mute_menu->set_name ("ArdourContextMenu");
-#if FIX_ME_IN_3_0
MenuList& items = mute_menu->items();
- CheckMenuItem* check;
- check = new CheckMenuItem(_("Pre Fader"));
- init_mute_menu(PRE_FADER, check);
- check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), PRE_FADER, check));
- _route->pre_fader_changed.connect(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), check));
- items.push_back (CheckMenuElem(*check));
- check->show_all();
+ pre_fader_mute_check = manage (new CheckMenuItem(_("Pre Fader")));
+ init_mute_menu(MuteMaster::PreFader, pre_fader_mute_check);
+ pre_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PreFader, pre_fader_mute_check));
+ items.push_back (CheckMenuElem(*pre_fader_mute_check));
+ pre_fader_mute_check->show_all();
+
+ post_fader_mute_check = manage (new CheckMenuItem(_("Post Fader")));
+ init_mute_menu(MuteMaster::PostFader, post_fader_mute_check);
+ post_fader_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::PostFader, post_fader_mute_check));
+ items.push_back (CheckMenuElem(*post_fader_mute_check));
+ post_fader_mute_check->show_all();
+
+ listen_mute_check = manage (new CheckMenuItem(_("Control Outs")));
+ init_mute_menu(MuteMaster::Listen, listen_mute_check);
+ listen_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Listen, listen_mute_check));
+ items.push_back (CheckMenuElem(*listen_mute_check));
+ listen_mute_check->show_all();
+
+ main_mute_check = manage (new CheckMenuItem(_("Main Outs")));
+ init_mute_menu(MuteMaster::Main, main_mute_check);
+ main_mute_check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MuteMaster::Main, main_mute_check));
+ items.push_back (CheckMenuElem(*main_mute_check));
+ main_mute_check->show_all();
- check = new CheckMenuItem(_("Post Fader"));
- init_mute_menu(POST_FADER, check);
- check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), POST_FADER, check));
- _route->post_fader_changed.connect(bind (mem_fun (*this, &RouteUI::post_fader_toggle), check));
- items.push_back (CheckMenuElem(*check));
- check->show_all();
-
- check = new CheckMenuItem(_("Control Outs"));
- init_mute_menu(CONTROL_OUTS, check);
- check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), CONTROL_OUTS, check));
- _route->control_outs_changed.connect(bind (mem_fun (*this, &RouteUI::control_outs_toggle), check));
- items.push_back (CheckMenuElem(*check));
- check->show_all();
-
- check = new CheckMenuItem(_("Main Outs"));
- init_mute_menu(MAIN_OUTS, check);
- check->signal_toggled().connect(bind (mem_fun (*this, &RouteUI::toggle_mute_menu), MAIN_OUTS, check));
- _route->main_outs_changed.connect(bind (mem_fun (*this, &RouteUI::main_outs_toggle), check));
- items.push_back (CheckMenuElem(*check));
- check->show_all();
-#endif
//items.push_back (SeparatorElem());
// items.push_back (MenuElem (_("MIDI Bind"), mem_fun (*mute_button, &BindableToggleButton::midi_learn)));
+
+ _route->mute_points_changed.connect (mem_fun (*this, &RouteUI::muting_change));
}
void
RouteUI::init_mute_menu(MuteMaster::MutePoint mp, CheckMenuItem* check)
{
- check->set_active (_route->mute_master()->muted_at (mp));
+ check->set_active (_route->mute_points() & mp);
}
void
RouteUI::toggle_mute_menu(MuteMaster::MutePoint mp, Gtk::CheckMenuItem* check)
{
- // _route->set_mute_config(type, check->get_active(), this);
+ if (check->get_active()) {
+ _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() | mp));
+ } else {
+ _route->set_mute_points (MuteMaster::MutePoint (_route->mute_points() & ~mp));
+ }
+}
+
+void
+RouteUI::muting_change ()
+{
+ ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::muting_change));
+
+ bool yn;
+ MuteMaster::MutePoint current = _route->mute_points ();
+
+ yn = (current & MuteMaster::PreFader);
+
+ if (pre_fader_mute_check->get_active() != yn) {
+ pre_fader_mute_check->set_active (yn);
+ }
+
+ yn = (current & MuteMaster::PostFader);
+
+ if (post_fader_mute_check->get_active() != yn) {
+ post_fader_mute_check->set_active (yn);
+ }
+
+ yn = (current & MuteMaster::Listen);
+
+ if (listen_mute_check->get_active() != yn) {
+ listen_mute_check->set_active (yn);
+ }
+
+ yn = (current & MuteMaster::Main);
+
+ if (main_mute_check->get_active() != yn) {
+ main_mute_check->set_active (yn);
+ }
}
void
_route->set_solo_isolated (check->get_active(), this);
}
+void
+RouteUI::toggle_solo_safe (Gtk::CheckMenuItem* check)
+{
+ _route->set_solo_safe (check->get_active(), this);
+}
+
void
RouteUI::set_route_group_solo(boost::shared_ptr<Route> route, bool yn)
{
RouteUI::set_color (const Gdk::Color & c)
{
char buf[64];
-
+
_color = c;
-
+
ensure_xml_node ();
snprintf (buf, sizeof (buf), "%d:%d:%d", c.get_red(), c.get_green(), c.get_blue());
xml_node->add_property ("color", buf);
RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
{
ensure_xml_node ();
-
+
XMLNodeList kids = xml_node->children();
XMLNodeConstIterator iter;
RouteUI::set_color_from_route ()
{
XMLProperty *prop;
-
+
RouteUI::ensure_xml_node ();
if ((prop = xml_node->property ("color")) != 0) {
_color.set_green(g);
_color.set_blue(b);
return 0;
- }
+ }
return 1;
}
name_prompter.get_result (result);
if (result.length()) {
_route->set_name (result);
- }
+ }
break;
}
return;
-
+
}
void
bool x;
ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_polarity));
-
+
if ((x = polarity_menu_item->get_active()) != _route->phase_invert()) {
_route->set_phase_invert (x);
if (x) {
bool x;
ENSURE_GUI_THREAD(mem_fun (*this, &RouteUI::toggle_denormal_protection));
-
+
if ((x = denormal_menu_item->get_active()) != _route->denormal_protection()) {
_route->set_denormal_protection (x);
}
}
void
-RouteUI::solo_isolated_toggle(void* src, Gtk::CheckMenuItem* check)
+RouteUI::solo_isolated_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
{
bool yn = _route->solo_isolated ();
}
}
-#ifdef FIX_THIS_FOR_3_0
-void
-RouteUI::pre_fader_toggle(void* src, Gtk::CheckMenuItem* check)
-{
- ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::pre_fader_toggle), src, check));
-
- bool yn = _route->get_mute_config(PRE_FADER);
- if (check->get_active() != yn) {
- check->set_active (yn);
- }
-}
void
-RouteUI::post_fader_toggle(void* src, Gtk::CheckMenuItem* check)
+RouteUI::solo_safe_toggle(void* /*src*/, Gtk::CheckMenuItem* check)
{
- ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::post_fader_toggle), src, check));
-
- bool yn = _route->get_mute_config(POST_FADER);
- if (check->get_active() != yn) {
- check->set_active (yn);
- }
-}
+ bool yn = _route->solo_safe ();
-void
-RouteUI::control_outs_toggle(void* src, Gtk::CheckMenuItem* check)
-{
- ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::control_outs_toggle), src, check));
-
- bool yn = _route->get_mute_config(CONTROL_OUTS);
if (check->get_active() != yn) {
check->set_active (yn);
}
}
-void
-RouteUI::main_outs_toggle(void* src, Gtk::CheckMenuItem* check)
-{
- ENSURE_GUI_THREAD(bind (mem_fun (*this, &RouteUI::main_outs_toggle), src, check));
-
- bool yn = _route->get_mute_config(MAIN_OUTS);
- if (check->get_active() != yn) {
- check->set_active (yn);
- }
-}
-#endif
-
void
RouteUI::disconnect_input ()
{
sys::path path;
Glib::ustring safe_name;
string name;
-
+
path = ARDOUR::user_route_template_directory ();
-
+
if (g_mkdir_with_parents (path.to_string().c_str(), 0755)) {
error << string_compose (_("Cannot create route template directory %1"), path.to_string()) << endmsg;
return;
}
-
+
Prompter p (true); // modal
-
+
p.set_prompt (_("Template name:"));
switch (p.run()) {
case RESPONSE_ACCEPT:
default:
return;
}
-
+
p.hide ();
p.get_result (name, true);
-
+
safe_name = legalize_for_path (name);
safe_name += template_suffix;
-
+
path /= safe_name;
-
+
_route->save_as_template (path.to_string(), name);
}
RouteUI::parameter_changed (string const & p)
{
ENSURE_GUI_THREAD (bind (mem_fun (*this, &RouteUI::parameter_changed), p));
-
+
if (p == "disable-disarm-during-roll") {
check_rec_enable_sensitivity ();
- } else if (p == "solo-model") {
+ } else if (p == "solo-control-is-listen-control") {
+ set_button_names ();
+ } else if (p == "listen-position") {
set_button_names ();
}
}
+void
+RouteUI::step_gain_up ()
+{
+ _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.1), this);
+}
+
+void
+RouteUI::page_gain_up ()
+{
+ _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) + 0.5), this);
+}
+
+void
+RouteUI::step_gain_down ()
+{
+ _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.1), this);
+}
+
+void
+RouteUI::page_gain_down ()
+{
+ _route->set_gain (dB_to_coefficient (accurate_coefficient_to_dB (_route->gain_control()->get_value()) - 0.5), this);
+}
+
+void
+RouteUI::open_remote_control_id_dialog ()
+{
+ ArdourDialog dialog (_("Remote Control ID"));
+
+ uint32_t const limit = _session.ntracks() + _session.nbusses () + 4;
+
+ HBox* hbox = manage (new HBox);
+ hbox->set_spacing (6);
+ hbox->pack_start (*manage (new Label (_("Remote control ID:"))));
+ SpinButton* spin = manage (new SpinButton);
+ spin->set_digits (0);
+ spin->set_increments (1, 10);
+ spin->set_range (0, limit);
+ spin->set_value (_route->remote_control_id());
+ hbox->pack_start (*spin);
+ dialog.get_vbox()->pack_start (*hbox);
+
+ dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
+ dialog.add_button (Stock::APPLY, RESPONSE_ACCEPT);
+
+ dialog.show_all ();
+ int const r = dialog.run ();
+
+ if (r == RESPONSE_ACCEPT) {
+ _route->set_remote_control_id (spin->get_value_as_int ());
+ }
+}