From 6446d0ce490265fc26beb04fbdfa993d7e3b1c9b Mon Sep 17 00:00:00 2001 From: Paul Davis Date: Wed, 18 Jun 2008 18:22:22 +0000 Subject: [PATCH] slightly modified patch from colinf to make region context menu items always operate on well-defined and reasonably obvious region selection git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@3476 d708f5d6-7413-0410-9779-e7cbd77b26cf --- gtk2_ardour/editor.cc | 122 +++++++++++++++++++++++--------------- gtk2_ardour/editor.h | 2 +- gtk2_ardour/editor_ops.cc | 89 +++++++++++++++------------ 3 files changed, 126 insertions(+), 87 deletions(-) diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index a8d37f9022..cbb9756d86 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -1603,9 +1603,19 @@ Editor::build_track_region_context_menu (nframes64_t frame) if ((ds = atv->get_diskstream()) && ((pl = ds->playlist()))) { Playlist::RegionList* regions = pl->regions_at ((nframes64_t) floor ( (double)frame * ds->speed())); - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->audio_view(), (*i), edit_items); + + if (selection->regions.size() > 1) { + // there's already a multiple selection: just add a + // single region context menu that will act on all + // selected regions + boost::shared_ptr dummy_region; // = NULL + add_region_context_items (atv->audio_view(), dummy_region, edit_items); + } else { + for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { + add_region_context_items (atv->audio_view(), (*i), edit_items); + } } + delete regions; } } @@ -1642,10 +1652,17 @@ Editor::build_track_crossfade_context_menu (nframes64_t frame) add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many); } - for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { - add_region_context_items (atv->audio_view(), (*i), edit_items); + if (selection->regions.size() > 1) { + // there's already a multiple selection: just add a + // single region context menu that will act on all + // selected regions + boost::shared_ptr dummy_region; // = NULL + add_region_context_items (atv->audio_view(), dummy_region, edit_items); + } else { + for (Playlist::RegionList::iterator i = regions->begin(); i != regions->end(); ++i) { + add_region_context_items (atv->audio_view(), (*i), edit_items); + } } - delete regions; } } @@ -1778,16 +1795,23 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr if (region) { ar = boost::dynamic_pointer_cast (region); + + /* when this particular menu pops up, make the relevant region + become selected. + */ + + region_menu->signal_map_event().connect ( + bind ( + mem_fun(*this, &Editor::set_selected_regionview_from_map_event), + sv, + boost::weak_ptr(region) + ) + ); + + items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region))); + items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region))); } - /* when this particular menu pops up, make the relevant region - become selected. - */ - - region_menu->signal_map_event().connect (bind (mem_fun(*this, &Editor::set_selected_regionview_from_map_event), sv, boost::weak_ptr(region))); - - items.push_back (MenuElem (_("Rename"), mem_fun(*this, &Editor::rename_region))); - items.push_back (MenuElem (_("Popup region editor"), mem_fun(*this, &Editor::edit_region))); items.push_back (MenuElem (_("Raise to top layer"), mem_fun(*this, &Editor::raise_region_to_top))); items.push_back (MenuElem (_("Lower to bottom layer"), mem_fun (*this, &Editor::lower_region_to_bottom))); items.push_back (SeparatorElem()); @@ -1807,49 +1831,51 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr sigc::connection fooc; - items.push_back (CheckMenuElem (_("Lock"))); - CheckMenuItem* region_lock_item = static_cast(&items.back()); - if (region->locked()) { - region_lock_item->set_active(); - } - region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock)); + if (region) { + items.push_back (CheckMenuElem (_("Lock"))); + CheckMenuItem* region_lock_item = static_cast(&items.back()); + if (region->locked()) { + region_lock_item->set_active(); + } + region_lock_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_lock)); - items.push_back (CheckMenuElem (_("Glue to Bars&Beats"))); - CheckMenuItem* bbt_glue_item = static_cast(&items.back()); + items.push_back (CheckMenuElem (_("Glue to Bars&Beats"))); + CheckMenuItem* bbt_glue_item = static_cast(&items.back()); - switch (region->positional_lock_style()) { - case Region::MusicTime: - bbt_glue_item->set_active (true); - break; - default: - bbt_glue_item->set_active (false); - break; - } + switch (region->positional_lock_style()) { + case Region::MusicTime: + bbt_glue_item->set_active (true); + break; + default: + bbt_glue_item->set_active (false); + break; + } - bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime)); + bbt_glue_item->signal_activate().connect (bind (mem_fun (*this, &Editor::set_region_lock_style), Region::MusicTime)); - items.push_back (CheckMenuElem (_("Mute"))); - CheckMenuItem* region_mute_item = static_cast(&items.back()); - fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute)); - if (region->muted()) { - fooc.block (true); - region_mute_item->set_active(); - fooc.block (false); - } - - if (!Profile->get_sae()) { - items.push_back (CheckMenuElem (_("Opaque"))); - CheckMenuItem* region_opaque_item = static_cast(&items.back()); - fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque)); - if (region->opaque()) { + items.push_back (CheckMenuElem (_("Mute"))); + CheckMenuItem* region_mute_item = static_cast(&items.back()); + fooc = region_mute_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_mute)); + if (region->muted()) { fooc.block (true); - region_opaque_item->set_active(); + region_mute_item->set_active(); fooc.block (false); } + + if (!Profile->get_sae()) { + items.push_back (CheckMenuElem (_("Opaque"))); + CheckMenuItem* region_opaque_item = static_cast(&items.back()); + fooc = region_opaque_item->signal_activate().connect (mem_fun(*this, &Editor::toggle_region_opaque)); + if (region->opaque()) { + fooc.block (true); + region_opaque_item->set_active(); + fooc.block (false); + } + } } items.push_back (CheckMenuElem (_("Original position"), mem_fun(*this, &Editor::naturalize))); - if (region->at_natural_position()) { + if (region && region->at_natural_position()) { items.back().set_sensitive (false); } @@ -1937,7 +1963,7 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr items.push_back (MenuElem (_("Multi-Duplicate"), (bind (mem_fun(*this, &Editor::duplicate_dialog), true)))); items.push_back (MenuElem (_("Fill Track"), (mem_fun(*this, &Editor::region_fill_track)))); items.push_back (SeparatorElem()); - items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_clicked_region))); + items.push_back (MenuElem (_("Remove"), mem_fun(*this, &Editor::remove_region))); /* OK, stick the region submenu at the top of the list, and then add the standard items. @@ -1948,7 +1974,7 @@ Editor::add_region_context_items (AudioStreamView* sv, boost::shared_ptr */ string::size_type pos = 0; - string menu_item_name = region->name(); + string menu_item_name = (region) ? region->name() : _("Selected regions"); while ((pos = menu_item_name.find ("_", pos)) != string::npos) { menu_item_name.replace (pos, 1, "__"); diff --git a/gtk2_ardour/editor.h b/gtk2_ardour/editor.h index 0099bb3fc5..be86ba4baf 100644 --- a/gtk2_ardour/editor.h +++ b/gtk2_ardour/editor.h @@ -1025,8 +1025,8 @@ class Editor : public PublicEditor void align_selection_relative (ARDOUR::RegionPoint point, nframes64_t position, const RegionSelection&); void align_region (boost::shared_ptr, ARDOUR::RegionPoint point, nframes64_t position); void align_region_internal (boost::shared_ptr, ARDOUR::RegionPoint point, nframes64_t position); + void remove_region (); void remove_clicked_region (); - void destroy_clicked_region (); void edit_region (); void rename_region (); void duplicate_some_regions (RegionSelection&, float times); diff --git a/gtk2_ardour/editor_ops.cc b/gtk2_ardour/editor_ops.cc index f474511f48..6ae78ff1cb 100644 --- a/gtk2_ardour/editor_ops.cc +++ b/gtk2_ardour/editor_ops.cc @@ -199,46 +199,50 @@ Editor::remove_clicked_region () } void -Editor::destroy_clicked_region () +Editor::remove_region () { - uint32_t selected = selection->regions.size(); - if (!session || !selected) { + RegionSelection rs; + get_regions_for_action (rs); + + if (!session) { return; } - vector choices; - string prompt; - - prompt = string_compose (_(" This is destructive, will possibly delete audio files\n\ -It cannot be undone\n\ -Do you really want to destroy %1 ?"), - (selected > 1 ? - _("these regions") : _("this region"))); - - choices.push_back (_("No, do nothing.")); - - if (selected > 1) { - choices.push_back (_("Yes, destroy them.")); - } else { - choices.push_back (_("Yes, destroy it.")); - } - - Gtkmm2ext::Choice prompter (prompt, choices); - - if (prompter.run() == 0) { /* first choice */ + if (rs.empty()) { return; } - if (selected) { - list > r; + begin_reversible_command (_("remove region")); - for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) { - r.push_back ((*i)->region()); - } + list > regions_to_remove; - session->destroy_regions (r); - } + 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)); + } + commit_reversible_command (); } boost::shared_ptr @@ -3152,15 +3156,23 @@ Editor::set_sync_point (nframes64_t where, const RegionSelection& rs) void Editor::remove_region_sync () { - if (clicked_regionview) { - boost::shared_ptr region (clicked_regionview->region()); - begin_reversible_command (_("remove sync")); - XMLNode &before = region->playlist()->get_state(); - region->clear_sync_position (); - XMLNode &after = region->playlist()->get_state(); - session->add_command(new MementoCommand(*(region->playlist()), &before, &after)); - commit_reversible_command (); + RegionSelection rs; + + 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 (); } void @@ -4470,6 +4482,7 @@ Editor::region_selection_op (void (Region::*pmf)(bool), bool yn) void Editor::external_edit_region () { + // XXX shouldn't this use get_regions_for_action(rs) too? if (!clicked_regionview) { return; }