X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_ops.cc;h=50ead21c33b0c3107493520d6330157aa08a0d9c;hb=79731a716deae9a90be646695480f06f92c268f5;hp=7ba7e944521ede1628347b04fd81447e12e6d782;hpb=881c8eeca8df141959861387b8e3af5c48ba287b;p=ardour.git diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 7ba7e94452..50ead21c33 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -58,16 +58,19 @@ #include "ardour/legatize.h" #include "ardour/region_factory.h" #include "ardour/reverse.h" +#include "ardour/selection.h" #include "ardour/session.h" #include "ardour/session_playlists.h" #include "ardour/strip_silence.h" #include "ardour/transient_detector.h" +#include "ardour/transport_master_manager.h" #include "ardour/transpose.h" #include "ardour/vca_manager.h" #include "canvas/canvas.h" #include "actions.h" +#include "ardour_ui.h" #include "audio_region_view.h" #include "audio_streamview.h" #include "audio_time_axis.h" @@ -173,7 +176,7 @@ Editor::redo (uint32_t n) } void -Editor::split_regions_at (MusicSample where, RegionSelection& regions, bool snap_sample) +Editor::split_regions_at (MusicSample where, RegionSelection& regions) { bool frozen = false; @@ -189,25 +192,11 @@ Editor::split_regions_at (MusicSample where, RegionSelection& regions, bool snap begin_reversible_command (_("split")); - // if splitting a single region, and snap-to is using - // region boundaries, don't pay attention to them if (regions.size() == 1) { -// switch (_snap_type) { //ToDo !!! -// case SnapToRegionStart: -// case SnapToRegionSync: -// case SnapToRegionEnd: -// break; -// default: -// if (snap_sample) { - snap_to (where); -// } -// } + /* TODO: if splitting a single region, and snap-to is using + region boundaries, mabye we shouldn't pay attention to them? */ } else { - if (snap_sample) { - snap_to (where); - } - frozen = true; EditorFreeze(); /* Emit Signal */ } @@ -708,12 +697,12 @@ void Editor::build_region_boundary_cache () { - //ToDo: maybe set a timer so we don't recalutate when lots of changes are coming in - //ToDo: maybe somehow defer this until session is fully loaded. - - if ( !_region_boundary_cache_dirty ) + /* TODO: maybe set a timer so we don't recalutate when lots of changes are coming in */ + /* TODO: maybe somehow defer this until session is fully loaded. */ + + if (!_region_boundary_cache_dirty) return; - + samplepos_t pos = 0; vector interesting_points; boost::shared_ptr r; @@ -727,30 +716,30 @@ Editor::build_region_boundary_cache () } bool maybe_first_sample = false; - - if ( UIConfiguration::instance().get_snap_to_region_start() ) { + + if (UIConfiguration::instance().get_snap_to_region_start()) { interesting_points.push_back (Start); maybe_first_sample = true; } - - if ( UIConfiguration::instance().get_snap_to_region_end() ) { + + if (UIConfiguration::instance().get_snap_to_region_end()) { interesting_points.push_back (End); } - - if ( UIConfiguration::instance().get_snap_to_region_sync() ) { + + if (UIConfiguration::instance().get_snap_to_region_sync()) { interesting_points.push_back (SyncPoint); } - + + /* if no snap selections are set, boundary cache should be left empty */ + if ( interesting_points.empty() ) { + _region_boundary_cache_dirty = false; + return; + } + TimeAxisView *ontrack = 0; TrackViewList tlist; - //in the past, we used the track selection to limit snap. I think this is not desired. - //or if it is, it needs to be updated every time the track selection changes (so the snapped-cursor can show it) -// if (!selection->tracks.empty()) { -// tlist = selection->tracks.filter_to_unique_playlists (); -// } else { - tlist = track_views.filter_to_unique_playlists (); -// } + tlist = track_views.filter_to_unique_playlists (); if (maybe_first_sample) { TrackViewList::const_iterator i; @@ -763,10 +752,18 @@ Editor::build_region_boundary_cache () } } - while (pos < _session->current_end_sample() && !at_end) { + //allow regions to snap to the video start (if any) as if it were a "region" + if (ARDOUR_UI::instance()->video_timeline) { + region_boundary_cache.push_back (ARDOUR_UI::instance()->video_timeline->get_video_start_offset()); + } + + std::pair ext = session_gui_extents (false); + samplepos_t session_end = ext.second; + + while (pos < session_end && !at_end) { samplepos_t rpos; - samplepos_t lpos = max_samplepos; + samplepos_t lpos = session_end; for (vector::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) { @@ -822,7 +819,7 @@ Editor::build_region_boundary_cache () /* finally sort to be sure that the order is correct */ sort (region_boundary_cache.begin(), region_boundary_cache.end()); - + _region_boundary_cache_dirty = false; } @@ -1962,13 +1959,13 @@ void Editor::temporal_zoom_selection (Editing::ZoomAxis axes) { if (!selection) return; - - if ( selection->regions.empty() && selection->time.empty() ) { + + if (selection->regions.empty() && selection->time.empty()) { if (axes == Horizontal || axes == Both) { temporal_zoom_step(true); } if (axes == Vertical || axes == Both) { - if ( !track_views.empty() ) { + if (!track_views.empty()) { TrackViewList tvl; @@ -1977,7 +1974,7 @@ Editor::temporal_zoom_selection (Editing::ZoomAxis axes) const double btm = top + _visible_canvas_height + 10; for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) { - if ( (*iter)->covered_by_y_range (top, btm) ) { + if ((*iter)->covered_by_y_range (top, btm)) { tvl.push_back(*iter); } } @@ -2004,10 +2001,10 @@ Editor::temporal_zoom_selection (Editing::ZoomAxis axes) if (axes == Vertical || axes == Both) { fit_selection (); } - + //normally, we don't do anything "automatic" to the user's selection. //but in this case, we will clear the selection after a zoom-to-selection. - selection->clear(); + selection->clear(); } void @@ -2599,7 +2596,7 @@ Editor::transition_to_rolling (bool fwd) } if (_session->config.get_external_sync()) { - switch (Config->get_sync_source()) { + switch (TransportMasterManager::instance().current()->type()) { case Engine: break; default: @@ -4772,10 +4769,7 @@ Editor::paste_internal (samplepos_t position, float times, const int32_t sub_num DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position)); } - if (position == last_paste_pos) { - /* repeated paste in the same position */ - ++paste_count; - } else { + if (position != last_paste_pos) { /* paste in new location, reset repeated paste state */ paste_count = 0; last_paste_pos = position; @@ -4864,6 +4858,8 @@ Editor::paste_internal (samplepos_t position, float times, const int32_t sub_num } } + ++paste_count; + commit_reversible_command (); } @@ -4882,17 +4878,40 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times) } boost::shared_ptr playlist; + std::set > playlists; // list of unique playlists affected by duplication RegionSelection sel = regions; // clear (below) may clear the argument list if its the current region selection RegionSelection foo; samplepos_t const start_sample = regions.start (); samplepos_t const end_sample = regions.end_sample (); - samplecnt_t const gap = end_sample - start_sample + 1; + samplecnt_t const span = end_sample - start_sample + 1; begin_reversible_command (Operations::duplicate_region); selection->clear_regions (); + /* ripple first so that we don't move the duplicates that will be added */ + + if (Config->get_edit_mode() == Ripple) { + + /* convert RegionSelection into RegionList so that we can pass it to ripple and exclude the regions we will duplicate */ + + RegionList exclude; + + for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) { + exclude.push_back ((*i)->region()); + playlist = (*i)->region()->playlist(); + if (playlists.insert (playlist).second) { + /* successfully inserted into set, so it's the first time we've seen this playlist */ + playlist->clear_changes (); + } + } + + for (set >::iterator p = playlists.begin(); p != playlists.end(); ++p) { + (*p)->ripple (start_sample, span * times, &exclude); + } + } + for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) { boost::shared_ptr r ((*i)->region()); @@ -4904,15 +4923,27 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times) samplepos_t const position = end_sample + (r->first_sample() - start_sample + 1); playlist = (*i)->region()->playlist(); - playlist->clear_changes (); - playlist->duplicate (r, position, gap, times); - _session->add_command(new StatefulDiffCommand (playlist)); + + if (Config->get_edit_mode() != Ripple) { + if (playlists.insert (playlist).second) { + playlist->clear_changes (); + } + } + + playlist->duplicate (r, position, span, times); c.disconnect (); foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end()); } + for (set >::iterator p = playlists.begin(); p != playlists.end(); ++p) { + _session->add_command (new StatefulDiffCommand (*p)); + vector cmds; + (*p)->rdiff (cmds); + _session->add_commands (cmds); + } + if (!foo.empty()) { selection->set (foo); } @@ -5891,18 +5922,18 @@ Editor::toggle_record_enable () } StripableList -tracklist_to_stripables( TrackViewList list ) +tracklist_to_stripables (TrackViewList list) { StripableList ret; - + for (TrackSelection::iterator i = list.begin(); i != list.end(); ++i) { RouteTimeAxisView* rtv = dynamic_cast ((*i)); if (rtv && rtv->is_track()) { - ret.push_back( rtv->track() ); + ret.push_back (rtv->track()); } } - + return ret; } @@ -5911,25 +5942,25 @@ Editor::play_solo_selection (bool restart) { //note: session::solo_selection takes care of invalidating the region playlist - if ( (!selection->tracks.empty()) && selection->time.length() > 0 ) { //a range is selected; solo the tracks and roll - + if ((!selection->tracks.empty()) && selection->time.length() > 0) { //a range is selected; solo the tracks and roll + StripableList sl = tracklist_to_stripables (selection->tracks); - _session->solo_selection( sl, true ); + _session->solo_selection (sl, true); - if ( restart ) { + if (restart) { samplepos_t start = selection->time.start(); samplepos_t end = selection->time.end_sample(); _session->request_bounded_roll (start, end); } - } else if ( ! selection->tracks.empty() ) { //no range is selected, but tracks are selected; solo the tracks and roll + } else if (! selection->tracks.empty()) { //no range is selected, but tracks are selected; solo the tracks and roll StripableList sl = tracklist_to_stripables (selection->tracks); - _session->solo_selection( sl, true ); + _session->solo_selection (sl, true); _session->request_cancel_play_range(); transition_to_rolling (true); - - } else if ( ! selection->regions.empty() ) { //solo any tracks with selected regions, and roll - StripableList sl = tracklist_to_stripables ( get_tracks_for_range_action() ); - _session->solo_selection( sl, true ); + + } else if (! selection->regions.empty()) { //solo any tracks with selected regions, and roll + StripableList sl = tracklist_to_stripables (get_tracks_for_range_action()); + _session->solo_selection (sl, true); _session->request_cancel_play_range(); transition_to_rolling (true); } else { @@ -6361,7 +6392,10 @@ Editor::set_playhead_cursor () void Editor::split_region () { - if (_drags->active ()) { + if (_dragging_playhead) { + /*continue*/ + } else if (_drags->active ()) { + /*any other kind of drag, bail out so we avoid Undo snafu*/ return; } @@ -6372,7 +6406,7 @@ Editor::split_region () } //if no range was selected, try to find some regions to split - if (current_mouse_mode() == MouseObject) { //don't try this for Internal Edit, Stretch, Draw, etc. + if (current_mouse_mode() == MouseObject || current_mouse_mode() == MouseRange ) { //don't try this for Internal Edit, Stretch, Draw, etc. RegionSelection rs = get_regions_from_selection_and_edit_point (); const samplepos_t pos = get_preferred_edit_position(); @@ -6391,79 +6425,13 @@ Editor::split_region () void Editor::select_next_stripable (bool routes_only) { - if (selection->tracks.empty()) { - selection->set (track_views.front()); - return; - } - - TimeAxisView* current = selection->tracks.front(); - - bool valid; - do { - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - - if (*i == current) { - ++i; - if (i != track_views.end()) { - current = (*i); - } else { - current = (*(track_views.begin())); - //selection->set (*(track_views.begin())); - } - break; - } - } - - if (routes_only) { - RouteUI* rui = dynamic_cast(current); - valid = rui && rui->route()->active(); - } else { - valid = 0 != current->stripable ().get(); - } - - } while (current->hidden() || !valid); - - selection->set (current); - - ensure_time_axis_view_is_visible (*current, false); + _session->selection().select_next_stripable (false, routes_only); } void Editor::select_prev_stripable (bool routes_only) { - if (selection->tracks.empty()) { - selection->set (track_views.front()); - return; - } - - TimeAxisView* current = selection->tracks.front(); - - bool valid; - do { - for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) { - - if (*i == current) { - ++i; - if (i != track_views.rend()) { - current = (*i); - } else { - current = *(track_views.rbegin()); - } - break; - } - } - if (routes_only) { - RouteUI* rui = dynamic_cast(current); - valid = rui && rui->route()->active(); - } else { - valid = 0 != current->stripable ().get(); - } - - } while (current->hidden() || !valid); - - selection->set (current); - - ensure_time_axis_view_is_visible (*current, false); + _session->selection().select_prev_stripable (false, routes_only); } void @@ -6617,11 +6585,8 @@ Editor::set_punch_start_from_edit_point () start.sample = get_preferred_edit_position(); } - //snap the selection start/end - snap_to(start); - //if there's not already a sensible selection endpoint, go "forever" - if (start.sample > end ) { + if (start.sample > end) { end = max_samplepos; } @@ -6650,9 +6615,6 @@ Editor::set_punch_end_from_edit_point () end.sample = get_preferred_edit_position(); } - //snap the selection start/end - snap_to (end); - set_punch_range (start, end.sample, _("set punch end from EP")); } @@ -6678,11 +6640,8 @@ Editor::set_loop_start_from_edit_point () start.sample = get_preferred_edit_position(); } - //snap the selection start/end - snap_to (start); - //if there's not already a sensible selection endpoint, go "forever" - if (start.sample > end ) { + if (start.sample > end) { end = max_samplepos; } @@ -6711,9 +6670,6 @@ Editor::set_loop_end_from_edit_point () end.sample = get_preferred_edit_position(); } - //snap the selection start/end - snap_to(end); - set_loop_range (start, end.sample, _("set loop end from EP")); } } @@ -7132,7 +7088,7 @@ Editor::snap_regions_to_grid () (*r)->region()->clear_changes (); MusicSample start ((*r)->region()->first_sample (), 0); - snap_to (start, RoundNearest, SnapToGrid ); + snap_to (start, RoundNearest, SnapToGrid_Unscaled, true); (*r)->region()->set_position (start.sample, start.division); _session->add_command(new StatefulDiffCommand ((*r)->region())); } @@ -7337,12 +7293,28 @@ Editor::playhead_forward_to_grid () return; } - MusicSample pos (playhead_cursor->current_sample (), 0); + MusicSample pos (playhead_cursor->current_sample (), 0); + + if ( _grid_type == GridTypeNone) { + if (pos.sample < max_samplepos - current_page_samples()*0.1) { + pos.sample += current_page_samples()*0.1; + _session->request_locate (pos.sample); + } else { + _session->request_locate (0); + } + } else { - if (pos.sample < max_samplepos - 1) { - pos.sample += 2; - snap_to_internal (pos, RoundUpAlways, SnapToGrid, false, true); - _session->request_locate (pos.sample); + if (pos.sample < max_samplepos - 1) { + pos.sample += 2; + pos = snap_to_grid (pos, RoundUpAlways, SnapToGrid_Scaled); + _session->request_locate (pos.sample); + } + } + + + /* keep PH visible in window */ + if (pos.sample > (_leftmost_sample + current_page_samples() *0.9)) { + reset_x_origin (pos.sample - (current_page_samples()*0.9)); } } @@ -7356,10 +7328,34 @@ Editor::playhead_backward_to_grid () MusicSample pos (playhead_cursor->current_sample (), 0); - if (pos.sample > 2) { - pos.sample -= 2; - snap_to_internal (pos, RoundDownAlways, SnapToGrid, false, true); - _session->request_locate (pos.sample); + if ( _grid_type == GridTypeNone) { + if ( pos.sample > current_page_samples()*0.1 ) { + pos.sample -= current_page_samples()*0.1; + _session->request_locate (pos.sample); + } else { + _session->request_locate (0); + } + } else { + + if (pos.sample > 2) { + pos.sample -= 2; + pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled); + } + + //handle the case where we are rolling, and we're less than one-half second past the mark, we want to go to the prior mark... + //also see: jump_backward_to_mark + if (_session->transport_rolling()) { + if ((playhead_cursor->current_sample() - pos.sample) < _session->sample_rate()/2) { + pos = snap_to_grid (pos, RoundDownAlways, SnapToGrid_Scaled); + } + } + + _session->request_locate (pos.sample, _session->transport_rolling()); + } + + /* keep PH visible in window */ + if (pos.sample < (_leftmost_sample + current_page_samples() *0.1)) { + reset_x_origin (pos.sample - (current_page_samples()*0.1)); } } @@ -7549,7 +7545,7 @@ edit your ardour.rc file to set the\n\ /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted * route). If the deleted route is currently displayed in the Editor-Mixer (highly * likely because deletion requires selection) this will call - * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ). + * Editor::set_selected_mixer_strip () which is expensive (MixerStrip::set_route()). * It's likewise likely that the route that has just been displayed in the * Editor-Mixer will be next in line for deletion. * @@ -7602,7 +7598,7 @@ Editor::do_insert_time () msg.run (); return; } - + InsertRemoveTimeDialog d (*this); int response = d.run ();