X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=gtk2_ardour%2Feditor_ops.cc;h=a2f8048fec8931a09b8efd994326aa1d3c27981d;hb=f250d16487ba747be0276ebd15b240ddd07da132;hp=60ea575624528dc64c6761c6c4bf3be90debc358;hpb=18190eaa5eb2a29b5824bfaa08e03d4360b6cbb3;p=ardour.git diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index 60ea575624..a2f8048fec 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -57,6 +57,7 @@ #include "canvas/canvas.h" +#include "actions.h" #include "ardour_ui.h" #include "audio_region_view.h" #include "audio_streamview.h" @@ -70,7 +71,6 @@ #include "editor_drag.h" #include "editor_regions.h" #include "editor_routes.h" -#include "gtk-custom-hruler.h" #include "gui_thread.h" #include "insert_time_dialog.h" #include "interthread_progress_window.h" @@ -89,7 +89,6 @@ #include "strip_silence_dialog.h" #include "time_axis_view.h" #include "transpose_dialog.h" -#include "utils.h" #include "i18n.h" @@ -134,7 +133,11 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions) { bool frozen = false; - list > used_playlists; + RegionSelection pre_selected_regions = selection->regions; + bool working_on_selection = !pre_selected_regions.empty(); + + list > used_playlists; + list used_trackviews; if (regions.empty()) { return; @@ -189,9 +192,16 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions) /* remember used playlists so we can thaw them later */ used_playlists.push_back(pl); + + TimeAxisView& tv = (*a)->get_time_axis_view(); + RouteTimeAxisView* rtv = dynamic_cast (&tv); + if (rtv) { + used_trackviews.push_back (rtv); + } pl->freeze(); } + if (pl) { pl->clear_changes (); pl->split_region ((*a)->region(), where); @@ -201,17 +211,38 @@ Editor::split_regions_at (framepos_t where, RegionSelection& regions) a = tmp; } + vector region_added_connections; + + for (list::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) { + region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view))); + } + + latest_regionviews.clear (); + while (used_playlists.size() > 0) { list >::iterator i = used_playlists.begin(); (*i)->thaw(); used_playlists.pop_front(); } + for (vector::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) { + (*c).disconnect (); + } + commit_reversible_command (); if (frozen){ EditorThaw(); /* Emit Signal */ } + + //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw. + _ignore_follow_edits = true; //a split will change the region selection in mysterious ways; its not practical or wanted to follow this edit + if( working_on_selection ) { + selection->add ( pre_selected_regions ); + selection->add (latest_regionviews); //these are the new regions created after the split + } + _ignore_follow_edits = false; + } /** Move one extreme of the current range selection. If more than one range is selected, @@ -1335,26 +1366,30 @@ Editor::scroll_down_one_track () { TrackViewList::reverse_iterator next = track_views.rend(); std::pair res; + const double bottom_of_trackviews = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - 1; for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) { if ((*t)->hidden()) { continue; } - /* find the trackview at the bottom of the trackview group */ - res = (*t)->covers_y_position (_visible_canvas_height); + /* If this is the bottom visible trackview, we want to display + the next one. + */ + + res = (*t)->covers_y_position (bottom_of_trackviews); if (res.first) { break; } - next = t; + ++next; // moves "next" towards the "front" since it is a reverse iterator } /* move to the track below the first one that covers the */ if (next != track_views.rend()) { - ensure_track_visible (*next); + ensure_time_axis_view_is_visible (**next); return true; } @@ -1364,7 +1399,7 @@ Editor::scroll_down_one_track () bool Editor::scroll_up_one_track () { - // double vertical_pos = vertical_adjustment.get_value (); + double vertical_pos = vertical_adjustment.get_value (); TrackViewList::iterator prev = track_views.end(); std::pair res; @@ -1376,9 +1411,10 @@ Editor::scroll_up_one_track () } /* find the trackview at the top of the trackview group */ - res = (*t)->covers_y_position (0); + res = (*t)->covers_y_position (vertical_pos); if (res.first) { + cerr << res.first->name() << " covers the top\n"; break; } @@ -1386,7 +1422,7 @@ Editor::scroll_up_one_track () } if (prev != track_views.end()) { - ensure_track_visible (*prev); + ensure_time_axis_view_is_visible (**prev); return true; } @@ -1398,7 +1434,7 @@ Editor::scroll_up_one_track () void Editor::tav_zoom_step (bool coarser) { - _routes->suspend_redisplay (); + DisplaySuspender ds; TrackViewList* ts; @@ -1412,14 +1448,12 @@ Editor::tav_zoom_step (bool coarser) TimeAxisView *tv = (static_cast(*i)); tv->step_height (coarser); } - - _routes->resume_redisplay (); } void Editor::tav_zoom_smooth (bool coarser, bool force_all) { - _routes->suspend_redisplay (); + DisplaySuspender ds; TrackViewList* ts; @@ -1444,42 +1478,8 @@ Editor::tav_zoom_smooth (bool coarser, bool force_all) tv->set_height (h + 5); } } - - _routes->resume_redisplay (); } -bool -Editor::clamp_samples_per_pixel (framecnt_t& fpp) const -{ - bool clamped = false; - - if (fpp < 1) { - fpp = 1; - clamped = true; - } - - framecnt_t sr; - - if (_session) { - sr = _session->frame_rate (); - } else { - sr = 48000; - } - - const framecnt_t three_days = 3 * 24 * 60 * 60 * sr; - const framecnt_t lots_of_pixels = 4000; - - /* if the zoom level is greater than what you'd get trying to display 3 - * days of audio on a really big screen, scale it down. - */ - - if (fpp * lots_of_pixels > three_days) { - fpp = three_days / _track_canvas->width(); - clamped = true; - } - - return clamped; -} void Editor::temporal_zoom_step (bool coarser) @@ -1516,7 +1516,6 @@ Editor::temporal_zoom (framecnt_t fpp) framecnt_t nfpp; double l; - clamp_samples_per_pixel (fpp); if (fpp == samples_per_pixel) { return; } @@ -1705,7 +1704,7 @@ Editor::temporal_zoom_region (bool both_axes) /* hide irrelevant tracks */ - _routes->suspend_redisplay (); + DisplaySuspender ds; for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) { if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) { @@ -1713,8 +1712,6 @@ Editor::temporal_zoom_region (bool both_axes) } } - _routes->resume_redisplay (); - vertical_adjustment.set_value (0.0); } @@ -1808,8 +1805,7 @@ Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame) new_spp = samples_per_pixel - (samples_per_pixel/2); } else { /* could bail out here since we cannot zoom any finer, - but leave that to the clamp_samples_per_pixel() and - equality test below + but leave that to the equality test below */ new_spp = samples_per_pixel; } @@ -1817,8 +1813,6 @@ Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame) range_before -= range_before/2; } - clamp_samples_per_pixel (new_spp); - if (new_spp == samples_per_pixel) { return; } @@ -1930,6 +1924,35 @@ Editor::add_location_from_playhead_cursor () add_location_mark (_session->audible_frame()); } +void +Editor::remove_location_at_playhead_cursor () +{ + if (_session) { + + //set up for undo + _session->begin_reversible_command (_("remove marker")); + XMLNode &before = _session->locations()->get_state(); + bool removed = false; + + //find location(s) at this time + Locations::LocationList locs; + _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0)); + for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) { + if ((*i)->is_mark()) { + _session->locations()->remove (*i); + removed = true; + } + } + + //store undo + if (removed) { + XMLNode &after = _session->locations()->get_state(); + _session->add_command(new MementoCommand(*(_session->locations()), &before, &after)); + _session->commit_reversible_command (); + } + } +} + /** Add a range marker around each selected region */ void Editor::add_locations_from_region () @@ -2114,85 +2137,6 @@ Editor::unhide_ranges () /* INSERT/REPLACE */ -void -Editor::insert_region_list_drag (boost::shared_ptr region, int x, int y) -{ - double cx, cy; - framepos_t where; - RouteTimeAxisView *rtv = 0; - boost::shared_ptr playlist; - - GdkEvent event; - event.type = GDK_BUTTON_RELEASE; - event.button.x = x; - event.button.y = y; - - where = window_event_sample (&event, &cx, &cy); - - if (where < leftmost_frame || where > leftmost_frame + current_page_samples()) { - /* clearly outside canvas area */ - return; - } - - std::pair tv = trackview_by_y_position (cy); - if (tv.first == 0) { - return; - } - - if ((rtv = dynamic_cast (tv.first)) == 0) { - return; - } - - if ((playlist = rtv->playlist()) == 0) { - return; - } - - snap_to (where); - - begin_reversible_command (_("insert dragged region")); - playlist->clear_changes (); - playlist->add_region (RegionFactory::create (region, true), where, 1.0); - _session->add_command(new StatefulDiffCommand (playlist)); - commit_reversible_command (); -} - -void -Editor::insert_route_list_drag (boost::shared_ptr route, int x, int y) -{ - double cx, cy; - RouteTimeAxisView *dest_rtv = 0; - RouteTimeAxisView *source_rtv = 0; - - GdkEvent event; - event.type = GDK_BUTTON_RELEASE; - event.button.x = x; - event.button.y = y; - - window_event_sample (&event, &cx, &cy); - - std::pair const tv = trackview_by_y_position (cy); - if (tv.first == 0) { - return; - } - - if ((dest_rtv = dynamic_cast (tv.first)) == 0) { - return; - } - - /* use this drag source to add underlay to a track. But we really don't care - about the Route, only the view of the route, so find it first */ - for(TrackViewList::iterator it = track_views.begin(); it != track_views.end(); ++it) { - if((source_rtv = dynamic_cast(*it)) == 0) { - continue; - } - - if(source_rtv->route() == route && source_rtv != dest_rtv) { - dest_rtv->add_underlay(source_rtv->view()); - break; - } - } -} - void Editor::insert_region_list_selection (float times) { @@ -2225,6 +2169,9 @@ Editor::insert_region_list_selection (float times) begin_reversible_command (_("insert region")); playlist->clear_changes (); playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times); + if (Config->get_edit_mode() == Ripple) + playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr()); + _session->add_command(new StatefulDiffCommand (playlist)); commit_reversible_command (); } @@ -2327,7 +2274,7 @@ Editor::get_preroll () void Editor::maybe_locate_with_edit_preroll ( framepos_t location ) { - if ( _session->transport_rolling() || !Config->get_always_play_range() ) + if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits ) return; location -= get_preroll(); @@ -2848,8 +2795,7 @@ Editor::separate_regions_between (const TimeSelection& ts) } if (in_command) { - selection->set (new_selection); - set_mouse_mode (MouseObject); +// selection->set (new_selection); commit_reversible_command (); } @@ -3786,30 +3732,15 @@ Editor::copy () bool Editor::can_cut_copy () const { - switch (effective_mouse_mode()) { - - case MouseObject: - if (!selection->regions.empty() || !selection->points.empty()) { - return true; - } - break; - - case MouseRange: - if (!selection->time.empty()) { - return true; - } - break; - - default: - break; - } + if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty()) + return true; return false; } /** Cut, copy or clear selected regions, automation points or a time range. - * @param op Operation (Cut, Copy or Clear) + * @param op Operation (Delete, Cut, Copy or Clear) */ void Editor::cut_copy (CutCopyOp op) @@ -3845,7 +3776,7 @@ Editor::cut_copy (CutCopyOp op) } } - if ( op != Clear ) //"Delete" doesn't change copy/paste buf + if ( op != Delete ) //"Delete" doesn't change copy/paste buf cut_buffer->clear (); if (entered_marker) { @@ -3881,77 +3812,60 @@ Editor::cut_copy (CutCopyOp op) bool did_edit = false; - switch (effective_mouse_mode()) { - case MouseGain: - if (!selection->points.empty()) { - begin_reversible_command (opname + _(" points")); - did_edit = true; - cut_copy_points (op); - if (op == Cut || op == Delete) { - selection->clear_points (); - } + if (!selection->points.empty()) { + begin_reversible_command (opname + _(" points")); + did_edit = true; + cut_copy_points (op); + if (op == Cut || op == Delete) { + selection->clear_points (); } - break; - - case MouseObject: - - if (!selection->regions.empty() || !selection->points.empty()) { + } else if (!selection->regions.empty() || !selection->points.empty()) { - string thing_name; + string thing_name; - if (selection->regions.empty()) { - thing_name = _("points"); - } else if (selection->points.empty()) { - thing_name = _("regions"); - } else { - thing_name = _("objects"); - } - - begin_reversible_command (opname + ' ' + thing_name); - did_edit = true; + if (selection->regions.empty()) { + thing_name = _("points"); + } else if (selection->points.empty()) { + thing_name = _("regions"); + } else { + thing_name = _("objects"); + } + + begin_reversible_command (opname + ' ' + thing_name); + did_edit = true; - if (!selection->regions.empty()) { - cut_copy_regions (op, selection->regions); - - if (op == Cut || op == Delete) { - selection->clear_regions (); - } - } - - if (!selection->points.empty()) { - cut_copy_points (op); - - if (op == Cut || op == Delete) { - selection->clear_points (); - } - } - } - break; + if (!selection->regions.empty()) { + cut_copy_regions (op, selection->regions); - case MouseRange: - if (selection->time.empty()) { - framepos_t start, end; - /* no time selection, see if we can get an edit range - and use that. - */ - if (get_edit_op_range (start, end)) { - selection->set (start, end); + if (op == Cut || op == Delete) { + selection->clear_regions (); } } - if (!selection->time.empty()) { - begin_reversible_command (opname + _(" range")); - - did_edit = true; - cut_copy_ranges (op); + + if (!selection->points.empty()) { + cut_copy_points (op); if (op == Cut || op == Delete) { - selection->clear_time (); + selection->clear_points (); } } - break; + } else if (selection->time.empty()) { + framepos_t start, end; + /* no time selection, see if we can get an edit range + and use that. + */ + if (get_edit_op_range (start, end)) { + selection->set (start, end); + } + } else if (!selection->time.empty()) { + begin_reversible_command (opname + _(" range")); + + did_edit = true; + cut_copy_ranges (op); - default: - break; + if (op == Cut || op == Delete) { + selection->clear_time (); + } } if (did_edit) { @@ -4085,10 +3999,11 @@ Editor::remove_clicked_region () boost::shared_ptr playlist = clicked_routeview->playlist(); - begin_reversible_command (_("remove region")); playlist->clear_changes (); playlist->clear_owned_changes (); playlist->remove_region (clicked_regionview->region()); + if (Config->get_edit_mode() == Ripple) + playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr()); /* We might have removed regions, which alters other regions' layering_index, so we need to do a recursive diff here. @@ -4151,6 +4066,9 @@ Editor::remove_selected_regions () playlist->clear_owned_changes (); playlist->freeze (); playlist->remove_region (*rl); + if (Config->get_edit_mode() == Ripple) + playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr()); + } vector >::iterator pl; @@ -4280,12 +4198,16 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) switch (op) { case Delete: pl->remove_region (r); + if (Config->get_edit_mode() == Ripple) + pl->ripple (r->position(), -r->length(), boost::shared_ptr()); break; case Cut: _xx = RegionFactory::create (r); npl->add_region (_xx, r->position() - first_position); pl->remove_region (r); + if (Config->get_edit_mode() == Ripple) + pl->ripple (r->position(), -r->length(), boost::shared_ptr()); break; case Copy: @@ -4294,7 +4216,9 @@ Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs) break; case Clear: - pl->remove_region (r); + pl->remove_region (r); + if (Config->get_edit_mode() == Ripple) + pl->ripple (r->position(), -r->length(), boost::shared_ptr()); break; } @@ -5639,7 +5563,7 @@ Editor::set_playhead_cursor () } } - if ( Config->get_always_play_range() ) + if ( Config->get_follow_edits() ) cancel_time_selection(); } @@ -5697,7 +5621,7 @@ Editor::select_next_route() selection->set(current); - ensure_track_visible(current); + ensure_time_axis_view_is_visible (*current); } void @@ -5728,37 +5652,7 @@ Editor::select_prev_route() 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(); - - 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() - vertical_adjustment.get_page_size(); - } - - vertical_adjustment.set_value(new_value); + ensure_time_axis_view_is_visible (*current); } void @@ -6672,8 +6566,11 @@ edit your ardour.rc file to set the\n\ return; } - for (vector >::iterator x = routes.begin(); x != routes.end(); ++x) { - _session->remove_route (*x); + { + Session::StateProtector sp (_session); + for (vector >::iterator x = routes.begin(); x != routes.end(); ++x) { + _session->remove_route (*x); + } } } @@ -7107,3 +7004,83 @@ Editor::toggle_midi_input_active (bool flip_others) _session->set_exclusive_input_active (rl, onoff, flip_others); } + +void +Editor::lock () +{ + if (!lock_dialog) { + lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true); + + Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed"))); + lock_dialog->get_vbox()->pack_start (*padlock); + + ArdourButton* b = manage (new ArdourButton); + b->set_name ("lock button"); + b->set_markup (string_compose ("%1", _("Click to unlock"))); + b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock)); + lock_dialog->get_vbox()->pack_start (*b); + + lock_dialog->get_vbox()->show_all (); + lock_dialog->set_size_request (200, 200); + } + +#ifdef __APPLE__ + /* The global menu bar continues to be accessible to applications + with modal dialogs, which means that we need to desensitize + all items in the menu bar. Since those items are really just + proxies for actions, that means disabling all actions. + */ + ActionManager::disable_all_actions (); +#endif + lock_dialog->present (); +} + +void +Editor::unlock () +{ + lock_dialog->hide (); + +#ifdef __APPLE__ + ActionManager::pop_action_state (); +#endif + + if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) { + start_lock_event_timing (); + } +} + +void +Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name) +{ + Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name)); +} + +void +Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name) +{ + label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total)); + Gtkmm2ext::UI::instance()->flush_pending (); +} + +void +Editor::bring_all_sources_into_session () +{ + if (!_session) { + return; + } + + Gtk::Label msg; + ArdourDialog w (_("Moving embedded files into session folder")); + w.get_vbox()->pack_start (msg); + w.present (); + + /* flush all pending GUI events because we're about to start copying + * files + */ + + Gtkmm2ext::UI::instance()->flush_pending (); + + cerr << " Do it\n"; + + _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3)); +}