diff --git a/gtk2_ardour/ardour.keys.in b/gtk2_ardour/ardour.keys.in index 7210130a46..a298625cef 100644 --- a/gtk2_ardour/ardour.keys.in +++ b/gtk2_ardour/ardour.keys.in @@ -231,6 +231,7 @@ This mode provides many different operations on both regions and control points, @wvis|Common/toggle-meterbridge|<@SECONDARY@>b|show meter bridge @edtrk|Editor/track-record-enable-toggle|<@TERTIARY@>b|toggle track rec-enable @sess|Main/AddTrackBus|<@PRIMARY@><@TERTIARY@>n|add track(s) or bus(ses) +@rop|Region/add-region-cue-marker|m|add a region/cue marker @sess|Main/New|<@PRIMARY@>n|open a new session @wvis|Window/toggle-midi-connection-manager|<@SECONDARY@><@TERTIARY@>m|toggle global midi patchbay @wvis|Common/show-mixer|<@SECONDARY@>m|show mixer window diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index ab28a6eca5..13ab2af5af 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -580,7 +580,7 @@ public: void split_region_at_points (boost::shared_ptr, ARDOUR::AnalysisFeatureList&, bool can_ferret, bool select_new = false); RegionSelection get_regions_from_selection_and_mouse (samplepos_t); void do_remove_gaps (); - void remove_gaps (samplecnt_t threshold, samplecnt_t leave); + void remove_gaps (samplecnt_t threshold, samplecnt_t leave, bool markers_too); void mouse_add_new_tempo_event (samplepos_t where); void mouse_add_new_meter_event (samplepos_t where); @@ -2370,6 +2370,8 @@ private: void toggle_reg_sens (Glib::RefPtr group, char const* name, char const* label, sigc::slot slot); void radio_reg_sens (Glib::RefPtr action_group, Gtk::RadioAction::Group& radio_group, char const* name, char const* label, sigc::slot slot); + void remove_gap_marker_callback (samplepos_t at, samplecnt_t distance); + friend class Drag; friend class RegionCutDrag; friend class RegionDrag; diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 6df6b2e547..190e77c0b2 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -8739,6 +8739,14 @@ Editor::add_region_marker () return; } + /* get these before we display the dialog, since it will interfere if + the edit point is "mouse" + */ + RegionSelection rs = get_regions_from_selection_and_edit_point (); + samplepos_t position = get_preferred_edit_position (); + + cerr << "adding cue marker @ " << position << " in " << rs.size() << endl; + ArdourDialog d (_("New Cue Marker Name"), true, false); Gtk::Entry e; d.get_vbox()->pack_start (e); @@ -8755,8 +8763,7 @@ Editor::add_region_marker () return; } - RegionSelection rs = get_regions_from_selection_and_edit_point (); - samplepos_t position = get_preferred_edit_position (); + bool in_command = false; for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { @@ -8764,6 +8771,7 @@ Editor::add_region_marker () boost::shared_ptr region ((*r)->region()); if (position < region->position() || position >= region->position() + region->length()) { + cerr << "nope on that one\n"; continue; } @@ -8946,8 +8954,11 @@ Editor::do_remove_gaps () hpacker2.pack_start (label2, true, false); hpacker2.pack_start (e2, false, false); + Gtk::CheckButton markers_too (_("Shift global markers too")); + d.get_vbox()->pack_start (hpacker1); d.get_vbox()->pack_start (hpacker2); + d.get_vbox()->pack_start (markers_too); d.get_vbox()->show_all (); e2.set_activates_default (); @@ -8971,8 +8982,8 @@ Editor::do_remove_gaps () goto again; } - if (threshold_secs <= 0) { - ArdourMessageDialog msg (_("The threshold value must be larger than zero")); + if (threshold_secs < 0) { + ArdourMessageDialog msg (_("The threshold value must be larger than or equal to zero")); msg.run(); goto again; } @@ -8997,14 +9008,39 @@ Editor::do_remove_gaps () d.hide (); - remove_gaps (threshold_samples, leave_samples); + remove_gaps (threshold_samples, leave_samples, markers_too.get_active()); +} + +/* one day, we can use an empty lambda for this */ +static +void gap_marker_callback_relax (samplepos_t, samplecnt_t) +{ } void -Editor::remove_gaps (samplecnt_t gap_threshold, samplecnt_t leave_gap) +Editor::remove_gap_marker_callback (samplepos_t at, samplecnt_t distance) +{ + _session->locations()->ripple (at, distance, false, false); +} + +void +Editor::remove_gaps (samplecnt_t gap_threshold, samplecnt_t leave_gap, bool markers_too) { bool in_command = false; TrackViewList ts = selection->tracks.filter_to_unique_playlists (); + XMLNode* locations_before (0); + + if (markers_too) { + locations_before = &_session->locations()->get_state(); + } + + set > pl; + + /* it will not be possible to infer this from the set<>, so keep track + * of it explicitly + */ + + boost::shared_ptr first_selected_playlist; for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { @@ -9013,33 +9049,51 @@ Editor::remove_gaps (samplecnt_t gap_threshold, samplecnt_t leave_gap) * playlist. */ - set > pl; - if ((*x)->playlist ()) { + if (!first_selected_playlist) { + first_selected_playlist = (*x)->playlist(); + } pl.insert ((*x)->playlist ()); } + } - for (set >::iterator i = pl.begin(); i != pl.end(); ++i) { + for (set >::iterator i = pl.begin(); i != pl.end(); ++i) { - (*i)->clear_changes (); - (*i)->clear_owned_changes (); + (*i)->clear_changes (); + (*i)->clear_owned_changes (); - if (!in_command) { - begin_reversible_command (_("remove gaps")); - in_command = true; - } - - (*i)->remove_gaps (gap_threshold, leave_gap); - - vector cmds; - (*i)->rdiff (cmds); - _session->add_commands (cmds); - - _session->add_command (new StatefulDiffCommand (*i)); + if (!in_command) { + begin_reversible_command (_("remove gaps")); + in_command = true; } + + /* only move markers when closing gaps on the first + * selected track/playlist + */ + + if (markers_too && (*i == first_selected_playlist)) { + boost::function callback (boost::bind (&Editor::remove_gap_marker_callback, this, _1, _2)); + (*i)->remove_gaps (gap_threshold, leave_gap, callback); + } else { + boost::function callback (boost::bind (gap_marker_callback_relax, _1, _2)); + (*i)->remove_gaps (gap_threshold, leave_gap, callback); + } + + vector cmds; + (*i)->rdiff (cmds); + _session->add_commands (cmds); + _session->add_command (new StatefulDiffCommand (*i)); } if (in_command) { + if (markers_too) { + XMLNode* locations_after = &_session->locations()->get_state(); + _session->add_command (new MementoCommand (*_session->locations(), locations_before, locations_after)); + } commit_reversible_command (); + } else { + if (markers_too) { + delete locations_before; + } } }