X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Froute_time_axis.cc;h=e723aeee4005ce55bb65e81609ca8fa43eaf296c;hb=89d6f40e33933b12a40079e391a96856bfa79e2a;hp=7c7753ae31f7801fbb887964c15ca979b4143f3f;hpb=12aa01660a20e9b5d923f5c7bb21ab3a3d6ba9cf;p=ardour.git diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index 7c7753ae31..e723aeee40 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -23,7 +23,7 @@ #include #include #include -#include +#include #include #include @@ -61,6 +61,8 @@ #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" #include "canvas_impl.h" @@ -111,14 +113,12 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh , playlist_button (_("p")) , automation_button (_("a")) , gm (sess, slider, true, 115) - , _ignore_track_mode_change (false) { 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; @@ -134,9 +134,6 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh 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; @@ -148,7 +145,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh playlist_button.unset_flags (Gtk::CAN_FOCUS); automation_button.unset_flags (Gtk::CAN_FOCUS); - route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::edit_click), false); + route_group_button.signal_button_release_event().connect (sigc::mem_fun(*this, &RouteTimeAxisView::route_group_click), false); playlist_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::playlist_click)); automation_button.signal_clicked().connect (sigc::mem_fun(*this, &RouteTimeAxisView::automation_click)); @@ -215,7 +212,6 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh if (is_track()) { - track()->TrackModeChanged.connect (*this, invalidator (*this), boost::bind (&RouteTimeAxisView::track_mode_changed, this), gui_context()); 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()); @@ -225,6 +221,7 @@ RouteTimeAxisView::RouteTimeAxisView (PublicEditor& ed, Session* sess, boost::sh } _editor.ZoomChanged.connect (sigc::mem_fun(*this, &RouteTimeAxisView::reset_samples_per_unit)); + _editor.HorizontalPositionChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::horizontal_position_changed)); ColorsChanged.connect (sigc::mem_fun (*this, &RouteTimeAxisView::color_handler)); PropertyList* plist = new PropertyList(); @@ -248,9 +245,6 @@ RouteTimeAxisView::~RouteTimeAxisView () delete *i; } - delete playlist_menu; - playlist_menu = 0; - delete playlist_action_menu; playlist_action_menu = 0; @@ -277,7 +271,7 @@ RouteTimeAxisView::post_construct () } gint -RouteTimeAxisView::edit_click (GdkEventButton *ev) +RouteTimeAxisView::route_group_click (GdkEventButton *ev) { if (Keyboard::modifier_state_equals (ev->state, Keyboard::PrimaryModifier)) { if (_route->route_group()) { @@ -286,8 +280,8 @@ RouteTimeAxisView::edit_click (GdkEventButton *ev) return false; } - route_group_menu->rebuild (_route->route_group ()); - route_group_menu->popup (ev->button, ev->time); + route_group_menu->build (_route->route_group ()); + route_group_menu->menu()->popup (ev->button, ev->time); return false; } @@ -319,6 +313,10 @@ RouteTimeAxisView::label_view () name_entry.set_text (x); } + if (x != name_label.get_text()) { + name_label.set_text (x); + } + ARDOUR_UI::instance()->set_tip (name_entry, x); } @@ -332,7 +330,6 @@ RouteTimeAxisView::route_property_changed (const PropertyChange& what_changed) void RouteTimeAxisView::take_name_changed (void *src) - { if (src != this) { label_view (); @@ -342,15 +339,7 @@ RouteTimeAxisView::take_name_changed (void *src) void RouteTimeAxisView::playlist_click () { - // always build a new action menu - - delete playlist_action_menu; - - playlist_action_menu = new Menu; - playlist_action_menu->set_name ("ArdourContextMenu"); - - build_playlist_menu (playlist_action_menu); - + build_playlist_menu (); conditionally_add_to_selection (); playlist_action_menu->popup (1, gtk_get_current_event_time()); } @@ -443,36 +432,76 @@ RouteTimeAxisView::build_display_menu () 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)); items.push_back (SeparatorElem()); 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 (&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 (&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)); if (!Profile->get_sae()) { @@ -482,23 +511,41 @@ RouteTimeAxisView::build_display_menu () 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(&alignment_items.back()); - if (track()->alignment_style() == ExistingMaterial) { - align_existing_item->set_active(); + + /* Same verbose hacks as for the layering options above */ + + int existing = 0; + int capture = 0; + TrackSelection const & s = _editor.get_selection().tracks; + for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { + RouteTimeAxisView* r = dynamic_cast (*i); + if (!r || !r->is_track ()) { + continue; + } + + switch (r->track()->alignment_style()) { + case ExistingMaterial: + ++existing; + break; + case CaptureTime: + ++capture; + break; + } } - 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(&alignment_items.back()); - if (track()->alignment_style() == CaptureTime) { - align_capture_item->set_active(); - } + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Existing Material"))); + RadioMenuItem* i = dynamic_cast (&alignment_items.back()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial, true)); + i->set_active (existing != 0 && capture == 0); + i->set_inconsistent (existing != 0 && capture != 0); + + alignment_items.push_back (RadioMenuElem (align_group, _("Align With Capture Time"))); + i = dynamic_cast (&alignment_items.back()); + i->signal_activate().connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime, true)); + i->set_active (existing == 0 && capture != 0); + i->set_inconsistent (existing != 0 && capture != 0); items.push_back (MenuElem (_("Alignment"), *alignment_menu)); - track()->AlignmentStyleChanged.connect (route_connections, invalidator (*this), boost::bind (&RouteTimeAxisView::align_style_changed, this), gui_context()); Menu* mode_menu = manage (new Menu); MenuList& mode_items = mode_menu->items (); @@ -506,36 +553,46 @@ RouteTimeAxisView::build_display_menu () 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(&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(&mode_items.back()); + for (TrackSelection::const_iterator i = s.begin(); i != s.end(); ++i) { + RouteTimeAxisView* r = dynamic_cast (*i); + if (!r || !r->is_track ()) { + continue; + } + + switch (r->track()->mode()) { + case Normal: + ++normal; + break; + case Destructive: + ++tape; + break; + case NonLayered: + ++non_layered; + break; + } + } - 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(&mode_items.back()); + mode_items.push_back (RadioMenuElem (mode_group, _("Normal Mode"))); + i = dynamic_cast (&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)); + mode_items.push_back (RadioMenuElem (mode_group, _("Tape Mode"))); + i = dynamic_cast (&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)); - _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, _("Non-Layered Mode"))); + i = dynamic_cast (&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)); } @@ -546,6 +603,19 @@ RouteTimeAxisView::build_display_menu () } items.push_back (SeparatorElem()); + + 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 (); + route_group_menu->build (_route->route_group ()); + items.push_back (MenuElem (_("Route Group"), *route_group_menu->menu ())); + + build_automation_action_menu (); + 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))); @@ -562,112 +632,46 @@ RouteTimeAxisView::build_display_menu () } } -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 (item && other_item && other_item_2 && track()->mode() != mode) { - _set_track_mode (track().get(), mode, other_item, other_item_2); - } -} - -void -RouteTimeAxisView::_set_track_mode (Track* track, TrackMode mode, RadioMenuItem* reset_item, RadioMenuItem* reset_item_2) -{ - bool needs_bounce; + if (apply_to_selection) { + _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_track_mode, _1, mode, false)); + } else { - if (!track->can_use_mode (mode, needs_bounce)) { + bool 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 (!track()->can_use_mode (mode, needs_bounce)) { + + if (!needs_bounce) { + /* cannot be done */ + return; + } else { + cerr << "would bounce this one\n"; + return; + } } + + track()->set_mode (mode); + + rec_enable_button->remove (); + + 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 (); } - - track->set_mode (mode); - - rec_enable_button->remove (); - - 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 (); -} - -void -RouteTimeAxisView::track_mode_changed () -{ - RadioMenuItem* item; - - 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; - } - - item->set_active (); } void -RouteTimeAxisView::show_timestretch (nframes_t start, nframes_t end) +RouteTimeAxisView::show_timestretch (framepos_t start, framepos_t end) { double x1; double x2; @@ -852,13 +856,12 @@ RouteTimeAxisView::set_height (uint32_t h) } void -RouteTimeAxisView::select_track_color () +RouteTimeAxisView::set_color (Gdk::Color const & c) { - if (RouteUI::choose_color ()) { - - if (_view) { - _view->apply_color (_color, StreamView::RegionColor); - } + RouteUI::set_color (c); + + if (_view) { + _view->apply_color (_color, StreamView::RegionColor); } } @@ -868,6 +871,14 @@ RouteTimeAxisView::reset_samples_per_unit () set_samples_per_unit (_editor.get_current_zoom()); } +void +RouteTimeAxisView::horizontal_position_changed () +{ + if (_view) { + _view->horizontal_position_changed (); + } +} + void RouteTimeAxisView::set_samples_per_unit (double spu) { @@ -885,42 +896,14 @@ RouteTimeAxisView::set_samples_per_unit (double spu) } void -RouteTimeAxisView::align_style_changed () +RouteTimeAxisView::set_align_style (AlignStyle style, bool apply_to_selection) { - 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(); + if (apply_to_selection) { + _editor.get_selection().tracks.foreach_route_time_axis (boost::bind (&RouteTimeAxisView::set_align_style, _1, style, false)); + } else { + if (track ()) { + track()->set_align_style (style); } - break; - } -} - -void -RouteTimeAxisView::set_align_style (AlignStyle style) -{ - 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 (item->get_active()) { - track()->set_align_style (style); } } @@ -1195,8 +1178,8 @@ RouteTimeAxisView::get_selectables (framepos_t start, framepos_t end, double top speed = track()->speed(); } - nframes_t start_adjusted = session_frame_to_track_frame(start, speed); - nframes_t end_adjusted = session_frame_to_track_frame(end, speed); + framepos_t const start_adjusted = session_frame_to_track_frame(start, speed); + framepos_t const end_adjusted = session_frame_to_track_frame(end, speed); if ((_view && ((top < 0.0 && bot < 0.0))) || touched (top, bot)) { _view->get_selectables (start_adjusted, end_adjusted, top, bot, results); @@ -1273,7 +1256,8 @@ RouteTimeAxisView::name_entry_changed () 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)) { - ARDOUR_UI::instance()->popup_error (_("You cannot create a track with that name as it is reserved for Ardour")); + 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 { _route->set_name (x); @@ -1281,7 +1265,7 @@ RouteTimeAxisView::name_entry_changed () } boost::shared_ptr -RouteTimeAxisView::find_next_region (nframes_t pos, RegionPoint point, int32_t dir) +RouteTimeAxisView::find_next_region (framepos_t pos, RegionPoint point, int32_t dir) { boost::shared_ptr pl = playlist (); @@ -1292,8 +1276,8 @@ RouteTimeAxisView::find_next_region (nframes_t pos, RegionPoint point, int32_t d return boost::shared_ptr (); } -nframes64_t -RouteTimeAxisView::find_next_region_boundary (nframes64_t pos, int32_t dir) +framepos_t +RouteTimeAxisView::find_next_region_boundary (framepos_t pos, int32_t dir) { boost::shared_ptr pl = playlist (); @@ -1327,21 +1311,18 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) } } - playlist->clear_history (); - playlist->clear_owned_history (); + playlist->clear_changes (); + playlist->clear_owned_changes (); switch (op) { case Cut: if ((what_we_got = playlist->cut (time)) != 0) { _editor.get_cut_buffer().add (what_we_got); - vector cmds; - + vector cmds; playlist->rdiff (cmds); - - for (vector::iterator c = cmds.begin(); c != cmds.end(); ++c) { - _session->add_command (*c); - } + _session->add_commands (cmds); + _session->add_command (new StatefulDiffCommand (playlist)); } break; @@ -1353,13 +1334,10 @@ RouteTimeAxisView::cut_copy_clear (Selection& selection, CutCopyOp op) case Clear: if ((what_we_got = playlist->cut (time)) != 0) { - vector cmds; - + + vector cmds; playlist->rdiff (cmds); - - for (vector::iterator c = cmds.begin(); c != cmds.end(); ++c) { - _session->add_command (*c); - } + _session->add_commands (cmds); _session->add_command (new StatefulDiffCommand (playlist)); what_we_got->release (); } @@ -1383,11 +1361,14 @@ RouteTimeAxisView::paste (framepos_t pos, float times, Selection& selection, siz 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_history (); + pl->clear_changes (); pl->paste (*p, pos, times); _session->add_command (new StatefulDiffCommand (pl)); @@ -1402,20 +1383,21 @@ struct PlaylistSorter { }; void -RouteTimeAxisView::build_playlist_menu (Gtk::Menu * menu) +RouteTimeAxisView::build_playlist_menu () { using namespace Menu_Helpers; - if (!menu || !is_track()) { + if (!is_track()) { return; } - MenuList& playlist_items = menu->items(); - menu->set_name ("ArdourContextMenu"); - playlist_items.clear(); - - delete playlist_menu; + delete playlist_action_menu; + playlist_action_menu = new Menu; + playlist_action_menu->set_name ("ArdourContextMenu"); + MenuList& playlist_items = playlist_action_menu->items(); + playlist_action_menu->set_name ("ArdourContextMenu"); + playlist_items.clear(); vector > playlists, playlists_tr; boost::shared_ptr tr = track(); @@ -1740,13 +1722,11 @@ void RouteTimeAxisView::region_view_added (RegionView* rv) { /* XXX need to find out if automation children have automationstreamviews. If yes, no ghosts */ - if (is_audio_track()) { - for (Children::iterator i = children.begin(); i != children.end(); ++i) { - boost::shared_ptr atv; - - if ((atv = boost::dynamic_pointer_cast (*i)) != 0) { - atv->add_ghost(rv); - } + for (Children::iterator i = children.begin(); i != children.end(); ++i) { + boost::shared_ptr atv; + + if ((atv = boost::dynamic_pointer_cast (*i)) != 0) { + atv->add_ghost(rv); } } @@ -1820,9 +1800,10 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr ProcessorAutomationNode* pan; if ((pan = find_processor_automation_node (processor, what)) == 0) { - error << _("programming error: ") - << string_compose (X_("processor automation curve for %1:%2 not registered with track!"), - processor->name(), what) + /* session state may never have been saved with new plugin */ + error << _("programming error: ") + << string_compose (X_("processor automation curve for %1:%2/%3/%4 not registered with track!"), + processor->name(), what.type(), (int) what.channel(), what.id() ) << endmsg; /*NOTREACHED*/ return; @@ -1839,14 +1820,14 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr /* FIXME: ew */ char state_name[256]; - snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id()); + snprintf (state_name, sizeof (state_name), "%s-%" PRIu32, legalize_for_xml_node (processor->name()).c_str(), what.id()); boost::shared_ptr control = boost::dynamic_pointer_cast(processor->control(what, true)); pan->view = boost::shared_ptr( - new AutomationTimeAxisView (_session, _route, processor, control, - _editor, *this, false, parent_canvas, name, state_name)); + new AutomationTimeAxisView (_session, _route, processor, control, control->parameter (), + _editor, *this, false, parent_canvas, name, state_name)); pan->view->Hiding.connect (sigc::bind (sigc::mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor)); @@ -2144,14 +2125,19 @@ RouteTimeAxisView::update_rec_display () } 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 { + + if (_view) { + _view->set_layer_display (d); + } + + ensure_xml_node (); + xml_node->add_property (N_("layer-display"), enum_2_string (d)); } - - ensure_xml_node (); - xml_node->add_property (N_("layer-display"), enum_2_string (d)); } LayerDisplay @@ -2268,7 +2254,7 @@ RouteTimeAxisView::set_underlay_state() if (prop) { PBD::ID id (prop->value()); - RouteTimeAxisView* v = _editor.get_route_view_by_id (id); + RouteTimeAxisView* v = _editor.get_route_view_by_route_id (id); if (v) { add_underlay(v->view(), false); @@ -2380,3 +2366,27 @@ RouteTimeAxisView::automation_child_menu_item (Evoral::Parameter param) return 0; } + +void +RouteTimeAxisView::create_gain_automation_child (const Evoral::Parameter& param, bool show) +{ + boost::shared_ptr c = _route->gain_control(); + if (!c) { + error << "Route has no gain automation, unable to add automation track view." << endmsg; + return; + } + + gain_track.reset (new AutomationTimeAxisView (_session, + _route, _route->amp(), c, param, + _editor, + *this, + 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); +}