#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"
#include "transpose_dialog.h"
#include "transform_dialog.h"
#include "ui_config.h"
+#include "utils.h"
#include "vca_time_axis.h"
#include "pbd/i18n.h"
/* if no snap selections are set, boundary cache should be left empty */
if ( interesting_points.empty() ) {
+ _region_boundary_cache_dirty = false;
return;
}
}
}
+ //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<samplepos_t, samplepos_t> ext = session_gui_extents (false);
samplepos_t session_end = ext.second;
}
if (_session->config.get_external_sync()) {
- switch (Config->get_sync_source()) {
+ switch (TransportMasterManager::instance().current()->type()) {
case Engine:
break;
default:
}
boost::shared_ptr<Playlist> playlist;
+ std::set<boost::shared_ptr<Playlist> > 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<boost::shared_ptr<Playlist> >::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<Region> r ((*i)->region());
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<boost::shared_ptr<Playlist> >::iterator p = playlists.begin(); p != playlists.end(); ++p) {
+ _session->add_command (new StatefulDiffCommand (*p));
+ vector<Command*> cmds;
+ (*p)->rdiff (cmds);
+ _session->add_commands (cmds);
+ }
+
if (!foo.empty()) {
selection->set (foo);
}
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;
}
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<RouteUI *>(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<RouteUI *>(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
(*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()));
}
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;
+ pos = snap_to_grid (pos, RoundUpAlways, SnapToGrid_Scaled);
+ _session->request_locate (pos.sample);
+ }
+ }
+
- if (pos.sample < max_samplepos - 1) {
- pos.sample += 2;
- snap_to_internal (pos, RoundUpAlways, SnapToGrid, false, true);
- _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));
}
}
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));
}
}
return;
}
+ if (!ARDOUR_UI_UTILS::engine_is_running ()) {
+ return;
+ }
+
vector<string> choices;
string prompt;
int ntracks = 0;