X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_ops.cc;h=1b5067e2ac1d1ccdd684a745f414f9940140b1ec;hb=f19c01bbb42f4e80769adb8e3e1015724fe9d6c6;hp=0be6221be5f37d0e0cdf32b2a8b377e892034c1f;hpb=a2a6cc0404757f445bd753d69f34d8bc2c0e87a9;p=ardour.git diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 0be6221be5..1b5067e2ac 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -25,34 +25,35 @@ #include #include #include +#include -#include -#include -#include -#include -#include +#include "pbd/error.h" +#include "pbd/basename.h" +#include "pbd/pthread_utils.h" +#include "pbd/memento_command.h" +#include "pbd/whitespace.h" #include #include #include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#include + +#include "ardour/audioengine.h" +#include "ardour/session.h" +#include "ardour/audioplaylist.h" +#include "ardour/audioregion.h" +#include "ardour/audio_diskstream.h" +#include "ardour/utils.h" +#include "ardour/location.h" +#include "ardour/named_selection.h" +#include "ardour/audio_track.h" +#include "ardour/audioplaylist.h" +#include "ardour/region_factory.h" +#include "ardour/playlist_factory.h" +#include "ardour/reverse.h" +#include "ardour/transient_detector.h" +#include "ardour/dB.h" +#include "ardour/quantize.h" #include "ardour_ui.h" #include "editor.h" @@ -61,6 +62,7 @@ #include "audio_time_axis.h" #include "automation_time_axis.h" #include "streamview.h" +#include "audio_streamview.h" #include "audio_region_view.h" #include "midi_region_view.h" #include "rgb_macros.h" @@ -109,7 +111,7 @@ Editor::split_region () } void -Editor::split_region_at (nframes_t where) +Editor::split_region_at (nframes64_t where) { RegionSelection rs; @@ -118,7 +120,7 @@ Editor::split_region_at (nframes_t where) } void -Editor::split_regions_at (nframes_t where, RegionSelection& regions) +Editor::split_regions_at (nframes64_t where, RegionSelection& regions) { list > used_playlists; @@ -171,26 +173,26 @@ Editor::split_regions_at (nframes_t where, RegionSelection& regions) } AudioRegionView* const arv = dynamic_cast(*a); - if (arv) { _new_regionviews_show_envelope = arv->envelope_visible(); } if (pl) { - XMLNode &before = pl->get_state(); + XMLNode &before = pl->get_state(); pl->split_region ((*a)->region(), where); - XMLNode &after = pl->get_state(); - session->add_command(new MementoCommand(*pl, &before, &after)); + XMLNode &after = pl->get_state(); + session->add_command(new MementoCommand(*pl, &before, &after)); } a = tmp; } - while (used_playlists.size() > 0) { + while (used_playlists.size() > 0) { list >::iterator i = used_playlists.begin(); (*i)->thaw(); used_playlists.pop_front(); } + commit_reversible_command (); _new_regionviews_show_envelope = false; } @@ -219,21 +221,44 @@ Editor::remove_clicked_region () void Editor::remove_selected_regions () { - if (selection->regions.empty()) { + RegionSelection rs; + get_regions_for_action (rs); + + if (!session) { + return; + } + + if (rs.empty()) { return; } - /* XXX: should be called remove regions if we're removing more than one */ begin_reversible_command (_("remove region")); - - while (!selection->regions.empty()) { - boost::shared_ptr region = selection->regions.front()->region (); - boost::shared_ptr playlist = region->playlist (); + list > regions_to_remove; - XMLNode &before = playlist->get_state(); - playlist->remove_region (region); - XMLNode &after = playlist->get_state(); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + // we can't just remove the region(s) in this loop because + // this removes them from the RegionSelection, and they thus + // disappear from underneath the iterator, and the ++i above + // SEGVs in a puzzling fashion. + + // so, first iterate over the regions to be removed from rs and + // add them to the regions_to_remove list, and then + // iterate over the list to actually remove them. + + regions_to_remove.push_back ((*i)->region()); + } + + for (list >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) { + boost::shared_ptr playlist = (*rl)->playlist(); + if (!playlist) { + // is this check necessary? + continue; + } + + XMLNode &before = playlist->get_state(); + playlist->remove_region (*rl); + XMLNode &after = playlist->get_state(); session->add_command(new MementoCommand(*playlist, &before, &after)); } @@ -245,7 +270,7 @@ Editor::select_region_for_operation (int dir, TimeAxisView **tv) { RegionView* rv; boost::shared_ptr region; - nframes_t start = 0; + nframes64_t start = 0; if (selection->time.start () == selection->time.end_frame ()) { @@ -288,7 +313,7 @@ Editor::extend_selection_to_end_of_region (bool next) { TimeAxisView *tv; boost::shared_ptr region; - nframes_t start; + nframes64_t start; if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) { return; @@ -316,7 +341,7 @@ Editor::extend_selection_to_start_of_region (bool previous) { TimeAxisView *tv; boost::shared_ptr region; - nframes_t end; + nframes64_t end; if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) { return; @@ -365,8 +390,8 @@ Editor::nudge_backward_release (GdkEventButton* ev) void Editor::nudge_forward (bool next, bool force_playhead) { - nframes_t distance; - nframes_t next_distance; + nframes64_t distance; + nframes64_t next_distance; RegionSelection rs; get_regions_for_action (rs); @@ -398,40 +423,45 @@ Editor::nudge_forward (bool next, bool force_playhead) } else if (!force_playhead && !selection->markers.empty()) { bool is_start; - Location* loc = find_location_from_marker (selection->markers.front(), is_start); - if (loc) { - - begin_reversible_command (_("nudge location forward")); - - XMLNode& before (loc->get_state()); - - if (is_start) { - distance = get_nudge_distance (loc->start(), next_distance); - if (next) { - distance = next_distance; - } - if (max_frames - distance > loc->start() + loc->length()) { - loc->set_start (loc->start() + distance); - } else { - loc->set_start (max_frames - loc->length()); - } - } else { - distance = get_nudge_distance (loc->end(), next_distance); - if (next) { - distance = next_distance; - } - if (max_frames - distance > loc->end()) { - loc->set_end (loc->end() + distance); + begin_reversible_command (_("nudge location forward")); + + for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) { + + Location* loc = find_location_from_marker ((*i), is_start); + + if (loc) { + + XMLNode& before (loc->get_state()); + + if (is_start) { + distance = get_nudge_distance (loc->start(), next_distance); + if (next) { + distance = next_distance; + } + if (max_frames - distance > loc->start() + loc->length()) { + loc->set_start (loc->start() + distance); + } else { + loc->set_start (max_frames - loc->length()); + } } else { - loc->set_end (max_frames); + distance = get_nudge_distance (loc->end(), next_distance); + if (next) { + distance = next_distance; + } + if (max_frames - distance > loc->end()) { + loc->set_end (loc->end() + distance); + } else { + loc->set_end (max_frames); + } } + XMLNode& after (loc->get_state()); + session->add_command (new MementoCommand(*loc, &before, &after)); } - XMLNode& after (loc->get_state()); - session->add_command (new MementoCommand(*loc, &before, &after)); - commit_reversible_command (); } + commit_reversible_command (); + } else { distance = get_nudge_distance (playhead_cursor->current_frame, next_distance); session->request_locate (playhead_cursor->current_frame + distance); @@ -441,8 +471,8 @@ Editor::nudge_forward (bool next, bool force_playhead) void Editor::nudge_backward (bool next, bool force_playhead) { - nframes_t distance; - nframes_t next_distance; + nframes64_t distance; + nframes64_t next_distance; RegionSelection rs; get_regions_for_action (rs); @@ -478,41 +508,48 @@ Editor::nudge_backward (bool next, bool force_playhead) } else if (!force_playhead && !selection->markers.empty()) { bool is_start; - Location* loc = find_location_from_marker (selection->markers.front(), is_start); - - if (loc) { - - begin_reversible_command (_("nudge location forward")); - XMLNode& before (loc->get_state()); - if (is_start) { - distance = get_nudge_distance (loc->start(), next_distance); - if (next) { - distance = next_distance; - } - if (distance < loc->start()) { - loc->set_start (loc->start() - distance); - } else { - loc->set_start (0); - } - } else { - distance = get_nudge_distance (loc->end(), next_distance); + begin_reversible_command (_("nudge location forward")); - if (next) { - distance = next_distance; - } + for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) { - if (distance < loc->end() - loc->length()) { - loc->set_end (loc->end() - distance); + Location* loc = find_location_from_marker ((*i), is_start); + + if (loc) { + + XMLNode& before (loc->get_state()); + + if (is_start) { + distance = get_nudge_distance (loc->start(), next_distance); + if (next) { + distance = next_distance; + } + if (distance < loc->start()) { + loc->set_start (loc->start() - distance); + } else { + loc->set_start (0); + } } else { - loc->set_end (loc->length()); + distance = get_nudge_distance (loc->end(), next_distance); + + if (next) { + distance = next_distance; + } + + if (distance < loc->end() - loc->length()) { + loc->set_end (loc->end() - distance); + } else { + loc->set_end (loc->length()); + } } + + XMLNode& after (loc->get_state()); + session->add_command (new MementoCommand(*loc, &before, &after)); } - - XMLNode& after (loc->get_state()); - session->add_command (new MementoCommand(*loc, &before, &after)); } - + + commit_reversible_command (); + } else { distance = get_nudge_distance (playhead_cursor->current_frame, next_distance); @@ -528,7 +565,7 @@ Editor::nudge_backward (bool next, bool force_playhead) void Editor::nudge_forward_capture_offset () { - nframes_t distance; + nframes64_t distance; RegionSelection rs; get_regions_for_action (rs); @@ -558,7 +595,7 @@ Editor::nudge_forward_capture_offset () void Editor::nudge_backward_capture_offset () { - nframes_t distance; + nframes64_t distance; RegionSelection rs; get_regions_for_action (rs); @@ -607,7 +644,7 @@ Editor::move_to_end () void Editor::build_region_boundary_cache () { - nframes_t pos = 0; + nframes64_t pos = 0; vector interesting_points; boost::shared_ptr r; TrackViewList tracks; @@ -650,8 +687,8 @@ Editor::build_region_boundary_cache () while (pos < session->current_end_frame() && !at_end) { - nframes_t rpos; - nframes_t lpos = max_frames; + nframes64_t rpos; + nframes64_t lpos = max_frames; for (vector::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) { @@ -673,7 +710,8 @@ Editor::build_region_boundary_cache () break; case SyncPoint: - rpos = r->adjust_to_sync (r->first_frame()); + rpos = r->sync_position (); + //r->adjust_to_sync (r->first_frame()); break; default: @@ -699,7 +737,7 @@ Editor::build_region_boundary_cache () to sort later. */ - vector::iterator ri; + vector::iterator ri; for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) { if (*ri == rpos) { @@ -721,20 +759,20 @@ Editor::build_region_boundary_cache () } boost::shared_ptr -Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack) +Editor::find_next_region (nframes64_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack) { TrackViewList::iterator i; - nframes_t closest = max_frames; + nframes64_t closest = max_frames; boost::shared_ptr ret; - nframes_t rpos = 0; + nframes64_t rpos = 0; float track_speed; - nframes_t track_frame; + nframes64_t track_frame; RouteTimeAxisView *rtav; for (i = tracks.begin(); i != tracks.end(); ++i) { - nframes_t distance; + nframes64_t distance; boost::shared_ptr r; track_speed = 1.0f; @@ -759,7 +797,8 @@ Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, Track break; case SyncPoint: - rpos = r->adjust_to_sync (r->first_frame()); + rpos = r->sync_position (); + // r->adjust_to_sync (r->first_frame()); break; } @@ -789,6 +828,7 @@ Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackView nframes64_t distance = max_frames; nframes64_t current_nearest = -1; + for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) { nframes64_t contender; nframes64_t d; @@ -814,10 +854,45 @@ Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackView return current_nearest; } +nframes64_t +Editor::get_region_boundary (nframes64_t pos, int32_t dir, bool with_selection, bool only_onscreen) +{ + nframes64_t target; + TrackViewList tvl; + + if (with_selection && Config->get_region_boundaries_from_selected_tracks()) { + + if (!selection->tracks.empty()) { + + target = find_next_region_boundary (pos, dir, selection->tracks); + + } else { + + if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) { + get_onscreen_tracks (tvl); + target = find_next_region_boundary (pos, dir, tvl); + } else { + target = find_next_region_boundary (pos, dir, track_views); + } + } + + } else { + + if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) { + get_onscreen_tracks (tvl); + target = find_next_region_boundary (pos, dir, tvl); + } else { + target = find_next_region_boundary (pos, dir, track_views); + } + } + + return target; +} + void -Editor::cursor_to_region_boundary (Cursor* cursor, int32_t dir) +Editor::cursor_to_region_boundary (bool with_selection, int32_t dir) { - nframes64_t pos = cursor->current_frame; + nframes64_t pos = playhead_cursor->current_frame; nframes64_t target; if (!session) { @@ -829,44 +904,31 @@ Editor::cursor_to_region_boundary (Cursor* cursor, int32_t dir) pos += dir; } - if (!selection->tracks.empty()) { - - target = find_next_region_boundary (pos, dir, selection->tracks); - - } else { - - target = find_next_region_boundary (pos, dir, track_views); - } - - if (target < 0) { + if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) { return; } - if (cursor == playhead_cursor) { - session->request_locate (target); - } else { - cursor->set_position (target); - } + session->request_locate (target); } void -Editor::cursor_to_next_region_boundary (Cursor* cursor) +Editor::cursor_to_next_region_boundary (bool with_selection) { - cursor_to_region_boundary (cursor, 1); + cursor_to_region_boundary (with_selection, 1); } void -Editor::cursor_to_previous_region_boundary (Cursor* cursor) +Editor::cursor_to_previous_region_boundary (bool with_selection) { - cursor_to_region_boundary (cursor, -1); + cursor_to_region_boundary (with_selection, -1); } void Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir) { boost::shared_ptr r; - nframes_t pos = cursor->current_frame; + nframes64_t pos = cursor->current_frame; if (!session) { return; @@ -908,7 +970,8 @@ Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir) break; case SyncPoint: - pos = r->adjust_to_sync (r->first_frame()); + pos = r->sync_position (); + // r->adjust_to_sync (r->first_frame()); break; } @@ -945,7 +1008,7 @@ Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point) void Editor::cursor_to_selection_start (Cursor *cursor) { - nframes_t pos = 0; + nframes64_t pos = 0; RegionSelection rs; get_regions_for_action (rs); @@ -977,7 +1040,7 @@ Editor::cursor_to_selection_start (Cursor *cursor) void Editor::cursor_to_selection_end (Cursor *cursor) { - nframes_t pos = 0; + nframes64_t pos = 0; RegionSelection rs; get_regions_for_action (rs); @@ -1007,7 +1070,7 @@ Editor::cursor_to_selection_end (Cursor *cursor) } void -Editor::selected_marker_to_region_boundary (int32_t dir) +Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir) { nframes64_t target; Location* loc; @@ -1039,16 +1102,7 @@ Editor::selected_marker_to_region_boundary (int32_t dir) pos += dir; } - if (!selection->tracks.empty()) { - - target = find_next_region_boundary (pos, dir, selection->tracks); - - } else { - - target = find_next_region_boundary (pos, dir, track_views); - } - - if (target < 0) { + if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) { return; } @@ -1056,22 +1110,22 @@ Editor::selected_marker_to_region_boundary (int32_t dir) } void -Editor::selected_marker_to_next_region_boundary () +Editor::selected_marker_to_next_region_boundary (bool with_selection) { - selected_marker_to_region_boundary (1); + selected_marker_to_region_boundary (with_selection, 1); } void -Editor::selected_marker_to_previous_region_boundary () +Editor::selected_marker_to_previous_region_boundary (bool with_selection) { - selected_marker_to_region_boundary (-1); + selected_marker_to_region_boundary (with_selection, -1); } void Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir) { boost::shared_ptr r; - nframes_t pos; + nframes64_t pos; Location* loc; bool ignored; @@ -1119,11 +1173,11 @@ Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir) } float speed = 1.0f; - AudioTimeAxisView *atav; + RouteTimeAxisView *rtav; - if ( ontrack != 0 && (atav = dynamic_cast(ontrack)) != 0 ) { - if (atav->get_diskstream() != 0) { - speed = atav->get_diskstream()->speed(); + if (ontrack != 0 && (rtav = dynamic_cast(ontrack)) != 0) { + if (rtav->get_diskstream() != 0) { + speed = rtav->get_diskstream()->speed(); } } @@ -1147,7 +1201,7 @@ Editor::selected_marker_to_previous_region_point (RegionPoint point) void Editor::selected_marker_to_selection_start () { - nframes_t pos = 0; + nframes64_t pos = 0; Location* loc; bool ignored; @@ -1186,7 +1240,7 @@ Editor::selected_marker_to_selection_start () void Editor::selected_marker_to_selection_end () { - nframes_t pos = 0; + nframes64_t pos = 0; Location* loc; bool ignored; @@ -1225,8 +1279,8 @@ Editor::selected_marker_to_selection_end () void Editor::scroll_playhead (bool forward) { - nframes_t pos = playhead_cursor->current_frame; - nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8); + nframes64_t pos = playhead_cursor->current_frame; + nframes64_t delta = (nframes64_t) floor (current_page_frames() / 0.8); if (forward) { if (pos == max_frames) { @@ -1258,8 +1312,8 @@ Editor::scroll_playhead (bool forward) void Editor::playhead_backward () { - nframes_t pos; - nframes_t cnt; + nframes64_t pos; + nframes64_t cnt; float prefix; bool was_floating; @@ -1267,15 +1321,15 @@ Editor::playhead_backward () cnt = 1; } else { if (was_floating) { - cnt = (nframes_t) floor (prefix * session->frame_rate ()); + cnt = (nframes64_t) floor (prefix * session->frame_rate ()); } else { - cnt = (nframes_t) prefix; + cnt = (nframes64_t) prefix; } } pos = playhead_cursor->current_frame; - if ((nframes_t) pos < cnt) { + if ((nframes64_t) pos < cnt) { pos = 0; } else { pos -= cnt; @@ -1292,8 +1346,8 @@ Editor::playhead_backward () void Editor::playhead_forward () { - nframes_t pos; - nframes_t cnt; + nframes64_t pos; + nframes64_t cnt; bool was_floating; float prefix; @@ -1301,9 +1355,9 @@ Editor::playhead_forward () cnt = 1; } else { if (was_floating) { - cnt = (nframes_t) floor (prefix * session->frame_rate ()); + cnt = (nframes64_t) floor (prefix * session->frame_rate ()); } else { - cnt = (nframes_t) floor (prefix); + cnt = (nframes64_t) floor (prefix); } } @@ -1362,9 +1416,9 @@ Editor::edit_cursor_backward () cnt = 1; } else { if (was_floating) { - cnt = (nframes_t) floor (prefix * session->frame_rate ()); + cnt = (nframes64_t) floor (prefix * session->frame_rate ()); } else { - cnt = (nframes_t) prefix; + cnt = (nframes64_t) prefix; } } @@ -1384,8 +1438,8 @@ Editor::edit_cursor_backward () void Editor::edit_cursor_forward () { - //nframes_t pos; - nframes_t cnt; + //nframes64_t pos; + nframes64_t cnt; bool was_floating; float prefix; @@ -1393,9 +1447,9 @@ Editor::edit_cursor_forward () cnt = 1; } else { if (was_floating) { - cnt = (nframes_t) floor (prefix * session->frame_rate ()); + cnt = (nframes64_t) floor (prefix * session->frame_rate ()); } else { - cnt = (nframes_t) floor (prefix); + cnt = (nframes64_t) floor (prefix); } } @@ -1408,16 +1462,16 @@ Editor::goto_frame () { float prefix; bool was_floating; - nframes_t frame; + nframes64_t frame; if (get_prefix (prefix, was_floating)) { return; } if (was_floating) { - frame = (nframes_t) floor (prefix * session->frame_rate()); + frame = (nframes64_t) floor (prefix * session->frame_rate()); } else { - frame = (nframes_t) floor (prefix); + frame = (nframes64_t) floor (prefix); } session->request_locate (frame); @@ -1426,19 +1480,19 @@ Editor::goto_frame () void Editor::scroll_backward (float pages) { - nframes_t frame; - nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit); + nframes64_t frame; + nframes64_t one_page = (nframes64_t) rint (canvas_width * frames_per_unit); bool was_floating; float prefix; - nframes_t cnt; + nframes64_t cnt; if (get_prefix (prefix, was_floating)) { - cnt = (nframes_t) floor (pages * one_page); + cnt = (nframes64_t) floor (pages * one_page); } else { if (was_floating) { - cnt = (nframes_t) floor (prefix * session->frame_rate()); + cnt = (nframes64_t) floor (prefix * session->frame_rate()); } else { - cnt = (nframes_t) floor (prefix * one_page); + cnt = (nframes64_t) floor (prefix * one_page); } } @@ -1454,19 +1508,19 @@ Editor::scroll_backward (float pages) void Editor::scroll_forward (float pages) { - nframes_t frame; - nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit); + nframes64_t frame; + nframes64_t one_page = (nframes64_t) rint (canvas_width * frames_per_unit); bool was_floating; float prefix; - nframes_t cnt; + nframes64_t cnt; if (get_prefix (prefix, was_floating)) { - cnt = (nframes_t) floor (pages * one_page); + cnt = (nframes64_t) floor (pages * one_page); } else { if (was_floating) { - cnt = (nframes_t) floor (prefix * session->frame_rate()); + cnt = (nframes64_t) floor (prefix * session->frame_rate()); } else { - cnt = (nframes_t) floor (prefix * one_page); + cnt = (nframes64_t) floor (prefix * one_page); } } @@ -1521,7 +1575,7 @@ Editor::scroll_tracks_down_line () { Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment(); - double vert_value = adj->get_value() + 20; + double vert_value = adj->get_value() + 60; if (vert_value>adj->get_upper() - canvas_height) { vert_value = adj->get_upper() - canvas_height; @@ -1533,7 +1587,7 @@ void Editor::scroll_tracks_up_line () { Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment(); - adj->set_value (adj->get_value() - 20); + adj->set_value (adj->get_value() - 60); } /* ZOOM */ @@ -1581,7 +1635,7 @@ Editor::temporal_zoom (gdouble fpu) nfpu = fpu; - new_page_size = (nframes_t) floor (canvas_width * nfpu); + new_page_size = (nframes64_t) floor (canvas_width * nfpu); half_page_size = new_page_size / 2; switch (zoom_focus) { @@ -1681,12 +1735,13 @@ Editor::temporal_zoom (gdouble fpu) } void -Editor::temporal_zoom_region () +Editor::temporal_zoom_region (bool both_axes) { nframes64_t start = max_frames; nframes64_t end = 0; RegionSelection rs; + set tracks; get_regions_for_action (rs); @@ -1695,12 +1750,16 @@ Editor::temporal_zoom_region () } for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + if ((*i)->region()->position() < start) { start = (*i)->region()->position(); } + if ((*i)->region()->last_frame() + 1 > end) { end = (*i)->region()->last_frame() + 1; } + + tracks.insert (&((*i)->get_time_axis_view())); } /* now comes an "interesting" hack ... make sure we leave a little space @@ -1713,8 +1772,15 @@ Editor::temporal_zoom_region () gint mmwidth = gdk_screen_get_width_mm (screen); double pix_per_mm = (double) pixwidth/ (double) mmwidth; double one_centimeter_in_pixels = pix_per_mm * 10.0; - nframes_t extra_samples = unit_to_frame (one_centimeter_in_pixels); - + + if ((start == 0 && end == 0) || end < start) { + return; + } + + nframes64_t range = end - start; + double new_fpu = (double)range / (double)canvas_width; + nframes64_t extra_samples = (nframes64_t) floor (one_centimeter_in_pixels * new_fpu); + if (start > extra_samples) { start -= extra_samples; } else { @@ -1727,17 +1793,53 @@ Editor::temporal_zoom_region () end = max_frames; } + if (both_axes) { + /* save visual state with track states included, and prevent + set_frames_per_unit() from doing it again. + */ + undo_visual_stack.push_back (current_visual_state(true)); + no_save_visual = true; + } + temporal_zoom_by_frame (start, end, "zoom to region"); + + if (both_axes) { + uint32_t per_track_height = (uint32_t) floor ((canvas_height - canvas_timebars_vsize - 10.0) / tracks.size()); + + /* set visible track heights appropriately */ + + for (set::iterator t = tracks.begin(); t != tracks.end(); ++t) { + (*t)->set_height (per_track_height); + } + + /* hide irrelevant tracks */ + + no_route_list_redisplay = true; + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) { + hide_track_in_display (**i, true); + } + } + + no_route_list_redisplay = false; + redisplay_route_list (); + + vertical_adjustment.set_value (0.0); + no_save_visual = false; + } + zoomed_to_region = true; + redo_visual_stack.push_back (current_visual_state()); } void -Editor::toggle_zoom_region () +Editor::toggle_zoom_region (bool both_axes) { if (zoomed_to_region) { swap_visual_state (); } else { - temporal_zoom_region (); + temporal_zoom_region (both_axes); } } @@ -1750,8 +1852,8 @@ Editor::temporal_zoom_selection () return; } - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; temporal_zoom_by_frame (start, end, "zoom to selection"); } @@ -1767,7 +1869,7 @@ Editor::temporal_zoom_session () } void -Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op) +Editor::temporal_zoom_by_frame (nframes64_t start, nframes64_t end, const string & op) { if (!session) return; @@ -1775,35 +1877,27 @@ Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & o return; } - nframes_t range = end - start; + nframes64_t range = end - start; double new_fpu = (double)range / (double)canvas_width; -// double p2 = 1.0; - -// while (p2 < new_fpu) { -// p2 *= 2.0; -// } -// new_fpu = p2; - nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu); - nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f )); - nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f)); - - if (new_leftmost > middle) new_leftmost = 0; + nframes64_t new_page = (nframes64_t) floor (canvas_width * new_fpu); + nframes64_t middle = (nframes64_t) floor( (double)start + ((double)range / 2.0f )); + nframes64_t new_leftmost = (nframes64_t) floor( (double)middle - ((double)new_page/2.0f)); -// begin_reversible_command (op); -// session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit)); -// session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu)); -// commit_reversible_command (); + if (new_leftmost > middle) { + new_leftmost = 0; + } reposition_and_zoom (new_leftmost, new_fpu); } void -Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame) +Editor::temporal_zoom_to_frame (bool coarser, nframes64_t frame) { - if (!session) return; - + if (!session) { + return; + } double range_before = frame - leftmost_frame; double new_fpu; @@ -1817,12 +1911,15 @@ Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame) range_before /= 1.61803399; } - if (new_fpu == frames_per_unit) return; - - nframes_t new_leftmost = frame - (nframes_t)range_before; + if (new_fpu == frames_per_unit) { + return; + } - if (new_leftmost > frame) new_leftmost = 0; + nframes64_t new_leftmost = frame - (nframes64_t)range_before; + if (new_leftmost > frame) { + new_leftmost = 0; + } // begin_reversible_command (_("zoom to frame")); // session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit)); // session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu)); @@ -1831,6 +1928,46 @@ Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame) reposition_and_zoom (new_leftmost, new_fpu); } + +bool +Editor::choose_new_marker_name(string &name) { + + if (!Config->get_name_new_markers()) { + /* don't prompt user for a new name */ + return true; + } + + ArdourPrompter dialog (true); + + dialog.set_prompt (_("New Name:")); + + WindowTitle title(Glib::get_application_name()); + title += _("Name New Location Marker"); + + dialog.set_title(title.get_string()); + + dialog.set_name ("MarkNameWindow"); + dialog.set_size_request (250, -1); + dialog.set_position (Gtk::WIN_POS_MOUSE); + + dialog.add_button (Stock::OK, RESPONSE_ACCEPT); + dialog.set_initial_text (name); + + dialog.show (); + + switch (dialog.run ()) { + case RESPONSE_ACCEPT: + break; + default: + return false; + } + + dialog.get_result(name); + return true; + +} + + void Editor::add_location_from_selection () { @@ -1844,8 +1981,8 @@ Editor::add_location_from_selection () return; } - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; session->locations()->next_available_name(rangename,"selection"); Location *location = new Location (start, end, rangename, Location::IsRangeMarker); @@ -1866,6 +2003,9 @@ Editor::add_location_mark (nframes64_t where) select_new_marker = true; session->locations()->next_available_name(markername,"mark"); + if (!choose_new_marker_name(markername)) { + return; + } Location *location = new Location (where, where, markername, Location::IsMark); session->begin_reversible_command (_("add marker")); XMLNode &before = session->locations()->get_state(); @@ -1882,7 +2022,7 @@ Editor::add_location_from_playhead_cursor () } void -Editor::add_location_from_audio_region () +Editor::add_locations_from_audio_region () { RegionSelection rs; @@ -1892,15 +2032,61 @@ Editor::add_location_from_audio_region () return; } - RegionView* rv = *(rs.begin()); - boost::shared_ptr region = rv->region(); + session->begin_reversible_command (rs.size () > 1 ? _("add markers") : _("add marker")); + XMLNode &before = session->locations()->get_state(); + + cerr << "Add locations\n"; + + for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) { + + boost::shared_ptr region = (*i)->region (); - Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker); + Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker); + + session->locations()->add (location, true); + } + + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), &before, &after)); + session->commit_reversible_command (); +} + +void +Editor::add_location_from_audio_region () +{ + RegionSelection rs; + + get_regions_for_action (rs); + + if (rs.empty()) { + return; + } + session->begin_reversible_command (_("add marker")); - XMLNode &before = session->locations()->get_state(); + XMLNode &before = session->locations()->get_state(); + + string markername; + + if (rs.size() > 1) { // more than one region selected + session->locations()->next_available_name(markername, "regions"); + } else { + RegionView* rv = *(rs.begin()); + boost::shared_ptr region = rv->region(); + markername = region->name(); + } + + if (!choose_new_marker_name(markername)) { + return; + } + + cerr << "Add location\n"; + + // single range spanning all selected + Location *location = new Location (rs.start(), rs.end_frame(), markername, Location::IsRangeMarker); session->locations()->add (location, true); - XMLNode &after = session->locations()->get_state(); - session->add_command(new MementoCommand(*(session->locations()), &before, &after)); + + XMLNode &after = session->locations()->get_state(); + session->add_command (new MementoCommand(*(session->locations()), &before, &after)); session->commit_reversible_command (); } @@ -1994,7 +2180,7 @@ Editor::jump_backward_to_mark () void Editor::set_mark () { - nframes_t pos; + nframes64_t pos; float prefix; bool was_floating; string markername; @@ -2003,13 +2189,16 @@ Editor::set_mark () pos = session->audible_frame (); } else { if (was_floating) { - pos = (nframes_t) floor (prefix * session->frame_rate ()); + pos = (nframes64_t) floor (prefix * session->frame_rate ()); } else { - pos = (nframes_t) floor (prefix); + pos = (nframes64_t) floor (prefix); } } session->locations()->next_available_name(markername,"mark"); + if (!choose_new_marker_name(markername)) { + return; + } session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true); } @@ -2088,14 +2277,13 @@ Editor::insert_region_list_drag (boost::shared_ptr region, int x, int y) { double wx, wy; double cx, cy; - TimeAxisView *tv; - nframes_t where; + nframes64_t where; RouteTimeAxisView *rtv = 0; boost::shared_ptr playlist; - track_canvas.window_to_world (x, y, wx, wy); - wx += horizontal_adjustment.get_value(); - wy += vertical_adjustment.get_value(); + track_canvas->window_to_world (x, y, wx, wy); + //wx += horizontal_adjustment.get_value(); + //wy += vertical_adjustment.get_value(); GdkEvent event; event.type = GDK_BUTTON_RELEASE; @@ -2108,12 +2296,13 @@ Editor::insert_region_list_drag (boost::shared_ptr region, int x, int y) /* clearly outside canvas area */ return; } - - if ((tv = trackview_by_y_position (cy)) == 0) { + + std::pair tv = trackview_by_y_position (cy); + if (tv.first == 0) { return; } - if ((rtv = dynamic_cast(tv)) == 0) { + if ((rtv = dynamic_cast (tv.first)) == 0) { return; } @@ -2134,12 +2323,11 @@ void Editor::insert_route_list_drag (boost::shared_ptr route, int x, int y) { double wx, wy; double cx, cy; - TimeAxisView *tv; nframes_t where; RouteTimeAxisView *dest_rtv = 0; RouteTimeAxisView *source_rtv = 0; - track_canvas.window_to_world (x, y, wx, wy); + track_canvas->window_to_world (x, y, wx, wy); wx += horizontal_adjustment.get_value(); wy += vertical_adjustment.get_value(); @@ -2150,11 +2338,12 @@ Editor::insert_route_list_drag (boost::shared_ptr route, int x, int y) { where = event_frame (&event, &cx, &cy); - if ((tv = trackview_by_y_position (cy)) == 0) { + std::pair const tv = trackview_by_y_position (cy); + if (tv.first == 0) { return; } - if ((dest_rtv = dynamic_cast(tv)) == 0) { + if ((dest_rtv = dynamic_cast (tv.first)) == 0) { return; } @@ -2310,14 +2499,19 @@ Editor::play_from_edit_point_and_return () nframes64_t start_frame; nframes64_t return_frame; + start_frame = get_preferred_edit_position (true); + + if (session->transport_rolling()) { + session->request_locate (start_frame, false); + return; + } + /* don't reset the return frame if its already set */ if ((return_frame = session->requested_return_frame()) < 0) { return_frame = session->audible_frame(); } - start_frame = get_preferred_edit_position (true); - if (start_frame >= 0) { session->request_roll_at_and_return (start_frame, return_frame); } @@ -2540,6 +2734,11 @@ Editor::build_interthread_progress_window () interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT); + interthread_progress_window->set_border_width (12); + interthread_progress_window->get_vbox()->set_spacing (6); + + interthread_progress_label.set_alignment (0.5, 0.5); + interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false); interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false); @@ -2572,34 +2771,29 @@ Editor::region_from_selection () return; } - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; - nframes_t selection_cnt = end - start + 1; + nframes64_t selection_cnt = end - start + 1; for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - boost::shared_ptr current; - boost::shared_ptr current_r; + boost::shared_ptr current; boost::shared_ptr pl; - - nframes_t internal_start; + nframes64_t internal_start; string new_name; if ((pl = (*i)->playlist()) == 0) { continue; } - if ((current_r = pl->top_region_at (start)) == 0) { + if ((current = pl->top_region_at (start)) == 0) { continue; } - current = boost::dynamic_pointer_cast (current_r); - assert(current); // FIXME - if (current != 0) { - internal_start = start - current->position(); - session->region_name (new_name, current->name(), true); - boost::shared_ptr region (RegionFactory::create (current, internal_start, selection_cnt, new_name)); - } + internal_start = start - current->position(); + session->region_name (new_name, current->name(), true); + boost::shared_ptr region (RegionFactory::create (current, + internal_start, selection_cnt, new_name)); } } @@ -2610,35 +2804,30 @@ Editor::create_region_from_selection (vector >& new_re return; } - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; sort_track_selection (); for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { - - boost::shared_ptr current; - boost::shared_ptr current_r; + boost::shared_ptr current; boost::shared_ptr playlist; - nframes_t internal_start; + nframes64_t internal_start; string new_name; if ((playlist = (*i)->playlist()) == 0) { continue; } - if ((current_r = playlist->top_region_at(start)) == 0) { + if ((current = playlist->top_region_at(start)) == 0) { continue; } - if ((current = boost::dynamic_pointer_cast(current_r)) == 0) { - continue; - } - internal_start = start - current->position(); session->region_name (new_name, current->name(), true); - new_regions.push_back (boost::dynamic_pointer_cast (RegionFactory::create (current, internal_start, end - start + 1, new_name))); + new_regions.push_back (RegionFactory::create (current, + internal_start, end - start + 1, new_name)); } } @@ -2653,19 +2842,12 @@ Editor::split_multichannel_region () return; } - vector > v; + vector< boost::shared_ptr > v; for (list::iterator x = rs.begin(); x != rs.end(); ++x) { - - AudioRegionView* arv = dynamic_cast(*x); - - if (!arv || arv->audio_region()->n_channels() < 2) { - continue; - } - - (arv)->audio_region()->separate_by_channel (*session, v); - } -} + (*x)->region()->separate_by_channel (*session, v); + } +} void Editor::new_region_from_selection () @@ -2710,8 +2892,8 @@ Editor::separate_regions_between (const TimeSelection& ts) } if (tmptracks.empty()) { - /* no regions selected: use all tracks */ - tmptracks = track_views; + /* no regions selected: do nothing */ + return; } } else { @@ -2722,9 +2904,6 @@ Editor::separate_regions_between (const TimeSelection& ts) sort_track_selection (&tmptracks); - - - for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) { RouteTimeAxisView* rtv; @@ -2754,10 +2933,12 @@ Editor::separate_regions_between (const TimeSelection& ts) for (list::const_iterator t = ts.begin(); t != ts.end(); ++t) { - sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view)); + sigc::connection c = rtv->view()->RegionViewAdded.connect ( + mem_fun(*this, &Editor::collect_new_region_view)); latest_regionviews.clear (); - playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true); + playlist->partition ((nframes64_t)((*t).start * speed), + (nframes64_t)((*t).end * speed), true); c.disconnect (); @@ -2765,15 +2946,17 @@ Editor::separate_regions_between (const TimeSelection& ts) got_some = true; - rtv->view()->foreach_regionview (bind (sigc::ptr_fun (add_if_covered), &(*t), &new_selection)); + rtv->view()->foreach_regionview (bind ( + sigc::ptr_fun (add_if_covered), + &(*t), &new_selection)); if (!in_command) { begin_reversible_command (_("separate")); in_command = true; } - session->add_command(new MementoCommand(*playlist, before, &playlist->get_state())); - + session->add_command(new MementoCommand( + *playlist, before, &playlist->get_state())); } } @@ -2800,6 +2983,7 @@ Editor::separate_region_from_selection () to allow discontiguous operation, since get_edit_op_range() currently returns a single range. */ + if (mouse_mode == MouseRange && !selection->time.empty()) { separate_regions_between (selection->time); @@ -2873,7 +3057,7 @@ Editor::crop_region_to_selection () } void -Editor::crop_region_to (nframes_t start, nframes_t end) +Editor::crop_region_to (nframes64_t start, nframes64_t end) { vector > playlists; boost::shared_ptr playlist; @@ -2907,9 +3091,9 @@ Editor::crop_region_to (nframes_t start, nframes_t end) return; } - nframes_t the_start; - nframes_t the_end; - nframes_t cnt; + nframes64_t the_start; + nframes64_t the_end; + nframes64_t cnt; begin_reversible_command (_("trim to selection")); @@ -2927,7 +3111,7 @@ Editor::crop_region_to (nframes_t start, nframes_t end) if the selection extends beyond the region */ - the_start = max (the_start, region->position()); + the_start = max (the_start, (nframes64_t) region->position()); if (max_frames - the_start < region->length()) { the_end = the_start + region->length() - 1; } else { @@ -2948,7 +3132,7 @@ Editor::crop_region_to (nframes_t start, nframes_t end) void Editor::region_fill_track () { - nframes_t end; + nframes64_t end; RegionSelection rs; get_regions_for_action (rs); @@ -3010,8 +3194,8 @@ Editor::region_fill_selection () TreeModel::iterator i = region_list_display.get_selection()->get_selected(); boost::shared_ptr region = (*i)[region_list_columns.region]; - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; boost::shared_ptr playlist; @@ -3019,7 +3203,7 @@ Editor::region_fill_selection () return; } - nframes_t selection_length = end - start; + nframes64_t selection_length = end - start; float times = (float)selection_length / region->length(); begin_reversible_command (_("fill selection")); @@ -3080,16 +3264,22 @@ Editor::set_sync_point (nframes64_t where, const RegionSelection& rs) void Editor::remove_region_sync () { - begin_reversible_command (_("remove sync")); + RegionSelection rs; - for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - boost::shared_ptr r = (*i)->region(); - XMLNode &before = r->playlist()->get_state(); - r->clear_sync_position (); - XMLNode &after = r->playlist()->get_state(); - session->add_command(new MementoCommand(*(r->playlist()), &before, &after)); + get_regions_for_action (rs); + + if (rs.empty()) { + return; } + begin_reversible_command (_("remove sync")); + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + + XMLNode &before = (*i)->region()->playlist()->get_state(); + (*i)->region()->clear_sync_position (); + XMLNode &after = (*i)->region()->playlist()->get_state(); + session->add_command(new MementoCommand(*((*i)->region()->playlist()), &before, &after)); + } commit_reversible_command (); } @@ -3119,7 +3309,7 @@ Editor::align (RegionPoint what) { RegionSelection rs; - get_regions_for_action (rs, false); + get_regions_for_action (rs); nframes64_t where = get_preferred_edit_position(); if (!rs.empty()) { @@ -3138,7 +3328,7 @@ Editor::align_relative (RegionPoint what) nframes64_t where = get_preferred_edit_position(); RegionSelection rs; - get_regions_for_action (rs, false); + get_regions_for_action (rs); if (!rs.empty()) { align_selection_relative (what, where, rs); @@ -3152,18 +3342,19 @@ struct RegionSortByTime { }; void -Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs) +Editor::align_selection_relative (RegionPoint point, nframes64_t position, const RegionSelection& rs) { if (rs.empty()) { return; } - nframes_t distance = 0; - nframes_t pos = 0; - int dir = 0; + nframes64_t distance = 0; + nframes64_t pos = 0; + int dir = 1; list sorted; rs.by_position (sorted); + boost::shared_ptr r ((*sorted.begin())->region()); switch (point) { @@ -3171,7 +3362,6 @@ Editor::align_selection_relative (RegionPoint point, nframes_t position, const R pos = position; if (position > r->position()) { distance = position - r->position(); - dir = 1; } else { distance = r->position() - position; dir = -1; @@ -3182,7 +3372,6 @@ Editor::align_selection_relative (RegionPoint point, nframes_t position, const R if (position > r->last_frame()) { distance = position - r->last_frame(); pos = r->position() + distance; - dir = 1; } else { distance = r->last_frame() - position; pos = r->position() - distance; @@ -3194,7 +3383,6 @@ Editor::align_selection_relative (RegionPoint point, nframes_t position, const R pos = r->adjust_to_sync (position); if (pos > r->position()) { distance = pos - r->position(); - dir = 1; } else { distance = r->position() - pos; dir = -1; @@ -3240,7 +3428,7 @@ Editor::align_selection_relative (RegionPoint point, nframes_t position, const R } void -Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs) +Editor::align_selection (RegionPoint point, nframes64_t position, const RegionSelection& rs) { if (rs.empty()) { return; @@ -3256,7 +3444,7 @@ Editor::align_selection (RegionPoint point, nframes_t position, const RegionSele } void -Editor::align_region (boost::shared_ptr region, RegionPoint point, nframes_t position) +Editor::align_region (boost::shared_ptr region, RegionPoint point, nframes64_t position) { begin_reversible_command (_("align region")); align_region_internal (region, point, position); @@ -3264,7 +3452,7 @@ Editor::align_region (boost::shared_ptr region, RegionPoint point, nfram } void -Editor::align_region_internal (boost::shared_ptr region, RegionPoint point, nframes_t position) +Editor::align_region_internal (boost::shared_ptr region, RegionPoint point, nframes64_t position) { XMLNode &before = region->playlist()->get_state(); @@ -3318,42 +3506,37 @@ Editor::trim_region_to_location (const Location& loc, const char* str) begin_reversible_command (str); for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) { - AudioRegionView* arv = dynamic_cast (*x); - - if (!arv) { - continue; - } + RegionView* rv = (*x); /* require region to span proposed trim */ - - switch (arv->region()->coverage (loc.start(), loc.end())) { + switch (rv->region()->coverage (loc.start(), loc.end())) { case OverlapInternal: break; default: continue; } - AudioTimeAxisView* atav = dynamic_cast (&arv->get_time_axis_view()); - - if (!atav) { + RouteTimeAxisView* tav = dynamic_cast (&rv->get_time_axis_view()); + if (!tav) { return; } float speed = 1.0; - nframes_t start; - nframes_t end; + nframes64_t start; + nframes64_t end; - if (atav->get_diskstream() != 0) { - speed = atav->get_diskstream()->speed(); + if (tav->get_diskstream() != 0) { + speed = tav->get_diskstream()->speed(); } start = session_frame_to_track_frame (loc.start(), speed); end = session_frame_to_track_frame (loc.end(), speed); - XMLNode &before = arv->region()->playlist()->get_state(); - arv->region()->trim_to (start, (end - start), this); - XMLNode &after = arv->region()->playlist()->get_state(); - session->add_command(new MementoCommand(*(arv->region()->playlist()), &before, &after)); + XMLNode &before = rv->region()->playlist()->get_state(); + rv->region()->trim_to (start, (end - start), this); + XMLNode &after = rv->region()->playlist()->get_state(); + session->add_command(new MementoCommand( + *(rv->region()->playlist()), &before, &after)); } commit_reversible_command (); @@ -3371,34 +3554,29 @@ Editor::trim_region_to_edit_point () begin_reversible_command (_("trim region start to edit point")); for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) { - AudioRegionView* arv = dynamic_cast (*x); - - if (!arv) { - continue; - } + RegionView* rv = (*x); /* require region to cover trim */ - - if (!arv->region()->covers (where)) { + if (!rv->region()->covers (where)) { continue; } - AudioTimeAxisView* atav = dynamic_cast (&arv->get_time_axis_view()); - - if (!atav) { + RouteTimeAxisView* tav = dynamic_cast (&rv->get_time_axis_view()); + if (!tav) { return; } float speed = 1.0; - if (atav->get_diskstream() != 0) { - speed = atav->get_diskstream()->speed(); + if (tav->get_diskstream() != 0) { + speed = tav->get_diskstream()->speed(); } - XMLNode &before = arv->region()->playlist()->get_state(); - arv->region()->trim_end( session_frame_to_track_frame(where, speed), this); - XMLNode &after = arv->region()->playlist()->get_state(); - session->add_command(new MementoCommand(*(arv->region()->playlist()), &before, &after)); + XMLNode &before = rv->region()->playlist()->get_state(); + rv->region()->trim_end( session_frame_to_track_frame(where, speed), this); + XMLNode &after = rv->region()->playlist()->get_state(); + session->add_command(new MementoCommand( + *(rv->region()->playlist()), &before, &after)); } commit_reversible_command (); @@ -3416,34 +3594,29 @@ Editor::trim_region_from_edit_point () begin_reversible_command (_("trim region end to edit point")); for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) { - AudioRegionView* arv = dynamic_cast (*x); - - if (!arv) { - continue; - } + RegionView* rv = (*x); /* require region to cover trim */ - - if (!arv->region()->covers (where)) { + if (!rv->region()->covers (where)) { continue; } - AudioTimeAxisView* atav = dynamic_cast (&arv->get_time_axis_view()); - - if (!atav) { + RouteTimeAxisView* tav = dynamic_cast (&rv->get_time_axis_view()); + if (!tav) { return; } float speed = 1.0; - if (atav->get_diskstream() != 0) { - speed = atav->get_diskstream()->speed(); + if (tav->get_diskstream() != 0) { + speed = tav->get_diskstream()->speed(); } - XMLNode &before = arv->region()->playlist()->get_state(); - arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this); - XMLNode &after = arv->region()->playlist()->get_state(); - session->add_command(new MementoCommand(*(arv->region()->playlist()), &before, &after)); + XMLNode &before = rv->region()->playlist()->get_state(); + rv->region()->trim_front ( session_frame_to_track_frame(where, speed), this); + XMLNode &after = rv->region()->playlist()->get_state(); + session->add_command(new MementoCommand( + *(rv->region()->playlist()), &before, &after)); } commit_reversible_command (); @@ -3452,17 +3625,17 @@ Editor::trim_region_from_edit_point () void Editor::unfreeze_route () { - if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) { + if (clicked_routeview == 0 || !clicked_routeview->is_track()) { return; } - clicked_routeview->audio_track()->unfreeze (); + clicked_routeview->track()->unfreeze (); } void* Editor::_freeze_thread (void* arg) { - PBD::ThreadCreated (pthread_self(), X_("Freeze")); + PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freeze")); return static_cast(arg)->freeze_thread (); } @@ -3470,13 +3643,14 @@ void* Editor::freeze_thread () { clicked_routeview->audio_track()->freeze (*current_interthread_info); + current_interthread_info->done = true; return 0; } gint Editor::freeze_progress_timeout (void *arg) { - interthread_progress_bar.set_fraction (current_interthread_info->progress/100); + interthread_progress_bar.set_fraction (current_interthread_info->progress); return !(current_interthread_info->done || current_interthread_info->cancel); } @@ -3514,11 +3688,11 @@ Editor::freeze_route () pthread_attr_init(&attr); pthread_attr_setstacksize(&attr, 500000); - pthread_create (&itt.thread, &attr, _freeze_thread, this); + pthread_create_and_store (X_("freezer"), &itt.thread, &attr, _freeze_thread, this); pthread_attr_destroy(&attr); - track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); + track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH)); while (!itt.done && !itt.cancel) { gtk_main_iteration (); @@ -3527,11 +3701,11 @@ Editor::freeze_route () interthread_progress_connection.disconnect (); interthread_progress_window->hide_all (); current_interthread_info = 0; - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } void -Editor::bounce_range_selection () +Editor::bounce_range_selection (bool replace, bool enable_processing) { if (selection->time.empty()) { return; @@ -3539,9 +3713,9 @@ Editor::bounce_range_selection () TrackSelection views = selection->tracks; - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; - nframes_t cnt = end - start + 1; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; + nframes64_t cnt = end - start + 1; begin_reversible_command (_("bounce range")); @@ -3565,9 +3739,17 @@ Editor::bounce_range_selection () itt.cancel = false; itt.progress = false; - XMLNode &before = playlist->get_state(); - rtv->track()->bounce_range (start, cnt, itt); - XMLNode &after = playlist->get_state(); + XMLNode &before = playlist->get_state(); + boost::shared_ptr r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing); + + if (replace) { + list ranges; + ranges.push_back (AudioRange (start, start+cnt, 0)); + playlist->cut (ranges); // discard result + playlist->add_region (r, start); + } + + XMLNode &after = playlist->get_state(); session->add_command (new MementoCommand (*playlist, &before, &after)); } @@ -3636,6 +3818,19 @@ Editor::cut_copy (CutCopyOp op) opname = _("clear"); break; } + + /* if we're deleting something, and the mouse is still pressed, + the thing we started a drag for will be gone when we release + the mouse button(s). avoid this. see part 2 at the end of + this function. + */ + + if (op == Cut || op == Clear) { + if (drag_info.item) { + drag_info.item->ungrab (0); + drag_info.item = 0; + } + } cut_buffer->clear (); @@ -3650,12 +3845,18 @@ Editor::cut_copy (CutCopyOp op) Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc)); } + break_drag (); + return; } RegionSelection rs; - get_regions_for_action (rs); + /* we only want to cut regions if some are selected */ + + if (!selection->regions.empty()) { + get_regions_for_action (rs); + } switch (current_mouse_mode()) { case MouseObject: @@ -3664,7 +3865,7 @@ Editor::cut_copy (CutCopyOp op) begin_reversible_command (opname + _(" objects")); if (!rs.empty()) { - cut_copy_regions (op); + cut_copy_regions (op, rs); if (op == Cut) { selection->clear_regions (); @@ -3710,6 +3911,11 @@ Editor::cut_copy (CutCopyOp op) default: break; } + + + if (op == Cut || op == Clear) { + break_drag (); + } } /** Cut, copy or clear selected automation points. @@ -3751,7 +3957,7 @@ struct PlaylistMapping { * @param op Operation (Cut, Copy or Clear) */ void -Editor::cut_copy_regions (CutCopyOp op) +Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) { /* we can't use a std::map here because the ordering is important, and we can't trivially sort a map when we want ordered access to both elements. i think. @@ -3759,21 +3965,18 @@ Editor::cut_copy_regions (CutCopyOp op) vector pmap; - nframes_t first_position = max_frames; + nframes64_t first_position = max_frames; set freezelist; pair::iterator,bool> insert_result; /* get ordering correct before we cut/copy */ - RegionSelection rs; - - get_regions_for_action (rs); rs.sort_by_position_and_track (); for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) { - first_position = min ((*x)->region()->position(), first_position); + first_position = min ((nframes64_t) (*x)->region()->position(), first_position); if (op == Cut || op == Clear) { boost::shared_ptr pl = (*x)->region()->playlist(); @@ -3889,9 +4092,14 @@ void Editor::cut_copy_ranges (CutCopyOp op) { TrackSelection* ts; + TrackSelection entered; if (selection->tracks.empty()) { - ts = &track_views; + if (!entered_track) { + return; + } + entered.push_back (entered_track); + ts = &entered; } else { ts = &selection->tracks; } @@ -3922,7 +4130,7 @@ Editor::mouse_paste () } void -Editor::paste_internal (nframes_t position, float times) +Editor::paste_internal (nframes64_t position, float times) { bool commit = false; @@ -4140,9 +4348,9 @@ void Editor::nudge_track (bool use_edit, bool forwards) { boost::shared_ptr playlist; - nframes_t distance; - nframes_t next_distance; - nframes_t start; + nframes64_t distance; + nframes64_t next_distance; + nframes64_t start; if (use_edit) { start = get_preferred_edit_position(); @@ -4220,7 +4428,7 @@ Editor::normalize_region () begin_reversible_command (_("normalize")); - track_canvas.get_window()->set_cursor (*wait_cursor); + track_canvas->get_window()->set_cursor (*wait_cursor); gdk_flush (); for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) { @@ -4233,7 +4441,7 @@ Editor::normalize_region () } commit_reversible_command (); - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } @@ -4356,7 +4564,7 @@ Editor::apply_filter (Filter& filter, string command) begin_reversible_command (command); - track_canvas.get_window()->set_cursor (*wait_cursor); + track_canvas->get_window()->set_cursor (*wait_cursor); gdk_flush (); for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) { @@ -4392,7 +4600,7 @@ Editor::apply_filter (Filter& filter, string command) rs.clear (); out: - track_canvas.get_window()->set_cursor (*current_canvas_cursor); + track_canvas->get_window()->set_cursor (*current_canvas_cursor); } void @@ -4430,7 +4638,7 @@ Editor::external_edit_region () } void -Editor::brush (nframes_t pos) +Editor::brush (nframes64_t pos) { RegionSelection sel; RegionSelection rs; @@ -4554,6 +4762,28 @@ Editor::toggle_region_opaque () } } +void +Editor::toggle_record_enable () +{ + bool new_state = false; + bool first = true; + for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) { + RouteTimeAxisView *rtav = dynamic_cast(*i); + if (!rtav) + continue; + if (!rtav->is_track()) + continue; + + if (first) { + new_state = !rtav->track()->record_enabled(); + first = false; + } + + rtav->track()->set_record_enable(new_state, this); + } +} + + void Editor::set_fade_length (bool in) { @@ -4574,7 +4804,7 @@ Editor::set_fade_length (bool in) } nframes64_t pos = get_preferred_edit_position(); - nframes_t len; + nframes64_t len; char* cmd; if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) { @@ -4813,6 +5043,69 @@ Editor::set_fade_out_active (bool yn) commit_reversible_command (); } +void +Editor::toggle_selected_region_fades (int dir) +{ + RegionSelection rs; + RegionSelection::iterator i; + boost::shared_ptr ar; + bool yn; + + get_regions_for_action (rs); + + if (rs.empty()) { + return; + } + + for (i = rs.begin(); i != rs.end(); ++i) { + if ((ar = boost::dynamic_pointer_cast((*i)->region())) != 0) { + if (dir == -1) { + yn = ar->fade_out_active (); + } else { + yn = ar->fade_in_active (); + } + break; + } + } + + if (i == rs.end()) { + return; + } + + /* XXX should this undo-able? */ + + for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) { + if ((ar = boost::dynamic_pointer_cast((*i)->region())) == 0) { + continue; + } + if (dir == 1 || dir == 0) { + ar->set_fade_in_active (!yn); + } + + if (dir == -1 || dir == 0) { + ar->set_fade_out_active (!yn); + } + } +} + + +/** Update region fade visibility after its configuration has been changed */ +void +Editor::update_region_fade_visibility () +{ + bool _fade_visibility = Config->get_show_region_fades (); + + for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { + AudioTimeAxisView* v = dynamic_cast(*i); + if (v) { + if (_fade_visibility) { + v->audio_view()->show_all_fades (); + } else { + v->audio_view()->hide_all_fades (); + } + } + } +} /** Update crossfade visibility after its configuration has been changed */ void @@ -4974,17 +5267,26 @@ Editor::select_next_route() TimeAxisView* current = selection->tracks.front(); - for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { - if (*i == current) { - ++i; - if (i != track_views.end()) { - selection->set (*i); - } else { - selection->set (*(track_views.begin())); + RouteUI *rui; + 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; } - break; } - } + rui = dynamic_cast(current); + } while ( current->hidden() || (rui != NULL && !rui->route()->active())); + + selection->set(current); + + ensure_track_visible(current); } void @@ -4997,17 +5299,55 @@ Editor::select_prev_route() TimeAxisView* current = selection->tracks.front(); - for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) { - if (*i == current) { - ++i; - if (i != track_views.rend()) { - selection->set (*i); - } else { - selection->set (*(track_views.rbegin())); + RouteUI *rui; + 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; } - break; } + rui = dynamic_cast(current); + } while ( current->hidden() || (rui != NULL && !rui->route()->active())); + + selection->set (current); + + ensure_track_visible(current); +} + +void +Editor::ensure_track_visible(TimeAxisView *track) +{ + if (track->hidden()) + return; + + double const current_view_min_y = vertical_adjustment.get_value(); + double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize; + + double const track_min_y = track->y_position (); + double const track_max_y = track->y_position () + track->effective_height (); + + if (track_min_y >= current_view_min_y && + track_max_y <= current_view_max_y) { + return; } + + double new_value; + + if (track_min_y < current_view_min_y) { + // Track is above the current view + new_value = track_min_y; + } else { + // Track is below the current view + new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size(); + } + + vertical_adjustment.set_value(new_value); } void @@ -5017,8 +5357,8 @@ Editor::set_loop_from_selection (bool play) return; } - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; set_loop_range (start, end, _("set loop range from selection")); @@ -5088,8 +5428,8 @@ Editor::set_punch_from_selection () return; } - nframes_t start = selection->time[clicked_selection].start; - nframes_t end = selection->time[clicked_selection].end; + nframes64_t start = selection->time[clicked_selection].start; + nframes64_t end = selection->time[clicked_selection].end; set_punch_range (start, end, _("set punch range from selection")); } @@ -5505,14 +5845,13 @@ Editor::tab_to_transient (bool forward) } } } - void Editor::playhead_forward_to_grid () { if (!session) return; nframes64_t pos = playhead_cursor->current_frame; - if (pos < max_frames) { - pos++; + if (pos < max_frames - 1) { + pos += 2; snap_to_internal (pos, 1, false); session->request_locate (pos); } @@ -5524,10 +5863,432 @@ Editor::playhead_backward_to_grid () { if (!session) return; nframes64_t pos = playhead_cursor->current_frame; - if (pos > 1) { - pos--; + if (pos > 2) { + pos -= 2; snap_to_internal (pos, -1, false); session->request_locate (pos); } } +void +Editor::set_track_height (uint32_t h) +{ + TrackSelection& ts (selection->tracks); + + if (ts.empty()) { + return; + } + + for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { + (*x)->set_height (h); + } +} + +void +Editor::toggle_tracks_active () +{ + TrackSelection& ts (selection->tracks); + bool first = true; + bool target = false; + + if (ts.empty()) { + return; + } + + for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { + RouteTimeAxisView* rtv = dynamic_cast(*x); + + if (rtv) { + if (first) { + target = !rtv->_route->active(); + first = false; + } + rtv->_route->set_active (target); + } + } +} + +void +Editor::remove_tracks () +{ + TrackSelection& ts (selection->tracks); + + if (ts.empty()) { + return; + } + + vector choices; + string prompt; + int ntracks = 0; + int nbusses = 0; + const char* trackstr; + const char* busstr; + vector > routes; + + for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { + RouteTimeAxisView* rtv = dynamic_cast (*x); + if (rtv) { + if (rtv->is_track()) { + ntracks++; + } else { + nbusses++; + } + } + routes.push_back (rtv->_route); + } + + if (ntracks + nbusses == 0) { + return; + } + + if (ntracks > 1) { + trackstr = _("tracks"); + } else { + trackstr = _("track"); + } + + if (nbusses > 1) { + busstr = _("busses"); + } else { + busstr = _("bus"); + } + + if (ntracks) { + if (nbusses) { + prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n" + "(You may also lose the playlists associated with the %2)\n\n" + "This action cannot be undone!"), + ntracks, trackstr, nbusses, busstr); + } else { + prompt = string_compose (_("Do you really want to remove %1 %2?\n" + "(You may also lose the playlists associated with the %2)\n\n" + "This action cannot be undone!"), + ntracks, trackstr); + } + } else if (nbusses) { + prompt = string_compose (_("Do you really want to remove %1 %2?"), + nbusses, busstr); + } + + choices.push_back (_("No, do nothing.")); + if (ntracks + nbusses > 1) { + choices.push_back (_("Yes, remove them.")); + } else { + choices.push_back (_("Yes, remove it.")); + } + + Choice prompter (prompt, choices); + + if (prompter.run () != 1) { + return; + } + + for (vector >::iterator x = routes.begin(); x != routes.end(); ++x) { + session->remove_route (*x); + } +} + +void +Editor::set_waveform_scale (WaveformScale ws) +{ + TrackSelection& ts (selection->tracks); + + if (ts.empty()) { + return; + } + + for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) { + AudioTimeAxisView* atv = dynamic_cast (*x); + if (atv) { + atv->set_waveform_scale (ws); + } + } +} + +void +Editor::do_insert_time () +{ + if (selection->tracks.empty()) { + return; + } + + nframes64_t pos = get_preferred_edit_position (); + ArdourDialog d (*this, _("Insert Time")); + VButtonBox button_box; + VBox option_box; + RadioButtonGroup group; + RadioButton leave_button (group, _("Stay in position")); + RadioButton move_button (group, _("Move")); + RadioButton split_button (group, _("Split & Later Section Moves")); + Label intersect_option_label (_("Intersected regions should:")); + CheckButton glue_button (_("Move Glued Regions")); + CheckButton marker_button (_("Move Markers")); + AudioClock clock ("insertTimeClock", true, X_("InsertTimeClock"), true, true, true); + HBox clock_box; + + clock.set (0); + clock.set_session (session); + clock.set_bbt_reference (pos); + + clock_box.pack_start (clock, false, true); + + option_box.set_spacing (6); + option_box.pack_start (intersect_option_label, false, false); + option_box.pack_start (button_box, false, false); + option_box.pack_start (glue_button, false, false); + option_box.pack_start (marker_button, false, false); + + button_box.pack_start (leave_button, false, false); + button_box.pack_start (move_button, false, false); + button_box.pack_start (split_button, false, false); + + d.get_vbox()->set_border_width (12); + d.get_vbox()->pack_start (clock_box, false, false); + d.get_vbox()->pack_start (option_box, false, false); + + leave_button.show (); + move_button.show (); + split_button.show (); + intersect_option_label.show (); + option_box.show (); + button_box.show (); + glue_button.show (); + clock.show_all(); + clock_box.show (); + marker_button.show (); + + d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); + d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK); + d.show (); + + int response = d.run (); + + if (response != RESPONSE_OK) { + return; + } + + nframes64_t distance = clock.current_duration (pos); + + if (distance == 0) { + return; + } + + InsertTimeOption opt; + + if (leave_button.get_active()) { + opt = LeaveIntersected; + } else if (move_button.get_active()) { + opt = MoveIntersected; + } else { + opt = SplitIntersected; + } + + insert_time (pos, distance, opt, glue_button.get_active(), marker_button.get_active()); +} + +void +Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt, + bool ignore_music_glue, bool markers_too) +{ + bool commit = false; + + if (Config->get_edit_mode() == Lock) { + return; + } + + begin_reversible_command (_("insert time")); + + for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) { + /* regions */ + boost::shared_ptr pl = (*x)->playlist(); + + if (pl) { + + XMLNode &before = pl->get_state(); + + if (opt == SplitIntersected) { + pl->split (pos); + } + + pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue); + + XMLNode &after = pl->get_state(); + + session->add_command (new MementoCommand (*pl, &before, &after)); + commit = true; + } + + /* automation */ + RouteTimeAxisView* rtav = dynamic_cast (*x); + if (rtav) { + rtav->route ()->shift (pos, frames); + commit = true; + } + } + + /* markers */ + if (markers_too) { + bool moved = false; + XMLNode& before (session->locations()->get_state()); + Locations::LocationList copy (session->locations()->list()); + + for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) { + + Locations::LocationList::const_iterator tmp; + + if ((*i)->start() >= pos) { + (*i)->set_start ((*i)->start() + frames); + if (!(*i)->is_mark()) { + (*i)->set_end ((*i)->end() + frames); + } + moved = true; + } + } + + if (moved) { + XMLNode& after (session->locations()->get_state()); + session->add_command (new MementoCommand(*session->locations(), &before, &after)); + } + } + + if (commit) { + commit_reversible_command (); + } +} + +void +Editor::fit_tracks () +{ + if (selection->tracks.empty()) { + return; + } + + uint32_t child_heights = 0; + + for (TrackSelection::iterator t = selection->tracks.begin(); t != selection->tracks.end(); ++t) { + + if (!(*t)->marked_for_display()) { + continue; + } + + child_heights += (*t)->effective_height() - (*t)->current_height(); + } + + uint32_t h = (uint32_t) floor ((canvas_height - child_heights - canvas_timebars_vsize)/selection->tracks.size()); + double first_y_pos = DBL_MAX; + + if (h < TimeAxisView::hSmall) { + MessageDialog msg (*this, _("There are too many selected tracks to fit in the current window")); + /* too small to be displayed */ + return; + } + + undo_visual_stack.push_back (current_visual_state()); + + /* operate on all tracks, hide unselected ones that are in the middle of selected ones */ + + bool prev_was_selected = false; + bool is_selected = selection->selected (track_views.front()); + bool next_is_selected; + + for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) { + + TrackViewList::iterator next; + + next = t; + ++next; + + if (next != track_views.end()) { + next_is_selected = selection->selected (*next); + } else { + next_is_selected = false; + } + + if (is_selected) { + (*t)->set_height (h); + first_y_pos = std::min ((*t)->y_position (), first_y_pos); + } else { + if (prev_was_selected && next_is_selected) { + hide_track_in_display (**t); + } + } + + prev_was_selected = is_selected; + is_selected = next_is_selected; + } + + /* + set the controls_layout height now, because waiting for its size + request signal handler will cause the vertical adjustment setting to fail + */ + + controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize; + vertical_adjustment.set_value (first_y_pos); + + redo_visual_stack.push_back (current_visual_state()); +} + +void +Editor::save_visual_state (uint32_t n) +{ + while (visual_states.size() <= n) { + visual_states.push_back (0); + } + + delete visual_states[n]; + + visual_states[n] = current_visual_state (true); + gdk_beep (); +} + +void +Editor::goto_visual_state (uint32_t n) +{ + if (visual_states.size() <= n) { + return; + } + + if (visual_states[n] == 0) { + return; + } + + use_visual_state (*visual_states[n]); +} + +void +Editor::start_visual_state_op (uint32_t n) +{ + cerr << "Start visual op\n"; + if (visual_state_op_connection.empty()) { + visual_state_op_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::end_visual_state_op), n), 1000); + cerr << "\tqueued new timeout\n"; + } +} + +void +Editor::cancel_visual_state_op (uint32_t n) +{ + if (!visual_state_op_connection.empty()) { + cerr << "cancel visual op, time to goto\n"; + visual_state_op_connection.disconnect(); + goto_visual_state (n); + } else { + cerr << "cancel visual op, do nothing\n"; + } +} + +bool +Editor::end_visual_state_op (uint32_t n) +{ + visual_state_op_connection.disconnect(); + save_visual_state (n); + + PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true); + char buf[32]; + snprintf (buf, sizeof (buf), _("Saved view %u"), n+1); + pup->set_text (buf); + pup->touch(); + + return false; // do not call again +} +