Don't invalidate AU preset on load
[ardour.git] / gtk2_ardour / editor_ops.cc
index fba1e2de28b28170b7808c44d7c1253bf71d189a..7a528929a8143453a4b759e6cee6f71d6c30ce3f 100644 (file)
 #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"
@@ -173,7 +177,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 +193,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 */
        }
@@ -743,6 +733,7 @@ Editor::build_region_boundary_cache ()
 
        /* if no snap selections are set, boundary cache should be left empty */
        if ( interesting_points.empty() ) {
+               _region_boundary_cache_dirty = false;
                return;
        }
 
@@ -762,6 +753,11 @@ Editor::build_region_boundary_cache ()
                }
        }
 
+       //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;
 
@@ -2601,7 +2597,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:
@@ -4774,10 +4770,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;
@@ -4866,6 +4859,8 @@ Editor::paste_internal (samplepos_t position, float times, const int32_t sub_num
                }
        }
 
+       ++paste_count;
+
        commit_reversible_command ();
 }
 
@@ -4884,17 +4879,40 @@ Editor::duplicate_some_regions (RegionSelection& regions, float times)
        }
 
        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());
@@ -4906,15 +4924,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<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);
        }
@@ -6363,7 +6393,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;
        }
 
@@ -6374,7 +6407,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();
@@ -6393,79 +6426,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<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
@@ -6619,9 +6586,6 @@ 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) {
                        end = max_samplepos;
@@ -6652,9 +6616,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"));
 
        }
@@ -6680,9 +6641,6 @@ 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) {
                        end = max_samplepos;
@@ -6713,9 +6671,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"));
        }
 }
@@ -7134,7 +7089,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()));
        }
@@ -7339,12 +7294,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;
+                       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));
        }
 }
 
@@ -7358,10 +7329,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));
        }
 }
 
@@ -7426,6 +7421,10 @@ Editor::_remove_tracks ()
                return;
        }
 
+       if (!ARDOUR_UI_UTILS::engine_is_running ()) {
+               return;
+       }
+
        vector<string> choices;
        string prompt;
        int ntracks = 0;