init ();
}
-RouteUI::RouteUI (boost::shared_ptr<ARDOUR::Route> rt, ARDOUR::Session* sess)
- : AxisView(sess)
-{
- init ();
- set_route (rt);
-}
-
RouteUI::~RouteUI()
{
_route.reset (); /* drop reference to route, so that it can be cleaned up */
RouteUI::init ()
{
self_destruct = true;
- xml_node = 0;
mute_menu = 0;
solo_menu = 0;
sends_menu = 0;
solo_safe_led = 0;
_solo_release = 0;
_mute_release = 0;
- route_active_menu_item = 0;
denormal_menu_item = 0;
step_edit_item = 0;
multiple_mute_change = false;
delete mute_menu;
mute_menu = 0;
- if (xml_node) {
- /* do not delete the node - its owned by the route */
- xml_node = 0;
- }
-
- route_active_menu_item = 0;
denormal_menu_item = 0;
}
if (self_destruct) {
rp->DropReferences.connect (route_connections, invalidator (*this), boost::bind (&RouteUI::self_delete, this), gui_context());
}
-
+
mute_button->set_controllable (_route->mute_control());
solo_button->set_controllable (_route->solo_control());
if (_mute_release) {
_mute_release->routes = _session->get_routes ();
}
-
+
_session->set_mute (_session->get_routes(), !_route->muted(), Session::rt_cleanup, true);
}
} else {
/* plain click applies change to this route */
-
+
boost::shared_ptr<RouteList> rl (new RouteList);
rl->push_back (_route);
if (ev->type == GDK_2BUTTON_PRESS || ev->type == GDK_3BUTTON_PRESS ) {
return true;
}
-
+
multiple_solo_change = false;
if (!_i_am_the_modifier) {
-
+
if (Keyboard::is_context_menu_event (ev)) {
-
+
if (!solo_isolated_led) {
if (solo_menu == 0) {
build_solo_menu ();
}
-
+
solo_menu->popup (1, ev->time);
}
-
+
} else {
-
+
if (Keyboard::is_button2_event (ev)) {
-
+
// Primary-button2 click is the midi binding click
// button2-click is "momentary"
-
+
if (solo_button->on_button_press_event (ev)) {
return true;
}
_solo_release = new SoloMuteRelease (_route->self_soloed());
}
-
+
if (ev->button == 1 || Keyboard::is_button2_event (ev)) {
-
+
if (Keyboard::modifier_state_equals (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::TertiaryModifier))) {
-
+
/* Primary-Tertiary-click applies change to all routes */
if (_solo_release) {
_solo_release->routes = _session->get_routes ();
}
-
+
if (Config->get_solo_control_is_listen_control()) {
- _session->set_listen (_session->get_routes(), !_route->listening(), Session::rt_cleanup, true);
+ _session->set_listen (_session->get_routes(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
} else {
_session->set_solo (_session->get_routes(), !_route->self_soloed(), Session::rt_cleanup, true);
}
-
+
} else if (Keyboard::modifier_state_contains (ev->state, Keyboard::ModifierMask (Keyboard::PrimaryModifier|Keyboard::SecondaryModifier))) {
-
+
// Primary-Secondary-click: exclusively solo this track
if (_solo_release) {
}
}
}
-
+
if (Config->get_solo_control_is_listen_control()) {
/* ??? we need a just_one_listen() method */
} else {
}
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::TertiaryModifier)) {
-
+
// shift-click: toggle solo isolated status
-
+
_route->set_solo_isolated (!_route->solo_isolated(), this);
delete _solo_release;
_solo_release = 0;
-
+
} else if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) {
-
+
/* Primary-button1: solo mix group.
NOTE: Primary-button2 is MIDI learn.
*/
-
+
if (ev->button == 1 && _route->route_group()) {
if (_solo_release) {
_solo_release->routes = _route->route_group()->route_list();
}
-
+
if (Config->get_solo_control_is_listen_control()) {
- _session->set_listen (_route->route_group()->route_list(), !_route->listening(), Session::rt_cleanup, true);
+ _session->set_listen (_route->route_group()->route_list(), !_route->listening_via_monitor(), Session::rt_cleanup, true);
} else {
_session->set_solo (_route->route_group()->route_list(), !_route->self_soloed(), Session::rt_cleanup, true);
}
}
-
+
} else {
-
+
/* click: solo this route */
-
+
boost::shared_ptr<RouteList> rl (new RouteList);
rl->push_back (route());
}
if (Config->get_solo_control_is_listen_control()) {
- _session->set_listen (rl, !_route->listening());
+ _session->set_listen (rl, !_route->listening_via_monitor());
} else {
_session->set_solo (rl, !_route->self_soloed());
}
RouteUI::solo_release (GdkEventButton*)
{
if (!_i_am_the_modifier) {
-
+
if (_solo_release) {
if (_solo_release->exclusive) {
if (midi_track()->step_editing()) {
return true;
- }
+ }
}
if (!_i_am_the_modifier && is_track() && rec_enable_button) {
return;
}
- /* no rec-button context menu for non-MIDI tracks
+ /* no rec-button context menu for non-MIDI tracks
*/
if (is_midi_track()) {
record_menu = new Menu;
record_menu->set_name ("ArdourContextMenu");
-
+
using namespace Menu_Helpers;
MenuList& items = record_menu->items();
-
- items.push_back (CheckMenuElem (_("Step Edit"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
+
+ items.push_back (CheckMenuElem (_("Step Entry"), sigc::mem_fun (*this, &RouteUI::toggle_step_edit)));
step_edit_item = dynamic_cast<CheckMenuItem*> (&items.back());
if (_route->record_enabled()) {
if (yn) {
if (rec_enable_button) {
rec_enable_button->set_visual_state (3);
- }
+ }
start_step_editing ();
if (rec_enable_button) {
rec_enable_button->set_visual_state (0);
- }
+ }
stop_step_editing ();
items.push_back (
MenuElem(_("Assign all tracks (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, false))
);
-
+
items.push_back (
MenuElem(_("Assign all tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PreFader, true))
);
-
+
items.push_back (
MenuElem(_("Assign all tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, false))
);
-
+
items.push_back (
MenuElem(_("Assign all tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_sends), PostFader, true))
);
items.push_back (
MenuElem(_("Assign selected tracks and buses (prefader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PreFader, true)));
-
+
items.push_back (
MenuElem(_("Assign selected tracks (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, false))
);
items.push_back (
MenuElem(_("Assign selected tracks and buses (postfader)"), sigc::bind (sigc::mem_fun (*this, &RouteUI::create_selected_sends), PostFader, true))
);
-
+
items.push_back (MenuElem(_("Copy track/bus gains to sends"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_from_track)));
items.push_back (MenuElem(_("Set sends gain to -inf"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_zero)));
items.push_back (MenuElem(_("Set sends gain to 0dB"), sigc::mem_fun (*this, &RouteUI::set_sends_gain_to_unity)));
}
}
}
-
+
_session->add_internal_sends (_route, p, rlist);
}
if (r->is_master() || r->is_monitor()) {
return 0;
}
-
+
if (Config->get_solo_control_is_listen_control()) {
- if (r->listening()) {
+ if (r->listening_via_monitor()) {
return 1;
} else {
return 0;
}
- }
-
+ }
+
if (r->soloed()) {
if (!r->self_soloed()) {
return 3;
if (r->is_master() || r->is_monitor()) {
return 0;
}
-
+
if (Config->get_solo_control_is_listen_control()) {
- if (r->listening()) {
+ if (r->listening_via_monitor()) {
return 1;
} else {
return 0;
}
- }
-
+ }
+
if (r->solo_isolated()) {
return 2;
} else if (r->soloed()) {
if (r->is_master() || r->is_monitor()) {
return 0;
}
-
+
if (r->solo_isolated()) {
return 1;
} else {
if (r->is_master() || r->is_monitor()) {
return 0;
}
-
+
if (r->solo_safe()) {
return 1;
} else {
if (Config->get_solo_control_is_listen_control()) {
- if (solo_button->get_active() != (x = _route->listening())) {
+ if (solo_button->get_active() != (x = _route->listening_via_monitor())) {
++_i_am_the_modifier;
solo_button->set_active(x);
--_i_am_the_modifier;
}
solo_button->set_visual_state (solo_visual_state (_route));
-
- /* some changes to solo status can affect mute display, so catch up
+
+ /* some changes to solo status can affect mute display, so catch up
*/
update_mute_display ();
return 0;
}
- if (Config->get_show_solo_mutes()) {
+
+ if (Config->get_show_solo_mutes() && !Config->get_solo_control_is_listen_control ()) {
if (r->muted ()) {
/* full mute */
--_i_am_the_modifier;
}
- mute_button->set_visual_state (mute_visual_state (_session, _route));
+ mute_button->set_visual_state (mute_visual_state (_session, _route));
}
void
if (!rec_enable_button || !_route) {
return;
}
-
+
bool model = _route->record_enabled();
bool view = rec_enable_button->get_active();
case Session::Recording:
rec_enable_button->set_visual_state (1);
break;
-
+
case Session::Disabled:
case Session::Enabled:
rec_enable_button->set_visual_state (2);
break;
-
+
}
if (step_edit_item) {
step_edit_item->set_sensitive (true);
}
}
-
+
check_rec_enable_sensitivity ();
}
_route->set_solo_safe (check->get_active(), this);
}
-bool
-RouteUI::choose_color()
+/** Ask the user to choose a colour, and then set all selected tracks
+ * to that colour.
+ */
+void
+RouteUI::choose_color ()
{
bool picked;
- Gdk::Color color;
-
- color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
+ Gdk::Color const color = Gtkmm2ext::UI::instance()->get_color (_("Color Selection"), picked, &_color);
if (picked) {
- set_color (color);
+ ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (
+ boost::bind (&RouteUI::set_color, _1, color)
+ );
}
-
- return picked;
}
void
_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);
-
+ set_gui_property ("color", buf);
_route->gui_changed ("color", (void *) 0); /* EMIT_SIGNAL */
}
-
-void
-RouteUI::ensure_xml_node ()
-{
- if (xml_node == 0) {
- if ((xml_node = _route->extra_xml ("GUI")) == 0) {
- xml_node = new XMLNode ("GUI");
- _route->add_extra_xml (*xml_node);
- } else {
- /* the Route has one, so it must have been loaded */
- if (Stateful::loading_state_version < 3000) {
- /* the GUI extra XML is in 2.X format; we must convert it to the new
- format to avoid problems later
- */
-
- XMLNode* new_xml_node = new XMLNode (X_("GUI"));
- XMLPropertyList old_gui_props = xml_node->properties ();
- for (XMLPropertyIterator i = old_gui_props.begin(); i != old_gui_props.end(); ++i) {
- new_xml_node->add_property ((*i)->name().c_str (), (*i)->value().c_str ());
- }
-
- XMLNodeList old_children = xml_node->children ();
- for (XMLNodeConstIterator i = old_children.begin(); i != old_children.end(); ++i) {
- XMLNode* new_child = new XMLNode (AutomationTimeAxisView::state_node_name);
- new_child->add_property (X_("automation-id"), (*i)->name());
-
- XMLPropertyList old_props = (*i)->properties ();
- for (XMLPropertyIterator j = old_props.begin(); j != old_props.end(); ++j) {
- new_child->add_property ((*j)->name().c_str (), (*j)->value().c_str ());
- }
-
- new_xml_node->add_child_nocopy (*new_child);
- }
-
- _route->add_extra_xml (*new_xml_node);
- }
- }
- }
-}
-
-XMLNode*
-RouteUI::get_automation_child_xml_node (Evoral::Parameter param)
+int
+RouteUI::set_color_from_route ()
{
- ensure_xml_node ();
-
- XMLNodeList kids = xml_node->children();
- XMLNodeConstIterator iter;
+ const string str = gui_property ("color");
- const string sym = ARDOUR::EventTypeMap::instance().to_symbol(param);
-
- for (iter = kids.begin(); iter != kids.end(); ++iter) {
-
- if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
- XMLProperty* type = (*iter)->property("automation-id");
- if (type && type->value() == sym) {
- return *iter;
- }
- }
+ if (str.empty()) {
+ return 1;
}
- // Didn't find it, make a new one
- XMLNode* child = new XMLNode (AutomationTimeAxisView::state_node_name);
- child->add_property("automation-id", sym);
- xml_node->add_child_nocopy (*child);
+ int r, g, b;
- return child;
-}
+ sscanf (str.c_str(), "%d:%d:%d", &r, &g, &b);
-int
-RouteUI::set_color_from_route ()
-{
- XMLProperty *prop;
+ _color.set_red (r);
+ _color.set_green (g);
+ _color.set_blue (b);
- RouteUI::ensure_xml_node ();
-
- if ((prop = xml_node->property ("color")) != 0) {
- int r, g, b;
- sscanf (prop->value().c_str(), "%d:%d:%d", &r, &g, &b);
- _color.set_red(r);
- _color.set_green(g);
- _color.set_blue(b);
- return 0;
- }
- return 1;
+ return 0;
}
void
-RouteUI::remove_this_route ()
+RouteUI::remove_this_route (bool apply_to_selection)
{
- if ((route()->is_master() || route()->is_monitor()) &&
- !Config->get_allow_special_bus_removal()) {
- MessageDialog msg (_("That would be bad news ...."),
- false,
- Gtk::MESSAGE_INFO,
+ if (apply_to_selection) {
+ ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteUI::remove_this_route, _1, false));
+ } else {
+ if ((route()->is_master() || route()->is_monitor()) &&
+ !Config->get_allow_special_bus_removal()) {
+ MessageDialog msg (_("That would be bad news ...."),
+ false,
+ Gtk::MESSAGE_INFO,
Gtk::BUTTONS_OK);
- msg.set_secondary_text (string_compose (_(
+ msg.set_secondary_text (string_compose (_(
"Removing the master or monitor bus is such a bad idea\n\
that %1 is not going to allow it.\n\
\n\
edit your ardour.rc file to set the\n\
\"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
- msg.present ();
- msg.run ();
- return;
- }
+ msg.present ();
+ msg.run ();
+ return;
+ }
- vector<string> choices;
- string prompt;
+ vector<string> choices;
+ string prompt;
- if (is_track()) {
- prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
- } else {
- prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
- }
+ if (is_track()) {
+ prompt = string_compose (_("Do you really want to remove track \"%1\" ?\n\nYou may also lose the playlist used by this track.\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
+ } else {
+ prompt = string_compose (_("Do you really want to remove bus \"%1\" ?\n\n(This action cannot be undone, and the session file will be overwritten)"), _route->name());
+ }
- choices.push_back (_("No, do nothing."));
- choices.push_back (_("Yes, remove it."));
+ choices.push_back (_("No, do nothing."));
+ choices.push_back (_("Yes, remove it."));
- string title;
- if (is_track()) {
- title = _("Remove track");
- } else {
- title = _("Remove bus");
- }
+ string title;
+ if (is_track()) {
+ title = _("Remove track");
+ } else {
+ title = _("Remove bus");
+ }
- Choice prompter (title, prompt, choices);
+ Choice prompter (title, prompt, choices);
- if (prompter.run () == 1) {
- Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
+ if (prompter.run () == 1) {
+ Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (&RouteUI::idle_remove_this_route), this));
+ }
}
}
}
void
-RouteUI::toggle_route_active ()
+RouteUI::set_route_active (bool a, bool apply_to_selection)
{
- bool yn;
-
- if (route_active_menu_item) {
- if (route_active_menu_item->get_active() != (yn = _route->active())) {
- _route->set_active (!yn);
- }
- }
-}
-
-void
-RouteUI::route_active_changed ()
-{
- if (route_active_menu_item) {
- Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&CheckMenuItem::set_active, route_active_menu_item, _route->active()));
+ if (apply_to_selection) {
+ ARDOUR_UI::instance()->the_editor().get_selection().tracks.foreach_route_ui (boost::bind (&RouteTimeAxisView::set_route_active, _1, a, false));
+ } else {
+ _route->set_active (a, this);
}
}
-
void
RouteUI::toggle_denormal_protection ()
{
p.set_title (_("Save As Template"));
p.set_prompt (_("Template name:"));
+ p.add_button (Gtk::Stock::SAVE, Gtk::RESPONSE_ACCEPT);
switch (p.run()) {
case RESPONSE_ACCEPT:
break;
{
if (p == "disable-disarm-during-roll") {
check_rec_enable_sensitivity ();
- } else if (p == "solo-control-is-listen-control") {
- set_button_names ();
- } else if (p == "listen-position") {
+ } else if (p == "use-monitor-bus" || p == "solo-control-is-listen-control" || p == "listen-position") {
set_button_names ();
}
}
BindableToggleButton* b = manage (new BindableToggleButton);
b->signal_toggled().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::invert_toggled), i, b));
b->signal_button_press_event().connect (sigc::mem_fun (*this, &RouteUI::invert_press));
-
+
b->set_name (X_("MixerInvertButton"));
if (to_add == 1) {
b->add (*manage (new Label (X_("Ø"))));
} else {
UI::instance()->set_tip (*b, string_compose (_("Left-click to invert (phase reverse) all channels of this track. Right-click to show menu."), i + 1));
}
-
+
_invert_buttons.push_back (b);
_invert_button_box.pack_start (*b);
}
-
+
_invert_button_box.show_all ();
}
RouteUI::set_invert_button_state ()
{
++_i_am_the_modifier;
-
+
uint32_t const N = _route->input()->n_ports().n_audio();
if (N > _max_invert_buttons) {
_invert_buttons.front()->set_active (_route->phase_invert().any());
if (_i_am_the_modifier) {
return;
}
-
+
uint32_t const N = _route->input()->n_ports().n_audio();
if (N <= _max_invert_buttons) {
_route->set_phase_invert (i, b->get_active ());
if (_i_am_the_modifier) {
return;
}
-
+
_route->set_phase_invert (c, !_route->phase_invert (c));
}
+
+void
+RouteUI::set_invert_sensitive (bool yn)
+{
+ for (list<BindableToggleButton*>::iterator b = _invert_buttons.begin(); b != _invert_buttons.end(); ++b) {
+ (*b)->set_sensitive (yn);
+ }
+}
+
+void
+RouteUI::request_redraw ()
+{
+ if (_route) {
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ }
+}