#include "ardour/playlist.h"
#include "ardour/processor.h"
#include "ardour/profile.h"
+#include "ardour/region_factory.h"
#include "ardour/route_group.h"
#include "ardour/session.h"
#include "ardour/session_playlist.h"
#include "evoral/Parameter.hpp"
#include "ardour_ui.h"
+#include "debug.h"
#include "global_signals.h"
#include "route_time_axis.h"
#include "automation_time_axis.h"
}
}
-RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::shared_ptr<Route> rt, Canvas& canvas)
+RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, Canvas& canvas)
: AxisView(sess)
- , RouteUI(rt, sess)
+ , RouteUI(sess)
, TimeAxisView(sess,ed,(TimeAxisView*) 0, canvas)
+ , _view (0)
, parent_canvas (canvas)
+ , no_redraw (false)
, button_table (3, 3)
, route_group_button (_("g"))
, playlist_button (_("p"))
, automation_button (_("a"))
+ , automation_action_menu (0)
+ , plugins_submenu_item (0)
+ , route_group_menu (0)
+ , playlist_action_menu (0)
+ , mode_menu (0)
+ , color_mode_menu (0)
, gm (sess, slider, true, 115)
- , _ignore_track_mode_change (false)
{
+}
+
+void
+RouteTimeAxisView::set_route (boost::shared_ptr<Route> rt)
+{
+ RouteUI::set_route (rt);
+
gm.set_controls (_route, _route->shared_peak_meter(), _route->amp());
gm.get_level_meter().set_no_show_all();
gm.get_level_meter().setup_meters(50);
- _has_state = true;
- playlist_menu = 0;
- playlist_action_menu = 0;
- automation_action_menu = 0;
- plugins_submenu_item = 0;
- mode_menu = 0;
- _view = 0;
+ string str = gui_property ("height");
+ if (!str.empty()) {
+ set_height (atoi (str));
+ } else {
+ set_height (preset_height (HeightNormal));
+ }
if (!_route->is_hidden()) {
- _marked_for_display = true;
+ if (gui_property ("visible").empty()) {
+ set_gui_property ("visible", true);
+ }
+ } else {
+ set_gui_property ("visible", false);
}
mute_changed (0);
timestretch_rect = 0;
no_redraw = false;
- destructive_track_mode_item = 0;
- normal_track_mode_item = 0;
- non_layered_track_mode_item = 0;
ignore_toggle = false;
rec_enable_button->set_sensitive (_session->writable());
}
-
+
controls_hbox.pack_start(gm.get_level_meter(), false, false);
_route->meter_change.connect (*this, invalidator (*this), bind (&RouteTimeAxisView::meter_changed, this), gui_context());
_route->input()->changed.connect (*this, invalidator (*this), ui_bind (&RouteTimeAxisView::io_changed, this, _1, _2), gui_context());
if (is_track()) {
- track()->TrackModeChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::track_mode_changed, this), gui_context());
+ str = gui_property ("layer-display");
+ if (!str.empty()) {
+ set_layer_display (LayerDisplay (string_2_enum (str, _view->layer_display ())));
+ }
+
track()->FreezeChange.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::map_frozen, this), gui_context());
track()->SpeedChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::speed_changed, this), gui_context());
/* pick up the correct freeze state */
map_frozen ();
-
}
_editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit));
ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler));
PropertyList* plist = new PropertyList();
-
+
plist->add (ARDOUR::Properties::edit, true);
plist->add (ARDOUR::Properties::mute, true);
plist->add (ARDOUR::Properties::solo, true);
-
+
route_group_menu = new RouteGroupMenu (_session, plist);
- route_group_menu->GroupSelected.connect (sigc::mem_fun (*this, &RouteTimeAxisView::set_route_group_from_menu));
gm.get_gain_slider().signal_scroll_event().connect(sigc::mem_fun(*this, &RouteTimeAxisView::controls_ebox_scroll), false);
gm.get_gain_slider().set_name ("TrackGainFader");
+
+ gm.get_level_meter().signal_scroll_event().connect (sigc::mem_fun (*this, &RouteTimeAxisView::controls_ebox_scroll), false);
+
+ show_name_entry ();
+ hide_name_label ();
}
RouteTimeAxisView::~RouteTimeAxisView ()
delete *i;
}
- delete playlist_menu;
- playlist_menu = 0;
-
delete playlist_action_menu;
playlist_action_menu = 0;
/* map current state of the route */
update_diskstream_display ();
+ setup_processor_menu_and_curves ();
+ reset_processor_automation_curves ();
+}
+/** Set up the processor menu for the current set of processors, and
+ * display automation curves for any parameters which have data.
+ */
+void
+RouteTimeAxisView::setup_processor_menu_and_curves ()
+{
_subplugin_menu_map.clear ();
subplugin_menu.items().clear ();
_route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
_route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
- reset_processor_automation_curves ();
}
gint
return false;
}
- route_group_menu->rebuild (_route->route_group ());
- route_group_menu->popup (ev->button, ev->time);
+ WeakRouteList r;
+ r.push_back (route ());
- return false;
-}
+ route_group_menu->build (r);
+ route_group_menu->menu()->popup (ev->button, ev->time);
-void
-RouteTimeAxisView::set_route_group_from_menu (RouteGroup *eg)
-{
- if (eg) {
- eg->add (_route);
- } else {
- if (_route->route_group()) {
- _route->route_group()->remove (_route);
- }
- }
+ return false;
}
void
RouteTimeAxisView::automation_click ()
{
conditionally_add_to_selection ();
- build_automation_action_menu ();
+ build_automation_action_menu (false);
automation_action_menu->popup (1, gtk_get_current_event_time());
}
-int
-RouteTimeAxisView::set_state (const XMLNode& node, int version)
-{
- TimeAxisView::set_state (node, version);
-
- XMLNodeList kids = node.children();
- XMLNodeConstIterator iter;
- const XMLProperty* prop;
-
- if (_view && (prop = node.property ("layer-display"))) {
- set_layer_display (LayerDisplay (string_2_enum (prop->value(), _view->layer_display ())));
- }
-
- for (iter = kids.begin(); iter != kids.end(); ++iter) {
- if ((*iter)->name() == AutomationTimeAxisView::state_node_name) {
- if ((prop = (*iter)->property ("automation-id")) != 0) {
-
- Evoral::Parameter param = ARDOUR::EventTypeMap::instance().new_parameter(prop->value());
- bool show = ((prop = (*iter)->property ("shown")) != 0) && string_is_affirmative (prop->value());
- create_automation_child(param, show);
- } else {
- warning << "Automation child has no ID" << endmsg;
- }
- }
- }
-
- return 0;
-}
-
void
-RouteTimeAxisView::build_automation_action_menu ()
+RouteTimeAxisView::build_automation_action_menu (bool for_selection)
{
using namespace Menu_Helpers;
MenuList& items = automation_action_menu->items();
automation_action_menu->set_name ("ArdourContextMenu");
-
+
items.push_back (MenuElem (_("Show All Automation"),
- sigc::mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
-
+ sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_all_automation), for_selection)));
+
items.push_back (MenuElem (_("Show Existing Automation"),
- sigc::mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
-
+ sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::show_existing_automation), for_selection)));
+
items.push_back (MenuElem (_("Hide All Automation"),
- sigc::mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
+ sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::hide_all_automation), for_selection)));
items.push_back (SeparatorElem ());
-
+
/* Attach the plugin submenu. It may have previously been used elsewhere,
so it was detached above */
items.push_back (MenuElem (_("Plugins"), subplugin_menu));
- items.back().set_sensitive (!subplugin_menu.items().empty());
+ items.back().set_sensitive (!subplugin_menu.items().empty() && (!for_selection || _editor.get_selection().tracks.size() == 1));;
}
void
MenuList& items = display_menu->items();
display_menu->set_name ("ArdourContextMenu");
- items.push_back (MenuElem (_("Color..."), sigc::mem_fun(*this, &RouteTimeAxisView::select_track_color)));
+ items.push_back (MenuElem (_("Color..."), sigc::mem_fun (*this, &RouteUI::choose_color)));
+ if (_size_menu) {
+ detach_menu (*_size_menu);
+ }
build_size_menu ();
items.push_back (MenuElem (_("Height"), *_size_menu));
if (!Profile->get_sae()) {
items.push_back (MenuElem (_("Remote Control ID..."), sigc::mem_fun (*this, &RouteUI::open_remote_control_id_dialog)));
- /* rebuild this every time */
- build_automation_action_menu ();
- detach_menu (*automation_action_menu);
- items.push_back (MenuElem (_("Automation"), *automation_action_menu));
+ items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
items.push_back (SeparatorElem());
}
// Hook for derived classes to add type specific stuff
append_extra_display_menu_items ();
- items.push_back (SeparatorElem());
if (is_track()) {
- Menu *layers_menu = manage(new Menu);
+ Menu* layers_menu = manage (new Menu);
MenuList &layers_items = layers_menu->items();
layers_menu->set_name("ArdourContextMenu");
RadioMenuItem::Group layers_group;
- layers_items.push_back(RadioMenuElem (layers_group, _("Overlaid"),
- sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid)));
- layers_items.push_back(RadioMenuElem (layers_group, _("Stacked"),
- sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked)));
+ /* Find out how many overlaid/stacked tracks we have in the selection */
+
+ int overlaid = 0;
+ int stacked = 0;
+ TrackSelection const & s = _editor.get_selection().tracks;
+ for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
+ StreamView* v = (*i)->view ();
+ if (!v) {
+ continue;
+ }
+
+ switch (v->layer_display ()) {
+ case Overlaid:
+ ++overlaid;
+ break;
+ case Stacked:
+ ++stacked;
+ break;
+ }
+ }
+
+ /* We're not connecting to signal_toggled() here; in the case where these two items are
+ set to be in the `inconsistent' state, it seems that one or other will end up active
+ as well as inconsistent (presumably due to the RadioMenuItem::Group). Then when you
+ select the active one, no toggled signal is emitted so nothing happens.
+ */
+
+ layers_items.push_back (RadioMenuElem (layers_group, _("Overlaid")));
+ RadioMenuItem* i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
+ i->set_active (overlaid != 0 && stacked == 0);
+ i->set_inconsistent (overlaid != 0 && stacked != 0);
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Overlaid, true));
+
+ layers_items.push_back (
+ RadioMenuElem (layers_group, _("Stacked"),
+ sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true))
+ );
+
+ i = dynamic_cast<RadioMenuItem*> (&layers_items.back ());
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_layer_display), Stacked, true));
+ i->set_active (overlaid == 0 && stacked != 0);
+ i->set_inconsistent (overlaid != 0 && stacked != 0);
items.push_back (MenuElem (_("Layers"), *layers_menu));
Menu* alignment_menu = manage (new Menu);
MenuList& alignment_items = alignment_menu->items();
alignment_menu->set_name ("ArdourContextMenu");
-
+
RadioMenuItem::Group align_group;
-
- alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"),
- sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial)));
- align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
- if (track()->alignment_style() == ExistingMaterial) {
- align_existing_item->set_active();
- }
-
- alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"),
- sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime)));
- align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
- if (track()->alignment_style() == CaptureTime) {
- align_capture_item->set_active();
+
+ /* Same verbose hacks as for the layering options above */
+
+ int existing = 0;
+ int capture = 0;
+ int automatic = 0;
+ int styles = 0;
+ boost::shared_ptr<Track> first_track;
+
+ TrackSelection const & s = _editor.get_selection().tracks;
+ for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
+ RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
+ if (!r || !r->is_track ()) {
+ continue;
+ }
+
+ if (!first_track) {
+ first_track = r->track();
+ }
+
+ switch (r->track()->alignment_choice()) {
+ case Automatic:
+ ++automatic;
+ styles |= 0x1;
+ switch (r->track()->alignment_style()) {
+ case ExistingMaterial:
+ ++existing;
+ break;
+ case CaptureTime:
+ ++capture;
+ break;
+ }
+ break;
+ case UseExistingMaterial:
+ ++existing;
+ styles |= 0x2;
+ break;
+ case UseCaptureTime:
+ ++capture;
+ styles |= 0x4;
+ break;
+ }
}
-
- items.push_back (MenuElem (_("Alignment"), *alignment_menu));
- track()->AlignmentStyleChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteTimeAxisView::align_style_changed, this), gui_context());
+
+ bool inconsistent;
+ switch (styles) {
+ case 1:
+ case 2:
+ case 4:
+ inconsistent = false;
+ break;
+ default:
+ inconsistent = true;
+ break;
+ }
+
+ RadioMenuItem* i;
+
+ if (!inconsistent && first_track) {
+
+ alignment_items.push_back (RadioMenuElem (align_group, _("Automatic (based on I/O connections)")));
+ i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
+ i->set_active (automatic != 0 && existing == 0 && capture == 0);
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, Automatic, true));
+
+ switch (first_track->alignment_choice()) {
+ case Automatic:
+ switch (first_track->alignment_style()) {
+ case ExistingMaterial:
+ alignment_items.push_back (MenuElem (_("(Currently: Existing Material)")));
+ break;
+ case CaptureTime:
+ alignment_items.push_back (MenuElem (_("(Currently: Capture Time)")));
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material")));
+ i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
+ i->set_active (existing != 0 && capture == 0 && automatic == 0);
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseExistingMaterial, true));
+
+ alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time")));
+ i = dynamic_cast<RadioMenuItem*> (&alignment_items.back());
+ i->set_active (existing == 0 && capture != 0 && automatic == 0);
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_choice), i, UseCaptureTime, true));
+
+ items.push_back (MenuElem (_("Alignment"), *alignment_menu));
+
+ } else {
+ /* show nothing */
+ }
Menu* mode_menu = manage (new Menu);
MenuList& mode_items = mode_menu->items ();
RadioMenuItem::Group mode_group;
- mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode"), sigc::bind (
- sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode),
- ARDOUR::Normal)));
- normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&mode_items.back());
+ int normal = 0;
+ int tape = 0;
+ int non_layered = 0;
- mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode"), sigc::bind (
- sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode),
- ARDOUR::Destructive)));
- destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&mode_items.back());
+ for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
+ RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
+ if (!r || !r->is_track ()) {
+ continue;
+ }
- mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode"),
- sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered)));
- non_layered_track_mode_item = dynamic_cast<RadioMenuItem*>(&mode_items.back());
+ switch (r->track()->mode()) {
+ case Normal:
+ ++normal;
+ break;
+ case Destructive:
+ ++tape;
+ break;
+ case NonLayered:
+ ++non_layered;
+ break;
+ }
+ }
+ mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode")));
+ i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal, true));
+ i->set_active (normal != 0 && tape == 0 && non_layered == 0);
+ i->set_inconsistent (normal != 0 && (tape != 0 || non_layered != 0));
- _ignore_track_mode_change = true;
-
- switch (track()->mode()) {
- case ARDOUR::Destructive:
- destructive_track_mode_item->set_active ();
- break;
- case ARDOUR::Normal:
- normal_track_mode_item->set_active ();
- break;
- case ARDOUR::NonLayered:
- non_layered_track_mode_item->set_active ();
- break;
- }
-
- _ignore_track_mode_change = false;
+ mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode")));
+ i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive, true));
+ i->set_active (normal == 0 && tape != 0 && non_layered == 0);
+ i->set_inconsistent (tape != 0 && (normal != 0 || non_layered != 0));
+
+ mode_items.push_back (RadioMenuElem (mode_group, _("Non-Layered Mode")));
+ i = dynamic_cast<RadioMenuItem*> (&mode_items.back ());
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::NonLayered, true));
+ i->set_active (normal == 0 && tape == 0 && non_layered != 0);
+ i->set_inconsistent (non_layered != 0 && (normal != 0 || tape != 0));
items.push_back (MenuElem (_("Mode"), *mode_menu));
}
build_playlist_menu ();
items.push_back (MenuElem (_("Playlist"), *playlist_action_menu));
+ items.back().set_sensitive (_editor.get_selection().tracks.size() <= 1);
+
+ route_group_menu->detach ();
+
+ WeakRouteList r;
+ for (TrackSelection::iterator i = _editor.get_selection().tracks.begin(); i != _editor.get_selection().tracks.end(); ++i) {
+ RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
+ if (rtv) {
+ r.push_back (rtv->route ());
+ }
+ }
- route_group_menu->rebuild (_route->route_group ());
- items.push_back (MenuElem (_("Route Group"), *route_group_menu));
+ if (r.empty ()) {
+ r.push_back (route ());
+ }
+
+ route_group_menu->build (r);
+ items.push_back (MenuElem (_("Route Group"), *route_group_menu->menu ()));
- build_automation_action_menu ();
+ build_automation_action_menu (true);
items.push_back (MenuElem (_("Automation"), *automation_action_menu));
items.push_back (SeparatorElem());
}
- items.push_back (CheckMenuElem (_("Active"), sigc::mem_fun(*this, &RouteUI::toggle_route_active)));
- route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
- route_active_menu_item->set_active (_route->active());
+ int active = 0;
+ int inactive = 0;
+ TrackSelection const & s = _editor.get_selection().tracks;
+ for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) {
+ RouteTimeAxisView* r = dynamic_cast<RouteTimeAxisView*> (*i);
+ if (!r) {
+ continue;
+ }
+
+ if (r->route()->active()) {
+ ++active;
+ } else {
+ ++inactive;
+ }
+ }
+
+ items.push_back (CheckMenuElem (_("Active")));
+ CheckMenuItem* i = dynamic_cast<CheckMenuItem *> (&items.back());
+ bool click_sets_active = true;
+ if (active > 0 && inactive == 0) {
+ i->set_active (true);
+ click_sets_active = false;
+ } else if (active > 0 && inactive > 0) {
+ i->set_inconsistent (true);
+ }
+ i->signal_activate().connect (sigc::bind (sigc::mem_fun (*this, &RouteUI::set_route_active), click_sets_active, true));
items.push_back (SeparatorElem());
- items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, false)));
+ items.push_back (MenuElem (_("Hide"), sigc::bind (sigc::mem_fun(_editor, &PublicEditor::hide_track_in_display), this, true)));
if (!Profile->get_sae()) {
- items.push_back (MenuElem (_("Remove"), sigc::mem_fun(*this, &RouteUI::remove_this_route)));
+ items.push_back (MenuElem (_("Remove"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true)));
} else {
items.push_front (SeparatorElem());
- items.push_front (MenuElem (_("Delete"), sigc::mem_fun(*this, &RouteUI::remove_this_route)));
+ items.push_front (MenuElem (_("Delete"), sigc::bind (sigc::mem_fun(*this, &RouteUI::remove_this_route), true)));
}
}
-static bool __reset_item (RadioMenuItem* item, RadioMenuItem* item_2)
-{
- item->set_active ();
- item_2->set_active ();
- return false;
-}
-
void
-RouteTimeAxisView::set_track_mode (TrackMode mode)
+RouteTimeAxisView::set_track_mode (TrackMode mode, bool apply_to_selection)
{
- if (_ignore_track_mode_change) {
- return;
- }
-
- RadioMenuItem* item;
- RadioMenuItem* other_item;
- RadioMenuItem* other_item_2;
-
- switch (mode) {
- case ARDOUR::Normal:
- item = normal_track_mode_item;
- other_item = non_layered_track_mode_item;
- other_item_2 = destructive_track_mode_item;
- break;
- case ARDOUR::NonLayered:
- item = non_layered_track_mode_item;
- other_item = normal_track_mode_item;
- other_item_2 = destructive_track_mode_item;
- break;
- case ARDOUR::Destructive:
- item = destructive_track_mode_item;
- other_item = normal_track_mode_item;
- other_item_2 = non_layered_track_mode_item;
- break;
- default:
- fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", mode) << endmsg;
- /*NOTREACHED*/
- return;
- }
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false));
+ } else {
- if (item && other_item && other_item_2 && track()->mode() != mode) {
- _set_track_mode (track().get(), mode, other_item, other_item_2);
- }
-}
+ bool needs_bounce;
-void
-RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item, RadioMenuItem* reset_item_2)
-{
- bool needs_bounce;
-
- if (!track->can_use_mode (mode, needs_bounce)) {
+ if (!track()->can_use_mode (mode, needs_bounce)) {
- if (!needs_bounce) {
- /* cannot be done */
- Glib::signal_idle().connect (sigc::bind (sigc::ptr_fun (__reset_item), reset_item, reset_item_2));
- return;
- } else {
- cerr << "would bounce this one\n";
- /* XXX: radio menu item becomes inconsistent with track state in this case */
- return;
+ if (!needs_bounce) {
+ /* cannot be done */
+ return;
+ } else {
+ cerr << "would bounce this one\n";
+ return;
+ }
}
- }
-
- track->set_mode (mode);
- rec_enable_button->remove ();
+ track()->set_mode (mode);
- switch (mode) {
- case ARDOUR::NonLayered:
- case ARDOUR::Normal:
- rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
- break;
- case ARDOUR::Destructive:
- rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
- break;
- }
-
- rec_enable_button->show_all ();
-}
+ rec_enable_button->remove ();
-void
-RouteTimeAxisView::track_mode_changed ()
-{
- RadioMenuItem* item;
+ switch (mode) {
+ case ARDOUR::NonLayered:
+ case ARDOUR::Normal:
+ rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_normal_red"))))));
+ break;
+ case ARDOUR::Destructive:
+ rec_enable_button->add (*(manage (new Image (::get_icon (X_("record_tape_red"))))));
+ break;
+ }
- switch (track()->mode()) {
- case ARDOUR::Normal:
- item = normal_track_mode_item;
- break;
- case ARDOUR::NonLayered:
- item = non_layered_track_mode_item;
- break;
- case ARDOUR::Destructive:
- item = destructive_track_mode_item;
- break;
- default:
- fatal << string_compose (_("programming error: %1 %2"), "illegal track mode in RouteTimeAxisView::set_track_mode", track()->mode()) << endmsg;
- /*NOTREACHED*/
- return;
+ rec_enable_button->show_all ();
}
-
- item->set_active ();
}
void
TimeAxisView::set_height (h);
- ensure_xml_node ();
-
if (_view) {
_view->set_height ((double) current_height());
}
- char buf[32];
- snprintf (buf, sizeof (buf), "%u", height);
- xml_node->add_property ("height", buf);
-
if (height >= preset_height (HeightNormal)) {
+
reset_meter();
- show_name_entry ();
- hide_name_label ();
gm.get_gain_slider().show();
mute_button->show();
playlist_button.show();
}
- } else if (height >= preset_height (HeightSmaller)) {
+ } else {
reset_meter();
- show_name_entry ();
- hide_name_label ();
gm.get_gain_slider().hide();
mute_button->show();
playlist_button.hide ();
}
- } else {
-
-
- /* don't allow name_entry to be hidden while
- it has focus, otherwise the GUI becomes unusable.
- */
-
- if (name_entry.has_focus()) {
- if (name_entry.get_text() != _route->name()) {
- name_entry_changed ();
- }
- controls_ebox.grab_focus ();
- }
-
- hide_name_entry ();
- show_name_label ();
-
- gm.get_gain_slider().hide();
- mute_button->hide();
- solo_button->hide();
- if (rec_enable_button)
- rec_enable_button->hide();
-
- route_group_button.hide ();
- automation_button.hide ();
- playlist_button.hide ();
- name_label.set_text (_route->name());
}
if (height_changed && !no_redraw) {
/* only emit the signal if the height really changed */
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ request_redraw ();
}
}
void
-RouteTimeAxisView::select_track_color ()
+RouteTimeAxisView::route_color_changed ()
{
- if (RouteUI::choose_color ()) {
-
- if (_view) {
- _view->apply_color (_color, StreamView::RegionColor);
- }
+ if (_view) {
+ _view->apply_color (color(), StreamView::RegionColor);
}
}
}
void
-RouteTimeAxisView::align_style_changed ()
-{
- switch (track()->alignment_style()) {
- case ExistingMaterial:
- if (!align_existing_item->get_active()) {
- align_existing_item->set_active();
- }
- break;
- case CaptureTime:
- if (!align_capture_item->get_active()) {
- align_capture_item->set_active();
- }
- break;
- }
-}
-
-void
-RouteTimeAxisView::set_align_style (AlignStyle style)
+RouteTimeAxisView::set_align_choice (RadioMenuItem* mitem, AlignChoice choice, bool apply_to_selection)
{
- RadioMenuItem* item;
-
- switch (style) {
- case ExistingMaterial:
- item = align_existing_item;
- break;
- case CaptureTime:
- item = align_capture_item;
- break;
- default:
- fatal << string_compose (_("programming error: %1 %2"), "illegal align style in RouteTimeAxisView::set_align_style", style) << endmsg;
- /*NOTREACHED*/
- return;
- }
+ if (!mitem->get_active()) {
+ /* this is one of the two calls made when these radio menu items change status. this one
+ is for the item that became inactive, and we want to ignore it.
+ */
+ return;
+ }
- if (item->get_active()) {
- track()->set_align_style (style);
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_choice, _1, mitem, choice, false));
+ } else {
+ if (track ()) {
+ track()->set_align_choice (choice);
+ }
}
}
name = pl->name();
- if (route_group() && route_group()->is_active()) {
+ if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) {
name = resolve_new_group_playlist_name(name, playlists_before_op);
}
name = pl->name();
- if (route_group() && route_group()->is_active()) {
+ if (route_group() && route_group()->is_active() && route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) {
name = resolve_new_group_playlist_name(name,playlists_before_op);
}
void
RouteTimeAxisView::name_entry_changed ()
{
- string x;
-
- x = name_entry.get_text ();
+ string x = name_entry.get_text ();
if (x == _route->name()) {
return;
}
- strip_whitespace_edges(x);
+ strip_whitespace_edges (x);
if (x.length() == 0) {
name_entry.set_text (_route->name());
return;
}
- if (!_session->route_name_unique (x)) {
- ARDOUR_UI::instance()->popup_error (_("A track already exists with that name"));
- name_entry.set_text (_route->name());
- } else if (_session->route_name_internal (x)) {
+ if (_session->route_name_internal (x)) {
ARDOUR_UI::instance()->popup_error (string_compose (_("You cannot create a track with that name as it is reserved for %1"),
- PROGRAM_NAME));
- name_entry.set_text (_route->name());
- } else {
+ PROGRAM_NAME));
+ name_entry.grab_focus ();
+ } else if (RouteUI::verify_new_route_name (x)) {
_route->set_name (x);
+ } else {
+ name_entry.grab_focus ();
}
}
playlist->clear_owned_changes ();
switch (op) {
+ case Delete:
+ if (playlist->cut (time) != 0) {
+ vector<Command*> cmds;
+ playlist->rdiff (cmds);
+ _session->add_commands (cmds);
+
+ _session->add_command (new StatefulDiffCommand (playlist));
+ }
+ break;
+
case Cut:
if ((what_we_got = playlist->cut (time)) != 0) {
_editor.get_cut_buffer().add (what_we_got);
-
vector<Command*> cmds;
playlist->rdiff (cmds);
_session->add_commands (cmds);
-
+
_session->add_command (new StatefulDiffCommand (playlist));
}
break;
return false;
}
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("paste to %1\n", pos));
+
if (track()->speed() != 1.0f) {
pos = session_frame_to_track_frame (pos, track()->speed());
+ DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("modified paste to %1\n", pos));
}
pl->clear_changes ();
playlist_action_menu->set_name ("ArdourContextMenu");
playlist_items.clear();
- delete playlist_menu;
-
- vector<boost::shared_ptr<Playlist> > playlists, playlists_tr;
- boost::shared_ptr<Track> tr = track();
RadioMenuItem::Group playlist_group;
+ boost::shared_ptr<Track> tr = track ();
- _session->playlists->get (playlists);
-
- /* find the playlists for this diskstream */
- for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
- if (((*i)->get_orig_diskstream_id() == tr->diskstream_id()) || (tr->playlist()->id() == (*i)->id())) {
- playlists_tr.push_back(*i);
- }
- }
+ vector<boost::shared_ptr<Playlist> > playlists_tr = _session->playlists->playlists_for_track (tr);
/* sort the playlists */
PlaylistSorter cmp;
sort (playlists_tr.begin(), playlists_tr.end(), cmp);
-
+
/* add the playlists to the menu */
for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists_tr.begin(); i != playlists_tr.end(); ++i) {
playlist_items.push_back (RadioMenuElem (playlist_group, (*i)->name()));
RadioMenuItem *item = static_cast<RadioMenuItem*>(&playlist_items.back());
item->signal_toggled().connect(sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::use_playlist), item, boost::weak_ptr<Playlist> (*i)));
-
+
if (tr->playlist()->id() == (*i)->id()) {
item->set_active();
-
+
}
}
-
+
playlist_items.push_back (SeparatorElem());
playlist_items.push_back (MenuElem (_("Rename..."), sigc::mem_fun(*this, &RouteTimeAxisView::rename_current_playlist)));
playlist_items.push_back (SeparatorElem());
- if (!route_group() || !route_group()->is_active()) {
+ if (!route_group() || !route_group()->is_active() || !route_group()->enabled_property (ARDOUR::Properties::edit.property_id)) {
playlist_items.push_back (MenuElem (_("New..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::new_playlists), this)));
playlist_items.push_back (MenuElem (_("New Copy..."), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::copy_playlists), this)));
playlist_items.push_back (MenuElem (_("Clear Current"), sigc::bind(sigc::mem_fun(_editor, &PublicEditor::clear_playlists), this)));
playlist_items.push_back (SeparatorElem());
- playlist_items.push_back (MenuElem(_("Select from all..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
+ playlist_items.push_back (MenuElem(_("Select From All..."), sigc::mem_fun(*this, &RouteTimeAxisView::show_playlist_selector)));
}
void
return;
}
- boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
+ if (track()->playlist() == pl) {
+ // exit when use_playlist is called by the creation of the playlist menu
+ // or the playlist choice is unchanged
+ return;
+ }
- if (apl) {
- if (track()->playlist() == apl) {
- // exit when use_playlist is called by the creation of the playlist menu
- // or the playlist choice is unchanged
+ track()->use_playlist (pl);
+
+ RouteGroup* rg = route_group();
+
+ if (rg && rg->is_active() && rg->enabled_property (ARDOUR::Properties::edit.property_id)) {
+ std::string group_string = "." + rg->name() + ".";
+
+ std::string take_name = pl->name();
+ std::string::size_type idx = take_name.find(group_string);
+
+ if (idx == std::string::npos)
return;
- }
- track()->use_playlist (apl);
-
- if (route_group() && route_group()->is_active()) {
- std::string group_string = "."+route_group()->name()+".";
-
- std::string take_name = apl->name();
- std::string::size_type idx = take_name.find(group_string);
-
- if (idx == std::string::npos)
- return;
-
- take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
-
- boost::shared_ptr<RouteList> rl (route_group()->route_list());
-
- for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
- if ( (*i) == this->route()) {
- continue;
- }
-
- std::string playlist_name = (*i)->name()+group_string+take_name;
-
- boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
- if (!track) {
- std::cerr << "route " << (*i)->name() << " is not a Track" << std::endl;
- continue;
- }
-
- boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
- if (!ipl) {
- // No playlist for this track for this take yet, make it
- track->use_new_playlist();
- track->playlist()->set_name(playlist_name);
- } else {
- track->use_playlist(ipl);
- }
+
+ take_name = take_name.substr(idx + group_string.length()); // find the bit containing the take number / name
+
+ boost::shared_ptr<RouteList> rl (rg->route_list());
+
+ for (RouteList::const_iterator i = rl->begin(); i != rl->end(); ++i) {
+ if ( (*i) == this->route()) {
+ continue;
+ }
+
+ std::string playlist_name = (*i)->name()+group_string+take_name;
+
+ boost::shared_ptr<Track> track = boost::dynamic_pointer_cast<Track>(*i);
+ if (!track) {
+ continue;
+ }
+
+ boost::shared_ptr<Playlist> ipl = session()->playlists->by_name(playlist_name);
+ if (!ipl) {
+ // No playlist for this track for this take yet, make it
+ track->use_new_playlist();
+ track->playlist()->set_name(playlist_name);
+ } else {
+ track->use_playlist(ipl);
}
}
}
{
boost::shared_ptr<AutomationTimeAxisView> track = automation_child (param);
Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
-
+
if (!track) {
/* it doesn't exist yet, so we don't care about the button state: just add it */
create_automation_child (param, true);
} else {
assert (menu);
bool yn = menu->get_active();
- if (track->set_visibility (menu->get_active()) && yn) {
-
+ bool changed = false;
+
+ if ((changed = track->set_marked_for_display (menu->get_active())) && yn) {
+
/* we made it visible, now trigger a redisplay. if it was hidden, then automation_track_hidden()
will have done that for us.
*/
-
- if (!no_redraw) {
- _route->gui_changed (X_("track_height"), (void *) 0); /* EMIT_SIGNAL */
- }
+
+ if (changed && !no_redraw) {
+ request_redraw ();
+ }
}
}
}
Gtk::CheckMenuItem* menu = automation_child_menu_item (param);
- // if Evoral::Parameter::operator< doesn't obey strict weak ordering, we may crash here....
- track->get_state_node()->add_property (X_("shown"), X_("no"));
-
if (menu && !_hidden) {
ignore_toggle = true;
menu->set_active (false);
}
if (_route && !no_redraw) {
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ request_redraw ();
}
}
void
-RouteTimeAxisView::show_all_automation ()
+RouteTimeAxisView::show_all_automation (bool apply_to_selection)
{
- no_redraw = true;
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_all_automation, _1, false));
+ } else {
+ no_redraw = true;
- /* Show our automation */
+ /* Show our automation */
- for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
- i->second->set_marked_for_display (true);
- i->second->canvas_display()->show();
- i->second->get_state_node()->add_property ("shown", X_("yes"));
+ for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
+ i->second->set_marked_for_display (true);
- Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
-
- if (menu) {
- menu->set_active(true);
+ Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
+
+ if (menu) {
+ menu->set_active(true);
+ }
}
- }
- /* Show processor automation */
+ /* Show processor automation */
- for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
- for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- if ((*ii)->view == 0) {
- add_processor_automation_curve ((*i)->processor, (*ii)->what);
- }
+ for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
+ for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ if ((*ii)->view == 0) {
+ add_processor_automation_curve ((*i)->processor, (*ii)->what);
+ }
- (*ii)->menu_item->set_active (true);
+ (*ii)->menu_item->set_active (true);
+ }
}
- }
- no_redraw = false;
+ no_redraw = false;
- /* Redraw */
+ /* Redraw */
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ request_redraw ();
+ }
}
void
-RouteTimeAxisView::show_existing_automation ()
+RouteTimeAxisView::show_existing_automation (bool apply_to_selection)
{
- no_redraw = true;
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::show_existing_automation, _1, false));
+ } else {
+ no_redraw = true;
- /* Show our automation */
+ /* Show our automation */
- for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
- if (i->second->has_automation()) {
- i->second->set_marked_for_display (true);
- i->second->canvas_display()->show();
- i->second->get_state_node()->add_property ("shown", X_("yes"));
+ for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
+ if (i->second->has_automation()) {
+ i->second->set_marked_for_display (true);
- Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
- if (menu) {
- menu->set_active(true);
+ Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
+ if (menu) {
+ menu->set_active(true);
+ }
}
}
- }
+ /* Show processor automation */
- /* Show processor automation */
-
- for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
- for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
- (*ii)->menu_item->set_active (true);
+ for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
+ for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ if ((*ii)->view != 0 && (*i)->processor->control((*ii)->what)->list()->size() > 0) {
+ (*ii)->menu_item->set_active (true);
+ }
}
}
- }
- no_redraw = false;
+ no_redraw = false;
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ request_redraw ();
+ }
}
void
-RouteTimeAxisView::hide_all_automation ()
+RouteTimeAxisView::hide_all_automation (bool apply_to_selection)
{
- no_redraw = true;
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::hide_all_automation, _1, false));
+ } else {
+ no_redraw = true;
- /* Hide our automation */
+ /* Hide our automation */
- for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
- i->second->set_marked_for_display (false);
- i->second->hide ();
- i->second->get_state_node()->add_property ("shown", X_("no"));
+ for (AutomationTracks::iterator i = _automation_tracks.begin(); i != _automation_tracks.end(); ++i) {
+ i->second->set_marked_for_display (false);
- Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
-
- if (menu) {
- menu->set_active (false);
+ Gtk::CheckMenuItem* menu = automation_child_menu_item (i->first);
+
+ if (menu) {
+ menu->set_active (false);
+ }
}
- }
- /* Hide processor automation */
+ /* Hide processor automation */
- for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
- for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- (*ii)->menu_item->set_active (false);
+ for (list<ProcessorAutomationInfo*>::iterator i = processor_automation.begin(); i != processor_automation.end(); ++i) {
+ for (vector<ProcessorAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ (*ii)->menu_item->set_active (false);
+ }
}
- }
- no_redraw = false;
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ no_redraw = false;
+ request_redraw ();
+ }
}
/* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */
for (Children::iterator i = children.begin(); i != children.end(); ++i) {
boost::shared_ptr<AutomationTimeAxisView> atv;
-
+
if ((atv = boost::dynamic_pointer_cast<AutomationTimeAxisView> (*i)) != 0) {
atv->add_ghost(rv);
}
return 0;
}
-static string
-legalize_for_xml_node (string str)
-{
- string::size_type pos;
- string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_=:";
- string legal;
-
- legal = str;
- pos = 0;
-
- while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
- legal.replace (pos, 1, "_");
- pos += 1;
- }
-
- return legal;
-}
-
-
+/** Add an AutomationTimeAxisView to display automation for a processor's parameter */
void
RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor> processor, Evoral::Parameter what)
{
return;
}
- name = processor->describe_parameter (what);
-
- /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
-
- /* FIXME: ew */
-
- char state_name[256];
- snprintf (state_name, sizeof (state_name), "%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id());
-
boost::shared_ptr<AutomationControl> control
- = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
-
+ = boost::dynamic_pointer_cast<AutomationControl>(processor->control(what, true));
+
pan->view = boost::shared_ptr<AutomationTimeAxisView>(
new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (),
- _editor, *this, false, parent_canvas, name, state_name));
+ _editor, *this, false, parent_canvas,
+ processor->describe_parameter (what), processor->name()));
pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
- if (!pan->view->marked_for_display()) {
- pan->view->hide ();
- } else {
- pan->menu_item->set_active (true);
- }
-
- add_child (pan->view);
+ add_automation_child (control->parameter(), pan->view, pan->view->marked_for_display ());
if (_view) {
_view->foreach_regionview (sigc::mem_fun(*pan->view.get(), &TimeAxisView::add_ghost));
}
-
- processor->mark_automation_visible (what, true);
}
void
-RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor> i)
+RouteTimeAxisView::processor_automation_track_hidden (RouteTimeAxisView::ProcessorAutomationNode* pan, boost::shared_ptr<Processor>)
{
if (!_hidden) {
pan->menu_item->set_active (false);
}
- i->mark_automation_visible (pan->what, false);
-
if (!no_redraw) {
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ request_redraw ();
}
}
RouteTimeAxisView::add_existing_processor_automation_curves (boost::weak_ptr<Processor> p)
{
boost::shared_ptr<Processor> processor (p.lock ());
- if (!processor) {
+
+ if (!processor || boost::dynamic_pointer_cast<Amp> (processor)) {
+ /* The Amp processor is a special case and is dealt with separately */
return;
}
- set<Evoral::Parameter> s;
- boost::shared_ptr<AutomationLine> al;
+ set<Evoral::Parameter> existing;
- processor->what_has_visible_data (s);
+ processor->what_has_data (existing);
- for (set<Evoral::Parameter>::iterator i = s.begin(); i != s.end(); ++i) {
+ for (set<Evoral::Parameter>::iterator i = existing.begin(); i != existing.end(); ++i) {
+
+ Evoral::Parameter param (*i);
+ boost::shared_ptr<AutomationLine> al;
- if ((al = find_processor_automation_curve (processor, *i)) != 0) {
+ if ((al = find_processor_automation_curve (processor, param)) != 0) {
al->queue_reset ();
} else {
- add_processor_automation_curve (processor, (*i));
+ add_processor_automation_curve (processor, param);
}
}
}
{
using namespace Menu_Helpers;
- XMLProperty* prop;
- XMLNode* node;
-
add_child (track);
track->Hiding.connect (sigc::bind (sigc::mem_fun (*this, &RouteTimeAxisView::automation_track_hidden), param));
- bool hideit = (!show);
+ _automation_tracks[param] = track;
- if ((node = track->get_state_node()) != 0) {
- if ((prop = node->property ("shown")) != 0) {
- if (string_is_affirmative (prop->value())) {
- hideit = false;
- }
- }
+ /* existing state overrides "show" argument */
+ string s = track->gui_property ("visible");
+ if (!s.empty()) {
+ show = string_is_affirmative (s);
}
- _automation_tracks[param] = track;
-
- track->set_visibility (!hideit);
+ /* this might or might not change the visibility status, so don't rely on it */
+ track->set_marked_for_display (show);
- if (!no_redraw) {
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+ if (show && !no_redraw) {
+ request_redraw ();
}
if (!EventTypeMap::instance().is_midi_parameter(param)) {
return;
}
+ /* we use this override to veto the Amp processor from the plugin menu,
+ as its automation lane can be accessed using the special "Fader" menu
+ option
+ */
+
+ if (boost::dynamic_pointer_cast<Amp> (processor) != 0) {
+ return;
+ }
+
using namespace Menu_Helpers;
ProcessorAutomationInfo *rai;
list<ProcessorAutomationInfo*>::iterator x;
const std::set<Evoral::Parameter>& automatable = processor->what_can_be_automated ();
- std::set<Evoral::Parameter> has_visible_automation;
-
- processor->what_has_visible_data(has_visible_automation);
if (automatable.empty()) {
return;
items.clear ();
+ std::set<Evoral::Parameter> has_visible_automation;
+ AutomationTimeAxisView::what_has_visible_automation (processor, has_visible_automation);
+
for (std::set<Evoral::Parameter>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
ProcessorAutomationNode* pan;
items.push_back (CheckMenuElem (name));
mitem = dynamic_cast<CheckMenuItem*> (&items.back());
-
+
_subplugin_menu_map[*i] = mitem;
if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
redraw = true;
}
- if (pan->view && showit != pan->view->marked_for_display()) {
-
- if (showit) {
- pan->view->set_marked_for_display (true);
- pan->view->canvas_display()->show();
- pan->view->canvas_background()->show();
- } else {
- rai->processor->mark_automation_visible (pan->what, true);
- pan->view->set_marked_for_display (false);
- pan->view->hide ();
- }
-
+ if (pan->view && pan->view->set_marked_for_display (showit)) {
redraw = true;
-
}
-
+
if (redraw && !no_redraw) {
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
-
+ request_redraw ();
}
}
(*i)->valid = false;
}
- _subplugin_menu_map.clear ();
- subplugin_menu.items().clear ();
-
- _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_processor_to_subplugin_menu));
- _route->foreach_processor (sigc::mem_fun (*this, &RouteTimeAxisView::add_existing_processor_automation_curves));
+ setup_processor_menu_and_curves ();
bool deleted_processor_automation = false;
}
if (deleted_processor_automation && !no_redraw) {
- _route->gui_changed ("track_height", this);
+ request_redraw ();
}
}
}
void
-RouteTimeAxisView::set_layer_display (LayerDisplay d)
+RouteTimeAxisView::set_layer_display (LayerDisplay d, bool apply_to_selection)
{
- if (_view) {
- _view->set_layer_display (d);
- }
+ if (apply_to_selection) {
+ _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_layer_display, _1, d, false));
+ } else {
- ensure_xml_node ();
- xml_node->add_property (N_("layer-display"), enum_2_string (d));
+ if (_view) {
+ _view->set_layer_display (d);
+ }
+
+ set_gui_property (X_("layer-display"), enum_2_string (d));
+ }
}
LayerDisplay
}
void
-RouteTimeAxisView::add_underlay (StreamView* v, bool update_xml)
+RouteTimeAxisView::add_underlay (StreamView* v, bool /*update_xml*/)
{
if (!v) {
return;
v->foreach_regionview(sigc::mem_fun(*this, &RouteTimeAxisView::add_ghost));
+#ifdef GUI_OBJECT_STATE_FIX_REQUIRED
if (update_xml) {
if (!underlay_xml_node) {
- ensure_xml_node();
underlay_xml_node = xml_node->add_child("Underlays");
}
XMLProperty* prop = node->add_property("id");
prop->set_value(v->trackview().route()->id().to_s());
}
+#endif
}
}
rec_enable_button_label.set_text (_("r"));
if (_route && _route->solo_safe()) {
- solo_button_label.set_text (X_("!"));
+ solo_button->remove ();
+ if (solo_safe_image == 0) {
+ solo_safe_image = new Gtk::Image (::get_icon("solo-safe-enabled"));
+ solo_safe_image->show ();
+ }
+ solo_button->add (*solo_safe_image);
} else {
+ solo_button->remove ();
+ solo_button->add (solo_button_label);
+ solo_button_label.show ();
if (Config->get_solo_control_is_listen_control()) {
switch (Config->get_listen_position()) {
case AfterFaderListen:
if (i != _main_automation_menu_map.end()) {
return i->second;
}
-
+
i = _subplugin_menu_map.find (param);
if (i != _subplugin_menu_map.end()) {
return i->second;
false,
parent_canvas,
_route->amp()->describe_parameter(param)));
-
+
+ if (_view) {
+ _view->foreach_regionview (sigc::mem_fun (*gain_track.get(), &TimeAxisView::add_ghost));
+ }
+
add_automation_child (Evoral::Parameter(GainAutomation), gain_track, show);
}
+
+static
+void add_region_to_list (RegionView* rv, Playlist::RegionList* l)
+{
+ l->push_back (rv->region());
+}
+
+RegionView*
+RouteTimeAxisView::combine_regions ()
+{
+ /* as of may 2011, we do not offer uncombine for MIDI tracks
+ */
+
+ if (!is_audio_track()) {
+ return 0;
+ }
+
+ if (!_view) {
+ return 0;
+ }
+
+ Playlist::RegionList selected_regions;
+ boost::shared_ptr<Playlist> playlist = track()->playlist();
+
+ _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
+
+ if (selected_regions.size() < 2) {
+ return 0;
+ }
+
+ playlist->clear_changes ();
+ boost::shared_ptr<Region> compound_region = playlist->combine (selected_regions);
+
+ _session->add_command (new StatefulDiffCommand (playlist));
+ /* make the new region be selected */
+
+ return _view->find_view (compound_region);
+}
+
+void
+RouteTimeAxisView::uncombine_regions ()
+{
+ /* as of may 2011, we do not offer uncombine for MIDI tracks
+ */
+ if (!is_audio_track()) {
+ return;
+ }
+
+ if (!_view) {
+ return;
+ }
+
+ Playlist::RegionList selected_regions;
+ boost::shared_ptr<Playlist> playlist = track()->playlist();
+
+ /* have to grab selected regions first because the uncombine is going
+ * to change that in the middle of the list traverse
+ */
+
+ _view->foreach_selected_regionview (sigc::bind (sigc::ptr_fun (add_region_to_list), &selected_regions));
+
+ playlist->clear_changes ();
+
+ for (Playlist::RegionList::iterator i = selected_regions.begin(); i != selected_regions.end(); ++i) {
+ playlist->uncombine (*i);
+ }
+
+ _session->add_command (new StatefulDiffCommand (playlist));
+}
+
+string
+RouteTimeAxisView::state_id() const
+{
+ return string_compose ("rtav %1", _route->id().to_s());
+}
+